Basic Stream Graph — MUI X Charts

A streamgraph (also known as a stacked area chart with a centered baseline) displaying the composition of multiple categories over time with smooth, flowing curves. Unlike traditional stacked area charts, streamgraphs use a symmetric baseline centered around the x-axis, creating an organic, river-like appearance that emphasizes the overall shape and relative proportions of each category while minimizing the visual distortion of individual layers.

Basic Stream Graph rendered with MUI X Charts

Renders

JavaScript source (MUI X Charts)

// anyplot.ai
// streamgraph-basic: Basic Stream Graph
// Library: muix 7.29.1 | JavaScript 22.23.1
// Quality: 88/100 | Created: 2026-08-05

import { LineChart } from "@mui/x-charts/LineChart";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";

const t = window.ANYPLOT_TOKENS;

// --- Data (in-memory, deterministic) ----------------------------------------
// Monthly listening hours (in thousands) by music genre, two years of data.

const MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
const MONTHS_COUNT = 24;
const months = Array.from(
  { length: MONTHS_COUNT },
  (_, i) => `${MONTH_NAMES[i % 12]} ${2024 + Math.floor(i / 12)}`,
);

// Tiny fixed-seed LCG for reproducible micro-variation (no seeded RNG in the browser)
let seed = 42;
function nextRandom() {
  seed = (seed * 1103515245 + 12345) & 0x7fffffff;
  return seed / 0x7fffffff;
}

// Genre trajectories: Electronic and Hip-Hop grow steadily, Rock cools off,
// Jazz and Classical decline slowly, Pop stays roughly flat.
const genres = [
  { name: "Pop", base: 380, amp: 55, freq: 0.55, phase: 0.4, trend: 0.4 },
  { name: "Hip-Hop", base: 300, amp: 70, freq: 0.45, phase: 2.1, trend: 5.5 },
  { name: "Electronic", base: 190, amp: 60, freq: 0.65, phase: 4.0, trend: 8.5 },
  { name: "Rock", base: 260, amp: 45, freq: 0.35, phase: 1.2, trend: -3.5 },
  { name: "Jazz", base: 140, amp: 25, freq: 0.5, phase: 3.3, trend: -2.0 },
  { name: "Classical", base: 100, amp: 18, freq: 0.4, phase: 5.1, trend: -1.2 },
];

const genreValues = genres.map((g) =>
  Array.from({ length: MONTHS_COUNT }, (_, i) => {
    const wave = Math.sin(i * g.freq * 0.5 + g.phase) * g.amp;
    const noise = (nextRandom() - 0.5) * g.amp * 0.3;
    return Math.round(Math.max(30, g.base + g.trend * i + wave + noise));
  }),
);

const series = genres.map((g, idx) => ({
  id: g.name,
  label: g.name,
  data: genreValues[idx],
  area: true,
  stack: "listening",
  stackOrder: "insideOut" as const,
  stackOffset: "wiggle" as const,
  curve: "catmullRom" as const,
  showMark: false,
  color: t.palette[idx],
}));

const TITLE = "Genre Streaming Hours · streamgraph-basic · javascript · muix · anyplot.ai";
const TITLE_FONT_SIZE = Math.max(15, Math.round(22 * Math.min(1, 67 / TITLE.length)));
const TITLE_HEIGHT = 60;

// --- Chart (default-exported component — the harness mounts it) ------------
export default function Chart() {
  const { width, height } = window.ANYPLOT_SIZE;

  return (
    <Box
      sx={{
        width,
        height,
        display: "flex",
        flexDirection: "column",
      }}
    >
      <Typography
        sx={{
          color: t.ink,
          fontSize: TITLE_FONT_SIZE,
          fontWeight: 500,
          textAlign: "center",
          lineHeight: 1.2,
          paddingTop: "16px",
        }}
      >
        {TITLE}
      </Typography>
      <LineChart
        width={width}
        height={height - TITLE_HEIGHT}
        skipAnimation
        series={series}
        xAxis={[
          {
            scaleType: "point",
            data: months,
            tickLabelInterval: (_value: string, index: number) => index % 3 === 0,
            disableTicks: true,
          },
        ]}
        leftAxis={null}
        grid={{ horizontal: false, vertical: false }}
        margin={{ left: 64, right: 24, top: 44, bottom: 56 }}
        slotProps={{
          legend: {
            position: { vertical: "top", horizontal: "middle" },
            direction: "row",
            padding: { top: 0, bottom: 12 },
          },
        }}
        sx={{
          "& .MuiChartsAxis-tickLabel": { fontSize: "14px", fill: t.inkSoft },
          "& .MuiChartsLegend-label": { fontSize: "14px" },
          "& .MuiAreaElement-root": { fillOpacity: 0.92 },
          "& .MuiLineElement-root": { strokeWidth: 1.5 },
        }}
      />
    </Box>
  );
}

Part of Basic Stream Graph on anyplot.ai.

Other implementations