question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

1.0, modularity, future.

See original GitHub issue

uPlot will just cross 20 KB in size shortly, so it’s good to review some things.

uPlot is currently monolithic, though it’s odd to use that term when the next largest lib is 6x bigger and doesn’t do that much more (and in some cases, less). it’s monolithic because it is not possible to opt out of unused features. e.g:

  • few actual use-cases need cursor sync (which pulls in with it a pub-sub impl)
  • the candlesticks demo does not need any of the line drawing code, or cursor points.
  • the sparklines demo does not need anything but scales and line drawing code
  • any line chart not needing a time scale does not need the code used for temporal tick gen, the date formatters, timezone/dst handling, etc.

one benefit of a monolith is reduced code size when you actually do need everything - a modular design would probably be 15-25% larger. another possible monolith benefit is performance because features need to cross fewer API boundaries to get things done by having direct access to internals structures and functions.

i’ve considered several avenues to solving this.

  1. adding feature gating to the build script as i do with domvm [1]. this allows uPlot to remain a monolith, but also offers a way to opt out of including parts of the API a user might not use. e.g. FEAT_TIME, FEAT_LINE, FEAT_SYNC. this provides a workable alternative to “tree-shaking” in a monolithic architecture.
  2. converting some features into plugins. now that we have a pretty solid API, it’s likely possible to move some things out of the core. however, there are still large parts which cannot be moved out efficiently or effectively. cursor sync is perf-sensitive, and using hooks/plugins for this will not be ideal. cursor and hover points can probably be moved out, as can select. live legend can be moved out. temporal features cannot really be moved out. in the end i think this will be only be a half-solution.
  3. changing the API to be more ES6-ish and allowing external tools like rollup to shake away unused code. the main issue with this is that the opts can no longer be simple keys/values. e.g. you’d need to define stuff with actual exported functions and be more verbose everywhere: scales.x: {time: true} would become something like scales.x: uPlot.TimeScale(scaleOpts), cursor: uPlot.Cursor(cursorOpts). this would invalidate a large swath of the current API, and require the end user to compile/bundle the ES6 modules.

long-term, option 3 is likely the way to go but will require a significant refactor and major API changes. this is something i will evaluate for v2.0, but this conversion will take time, increase the API complexity and ultimately may not be worthwhile.

on the other hand, the feature-gating route can work without major breakage and still provide good size savings when needed.

i’d like to get v1.0 tagged within the next couple weeks and given all the above, i’m going to make several final breaking API changes.

  1. new uPlot.Line(opts) does not make sense if we’re staying a monolith and the line drawing functionality can be disabled (like candlesticks and bars [2]) or even feature-gated away. the best way to describe the common core of uPlot 1.0 is Cartesian-Columnar, which describes the format of data it accepts and the type of chart it outputs (regardless of whether it has lines, points, fills, candlesticks, time. or numeric components. i’m going to go back to the original naming for v1.0: new uPlot(opts).
  2. in the same vein as above, i’m going to move line-specific options inwards 1 level to a new series.line: {width, stroke, fill, dash, paths}. #10 will bring a new series.points, so this will help with uniformity, as well as avoid awkwardness if line-drawing features are gated away.
  3. i may future-proof cursor.points: true by moving to cursor.points: {show: true}
  4. all dimensions in the opts will be in CSS pixels. currently series.width is in canvas pixels, which guarantees crispness at high data densities, but the line thickness becomes pixelRatio dependent. this means that if you have a lot of data and prefer crispness over line thickness uniformity, you would explicitly set series.line.width: 1/devicePixelRatio.

cc @ldstein @danyalejandro @CrashLaker @dgl @silverwind

[1] https://github.com/domvm/domvm [2] https://github.com/leeoniya/uPlot/issues/9#issuecomment-590289541

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:10 (9 by maintainers)

github_iconTop GitHub Comments

5reactions
leeoniyacommented, Mar 10, 2020
1reaction
leeoniyacommented, Feb 27, 2020

i’m not sure i want to go that generic with uPlot, as there are other libs which already fill this space, e.g. https://vega.github.io/vega/ which is an entire visualization grammar that can have an infinite number of renderers, then there’s d3 which is somewhere in the middle.

i’d like to stick to canvas as i don’t think any other options are likely to ever be as fast as raw canvas, and only svg or webgl has any hope of even being interactive; the rest are just static charts, for which many other libs exist.

i’ve noticed a new webgl plotting lib that looks nice for when you need oscilloscope-level update rates: https://github.com/danchitnis/webgl-plot. i think it makes a great complement to uPlot in terms of micro-libs but it has its obvious limits, too: “cannot change the line width due to the OpenGL implementation of a line. The OpenGL specification only guarantees a minimum of a single pixel line width. There are other solutions to increase the line width however they substantially increase the size of data vector and take a hit on the performance.”

One approach would be for the engine to generate a simple JSON array of Path2D-like commands:

this will not work without an absolutely massive perf hit for the sizes of datasets that uPlot currently excels at. an alternative may be to provide a pluggable renderer interface where each command is a function call into your renderer, but this would be such a thin layer over just defining your own series.paths as to make it quite pointless.

once i’ve added feature-gating to the build script and v1 is stable for a while, i’ll get back to giving this more thought, but i need a good break from the endless refactoring & abstraction-building cycle.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Materiology 1.0: What Happens When Tomorrow Becomes ...
The future seems to always remain at an unsettling end in our lives. Confusing, alienating and uncanny. However, what is often forgotten is...
Read more >
Chapter 4: Modularity — notes 1.0 documentation
Chapter 4: Modularity. Compactness; Orthogonality; The SPOT Rule; Software Is a Many-Layered Thing. In the beginning, everything was one big lump of machine ......
Read more >
Java 9, OSGi and the Future of Modularity (Part 1) - InfoQ
Java has grown by 20 times since version 1.0, and there is a need to modularise the platform. There have been many unsuccessful...
Read more >
Modularity for International Internet Governance - Lawfare Blog
The modern-day “global” internet faces a dubious future. ... Modularity offers many advantages for digital platform governance.
Read more >
Announcing cadCAD 1.0: Foundations for a New Era of Open ...
Community Update — cadCAD 1.0 Launch, Upcoming Bounties & New Model ... They wanted more flexibility and modularity in the way it is ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found