Solution - Inheritance - Works in Panel 0.9.7
This works and can be instantiated and used as simple as MyCustomWidget(df)
.
import matplotlib.pyplot as plt
import pandas as pd
import panel as pn
import param
import seaborn as sns
class MyCustomWidget(pn.Column):
column = param.Selector()
def __init__(self, data, **params):
self._rename["column"] = None
# Note:
# I need to add _rename of `column` in order to not get the exception
# AttributeError: unexpected attribute 'column' to Column, possible attributes are align, aspect_ratio, background, children, css_classes, disabled, height, height_policy, js_event_callbacks, js_property_callbacks, margin, max_height, max_width, min_height, min_width, name, rows, sizing_mode, spacing, subscribed_events, tags, visible, width or width_policy
# The reason is that the code of Column tries to map every parameter on the class to a property on the underlying bokeh model.
# and `column` is not a property on the underlying bokeh model.
super().__init__(**params)
self._plot_pane = pn.pane.Matplotlib(background="blue", width=300, height=300)
self[:] = [self.param.column, self._plot_pane]
self.param.watch(self._update_plot_pane, "column")
# Note: Setting @param.depends("column", watch=True) on _update_plot_pane does not work.
columns = data.columns.values
self.param.column.objects = columns
self.column = columns[0]
# Note: I need to set self.column to show a plot initially
def _update_plot_pane(self, _):
plt.close()
# Note:
# - I get exception if plt.close is below ax line. See https://github.com/holoviz/panel/issues/1482
# - The plot does not change if I remove plot.close() fully.
ax = sns.distplot(df[self.column])
self._plot_pane.object = ax.figure
df = pd.DataFrame(data={"x": [1, 2, 3, 4, 5, 6, 7], "y": [1, 2, 2, 4, 5, 9, 7]})
MyCustomWidget(df).servable()
Pros
- Simple, natural way of constructing and using an instance of the component
Cons
- The implementation is not a simple and flexible as it should be.
- I need to
_rename
my custom parameters. -
@param.depends("column", watch=True)
is not working.- I need to use
self.param.watch
instead.
- I need to use
- I cannot use
objects
like strings or plots inself[:]
.- I need to use layouts, panes or widgets in
self[:]
- I need to use layouts, panes or widgets in
- The order of
watch
,plot_pane
,self.column=
matters.- (
self.column=
should be below the two others). - Could lead to confusion and questions from new Panel developers.
- (
- I need to
- A user could in fact change the content of the column after construction.
For me this is the way to do it. And the cons above should be removed or minimized.
WHAT DO YOU THINK?