'Plotly express Choropleth Map subplot does not display everything

Problem

To visualize election winner results by region, I want to display 2 choropleth maps in a subplot to compare the first and second rounds.

Here's what my code looks like:

import geopandas as gpd
import pandas as pd
import plotly.express as px
from plotly.subplots import make_subplots

# Results
t1_dep = pd.read_csv('https://www.data.gouv.fr/fr/datasets/r/bf616688-8478-46fa-8abe-cd1cc1a53b83')

t1_dep.drop(t1_dep.columns[28:52], axis=1, inplace=True)
t1_dep.drop(t1_dep.columns[[3, 5, 6, 7, 8, 10, 11, 13, 14]], axis=1, inplace=True)

t1_dep.columns = ['Code Département','Département', 'Inscrits', 'Taux Abstention', 'Taux Blanc', 'Taux Nul', 'Taux Exprimé',
                  'ARTHAUD', 'ROUSSEL', 'MACRON', 'LASSALLE', 'LE PEN', 'ZEMMOUR', 'MÉLENCHON', 'HIDALGO', 'JADOT', 'PÉCRESSE', 'POUTOU', 'DUPONT-AIGNAN']

t2_dep = pd.read_csv('https://www.data.gouv.fr/fr/datasets/r/c7b72e78-5e78-4976-995f-30533f0a35d3')

t2_dep.drop(t2_dep.columns[18:52], axis=1, inplace=True)
t2_dep.drop(t2_dep.columns[[3, 5, 6, 7, 8, 10, 11, 13, 14]], axis=1, inplace=True)

t2_dep.columns = ['Code Département','Département', 'Inscrits', 'Taux Abstention', 'Taux Blanc', 'Taux Nul', 'Taux Exprimé',
                  'MACRON', 'LE PEN']

# Geo
geo_dep = gpd.read_file('https://www.data.gouv.fr/fr/datasets/r/92f37c92-3aae-452c-8af1-c77e6dd590e5')

for i in geo_dep.index[96:]:
    dep = geo_dep.loc[i, 'libgeo']
    code = geo_dep.loc[i, 'dep']
    
    t1_dep.loc[t1_dep['Département'] == dep, 'Code Département'] = code
    t2_dep.loc[t2_dep['Département'] == dep, 'Code Département'] = code
    
# Rounds winner per region
t1_vainq_dep = t1_dep[t1_dep.columns[7:]].idxmax(axis=1).to_frame(name='Vainqueur')
t1_vainq_dep['Code Département'] = t1_dep['Code Département']
t1_vainq_dep['Département'] = t1_dep['Département']

t2_vainq_dep = t2_dep[t2_dep.columns[7:]].idxmax(axis=1).to_frame(name='Vainqueur')
t2_vainq_dep['Code Département'] = t2_dep['Code Département']
t2_vainq_dep['Département'] = t2_dep['Département']
    
# Plot
fig_t1 = px.choropleth_mapbox(t1_vainq_dep,
                              locations='Code Département',
                              geojson=geo_dep,
                              color='Vainqueur',
                              featureidkey='properties.dep',
                              hover_name='Vainqueur')
fig_t2 = px.choropleth_mapbox(t2_vainq_dep,
                              locations='Code Département',
                              geojson=geo_dep,
                              color='Vainqueur',
                              featureidkey='properties.dep',
                              hover_name='Vainqueur')

fig = make_subplots(rows=1, cols=2,
                    subplot_titles=['Premier tour', 'Second tour'],
                    specs=[[{'type': 'choroplethmapbox'}, {'type': 'choroplethmapbox'}]])

fig.add_trace(fig_t1['data'][0], row=1, col=1)
fig.add_trace(fig_t2['data'][0], row=1, col=2)

fig.update_mapboxes(style='white-bg',
                    center={'lat': 46.3, 'lon': 1.6751},
                    zoom=4.2)
fig.update_layout(title_text='Élection Présidentielle 2022 - Vainqueur par département',
                  margin={'l': 0, 'r': 0, 't': 100, 'b': 0},
                  height=500)

fig.show()

enter image description here

The maps only display the region won by the first candidate but not the other, and this is not due to a problem with the data because I can correctly each map separately.

I also, with a similar code, correctly subplot 2 maps representing the absentation rate per region without any problem. So the problem may be coming from the fact that plotly has to figure out colours for each candidate but not sure.

Any suggestion?

What I tried

When I first look at how to create a subplot, the plotly documentation shows examples using Graph Object because Express doesn't 'support' subplot.

