# Line chart
## Microsim
### Live player
<div class="microsim-player">
<iframe src="https://editor.p5js.org/sciencenibber/full/iA8N0UE3t" width="100%" height="620" frameborder="0" sandbox="allow-scripts allow-same-origin"></iframe>
</div>
<div class="microsim-fallback">
<img src="Microsims/thumbs/Line_chart.png" alt="Line_chart microsim poster" style="width:100%;border:1px solid #4445;border-radius:6px;">
<p><em>Live microsim (desktop) · <a href="https://editor.p5js.org/sciencenibber/sketches/iA8N0UE3t">open sketch in the p5.js editor</a></em></p>
</div>
**Editor URL:** https://editor.p5js.org/sciencenibber/sketches/iA8N0UE3t
**Description (100 words):**
This microsim renders a small twelve-point monthly time series as a Pattern A line chart: a zero-baselined frame with gridlines, axis labels, and tick marks, with a single open polyline connecting consecutive points. Press M to toggle marker dots and A to fill the area underneath, watching the same data shift between line, line+markers, and area encodings. Hovering the mouse near any data point surfaces a tooltip with the exact label and value. The HUD shows the article slug, the Wikitube URL, current min/max/mean readouts, and the glyph mapping y_i to (xScale(i), yScale(y_i)).
```js
// =============================================================================
// Line_chart -- Visualization room microsim
// -----------------------------------------------------------------------------
// ARTICLE : Line_chart
// Room : Visualization (the V in GENERATIVE)
// Pattern : Pattern A composition -- Statistical chart types
// Wikitube URL : en.wikitube.io/wiki/Line_chart
//
// What this sketch is
// -------------------
// A small, interactive Pattern-A composition: chart frame + scale closures
// + glyph dictionary entries. The data is a fixed twelve-month synthetic
// series; the rendering is line + (optional) markers + (optional) filled
// area underneath, with a hover tooltip and a chart title that updates to
// reflect the current encoding choice.
//
// Parameter table
// ---------------
// markersOn : boolean -- toggle the dot glyph at each data point
// areaOn : boolean -- toggle the alpha-filled area under the curve
//
// Layout (Betterfire HUD)
// -----------------------
// TL : title (ARTICLE) + Wikitube URL on the row below
// TR : control hints (M markers A area)
// BL : readouts (current min / max / mean of the displayed series)
// BR : equation text (the line glyph mapping y_i -> (xScale(i), yScale(y_i)))
// =============================================================================
const ARTICLE = "Line_chart";
p5.disableFriendlyErrors = true; // FES off -- the Betterfire standard
// ----- canonical Visualization palette (light background, ink-on-paper) -----
const BG = 250;
const FG = 24;
const AXIS = [ 80, 90, 110];
const GRID = [200, 205, 215];
const MUTED = [140, 150, 165];
const INK = [ 40, 48, 60];
const LINE_C = [ 70, 130, 200]; // canonical chart-line blue
const LINE_HI = [220, 110, 60]; // contrast color for the hovered marker
const AREA_A = 36; // alpha for the filled-area pass
const MARGIN = { top: 56, right: 24, bottom: 64, left: 64 };
// ----- the synthetic dataset --------------------------------------------------
// Twelve months of revenue-style numbers. Values were hand-picked so the
// series has a clear seasonal hump in the middle and a small dip in spring,
// which lets the reader see slope, inflection, and a local maximum at once.
const data = [
{ label: "Jan", value: 38 },
{ label: "Feb", value: 41 },
{ label: "Mar", value: 33 },
{ label: "Apr", value: 47 },
{ label: "May", value: 58 },
{ label: "Jun", value: 71 },
{ label: "Jul", value: 79 },
{ label: "Aug", value: 74 },
{ label: "Sep", value: 62 },
{ label: "Oct", value: 53 },
{ label: "Nov", value: 46 },
{ label: "Dec", value: 51 },
];
let markersOn = true; // M toggles the marker dots
let areaOn = false; // A toggles the area fill
// =============================================================================
// p5 lifecycle
// =============================================================================
function setup() {
createCanvas(windowWidth, windowHeight);
textAlign(LEFT, TOP);
textFont("Helvetica");
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
// Keyboard control:
// m / M -> toggle marker dots
// a / A -> toggle area fill
function keyPressed() {
if (key === "m" || key === "M") markersOn = !markersOn;
if (key === "a" || key === "A") areaOn = !areaOn;
}
// =============================================================================
// draw -- deterministic render: read state, lay out, draw frame, draw glyphs
// =============================================================================
function draw() {
background(BG);
// --- chart frame geometry (margins drive the inset) -----------------------
const x0 = MARGIN.left;
const y0 = MARGIN.top;
const w = width - MARGIN.left - MARGIN.right;
const h = height - MARGIN.top - MARGIN.bottom;
// --- y-domain : pad the top so the line never touches the frame ---------
const rawMax = Math.max.apply(null, data.map(function(d){ return d.value; }));
const rawMin = Math.min.apply(null, data.map(function(d){ return d.value; }));
const yMax = Math.ceil((rawMax + 5) / 10) * 10; // round up to nearest 10
const yMin = 0; // honor zero baseline
// --- scale closures (the formal core of Pattern A composition) ----------
// xScale maps category index i -> pixel x; yScale maps value -> pixel y.
const xScale = function (i) { return x0 + (i / (data.length - 1)) * w; };
const yScale = function (v) { return y0 + h - ((v - yMin) / (yMax - yMin)) * h; };
// --- frame underneath the data so gridlines do not paint over the line --
drawFrame(x0, y0, w, h, yMax);
// --- area glyph (optional, drawn first so the line sits on top) ---------
if (areaOn) drawArea(xScale, yScale, y0 + h);
// --- line glyph (the headline mark) -------------------------------------
drawLineGlyph(xScale, yScale);
// --- find the data point closest to the cursor in screen space ----------
let hovered = -1;
let bestDist = 16; // pixel radius for a "hit"
for (let i = 0; i < data.length; i++) {
const dx = mouseX - xScale(i);
const dy = mouseY - yScale(data[i].value);
const d = Math.sqrt(dx * dx + dy * dy);
if (d < bestDist) { bestDist = d; hovered = i; }
}
// --- marker glyph (optional dots, with the hovered one highlighted) -----
if (markersOn) drawMarkers(xScale, yScale, hovered);
// --- tooltip + HUD overlays (always last so they sit on top) ------------
if (hovered >= 0) drawTooltip(mouseX, mouseY, data[hovered]);
drawHud(rawMin, rawMax);
}
// =============================================================================
// Glyphs (the dictionary entries this microsim composes)
// =============================================================================
// drawLineGlyph : connect every data point with a single open polyline.
function drawLineGlyph(xScale, yScale) {
noFill();
stroke(LINE_C[0], LINE_C[1], LINE_C[2]);
strokeWeight(2);
beginShape();
for (let i = 0; i < data.length; i++) {
vertex(xScale(i), yScale(data[i].value));
}
endShape();
}
// drawArea : alpha-filled region between the line and the chart baseline.
function drawArea(xScale, yScale, baselineY) {
noStroke();
fill(LINE_C[0], LINE_C[1], LINE_C[2], AREA_A);
beginShape();
vertex(xScale(0), baselineY); // bottom-left anchor
for (let i = 0; i < data.length; i++) {
vertex(xScale(i), yScale(data[i].value)); // walk the line
}
vertex(xScale(data.length - 1), baselineY); // bottom-right anchor
endShape(CLOSE);
}
// drawMarkers : a dot at every (i, value) ; the hovered one swaps color.
function drawMarkers(xScale, yScale, hovered) {
noStroke();
for (let i = 0; i < data.length; i++) {
const cx = xScale(i);
const cy = yScale(data[i].value);
if (i === hovered) {
fill(LINE_HI[0], LINE_HI[1], LINE_HI[2]);
circle(cx, cy, 10);
} else {
fill(LINE_C[0], LINE_C[1], LINE_C[2]);
circle(cx, cy, 6);
}
}
}
// =============================================================================
// Chart frame -- canonical Visualization frame: axes, gridlines, tick labels,
// axis titles, chart title. Becomes chart_frame.js once extracted.
// =============================================================================
function drawFrame(x, y, w, h, yMax) {
// horizontal gridlines (light, behind everything)
stroke(GRID[0], GRID[1], GRID[2]);
strokeWeight(1);
for (let t = 0; t <= 5; t++) {
const yy = y + h - (t / 5) * h;
line(x, yy, x + w, yy);
}
// axes -- the L-shape that bounds the plot
stroke(AXIS[0], AXIS[1], AXIS[2]);
strokeWeight(1.5);
line(x, y, x, y + h); // left vertical axis
line(x, y + h, x + w, y + h); // bottom horizontal axis
// y tick labels
noStroke();
fill(AXIS[0], AXIS[1], AXIS[2]);
textAlign(RIGHT, CENTER);
textSize(10);
for (let t = 0; t <= 5; t++) {
const yy = y + h - (t / 5) * h;
text(nf((t / 5) * yMax, 1, 0), x - 6, yy);
}
// x tick labels (one per data point)
textAlign(CENTER, TOP);
for (let i = 0; i < data.length; i++) {
const cx = x + (i / (data.length - 1)) * w;
text(data[i].label, cx, y + h + 6);
}
// y-axis title (rotated)
push();
translate(x - 44, y + h / 2);
rotate(-HALF_PI);
fill(AXIS[0], AXIS[1], AXIS[2]);
textAlign(CENTER, CENTER);
textSize(12);
text("value", 0, 0);
pop();
// x-axis title
fill(AXIS[0], AXIS[1], AXIS[2]);
textAlign(CENTER, TOP);
textSize(12);
text("month", x + w / 2, y + h + 28);
// chart title -- changes with encoding choice
let modeLabel = "line";
if (markersOn && areaOn) modeLabel = "line + markers + area";
else if (markersOn) modeLabel = "line + markers";
else if (areaOn) modeLabel = "line + area";
fill(INK[0], INK[1], INK[2]);
textAlign(LEFT, TOP);
textSize(14);
text("Monthly value -- " + modeLabel, x, y - 22);
// restore the global text state -- helpers are not allowed to leak align
textAlign(LEFT, TOP);
}
// =============================================================================
// Tooltip + HUD
// =============================================================================
function drawTooltip(mx, my, d) {
const tip = d.label + " -- " + d.value;
textSize(12);
textAlign(LEFT, TOP);
const tw = textWidth(tip) + 14;
const th = 22;
// clamp so the tooltip never spills past the right edge or bottom
let tx = mx + 12;
let ty = my + 12;
if (tx + tw > width - 4) tx = mx - tw - 12;
if (ty + th > height - 4) ty = my - th - 12;
noStroke();
fill(0, 200);
rect(tx, ty, tw, th, 4);
fill(255);
text(tip, tx + 7, ty + 5);
// restore default
textAlign(LEFT, TOP);
}
function drawHud(rawMin, rawMax) {
// --- top-left : title bar with the article slug + Wikitube URL ----------
noStroke();
fill(0, 180);
rect(8, 8, 360, 44, 4);
fill(255);
textSize(13);
textAlign(LEFT, TOP);
text(ARTICLE, 16, 13);
textSize(11);
text("en.wikitube.io/wiki/" + ARTICLE, 16, 32);
// --- top-right : control hints -----------------------------------------
const hint = "M markers . A area";
textSize(11);
textAlign(RIGHT, TOP);
const hintW = textWidth(hint) + 16;
fill(0, 180);
rect(width - 8 - hintW, 8, hintW, 22, 4);
fill(255);
text(hint, width - 16, 13);
// --- bottom-left : readouts (data summary) ----------------------------
const mean = data.reduce(function (s, d) { return s + d.value; }, 0) / data.length;
const readout =
"min " + nf(rawMin, 1, 0) +
" max " + nf(rawMax, 1, 0) +
" mean " + nf(mean, 1, 1);
textSize(11);
textAlign(LEFT, BOTTOM);
const rw = textWidth(readout) + 16;
fill(0, 180);
rect(8, height - 30, rw, 22, 4);
fill(255);
text(readout, 16, height - 14);
// --- bottom-right : equation / glyph definition -----------------------
const eq = "y_i -> ( xScale(i), yScale(y_i) )";
textSize(11);
textAlign(RIGHT, BOTTOM);
const eqW = textWidth(eq) + 16;
fill(0, 180);
rect(width - 8 - eqW, height - 30, eqW, 22, 4);
fill(255);
text(eq, width - 16, height - 14);
// restore baseline state
textAlign(LEFT, TOP);
}
```
## Links (Wikipedia order)
<!-- injected from _registry/childlinks/Line_chart.json (2026-07-30T02:09:12Z) -->
`Chart` · `Chartjunk` · `Curve_fitting` · `Data_and_information_visualization` · `Gradient` · `Johann_Heinrich_Lambert` · `Line_graph` · `Linear_equation` · `List_of_information_graphics_software` · `Michael_Friendly` · `Run_chart` · [[Scatter_plot]] · `Simple_linear_regression` · `Spreadsheet` · [[Time_series]] · `William_Addison_Dwiggins` · `William_Playfair`
## From the Real GENERATIVE library

