File size: 8,579 Bytes
b9a0f21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
```python
import ipywidgets as ipw
import hvplot.xarray # noqa
import hvplot.pandas # noqa
import panel as pn
import pandas as pd
import panel.widgets as pnw
import xarray as xr
```

Interactive command-line or notebook interfaces are incredibly powerful tools for quickly doing exploratory analysis, letting you supply arguments to Python methods and functions and see the results immediately. However, this process of exploration can be slow and awkward for large parameter spaces because it requires manually typing each argument value. To further ease exploratory workflows, hvPlot ships with a convenient `.interactive` API, which mirrors the regular API of your favorite data analysis libraries like Pandas, Dask, and xarray but makes it possible to pass in _widgets_ for each argument value, not just a constant. When the widgets are used, the output will dynamically update the full pipeline of method calls so that it works just as if that particular value had been specified in the call being wrapped.

In this user guide we will explore how to use the .interactive API on xarray and pandas objects:


```python
ds = xr.tutorial.load_dataset('air_temperature')
ds
```


```python
from bokeh.sampledata.stocks import IBM

df = pd.DataFrame(IBM)
df['date'] = pd.to_datetime(df.date)
```

## Interactive widgets

We can supply both regular values, widgets and parameters as arguments to methods on the `.interactive` accessor. Here, we'll use widgets from the [Panel](https://panel.holoviz.org) library.  The repr of the resulting object will contain a layout of the widget and a view of the resulting output:


```python
slider = pnw.IntSlider(name='time', start=0, end=10)

ds.air.interactive(width=800).isel(time=slider)
```

