Model Lift Chart — Highcharts

A lift curve visualizes how much better a predictive model performs compared to random selection, showing the cumulative lift ratio as you target increasing percentages of the population. It answers the question: "If I target the top X% of predictions, how many times more responders will I capture than random targeting?" This plot is essential for evaluating and comparing classification models in scenarios where targeting efficiency matters.

Model Lift Chart rendered with Highcharts

Renders

JavaScript source (Highcharts)

// anyplot.ai
// lift-curve: Model Lift Chart
// Library: highcharts 12.6.0 | JavaScript 22.23.2
// Quality: 93/100 | Created: 2026-09-05

//# anyplot-orientation: landscape
const t = window.ANYPLOT_TOKENS;

// --- Data: simulate a retention-campaign response model on 2000 customers --
// Deterministic PRNG (mulberry32) — the browser has no seeded Math.random.
function mulberry32(seed) {
  return function () {
    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 CUSTOMER_COUNT = 2000;
let totalResponders = 0;
const customers = [];
for (let i = 0; i < CUSTOMER_COUNT; i++) {
  // Most customers have low churn-retention-offer propensity; a few are highly likely to respond.
  const propensity = Math.pow(rand(), 4);
  const trueResponseProb = Math.min(0.9, propensity);
  const responded = rand() < trueResponseProb ? 1 : 0;
  totalResponders += responded;
  // The model score correlates with true propensity but is imperfect (added noise).
  const score = propensity + (rand() - 0.5) * 0.3;
  customers.push({ responded, score });
}
customers.sort((a, b) => b.score - a.score);

const baselineRate = totalResponders / CUSTOMER_COUNT;

const liftData = [];
let cumResponders = 0;
let cumCustomers = 0;
for (let pct = 1; pct <= 100; pct++) {
  const cutoff = Math.round((pct / 100) * CUSTOMER_COUNT);
  while (cumCustomers < cutoff) {
    cumResponders += customers[cumCustomers].responded;
    cumCustomers++;
  }
  const lift = cumResponders / cumCustomers / baselineRate;
  const isDecile = pct % 10 === 0;
  liftData.push({
    x: pct,
    y: Number(lift.toFixed(3)),
    marker: { enabled: isDecile, radius: isDecile ? 6 : 0 },
    dataLabels: { enabled: isDecile },
    custom: { responders: cumResponders, customers: cumCustomers },
  });
}

const randomSelectionData = [
  { x: 0, y: 1 },
  { x: 100, y: 1 },
];

// --- Chart -------------------------------------------------------------------
Highcharts.chart("container", {
  chart: {
    type: "line",
    backgroundColor: "transparent",
    animation: false,
    style: { fontFamily: "inherit" },
  },
  credits: { enabled: false },
  colors: t.palette,
  title: {
    text: "lift-curve · javascript · highcharts · anyplot.ai",
    style: { color: t.ink, fontSize: "24px", fontWeight: "700" },
  },
  subtitle: {
    text: `Retention offer targeting · baseline response rate ${(baselineRate * 100).toFixed(1)}%`,
    style: { color: t.inkSoft, fontSize: "14px" },
  },
  xAxis: {
    title: { text: "Population Targeted (%)", style: { color: t.inkSoft, fontSize: "16px" } },
    min: 0,
    max: 100,
    tickInterval: 10,
    lineColor: t.inkSoft,
    tickColor: t.inkSoft,
    gridLineColor: t.grid,
    labels: { style: { color: t.inkSoft, fontSize: "14px" }, format: "{value}%" },
  },
  yAxis: {
    title: { text: "Cumulative Lift", style: { color: t.inkSoft, fontSize: "16px" } },
    min: 0,
    gridLineColor: t.grid,
    labels: { style: { color: t.inkSoft, fontSize: "14px" }, format: "{value}x" },
  },
  legend: {
    itemStyle: { color: t.inkSoft, fontSize: "14px" },
    itemHoverStyle: { color: t.ink },
  },
  plotOptions: {
    series: { animation: false },
    line: { lineWidth: 3, marker: { enabled: false } },
    area: { lineWidth: 3, marker: { enabled: false } },
  },
  series: [
    {
      name: "Model",
      type: "area",
      data: liftData,
      color: t.palette[0],
      // Fill only the wedge between the curve and the y=1 baseline, not down to 0,
      // to visually emphasize the lift magnitude being captured.
      threshold: 1,
      fillOpacity: 0.18,
      fillColor: Highcharts.color(t.palette[0]).setOpacity(0.18).get("rgba"),
      zIndex: 2,
      dataLabels: {
        enabled: false,
        format: "{y:.1f}x",
        style: { color: t.ink, fontSize: "14px", fontWeight: "600", textOutline: "none" },
        y: -14,
      },
      tooltip: {
        pointFormatter: function () {
          const c = this.custom || {};
          return (
            `<span style="color:${this.color}">●</span> ${this.series.name}: <b>${this.y}x</b> lift<br/>` +
            `Captured ${c.responders} of ${totalResponders} responders (${c.customers} customers targeted)<br/>`
          );
        },
      },
    },
    {
      name: "Random selection (no lift)",
      data: randomSelectionData,
      color: t.ink,
      dashStyle: "Dash",
      lineWidth: 2,
      marker: { enabled: false },
      enableMouseTracking: false,
      zIndex: 1,
    },
  ],
});

Retrieve this implementation

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

Part of Model Lift Chart on anyplot.ai.

Other implementations