Cumulative Explained Variance for PCA Component Selection — Apache ECharts

A line plot showing the cumulative proportion of explained variance as a function of the number of Principal Component Analysis (PCA) components. This visualization helps determine the optimal number of components to retain by displaying the trade-off between dimensionality reduction and information preservation. The cumulative curve typically exhibits an elbow pattern where additional components yield diminishing returns, and horizontal threshold lines (e.g., 90%, 95%) guide component selection decisions.

Cumulative Explained Variance for PCA Component Selection rendered with Apache ECharts

Renders

JavaScript source (Apache ECharts)

// anyplot.ai
// line-pca-variance-cumulative: Cumulative Explained Variance for PCA Component Selection
// Library: echarts 6.1.0 | JavaScript 22.23.2
// Quality: 91/100 | Created: 2026-08-26

const t = window.ANYPLOT_TOKENS;

// --- Data (in-memory, deterministic) ----------------------------------------
// Synthetic PCA spectrum for a 15-sensor industrial monitoring array: a
// geometrically decaying eigenvalue sequence, normalized so the individual
// ratios sum to 1 (mirrors sklearn's PCA.explained_variance_ratio_).
const N_COMPONENTS = 15;
const DECAY = 0.78;
const rawEigenvalues = Array.from({ length: N_COMPONENTS }, (_, i) => 45 * Math.pow(DECAY, i));
const eigenSum = rawEigenvalues.reduce((a, b) => a + b, 0);
const individualPct = rawEigenvalues.map((v) => (v / eigenSum) * 100);
const cumulativePct = individualPct.reduce((acc, v, i) => {
  acc.push((i === 0 ? 0 : acc[i - 1]) + v);
  return acc;
}, []);
const components = Array.from({ length: N_COMPONENTS }, (_, i) => String(i + 1));

// Elbow point: index of maximum perpendicular distance from the chord joining
// the first and last cumulative points (kneedle heuristic for a concave curve).
function findElbowIndex(values) {
  const n = values.length;
  const x1 = 1, y1 = values[0];
  const x2 = n, y2 = values[n - 1];
  const denom = Math.sqrt((y2 - y1) ** 2 + (x2 - x1) ** 2);
  let bestIdx = 0, bestDist = -1;
  values.forEach((y0, i) => {
    const x0 = i + 1;
    const dist = Math.abs((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1) / denom;
    if (dist > bestDist) { bestDist = dist; bestIdx = i; }
  });
  return bestIdx;
}
const elbowIdx = findElbowIndex(cumulativePct);

// --- Init --------------------------------------------------------------------
const chart = echarts.init(document.getElementById("container"));

// --- Option -------------------------------------------------------------------
chart.setOption({
  animation: false,
  color: [t.palette[0]],
  backgroundColor: "transparent",
  title: {
    text: "line-pca-variance-cumulative · javascript · echarts · anyplot.ai",
    left: "center",
    top: 24,
    textStyle: { color: t.ink, fontSize: 22, fontWeight: "bold" },
  },
  legend: {
    data: ["Cumulative variance", "Individual variance"],
    top: 74,
    left: "center",
    textStyle: { color: t.inkSoft, fontSize: 15 },
    itemWidth: 22,
    itemHeight: 14,
  },
  grid: { left: 100, right: 70, top: 140, bottom: 90 },
  xAxis: {
    type: "category",
    data: components,
    name: "Number of Components",
    nameLocation: "middle",
    nameGap: 42,
    nameTextStyle: { color: t.ink, fontSize: 16 },
    axisLabel: { color: t.inkSoft, fontSize: 14 },
    axisLine: { lineStyle: { color: t.inkSoft } },
    axisTick: { show: false },
    splitLine: { show: false },
  },
  yAxis: {
    type: "value",
    name: "Explained Variance",
    nameLocation: "middle",
    nameGap: 64,
    nameTextStyle: { color: t.ink, fontSize: 16 },
    min: 0,
    max: 100,
    axisLabel: { color: t.inkSoft, fontSize: 14, formatter: "{value}%" },
    axisLine: { show: false },
    splitLine: { lineStyle: { color: t.grid } },
  },
  series: [
    {
      name: "Cumulative variance",
      type: "line",
      data: cumulativePct,
      symbol: "circle",
      symbolSize: 11,
      lineStyle: { width: 3.5, color: t.palette[0] },
      itemStyle: { color: t.palette[0] },
      areaStyle: { color: t.palette[0], opacity: 0.06 },
      z: 3,
      markLine: {
        symbol: "none",
        silent: true,
        lineStyle: { type: "dashed", color: t.inkSoft, width: 1.5 },
        label: { color: t.inkSoft, fontSize: 15, position: "insideEndTop", formatter: "{b}" },
        data: [
          { yAxis: 90, name: "90% threshold" },
          { yAxis: 95, name: "95% threshold" },
        ],
      },
      markPoint: {
        symbol: "circle",
        symbolSize: 16,
        symbolOffset: [16, -16],
        itemStyle: { color: t.pageBg, borderColor: t.ink, borderWidth: 3 },
        label: {
          show: true,
          position: "top",
          distance: 14,
          color: t.ink,
          fontSize: 15,
          fontWeight: "bold",
          formatter: `Elbow (n=${elbowIdx + 1})`,
        },
        data: [{ coord: [elbowIdx, cumulativePct[elbowIdx]] }],
      },
    },
    {
      name: "Individual variance",
      type: "bar",
      data: individualPct,
      barWidth: "55%",
      itemStyle: { color: t.inkSoft, opacity: 0.35 },
      z: 1,
    },
  ],
});

Part of Cumulative Explained Variance for PCA Component Selection on anyplot.ai.

Other implementations