I wrote a processing.js visualization for displaying pair-wise information as a triangle-plot/heatmap.
Here is a working jsfiddle version: http://jsfiddle.net/timeu/uK6SB/
Performance is somehow fine, however I think there might be some room for improvement.
Basically in the above example I display 691 pair-wise information (477481 float values between 0 and 1) as a heatmap.
As I am only interested in a certain range so I only color-code values above a certain threshold (0.3 in my case).
After filtering I end up with approximately 10 000 float values for which I have to display colored rectangles.
When the user moves the mouse over a datapoint it will grey out all values and only highlight the selected one and display the pair-wise value in the scaler on the left side.
The plot is created using following steps:
- Create a rectangle with a blue background (for all values below the threshold)
- Create colored rectangles for all values above the threshold (around 10.000)
- Rotate and translate the screen to create the triangle effect
When the user moves the mouse above a datapoint it does following steps in additional to the above ones:
- Draw a half transparent grey rectangle over the whole plot (to grey out all other values)
- Redraw the datapoint
In my first naive approach I redraw the whole plot when I the highlighted datapoint is changed.
However performance was really bad. After profiling I found out that redrawing 10.000 rectangles is the bottleneck.
To fix this I draw the initial plot once into a backbuffer (in processing.js one can use a PImage) and then just re-draw the backbuffer when I need to update the plot. This significantly improved performance.
However when I display the plot with a really high resolution (above 2000 pixels), performance degrades quite a bit. After profiling I found out that toImageData
(re-drawing the backbuffer) takes most of the time.
I did some research on how to improve canvas performance (html5rocks,msdn,stackoverflow)
So I came up with following possible improvements:
- As I only display a maximum of 500 points (-> 250.000 float values) I could just render my plot with a resolution of 500x500 px and then use hardware upscaling to upscale to the native resolution.
- I calculate the size of the rectangle by dividing the width of the canvas by the number of points. Most of the time I end up with floating point coordinates which lead to subpixel rendering and bad performance. However rounding is not an option as I have the requirement to use up all the available space (if I round up I won't see the complete plot and if I floor the coordinates the plot doesn't span the entire canvas). Is there a solution?
- Instead of redrawing the whole backbuffer when I highlight a different datapoint I could somehow use clearRect and redraw the parts that have changed. Not sure how exactly this can be done tough.
I would be thankful for any feedback or additional performance suggestions.