I am streaming random data into a plotly bar plot. The stream is switched through a Toggle widget, defined through the params of a Parametrized class. Here the code:
import param
import numpy as np
import pandas as pd
import panel as pn
import plotly.graph_objects as go
import plotly.express as px
import seaborn as sns
from dataclasses import dataclass, field
from datetime import datetime
pn.extension("plotly", sizing_mode="stretch_width")
param_wdgt_dct = {"update_data": pn.widgets.Button, "toggle_stream":{"widget_type": pn.widgets.Toggle, "button_style": "outline", "button_type": "primary"}}
class PanelClass(param.Parameterized):
num = param.Integer(default=1)
df = param.DataFrame(precedence=-1, default=pd.DataFrame(np.zeros((7,4)), columns=list('ABCD')))
update_data = param.Action(default=lambda x: x.param.trigger('update_data'))
toggle_stream = param.Boolean(default=False)
plot_output:pn.pane.Plotly
stream_callback:pn.io.PeriodicCallback
def __init__(self, **params):
super().__init__(**params)
self.update_df()
fig, fig_patch = self.generate_figure()
self.plot_output = pn.pane.Plotly(fig_patch)
self.stream_callback = pn.state.add_periodic_callback(self.update_df, period= self.num * 1000, start=self.toggle_stream)
def generate_figure(self):
indo = self.df.index.to_series().apply(str).tolist()
palette = sns.color_palette("hls", n_colors=len(indo)).as_hex()
pal_dct = {kkk:vvv for kkk, vvv in enumerate(palette)}
traccio = go.Bar(
x=self.df.A,
y=indo,
orientation='h',
marker_color=[pal_dct[int(eee)] for eee in indo],
)
fig = None
# fig = go.Figure()
# fig.add_trace(traccio)
fig_patch = dict(data=[traccio], layout=go.Layout())
return fig, fig_patch
@param.depends("toggle_stream", watch=True)
def start_streamo(self):
self.stream_callback.running = self.toggle_stream
@param.depends("update_data", watch=True)
def update_df(self):
self.df += pd.DataFrame(np.random.randint(0,10,size=(7, 4)), columns=list('ABCD'))
self.df.sort_values("A", inplace=True)
@param.depends("num", watch=True)
def change_stream_pace(self):
self.stream_callback.period = self.num * 1000
@param.depends("df", watch=False)
def view(self):
tmp_arro = []
tmp_arro.append(pn.pane.HTML(f"<h2>Last update:{datetime.now()}</h2>"))
tmp_arro.append(self.df)
fig, fig_patch = self.generate_figure()
self.plot_output.object = fig_patch
return pn.Column(*tmp_arro)
tmplt = pn.template.BootstrapTemplate()
insto = PanelClass(num=1)
insto_1 = PanelClass(num=5)
tmplt.sidebar.append(pn.Param(insto.param, widgets=param_wdgt_dct))
tmplt.sidebar.append(pn.Param(insto_1.param, widgets=param_wdgt_dct))
tmplt.main.append(pn.Row(insto.plot_output, insto_1.plot_output))
tmplt.main.append(pn.Row(insto.view, insto_1.view))
tmplt.servable()
It works already rather well, what I wanted to reach is about changing the Toggle button_type depending on its value, e.g. success if True and danger if False. What I tried is to define an instance element of the class called toggle_view, initialise it in the init method as a pn.Param from self.toggle_stream, and then display into an according layout. This way the Toggle widget is still related to the events of each self.toggle_stream. Then I tried to change its properties in the start_streamo method, but I have no idea how to access the widget properties, since it is somewhere into the pn.Param object.
Any suggestion how to do that?