Win Probability Chart — Apache ECharts

A win probability chart shows how each team's likelihood of winning evolves over the course of a game. The line starts near 50% and fluctuates based on scoring events, ultimately reaching 100% or 0% at game end. The area above and below the 50% baseline is filled with team colors to convey momentum at a glance. This visualization is widely used across major sports for post-game analysis and live broadcasting.

Win Probability Chart rendered with Apache ECharts

Renders

JavaScript source (Apache ECharts)

// anyplot.ai
// line-win-probability: Win Probability Chart
// Library: echarts 5.5.1 | JavaScript 22.22.3
// Quality: 90/100 | Created: 2026-06-21

const t = window.ANYPLOT_TOKENS;

// NFL comeback — Atlanta Falcons (home) vs Baltimore Ravens (away)
// Home-team win probability by game minute, derived from in-game model
const keyPoints = [
  [0, 50], [8, 65], [18, 50], [23, 35],
  [30, 32], [37, 18], [43, 38], [49, 55], [54, 72], [60, 85],
];

// Linear interpolation between key turning points (~2 pts per minute)
const times = [], probs = [];
for (let i = 0; i < keyPoints.length - 1; i++) {
  const [x0, y0] = keyPoints[i], [x1, y1] = keyPoints[i + 1];
  const steps = Math.max(4, Math.round((x1 - x0) * 2));
  for (let s = 0; s < steps; s++) {
    const f = s / steps;
    times.push(+(x0 + (x1 - x0) * f).toFixed(2));
    probs.push(+(y0 + (y1 - y0) * f).toFixed(1));
  }
}
times.push(60); probs.push(85);

// Clamped arrays: area above 50% (home) and below 50% (away)
const lineData     = times.map((m, i) => [m, probs[i]]);
const homeAreaData = times.map((m, i) => [m, Math.max(probs[i], 50)]);
const awayAreaData = times.map((m, i) => [m, Math.min(probs[i], 50)]);

// Title with proportional font scaling
const titleText = "Win Probability · line-win-probability · javascript · echarts · anyplot.ai";
const titleFs = Math.max(14, Math.round(22 * Math.min(1, 67 / titleText.length)));

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

chart.setOption({
  animation: false,
  backgroundColor: "transparent",
  color: t.palette,

  title: {
    text: titleText,
    left: "center",
    top: 24,
    textStyle: { color: t.ink, fontSize: titleFs, fontWeight: "600" },
  },

  legend: {
    data: [
      { name: "Falcons (Home)", icon: "roundRect" },
      { name: "Ravens (Away)",  icon: "roundRect" },
    ],
    right: 40,
    bottom: 20,
    textStyle: { color: t.ink, fontSize: 14 },
    itemWidth: 22,
    itemHeight: 12,
    itemGap: 28,
  },

  grid: { left: 92, right: 40, top: 90, bottom: 80 },

  xAxis: {
    type: "value",
    name: "Game Time (minutes)",
    nameLocation: "middle",
    nameGap: 48,
    nameTextStyle: { color: t.inkSoft, fontSize: 14 },
    min: 0, max: 60,
    interval: 15,
    axisLabel: {
      color: t.inkSoft, fontSize: 13,
      formatter: v => ({ 0: "Kickoff", 15: "Q2", 30: "Half", 45: "Q4", 60: "Final" }[v] ?? ""),
    },
    axisLine: { lineStyle: { color: t.inkSoft } },
    axisTick: { show: false },
    splitLine: { show: false },
  },

  yAxis: {
    type: "value",
    name: "Home Win Probability",
    nameLocation: "middle",
    nameGap: 58,
    nameTextStyle: { color: t.inkSoft, fontSize: 14 },
    min: 0, max: 100,
    interval: 25,
    axisLabel: { color: t.inkSoft, fontSize: 13, formatter: "{value}%" },
    axisLine: { show: false },
    axisTick: { show: false },
    splitLine: { show: false },
  },

  series: [
    // Away team fill — below 50% (Ravens)
    {
      name: "Ravens (Away)",
      type: "line",
      data: awayAreaData,
      symbol: "none",
      lineStyle: { width: 0 },
      itemStyle: { color: t.palette[4] },
      areaStyle: { color: t.palette[4], opacity: 0.28, origin: 50 },
      z: 1, silent: true,
    },
    // Home team fill — above 50% (Falcons)
    {
      name: "Falcons (Home)",
      type: "line",
      data: homeAreaData,
      symbol: "none",
      lineStyle: { width: 0 },
      itemStyle: { color: t.palette[0] },
      areaStyle: { color: t.palette[0], opacity: 0.28, origin: 50 },
      z: 1, silent: true,
    },
    // Main win-probability line with annotations
    {
      type: "line",
      data: lineData,
      symbol: "none",
      lineStyle: { width: 2.5, color: t.ink },
      z: 3,
      markLine: {
        silent: true,
        symbol: "none",
        data: [
          // 50% reference
          {
            yAxis: 50,
            lineStyle: { color: t.inkSoft, type: "dashed", width: 1.5 },
            label: {
              show: true, position: "insideStartTop",
              formatter: "Even", color: t.inkSoft, fontSize: 11,
            },
          },
          // Quarter dividers
          { xAxis: 15, lineStyle: { color: t.grid, type: "solid", width: 1 }, label: { show: false } },
          { xAxis: 30, lineStyle: { color: t.grid, type: "solid", width: 1 }, label: { show: false } },
          { xAxis: 45, lineStyle: { color: t.grid, type: "solid", width: 1 }, label: { show: false } },
        ],
      },
      markPoint: {
        silent: true,
        symbolSize: 10,
        data: [
          {
            coord: [8, 65],
            itemStyle: { color: t.palette[0] },
            label: { show: true, formatter: "TD 7–0",   color: t.palette[0], fontSize: 11, fontWeight: "700", position: "top" },
          },
          {
            coord: [23, 35],
            itemStyle: { color: t.palette[4] },
            label: { show: true, formatter: "TD 7–14",  color: t.palette[4], fontSize: 11, fontWeight: "700", position: "bottom" },
          },
          {
            coord: [37, 18],
            itemStyle: { color: t.palette[4] },
            label: { show: true, formatter: "TD 7–21",  color: t.palette[4], fontSize: 11, fontWeight: "700", position: "bottom" },
          },
          {
            coord: [49, 55],
            itemStyle: { color: t.palette[0] },
            label: { show: true, formatter: "TD 21–21", color: t.palette[0], fontSize: 11, fontWeight: "700", position: "top" },
          },
          {
            coord: [54, 72],
            itemStyle: { color: t.palette[0] },
            label: { show: true, formatter: "FG 24–21", color: t.palette[0], fontSize: 11, fontWeight: "700", position: "top" },
          },
        ],
      },
    },
  ],

  graphic: [
    {
      type: "text",
      z: 5,
      style: {
        text: "Final: Falcons 24 – Ravens 21",
        fill: t.ink,
        fontSize: 13,
        fontWeight: "600",
        x: 1200,
        y: 106,
        textAlign: "right",
      },
    },
  ],
});

Part of Win Probability Chart on anyplot.ai.

Other implementations