Home > OS >  Plotly: select df to show by using drop-down menu
Plotly: select df to show by using drop-down menu

Time:10-19

currently I have a Plotly plot with 4 subplots, generated from a single Pandas dataframe (df).

Now I have a dictionary of dfs: dfs = {'Germany':DF, 'France':DF, ...}

Is it possible to create a plot with a drop-down menu that I can select the country and use that country's df to generate the 4 subplots accordingly? What is the easiest way to achieve this? Thanks.

P.S.: I looked at the drop-down menu examples from Plotly, but they seem to work on a single df only.

CodePudding user response:

  • have consider two different approaches
  • start by constructing dfs to be similar to what you described
import requests
import io
import pandas as pd
import plotly.express as px

# fmt: off
# case / death data
dfall = pd.read_csv(io.StringIO(
    requests.get("https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/owid-covid-data.csv").text))
dfall["date"] = pd.to_datetime(dfall["date"])
countries = ['Australia', 'Austria', 'France', 'Germany', 'Japan', 'New Zealand', 'Singapore', 'United Kingdom', 'United States']
# fmt: on

# mimic described dict of dataframes
dfs = {c: dfall.loc[dfall["location"].eq(c), ["date", "new_cases"]] for c in countries}

approach one - plot all data frames as traces

  • construct concatenated dataframe of all data frames in dfs
  • updatemenus is standard trace visibility use case
px.line(
    pd.concat([dfs[c].assign(country=c) for c in dfs.keys()]),
    x="date",
    y="new_cases",
    color="country",
).update_traces(visible=False).update_layout(
    updatemenus=[
        {
            "buttons": [
                {
                    "label": c,
                    "method": "update",
                    "args": [{"visible": [c == c2 for c2 in dfs.keys()]}],
                }
                for c in dfs.keys()
            ]
        }
    ]
)

approach 2 - data in updatemenus

  • when constructing figure it has to have a trace, hence using first dataframe in dfs
px.line(dfs[list(dfs.keys())[0]], x="date", y="new_cases").update_layout(
    updatemenus=[
        {
            "buttons": [
                {
                    "label": c,
                    "method": "restyle",
                    "args": [
                        {"x": [dfs[c]["date"]], "y": [dfs[c]["new_cases"]]},
                    ],
                }
                for c in dfs.keys()
            ]
        }
    ]
)

enter image description here

Plotly Express with sub-plots

  • effectively approach one, where there are multiple traces per country
  • truth list is built be check if country is in hovertemplate
# mimic describe dict of dataframes
dfs = {
    c: dfall.loc[
        dfall["location"].eq(c), ["date", "new_cases", "new_deaths", "new_vaccinations"]
    ]
    .set_index("date")
    .stack()
    .reset_index()
    .rename(columns={"level_1": "measure", 0: "value"})
    for c in countries
}

fig = (
    px.line(
        pd.concat([dfs[c].assign(country=c) for c in dfs.keys()]),
        x="date",
        y="value",
        facet_row="measure",
        color="country",
    )
    .update_layout({f"yaxis{n}": {"matches": None} for n in range(2, 6)})
    .update_traces(visible=False)
)

fig.update_layout(
    showlegend=False,
    updatemenus=[
        {
            "buttons": [
                {
                    "label": c,
                    "method": "update",
                    "args": [{"visible": [c in t.hovertemplate for t in fig.data]}],
                }
                for c in dfs.keys()
            ]
        }
    ],
    annotations=[
        {**a, **{"text": a["text"].replace("measure=", "")}}
        for a in fig.to_dict()["layout"]["annotations"]
    ],
)
  • Related