Search code examples
pythonpandasbuttonplotly

Plotly Dash function to toggle graph parameters - python


I'm trying to install a function that provides a switch or toggle to alter a plotly graph. Using below, I have a scatter plot and two buttons that intend to change the color and size of the points.

The buttons are applied to the same scatter plot. I can use daq.BooleanSwitch individually on either color or size but I can't use them together on the same two as two calls for id raises an error.

Is it possible two use a button instead? Where it can toggle each parameter on or off. I don't want dropdown bars or distinct buttons as the graph should be able to hold combinations (on/off) for both buttons.

At the moment, the buttons are in place but they don;t alter the color or size of the graph.

import dash
import dash_daq as daq
from dash import dcc, html
import dash_mantine_components as dmc
from dash.dependencies import Input, Output
import plotly.express as px
import plotly.graph_objs as go
import pandas as pd

df = px.data.iris()

color_dict = {'setosa':'green', 'versicolor':'yellow', 'virginica':'red'}
colormap = df["species"].map(color_dict)

app = dash.Dash(__name__)

app.layout = html.Div(
    [
        html.P("Color"),
        #daq.BooleanSwitch(id="color_toggle", on=False, color="red"),
        dmc.Button('Color', id="color_toggle", variant="light"),
        html.P("Size"),
        #daq.BooleanSwitch(id="size_toggle", on=False, color="red"),
        dmc.Button('Size', id="size_toggle", variant="light"),
        html.Div(
            dcc.Graph(id="chart"), 
            #id="power-button-result-1", 
            #id="power-button-result-2"
        ),
    ]
)

@app.callback(
    Output("chart", "figure"),
    #Output("power-button-result-1", "children"),
    #Output("power-button-result-2", "children"),
    [
    Input("color_toggle", "value"),
    Input("size_toggle", "value"),
    ]
)
def update_output(color_on, 
                  size_on,
                  ):

    if color_on:
            fig = px.scatter(df, x="sepal_width", y="sepal_length", color = colormap)
            #dcc.Graph(figure=fig)
            #return [dcc.Graph(figure=fig)]
    else:
            fig = px.scatter(df, x="sepal_width", y="sepal_length")
            #return [dcc.Graph(figure=fig)]
    
    if size_on:
            fig = px.scatter(df, x="sepal_width", y="sepal_length", size = 'sepal_length')
            #dcc.Graph(figure=fig)
            #return [dcc.Graph(figure=fig)]
    else:
            fig = px.scatter(df, x="sepal_width", y="sepal_length")
            #return [dcc.Graph(figure=fig)]
    
    return fig


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

enter image description here


Solution

  • It appears that you need the toggles for the Size and the Color.

    In that case, you can take advantage of dcc.checklist() in your html and style it.

    This code would most likely work, run it and see:

    app.layout = html.Div(
        [
            html.P("Toggle for the Color"),
            dcc.Checklist(
                id="color_toggle",
                options=[{"label": "", "value": True}],
                value=[],
                inline=True
            ),
            html.P("Toggle for the Size"),
            dcc.Checklist(
                id="size_toggle",
                options=[{"label": "", "value": True}],
                value=[],
                inline=True
            ),
            html.Div(
                dcc.Graph(id="chart"),
            ),
        ]
    )
    
    

    Then you don't need the if and else statements in the update_output(). For that, you can just call the update_traces() method.

        if color_on:
            fig.update_traces(marker=dict(color=colormap))
    
        if size_on:
            fig.update_traces(marker=dict(size=10))
    

    Code

    import dash
    from dash import dcc, html
    from dash.dependencies import Input, Output
    import plotly.express as px
    import pandas as pd
    
    df = px.data.iris()
    color_dict = {'setosa': 'green', 'versicolor': 'yellow', 'virginica': 'red'}
    colormap = df["species"].map(color_dict)
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div(
        [
            html.P("Toggle for the Color"),
            dcc.Checklist(
                id="color_toggle",
                options=[{"label": "", "value": True}],
                value=[],
                inline=True
            ),
            html.P("Toggle for the Size"),
            dcc.Checklist(
                id="size_toggle",
                options=[{"label": "", "value": True}],
                value=[],
                inline=True
            ),
            html.Div(
                dcc.Graph(id="chart"),
            ),
        ]
    )
    
    
    @app.callback(
        Output("chart", "figure"),
        [Input("color_toggle", "value"), Input("size_toggle", "value")]
    )
    def update_output(color_on, size_on):
        fig = px.scatter(df, x="sepal_width", y="sepal_length")
    
        if color_on:
            fig.update_traces(marker=dict(color=colormap))
    
        if size_on:
            fig.update_traces(marker=dict(size=10))
    
        return fig
    
    
    if __name__ == "__main__":
        app.run_server(debug=False)
    
    

    Notes: