Param.depends() is not reacting on Parameters with "per_instance=False" flag

I guess my issue is either a bug or is very easy to solve, if someone knows how:

Above you see a mini app created by belows self-contained minimal example:
it creates some dummy histograms and shows a DropDown widget to select and visualize a single histogram.

Further, each Histogram object has the Boolean param.Parameter normed.
Changing normed triggers a new histogram calculation (norming the y-axis/density) and updates the plot correspondingly. (I love param+panel+holoviews)

Each Histogram has it’s own normed Parameter, but what I need is a “global” normed, affecting all Histogram() instances.

Trying that with the per_instance=False flag and/or with param.shared_parameters() achieves this but prevents param.depends("normed") from triggering the corresponding function and updating the DynamicMap.

How can I achieve aboves working behaviour WITH a global normed Parameter?
It still is important to me, that normed is a Parameter of the Histogram() class!

The following code produces aboves minimal example.
Add per_instance=False in the normed param.Boolean definition and re-run the code, to see what I mean by " prevents param.depends("normed") from triggering".

import numpy as np
import holoviews as hv
import param
import panel as pn
hv.extension("bokeh")
pn.extension()

class Histogram(param.Parameterized):
    normed: bool = param.Boolean(True) #! PUTTING per_instance=False HERE, PREVENTS Histogram.show() TO BE TRIGGERED
        
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.data = np.random.normal(loc=0, scale=5, size=1000)
    
    def calculate_histogram(self):
        np_hist = np.histogram(self.data, bins=50, density=self.normed)
        y_label = "Frequency (normed)" if self.normed else "Frequency"
        return hv.Histogram(np_hist).opts(ylabel=y_label, framewise=True)
        
    @param.depends("normed")
    def show(self, **kwargs):
        return hv.DynamicMap(self.calculate_histogram)


class HistogramContainer:
    def __init__(self, num_histograms=10):
        with param.shared_parameters(): # Having this context manager or not does not change anything
            self.histograms = {f"Histogram_{i+1}": Histogram() for i in range(num_histograms)}
        
def histogram_explorer(histogram_container: HistogramContainer):
    select_histogram = pn.widgets.Select(
            options=[name for name in histogram_container.histograms.keys()],
            name="Histograms",
            width=220,
        )
    
    @pn.depends(hist=select_histogram)
    def show_hist(hist):
        histogram_of_interest = histogram_container.histograms[hist]
        return pn.Column(histogram_of_interest.param.normed, pn.Pane(histogram_of_interest.show))
    
    return pn.Column(select_histogram, show_hist).servable()

my_histograms = HistogramContainer()
histogram_explorer(my_histograms)

Thank you! I appreciate the HoloViz community support a lot.

1 Like

May I ask you @Marc directly, if you have any advice for me?

1 Like

I can also reproduce the behavior. I would recommend reporting it as a bug.

1 Like