Search code examples
plotlyplotly-pythonchoroplethplotly-express

Add dropdown button to plotly express choropleth map


I already saw this and i am trying to build off this solution (Dropdown menu for Plotly Choropleth Map Plots) but I keep getting errors for the visible section, here is my code.

import pandas as pd
import numpy as np
import plotly.graph_objs as go
import plotly.express as px

# Data
cols_dd = ["Total tests", "Total cases", "Total deaths"]
# 
visible = np.array(cols_dd)

# define traces and buttons at once
traces = []
buttons = []
for value in cols_dd:
    traces.append(px.choropleth(df,
       locations="Iso code", # Spatial coordinates
        color=value, # Data to be color-coded
        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= True if value==cols_dd[0] else False)

buttons.append(dict(label=value, method="update", args=[{"visible":list(visible==value)}, {"title":f"<b>{value}</b>"}]))

updatemenus = [{"active":0,"buttons":buttons}]

layout = go.Layout(
    showlegend=True,
    font=dict(size=12),
    width = 800,
    height = 500,
    margin=dict(l=0,r=0,b=0,t=40)
    )


# Show figure
fig = go.Figure(data=traces, layout=dict(updatemenus=updatemenus))
# This is in order to get the first title displayed correctly
first_title = cols_dd[0]
fig.update_layout(layout)
fig.update_geos(scope="africa")
fig.update_layout(title=f"<b>{first_title}</b>",title_x=0.5)
fig.show()

I get the error message 'NoneType' object has no attribute 'update_traces', also if its possible to get the fix for dash, that would be greatly appreciated


Solution

    • OWID data is pretty much what you are using. Column names are a little different so renamed to use
    • fundamentally, be systematic on how you build traces and layout
    • have created a colorbar config for each trace to ensure it's more responsive
    • extended cols_dd to show how it can be used for plotting more metrics
    • as per comments included scatter as well as choropleth
    import pandas as pd
    import numpy as np
    import plotly.express as px
    import plotly.graph_objects as go
    import itertools
    
    # 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", "new_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",
    }
    
    fig = go.Figure()
    
    for i, value in enumerate(cols_dd):
        # use a different color axis for each trace... makes it more responsive
        ca = f"coloraxis{i+2}"
    
        figc = px.choropleth(
            df,
            locations="Iso code",  # Spatial coordinates
            color=value,  # Data to be color-coded
            hover_data=hd,
            color_continuous_scale="spectral_r",
            hover_name="Location",
        ).update_traces(visible=False, coloraxis=ca)
        figs = px.scatter_geo(
            df,
            locations="Iso code",  # Spatial coordinates
            color=value,  # Data to be color-coded
            hover_data=hd,
            color_continuous_scale="spectral_r",
            hover_name="Location",
        ).update_traces(visible=False, marker={"coloraxis": ca})
    
        fig = fig.add_traces(figc.data)
        fig = fig.add_traces(figs.data)
        fig = fig.update_layout(
            {
                ca: {
                    "cmin": df[value].replace(0, np.nan).quantile(0.25),
                    "cmax": df[value].replace(0, np.nan).quantile(0.75),
                    "colorbar": {"title": value},
                }
            }
        )
    
    
    fig.update_layout(
        updatemenus=[
            {
                "buttons": [
                    {
                        "label": f"{m} - {p}",
                        "method": "update",
                        "args": [
                            {
                                "visible": [
                                    (m2 == m and p2 == p)
                                    for m2, p2 in itertools.product(
                                        cols_dd, ["choropleth", "scatter"]
                                    )
                                ]
                            },
                            {"title": f"<b>{m}</b>"},
                        ],
                    }
                    for m, p in itertools.product(cols_dd, ["choropleth", "scatter"])
                ]
            }
        ],
        margin={"l": 0, "r": 0, "t": 25, "b": 0},
    )