Black Lives Matter. Please consider donating to Black Girls Code today.

Heatmapgl issues

I’m trying to plot atmospheric data as a heatmap overlaid on a continent map. I’ve been able to achieve pretty much what I’m looking for using the normal heatmap and scatter/scattergl functions. However svg rendering seems too slow for me, particularly as I wanted to animate components, so I was hoping to use heatmapgl for the heatmap component. This gives much improved performance, but it seems to have an issue when I try to combine it with other traces. Specifically, it seems to cover up other plot elements.

Here’s what it should look like (with go.Heatmap):

And here’s what it looks like with go.Heatmapgl:

I can hack it to look correct if I open the web inspector and manually reorder the canvas elements (seems the heatmap and scatter traces are plotted on separate elements). I also have to reorder the svg elemtents to get input to work correctly.

It seems heatmapgl may be being deprecated, but if anyone has a fix it would be much appreciated!

# This code just opens the data (a NetCDF file and does a manual projection for plotting)
import xarray as xr
import sys, os, conda
import plotly.graph_objects as go
import pandas as pd
import numpy as np
conda_file_dir = conda.__file__
conda_dir = conda_file_dir.split('lib')[0]
proj_lib = os.path.join(os.path.join(conda_dir, 'share'), 'proj')
os.environ["PROJ_LIB"] = proj_lib

from mpl_toolkits.basemap import Basemap

DATA_BASE_DIR = '/Users/personal/Documents/Research/Climate/Data'
ds = xr.open_dataset(os.path.join(DATA_BASE_DIR, 'w', 'w_01_2005.nc'))
df = ds.to_dataframe()

plotdata = df.xs(200, level='level').xs('2005-01-01', level='time')
m,n = len(plotdata.index.levels[0]), len(plotdata.index.levels[1])
arr = plotdata.values.reshape(m,n)
w = arr[5:-5].T
lat = plotdata.index.levels[0][5:-5].values
long = plotdata.index.levels[1].values - 180.
m = Basemap(projection='merc', resolution='c')
x, y = np.meshgrid(long, lat)
x, y = m(x, y)
x = x[0]
y = y[:, 0]

# Plotly code
fig = go.Figure()

fig.add_trace(go.Heatmapgl( # <-- Issue is here, replacing Heatmapgl with Heatmap makes things work properly at the expense of performance
    x = x,
    y = y,
    z=w.T,
    colorscale='RdBu',
    #zsmooth = 'fast'
    ))

for seg in m.coastsegs:
    fig.add_trace(go.Scatter(
        x = np.array(seg)[:, 0],
        y = np.array(seg)[:, 1],
        mode = 'lines',
        line_color='black',
        showlegend=False
        ))

fig.update_layout(plot_bgcolor='white',autosize=False,
    width=1000,
    height=600,)

fig.update_yaxes(tickvals=y[::15], ticktext=lat[1::15], showgrid=True)
fig.update_xaxes(tickvals=x[::15], ticktext=long[1::15], showgrid=True)

fig.show(config={'scrollZoom': True})

Well, it turns out SVG rendering wasn’t really the bottleneck I was experiencing. If I make all of the traces the default SVG versions and render to HTML instead of using the Jupyterlab renderer, everything works perfectly and the performance is much better. I don’t have any insight into why the Jupyterlab renderer’s performance seems so poor, but this is a fine workaround for me.

# Replace:
fig.show(config={'scrollZoom': True})
# With:
import plotly.io as pio
from IPython.core.display import display, HTML
div = pio.to_html(fig, auto_play=False, full_html=False,  config={'scrollZoom': True})
display(HTML(div))