Callbacks multiplying from param depends

I am trying to create fade effect in my panel app. When I click a button, it should highlight some things being displayed, then the highlight should fade away. I have this effect “working” in the code below, but it’s multiplying the number of callbacks with every redraw. I can’t see why it would be doing this.

import panel as pn
import time
import param

pn.extension()

class CallbackTest(param.Parameterized):

    redraw_trigger = param.Integer(default=0)

    def __init__(self,**params):
        super().__init__(**params)
        self.background = pn.widgets.TextInput(value='#ffffff', placeholder='#ffffff')

        # create validate button
        self.validate_button = pn.widgets.Button(
            name='Validate', button_type='primary', width=150, height=40)
        # connect callback to button
        self.validate_button.on_click(self.on_click_validate)
        
        self.background_fade_series = ['#3399ff', '#4da6ff', '#66b3ff', '#80bfff', '#99ccff', '#b3d9ff', '#cce6ff', '#e6f2ff']

        
    def run_aftereffect(self):
        wait_time = 0.02
        for color in self.background_fade_series:
            # wait
            time.sleep(wait_time)
            # change color
            self.background.value = color
            print('redraw_trigger 1')
            self.redraw_trigger += 1
        
        # return background color to default
        self.background.value = self.background.placeholder
        print('redraw_trigger 2')
        self.redraw_trigger += 1

    def on_click_validate(self, event):
        """callback for validate button"""
        print('validate button clicked')
        print(event)
        
        if event.what == "value" \
                and event.type == "changed":
            self.background.value = self.background_fade_series[0]
            self.run_aftereffect()

    def view_post_date(self):
        return pn.pane.Markdown('post date', background=self.background.value)


    @param.depends('redraw_trigger')
    def view_label(self):
        print('view label')
        
        view_properties = pn.pane.Markdown('properies', background=self.background.value)

        label = pn.Column(
            pn.Row(
                pn.pane.Markdown(
                    'article number',
                    style={'font-size': "16pt"},
                    background=self.background.value,
                ),
            ),
            view_properties,
            pn.pane.Markdown(
                'production number',
                style={'font-size': "8pt", "vertical-align": "bottom"},
                background=self.background.value,
            ),

        )
        return label
        
        
    def layout(self):
        """create the entire dashboard layout"""
        return pn.Column(
            pn.Row(
                pn.Column(
                    self.view_post_date,
                ),
                self.validate_button,
            ),
            self.view_label,
        )

    def panel(self):
        """visualize the entire dashboard"""
        return pn.panel(self.layout)

ct = CallbackTest()
ct.panel()

I have rebuilt this several times over with various combinations of param and panel and I can’t figure it out. The print output from clicking the validate button looks like this:

Python callback returned following output: 
	validate button clicked
	Event(what='value', name='clicks', obj=Button(button_type='primary', clicks=1, height=40, name='Validate', sizing_mode='fixed', width=150), cls=<class 'panel.widgets.button.Button'>, old=0, new=1, type='changed')
	redraw_trigger 1
	view label
	view label
	view label
	redraw_trigger 1
	view label
	view label
	view label
	view label
	redraw_trigger 1
	view label
	view label
	view label
	view label
	view label
	redraw_trigger 1
	view label
	view label
	view label
	view label
	view label
	view label
	redraw_trigger 1
	view label
	view label
	view label
	view label
	view label
	view label
	view label
	redraw_trigger 1
	view label
	view label
	view label
	view label
	view label
	view label
	view label
	view label
	redraw_trigger 1
	view label
	view label
	view label
	view label
	view label
	view label
	view label
	view label
	view label
	redraw_trigger 1
	view label
	view label
	view label
	view label
	view label
	view label
	view label
	view label
	view label
	view label
	redraw_trigger 2
	view label
	view label
	view label
	view label
	view label
	view label
	view label
	view label
	view label
	view label
	view label

Any ideas?

The solution - call the layout method:

def panel(self):
        """visualize the entire dashboard"""
        return pn.panel(self.layout())
1 Like