Styled Line Plot — MUI X Charts

A line plot using different line styles (solid, dashed, dotted, dash-dot) to distinguish multiple data series. This is especially useful for black-and-white printing or when color distinction is insufficient.

Styled Line Plot rendered with MUI X Charts

Renders

JavaScript source (MUI X Charts)

// anyplot.ai
// line-styled: Styled Line Plot
// Library: muix 7.29.1 | JavaScript 22.23.2
// Quality: 91/100 | Created: 2026-09-05
import {
  LineChart,
  lineElementClasses,
  getLineElementUtilityClass,
} from "@mui/x-charts/LineChart";
import { ChartsReferenceLine } from "@mui/x-charts/ChartsReferenceLine";

const t = window.ANYPLOT_TOKENS;

// --- Data (in-memory, deterministic mulberry32 PRNG) ------------------------
function mulberry32(seed: number) {
  return () => {
    seed |= 0;
    seed = (seed + 0x6d2b79f5) | 0;
    let x = Math.imul(seed ^ (seed >>> 15), 1 | seed);
    x = (x + Math.imul(x ^ (x >>> 7), 61 | x)) ^ x;
    return ((x ^ (x >>> 14)) >>> 0) / 4294967296;
  };
}
const rand = mulberry32(42);

const MINUTES = Array.from({ length: 60 }, (_, i) => i);

const p50: number[] = [];
const p90: number[] = [];
const p99: number[] = [];
const p999: number[] = [];
let baseline = 42;
for (let i = 0; i < MINUTES.length; i += 1) {
  baseline += (rand() - 0.5) * 4;
  baseline = Math.min(58, Math.max(32, baseline));
  const tailGap = 14 + rand() * 8;
  const deepTailGap = 30 + rand() * 14 + Math.sin(i / 6) * 6;
  const spike = i % 17 === 0 ? 55 + rand() * 35 : rand() * 10;
  p50.push(Math.round(baseline * 10) / 10);
  p90.push(Math.round((baseline + tailGap) * 10) / 10);
  p99.push(Math.round((baseline + tailGap + deepTailGap) * 10) / 10);
  p999.push(Math.round((baseline + tailGap + deepTailGap + spike) * 10) / 10);
}

// The single largest tail-latency spike is the focal point of the story
// (called out with a reference line below) — find it once, up front.
let peakIndex = 0;
for (let i = 1; i < p999.length; i += 1) {
  if (p999[i] > p999[peakIndex]) peakIndex = i;
}
const peakMinute = MINUTES[peakIndex];
const peakValue = p999[peakIndex];

// Standard line styles mapped to series, so the chart stays legible when
// printed in monochrome (spec: solid, dashed, dotted, dash-dot). p99's dots
// are a touch denser/thicker than a minimal dotted pattern so they stay
// visible where p99 and p99.9 cross, and at small (mobile) render scale.
const SERIES = [
  { id: "p50", label: "p50 latency", dash: "none" },
  { id: "p90", label: "p90 latency", dash: "11 7" },
  { id: "p99", label: "p99 latency", dash: "3 5" },
  { id: "p999", label: "p99.9 latency", dash: "13 5 2 5" },
];

// Consistent line width across styles; strokeDasharray keyed per series id
// via the utility class MUI X attaches to each line's root element.
const lineSx = {
  [`.${lineElementClasses.root}`]: { strokeWidth: 3 },
  ...Object.fromEntries(
    SERIES.map((s) => [
      `.${getLineElementUtilityClass(`series-${s.id}`)}`,
      { strokeDasharray: s.dash },
    ]),
  ),
};

// Custom legend swatch: a short dashed line sample next to the series name.
// MUI X's built-in legend only draws color squares (no dash preview) and its
// bottom-anchored position ignores the chart's own margin, so a plain HTML
// row below the chart both fixes the layout and shows the actual line style.
function LegendRow({ topGap }: { topGap: number }) {
  return (
    <div
      style={{
        display: "flex",
        justifyContent: "center",
        alignItems: "center",
        gap: 32,
        paddingTop: topGap,
        fontFamily: "system-ui, sans-serif",
      }}
    >
      {SERIES.map((s, i) => (
        <div
          key={s.id}
          style={{ display: "flex", alignItems: "center", gap: 8 }}
        >
          <svg width={40} height={14}>
            <line
              x1={0}
              y1={7}
              x2={40}
              y2={7}
              stroke={t.palette[i]}
              strokeWidth={3}
              strokeDasharray={s.dash}
            />
          </svg>
          <span style={{ fontSize: 14, color: t.inkSoft }}>{s.label}</span>
        </div>
      ))}
    </div>
  );
}

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

  return (
    <div style={{ width, height, display: "flex", flexDirection: "column" }}>
      <div
        style={{
          height: titleHeight,
          display: "flex",
          alignItems: "center",
          paddingLeft: 8,
          fontSize: 22,
          fontWeight: 500,
          color: t.ink,
          fontFamily: "system-ui, sans-serif",
        }}
      >
        line-styled · javascript · muix · anyplot.ai
      </div>
      <LineChart
        width={width}
        height={chartHeight}
        skipAnimation
        dataset={MINUTES.map((minute, i) => ({
          minute,
          p50: p50[i],
          p90: p90[i],
          p99: p99[i],
          p999: p999[i],
        }))}
        xAxis={[
          {
            dataKey: "minute",
            label: "Time (minutes)",
            scaleType: "linear",
            labelStyle: { fontSize: 16, fill: t.ink },
            tickLabelStyle: { fontSize: 14, fill: t.inkSoft },
          },
        ]}
        yAxis={[
          {
            label: "Response Latency (ms)",
            // MUI X positions the axis label at a fixed `tickFontSize + tickSize
            // + 10` offset from the axis line, independent of how wide the tick
            // numbers actually render — with 3-digit ticks (up to "190") the
            // real default collides with the label. `tickFontSize` only feeds
            // that offset math here since `tickLabelStyle.fontSize` below wins
            // for the rendered numbers, so bumping it clears the collision
            // without changing the tick numbers' visual size.
            tickFontSize: 34,
            labelStyle: { fontSize: 16, fill: t.ink },
            tickLabelStyle: { fontSize: 14, fill: t.inkSoft },
          },
        ]}
        series={SERIES.map((s, i) => ({
          id: s.id,
          dataKey: s.id,
          label: s.label,
          color: t.palette[i],
          curve: "monotoneX",
          showMark: false,
        }))}
        grid={{ horizontal: true }}
        margin={{ top: 20, right: 32, bottom: 64, left: 96 }}
        slots={{ legend: () => null }}
        sx={{
          ...lineSx,
          "& .MuiChartsAxisLine": { stroke: t.inkSoft },
          "& .MuiChartsAxisTick": { stroke: t.inkSoft },
        }}
      >
        {/* Focal-point touch: mark the single largest tail-latency spike
            instead of leaving the p99.9 story purely implicit. */}
        <ChartsReferenceLine
          x={peakMinute}
          label={`peak p99.9 · ${peakValue}ms`}
          labelAlign="start"
          spacing={{ x: -150, y: 10 }}
          lineStyle={{ stroke: t.inkSoft, strokeDasharray: "4 4" }}
          labelStyle={{ fontSize: 13, fill: t.inkSoft }}
        />
      </LineChart>
      <LegendRow topGap={legendHeight - 14 - 8} />
    </div>
  );
}

Retrieve this implementation

Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/line-styled/muix/code. Any spec id and library id listed in llms-full.txt fit the same URL shape; every URL below is complete and callable.

{
  "spec_id": "line-styled",
  "language": "javascript",
  "library": "muix",
  "page": "https://anyplot.ai/line-styled/javascript/muix",
  "hub": "https://anyplot.ai/line-styled",
  "code_json": "https://api.anyplot.ai/specs/line-styled/muix/code",
  "spec_json": "https://api.anyplot.ai/specs/line-styled",
  "render_light_png": "https://storage.googleapis.com/anyplot-images/plots/line-styled/javascript/muix/plot-light.png",
  "render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/line-styled/javascript/muix/plot-dark.png",
  "interactive_light_html": "https://storage.googleapis.com/anyplot-images/plots/line-styled/javascript/muix/plot-light.html",
  "interactive_dark_html": "https://storage.googleapis.com/anyplot-images/plots/line-styled/javascript/muix/plot-dark.html",
  "quality_score": 91.0,
  "license": "MIT",
  "guide": "https://anyplot.ai/llms.txt"
}

Part of Styled Line Plot on anyplot.ai.

Other implementations