Monday, November 18, 2019

Published 8:26 PM by with 0 comment

How to Render Plotly Plots in Order

Ever wanted to put up a bunch of plots on your page, and have them render in a specific order instead of all at once? Here's a quick tutorial.
First, let's see an example of what I mean by all at once. Click this link, and you should see nothing for a while, and then see 9 plots. What's the code look like? Just change the view to editor in that link to see the full code sample. The important part is this though:

Plotly.react('plot1', traces, layout);
Plotly.react('plot2', traces, layout);
Plotly.react('plot3', traces, layout);
Plotly.react('plot4', traces, layout);
Plotly.react('plot5', traces, layout);
Plotly.react('plot6', traces, layout);
Plotly.react('plot7', traces, layout);
Plotly.react('plot8', traces, layout);
Plotly.react('plot9', traces, layout);

That executes each plot render one after the next with no break between them. Thus, the screen actually updates with the plots all rendered after the 9th one renders.

What if you want to render the first one, then the second, and so on? Click this link and you should see just that. Again, change the view to editor in that link to see the full code sample. The important change though is that the code from above has been replaced with this:

Plotly.react('plot1', traces, layout).then(setTimeout(function() {
Plotly.react('plot2', traces, layout).then(setTimeout(function() {
Plotly.react('plot3', traces, layout).then(setTimeout(function() {
Plotly.react('plot4', traces, layout).then(setTimeout(function() {
Plotly.react('plot5', traces, layout).then(setTimeout(function() {
Plotly.react('plot6', traces, layout).then(setTimeout(function() {
Plotly.react('plot7', traces, layout).then(setTimeout(function() {
Plotly.react('plot8', traces, layout).then(setTimeout(function() {
Plotly.react('plot9', traces, layout)}, 5)) }, 5)) }, 5)) }, 5)) }, 5)) }, 5)) }, 5)) }, 5));

Each plotly react call returns a promise that resolves when rendering is finished. You just execute the next one in the 'then' method. 'setTimeout' is used to allow a screen update to go through between the promise resolving and the next one starting. That's super-hard-coded though right? How could you make this generic? Further, how could you make it so that you could render them in groups of three instead of one at a time? Here's an example of that:

plotGroups(1, 9, 3);

async function plotGroups(plotNum, totalPlots, groupSize) {
  
  //return if done
  if ((plotNum + groupSize) > (totalPlots + 1)) {
    return;
  }
  
  //make array of promises and wait for all to resolve
  let reqs = [];
  for (let i = 0; i < groupSize; i++) {
    reqs.push(Plotly.react('plot' + (plotNum + i).toString(), traces, layout));
  }
  await Promise.all(reqs);
  
  //call recursively with next set
  setTimeout(function() { plotGroups(plotNum + groupSize, totalPlots, groupSize) }, 5);
}

It's still got some hard-coding...I have the plot names hard-coded in order and I'm relying on that, I'm artificially sharing traces and layout among all plots, etc. It should be simple to adapt this to a similar use case though (e.g., pass in arrays of plot names and trace/layout pairs). I'd actually never written a recursive, async method, so it was kind of cool that it just worked as easily as it seemed like it could.

Anyway...that's it. The fact that plotly plotting methods return promises makes this pretty simple to do.



      edit

0 comments:

Post a Comment