I didn't go without for the only reason that, I have no idea why, but the go.Choropleth map doesn't like my GeoJson (even after parsing using to_json()) and displays me a very long error message in the Jupyter notebook console.

So I manage to find the workaround to be able to transfer Express plots to a subplot.



Solution 1:[1]

Reusing plotly.express data is a common way to reuse data, but for some reason it doesn't work in this case. The cause is not clear to me either. As a workaround, you can add the candidate IDs as numbers and specify the colors to those IDs to draw the map.

import geopandas as gpd
import pandas as pd
import plotly.express as px
from plotly.subplots import make_subplots
from urllib import request
import json

# Results
t1_dep = pd.read_csv('https://www.data.gouv.fr/fr/datasets/r/bf616688-8478-46fa-8abe-cd1cc1a53b83')

t1_dep.drop(t1_dep.columns[28:52], axis=1, inplace=True)
t1_dep.drop(t1_dep.columns[[3, 5, 6, 7, 8, 10, 11, 13, 14]], axis=1, inplace=True)

t1_dep.columns = ['Code Département','Département', 'Inscrits', 'Taux Abstention', 'Taux Blanc', 'Taux Nul', 'Taux Exprimé',
                  'ARTHAUD', 'ROUSSEL', 'MACRON', 'LASSALLE', 'LE PEN', 'ZEMMOUR', 'MÉLENCHON', 'HIDALGO', 'JADOT', 'PÉCRESSE', 'POUTOU', 'DUPONT-AIGNAN']

t2_dep = pd.read_csv('https://www.data.gouv.fr/fr/datasets/r/c7b72e78-5e78-4976-995f-30533f0a35d3')

t2_dep.drop(t2_dep.columns[18:52], axis=1, inplace=True)
t2_dep.drop(t2_dep.columns[[3, 5, 6, 7, 8, 10, 11, 13, 14]], axis=1, inplace=True)

t2_dep.columns = ['Code Département','Département', 'Inscrits', 'Taux Abstention', 'Taux Blanc', 'Taux Nul', 'Taux Exprimé',
                  'MACRON', 'LE PEN']

with request.urlopen('https://www.data.gouv.fr/fr/datasets/r/92f37c92-3aae-452c-8af1-c77e6dd590e5') as f:
    geo_dep = json.load(f)

# Rounds winner per region
t1_vainq_dep = t1_dep[t1_dep.columns[7:]].idxmax(axis=1).to_frame(name='Vainqueur')
t1_vainq_dep['Code Département'] = t1_dep['Code Département']
t1_vainq_dep['Département'] = t1_dep['Département']
t1_vainq_dep['Vainqueur_id'] = t1_vainq_dep['Vainqueur'].map({'MACRON':0, 'LE PEN':1, 'MÉLENCHON':2})

t2_vainq_dep = t2_dep[t2_dep.columns[7:]].idxmax(axis=1).to_frame(name='Vainqueur')
t2_vainq_dep['Code Département'] = t2_dep['Code Département']
t2_vainq_dep['Département'] = t2_dep['Département']
t2_vainq_dep['Vainqueur_id'] = t2_vainq_dep['Vainqueur'].map({'MACRON':0, 'LE PEN':1})

# Plot
fig_t1 = px.choropleth_mapbox(t1_vainq_dep,
                              locations='Code Département',
                              geojson=geo_dep,
                              color='Vainqueur_id',
                              featureidkey='properties.dep',
                              hover_name='Vainqueur')
fig_t2 = px.choropleth_mapbox(t2_vainq_dep,
                              locations='Code Département',
                              geojson=geo_dep,
                              color='Vainqueur_id',
                              featureidkey='properties.dep',
                              hover_name='Vainqueur')

fig = make_subplots(rows=1, cols=2,
                    subplot_titles=['Premier tour', 'Second tour'],
                    specs=[[{'type': 'choroplethmapbox'}, {'type': 'choroplethmapbox'}]])

fig.add_trace(fig_t1['data'][0], row=1, col=1)
fig.add_trace(fig_t2['data'][0], row=1, col=2)

fig.update_layout(coloraxis_showscale=False) # update

fig.update_mapboxes(style='white-bg',
                    center={'lat': 46.3, 'lon': 1.6751},
                    zoom=4.2)
fig.update_layout(title_text='Élection Présidentielle 2022 - Vainqueur par département',
                  margin={'l': 0, 'r': 0, 't': 100, 'b': 0},
                  height=500)

fig.show()

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1