← Blog

michi-vz chart by chart: line, range and fan

August 26, 20265 min read

This is part 1 of 9 in a series touring all 22 michi-vz chart types, family by family. The series starts in Introducing @michi-vz.

First stop: the time series family. Three charts that share one conviction, that a chart should show what you do not know as clearly as what you do. The fan chart at the end is literally built from the other two. Every michi-vz chart takes the same props in React, Vue, Svelte, Angular and plain HTML; the first chart below shows all four flavours, the rest show React to keep things short.

The line chart

The workhorse: values over time, one series or fifty. The michi-vz version adds two things I always ended up hand-rolling elsewhere. Every point carries a certainty flag, so forecast segments draw dashed while history stays solid, and detectGaps renders missing periods as labeled gaps instead of silently interpolating across them. The last two points of each series here are forecasts, which is why the lines turn dashed:

Live chart, rendered in your browser by @michi-vz/wc straight from the CDN. Hover it.

The data is an array of series where each point is { date, value, certainty }:

const data = [
  {
    label: "Vietnam",
    series: [
      { date: 2019, value: 1717, certainty: true },
      // ...history...
      { date: 2025, value: 1710, certainty: false, predicted: true },
    ],
  },
  // ...more series...
];
import { LineChart } from "@michi-vz/react";

<LineChart
  dataSet={data}
  width={640}
  height={320}
  xAxisDataType="date_annual"
  showDataPoints
/>;
  • detectGaps derives certainty from missing periods, so holes in the data draw as dashes without you touching the points.
  • renderer: "canvas" switches to canvas with LTTB decimation for thousands of points; props and getContext() stay identical.
  • sharedTooltip shows one crosshair tooltip listing every series at the hovered year, and zoom enables drag-to-zoom on the x axis.

Full props on the line chart API page.

The range chart

Averages flatter your data. The range chart draws the whole spread per period as a shaded band with an optional median line through it, so best case and worst case travel together. Commodity prices, temperature ranges, percentile bands: anywhere the honest answer is an interval, not a number:

Live chart, rendered in your browser by @michi-vz/wc straight from the CDN. Hover it.

One series per band; each point carries the extents and an optional median:

const data = [
  {
    label: "Arabica",
    series: [
      { date: 2019, valueMin: 2.1, valueMax: 2.9, valueMedium: 2.5 },
      // ...valueMedium is optional; it defaults to the midpoint...
    ],
  },
];
import { RangeChart } from "@michi-vz/react";

<RangeChart
  dataSet={data}
  width={640}
  height={320}
  xAxisDataType="date_annual"
  fillOpacity={0.35}
/>;
  • valueMedium draws the median line; omit it and the band midpoint is used.
  • Keep fillOpacity low when several bands overlap, or the crossing regions turn to mud.

Full props on the range chart API page.

The fan chart

Put the two previous charts together and you get the fan. A single forecast line is a lie of precision; what a forecast really says is "somewhere in this widening cone, probably here". The fan draws solid history, a dashed most-likely path, and nested confidence bands that widen into the future. Under the hood it literally composes the line and range primitives:

Live chart, rendered in your browser by @michi-vz/wc straight from the CDN. Hover it.

A fan series is a line series plus bands: history points carry certainty: true, the forecast median carries certainty: false, and each band is a confidence level with range points:

const data = [
  {
    label: "Users",
    series: [
      { date: 2020, value: 120, certainty: true },
      // ...history, then the forecast median...
      { date: 2026, value: 505, certainty: false },
    ],
    bands: [
      {
        level: 0.8,
        series: [
          { date: 2025, valueMin: 408, valueMax: 492 },
          { date: 2026, valueMin: 428, valueMax: 582 },
        ],
      },
      // ...a narrower 0.5 band on top...
    ],
  },
];
import { FanChart } from "@michi-vz/react";

<FanChart
  dataSet={data}
  width={640}
  height={320}
  xAxisDataType="date_annual"
  forecastZone
/>;
  • forecastZone shades the forecast region from the last solid point onward, so the reader sees where history stops.
  • Bands draw widest first, so narrower intervals always sit on top with graduated opacity.
  • No confidence intervals in your data? @michi-vz/insights computes a Holt-Winters forecast with bands in the browser.

Full props on the fan chart API page.

Next in the series: area, stack bar and ribbon.