I have a web app which uses Node canvas to plot points on a graph. Each point is called an 'event'. An event is an array of usually 6 'parameters' represented as numbers. My app allows users to plot 2 different numbers from each event on an XY graph.
E.g. say one event is:
// Event 1 (e1) is
[69876, 7, 210089, 122000, 7676, 189909]
// Event 2 (e2) is
[78, 23782, 66976, 253990, 2310, 88213]
If the user chooses to plot the 3rd and 5th parameter then then e1 is represented as 210089, 7676 and e2 is 66976, 2310. A typical plot might look like:
Typically, a graph is 300 pixels. In this case above, the maximum values any parameter can be is 262144. So to figure out where to plot I just work out the ratio:
300 / 262144 = 0.001144409
Then multiple the ratio by the x, y numbers.
So e1 will be shown at 240, 9 (210089 * 0.001144409 = 240 etc) and e2 will be shown at the pixels 77, 3.
This all works fine when there are less than 100k events. However, when there are, say, 800k events, this becomes very slow.
Is there any way of doing this more efficiently by somehow preprocessing the data? So say there are 800k events and you know the maximum value of each one is 262144 and that the graph size will be 300px, could some sort of data binning be done?
For example, the numbers 400, 550, 650 will all appear in the first pixel (since anything from 0 to 873 (262144 / 300) will fall into the first pixel on a 300px graph). Is there a method I could use to condense all this data down so that I can loop through much quicker and plot?
The code is:
for (var i = 0; i < dataAsNumbers.length; i++) {
x = dataAsNumbers[i][paramX];
y = dataAsNumbers[i][paramY];
pointX = getPointOnCanvas({
value: x
ratio: ratio
});
pointY = getPointOnCanvas({
value: y,
ratio: ratio
});
toPlotColors.push({
pointX: pointX,
pointY: pointY
});
}
paintDotsAtOnce(toPlotColors);
var getPointOnCanvas = function(params) {
var value = params.value;
var ratio = params.ratio;
return Math.floor(ratio * value);
};
var paintDotsAtOnce = function(plotColors) {
plotColors.forEach(function(plotColor){
if(plotColor.plotDot) {
memoized(plotColor.pointX, plotColor.pointY, plotColor.color);
}
});
};
var paintDotS = function(pointX, pointY, color) {
context.fillStyle = color;
context.fillRect(pointX, pointY, 1, 1);
};
var memoized = memoize(paintDotS);
So if dataAsNumbers.length
is 800k, it has to loop that many times. I'm worndering if data binning could reduce the need to do this.