Parallel coordinates chart - design
See original GitHub issueApproach
This issue is dedicated to parallel coordinates. As this is the first new chart where we’re moving away from past gl-vis/***2d
charts, some of the discussions is broader than that.
As we discussed on the requirements meeting, it’s not easy to have both full, continuous interactivity and a lot of lines, because of the large number of lines (1k and up) either overload the shaders (no matter if WebGL or Canvas2d) or there’s a need for time-consuming preprocessing e.g. splatting (we might be able to do on-GPU splatting but probably it’s best to start with something simple, reasonably fast and direct).
So our requirements analysis said that - esp. with more than 1k lines - the axis sliders would be debounced, and would only render when the user stops for a bit or releases it. Even with this, a direct rendering is only good till about 10k…20k lines (around 100ms to generate) and beyond that, the direct approach would need incremental rendering. So here’s an approach under consideration:
- Unlike with many current charts, we should avoid the rerender on every frame (useful irrespective of chart type, because it minimizes processing load) - and similarly, we should avoid “dummy renders”, when a chart is getting initialized by rendering it with empty data, to be followed up by subsequent updates with more and more of the necessary input
- As a consequence, the line bundle (here shown as 16k blue lines) and the interactive stuff (tooltip, axis slider etc) should reside on separate layers (can be WebGL + SVG, WebGL + Canvas2d, WebGL + WebGL irrelevant for this point)
- We may need more layers, e.g. for some kind of a backdrop
- This means that the blue line bundle can be rendered with whatever is fastest (Canvas2D or WebGL)
- Here’s the weird part 🔥 : on low-end hardware (13" Retina Macbook Pro) perf tests show Canvas2d to be faster for interesting cases (with this example, 100ms vs 500ms render time) - and I tried a couple ways of rendering lines in WebGL (though no splatting yet). Canvas2d uses hardware acceleration i.e. the GPU, and probably a lot of work went into optimizing it. On powerful GPUs the bottlenecks are probably elsewhere though.
- This 16k line image above is now generated with WebGL (
regl
) or Canvas2d, it looks almost identical (minuscule blending hue difference) - Canvas2d is lightweight in that there’s no additional code dependency, i.e. there’s no significant bundle size increase if we use it; also, it’s much quicker to prototype and do exploratory coding with Canvas2d than with WebGL
- As a consequence, it looks simplest to do layers in Canvas2d and/or SVG, and at some more mature stage (still within this PR) plug in WebGL (via
regl
) for the heavy-lifting layer to see if it does better or worse - this way we don’t end up with the rather large code differences between non-WebGL and WebGL versions - Therefore the calculations should be substrate independent; loose coupling between the
viewModel
and the renderer - Since WebGL, and the eventual need for Web Workers suggests typed arrays, the parcoords proto-prototype uses typed arrays internally; Canvas2d/SVG can use it too; we can preface it with an untyped -> typed conversion for users
- Since typed arrays are 1-dimensional arrays but in reality encode multiple dimensions, the parcoords prototype is using
ndarray
- it’s already part of our dependency stack so no code increase, and perf profiling shows essentially no speed cost relative to indexing manually. It makes the code a lot more readable. - In conclusion, the experiences point to a code structure with a linear flow of data (also in line with current
plotly.js
practices):- user input
- arrive at defaults
- calculate a common viewModel
- populate and render multiple layers, which may be of a heterogenous type, some of them alternatives to one another, and some of them getting new versions as part of shorter iterations (e.g. an SVG or Canvas2d layer gets a WebGL /
regl
alternative)
Issue Analytics
- State:
- Created 7 years ago
- Comments:26 (20 by maintainers)
@ibayer the
parcoords
inplotly.js
does emit events on line hover and unhover. For an example navigate to this codepen, open the Dev Console and see events makingconsole.log
calls:Other events on interactions also show up.
@tantrev yes, that’d be a good addition, it’s not trivial due to how lines are currently rendered with WebGL and we didn’t have it in the original scope, but an additional SVG overlay for a single polyline looks feasible. I’m not sure how this item would be scheduled, maybe the next time we need to make a round of improvements to parcoords.