Coroplethmapbox update z only

Hi everyone,
I have a complex map, with many polygons. I want te create a dash app where I load my polygons on a map only once using coroplethmapbox and then add a drop-down menu to update the z value inside the polygons without reloading the polygons (geojson).
Any idea or link to similar question
Thanks,
Laurent

Hi @ltestut1 welcome to the forums. You could update the z- value via a clientside callback. Here an example:

  • the chart is loaded with the initial values
  • on app startup these initial values are written into the clientside store
  • a callback is fired if a value is selected from the drop down, the z- values are updated accordingly

Keep in mind, that only the z- values are getting updated, the colorscale (min/max) is not updated. If needed, you would have to to this in the callback too.

from dash import Dash, dcc, Input, Output, State
import dash_bootstrap_components as dbc
from plotly_docs import fig
# ^^ this is actually just the figure of the first example here: https://plotly.com/python/mapbox-county-choropleth/

app = Dash(
    __name__,
    external_stylesheets=[dbc.themes.BOOTSTRAP]
)

app.layout = dbc.Container(
    [
        dbc.Row(
            dcc.Graph(
                id='graph',
                figure=fig
            )
        ),
        dbc.Row([
            dcc.Dropdown(
                id='drop',
                options=[
                    {'label': 'initial', 'value': 1.0},
                    {'label': 'half', 'value': 0.5},
                    {'label': 'double', 'value': 2.0}
                ]
            ),
            dcc.Store(id='store')
        ])
    ],
    fluid=True
)

app.clientside_callback(
    """
    function(dummy_val, fig) {
        return fig['data'][0]['z']
    }
    """,
    Output('store', 'data'),
    Input('drop', 'options'),
    State('graph', 'figure')
)


app.clientside_callback(
    """
    function(drop_val, fig, init_val) {
        newFig = JSON.parse(JSON.stringify(fig))
        if (drop_val == 1.0) {
            newFig['data'][0]['z'] = init_val
        } else {
            newFig['data'][0]['z'] = init_val.map(element => element * drop_val)
        }
        return newFig
    }
    """,
    Output('graph', 'figure'),
    Input('drop', 'value'),
    State('graph', 'figure'),
    State('store', 'data'),
    prevent_initial_call=True
)

if __name__ == '__main__':
    app.run(debug=True, port=8050)

plotly_docs.py

from urllib.request import urlopen
import plotly.express as px
import pandas as pd
import json

with urlopen('https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json') as response:
    counties = json.load(response)

df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/fips-unemp-16.csv",
                 dtype={"fips": str})

fig = px.choropleth_mapbox(
    df,
    geojson=counties,
    locations='fips',
    color='unemp',
    color_continuous_scale="Viridis",
    range_color=(0, 12),
    mapbox_style="carto-positron",
    zoom=3, center={"lat": 37.0902, "lon": -95.7129},
    opacity=0.5,
    labels={'unemp': 'unemployment rate'}
)
fig.update_layout(margin={"r": 0, "t": 0, "l": 0, "b": 0})
1 Like

Hi AIMPED,
Thanks a lot for your solution. Do you know if I can use the dash Patch object I recently discover to update the z value without using a clientside callback?

Hi @ltestut1, yes, the Patch() should work too. It allows you to update your figure partially.