plotlyplotly-pythonchoropleth

Plotly choropleth map is extremely large and slow to load


I am plotting the regional boundaries of states in Australia.

This renders extremely slowly (10+ minutes) and according to Juputerlab is using up crazy amounts of memory (4Gb+).

I've filtered down the df to a single state to reduce the amount of boundaries to plot. Plotting with a color set to one of the columns takes up even more time and memory. If I don't set a color then it loads in a minute or so.

Is this to be expected? Or is there something I can do with the code so that it renders the map in a reasonable amount of time?

The shape file used can be found here:

import geopandas as gpd
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import plotly.graph_objects as go
import plotly.express as px
import plotly.offline as pyo

og_sa4_df = gpd.read_file()
sa4_df = og_sa4_df.copy(deep = True)

sa4_df = sa4_df[sa4_df['STE_NAME21'] == 'New South Wales']
sa4_df.dropna(axis = 0, subset = 'geometry', how = 'any', inplace = True)
sa4_df.set_index('SA4_NAME21')
sa4_df = sa4_df.to_crs(epsg = 4326)
geojson = sa4_df.__geo_interface__  

fig = px.choropleth_mapbox(sa4_df,
                              geojson = sa4_df.geometry,
                              locations = sa4_df.index,
                              color = sa4_df.SA4_NAME21,
                              center={"lat": -33.865143, "lon": 151.209900},
                               mapbox_style="carto-positron", 
                               zoom=8,
                              width = 800,
                              height = 500)
    
    fig.show()

SOLUTION

Using Robs solution in the comments, this sped up the rendering immensely:

import geopandas as gpd
import pandas as pd
import plotly.express as px

og_sa4_df = gpd.read_file('/Users/kamila/Downloads/SA4_2021_AUST_SHP_GDA94/SA4_2021_AUST_GDA94.shp')
sa4_df = og_sa4_df.copy(deep = True)
geocol = sa4_df.pop('geometry')
sa4_df.insert(0, 'geometry', geocol)
sa4_df = sa4_df[sa4_df['STE_NAME21'] == 'New South Wales']
sa4_df.dropna(axis = 0, subset = 'geometry', how = 'any', inplace = True) #need to drop None value rows for the geometry to be simplified below
sa4_df["geometry"] = (sa4_df.to_crs(sa4_df.estimate_utm_crs()).simplify(1000).to_crs(sa4_df.crs))
sa4_df.set_index('SA4_NAME21')
sa4_df = sa4_df.to_crs(epsg = 4326)
geojson = sa4_df.__geo_interface__

fig = px.choropleth_mapbox(sa4_df,
                          geojson = sa4_df.geometry,
                          locations = sa4_df.index,
                          color = sa4_df.SA4_NAME21,
                           color_discrete_map={'Central West': 'red'},
                          center={"lat": -33.865143, "lon": 151.209900},
                           mapbox_style="carto-positron", 
                           zoom=8,
                          width = 1600,
                          height = 800)

fig.show()

Solution

  • Quite often I find that mapbox slows down very significantly with overly accurate geometry. Have just taken step to simplify to accuracy of 1000m and then everything runs pretty quickly.

    import geopandas as gpd
    import plotly.express as px
    
    sa4_df = gpd.read_file("https://www.abs.gov.au/statistics/standards/australian-statistical-geography-standard-asgs-edition-3/jul2021-jun2026/access-and-downloads/digital-boundary-files/SA4_2021_AUST_SHP_GDA94.zip")
    sa4_df = sa4_df[sa4_df["STE_NAME21"] == "New South Wales"]
    # simplify geometry to 1000m accuracy
    sa4_df["geometry"] = (
        sa4_df.to_crs(sa4_df.estimate_utm_crs()).simplify(1000).to_crs(sa4_df.crs)
    )
    sa4_df.dropna(axis=0, subset="geometry", how="any", inplace=True)
    sa4_df.set_index("SA4_NAME21")
    sa4_df = sa4_df.to_crs(epsg=4326)
    geojson = sa4_df.__geo_interface__
    
    fig = px.choropleth_mapbox(
        sa4_df,
        geojson=sa4_df.geometry,
        locations=sa4_df.index,
        color=sa4_df.SA4_NAME21,
        center={"lat": -33.865143, "lon": 151.209900},
        mapbox_style="carto-positron",
        zoom=8,
        width=800,
        height=500,
    )
    
    fig.show()