Cumulative Gains Chart — Highcharts

A cumulative gains chart visualizes the effectiveness of a classification model by showing what percentage of positive cases is captured when targeting increasing percentages of the population, ranked by predicted probability. It answers the question: "If I target the top X% of my predictions, what percentage of all actual positives will I capture?" This plot is essential for evaluating targeting strategies in marketing, risk assessment, and resource allocation scenarios.

Cumulative Gains Chart rendered with Highcharts

Renders

JavaScript source (Highcharts)

// anyplot.ai
// gain-curve: Cumulative Gains Chart
// Library: highcharts 12.6.0 | JavaScript 22.23.2
// Quality: 90/100 | Created: 2026-09-05

const t = window.ANYPLOT_TOKENS;

// --- Data (in-memory, deterministic) ---------------------------------------
const N_TRANSACTIONS = 2000;
const FRAUD_RATE = 0.05;

function mulberry32(seed) {
  return function () {
    seed = (seed + 0x6d2b79f5) | 0;
    let z = Math.imul(seed ^ (seed >>> 15), 1 | seed);
    z = (z + Math.imul(z ^ (z >>> 7), 61 | z)) ^ z;
    return ((z ^ (z >>> 14)) >>> 0) / 4294967296;
  };
}
const rand = mulberry32(42);

function randNormal() {
  let u1 = rand();
  while (u1 === 0) u1 = rand();
  const u2 = rand();
  return Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
}

// A fraud-detection risk score: fraudulent transactions skew higher, but
// overlap with legitimate ones, mimicking a realistic (imperfect) model.
const transactions = [];
for (let i = 0; i < N_TRANSACTIONS; i++) {
  const isFraud = rand() < FRAUD_RATE ? 1 : 0;
  const riskScore = isFraud ? 0.62 + 0.22 * randNormal() : 0.22 + 0.18 * randNormal();
  transactions.push({ isFraud, riskScore });
}
transactions.sort((a, b) => b.riskScore - a.riskScore);

const totalFraud = transactions.reduce((sum, tx) => sum + tx.isFraud, 0);

const modelGains = [[0, 0]];
let capturedFraud = 0;
transactions.forEach((tx, i) => {
  capturedFraud += tx.isFraud;
  const targetedPct = ((i + 1) / N_TRANSACTIONS) * 100;
  const capturedPct = (capturedFraud / totalFraud) * 100;
  modelGains.push([targetedPct, capturedPct]);
});

const baselineGains = [
  [0, 0],
  [100, 100],
];

// Highlight the point where the model first captures 95% of fraud cases —
// the "diminishing returns" transition called out via a plotLine dropline.
const PLATEAU_CAPTURE_PCT = 95;
const [plateauTargetedPct, plateauCapturedPct] =
  modelGains.find(([, capturedPct]) => capturedPct >= PLATEAU_CAPTURE_PCT) ??
  modelGains[modelGains.length - 1];

// --- Chart -------------------------------------------------------------
Highcharts.chart("container", {
  chart: {
    type: "line",
    backgroundColor: "transparent",
    animation: false,
    style: { fontFamily: "inherit" },
  },
  credits: { enabled: false },
  title: {
    text: "gain-curve · javascript · highcharts · anyplot.ai",
    style: { color: t.ink, fontSize: "22px", fontWeight: "600" },
  },
  subtitle: {
    text: "Fraud investigations ranked by model risk score vs. random selection",
    style: { color: t.inkSoft, fontSize: "14px" },
  },
  xAxis: {
    title: {
      text: "Transactions Investigated (%)",
      style: { color: t.inkSoft, fontSize: "16px" },
    },
    min: 0,
    max: 100,
    tickInterval: 20,
    lineColor: t.inkSoft,
    tickColor: t.inkSoft,
    gridLineColor: t.grid,
    labels: { format: "{value}%", style: { color: t.inkSoft, fontSize: "14px" } },
    plotLines: [
      {
        value: plateauTargetedPct,
        color: t.inkSoft,
        width: 1,
        dashStyle: "ShortDot",
        zIndex: 4,
        label: {
          text: `${PLATEAU_CAPTURE_PCT}% captured at ${plateauTargetedPct.toFixed(0)}% targeted`,
          style: { color: t.inkSoft, fontSize: "12px" },
          rotation: 0,
          align: "left",
          x: 8,
          verticalAlign: "bottom",
          y: -10,
        },
      },
    ],
  },
  yAxis: {
    title: {
      text: "Fraud Cases Captured (%)",
      style: { color: t.inkSoft, fontSize: "16px" },
    },
    min: 0,
    max: 100,
    tickInterval: 20,
    gridLineColor: t.grid,
    labels: { format: "{value}%", style: { color: t.inkSoft, fontSize: "14px" } },
    plotLines: [
      { value: plateauCapturedPct, color: t.inkSoft, width: 1, dashStyle: "ShortDot", zIndex: 4 },
    ],
  },
  legend: {
    itemStyle: { color: t.inkSoft, fontSize: "14px" },
    itemHoverStyle: { color: t.ink },
  },
  tooltip: {
    formatter: function () {
      const lift = this.x > 0 ? (this.y / this.x).toFixed(2) : "—";
      return `<b>${this.series.name}</b><br/>Targeted: ${this.x.toFixed(1)}%<br/>Captured: ${this.y.toFixed(1)}%<br/>Lift vs. random: ${lift}×`;
    },
  },
  plotOptions: {
    series: { animation: false, marker: { enabled: false } },
  },
  series: [
    {
      name: "Fraud Risk Model",
      type: "area",
      data: modelGains,
      color: t.palette[0],
      fillOpacity: 0.15,
      threshold: 0,
      lineWidth: 3,
      zIndex: 2,
    },
    {
      name: "Random Selection",
      type: "line",
      data: baselineGains,
      color: t.ink,
      lineWidth: 2,
      dashStyle: "Dash",
      zIndex: 3,
    },
  ],
});

Retrieve this implementation

Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/gain-curve/highcharts/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": "gain-curve",
  "language": "javascript",
  "library": "highcharts",
  "page": "https://anyplot.ai/gain-curve/javascript/highcharts",
  "hub": "https://anyplot.ai/gain-curve",
  "code_json": "https://api.anyplot.ai/specs/gain-curve/highcharts/code",
  "spec_json": "https://api.anyplot.ai/specs/gain-curve",
  "render_light_png": "https://storage.googleapis.com/anyplot-images/plots/gain-curve/javascript/highcharts/plot-light.png",
  "render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/gain-curve/javascript/highcharts/plot-dark.png",
  "interactive_light_html": "https://storage.googleapis.com/anyplot-images/plots/gain-curve/javascript/highcharts/plot-light.html",
  "interactive_dark_html": "https://storage.googleapis.com/anyplot-images/plots/gain-curve/javascript/highcharts/plot-dark.html",
  "quality_score": 90.0,
  "license": "MIT",
  "guide": "https://anyplot.ai/llms.txt"
}

Part of Cumulative Gains Chart on anyplot.ai.

Other implementations