更新图形的一种方法是使用参数化类并使用 tornado PeriodicCallback
,有关详细信息,请参阅param、panel-param和tornado.ioloop的文档。
from hvplot import hvPlot
import numpy as np
import pandas as pd
import param
import panel as pn
import tornado
class Plot(param.Parameterized):
df = param.DataFrame(precedence=-1)
def __init__(self, **params):
super(Plot, self).__init__(**params)
self.generate_df() # create a first random dataframe
self.set_plot() # create a first plot with our new dataframe
# Once the bokeh server (for serving our plot to a webpage) is started,
# the underlying tornado server is taking control.
# To be able to fetch (or here: generate) new data, we have to register
# our method with the tornado ioloop.
# To poll for new data, the PeriodicCallback can be used.
self.cb = tornado.ioloop.PeriodicCallback(self.generate_df, 1000, .2)
self.cb.start() # start the callback
# self.callback.stop () ## In this example not implemented, callback runs indefinitely
def generate_df(self):
print('generate df')
self.df = pd.DataFrame(np.random.randint(90,100,size=(5, 1)), columns=['1'])
@param.depends('df', watch=True)
def set_plot(self):
self.plot = hvPlot(self.df)
@param.depends('df', watch=True)
def dashboard(self):
return self.plot()
b = Plot(name="Plot")
app = pn.panel(b.dashboard)
server = app.show(threaded=False)
在此示例中,每次更改数据框时都会重新绘制整个图(例如,每次都会重置缩放...)。对情节外观的进一步更改将需要额外的回调。
如果只有数据发生变化,您将返回 Streams。在这里,我将从 切换hvplot
到holoviews
,在我看来,它为 Streams 提供了一个更简单的接口(holoviews - 响应事件)。
第一种方法改为
import holoviews as hv
from holoviews.streams import Stream, param
import numpy as np
import pandas as pd
import param
import panel as pn
import tornado
# returns an hv.Overlay of hv.Curves for each column
# in a given data frame
def interactive_df(df):
curve_list = []
for column in df.columns.values:
curve_list.append(hv.Curve(df[column]))
overlay = hv.Overlay(curve_list)
return overlay
class Plot2(param.Parameterized):
df = param.DataFrame(precedence=-1)
DF = Stream.define('DF', df=df) # definition of a stream class, source is df
streamdf = DF() # instance of the stream class 'DF'
# stream data are provided to a dynamic map
dmap = hv.DynamicMap(interactive_df, streams=[streamdf])
def __init__(self, **params):
super(Plot2, self).__init__(**params)
self.generate_df() # create a first random dataframe
self.set_plot() # create a first plot with our new dataframe
self.cb = tornado.ioloop.PeriodicCallback(self.generate_df, 1000, .2)
self.cb.start() # start the callback
# self.callback.stop () ## In this example not implemented, callback runs indefinitely
def generate_df(self):
self.df = pd.DataFrame(np.random.randint(90,100,size=(100, 1)), columns=['1'])
@param.depends('df', watch=True)
def set_plot(self):
self.dmap.event(df=self.df)
s = Plot2(name="Plot Stream")
app = pn.panel(s.dmap)
server = app.show(threaded=False)
由于只有数据发生变化,因此可以毫无问题地使用框缩放等。
此外:matplotlib的文档说,hold
不推荐使用。