*Line chart — placed from the Real G.E.N.E.R.A.T.I.V.E. course library (Visualization room). Source: Wikimedia Commons (via Wikipedia article media). [Details & license](https://commons.wikimedia.org/wiki/File:Pushkin_population_history.svg).*
> A line chart or line graph, also known as curve chart,[1] is a type of chart that displays information as a series of data points called 'markers' connected by straight line segments.[2] It is a basic type of chart common in many fields. It is similar to a scatter plot except that the measurement points are ordered (typically by their x-axis value) and joine ([Wikipedia](https://en.wikipedia.org/wiki/Line_chart))
<!-- REAL-GENERATIVE-MEDIA:END -->
<!-- LOCAL-MEDIA-PASS:START -->
## From the vault media library
!Line chart thumb.png
*Line Chart — from the vault's own media holdings, placed 2026-07-09. MTN / Wikitube.io original · CC BY-SA 4.0.*
<!-- LOCAL-MEDIA-PASS:END -->
> **Room:** Visualization · **Status:** ✅ shipped
## Overview
A line chart is a chart type that displays [[Information|information]] as a series of data points called markers connected by straight line segments. It is one of the most common forms of statistical visualization, especially well suited to displaying a quantitative variable over a continuous independent axis — most often time. The line's slope encodes the rate of change at a glance: rising slopes [[Signal|signal]] growth, falling slopes signal decline, flat segments signal stasis, and inflection points mark moments where the underlying behaviour shifts. Because the human visual [[System|system]] tracks contour very efficiently, a properly constructed line chart lets the reader take in trend, seasonality, outliers, and missing data in a single glance, which is why Edward Tufte's data-ink-ratio analysis treats the line chart as a near-optimal vehicle for time-series prose.
The microsim renders a small synthetic monthly [[Time_series|time series]], draws a complete chart frame with axes, gridlines, tick labels, and chart title, then overlays the line and its markers. A hover detector finds the nearest data point in screen space and surfaces a tooltip with the exact label-and-value pair. Two interactive controls let the reader toggle the marker glyphs and fill the area beneath the line, demonstrating how the same data renders as line, line-with-markers, or area chart depending on encoding choices.
## See also
- Room hub: Visualization
- p5.js Editor conventions: P5 JS EDITOR
- Wiki root: MAIN
---
*Scaffolded by `generative-microsim` from row 0 of the Visualization sheet on 2026-04-30T13:49:58Z.*
Letters: mined_visualization · chart_glyph_dictionary · encoding · gradient · signal · flow · mined_information · logic_notation
<!-- REAL-GENERATIVE-MEDIA:START -->
<!-- CRAFT-LINK:START g12 -->
*Built to the [[WT!P5_js_Microsim_Master_Class|p5.js Master Class]].*
<!-- CRAFT-LINK:END -->
## Wikipedia : Wikitube
**Strict pair:** [Wikipedia](https://en.wikipedia.org/wiki/Line_chart) : [Wikitube](https://en.wikitube.io/wiki/Line_chart)
## Previous hub tags
Tree parents: [[Monte_Carlo_method]] · [[Reliability_engineering]].
Legacy hubs: `GENERATIVE`.
---
*Sources: 1 legacy note. Minted wave 1, 2026-07-30 (v1.6 order).*