We are adding 10+ scattergl charts to a page, but running into issues where we run out of webgl contexts. It appears that creating a new plot.ly chart uses it's own webgl context.
Is there a way to create a webgl context and use it for all the charts, or is there a another way to have many charts on the page without having this issue ?
Thanks
That shouldn't happen since 1.33.0. Can you share a reproducible example?
Unfortunately I cannot share the code.

Ok. Are you embedding plots from our cloud service on plot.ly?
no, we are not using the cloud service
we directly create the plots - we are using Angular 4
ie.
Plotly.newPlot(this.element.nativeElement, this.data, this.plotlyLayout, this.plotlyConfiguration );
our layout for a chart looks like this:
{
"chartType": "scattergl",
"label": "xxxxx",
"displayByDataType": false,
"x": "xxx",
"y": "yyyy",
"chartLayout":{
"title": "xxxxx",
"xaxis": {"title": "xxxx(Z)", "type":"date", "hoverformat": "%Y-%m-%dT%H:%M:%S" },
"yaxis": {"title": "xxxx"},
"margin": {"t": 80},
"hovermode": "closest",
"showlegend": true,
"legend": {
"orientation": "h",
"xanchor": "center",
"yancher": "bottom",
"y": -0.35,
"x": 0.5
},
"autosize": true,
"annotations": [{
"xref": "paper",
"yref": "paper",
"x": 0,
"xanchor": "middle",
"y": 1,
"yanchor": "bottom",
"text": "xxxx",
"showarrow": false,
"font": {
"size": 16,
"color": "black"
}
}]
}
},
... and what does console.log(Plotly.version) output?
1.33.1
Oh. Sorry I misread. You have 10 different scattergl charts in different <div> elements? Not 10 scattergl subplots? Correct?
If the former is correct, I think I know what's happening:
Before 1.33.0, we created 1 WebGL context per scattergl subplot. So in your case (assuming you have one scattergl subplot per graph), that means 10 WebGL contexts - which is under the Chrome threshold for that console warning you're seeing (I believe that threshold is 16).
Now starting in 1.33.0, we create 3 WebGL contexts per graph, no matter how many scatterglsubplots there are. In the other words, those three WebGL contexts are shared across subplots in a given graph making graphs like this one generate reasonable fast and without console warnings using only 3 WebGL contexts (compare to 35 before version 1.33.0). But for your use case this means 3 times 10 (number of graphs) WebGL contexts on your page which is above Chrome's threshold.
We aren't planning on extended WebGL-context sharing across multiple graphs in the near future unfortunately, but it's something we should think about. So, thanks very much for posting. In the meantime, I suggest converting your 10 graph <div>s into subplots on the least number of graph <div>s possible. Sorry for the inconvenience.
Thank you - we have a dashboard like page with many different charts that
aren't really subplots
We need scattergl since we load a large quantity of points.
We should give https://github.com/regl-project/multi-regl a try. It might be just what we need here.
I saw the last reply from @etpinard on #2614. It sounds like they've reduced the number of contexts used by each plot from 3 to 2. Which theoretically should allow 7 GL plots at once.
In practice, this doesn't work very well though. We're constantly updating the plot data and layout, and after trying out the various Plotly methods (update(), relayout(), etc.), the only option that worked for the extensive and arbitrary updates we must allow for is to purge() and then recreate with plot(). This introduces a ton of complications though (maintaining zoom, maintaining selection, maintaining modebar state, etc.). I've dealt with most of these (though it was certainly not easy).
Apparently, a purge() tears everything down and attempts to release the GL context(s) back to the browser's pool. However, it seems like this release is not immediate/synchronous (it looks like they are garbage collected eventually, but not necessarily instantly). So "out of context" warnings will often appear, even if the browser _subsequently_ gets the released context back again after the next GC run.
So, one thing that could help is to provide a way to re-create a chart (like a purge() + plot()), but in a way that tells Plotly to re-use the previous contexts instead of releasing them and trying to grab 2 more from the browser pool. Perhaps a Plotly.replot() function, or something similar?
Obviously, it would also help if each plot only used one context (instead of two). If each plot used one context, and we could re-create plots while continuing to use the same contexts, that would allow for up to 16 GL plots.
Now, an ever better option would be to share contexts across all of the plots. To help with performance, the best option would be a way to tell Plotly to pre-allocate N contexts to a "Plotly GL context pool", and use them as needed across all plots on the page. So we could set this to 12, or 14 or whatever we wanted to. We have chart sets that include a Cesium plot, so we need to allow for some contexts to be used outside of Plotly.
On a loosely related note, I have an open issue with Chrome to make the GL context limit configurable (https://bugs.chromium.org/p/chromium/issues/detail?id=771792#c10). The limit of 16 was chosen arbitrarily, and anyone with a powerful GPU should easily be able to handle more than 16.
We're constantly updating the plot data and layout, and after trying out the various Plotly methods (update(), relayout(), etc.), the only option that worked for the extensive and arbitrary updates we must allow for is to purge() and then recreate with plot()
That shouldn't happen. Calling Plotly.relayout or Plotly.update should not create new WebGL contexts (unless you're restyling from an SVG trace to a WebGL trace).
Would you mind sharing a reproducible example?
The problems we had with relayout() and update() weren't related to WebGL contexts, but were related to trying to get the arbitrary updates we must make to go through:
restyle() doesn't work, because each trace's data is changing independent of the others (X/Y values, individual point color, size, etc.). Further, traces can also be getting added and removed.relayout() seems fine for updates to only the layout, but our updates are usually to both the trace data and the layout.update() covers both cases, but doesn't account for the fact that traces may be getting added and removed, nor the fact that the X/Y arrays, individual point color, size, etc. for each trace are changing separately.At one point I tried combining several of these (e.g.: deleteTraces() + addTraces() + relayout()), but running each of these on each plot was actually slower than just re-creating it with a purge() and a plot().
I have not had a chance to look at react() yet, since it is very new. Does it maintain the GL context?
At one point I tried combining several of these (e.g.: deleteTraces() + addTraces() + relayout()), but running each of these on each plot was actually slower than just re-creating it with a purge() and a plot().
Ha I see. You might want to try our newest API method Plotly.react.
Right, I mentioned react() in the last line above. Would using react() re-use the existing WebGL contexts for the plot?
Would using react() re-use the existing WebGL contexts for the plot?
Yes :tada:
OK, that may be something to look at. It would help with the asynchronous release of the contexts causing context limit errors. However, the underlying issue of allowing for more than 6 or 7 GL plots at once is still a challenge. Some sort of context sharing across all of the GL plots would be a great option.
I've also looked at subplots to handle this, but the lack of a modebar for each subplot is one issue (e.g. can't autoscale only one subplot), and determining a "dynamic" full-screen layout for the subplots is challenging, when the number of plots shown varies, and when the user can add and remove plots at will. Right now we're using divs with column-based flex layout for the chart sets, so they effectively use all the available browser width and height.
Another workaround is to virtual scrolling so that only 6 charts are rendered at one time.
Is there a scatter renderer that uses 2d instead of webgl? Thanks.
I'm using react-plotly.js and having the same issue, my case is a dashboard page that loads ~20 different plots with too many points. the page can handle 11 of them but after adding 12th one it starts showing the warning and some old plot randomly will be broken. The react component using the react() method underneath.
list.map((item)=><Plot
useResizeHandler
onRelayout={onLayoutChange}
onClick={onClick}
onLegendClick={onLegendClick}
onLegendDoubleClick={onLegendDoubleClick}
style={{ width: '100%', height: '100%' }}
layout={_.cloneDeep(plotProps.layout)}
config={{
displaylogo: false,
scrollZoom: true,
modeBarButtonsToRemove: ['sendDataToCloud'],
}}
/>)
in case someone finds this helpful, i'll plug https://github.com/leeoniya/uPlot, which does not use GL, is lightweight and can handle hundreds of charts with millions of datapoints without issue.
This issue has been tagged with NEEDS SPON$OR
A community PR for this feature would certainly be welcome, but our experience is deeper features like this are difficult to complete without the Plotly maintainers leading the effort.
Sponsorship range: $25k-$30k
What Sponsorship includes:
Please include the link to this issue when contacting us to discuss.
Most helpful comment
We should give https://github.com/regl-project/multi-regl a try. It might be just what we need here.