Skip to content

Commit ed48215

Browse files
Merge pull request #2997 from plotly/trendlines2
Trendline options
2 parents 9f8633a + f42c5af commit ed48215

File tree

9 files changed

+568
-85
lines changed

9 files changed

+568
-85
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
88
### Added
99
- Extra flags were added to the `gapminder` and `stocks` dataset to facilitate testing, documentation and demos [#3305](https://github.com/plotly/plotly.py/issues/3305)
1010
- All line-like Plotly Express functions now accept `markers` argument to display markers, and all but `line_mapbox` accept `symbol` to map a field to the symbol attribute, similar to scatter-like functions [#3326](https://github.com/plotly/plotly.py/issues/3326)
11+
- `px.scatter` and `px.density_contours` now support new `trendline` types `'rolling'`, `'expanding'` and `'ewm'` [#2997](https://github.com/plotly/plotly.py/pull/2997)
12+
- `px.scatter` and `px.density_contours` now support new `trendline_options` argument to parameterize trendlines, with support for constant control and log-scaling in `'ols'` and specification of the fraction used for `'lowess'`, as well as pass-through to Pandas for `'rolling'`, `'expanding'` and `'ewm'` [#2997](https://github.com/plotly/plotly.py/pull/2997)
13+
- `px.scatter` and `px.density_contours` now support new `trendline_scope` argument that accepts the value `'overall'` to request a single trendline for all traces, including across facets and animation frames [#2997](https://github.com/plotly/plotly.py/pull/2997)
1114

1215
### Fixed
1316
- Fixed regression introduced in version 5.0.0 where pandas/numpy arrays with `dtype` of Object were being converted to `list` values when added to a Figure ([#3292](https://github.com/plotly/plotly.py/issues/3292), [#3293](https://github.com/plotly/plotly.py/pull/3293))

doc/apidoc/plotly.express.rst

+3
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ plotly's high-level API for rapid figure generation. ::
4949
density_heatmap
5050
density_mapbox
5151
imshow
52+
set_mapbox_access_token
53+
get_trendline_results
5254

5355

5456
`plotly.express` subpackages
@@ -60,3 +62,4 @@ plotly's high-level API for rapid figure generation. ::
6062

6163
generated/plotly.express.data.rst
6264
generated/plotly.express.colors.rst
65+
generated/plotly.express.trendline_functions.rst

doc/python/linear-fits.md

+156-9
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ jupyter:
55
text_representation:
66
extension: .md
77
format_name: markdown
8-
format_version: '1.1'
9-
jupytext_version: 1.1.1
8+
format_version: '1.2'
9+
jupytext_version: 1.4.2
1010
kernelspec:
1111
display_name: Python 3
1212
language: python
@@ -20,11 +20,12 @@ jupyter:
2020
name: python
2121
nbconvert_exporter: python
2222
pygments_lexer: ipython3
23-
version: 3.6.8
23+
version: 3.7.7
2424
plotly:
2525
description: Add linear Ordinary Least Squares (OLS) regression trendlines or
2626
non-linear Locally Weighted Scatterplot Smoothing (LOWESS) trendlines to scatterplots
27-
in Python.
27+
in Python. Options for moving averages (rolling means) as well as exponentially-weighted
28+
and expanding functions.
2829
display_as: statistical
2930
language: python
3031
layout: base
@@ -39,7 +40,7 @@ jupyter:
3940

4041
[Plotly Express](/python/plotly-express/) is the easy-to-use, high-level interface to Plotly, which [operates on a variety of types of data](/python/px-arguments/) and produces [easy-to-style figures](/python/styling-plotly-express/).
4142

42-
Plotly Express allows you to add [Ordinary Least](https://en.wikipedia.org/wiki/Ordinary_least_squares) Squares regression trendline to scatterplots with the `trendline` argument. In order to do so, you will need to install `statsmodels` and its dependencies. Hovering over the trendline will show the equation of the line and its R-squared value.
43+
Plotly Express allows you to add [Ordinary Least Squares](https://en.wikipedia.org/wiki/Ordinary_least_squares) regression trendline to scatterplots with the `trendline` argument. In order to do so, you will need to [install `statsmodels` and its dependencies](https://www.statsmodels.org/stable/install.html). Hovering over the trendline will show the equation of the line and its R-squared value.
4344

4445
```python
4546
import plotly.express as px
@@ -66,14 +67,160 @@ print(results)
6667
results.query("sex == 'Male' and smoker == 'Yes'").px_fit_results.iloc[0].summary()
6768
```
6869

69-
### Non-Linear Trendlines
70+
### Displaying a single trendline with multiple traces
7071

71-
Plotly Express also supports non-linear [LOWESS](https://en.wikipedia.org/wiki/Local_regression) trendlines.
72+
_new in v5.2_
73+
74+
To display a single trendline using the entire dataset, set the `trendline_scope` argument to `"overall"`. The same trendline will be overlaid on all facets and animation frames. The trendline color can be overridden with `trendline_color_override`.
75+
76+
```python
77+
import plotly.express as px
78+
79+
df = px.data.tips()
80+
fig = px.scatter(df, x="total_bill", y="tip", symbol="smoker", color="sex", trendline="ols", trendline_scope="overall")
81+
fig.show()
82+
```
83+
84+
```python
85+
import plotly.express as px
86+
87+
df = px.data.tips()
88+
fig = px.scatter(df, x="total_bill", y="tip", facet_col="smoker", color="sex",
89+
trendline="ols", trendline_scope="overall", trendline_color_override="black")
90+
fig.show()
91+
```
92+
93+
### OLS Parameters
94+
95+
_new in v5.2_
96+
97+
OLS trendlines can be fit with log transformations to both X or Y data using the `trendline_options` argument, independently of whether or not the plot has [logarithmic axes](https://plotly.com/python/log-plot/).
98+
99+
```python
100+
import plotly.express as px
101+
102+
df = px.data.gapminder(year=2007)
103+
fig = px.scatter(df, x="gdpPercap", y="lifeExp",
104+
trendline="ols", trendline_options=dict(log_x=True),
105+
title="Log-transformed fit on linear axes")
106+
fig.show()
107+
```
108+
109+
```python
110+
import plotly.express as px
111+
112+
df = px.data.gapminder(year=2007)
113+
fig = px.scatter(df, x="gdpPercap", y="lifeExp", log_x=True,
114+
trendline="ols", trendline_options=dict(log_x=True),
115+
title="Log-scaled X axis and log-transformed fit")
116+
fig.show()
117+
```
118+
119+
### Locally WEighted Scatterplot Smoothing (LOWESS)
120+
121+
Plotly Express also supports non-linear [LOWESS](https://en.wikipedia.org/wiki/Local_regression) trendlines. In order use this feature, you will need to [install `statsmodels` and its dependencies](https://www.statsmodels.org/stable/install.html).
122+
123+
```python
124+
import plotly.express as px
125+
126+
df = px.data.stocks(datetimes=True)
127+
fig = px.scatter(df, x="date", y="GOOG", trendline="lowess")
128+
fig.show()
129+
```
130+
131+
_new in v5.2_
132+
133+
The level of smoothing can be controlled via the `frac` trendline option, which indicates the fraction of the data that the LOWESS smoother should include. The default is a fairly smooth line with `frac=0.6666` and lowering this fraction will give a line that more closely follows the data.
134+
135+
```python
136+
import plotly.express as px
137+
138+
df = px.data.stocks(datetimes=True)
139+
fig = px.scatter(df, x="date", y="GOOG", trendline="lowess", trendline_options=dict(frac=0.1))
140+
fig.show()
141+
```
142+
143+
### Moving Averages
144+
145+
_new in v5.2_
146+
147+
Plotly Express can leverage Pandas' [`rolling`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.rolling.html), [`ewm`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.ewm.html) and [`expanding`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.expanding.html) functions in trendlines as well, for example to display moving averages. Values passed to `trendline_options` are passed directly to the underlying Pandas function (with the exception of the `function` and `function_options` keys, see below).
148+
149+
```python
150+
import plotly.express as px
151+
152+
df = px.data.stocks(datetimes=True)
153+
fig = px.scatter(df, x="date", y="GOOG", trendline="rolling", trendline_options=dict(window=5),
154+
title="5-point moving average")
155+
fig.show()
156+
```
157+
158+
```python
159+
import plotly.express as px
160+
161+
df = px.data.stocks(datetimes=True)
162+
fig = px.scatter(df, x="date", y="GOOG", trendline="ewm", trendline_options=dict(halflife=2),
163+
title="Exponentially-weighted moving average (halflife of 2 points)")
164+
fig.show()
165+
```
166+
167+
```python
168+
import plotly.express as px
169+
170+
df = px.data.stocks(datetimes=True)
171+
fig = px.scatter(df, x="date", y="GOOG", trendline="expanding", title="Expanding mean")
172+
fig.show()
173+
```
174+
175+
### Other Functions
176+
177+
The `rolling`, `expanding` and `ewm` trendlines support other functions than the default `mean`, enabling, for example, a moving-median trendline, or an expanding-max trendline.
72178

73179
```python
74180
import plotly.express as px
75181

76-
df = px.data.gapminder().query("year == 2007")
77-
fig = px.scatter(df, x="gdpPercap", y="lifeExp", color="continent", trendline="lowess")
182+
df = px.data.stocks(datetimes=True)
183+
fig = px.scatter(df, x="date", y="GOOG", trendline="rolling", trendline_options=dict(function="median", window=5),
184+
title="Rolling Median")
78185
fig.show()
79186
```
187+
188+
```python
189+
import plotly.express as px
190+
191+
df = px.data.stocks(datetimes=True)
192+
fig = px.scatter(df, x="date", y="GOOG", trendline="expanding", trendline_options=dict(function="max"),
193+
title="Expanding Maximum")
194+
fig.show()
195+
```
196+
197+
In some cases, it is necessary to pass options into the underying Pandas function, for example the `std` parameter must be provided if the `win_type` argument to `rolling` is `"gaussian"`. This is possible with the `function_args` trendline option.
198+
199+
```python
200+
import plotly.express as px
201+
202+
df = px.data.stocks(datetimes=True)
203+
fig = px.scatter(df, x="date", y="GOOG", trendline="rolling",
204+
trendline_options=dict(window=5, win_type="gaussian", function_args=dict(std=2)),
205+
title="Rolling Mean with Gaussian Window")
206+
fig.show()
207+
```
208+
209+
### Displaying only the trendlines
210+
211+
In some cases, it may be desirable to show only the trendlines, by removing the scatter points.
212+
213+
```python
214+
import plotly.express as px
215+
216+
df = px.data.stocks(indexed=True, datetimes=True)
217+
fig = px.scatter(df, trendline="rolling", trendline_options=dict(window=5),
218+
title="5-point moving average")
219+
fig.data = [t for t in fig.data if t.mode == "lines"]
220+
fig.update_traces(showlegend=True) #trendlines have showlegend=False by default
221+
fig.show()
222+
```
223+
224+
```python
225+
226+
```

packages/python/plotly/plotly/express/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060

6161
from ._special_inputs import IdentityMap, Constant, Range # noqa: F401
6262

63-
from . import data, colors # noqa: F401
63+
from . import data, colors, trendline_functions # noqa: F401
6464

6565
__all__ = [
6666
"scatter",
@@ -100,6 +100,7 @@
100100
"imshow",
101101
"data",
102102
"colors",
103+
"trendline_functions",
103104
"set_mapbox_access_token",
104105
"get_trendline_results",
105106
"IdentityMap",

packages/python/plotly/plotly/express/_chart_types.py

+4
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ def scatter(
4646
marginal_x=None,
4747
marginal_y=None,
4848
trendline=None,
49+
trendline_options=None,
4950
trendline_color_override=None,
51+
trendline_scope="trace",
5052
log_x=False,
5153
log_y=False,
5254
range_x=None,
@@ -90,7 +92,9 @@ def density_contour(
9092
marginal_x=None,
9193
marginal_y=None,
9294
trendline=None,
95+
trendline_options=None,
9396
trendline_color_override=None,
97+
trendline_scope="trace",
9498
log_x=False,
9599
log_y=False,
96100
range_x=None,

0 commit comments

Comments
 (0)