You can also use widgets from the [ipywidgets](https://ipywidgets.readthedocs.io) library:


```python
slider = ipw.IntSlider(description='time', min=0, max=10)

ds.air.interactive(width=800).isel(time=slider)
```

Note that this works just as well for DataFrame objects whether they are Pandas, Dask or cuDF dataframes:


```python
nrows = pn.widgets.IntSlider(start=1, end=100, value=10)

df.interactive(width=500).head(nrows)
```

For Panel widgets, we can let .interactive automatically configure the widget, which is particularly convenient when working with `DiscreteSlider` widgets:


```python
ds.air.interactive(width=800).sel(time=pnw.DiscreteSlider)
```

## Functions as inputs

In some cases your starting point for your interactive pipeline may not simply be a DataFrame or xarray Dataset but a function that fetches some data or applies some initial processing on your data. In such a case you can use the `hvplot.bind` function to bind static AND dynamic arguments to your function. Binding dynamic arguments such as a widget or parameter means that whenever the widget/parameter value changes the output of the function will change as well. This makes it possible to construct functions as the input to your interactive pipeline that themselves represent some data pipeline.

In the example below we will explicitly declare a `Select` widget to select between multiple stock tickers and a function that loads dataframes containing data for each of those stocks. Using the `hvplot.bind` function we then bind the `ticker` select widget to the `ticker` argument of the `stock_df` function and call `.interactive` on the resulting bound function:


```python
from bokeh import sampledata

ticker = pn.widgets.Select(options=['AAPL', 'IBM', 'GOOG', 'MSFT'], name='Ticker')

def stock_df(ticker):
    df = pd.DataFrame(getattr(sampledata.stocks, ticker))
    df['date'] = pd.to_datetime(df.date)
    return df

stock_dfi = hvplot.bind(stock_df, ticker).interactive(width=600)

stock_dfi.head(10)
```

As you can see this `interactive` component behaves just like any other, allowing us to chain `.head` on it and updating when the `ticker` widget changes.

Just like any other `interactive` component you may also chain it further:


```python
ticker = pn.widgets.Select(options=['AAPL', 'IBM', 'GOOG', 'MSFT'], name='Ticker')

def stock_df(ticker):
    df = pd.DataFrame(getattr(sampledata.stocks, ticker))
    df['date'] = pd.to_datetime(df.date)
    return df

stock_dfi = hvplot.bind(stock_df, ticker).interactive()

dt_range = pn.widgets.DateRangeSlider(start=df.date.iloc[-1000], end=df.date.max(), value=(df.date.iloc[-100], df.date.max()))

stock_dfi[(stock_dfi.date>=dt_range.param.value_start) & (stock_dfi.date<=dt_range.param.value_end)].hvplot(kind='ohlc', grid=True, title=ticker)
```

## Docstrings

When accessing a method on the `.interactive` accessor it will transparently mirror the docstring of the equivalent method in the underlying library being wrapped:


```python
print(ds.air.interactive.isel.__doc__)
```

## Plotting

One of the most useful aspects of the .interactive API is to feed the output of chained method calls into a plot.

### Matplotlib

The output can be almost anything, such as the HTML repr (above) or a matplotlib plot:


```python
ds.air.interactive.sel(time=pnw.DiscreteSlider).plot()
```

If we like, we can animate the output with a `Player` widget, and customize the location of the widget using the `loc` keyword argument to `.interactive`:


```python
time = pnw.Player(name='time', start=0, end=10, loop_policy='loop', interval=100)

ds.air.interactive(loc='bottom').isel(time=time).plot()
```

### hvPlot

We can also make use of the `.hvplot` method to get fully interactive Bokeh-based plots:


```python
slider = pnw.FloatSlider(name='quantile', start=0, end=1)

ds.air.interactive.quantile(slider, dim='time').hvplot(data_aspect=1)
```

You can chain any number of methods, with as many widgets controlling steps in this pipeline as you wish:


```python
q = pnw.FloatSlider(name='quantile', start=0, end=1)

(ds.air.interactive(loc='left')
 .sel(time=pnw.DiscreteSlider)
 .quantile(q=q, dim='lon')
 .hvplot(aspect=1))
```

We can also use a `RangeSlider` to select a slice and compute the mean over that range instead of selecting a specific time:


```python
range_slider = pnw.IntRangeSlider

(ds.air.interactive
 .isel(time=range_slider)
 .mean('time')
 .hvplot())
```

`.interactive` supports arbitrary chains of method calls, including anything that is supported by your data object. For instance, you can even convert your xarray object into a dataframe using `.to_dataframe`, then call pandas methods:


```python
ds.air.interactive.sel(lat=pnw.DiscreteSlider).to_dataframe().groupby('time').mean().hvplot('time', 'air')
```

## Operators

You can further transform your output, if desired, by applying math operators on the interactive object:


```python
slider = pnw.IntSlider(name='time', start=0, end=10)
baseline = ds.air.mean().item()
baseline
```


```python
ds.air.interactive(width=800).isel(time=slider).mean().item() - baseline
```

You can even do math with a widget:


```python
slider = pnw.IntSlider(name='time',   start=0, end=10)
offset = pnw.IntSlider(name='offset', start=0, end=500)

ds.air.interactive.isel(time=slider).mean().item() + offset
```

Math operators work with array data as well, such as the time-averaged value of each array value:


```python
diff = ds.air.interactive.sel(time=pnw.DiscreteSlider) - ds.air.mean('time')
kind = pnw.Select(options=['contour', 'contourf', 'image'])

diff.hvplot(cmap='RdBu_r', clim=(-20, 20), kind=kind)
```

If you want more control over the layout, you can use any of the features from [Panel](https://panel.holoviz.org). In this case, `interactive.panel()` (or `interactive.output()`) make sure you display the interactive plot only, with the widgets explicitly declared by `interactive.widgets()`:


```python
diff = ds.air.interactive.sel(time=pnw.DiscreteSlider) - ds.air.mean('time')
kind = pnw.Select(options=['contourf', 'contour', 'image'], value='image')
interactive = diff.hvplot(cmap='RdBu_r', clim=(-20, 20), kind=kind)

pn.Column(
    pn.Row(
        pn.panel("https://hvplot.holoviz.org/assets/hvplot-wm.png", width=100), 
        pn.Spacer(width=20),
        pn.Column(
            pn.panel("## Select a time and type of plot", width=400),
            interactive.widgets()
        ),
        pn.panel("https://panel.holoviz.org/_static/logo_stacked.png", width=100)
    ),
    interactive.panel()
).servable()
```

As you can see, the `.interactive` functionality makes it simple to work interactively with your data, letting you use widgets about as easily as any other method argument! See the Panel or ipwidgets docs for the various widgets and other functionality available.