Horizon Chart Tutorial

Kenya life expectancy Horizon chart

This chart folds Kenya’s life expectancy above and below a 55-year baseline into three compact bands. The source rows stay immutable. encodeHorizon creates one derived dataset and ordinary closed area paths, so Browser Canvas and Node PNG use the same backend-neutral graphics.

The repository contains a runnable browser example and its complete program.

Complete program

import { chart, render } from "ggaction";

const response = await fetch("/gapminder.json");
if (!response.ok) throw new Error(`Failed to load data: ${response.status}`);
const gapminder = await response.json();

const program = chart()
  .createCanvas({
    width: 760,
    height: 300,
    margin: { top: 78, right: 30, bottom: 58, left: 50 }
  })
  .createData({ values: gapminder })
  .filterData({ id: "kenya", field: "country", oneOf: ["Kenya"] })
  .createAreaMark({ curve: "monotone" })
  .encodeHorizon({
    x: "year",
    y: "life_expect",
    bands: 3,
    baseline: 55,
    palette: { positive: "blues", negative: "reds" }
  })
  .createGuides({ axes: { y: false } })
  .createTitle({
    text: "Kenya Life Expectancy",
    subtitle: "Blue above, red below · three folded bands around 55 years"
  });

render(program, document.querySelector("#chart").getContext("2d"));

What the atomic encoding owns

Decision Result
baseline: 55 Values are represented as signed deviations from 55
bands: 3 Each sign is divided into three equal-amplitude folds
extent: "auto" The largest absolute deviation defines the shared band height
missing: "break" Missing y values split, rather than bridge, a path
overflow: "clip" An explicit smaller extent clips excess amplitude

The folded y scale is always [0, 1]. Because its ticks would describe folded amplitude rather than the original life-expectancy values, Horizon guide policy creates only the original x axis and grid and no automatic legend.

Revise without mutation

const revised = program.editHorizon({
  bands: 4,
  baseline: 58,
  palette: { positive: "teals" }
});

The revision keeps the source dataset and scale IDs, creates a new namespaced derived dataset, rebinds the same area layer, and removes the old revision only when no layer still references it. The earlier program remains unchanged.

Key action trace

program
├─ createAreaMark
├─ encodeHorizon
│  ├─ createHorizonData
│  │  └─ materializeHorizonData
│  ├─ rebindLayerData
│  ├─ encodeX
│  ├─ encodeY
│  ├─ encodeGroup
│  ├─ encodeY2
│  └─ encodeColor
├─ createGuides
└─ createTitle

Continue with Encodings, Area marks, and Faceting.