Visualize Time Series Data With μPlot Library

Category: Chart & Graph , Javascript , Recommended | January 16, 2021
Author: leeoniya
Views Total: 10 views
Official Page: Go to website
Last Update: January 16, 2021
License: MIT


Visualize Time Series Data With μPlot Library


μPlot is a lightweight, interactive, scalable, high-performance chart library to visualize any time series data (a series of data points indexed in time order) using Canvas API.

More features:

  • Crosshair cursor.
  • Configurable x and y-axis.
  • Legend with live values.
  • Dynamic data fetching.

How to use it:

1. Download and import the μPlot library.

<link rel="stylesheet" href="uPlot.css">
<script src="uPlot.iife.min.js"></script>

2. Prepare the time series data.

const data = [

      // x-values (Unix timestamps)
      [1566453600, 1566457260, 1566460860, 1566464460], 

      // data series 1  
      [0.54, 0.15, 3.27, 7.51],

      // data series 2
      [12.85, 13.21, 13.65, 14.01],

      // data series 3
      [0.52, 1.25, 0.75, 3.62]


3. The example JS to initialize the μPlot Library.

let myChart = new uPlot({

    // width/height in pixels
    width: 960,
    height: 400,

    // chart title
    title: "My Chart",

    // unique chart ID
    id: "chart1",

    // additional CSS class(es)
    class: "my-chart",

    // determines how to present your data
    series: [
        // initial toggled state (optional)
        show: true,
        spanGaps: false,
        // in-legend display
        label: "RAM",
        value: (self, rawValue) => "$" + rawValue.toFixed(2),
        // series style
        stroke: "red",
        width: 1,
        fill: "rgba(255, 0, 0, 0.3)",
        dash: [10, 5],

    // customize the x, y axis
    axes: {
      y: [
          scale: '%',
          values: (vals, space) => => +v.toFixed(1) + "%"),
          side: 3,
          scale: 'mb',
          values: (vals, space) => => +v.toFixed(2) + "MB"),
          grid: null,
}, data, document.body);

4. Default x-axis options.

scale: 'x',
space: 40,
height: 30,
side: 0,
class: "x-time",
incrs: timeIncrs,
values: (vals, space) => {
  let incr = vals[1] - vals[0];

  let stamp = (
    incr >= d ? fmtDate('{M}/{D}') :
    // {M}/{DD}/{YY} should only be prepended at 12a?   // {YY} only at year boundaries?
    incr >= h ? fmtDate('{M}/{DD}\n{h}{aa}') :
    incr >= m ? fmtDate('{M}/{DD}\n{h}:{mm}{aa}') :

  return => stamp(new Date(val * 1e3)));
grid: {
  color: "#eee",
  width: 2

6. Default y-axis options.

scale: 'y',
space: 30,
width: 50,
side: 1,
class: "y-vals",
incrs: numIncrs,
values: (vals, space) => vals,
grid: {
  color: "#eee",
  width: 2

7. Default options for the time series data on the x-axis.

label: "Time",
scale: "x",
value: v => stamp(new Date(v * 1e3))

8. Default options for the time series data on the y-axis.

shown: true,
label: "Value",
scale: "y",
value: v => v


1.6.1 (01/16/2021)

  • tweak/fix some y scale auto-ranging behavior

1.6.0 (01/13/2021)

  • handle scale orientation for selection, drag & sync

1.5.2 (12/16/2020)

  • improved hover-point alignment

1.5.1 (12/12/2020)

  • join(): skipGaps bools -> nullModes flags

1.5.0 (12/11/2020)

  • extract addGap() & clipGaps() from closure (expose as util fns). rename uPlot.alignData() -> uPlot.join()

1.4.7 (12/04/2020)

  • update

1.4.6 (11/28/2020)

  • fix tooltip-closest chart size for small screens

1.4.4 (11/21/2020)

  • add {data, isGap} signature to setData() & constructor

1.4.2 (11/19/2020)

  • update

1.4.0 (11/19/2020)

  • dynamic gutter sizing

v1.3.0 (11/06/2020)

  • Bugfixes

v1.2.2 (09/29/2020)

  • fix axis splitting for year+ incrs to account for leap years.
  • improve empty chart creation. init default x/y scales without relying on x/y series presence.
  • add raw xValue arg to cursor.dataIdx() to simplify adjustment of the hovered points.

v1.2.1 (09/18/2020)

  • fix ESM build
  • decouple axis splits filtering from splits formatting (add axis.filter(), axis.grid.filter(), axis.ticks.filter())
  • fix series.fill for log scales trying to fill to non-existent 0
  • log base 2 support as axis.log: 10
  • fix rounding errors in rangeLog() which threw an infinite loop for values < 1e-3
  • some internal cleanup and optimizations

v1.2.0 (09/16/2020)

  • [BREAKING] expansion and improvement of the temporal axis.values config array
  • fix a long-standing bug where series hover points were cut off at plot edges
  • {select: {over: true}} ability to choose whether .u-select is placed inside .u-over as previously, or .u-under. this is now relevant since .u-over is no longer overflow: hidden and it’s possible for a programatically-set selection inside .u-over to visually overflow the plot bounds
  • false can be used to exclude a series’ data from being considered when auto-ranging its y scale
  • a bunch of fixes for plots with no datapoints, or single datapoint
  • much-improved line-smoothing demo using Centripetal Catmull-Rom Spline algo

v1.1.2 (08/25/2020)

  • fix: DST rollover periods were dropping axis splits when zoomed in to <= 1hr resolutions.
  • fix: more accurate floating point math when generating axis splits with decimals.
  • fix: regression caused by precision increase and add more guards against infinite loops.
  • fix-demo: tooltips-closest failed to toggle tooltip display on plot re-entry.
  • fix-demo: tooltips-closest was drawing interpolated markers outside plotting area when zoomed in.

v1.1.1 (08/22/2020)

  • new: series.fillTo() API to adjust the area-fill baseline (instead of always 0)
  • new: cursor.move callback to refine or snap cursor position
  • new: false option to disable live cursor values (static legend)
  • fix: force update legend for setData() calls, even when cursor.idx is unchanged
  • fix: also defocus hovered points when defocusing inactive series
  • fix: typings & demos

v1.1.0 (08/03/2020)

  • new: logarithmic scales (via scale.distr: 3)
  • new: uPlot.rangeLog() and uPlot.fmtNum() util funcs
  • new: cursor.dataIdx can now transform the hovered idx to a different data idx used for legend display and cursor hover points
  • chg: all CSS classes are now prefixed with u-. also, some legend classes got better names
  • chg: axis functions now receive axisIdx as an argument
  • chg: axis.split option renamed to axis.splits
  • fix: saner & more consistent scale padding (ranging) behavior

v1.0.11 (06/16/2020)

  • fix for data gaps (null values) at start and end of datasets when spanGaps: true
  • fix for plots with leading/trailing gaps and only single data point
  • fix for initially empty-data plots improperly retaining initial y-scale min/max after first setData() call
  • fix for deleting a series when false

v1.0.10 (06/08/2020)

  • fix path filling oddities when spanGaps was used with leading or trailing null data
  • fix an init bug by setting default y scales
  • perf optimizations for mousemove & legend display

v1.0.7 (05/04/2020)

  • ensure chart position cache is always in sync
  • ensure scale.range can get current scale min/max
  • TS defs fixups
  • various fixes for charts without data

v1.0.7 (04/23/2020)

  • fix legend showing junk in legend when cursor is enabled without data in chart
  • .redraw() will now force-rebuild the paths, unless false is passed in to opt out
  • axis.rotate for user-defined x-axis label rotation

v1.0.6 (04/12/2020)

  • fixed scale ranging for a single data points (where dataMin == dataMax)

v1.0.5 (04/05/2020)

  • fix esm build regression caused by recent refactor.

v1.0.4 (04/05/2020)

  • opts.fmtDate & new “names” arg for uPlot.fmtDate() for redefining month and weekday names.
  • .syncRect() for handling plot position changes unrelated to window scroll & resize.
  • new post-init series apis: “.addSeries(opts, idx)” and “.delSeries(idx)”

v1.0.3 (03/28/2020)

  • TypeScript declarations for API
  • better Webpack compat by avoiding a lone use of this
  • perf optimization to point rendering
  • minor api tweaks (u.idxs -> u.series[i].idxs)

v1.0.2 (03/13/2020)

  • for the purpose of auto-adding axis gutters, treat axis.size: 0 the same as false. this avoids creating superfluous gutters which would otherwise require explicit disablement via e.g. gutters: {x: 0, y: 0}

v1.0.1 (03/13/2020)

  • You can create a custom build that disables any of these features to cut down on lib size and unused code.
  • .setSelect() now requires explicit sizing and no longer relies on cursor.drag.x or cursor.drag.y to auto-size the selection size in the drag-perpendicular dimension. the effect is that both width and height must be explicitly set. you can see the effect in this diff: a1f720d. this should have no impact on drag selection performed with a cursor, where cursor.drag is taken into account to infer the perpendicular select size.
  • the alpha option of cursor.focus was moved to a new top-level opt focus.alpha. this ensures that .setSeries(2, {focus: true}) can continue to work without relying on cursor opts. cursor.focus.prox remains in place. cursor.focus.alpha should continue to work as a side-effect of the internal option merging, but should not be relied upon going forward.


  • v1.0


  • improve pixel snapping


  • Fix high/low band series toggling

You Might Be Interested In:

Leave a Reply