Thursday, March 12, 2020

Published 8:56 PM by with 0 comment

Improving Plotly Performance - Coloring Plots

When doing colored marker plots in plotly, is it faster to pass an array of colors for the markers, or do 1 trace per color?
There's actually not a perfect answer here, but I found '1 trace per color' to be much faster for real use cases. The issue is that plotting n total points across m traces slows down as m increases. However, you can only really resolve 10-20 colors on a plot, so realistically you'd have 10-20 traces at most here.

Here is an example:

let count = 500000;

let x = [];
let y = [];
let colors = [];
let sourceColors = ['rgb(255, 50, 50)', 'rgb(50, 255, 50)', 'rgb(50, 50, 255)', 'rgb(155, 50, 50)', 'rgb(50, 155, 50)', 'rgb(50, 50, 155)', 'rgb(255, 50, 255)', 'rgb(255, 255, 50)', 'rgb(50, 255, 255)'];
let ncolors = 8;

//assign a color to each marker
for (let i = 0; i < count; i++) {
  x.push(i);
  y.push(Math.random());
  colors.push(sourceColors[Math.floor(ncolors*i/count)]);
}

let traces = [{
  x: x,
  y: y,
  marker: {
    color: colors
  },
  type: 'scattergl',
  mode: 'markers'
}];

let time = new Date().getTime();
Plotly.react('plot', traces).then(alert(new Date().getTime() - time));

traces = [];
counter = 0;

//create a trace for each color
for (let i = 0; i < ncolors; i++) {
  let trace = {};
  x = [];
  y = [];
  for (; counter < (1 + i)*count / ncolors; counter++) {
    x.push(counter);
    y.push(Math.random());
  }
  trace.x = x;
  trace.y = y;
  trace.type = 'scattergl';
  trace.mode = 'markers';
  trace.marker = { color: sourceColors[i] };
  traces.push(trace);
}

time = new Date().getTime();
Plotly.react('plot2', traces, { showlegend: false }).then(alert(new Date().getTime() - time));

This builds two 8 color, 500,000 point plots. The first one loops through the points and assigns a color per point to the colors array then creates on trace with that color array. The second one loops through the colors and creates a trace per color.

On my current laptop, the first one takes ~2000 ms to render and the second one takes ~500 ms to render. For the same view for the user, the '1 trace per color' implementation is 4x faster. The tool I hit this with allows users to really quickly view up to ~1M points at a time, so this was an enormous difference. As an example in the actual tool, total processing from click to finished render went from ~3500 ms to ~1000 ms.

For small amounts of data, this won't matter much, but there are situations where this is a massive impact so it's a cool thing to have available.

Click here for a working demo.


      edit

0 comments:

Post a Comment