uPlot in HTML: align the samples before drawing the line

Align observations by their actual x values and preserve missing readings rather than shifting values into another time slot.

Two measurements taken at different times should not share a timestamp merely because they occupy the same array position. Build one ascending x array for uPlot, then align every measurement column to it. Put null where a series has no observation instead of sliding the next value into that slot.

This fictional test-bench extract uses elapsed seconds rather than calendar dates:

Sensor histories: aligned observations and a missing-value gap
Sensor histories: aligned observations and a missing-value gap
Open the full example ↗

Open the complete example · Download the full HTML source

Elapsed seconds Sensor A, °C Sensor B, °C
0 21 20
10 23 Not recorded
20 22 24

Sensor B has two readings, not three. A summary that treats its missing reading as zero would answer a different question from the one in this source.

Use the aligned data structure

The uPlot 1.6.32 documentation describes numeric, unique, ascending x values and aligned y arrays. For the table above, the input is:

const data = [
  [0, 10, 20],
  [21, 23, 22],
  [20, null, 24]
];

const options = {
  width: 600,
  height: 300,
  scales: { x: { time: false } },
  series: [
    { label: 'Elapsed seconds' },
    { label: 'Sensor A (°C)', stroke: '#335d9b' },
    { label: 'Sensor B (°C)', stroke: '#a75230', spanGaps: false }
  ]
};
const chart = new uPlot(options, data, document.querySelector('#plot'));

Load the matching JavaScript and CSS distributions before creating the chart. Set the width from the available container in the finished page; the numeric width above only makes the initialization shape explicit.

time: false matters here. The values mean seconds since the start of this fictional run. They are not Unix timestamps. If your real x values are calendar timestamps, document the unit and timezone instead of borrowing this elapsed-time setting.

Leave missing observations visible

Keep the table below the chart and write “Not recorded” for the null cell. The gap belongs to the source, not the styling. Do not fill it by averaging neighboring temperatures unless your analysis explicitly calls for interpolation and labels the derived value.

For this fixture, Sensor A has three recorded observations and Sensor B has two. Their recorded-value means are both 22 °C: (21 + 23 + 22) / 3 and (20 + 24) / 2. Equal means do not mean the two measurement histories are identical.

If you offer a control to hide Sensor B, keep that action separate from deleting its data. Label the control as a view choice and leave the source table available. A reviewer should know whether a series is hidden, missing, or absent from the file.

Update the chart you already created

The versioned type declarations include setData() and setSize(). Use setData(nextData) when replacing aligned observations, and setSize({width, height}) when the container changes size. Avoid appending another chart every time the browser width changes.

Validate array lengths, x ordering, and numeric values before passing replacement data to the renderer. A rejected edit should show an explanation and stop any old summary from describing the new input.

The existing interactive chart guide covers the broader handoff. For a uPlot review in NOS, keep the aligned arrays and units with the page. Ask whether the missing ten-second reading is intentional before anyone draws a conclusion from the line across the run.

Keep reading