I’ve been playing around with Plotly and Dash for the first time over the past few days, with the hope of developing a browser-based data explorer for geographic NetCDF4 data. I’ve been impressed at how straightforward this has been so far, however I’m finding that some interactions are taking longer to update and render than I’d hoped. I believe this may be the same issue discussed here: Choroplethmapbox update _very_ slow when deployed
The following refers to the code and sample data available here: CloudStor
# Create the callback and callback function (update_figure) @app.callback(Output('plot', 'figure'), [Input('slide', 'value')], [State('plot','relayoutData'),State('plot', 'figure')]) def update_figure(x,r,f): t0 = tme.time() f['layout']['mapbox']['center']['lat'] = f['layout']['mapbox']['center']['lat'] f['layout']['mapbox']['center']['lon'] = f['layout']['mapbox']['center']['lon'] f['layout']['mapbox']['zoom'] = f['layout']['mapbox']['zoom'] # If the map window has been panned or zoomed, grab those values for the new figure if r is not None: if 'mapbox.center' in r: f['layout']['mapbox']['center']['lat'] = r['mapbox.center']['lat'] f['layout']['mapbox']['center']['lon'] = r['mapbox.center']['lon'] f['layout']['mapbox']['zoom'] = r['mapbox.zoom'] # Extract the new time values from the NetCDF file tmp = nc['temp'][x, -1, :, :].values.flatten() # Repace the Z values in the original figure with the updated values, leave everything else (e.g. cell geojson and max/min ranges) as-is f['data']['z'] = np.where(np.isnan(tmp), None, tmp).tolist() print("update_figure() time: ",tme.time()-t0) return f
The source of my data comes from a 4D NetCDF4 file (in this case a model of ocean temperature - temp.nc) with dimensions of time, depth, lat and lon. In my case I’m only plotting a 2D chloropleth map, but I’d like the user to interactively select the desired time interval (and eventually depth) as well (the render will always be in 2D space).
Using the examples from Mapbox Choropleth Maps | Python | Plotly, I’m using a geojson file of the 2D grid cells coupled with a Pandas DataFrame to render the ocean temperature. Everything is working as expected, however any changes to the slider value (time) take a long time to update (approx six seconds on my machine). It appears as though there’s a second or so between selecting the slider value and running the update_figure() callback, then another 4-5 seconds before the new render starts to take place in the browser.
The update_figure() callback reads the requested data directly from the NetCDF4 file, then directly updates the Z values in the existing figure dictionary and returns this as a new figure. At first I was concerned that the slow response time was due to reading from the NetCDF4, however a basic timing function shows that the update_figure() callback runs in less than 0.01 seconds in most cases. So it appears the delay is either coming from the @app.callback or the render function (post update_figure() in Dash?
I suspect that the slow render times are somehow related to the geojson of each cell polygon (47k grid cell polygons are being rendered in total, with each polygon being defined by 6 points (i.e. 284k points total)), and unfortunately this can’t be simplified any further. It was also unclear to me from the documentation whether chloroplethmapbox uses WebGL for rendering? If it’s using SVG then this would explain the slow times with this number of geojson polygons.
As far as I understand, I can’t really implement a client side callback here as the data needs to be read directly out of the NetCDF file using xarray.
Can anyone see/explain what’s causing the slow render times when new slider values are selected? Any assistance to understand (and possible workarounds) would be amazing.
Thanks in advance.