File size: 6,513 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
hvPlot supports [streamz](https://github.com/mrocklin/streamz) DataFrame and Series objects, automatically generating streaming plots in a Jupyter notebook or deployed as a [Bokeh Server app](https://bokeh.pydata.org/en/latest/docs/user_guide/server.html). 

All hvPlot methods on streamz objects return HoloViews `DynamicMap` objects that update the plot whenever `streamz` triggers an event. For more information on `DynamicMap` and HoloViews dynamic plotting support, see the [HoloViews User Guide](https://holoviews.org/user_guide); here we will focus on using the simple, high-level hvPlot API rather than on the details of how events and data flow behind the scenes.

**All plots generated by the streamz plotting interface dynamically stream data from Python into the web browser.  The web version for this page includes *screen captures* of the streaming visualizations, not live streaming data.**

As for any of the data backends, we start by patching the streamz library with the plotting API:


```python
import hvplot.streamz  # noqa
```

## Basic plotting

Throughout this section we will be using the ``Random`` object from streamz, which provides an easy way of generating a DataFrame of random streaming data but which could be substituted with any streamz ``DataFrame`` or ``Series`` driven by a live, external data source instead. To stop the ``Random`` stream you can call ``df.stop()`` at any point.


```python
from streamz.dataframe import Random
df = Random(interval='200ms', freq='50ms')
```

<img src='https://assets.holoviews.org/hvplot/gifs/df_streamz.gif' width=400px></img>

The plot method on Series and DataFrame is a simple wrapper around a
line plot, which will plot all columns:


```python
df.hvplot()
```

<center><img src='https://assets.holoviews.org/hvplot/gifs/df_plot.gif' width=700px></img></center>

The plot method can also be called on a Series, plotting a specific column:


```python
df.z.cumsum().hvplot()
```

<center><img src='https://assets.holoviews.org/hvplot/gifs/df_curve.gif' width=700px></img></center>

Actually, *all* the functionality described in the [Plotting](Plotting.ipynb) user guide should work just the same as it does for a regular (non-streaming) dask or pandas DataFrame or Series, but will now update as new data appears.

## Controlling the backlog

The main difference when using a streaming DataFrame is that a only a certain amount of data will be buffered and displayed. The number of rows of data that will be buffered can be controlled by the ``backlog`` parameter. Here, let's buffer and display 10 rows of our streaming DataFrame as a table:


```python
df.hvplot.table(width=400, backlog=10)
```

<center><img src='https://assets.holoviews.org/hvplot/gifs/df_table.gif' width=400px></img></center>

This of course only has an effect when we are directly streaming data point by point. When we have an aggregate DataFrame, the plot will continuously accumulate updates:


```python
df.groupby('y').sum().hvplot.bar(x='y')
```

<center><img src='https://assets.holoviews.org/hvplot/gifs/df_bars.gif' width=700px></img></center>

## Composing Plots

hvPlot is a convenient API for generating HoloViews objects. One of the core strengths of HoloViews objects is the ease with which they can be composed, which works with streaming plots just as with static ones. Individual plots can be composed using the ``*`` and ``+`` operators, which overlay and compose plots into layouts respectively. For more information on composing objects see the HoloViews [User Guide](https://holoviews.org/user_guide/Composing_Elements.html).

By using these operators we can combine multiple plots into composite Overlay and Layout objects, and lay them out in two columns using the ``Layout.cols`` method:


```python
(df.hvplot.line(width=400, backlog=100) * df.hvplot.scatter(width=400, backlog=100) +
 df.groupby('y').sum().hvplot.bar('y', 'x', width=400) +
 df.hvplot.box(width=400) + df.x.hvplot.kde(width=400, shared_axes=False)).cols(2)
```

<center><img src='https://assets.holoviews.org/hvplot/gifs/df_composite.gif' width=700px></img></center>

## Deployment as Bokeh apps

HoloViews objects automatically render themselves in Jupyter notebook cells, but when deploying a bokeh app the plot has to be rendered explicitly. Deploying as a Bokeh Server app allows you to share live, dynamically updated visualizations like those for streaming data, backed by a running Python process.

The following example describes how to set up a streaming DataFrame, declare some plots, compose them, set up a callback to update the plot and finally convert the composite plot to a bokeh Document, which can be served from a script using ``bokeh serve`` on the commandline.

```python

import numpy as np
import pandas as pd
import hvplot.streamz
import holoviews as hv

from streamz import Stream
from streamz.dataframe import DataFrame

renderer = hv.renderer('bokeh')

# Set up streaming DataFrame
stream = Stream()
index = pd.DatetimeIndex([])
example = pd.DataFrame({'x': [], 'y': [], 'z': []},
                       columns=['x', 'y', 'z'], index=[])
df = DataFrame(stream, example=example)
cumulative = df.cumsum()[['x', 'z']]

# Declare plots
line = cumulative.hvplot.line(width=400)
scatter = cumulative.hvplot.scatter(width=400)
bars = df.groupby('y').sum().hvplot.bar(width=400)
box = df.hvplot.box(width=400)
kde = df.x.hvplot.kde(width=400)

# Compose plots
layout = (line * scatter + bars + box + kde).cols(2)

# Set up callback with streaming data
def emit():
    now = pd.datetime.now()
    delta = np.timedelta64(500, 'ms')
    index = pd.date_range(np.datetime64(now)-delta, now, freq='100ms')
    df = pd.DataFrame({'x': np.random.randn(len(index)),
                       'y': np.random.randint(0, 10, len(index)),
                       'z': np.random.randn(len(index))},
                      columns=['x', 'y', 'z'], index=index)
    stream.emit(df)

# Render layout to bokeh server Document and attach callback
doc = renderer.server_doc(layout)
doc.title = 'Streamz HoloViews based Plotting API Bokeh App Demo'
doc.add_periodic_callback(emit, 500)
```

For more details on deploying Bokeh apps see the HoloViews [User Guide](https://holoviews.org/user_guide/Deploying_Bokeh_Apps.html).

## Using HoloViews directly

HoloViews itself includes first class support for streamz DataFrame and Series; for more details see the [Streaming Data section](https://holoviews.org/user_guide/Streaming_Data.html) in the HoloViews documentation.