2

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

2
  • 1
    update your question to include your sample data as markdown instead of an image. print(df_test.to_markdown()) and paste markdown into question Commented Jul 21, 2021 at 14:08
  • 1
    Apologies I didn't know that was possible thanks for the pointer. I believe I have done that now. Commented Jul 21, 2021 at 14:16

1 Answer 1

3
  • 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")
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you very much Rob this is really helpful. After I posted the problem I started to realise why is wasn't working and after studying the way the buttonlists are generated I figured out that as you stated that the updatemenus are static and separate meaning they are not talking to each other. My understanding of Dash is that the outputs can not be saved to a HTML file for sharing which is what I need to be able to do.
I have included dash solution - as you can see it becomes very simple...
Thanks again it is indeed much easier, however as the output is not easy to share via email (sharing the code it not an option) it would be tricky to use this in my project.
it should be quite simple to deploy to azure, GCP or AWS
Yeah I am sure it is but I am not allowed to use those services. Really thanks for your help though it has been brilliant. Cheers

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.