MrObvious
MrObvious

Reputation: 35

Plotly express multiple dropdown menus in python

I am wondering if someone would be able to help me out. I have searched loads of answers on multiple website to get me where I am and I believe I am close to an answer but am struggling with the last bit.

I am trying to make an interactive graph using plotly express

I have a dataframe that looks like this:

num label color value1 value 2 value3
0 1 A red 0.4 4 40
1 2 A blue 0.2 2 20
2 3 A green 0.3 3 30
3 4 A red 0.6 6 60
4 5 A blue 0.7 7 70
5 6 A green 0.4 4 40
6 7 B blue 0.2 2 20
7 8 B green 0.4 4 40
8 9 B red 0.4 4 40
9 10 B green 0.2 2 20
10 11 C red 0.1 1 10
11 12 C blue 0.3 3 30
12 13 D red 0.8 8 80
13 14 D blue 0.4 4 40
14 15 D green 0.6 6 60
15 16 D yellow 0.5 5 50

I would like to plot a graph in plotly that has two dropdown menu's, one that controls which value is being plotted and the other that controls which color is being plotted so for example if the dropdowns said: red and value1, I would get a bar graph of only that data.

My current code is as follow and it sort of works but I am getting values appearing on the graph when I change the color settings.

#Import the dataframe
df_test = pd.read_csv('test.csv')

#Plot a figure using plotly express
fig = px.bar(df_test,  y="value1", )

#Create a button list for the value columns
buttonlist = []
for col in df_test.columns[3:]:
      buttonlist.append(
        dict(
            args=['y',[df_test[str(col)]] ],
            label=str(col),
            method='restyle'
        )
      )

#Create a button list for the colors
buttonlist2 = []
for p in df_test['color'].unique():
      buttonlist2.append(
        dict(
            args=['y',[df_test[df_test['color']==p]]],
            label= 'Color ' + str(p),
            method='restyle'))      

#Update the layout to include the dropdown menus, and to show titles etc
fig.update_layout(title="Test",
      yaxis_title="value",
      xaxis_title="Color",
    updatemenus = [
   dict(buttons = buttonlist, showactive = True),
   dict(buttons = buttonlist2, showactive = True, y = 0.9)
   ])

#Show the figure
fig.show()

Any help would be appreciated

Thanks

Upvotes: 2

Views: 4723

Answers (1)

Rob Raymond
Rob Raymond

Reputation: 31226

  • updatemenus are static and each dropdown is independent. Hence to provide a facade of being dynamic and linked, build a static structure that does this
  • below code shows this, but does not rebuild column selector
  • IMHO, it's much simpler to switch to dash where it becomes very simple to interact with a figure using callbacks to implement your desired behaviour
fig = px.bar(
    df_test,
    y="value1",
)

# Create a button list for the value columns
buttonlist = [
    {
        "args": [
            {
                "y": [df_test.loc[df_test["color"].eq("red"), col]],
                "updatemenus": [
                    {"buttons":[{"label":"Back","method":"relayout","args":[{}]}]},
                    {
                        "buttons": [
                            {
                                "label": f"Color {c}",
                                "method": "restyle",
                                "args": [
                                    {"y": [df_test.loc[df_test["color"].eq(c), col]]}
                                ],
                            }
                            for c in df_test["color"].unique()
                        ],
                        "y": 0.9,
                    }
                ],
            }
        ],
        "label": str(col),
        "method": "relayout",
    }
    for col in df_test.columns[3:]
]

# Update the layout to include the dropdown menus, and to show titles etc
fig.update_layout(
    title="Test",
    yaxis_title="value",
    xaxis_title="Color",
    updatemenus=[
        {"buttons":buttonlist, "showactive":True},
    ],
)

using dash

from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import plotly.express as px
import pandas as pd
import io

df_test = pd.read_csv(io.StringIO(""" num label  color  value1  value2  value3
   1     A    red     0.4        4      40
   2     A   blue     0.2        2      20
   3     A  green     0.3        3      30
   4     A    red     0.6        6      60
   5     A   blue     0.7        7      70
   6     A  green     0.4        4      40
   7     B   blue     0.2        2      20
   8     B  green     0.4        4      40
   9     B    red     0.4        4      40
  10     B  green     0.2        2      20
  11     C    red     0.1        1      10
  12     C   blue     0.3        3      30
  13     D    red     0.8        8      80
  14     D   blue     0.4        4      40
  15     D  green     0.6        6      60
  16     D yellow     0.5        5      50"""), sep="\s+")

# Build App
app = JupyterDash(__name__)

app.layout = html.Div(
    [
        dcc.Dropdown(
            id="color",
            options=[{"label": x, "value": x} for x in df_test["color"].unique()],
            value="red",
        ),
        dcc.Dropdown(
            id="value",
            options=[{"label": x, "value": x} for x in df_test.columns[3:]],
            value="value1",
        ),
        dcc.Graph(id="graph1"),
    ]
)


@app.callback(
    Output("graph1", "figure"),
    Input("color", "value"),
    Input("value", "value"),
)
def update_graph1(color, value):
    print(color, value)
    return px.bar(df_test.loc[df_test["color"].eq(color)], y=value)


# Run app and display result inline in the notebook
app.run_server(mode="inline")

Upvotes: 3

Related Questions