A time-to-value sawtooth chart for cumulative series, inspired by Romain Vuillemot's Observable notebook and the BioVis 2020 paper.
The chart splits cumulative values into fixed value bands with cumbin, resets each band to zero, and uses each segment slope to show how long that band took to accumulate.
This repository follows the same shape as cumbin:
fixtures/ shared JavaScript/Python expected outputs
packages/javascript/ npm package
packages/python/ PyPI package
examples/sawtooth/ D3, Vega, and notebook examples
runDev.sh test and serve local examples
runPublishNpm.sh npm package checks and publish helper
runPublishPyPi.sh Python package checks and publish helper
import { sawtooth, sawtoothSvg } from "sawtooth-chart";
const data = [
{ country: "A", date: "2020-03-01", deaths: 0 },
{ country: "A", date: "2020-03-06", deaths: 500 },
{ country: "A", date: "2020-03-10", deaths: 1000 }
];
const spec = {
time: "date",
cumulative: "deaths",
binSize: 500,
groupBy: "country"
};
const rows = sawtooth(data, spec);
const svg = sawtoothSvg(rows, spec, { groupBy: "country", timeLabel: "days" });
document.querySelector("#chart").innerHTML = svg;from sawtooth_chart import sawtooth, sawtooth_svg
data = [
{"country": "A", "date": "2020-03-01", "deaths": 0},
{"country": "A", "date": "2020-03-06", "deaths": 500},
{"country": "A", "date": "2020-03-10", "deaths": 1000},
]
spec = {
"time": "date",
"cumulative": "deaths",
"binSize": 500,
"groupBy": "country",
}
rows = sawtooth(data, spec)
svg = sawtooth_svg(rows, spec, chart={"group_by": "country", "time_label": "days"})From this repository root:
./runDev.shOpen:
http://127.0.0.1:8125/examples/sawtooth/
http://127.0.0.1:8125/examples/sawtooth/vega.html
http://127.0.0.1:8125/examples/sawtooth/python_notebook.ipynb
The default browser example is written directly in D3.js and mirrors the original sawtooth design: fixed value bands are placed side by side in one shared chart, with slope encoding time-to-value. The Vega example uses the same sawtooth() rows as inline Vega data. The notebook demonstrates the Python mirror against the same sample data.
Generate the Python SVG example:
python3 examples/sawtooth/python_sawtooth.pyThe examples use cumbin as the cumulative binning dependency. runDev.sh runs the shared JavaScript and Python fixture tests, checks the notebook JSON, links a sibling ../cumbin checkout when cumbin is not installed, generates the Python SVG example, and serves the D3, Vega, and notebook examples.
Observable notebooks can import the package directly:
import { sawtooth, sawtoothSvg } from "npm:sawtooth-chart"For a dynamic CDN import of the published 0.1.0, use:
sawtooth_chart = (await import("https://esm.unpkg.com/sawtooth-chart@0.1.0/sawtooth-chart.js")).defaultAfter the JavaScript package 0.1.1 is published, the raw UNPKG file also works because cumbin is packaged as a relative module:
sawtooth_chart = (await import("https://unpkg.com/sawtooth-chart@0.1.1/sawtooth-chart.js")).defaultPublish the npm update:
./runUpdateNpm.shnpm test
npm run test:js
npm run test:pyBoth package test suites read the same JSON fixtures from fixtures/ and compare the mirrored time-to-value rows. The fixtures also exercise SVG rendering through shared expected substrings.