{"spec_id":"line-growth-percentile","library":"highcharts","language":"javascript","code":"// anyplot.ai\n// line-growth-percentile: Pediatric Growth Chart with Percentile Curves\n// Library: highcharts 12.6.0 | JavaScript 22.22.3\n// Quality: 86/100 | Created: 2026-06-20\n//# anyplot-orientation: landscape\n\n// anyplot.ai\n// line-growth-percentile: Pediatric Growth Chart with Percentile Curves\n// Library: Highcharts 12.6.0 | Node 22\n// License: Highcharts — commercial license, free for non-commercial use (highcharts.com/license)\n// Quality: pending | Created: 2026-06-20\n\nconst t = window.ANYPLOT_TOKENS;\nconst PAGE_BG = window.ANYPLOT_THEME === 'light' ? '#FAF8F1' : '#1A1A17';\n\n// Age reference points (months)\nconst ages = [0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36];\n\n// WHO boys weight-for-age reference percentiles (kg, approximate)\nconst p3  = [2.5, 5.0, 6.4, 7.2, 7.7, 8.2, 8.7, 9.1,  9.5,  9.8, 10.1, 10.4, 10.7];\nconst p10 = [2.8, 5.4, 6.9, 7.8, 8.3, 8.9, 9.4, 9.9, 10.3, 10.6, 11.0, 11.3, 11.6];\nconst p25 = [3.1, 5.8, 7.4, 8.4, 9.0, 9.6, 10.1, 10.6, 11.1, 11.5, 11.9, 12.3, 12.7];\nconst p50 = [3.4, 6.4, 7.9, 9.0, 9.7, 10.3, 10.9, 11.5, 12.0, 12.5, 12.9, 13.4, 13.9];\nconst p75 = [3.7, 6.9, 8.6, 9.7, 10.5, 11.1, 11.8, 12.4, 13.0, 13.5, 14.0, 14.5, 15.1];\nconst p90 = [4.1, 7.5, 9.2, 10.5, 11.2, 12.0, 12.7, 13.4, 14.0, 14.7, 15.2, 15.8, 16.4];\nconst p97 = [4.5, 8.0, 9.8, 11.1, 12.0, 12.8, 13.7, 14.4, 15.0, 15.8, 16.4, 17.0, 17.7];\n\n// Stacked deltas: each band fills between adjacent percentile curves\nconst delta = (hi, lo) => hi.map((v, i) => +(v - lo[i]).toFixed(2));\nconst dBase  = p3;\nconst d3_10  = delta(p10, p3);\nconst d10_25 = delta(p25, p10);\nconst d25_50 = delta(p50, p25);\nconst d50_75 = delta(p75, p50);\nconst d75_90 = delta(p90, p75);\nconst d90_97 = delta(p97, p90);\n\n// Individual patient trajectory — well-child visit weights (boy, between P75 and P90)\nconst patientVisits = [[0, 3.6], [3, 6.8], [6, 8.3], [9, 9.5], [12, 10.7], [18, 11.8], [24, 13.1], [36, 15.4]];\nconst patientData = patientVisits.map(([a, w]) => [ages.indexOf(a), w]);\n\n// Title with font scaling: 83 chars → 22 × 67/83 ≈ 18px\nconst title = 'Boys Weight 0–36 mo · line-growth-percentile · javascript · highcharts · anyplot.ai';\nconst titleFontSize = Math.max(16, Math.round(22 * 67 / title.length)) + 'px';\n\n// Imprint blue (#4467A3) at varying alpha for graduated band fills\nconst bandFill = (alpha) => `rgba(68,103,163,${alpha})`;\nconst BLUE = '#4467A3';\n\n// Right-margin data label for the last age tick only (for curve series)\nconst rightLabel = (lbl, bold) => ({\n  enabled: true,\n  formatter: function () { return this.point.index === ages.length - 1 ? lbl : null; },\n  align: 'left',\n  x: 8,\n  y: 4,\n  allowOverlap: true,\n  crop: false,\n  overflow: 'allow',\n  style: {\n    color: bold ? t.ink : t.inkSoft,\n    fontSize: bold ? '13px' : '12px',\n    fontWeight: bold ? '700' : 'normal',\n    textOutline: 'none',\n  },\n});\n\n// Stacked area bands (fills only — no lines, no labels)\nconst bandSeries = [\n  { name: 'base',    data: dBase,  fill: PAGE_BG        },\n  { name: 'P3-P10',  data: d3_10,  fill: bandFill(0.38) },\n  { name: 'P10-P25', data: d10_25, fill: bandFill(0.25) },\n  { name: 'P25-P50', data: d25_50, fill: bandFill(0.13) },\n  { name: 'P50-P75', data: d50_75, fill: bandFill(0.13) },\n  { name: 'P75-P90', data: d75_90, fill: bandFill(0.25) },\n  { name: 'P90-P97', data: d90_97, fill: bandFill(0.38) },\n].map(s => ({\n  type: 'areaspline',\n  name: s.name,\n  data: s.data,\n  fillColor: s.fill,\n  lineWidth: 0,\n  marker: { enabled: false },\n  animation: false,\n  enableMouseTracking: false,\n  showInLegend: false,\n  dataLabels: { enabled: false },\n}));\n\n// Non-stacked percentile curves — provide actual y-positions for the reference lines and labels\nconst curves = [\n  { key: 'P3',  vals: p3,  lbl: 'P3',  lw: 1,   color: bandFill(0.45), bold: false },\n  { key: 'P10', vals: p10, lbl: 'P10', lw: 1,   color: bandFill(0.50), bold: false },\n  { key: 'P25', vals: p25, lbl: 'P25', lw: 1,   color: bandFill(0.55), bold: false },\n  { key: 'P50', vals: p50, lbl: 'P50', lw: 2.5, color: BLUE,           bold: true  },\n  { key: 'P75', vals: p75, lbl: 'P75', lw: 1,   color: bandFill(0.55), bold: false },\n  { key: 'P90', vals: p90, lbl: 'P90', lw: 1,   color: bandFill(0.50), bold: false },\n  { key: 'P97', vals: p97, lbl: 'P97', lw: 1,   color: bandFill(0.45), bold: false },\n];\n\nconst curveSeries = curves.map(c => ({\n  type: 'spline',\n  name: c.key,\n  data: c.vals,   // raw values on the y-axis — not stacked\n  color: c.color,\n  lineWidth: c.lw,\n  marker: { enabled: false },\n  animation: false,\n  enableMouseTracking: false,\n  showInLegend: false,\n  dataLabels: rightLabel(c.lbl, c.bold),\n}));\n\nHighcharts.chart('container', {\n  chart: {\n    backgroundColor: 'transparent',\n    animation: false,\n    marginRight: 58,\n    style: { fontFamily: 'inherit' },\n  },\n  credits: { enabled: false },\n  title: {\n    text: title,\n    style: { color: t.ink, fontSize: titleFontSize, fontWeight: '600' },\n  },\n  xAxis: {\n    categories: ages.map(String),\n    title: { text: 'Age (months)', style: { color: t.inkSoft, fontSize: '16px' } },\n    lineColor: t.inkSoft,\n    tickColor: t.inkSoft,\n    gridLineWidth: 0,\n    labels: { style: { color: t.inkSoft, fontSize: '14px' } },\n  },\n  yAxis: {\n    min: 2,\n    title: { text: 'Weight (kg)', style: { color: t.inkSoft, fontSize: '16px' } },\n    gridLineColor: t.grid,\n    labels: { style: { color: t.inkSoft, fontSize: '14px' } },\n  },\n  plotOptions: {\n    areaspline: {\n      stacking: 'normal',\n      animation: false,\n    },\n    spline: {\n      animation: false,\n    },\n    series: { animation: false },\n  },\n  legend: { enabled: false },\n  tooltip: { enabled: false },\n  series: [\n    // Band fills (stacked areaspline) — drawn first so curves overlay on top\n    ...bandSeries,\n    // Reference curves (non-stacked spline) — drawn at actual percentile y-values\n    ...curveSeries,\n    // Individual patient trajectory — Imprint brand green (#009E73) as contrasting series\n    {\n      type: 'spline',\n      name: 'Patient',\n      data: patientData,\n      color: '#009E73',\n      lineWidth: 2.5,\n      zIndex: 10,\n      animation: false,\n      enableMouseTracking: false,\n      showInLegend: false,\n      marker: {\n        enabled: true,\n        radius: 6,\n        fillColor: '#009E73',\n        lineWidth: 2,\n        lineColor: PAGE_BG,\n      },\n    },\n  ],\n});\n"}