A histogram displayed as step lines (outline only) without filled bars. The distribution is shown as connected horizontal and vertical line segments, creating a step function appearance.

// anyplot.ai
// histogram-stepwise: Step Histogram
// Library: chartjs 4.4.7 | JavaScript 22.23.2
// Quality: 91/100 | Created: 2026-09-05
const t = window.ANYPLOT_TOKENS;
// --- Data (in-memory, deterministic) ----------------------------------------
// Small LCG PRNG + Box-Muller transform — the browser has no seeded RNG.
let seed = 42;
function lcgRandom() {
seed = (seed * 1664525 + 1013904223) % 4294967296;
return seed / 4294967296;
}
function randomNormal(mean, stdDev) {
const u1 = 1 - lcgRandom();
const u2 = lcgRandom();
const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
return mean + z * stdDev;
}
const endpoints = [
{ name: "API v1 (legacy)", mean: 220, stdDev: 55, n: 700 },
{ name: "API v2 (rewrite)", mean: 140, stdDev: 30, n: 700 },
];
endpoints.forEach((endpoint) => {
endpoint.latencies = Array.from({ length: endpoint.n }, () =>
Math.max(5, randomNormal(endpoint.mean, endpoint.stdDev)),
);
});
// --- Shared bins across both endpoints (aligned edges for direct overlay) ---
const allLatencies = endpoints.flatMap((endpoint) => endpoint.latencies);
const binWidth = 12;
const minEdge = Math.floor(Math.min(...allLatencies) / binWidth) * binWidth;
const maxEdge = Math.ceil(Math.max(...allLatencies) / binWidth) * binWidth;
const binCount = (maxEdge - minEdge) / binWidth;
const edges = Array.from({ length: binCount + 1 }, (_, i) => minEdge + i * binWidth);
// One point per bin's left edge (plus a trailing point at the final right
// edge, zero-padded at both ends) — Chart.js's native `stepped: "after"` line
// option draws the horizontal-then-vertical step outline between them, so no
// point-doubling is needed to fake the shape.
function stepOutline(latencies) {
const counts = new Array(binCount).fill(0);
latencies.forEach((value) => {
const idx = Math.min(binCount - 1, Math.max(0, Math.floor((value - minEdge) / binWidth)));
counts[idx] += 1;
});
const points = [{ x: edges[0], y: 0 }];
for (let i = 0; i < binCount; i++) {
points.push({ x: edges[i], y: counts[i] });
}
points.push({ x: edges[binCount], y: counts[binCount - 1] });
points.push({ x: edges[binCount], y: 0 });
return points;
}
// --- Mount -------------------------------------------------------------------
const canvas = document.createElement("canvas");
document.getElementById("container").appendChild(canvas);
// --- Chart -----------------------------------------------------------------
new Chart(canvas, {
type: "line",
data: {
datasets: endpoints.map((endpoint, i) => ({
label: endpoint.name,
data: stepOutline(endpoint.latencies),
stepped: "after",
borderColor: t.palette[i],
backgroundColor: "transparent",
// Rewrite's tighter, faster distribution is the story — give it the
// heavier line weight so it reads as the visual focal point.
borderWidth: i === 1 ? 4.5 : 2.75,
pointRadius: 0,
fill: false,
})),
},
options: {
responsive: true,
maintainAspectRatio: false,
animation: false,
layout: {
padding: { right: 24, top: 8 },
},
plugins: {
title: {
display: true,
text: "API Latency · histogram-stepwise · javascript · chartjs · anyplot.ai",
color: t.ink,
font: { size: 20, weight: "600" },
padding: { bottom: 20 },
},
legend: {
labels: {
color: t.inkSoft,
font: { size: 14 },
boxWidth: 14,
usePointStyle: true,
pointStyle: "line",
},
},
},
scales: {
x: {
type: "linear",
ticks: { color: t.inkSoft, font: { size: 13 } },
grid: { display: false },
title: {
display: true,
text: "Response Time (ms)",
color: t.ink,
font: { size: 16 },
},
},
y: {
beginAtZero: true,
ticks: { color: t.inkSoft, font: { size: 13 } },
grid: { color: t.grid },
title: {
display: true,
text: "Number of Requests",
color: t.ink,
font: { size: 16 },
},
},
},
},
});
Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/histogram-stepwise/chartjs/code. Any spec id and library id listed in llms-full.txt fit the same URL shape; every URL below is complete and callable.
{
"spec_id": "histogram-stepwise",
"language": "javascript",
"library": "chartjs",
"page": "https://anyplot.ai/histogram-stepwise/javascript/chartjs",
"hub": "https://anyplot.ai/histogram-stepwise",
"code_json": "https://api.anyplot.ai/specs/histogram-stepwise/chartjs/code",
"spec_json": "https://api.anyplot.ai/specs/histogram-stepwise",
"render_light_png": "https://storage.googleapis.com/anyplot-images/plots/histogram-stepwise/javascript/chartjs/plot-light.png",
"render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/histogram-stepwise/javascript/chartjs/plot-dark.png",
"interactive_light_html": "https://storage.googleapis.com/anyplot-images/plots/histogram-stepwise/javascript/chartjs/plot-light.html",
"interactive_dark_html": "https://storage.googleapis.com/anyplot-images/plots/histogram-stepwise/javascript/chartjs/plot-dark.html",
"quality_score": 91.0,
"license": "MIT",
"guide": "https://anyplot.ai/llms.txt"
}Part of Step Histogram on anyplot.ai.