Search code examples
pythonplotlyplotly-dash

Need help on plotly dash python callback with input, out, button, graph


I'm new at plotly dash python. I need help updating the graph after input value and clicking the Set button. I tried many ways but I can't make it right. Also, the refresh button is to refresh the graph back to 0 input value. I'm so stuck here. Do I have to update the graph after the input or just update the value?

from dash import html, Dash, dcc, Input, Output, State
import plotly.express as px
import pandas as pd



app = Dash(__name__)



df = pd.DataFrame({
    "Minimum/Maximum":["Minimum", "Maximum"],
    "Numbers of Beat": [2,60]
    })
fig = px.bar(df, x = "Minimum/Maximum", y = "Numbers of Beat", color="Minimum/Maximum")

app.layout = html.Div(
    children=[
    html.H1(children= 'HTML Dashboard Application'),
    html.Div(children= 
             '''
             Dash: Minimum/Maximum Bar Graph
             '''),
    dcc.Graph(
        id='dash_graph',
        figure = fig
        ),
    html.Div(dcc.Input(placeholder='Enter a min value...' ,id='min_value', type='text')),
    html.Div(dcc.Input(placeholder='Enter a max value...' ,id='max_value', type='text')),
    html.Button(id='Set-val', n_clicks=0, children= 'Set'),
    html.Button(id='Refresh_current_BPM', n_clicks=0, children= 'Refresh'),
    ])
             
@app.callback(
    Output('dash_graph', 'figure'),
    Input('Set-val', 'n_clicks'),
    State('min_value', 'value'),
    State('max_value', 'value')
)
def update_value(min_value, max_value, n_clicks):
    #new value should appear in the graph here
    return fig
    
    
    

if __name__ == '__main__':
    app.run_server(debug = True)

Solution

  • I need help updating the graph after input value and clicking the Set button. I tried many ways but I can't make it right.

    You have the design right for your callback (although in your provided code, you mixed the order of the arguments). You just have to reconstruct the dataframe with the appropriate values you capture from the inputs. Since you pass both inputs min and max to the callback, you can reconstruct the dataframe, pass that into the plotly figure and return it back to the dcc.Graph component.

    Also, the refresh button is to refresh the graph back to 0 input value. I'm so stuck here. Do I have to update the graph after the input or just update the value?

    You want to refresh the graph so that both subplots are zero, in which case you have 2 options:

    1. You can set the inputs back to 0 in a new callback, which in turn will trigger the original callback you have and set the graphs to 0.

    2. In your original callback, use dash.ctx.triggered to establish which button was clicked on, then set the dataframe values to 0 for both min and max.

    The first solution might be more elegant in terms of design.

    Here is an example modified from original code:

    from dash import html, Dash, dcc, Input, Output, State
    import plotly.express as px
    import pandas as pd
    import dash
    
    app = Dash(__name__)
    
    df = pd.DataFrame({
        "Minimum/Maximum":["Minimum", "Maximum"],
        "Numbers of Beat": [2,60]
        })
    fig = px.bar(df, x = "Minimum/Maximum", y = "Numbers of Beat", color="Minimum/Maximum")
    
    app.layout = html.Div(
        children=[
        html.H1(children= 'HTML Dashboard Application'),
        html.Div(children= 
                 '''
                 Dash: Minimum/Maximum Bar Graph
                 '''),
        dcc.Graph(
            id='dash_graph'
        ),
        html.Div(dcc.Input(placeholder='Enter a min value...', id='min_value', type='number', value=0)),
        html.Div(dcc.Input(placeholder='Enter a max value...', id='max_value', type='number', value=0)),
        html.Button(id='Set-val', n_clicks=0, children= 'Set'),
        html.Button(id='Refresh_current_BPM', n_clicks=0, children= 'Refresh'),
        ])
                 
    @app.callback(
        Output('dash_graph', 'figure'),
        State('min_value', 'value'),
        State('max_value', 'value'),
        Input('Set-val', 'n_clicks'),
        Input('Refresh_current_BPM', 'n_clicks'),
    
    )
    def update_value(min_value, max_value, *_):
        # check if a button was triggered, if not then just render both plots with 0
        ctx = dash.callback_context
        if ctx.triggered:
            # grab the ID of the button that was triggered
            button_id = ctx.triggered[0]['prop_id'].split('.')[0]
            # if the button that was triggered is the refresh one, then set min,max to 0
            # otherwise, the set button was triggered and so carry on normally
            if button_id == "Refresh_current_BPM":
                min_value = 0
                max_value = 0
    
        df = pd.DataFrame({
        "Minimum/Maximum":["Minimum", "Maximum"],
        "Numbers of Beat": [min_value, max_value]
        })
        fig = px.bar(df, x = "Minimum/Maximum", y = "Numbers of Beat", color="Minimum/Maximum")
        return fig
    
    if __name__ == '__main__':
        app.run_server(debug = True)
    

    NOTE

    Try not to use a global dataframe or variable in your dash app. What I did in the example is set the inputs to a default of 0, and just construct the graph in the callback that will be triggered upon the initial loading of the app.