{"spec_id":"band-basic","library":"echarts","language":"javascript","code":"// anyplot.ai\n// band-basic: Basic Band Plot\n// Library: echarts 6.1.0 | JavaScript 22.23.2\n// Quality: 90/100 | Created: 2026-08-24\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// Simple LCG so the sample data is reproducible without Math.random().\nlet seed = 42;\nfunction rand() {\n  seed = (seed * 1103515245 + 12345) & 0x7fffffff;\n  return seed / 0x7fffffff;\n}\n\n// A 48-hour temperature forecast issued at hour 0. Uncertainty (the 90%\n// confidence band) widens with lead time, the classic forecast-skill decay\n// pattern, while the central estimate follows a diurnal cycle plus mild\n// warming drift.\nconst HOURS = 48;\nconst hoursAhead = Array.from({ length: HOURS }, (_, i) => i);\n\nconst centerTemp = hoursAhead.map((h) => {\n  const diurnal = 18 + 6 * Math.sin(((h - 6) / 24) * 2 * Math.PI);\n  const drift = h * 0.03;\n  const noise = (rand() - 0.5) * 0.6;\n  return diurnal + drift + noise;\n});\nconst halfWidth = hoursAhead.map((h) => 0.4 + h * 0.09);\nconst lowerBound = centerTemp.map((v, i) => v - halfWidth[i]);\nconst bandSpan = halfWidth.map((h) => h * 2);\n\n// --- Init ---------------------------------------------------------------------\nconst chart = echarts.init(document.getElementById(\"container\"));\n\n// --- Option ---------------------------------------------------------------------\nchart.setOption({\n  animation: false,\n  backgroundColor: \"transparent\",\n  title: {\n    text: \"band-basic · javascript · echarts · anyplot.ai\",\n    left: \"center\",\n    top: 20,\n    textStyle: { color: t.ink, fontSize: 22, fontWeight: 500 },\n  },\n  tooltip: {\n    trigger: \"axis\",\n    formatter: (params) => {\n      const i = params[0].dataIndex;\n      return [\n        `Hour +${hoursAhead[i]}`,\n        `Forecast: ${centerTemp[i].toFixed(1)}°C`,\n        `90% range: ${lowerBound[i].toFixed(1)}–${(lowerBound[i] + bandSpan[i]).toFixed(1)}°C`,\n      ].join(\"<br/>\");\n    },\n  },\n  legend: {\n    data: [\"90% confidence band\", \"Forecast temperature\"],\n    top: 66,\n    left: \"center\",\n    textStyle: { color: t.ink, fontSize: 16 },\n    itemWidth: 18,\n    itemHeight: 12,\n  },\n  grid: {\n    left: 90,\n    right: 60,\n    top: 130,\n    bottom: 70,\n    containLabel: true,\n  },\n  xAxis: {\n    type: \"value\",\n    name: \"Hours Since Forecast Issued\",\n    nameLocation: \"middle\",\n    nameGap: 40,\n    nameTextStyle: { color: t.inkSoft, fontSize: 14 },\n    min: 0,\n    max: HOURS - 1,\n    axisLabel: { color: t.inkSoft, fontSize: 13 },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    axisTick: { show: false },\n    splitLine: { show: false },\n  },\n  yAxis: {\n    type: \"value\",\n    name: \"Temperature (°C)\",\n    nameLocation: \"middle\",\n    nameGap: 60,\n    nameTextStyle: { color: t.inkSoft, fontSize: 14 },\n    scale: true,\n    axisLabel: { color: t.inkSoft, fontSize: 13 },\n    axisLine: { show: false },\n    axisTick: { show: false },\n    splitLine: { lineStyle: { color: t.grid } },\n  },\n  series: [\n    {\n      name: \"Lower bound\",\n      type: \"line\",\n      // A value-type x-axis needs explicit [x, y] pairs — plain y-arrays\n      // desync the two axes since echarts no longer indexes by category.\n      data: hoursAhead.map((h, i) => [h, lowerBound[i]]),\n      stack: \"confidence-band\",\n      symbol: \"none\",\n      lineStyle: { opacity: 0 },\n      areaStyle: { opacity: 0 },\n      silent: true,\n      z: 1,\n    },\n    {\n      name: \"90% confidence band\",\n      type: \"line\",\n      data: hoursAhead.map((h, i) => [h, bandSpan[i]]),\n      stack: \"confidence-band\",\n      symbol: \"none\",\n      lineStyle: { opacity: 0 },\n      areaStyle: { color: t.palette[0], opacity: 0.22 },\n      itemStyle: { color: t.palette[0] },\n      z: 1,\n    },\n    {\n      name: \"Forecast temperature\",\n      type: \"line\",\n      data: hoursAhead.map((h, i) => [h, centerTemp[i]]),\n      symbol: \"circle\",\n      symbolSize: 6,\n      smooth: 0.3,\n      lineStyle: { width: 3, color: t.palette[0] },\n      itemStyle: { color: t.palette[0] },\n      z: 10,\n    },\n  ],\n});\n"}