# 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](https://upload.wikimedia.org/wikipedia/commons/thumb/b/bd/Pushkin_population_history.svg/220px-Pushkin_population_history.svg.png) *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).*