简体   繁体   中英

How to add a button to a Plotly Express graph to update a specific value?

What I'm Trying To Do...

I am trying to keep the formatting of a Plotly Express Scatterplot for data from the happiness report (2018). I simply want to create a button that can change the x-axis value between certain columns in a pandas dataframe (eg "GDP per Capita", "Social Support", etc.)

Here's an example of the scatter plot I am trying to create a button for to switch the X-value of the graph and have it update accordingly.

df = pd.read_csv("https://media.githubusercontent.com/media/ajgallard/happiness_report/main/data/2018_eng.csv")
fig = px.scatter(df, 
                 x="GDP per capita", # The Value I am creating a button for 
                 y="Score", 
                 size="Population", 
                 color="Continent",
                 hover_name="Country/Region", 
                 size_max=60, 
                 color_discrete_sequence=px.colors.qualitative.G10)
fig.show()

I get the following as a result: Plotly Express Scatter Plot:
Plotly Express 散点图

Attempted Solutions...

I attempted to implement a solution to a similar question from: Build a plotly scatterplot with two drop down buttons one for x and one for y axis

import pandas as pd
import plotly.express as px
import plotly.graph_objects as go

df = pd.read_csv("https://media.githubusercontent.com/media/ajgallard/happiness_report/main/data/2018_eng.csv")

cols = df.columns[2:4].values.tolist() # "GDP per Capita" & "Social Support"

fig = go.Figure()
for col in cols:
    figpx = px.scatter(df,
                       x=col,
                       y="Score",
                       size="Population",
                       color="Continent",
                       hover_name="Country/Region",
                       size_max=60,
                       color_discrete_sequence=px.colors.qualitative.G10).update_traces(visible=False)
    
    fig.add_traces(figpx.data)

fig.update_layout(
    updatemenus=[
        {
            "buttons": 
            [
                {
                    "label": k,
                    "method": "update",
                    "args": 
                    [
                        {"visible": [k for k in cols]},
                    ],
                }
                for k in cols
            ]
        }
    ]
).update_traces(visible=True, selector=0)

fig.show()

Using the above mentioned code I get the following as a result: Plotly Express with Button Attempt:
Plotly Express with Button Attempt

What seems to be happening is that the data is overlayed one on top of the other and the button itself does not update anything data related.

Open to Any Potential Workarounds...

I'm fairly new to implementing Plotly Graphs in my data visualizations and I'm open to any other potential workarounds to get the kind of interactive visualization I was hoping to achieve.

Following the referenced answer, we need to add an element to be updated: the value of the x-axis and the title. As an additional response, the legend has been changed from duplicate to single. I am quoting @A. Donda answer response.

import pandas as pd
import plotly.express as px
import plotly.graph_objects as go

df = pd.read_csv("https://media.githubusercontent.com/media/ajgallard/happiness_report/main/data/2018_eng.csv")

cols = df.columns[2:4].values.tolist() # "GDP per Capita" & "Social Support"

fig = go.Figure()
for col in cols:
    figpx = px.scatter(df,
                       x=col,
                       y="Score",
                       size="Population",
                       color="Continent",
                       hover_name="Country/Region",
                       size_max=60,
                       color_discrete_sequence=px.colors.qualitative.G10).update_traces(visible=False)
    
    fig.add_traces(figpx.data)

fig.update_layout(
    updatemenus=[
        {
            "buttons": 
            [
                {
                    "label": f'{k}',
                    "method": "update",
                    "args": 
                    [
                        {'x': [df[k]]},
                        {'xaxis':{'title':k}},
                        {"visible": k},
                    ],
                }
                for k in cols
            ]
        }        
    ]
).update_traces(visible=True, selector=0)

names = set()
fig.for_each_trace(
    lambda trace:
        trace.update(showlegend=False)
        if (trace.name in names) else names.add(trace.name))

figpx.data[0]['hovertemplate'] = '<b>%{hovertext}</b><br><br>Continent=Europe<br>GDP per capita=%{x}<br>Score=%{y}<br>Population=%{marker.size}<extra></extra>'

fig.show()

在此处输入图片说明

  • there is a core concept with this approach. Need to be able to identify the traces that belong to a column. In this case where color is a categorical there are multiple traces per column
  • added a synthetic column to dataframe dynamically and included in hoverdata Plot . This then means it is in each trace and accessible as customdata[0][0]
  • updatemenus visible then builds truth list based on value in each trace
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go

df = pd.read_csv("https://media.githubusercontent.com/media/ajgallard/happiness_report/main/data/2018_eng.csv")

cols = df.columns[2:4].values.tolist() # "GDP per Capita" & "Social Support"

fig = go.Figure()
for col in cols:
    figpx = px.scatter(df.assign(Plot=col),
                       x=col,
                       y="Score",
                       size="Population",
                       color="Continent",
                       hover_name="Country/Region",
                       hover_data=["Plot"],
                       size_max=60,
                       color_discrete_sequence=px.colors.qualitative.G10).update_traces(visible=False)
    
    fig.add_traces(figpx.data)

fig.update_layout(
    updatemenus=[
        {
            "buttons": 
            [
                {
                    "label": k,
                    "method": "update",
                    "args": 
                    [
                        {"visible": [t.customdata[0][0]==k for t in fig.data]},
                    ],
                }
                for k in cols
            ]
        }
    ]
).update_traces(visible=True, selector=lambda t: t.customdata[0][0]==cols[0] )

fig
  • note Plot in hover, this is customdata[0][0] 在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM