Ridgeline Chart of Hourly Demand by Weekday
If you are the store planner who sets the rota, the question is not how many orders a day brings. It is when in the day they arrive, and whether Saturday has the same shape as Tuesday. Staff the tills for a Tuesday lunch rush on a Saturday and you are short from mid-morning until closing.
A ridgeline chart answers that by stacking. Each weekday gets its own smooth curve of when orders land, drawn on one shared hour axis, so the humps line up and you can read the difference at a glance. The chart above is bound to the grid beneath it, one row per order, so filtering the rows redraws the chart. Filter the Weekday column to Tuesday and Saturday and compare the two ridges alone.
Why a ridgeline and not a line per day
Seven lines on one set of axes cross and tangle until none can be followed. Stacking the curves gives each weekday its own band, so the shapes compare without the clutter, and a seventh day costs one more row of height rather than one more tangle.
The chart over a grid
The chart reads the grid’s rows, so there is nothing to keep in step. A ridgeline takes a category column, x, and a measure column, y, and draws one density ridge per category over the values of the measure. Here the category is the weekday and the measure is the hour the order was placed. Ridgeline is an opt-in chart type, so it is imported on its own beside the charts module. Here is the example in plain JavaScript, with a few inline orders standing in for your own rows.
import { createGrid } from '@toclocoinc/lattice-grid';
import '@toclocoinc/lattice-grid/css';
import { createChart } from '@toclocoinc/lattice-grid/modules/charts';
import '@toclocoinc/lattice-grid/modules/chart-ridgeline';
const rows = [
{ id: 1, weekday: 'Tuesday', hour: 9, demand: 2 }, { id: 2, weekday: 'Tuesday', hour: 12, demand: 3 },
{ id: 3, weekday: 'Tuesday', hour: 12, demand: 1 }, { id: 4, weekday: 'Tuesday', hour: 13, demand: 2 },
{ id: 5, weekday: 'Tuesday', hour: 17, demand: 4 }, { id: 6, weekday: 'Tuesday', hour: 18, demand: 2 },
{ id: 7, weekday: 'Saturday', hour: 10, demand: 2 }, { id: 8, weekday: 'Saturday', hour: 12, demand: 3 },
{ id: 9, weekday: 'Saturday', hour: 13, demand: 1 }, { id: 10, weekday: 'Saturday', hour: 14, demand: 4 },
{ id: 11, weekday: 'Saturday', hour: 15, demand: 2 }, { id: 12, weekday: 'Saturday', hour: 16, demand: 3 },
];
const gridEl = document.createElement('div');
const chartEl = document.createElement('div');
gridEl.style.height = '260px';
chartEl.style.height = '320px';
document.body.append(gridEl, chartEl);
const grid = createGrid(gridEl, {
rowKey: 'id',
rows,
columns: [
{ field: 'weekday', title: 'Weekday', filter: { type: 'set' } },
{ field: 'hour', title: 'Hour', type: 'number' },
{ field: 'demand', title: 'Units', type: 'number' },
],
});
createChart({ grid, container: chartEl, type: 'ridgeline', x: 'weekday', y: 'hour',
margin: { left: 80 }, title: 'Orders by hour of the day' });
The same thing in React
The React adapter is a factory, so you build the component once at module scope. The ref’s grid is the real grid, which is what the chart binds to.
import React, { useEffect, useRef } from 'react';
import { createGrid } from '@toclocoinc/lattice-grid';
import '@toclocoinc/lattice-grid/css';
import { createLatticeGrid } from '@toclocoinc/lattice-grid/modules/react';
import { createChart } from '@toclocoinc/lattice-grid/modules/charts';
import '@toclocoinc/lattice-grid/modules/chart-ridgeline';
const LatticeGrid = createLatticeGrid({ React, createGrid });
const rows = [
{ id: 1, weekday: 'Tuesday', hour: 9 }, { id: 2, weekday: 'Tuesday', hour: 12 },
{ id: 3, weekday: 'Tuesday', hour: 13 }, { id: 4, weekday: 'Tuesday', hour: 17 },
{ id: 5, weekday: 'Saturday', hour: 10 }, { id: 6, weekday: 'Saturday', hour: 13 },
{ id: 7, weekday: 'Saturday', hour: 14 }, { id: 8, weekday: 'Saturday', hour: 16 },
];
const columns = [
{ field: 'weekday', title: 'Weekday', filter: { type: 'set' } },
{ field: 'hour', title: 'Hour', type: 'number' },
];
export function DemandByWeekday() {
const gridRef = useRef(null);
const chartRef = useRef(null);
useEffect(() => {
const chart = createChart({ grid: gridRef.current.grid, container: chartRef.current,
type: 'ridgeline', x: 'weekday', y: 'hour', margin: { left: 80 },
title: 'Orders by hour of the day' });
return () => chart.destroy();
}, []);
return (<>
<LatticeGrid ref={gridRef} rowKey="id" columns={columns} rows={rows} style={{ height: 220 }} />
<div ref={chartRef} style={{ height: 280 }} />
</>);
}
The options used
These are the rows of the charts reference for the options in the listings above.
| Option | Type | What it does |
|---|---|---|
grid |
Grid | Required. The grid to read. |
container |
Element or string | Required. Where to draw. |
type |
string | 'ridgeline' here. A name the base bundle does not know is looked up among the opt-in chart modules once imported. |
x |
string | The category column. Each distinct value, here the weekday, gets one ridge. |
y |
string | The measure column whose values each ridge is drawn over, here the hour of the order. |
margin |
number or object | Space in pixels around the plot. Widening the left margin leaves room for the weekday names beside the ridges. |
title |
string | Drawn above the plot. |
Reading the ridges
Every ridge is drawn on the same hour axis, so a hump further right means demand later in the day. Tuesday shows two humps, one at lunch and one after work, while Saturday is a single broad swell through the afternoon. That is the difference a rota built from daily totals cannot show. The grid still drives it: filter to the orders from one store, or to one season, and every ridge is drawn again from what is left.
Next
See the ridgeline beside the other distribution charts in the distribution chart demo, read the full list of chart types on the charts page, or follow the how-to for a chart that follows the grid.