Hello,
I want to customize widgets of different Selectors that I create inside a Param inherited class.
The idea is to create a class for the selector and then create a selector object inside a dashboard class as in awesome-panel.
Here is the Selector class :
class TimePeriodSelector(param.Parameterized):
settings_panel = param.Parameter(doc="A panel containing the settings of the LoadingStyler")
countries = param.ObjectSelector(default="ALL", objects=["ALL"])
time_period_type = param.ObjectSelector(default="Month", objects=["Week", "Month", 'Aggregates'])
time_period = param.ObjectSelector(default="ALL", objects=["ALL"])
suppliers = param.ObjectSelector(default="ALL", objects=["ALL"])
channels = param.ObjectSelector(default="ALL", objects=["ALL"])
sub_channels = param.ObjectSelector(default="ALL", objects=["ALL"])
classes = param.ObjectSelector(default="ALL", objects=["ALL"])
categories = param.ObjectSelector(default="ALL", objects=["ALL"])
sub_categories = param.ObjectSelector(default="ALL", objects=["ALL"])
brands = param.ObjectSelector(default="ALL", objects=["ALL"])
cpg_table = param.String()
cpg_country = param.String()
panels = param.List()
loading = param.Boolean(default=False, doc="""Whether or not to show the loading indicator""")
view = param.Parameter()
styler = param.ClassSelector(class_=LoadingStyler)
def __init__(self, BQHandler: BQSalesEvolutionDup, **params):
self.build_distinct_fields(self.distinct_fields)
super().__init__(**params)
self.settings_panel = pn.Param(
self,
parameters=[
"countries",
"time_period_type",
"time_period",
"suppliers",
"channels",
"sub_channels",
"classes",
"categories",
"sub_categories",
"brands"
],
widgets={'countries': pn.widgets.MultiChoice,
'time_period_type': pn.widgets.RadioButtonGroup,
"time_period": pn.widgets.MultiSelect,
"suppliers": pn.widgets.MultiSelect,
"channels": pn.widgets.MultiSelect,
"sub_channels": pn.widgets.MultiSelect,
"classes": pn.widgets.MultiSelect,
"categories": pn.widgets.MultiSelect,
"sub_categories": pn.widgets.MultiSelect,
"brands": pn.widgets.MultiSelect}
)
self.style_panel = pn.pane.HTML(sizing_mode="fixed", width=0, height=0, margin=0)
def view():
"""Returns the app in a Template"""
pn.config.sizing_mode = "stretch_width"
template = pn.template.FastListTemplate(title="Loading Spinners")
app = TimePeriodSelector(name="Filters")
pn.Param(app.param, )
template.sidebar[:] = [app.settings_panel]
if not issubclass(template.theme, pn.template.base.DefaultTheme):
app.styler.background_rgb = (0, 0, 0)
return template
if __name__.startswith("bokeh"):
view().servable()
And here is the dashboard class in a dashboard.py file:
class Dashboard(BaseDashboard):
selector = param.ClassSelector(class_=TimePeriodSelector)
barplot = param.ClassSelector(class_=OverlappingBarplot)
panels = param.List()
"""An app which shows the sales evolution"""
def __init__(self, BQHandler: BQSalesEvolutionDup, **params):
super().__init__(**params)
self.selector = TimePeriodSelector(self.BQHandler)
self.x_axis_data, self.month_year = self.get_x_axis_data()
# BarPlot
self.barplot = OverlappingBarplot(x_axis_data=self.x_axis_data, title="Sales", tooltips="""
<b>Sales yag: </b> @yag{(0.0 a)}€ <br>
<b>Sales current year: </b> @current{(0.0 a)}€
""")
self.plots = [self.barplot]
self.panels = [
self.barplot.figure
]
self.settings_panel = pn.Column(
pn.Param(self, parameters=["refresh_data"]),
pn.pane.Markdown("## Settings"),
self.selector.settings_panel,
width=400,
sizing_mode="fixed"
)
self.main = pn.Column(*self.panels, sizing_mode="stretch_both")
self._refresh_data()
self.view = pn.Row(self.main, self.settings_panel)
@site.add(APPLICATION)
def view():
"""Returns the app in a Template"""
pn.config.sizing_mode = "stretch_width"
template = pn.template.FastListTemplate(title="Loading Spinners")
# tenant_id = pn.state.session_args["tenant_id"]
tenant_id = "101013"
BQHandler = BQSalesEvolutionDup(tenant_id)
app = Dashboard(BQHandler, name="Sales Evolution Dashboard")
template.main[:] = [app.view]
if not issubclass(template.theme, pn.template.base.DefaultTheme):
app.styler.background_rgb = (0, 0, 0)
return app.view
if __name__.startswith("bokeh"):
view().servable()
When I launch the following command panel serve dashboard.py
, I get this error :
File "__init__.py", line 1423, in _validate_value:
raise ValueError("List parameter %r must be a list, not an object of type %s." Traceback (most recent call last):
[...]
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/param/__init__.py", line 1397, in _validate
self._validate_value(val, self.allow_None)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/param/__init__.py", line 1423, in _validate_value
raise ValueError("List parameter %r must be a list, not an object of type %s."
ValueError: List parameter 'value' must be a list, not an object of type <class 'str'>.
Things I have already tried :
- Remove the widgets dict from the panel.settings variable and put it in pn.param() in the view function → I get no errors but the selectors are not customized.
Am I doing something wrong ?