{"spec_id":"histogram-kde","library":"muix","language":"javascript","code":"// anyplot.ai\n// histogram-kde: Histogram with KDE Overlay\n// Library: muix 9.16.0 | JavaScript 22.23.3\n// Quality: 87/100 | Updated: 2026-10-24\nimport { ChartsContainer } from \"@mui/x-charts/ChartsContainer\";\nimport { LinePlot } from \"@mui/x-charts/LineChart\";\nimport { ChartsXAxis } from \"@mui/x-charts/ChartsXAxis\";\nimport { ChartsYAxis } from \"@mui/x-charts/ChartsYAxis\";\nimport { ChartsGrid } from \"@mui/x-charts/ChartsGrid\";\nimport { ChartsReferenceLine } from \"@mui/x-charts/ChartsReferenceLine\";\nimport { useDrawingArea } from \"@mui/x-charts/hooks\";\nimport Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\n\nconst t = window.ANYPLOT_TOKENS;\n\n// Constants\nconst FONT = \"system-ui, -apple-system, sans-serif\";\nconst TITLE = \"histogram-kde · javascript · muix · anyplot.ai\";\nconst BIN_COUNT = 30;\nconst KDE_POINTS = 240;\nconst X_PAD_RATIO = 0.04;\nconst Y_HEADROOM_RATIO = 0.15;\nconst SILVERMAN_FACTOR = 1.06;\n\nconst BRAND = t.palette[0];\nconst BLUE = t.palette[2];\n\n// Columns: set these to your data's column names\nconst DAILY_RETURN = \"Daily return (%)\"; // role: values\n\n// Data: replace this block with your own records\ntype KdeRow = {\n  [DAILY_RETURN]: number;\n};\n\nconst data: KdeRow[] = [];\nlet seed = 42 >>> 0;\nconst sampleSize = 500;\n\nfor (let i = 0; i < sampleSize; i++) {\n  seed = (Math.imul(1664525, seed) + 1013904223) >>> 0;\n  const isShockDay = seed / 0x100000000 < 0.09;\n  seed = (Math.imul(1664525, seed) + 1013904223) >>> 0;\n  const u1 = Math.max(seed / 0x100000000, 1e-10);\n  seed = (Math.imul(1664525, seed) + 1013904223) >>> 0;\n  const u2 = seed / 0x100000000;\n  const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);\n  const mean = isShockDay ? -2.6 : 0.12;\n  const sd = isShockDay ? 2.4 : 0.85;\n  data.push({\n    [DAILY_RETURN]: Number((mean + z * sd).toFixed(4)),\n  });\n}\n\n// Plot: reads only data and the constants above\nconst returns = data.map((r) => r[DAILY_RETURN]);\nconst n = returns.length;\nconst dataMin = Math.min(...returns);\nconst dataMax = Math.max(...returns);\nconst pad = (dataMax - dataMin) * X_PAD_RATIO;\nconst xMin = dataMin - pad;\nconst xMax = dataMax + pad;\n\nconst binWidth = (dataMax - dataMin) / BIN_COUNT;\nconst binCounts = new Array(BIN_COUNT).fill(0);\nfor (const v of returns) {\n  const idx = Math.min(BIN_COUNT - 1, Math.floor((v - dataMin) / binWidth));\n  binCounts[idx] += 1;\n}\nconst histogramDensity = binCounts.map((c) => c / (n * binWidth));\n\nconst sampleMean = returns.reduce((s, v) => s + v, 0) / n;\nconst sampleStd = Math.sqrt(\n  returns.reduce((s, v) => s + (v - sampleMean) ** 2, 0) / (n - 1),\n);\nconst bandwidth = SILVERMAN_FACTOR * sampleStd * Math.pow(n, -0.2);\n\nconst kdeX = Array.from(\n  { length: KDE_POINTS },\n  (_, i) => xMin + (i / (KDE_POINTS - 1)) * (xMax - xMin),\n);\nconst kdeDensity = kdeX.map((x) => {\n  let sum = 0;\n  for (const v of returns) {\n    const u = (x - v) / bandwidth;\n    sum += Math.exp(-0.5 * u * u);\n  }\n  return sum / (n * bandwidth * Math.sqrt(2 * Math.PI));\n});\n\nconst yMax = Math.max(...histogramDensity, ...kdeDensity) * (1 + Y_HEADROOM_RATIO);\n\nconst unitMatch = DAILY_RETURN.match(/\\(([^)]+)\\)/);\nconst unitSuffix = unitMatch ? unitMatch[1] : \"\";\nconst SUBTITLE = `${DAILY_RETURN} (n = ${n}) · Mean ${sampleMean.toFixed(2)}${unitSuffix}, SD ${sampleStd.toFixed(2)}${unitSuffix}, Silverman KDE bandwidth h = ${bandwidth.toFixed(2)}${unitSuffix}`;\n\nfunction HistogramBarsLayer() {\n  const { left, top, width, height } = useDrawingArea();\n  const binPx = (binWidth / (xMax - xMin)) * width;\n  return (\n    <g>\n      {histogramDensity.map((d, i) => {\n        const bx =\n          left + ((dataMin + i * binWidth - xMin) / (xMax - xMin)) * width;\n        const by = top + (1 - d / yMax) * height;\n        return (\n          <rect\n            key={i}\n            x={bx + 0.5}\n            y={by}\n            width={binPx - 1}\n            height={top + height - by}\n            fill={BRAND}\n            fillOpacity={0.5}\n          />\n        );\n      })}\n    </g>\n  );\n}\n\nexport default function Chart() {\n  const { width, height } = window.ANYPLOT_SIZE;\n  const HEADER_H = 108;\n\n  return (\n    <Box\n      sx={{\n        width,\n        height,\n        bgcolor: t.pageBg,\n        display: \"flex\",\n        flexDirection: \"column\",\n        overflow: \"hidden\",\n      }}\n    >\n      <Typography\n        sx={{\n          fontSize: 22,\n          fontWeight: 600,\n          color: t.ink,\n          pt: \"14px\",\n          px: \"40px\",\n          pb: 0,\n          lineHeight: 1.2,\n          fontFamily: FONT,\n        }}\n      >\n        {TITLE}\n      </Typography>\n      <Typography\n        sx={{\n          fontSize: 15,\n          fontWeight: 400,\n          color: t.inkSoft,\n          px: \"40px\",\n          pt: \"4px\",\n          pb: 0,\n          lineHeight: 1.2,\n          fontFamily: FONT,\n        }}\n      >\n        {SUBTITLE}\n      </Typography>\n\n      <Box\n        sx={{\n          display: \"flex\",\n          alignItems: \"center\",\n          gap: \"24px\",\n          px: \"40px\",\n          pt: \"8px\",\n        }}\n      >\n        <Box sx={{ display: \"flex\", alignItems: \"center\", gap: \"8px\" }}>\n          <Box\n            sx={{\n              width: 16,\n              height: 12,\n              bgcolor: BRAND,\n              opacity: 0.5,\n              borderRadius: \"2px\",\n            }}\n          />\n          <Typography\n            sx={{ fontSize: 14, fontWeight: 600, color: t.ink, fontFamily: FONT }}\n          >\n            Observed density ({BIN_COUNT} bins)\n          </Typography>\n        </Box>\n        <Box sx={{ display: \"flex\", alignItems: \"center\", gap: \"8px\" }}>\n          <Box\n            sx={{ width: 18, height: 3.5, bgcolor: BLUE, borderRadius: \"2px\" }}\n          />\n          <Typography\n            sx={{ fontSize: 14, fontWeight: 600, color: t.ink, fontFamily: FONT }}\n          >\n            Gaussian KDE estimate\n          </Typography>\n        </Box>\n      </Box>\n\n      <ChartsContainer\n        width={width}\n        height={height - HEADER_H}\n        series={[\n          {\n            type: \"line\",\n            id: \"kde\",\n            data: kdeDensity,\n            label: \"KDE estimate\",\n            color: BLUE,\n            showMark: false,\n          },\n        ]}\n        xAxis={[\n          {\n            id: \"return-axis\",\n            data: kdeX,\n            scaleType: \"linear\",\n            min: xMin,\n            max: xMax,\n            height: 60,\n            label: DAILY_RETURN,\n            valueFormatter: (v: number) => `${v.toFixed(1)}${unitSuffix}`,\n            labelStyle: { fontSize: 15, fill: t.ink, fontFamily: FONT },\n            tickLabelStyle: { fontSize: 14, fill: t.inkSoft, fontFamily: FONT },\n          },\n        ]}\n        yAxis={[\n          {\n            id: \"density-axis\",\n            min: 0,\n            max: yMax,\n            width: 96,\n            label: \"Probability Density\",\n            valueFormatter: (v: number) => v.toFixed(2),\n            labelStyle: { fontSize: 15, fill: t.ink, fontFamily: FONT },\n            tickLabelStyle: { fontSize: 14, fill: t.inkSoft, fontFamily: FONT },\n          },\n        ]}\n        margin={{ top: 24, right: 40, bottom: 20, left: 20 }}\n        skipAnimation\n      >\n        <ChartsGrid\n          horizontal\n          sx={{ \"& line\": { stroke: t.grid, strokeWidth: 0.8 } }}\n        />\n        <HistogramBarsLayer />\n        <LinePlot\n          skipAnimation\n          slotProps={{ line: { sx: { strokeWidth: 3.5 } } }}\n        />\n        <ChartsReferenceLine\n          x={sampleMean}\n          label={`Mean ${sampleMean.toFixed(2)}${unitSuffix}`}\n          labelAlign=\"start\"\n          lineStyle={{\n            stroke: t.inkSoft,\n            strokeDasharray: \"6 4\",\n            strokeWidth: 1.5,\n          }}\n          labelStyle={{\n            fontSize: 14,\n            fontWeight: 600,\n            fill: t.inkSoft,\n            fontFamily: FONT,\n          }}\n        />\n        <ChartsXAxis axisId=\"return-axis\" />\n        <ChartsYAxis axisId=\"density-axis\" />\n      </ChartsContainer>\n    </Box>\n  );\n}\n"}