Hi, I’m new to Dash and find it absolutely amazing.
My question: I have a Choroplethmapbox and a series of 10 buttons that switch between map modes. All modes are based on the same geojson and mapbox, and the buttons change only the z values (and the hover data). The z’s are just 10 different columns in the same dataframe: button A switches the z-values to column A, B - to column B, etc. All works perfectly, but as expected, the switch is quite slow - probably because I have to send the whole figure with every callback (a similar question: Updating data on mapbox without updating the whole map).
Ideally I would like to update just the specific property (as suggested here: Is it possible to update just `layout`, not whole `figure` of Graph in callback?): in my case something like @app.callback(Output('my-map', 'figure['data'][0]['z']'))
. But as far as I understand it’s impossible. Is there any other solution for that? Can caching help here in any way? I’m attaching a simplified version of my code below. I’d appreciate your comments!
# Data
map_modes = { ... }
button_ids = list(map_modes.keys())
with open( ... ) as f:
my_geojson = json.load(f)
my_df = pd.read_csv( ... )
my_df.set_index('id', inplace=True)
data = [
go.Choroplethmapbox(
geojson=my_geojson,
locations=my_df.index,
z=my_df['A'],
)
]
layout = go.Layout(
mapbox={
'style': 'carto-positron',
...
},
uirevision='same same'
)
# Layout
app.layout = html.Div(className='main_disp', children=[
dcc.Graph(
id='main_map'
),
html.Div(className='mode_buttons',
children=[html.Button(map_modes[x]['label'], id=x, className='inactive_button') for x in map_modes]
),
])
# Callbacks
@app.callback(
[Output('main_map', 'figure')] + [Output(button, 'className') for button in map_modes],
[Input(button, 'n_clicks') for button in map_modes]
)
def button_pressed(*args):
# when initialized, first button turns active, map remains default
if not any(args):
buttons_output = ['active_button'] + (['inactive_button'] * (len(button_ids) - 1))
# otherwise, the fired button turns active and the button's column in the df becomes z
else:
ctx = dash.callback_context
fired_button = ctx.triggered[0]['prop_id'].split('.')[0]
data[0]['z'] = my_df[fired_button]
figure_output = {'data': data, 'layout': layout}
buttons_output = ['inactive_button' if button != fired_button else 'active_button' for button in button_ids]
return [figure_output] + buttons_output