pythonpyvizholoviz

With pyviz/panel, how do I modify values in panes only when a button is clicked?


I'd like to make a dashboard with pyviz/panel so that it doesn't refresh live as soon as the values of the widgets are changed. Instead, I'd like for it to wait for a button click and only then, change the values in the dashboard accordingly.

A minimal working example is as follow. Here I'd like to generate some random numbers every time the button is clicked, but it doesn't seem to do anything.

In my real-world task, I would hit the database to get a few rows of data, based on the input widgets. I imagine that it could work the same way?

import numpy as np
import pandas as pd

import param

import panel as pn
pn.extension()

class UserDash(param.Parameterized):
    mean = pn.widgets.IntSlider(value=10, start=0, end=100)
    output_pane = pn.widgets.TextInput(value='Ready')
    button = pn.widgets.Button(name='Generate', button_type='primary')
    button.on_click(output_pane)

    @param.depends('button')
    def output_pane(self):
        print(self.mean.value)
        df = pd.DataFrame({'x': np.random.normal(int(self.mean.value), 1, 5)}, index=range(5))
        return df

    def panel(self):
        return pn.Column(self.mean, self.button, self.output_pane)

dash = UserDash()
dash.panel().servable()

I am using panel 0.6.0, running on Jupyter 6.0.0. Thanks!


Solution

  • Since you are creating a parameterized Class, you can't use pn.widgets().
    Your variables and buttons to select and generate values need to be params too.
    I've adjusted your example by changing variable 'mean' to a param.Integer() and 'button' to param.Action().

    More info on using params can be found here: https://panel.pyviz.org/user_guide/Param.html

    # import libraries
    import numpy as np
    import pandas as pd
    import param
    import panel as pn
    pn.extension()
    
    # instead of pn.widgets I'm using param.Integer() and param.Action() to create your variables
    class UserDash(param.Parameterized):
        mean = param.Integer(default=10, bounds=(0, 100))
        button = param.Action(lambda x: x.param.trigger('button'), label='Generate')
    
        @param.depends('button')
        def output_pane(self):
            return pd.DataFrame({'x': np.random.normal(int(self.mean), 1, 5)}, index=range(5))
    
        def panel(self):
            return pn.Column(
                self.param['mean'], 
                self.param['button'], 
                self.output_pane
            )
    
    # create instance of dashboard
    dash = UserDash()
    dash.panel().servable()
    

    The following question/answer on the use of buttons is also helpful here I think:
    https://stackoverflow.com/questions/57970603/use-button-to-trigger-action-in-panel-with-parameterized-class-and-when-button-a