I made a class to explore and train models.
When I change the value of dropdown 'choose_model_type' in the code example below, I would expect nothing to change in my dashboard, since there are no @param.depends('choose_model_type', watch=True)
in my class.
However, my dashboard gets updated, when I change the value of dropdown 'choose_model_type'. In this case function plot_y() gets triggered twice if I look at the logs:
2019-09-26 11:24:42,802 starting plot_y
2019-09-26 11:24:42,825 starting plot_y
This is for me unexpected behavior. I don't want plot_y() to be triggered when I change 'choose_model_type'.
How do i make sure that plot_y gets triggered only when 'y' changes (and my plot is updated in the dashboard) and not when other parameters such as dropdown change?
I want to control what gets triggered when, but for me there seems to be some magic going on.
Other related question is:
Why does plot_y() get triggered twice? If I change 'pred_target' it also triggers plot_y() twice. Same happens when I change the value of 'choose_model_type': plot_y() gets triggered twice.
# library imports
import logging
import numpy as np
import pandas as pd
import hvplot
import hvplot.pandas
import holoviews as hv
from holoviews.operation.datashader import datashade, dynspread
hv.extension('bokeh', logo=False)
import panel as pn
import param
# create some sample data
df = pd.DataFrame(np.random.choice(100, size=[50, 2]), columns=['TARGET1', 'TARGET2'])
# class to train my models with some settings
class ModelTrainer(param.Parameterized):
logging.info('initializing class')
pred_target = param.Selector(
default='TARGET1',
objects=['TARGET1', 'TARGET2'],
label='Choose prediction target'
)
choose_model_type = param.Selector(
default='LINEAR',
objects=['LINEAR', 'LGBM', 'RANDOM_FOREST'],
label='Choose type of model',
)
y = df[pred_target.default]
# i expect this function only to be triggered when pred_target changes
@param.depends('pred_target', watch=True)
def _reset_variables(self):
logging.info('starting reset variables')
self.y = df[self.pred_target]
# i expect plot_y() only to be triggered when y changes
@param.depends('y', watch=True)
def plot_y(self):
logging.info('starting plot_y')
self.y_plot = dynspread(datashade(self.y.hvplot.scatter()))
return self.y_plot
model_trainer = ModelTrainer()
# show model dashboard
pn.Column(
pn.Row(model_trainer.param['pred_target']),
pn.Row(model_trainer.param['choose_model_type']),
pn.Row(model_trainer.plot_y)
).servable()
The problem here is one of validation, specifically the issue is here: @param.depends('y', watch=True)
. y
is not a parameter in your example, therefore param.depends can't resolve it and ends up falling back to depending on all parameters. I've filed an issue to resolve this here. If you change your example to:
y = param.Series(default=df[pred_target.default])
It will work, however you will still have the issue with the callback being called twice. This is because you have set watch=True
in the depends declaration. Setting watch=True
only makes sense for methods that have side-effects, if your method is something that returns a value then it will rarely make sense to set it. To expand on that, when you pass the method to panel, e.g. pn.Row(model_trainer.plot_y)
, it will automatically watch the parameters and call the method to update the plot when the parameters change.