Creating a dropdown + slider for a Choropleth map with plotly.express?

Hey, I’m currently working on visualizing covid cases in Austria, and I’m struggling to create a slider combined with a dropdown menu via plotly.express. Obviusly, creating the slider isn’t hard with express, but I have no clue how a dropdown menu works, I would want it to change the value which the Choropleth map gets it’s values from (for example total cases, total deaths etc.). Any help appreciated!

Hi @Skrumpey ,

Here is an example of dropdown menu to select which dataframe column is used for values to be mapped to the colorscale.

Plotly provides two functions for updates, via dropdown: 'restyle, ‘relayout’ and ‘update’`. The first one is used for updating traces, the second for updating layout and the third for updating both some trace attributes and layout attributes.

import plotly.express as px

df = px.data.election()
#print(df.head())
geojson = px.data.election_geojson()

fig = px.choropleth(df, geojson=geojson, color="Bergeron",
                    locations="district", featureidkey="properties.district",
                    projection="mercator", color_continuous_scale="deep"
                   )
fig.update_geos(fitbounds="locations", visible=False)


button1 =  dict(method = "restyle",
                args = [{'z': [ df["Bergeron"] ] }],
                label = "Bergeron")
button2 =  dict(method = "restyle",
                args = [{'z': [ df["Joly"] ]}],
                label = "Joly")

fig.update_layout(width=700,
                  coloraxis_colorbar_thickness=23,
                  updatemenus=[dict(y=0.9,
                                    x=0.275,
                                    xanchor='right',
                                    yanchor='top',
                                    active=0,
                                    buttons=[button1, button2])
                              ]) 

To understand what is z in button’s definition inspect go.Choropleth here:
https://plotly.github.io/plotly.py-docs/generated/plotly.graph_objects.Choropleth.html.

In the button arg definition:

{'z': [ df["Bergeron"] ] }

we didn’t set

{'z': df['Bergeron'}

because plotly fig.data is a list, and we have to inform plotly.js which list element is updated. Hence we defined:

{'z': [ df["Bergeron"] ] }

which means that we are modifying 'z'in fig.data[0], i.e. within the only list element, in this case.

Hi, thanks for your reply, it’s almost working now! There’s still some things that aren’t working 100% correctly. First, is there any way to make the buttons actually like a dropdown? Because currently, they’re just right next to each other and it doesn’t look very nice. Also, whenever I press one of the buttons, all colors will turn to blue, until I move my slider (probably because it isn’t updating correctly). Also, the label of the coloraxis doesn’t change when I press a button. Any help here would be very appreciated!

EDIT: I actually just noticed that the colors don’t actually change to whatever I want, they just stay at the one which I assigned when creating the map.

@Skrumpey

For me the code I gave as example exhibits a dropdown menu with two options, and it works as expected.

Could you please paste here your button definition to identify why you have two buttons displayed next to each other?

@empet
Sorry for not replying for so long, I was a bit busy.
This is what I currently have, the dropdown now looks fine, but the data doesnt actually change when I click something else:

> import pandas as pd
import plotly.express as px
import json
import plotly

>df = pd.read_csv('owidFuerMap.csv')
df.info()

>df = df[df.continentExp == 'Europe']
df.drop(['year_week', 'continentExp', 'geoId'], axis=1, inplace=True)
df['Fälle pro 100k Einwohner (7-Tage)'] = df['cases_weekly'].div(df['popData2019'].div(100000))
df['Tode pro 100k Einwohner (7-Tage)'] = df['deaths_weekly'].div(df['popData2019'].div(100000))

>df[df['notification_rate_per_100000_population_14-days'].isna()]
df['Datum'] =pd.to_datetime(df.Datum,dayfirst = True)
df.sort_values('Datum',inplace=True)
df['Datum'] = df['Datum'].astype('string')
df['Datum'] = df['Datum'].astype('object')

>f = open('custom_geo_low.json')
data = json.load(f)
fig = px.choropleth(df,geojson = data
                    ,locationmode='ISO-3'
                    ,locations = 'countryterritoryCode'
                    ,scope = 'europe'
                    ,color = "Fälle pro 100k Einwohner (7-Tage)"
                    ,animation_frame = "Datum"
                   )
fig["layout"]
fig["layout"].pop("updatemenus")
fig.update_geos(fitbounds = "locations",visible=False)

>button1 =  dict(method = "restyle",
                args = [{'z': [ df["Fälle pro 100k Einwohner (7-Tage)"] ] }],
                label = "Fälle")
button2 =  dict(method = "restyle",
                args = [{'z': [ df["Tode pro 100k Einwohner (7-Tage)"] ]}],
                label = "Tode")
fig.update_layout(width=700,
                  coloraxis_colorbar_thickness=23,
                  updatemenus=[dict(y=0.9,
                                    x=0.275,
                                    xanchor='right',
                                    yanchor='top',
                                    active=0,
                                    buttons=[button1, button2])
                              ]) 

plotly

EDIT: This is the layout of the figure:

Layout({
    'coloraxis': {'colorbar': {'thickness': 23, 'title': {'text': 'Fälle pro 100k Einwohner (7-Tage)'}},
                  'colorscale': [[0.0, '#0d0887'], [0.1111111111111111,
                                 '#46039f'], [0.2222222222222222, '#7201a8'],
                                 [0.3333333333333333, '#9c179e'],
                                 [0.4444444444444444, '#bd3786'],
                                 [0.5555555555555556, '#d8576b'],
                                 [0.6666666666666666, '#ed7953'],
                                 [0.7777777777777778, '#fb9f3a'],
                                 [0.8888888888888888, '#fdca26'], [1.0, '#f0f921']]},
    'geo': {'center': {},
            'domain': {'x': [0.0, 1.0], 'y': [0.0, 1.0]},
            'fitbounds': 'locations',
            'scope': 'europe',
            'visible': False},
    'legend': {'tracegroupgap': 0},
    'margin': {'t': 60},
    'template': '...',
    'updatemenus': [{'active': 0,
                     'buttons': [{'args': [{'z': [8678      0.000000 5989
                                                  0.000000 537       0.000000 3010
                                                  0.000000 2352      0.000000
                                                  ...     1102    133.505079 4157
                                                  68.450973 1312    167.799065 4605
                                                  143.952814 51      156.265994
                                                  Name: Fälle pro 100k Einwohner
                                                  (7-Tage), Length: 2560, dtype:
                                                  float64]}],
                                  'label': 'Fälle',
                                  'method': 'restyle'},
                                 {'args': [{'z': [8678     0.000000 5989
                                                  0.000000 537      0.000000 3010
                                                  0.000000 2352     0.000000
                                                  ...     1102     8.754928 4157
                                                  0.693278 1312    13.157070 4605
                                                  3.558509 51       2.969508 Name:
                                                  Tode pro 100k Einwohner (7-Tage),
                                                  Length: 2560, dtype: float64]}],
                                  'label': 'Tode',
                                  'method': 'restyle'}],
                     'x': 0.275,
                     'xanchor': 'right',
                     'y': 0.9,
                     'yanchor': 'top'}],
    'width': 700
})

Hey! Thank you so much for sharing your question and your code. I am having the exact same issue: I want to add a slider to each map in the dropdown menu. The dropdown part works thanks to your posts, but the slider only works for the first map. How can I add a functioning slider to each map? I`m really looking forward to any updates.

Hi there - I’m in the exact same boat, wondering if there is a way to properly link sliders with dropdowns. Just wanted to check-in if anyone was able to figure this out? Thanks!

HI, I am facing the same problem. Have you figured out how to do this?
Thank you in advance.