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()
]
}
]
)
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"]
],
)