Search code examples
pythonpandasplotlyscatter-plotplotly-express

Build a plotly scatterplot with two drop down buttons one for x and one for y axis


I wish to build a scatter plot but using 2 drop down where I can switch between variables one for x axis and the other for y axis(e.g Total tests and Total cases, or Recent cases and Total cases), i have tried building off a solution i found by replacing

cols_dd = ["Total tests", "Total cases", "Total deaths"]

for value in cols_dd: 

with

cols_dd = {"Total tests":"Total cases", "Total deaths":"Recent cases", "Population":"Total vaccinations"}

k,v in cols_dd.items(): 

and the using k and v in place of values but it returns an error ('dict_keys' object is not subscriptable)

can someone please share a way to achive this, here is my code.

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

# get OWID data
df = pd.read_csv(
    "https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/latest/owid-covid-latest.csv"
)
# rename columns as sample code uses other names....
df = df.rename(
    columns={
        "location": "Location",
        "iso_code": "Iso code",
        "total_tests": "Total tests",
        "people_vaccinated_per_hundred": "Vaccines",
        "new_cases": "Recent cases",
        "total_cases": "Total cases",
        "total_deaths": "Total deaths",
        "total_vaccinations": "Total vaccinations",
        "people_vaccinated": "People vaccinated",
        "population": "Population",
        "total_boosters": "Vaccination policy",
    }
).fillna(0)

cols_dd = {"Total tests":"Total cases", "Total deaths":"Recent cases", "Population":"Total vaccinations"}


fig = go.Figure()

for k,v in cols_dd.items():
    fig.add_traces(px.scatter(df, x=k, y=v, color="Location",
            hover_data={
                "Iso code": False,
                "Vaccines": True,
                "Total tests": ": ,0.f",
                "Recent cases": ": ,0.f",
                "Total cases": ": ,0.f",
                "Total deaths": ": ,0.f",
                "Total vaccinations": ": ,0.f",
                "People vaccinated": ": ,0.f",
                "Population": ": ,0.f",
                "Vaccination policy": ": 0.f",
            },
            color_continuous_scale="spectral_r",
            hover_name="Location",
        )
        .update_traces(visible=(k == list(cols_dd.keys()[0]))
        .data
    ))


fig.update_layout(
    updatemenus=[
        {
            "buttons": [
                {
                    "label": value,
                    "method": "update",
                    "args": [
                        {"visible": [v2 == value for v2 in cols_dd]},
                        {"title": f"<b>{k}</b> vs <b>{v}</b>"},
                    ],
                }
                for k in cols_dd
            ]
        }
    ]
)

Solution

  • You can build all the combinations of variables as both traces and a menu.

    cols_dd = ["Total tests", "Total cases", "Total deaths"]
    hd = {
        "Iso code": False,
        "Vaccines": True,
        "Total tests": ": ,0.f",
        "Recent cases": ": ,0.f",
        "Total cases": ": ,0.f",
        "Total deaths": ": ,0.f",
        "Total vaccinations": ": ,0.f",
        "People vaccinated": ": ,0.f",
        "Population": ": ,0.f",
        "Vaccination policy": ": 0.f",
    }
    
    # px.scatter(df, x="Total cases", y="Total deaths", hover_data=hd, hover_name="Location")
    fig = go.Figure()
    for k, v in itertools.combinations(cols_dd, 2):
        figt = px.scatter(df, x=k, y=v, hover_data=hd, hover_name="Location").update_traces(
            visible=False
        )
        fig = fig.add_traces(figt.data)
    
    fig.update_layout(
        updatemenus=[
            {
                "buttons": [
                    {
                        "label": f"{k} - {v}",
                        "method": "update",
                        "args": [
                            {
                                "visible": [
                                    (k2 == k and v2 == v)
                                    for k2, v2 in itertools.combinations(cols_dd, 2)
                                ]
                            },
                            {"title": f"<b>{k} - {v}</b>"},
                        ],
                    }
                    for k, v in itertools.combinations(cols_dd, 2)
                ]
            }
        ],
        margin={"l": 0, "r": 0, "t": 25, "b": 0},
    ).update_traces(visible=True, selector=0)
    

    independent

    cols_dd = ["Total tests", "Total cases", "Total deaths"]
    
    fig = go.Figure(
        go.Scatter(
            x=df[np.random.choice(cols_dd, 1)[0]],
            y=df[np.random.choice(cols_dd, 1)[0]],
            hovertemplate='x: %{x} <br>y: %{y}',
            mode="markers"
        )
    )
    
    fig.update_layout(
        updatemenus=[
            {
                "buttons": [
                    {
                        "label": f"x - {x}",
                        "method": "update",
                        "args": [
                            {"x": [df[x]]},
                            {"xaxis": {"title": x}},
                        ],
                    }
                    for x in cols_dd
                ]
            },
            {
                "buttons": [
                    {
                        "label": f"y - {x}",
                        "method": "update",
                        "args": [{"y": [df[x]]}, {"yaxis": {"title": x}}],
                    }
                    for x in cols_dd
                ],
                "y": 0.9,
            },
        ],
        margin={"l": 0, "r": 0, "t": 25, "b": 0},
    )
    fig