I have an app that overlays lines onto of a graph with a go.scattermap fig of satellite map. It has sliders controlling line spacing and position.
This all works fine for the first few adjustments, then the browser freezes with a js error. The figure in Dash is updating in response to additional inputs (verified by fig.show() in the debugger), but the browser display is frozen.
The js console in the browser shows a Map error
Uncaught (in promise) Error: Map error.
at t.Map.r (plotly.min.js:8:718596)
at t.Map.fire (plotly.min.js:8:3714964)
at de.fire (plotly.min.js:8:3715109)
at de.removeLayer (plotly.min.js:8:4203279)
at t.Map.removeLayer (plotly.min.js:8:4490265)
at l.dispose (plotly.min.js:8:1359475)
at _.updateData (plotly.min.js:8:718055)
at plotly.min.js:8:716504
Edit: Solved, but not understood
Referencing a global color_lookup table when setting the color parameter of a trace triggers the js error after 3-10 callbacks. The first two calls always work.
I do not understand why, but empirically this change avoids the problem
There is a global color lookup dictionary:
lk_line_color = build_line_color_dict()
The update_graph callback rebuilds the figure containg traces like this one:
setting the color with color=lk_line_color[‘pac’] eventually fails after 3-10 calllbacks.
CASE 1 Works all the time: (color via discrete color)
fig.add_trace(go.Scattermap(lat=xyp_pac[:, 0],
lon=xyp_pac[:, 1],
mode=‘lines+markers’,
name=f’Pacific line {line_no}',
marker=dict(color=‘blue’, size=2),
line=dict(color=‘blue’) ) ) )
CASE 2 Fails after 3-10 calllbacks: (color via lookup_table)
fig.add_trace(go.Scattermap(lat=xyp_pac[:, 0],
lon=xyp_pac[:, 1],
mode=‘lines+markers’,
name=f’Pacific line {line_no}',
marker=dict(color=lk_line_color[‘pac’], size=2),
line=dict(color=lk_line_color[‘pac’]),
visible=‘legendonly’ ) )
Perhaps keeping the lookup table in the dcc.Store would avoid the error.
Previous problem description:
In reading I see in previous versions this was related to version mismatches. My current versions are:
dash==2.18.2
dash-bootstrap-components==1.6.0
dash-core-components==2.0.0
dash-html-components==2.0.0
dash-leaflet==1.0.15
dash-table==5.0.0
I am unclear whether I have conflicting callbacks or a javascript problem.
The callbacks are shown below. The settings_dict is stored in a dcc.Store with id=settings_store.
I hope this is enough. Constructing a full MWE will be daunting.
comment: updates fig and updated [connector_dict in settings_store ('data')
@callback(
[Output('graph', 'figure', allow_duplicate=True),
Output('settings_store', 'data')],
[Input('line_no', 'value'),
Input('width_km', 'value'),
Input('clip_range', 'value'),
Input('shift', 'value'),
Input('settings_store', 'data')],
prevent_initial_call=True
)
def update_graph_line(line_no, width_km, clip_range, shift, settings_dict):
if settings_dict is None:
# fill settings_dict with defaults: # width_km = 10, clip = [0, 100], shift = 0
settings_dict = {str(n): [10, [0, 100], 0] for n in range(1, 23)}
if ctx.triggered_id == 'line_no':
width_km, clip_range, shift = settings_dict[str(line_no)]
else:
settings_dict[str(line_no)] = width_km, clip_range, shift
fig, result_line = plot_line(line_no,
line_dict,
spacing=width_km,
min_pct=clip_range[0],
max_pct=clip_range[1],
shift=shift
)
return fig, settings_dict
comment: on line change: restore slider settings or set defaults if settings_dict is None
@callback(
[
Output('graph', 'figure', allow_duplicate=True),
Output('width_km', 'value', allow_duplicate=True),
Output('clip_range', 'value', allow_duplicate=True),
Output('shift', 'value', allow_duplicate=True),
Output('settings_store', 'data', allow_duplicate=True)],
[Input('line_no', 'value'),
Input('settings_store', 'data')],
prevent_initial_call=True
)
def specify_settings(line_no, settings_dict):
if ctx.triggered_id == 'line_no': # only update if line_no change
if settings_dict is None:
# fill settings_dict with defaults: # width_km = 10, clip = [0, 100], shift = 0
settings_dict = {str(n): [10, [0, 100], 0] for n in range(1, 23)}
width_km, clip_range, shift = settings_dict[str(line_no)]
fig, result_line = plot_line(line_no,
line_dict, # global line coordinate data dictionary
spacing=width_km,
min_pct=clip_range[0],
max_pct=clip_range[1],
shift=shift
)
return fig, width_km, clip_range, shift, settings_dict
return no_update
Thanks for any insight.