I am working on a script that periodically updates and plots a dataset using Holoviews and Panel. The script is designed to allow dynamic selection of the y-axis for the plot. However, I am encountering an issue where the axis selection does not respond to changes in the col_selector widget.
import pandas as pd
import numpy as np
import panel as pn
import hvplot.pandas
import param
import holoviews as hv
import datetime as dt
import time
pn.extension()
columns = list('XYZ')
def create_df():
return pd.DataFrame(columns=columns,data=np.random.randn(20,3))
class Selector(hv.streams.Stream):
y = param.Selector(objects='YZ',default='Y')
col_selector = Selector()
dfstream = hv.streams.Buffer(data=pd.DataFrame(columns=columns),length=90,index=False)
dfstream.send(create_df())
colormap = dict(zip(['Y','Z'],hv.Cycle('Category10').values))
def plot(data,y):
scatter = data.hvplot.scatter(x='X',y=y,c=colormap[y],xlim=(-5,5),ylim=(-5,5),grid=True)
return scatter+hv.operation.histogram(scatter).opts(color=colormap[y])
dmap = hv.DynamicMap(plot, streams=[dfstream,col_selector])
latest_update = pn.widgets.StaticText()
def update_plot():
latest_update.value = f'updating: {dt.datetime.now().strftime("%c")}'
time.sleep(0.5)
dfstream.send(create_df())
latest_update.value = f'latest: {dt.datetime.now().strftime("%c")}'
cb = pn.state.add_periodic_callback(update_plot, period=1000, start=False)
button = pn.widgets.Button(name = 'Click to Start', button_type = 'success')
def button_click(event):
if button.name == 'Click to Start':
print('started')
cb.start()
button.name = 'Click to Stop'
button.button_type = 'danger'
else:
print('stopped')
cb.stop()
button.name ='Click to Start'
button.button_type = 'success'
button.on_click(button_click)
pn.Column(
button,
pn.Param(col_selector),
pn.Column(
dmap
),
latest_update
)
This script uses two streams (dfstream and col_selector) for the DynamicMap update. The dfstream is updated periodically by the update_plot function, and the col_selector allows the user to select the y-axis for the plot. However, the plot does not update to reflect changes in the col_selector widget.
In general, I’ve struggled to combine buffer updates with other updates. Seems it should be possible, but all my attempts so far failed at some point.
Any help would be appreciated.
The reason I’m using this unusual streams object is because I can’t seem to figure out how to combine actual streams objects like Buffer and normal widgets as arguments in the DynamicMap call.
The error occurs for a Buffer in a dict-type argument for hv.DynamicMap and I’m hoping to use a Buffer for periodic updating. Panel widgets and dict-type arguments work just fine, but not what I need.
col_selector = pn.widgets.Select(options=list('YZ'))
data = pn.widgets.DataFrame(value=create_df()) # replace buffer with panel widget
# update this
dmap = hv.DynamicMap(plot, streams=dict(data=data,y=col_selector))
Since Buffer arguments error as the dict-type arguments, I was trying to create streams-list like argument for widgets. Hence the class Selector(hv.streams.Stream) instance. But, as mentioned, these widgets doesn’t seem to trigger updates in the panel.
Any idea how to handle the combination of Streams and widgets?