Training Loss Curve — Apache ECharts

A line plot showing training and validation loss curves over epochs during neural network training. This visualization is essential for monitoring model training, detecting overfitting (when validation loss diverges from training loss), and determining optimal early stopping points. The dual-curve display reveals the gap between training and generalization performance.

Training Loss Curve rendered with Apache ECharts

Renders

JavaScript source (Apache ECharts)

// anyplot.ai
// line-loss-training: Training Loss Curve
// Library: echarts 6.1.0 | JavaScript 22.23.2
// Quality: 94/100 | Created: 2026-09-05

const t = window.ANYPLOT_TOKENS;

// --- Data (in-memory, deterministic LCG) ------------------------------------
function makeLcg(seed) {
  let state = seed;
  return () => {
    state = (state * 1664525 + 1013904223) % 4294967296;
    return state / 4294967296;
  };
}
const rand = makeLcg(42);

const epochCount = 60;
const epochs = Array.from({ length: epochCount }, (_, i) => i + 1);

const trainLoss = [];
const valLoss = [];
let minValLossEpoch = 1;
let minValLoss = Infinity;
for (let i = 0; i < epochCount; i++) {
  const epoch = i + 1;
  // Training loss: smooth exponential decay
  const train = 0.15 + 2.1 * Math.exp(-epoch / 12) + (rand() - 0.5) * 0.015;
  // Validation loss: tracks training loss early on, then plateaus and
  // creeps back up past ~epoch 30 to show overfitting
  const overfitOnset = 28;
  const overfitTerm = epoch > overfitOnset ? 0.0022 * (epoch - overfitOnset) ** 1.3 : 0;
  const val = 0.22 + 2.0 * Math.exp(-epoch / 13) + overfitTerm + (rand() - 0.5) * 0.02;

  trainLoss.push(Number(train.toFixed(4)));
  valLoss.push(Number(val.toFixed(4)));

  if (val < minValLoss) {
    minValLoss = val;
    minValLossEpoch = epoch;
  }
}

const stopIdx = epochs.indexOf(minValLossEpoch);
const gapBase = epochs.map((e, i) => [e, i >= stopIdx ? trainLoss[i] : null]);
const gapFill = epochs.map((e, i) =>
  i >= stopIdx ? [e, Number((valLoss[i] - trainLoss[i]).toFixed(4))] : [e, null],
);

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

// --- Option --------------------------------------------------------------------
chart.setOption({
  animation: false,
  color: [t.palette[0], t.palette[1]],
  backgroundColor: "transparent",
  title: {
    text: "line-loss-training · javascript · echarts · anyplot.ai",
    left: "center",
    textStyle: { color: t.ink, fontSize: 22, fontWeight: 500 },
  },
  legend: {
    data: ["Training loss", "Validation loss"],
    top: 60,
    textStyle: { color: t.inkSoft, fontSize: 15 },
    itemWidth: 24,
    itemHeight: 3,
  },
  grid: { left: 90, right: 60, top: 130, bottom: 80 },
  xAxis: {
    type: "value",
    name: "Epoch",
    nameLocation: "middle",
    nameGap: 40,
    nameTextStyle: { color: t.ink, fontSize: 16 },
    min: 1,
    max: epochCount,
    axisLabel: { color: t.inkSoft, fontSize: 14 },
    axisLine: { show: false },
    splitLine: { show: false },
  },
  yAxis: {
    type: "value",
    name: "Cross-Entropy Loss",
    nameLocation: "middle",
    nameGap: 60,
    nameTextStyle: { color: t.ink, fontSize: 16 },
    axisLabel: { color: t.inkSoft, fontSize: 14 },
    axisLine: { show: false },
    splitLine: { lineStyle: { color: t.grid } },
  },
  series: [
    {
      name: "__gap_base",
      type: "line",
      data: gapBase,
      stack: "gap",
      showSymbol: false,
      silent: true,
      tooltip: { show: false },
      lineStyle: { opacity: 0 },
      areaStyle: { opacity: 0 },
      z: 1,
    },
    {
      name: "__gap_fill",
      type: "line",
      data: gapFill,
      stack: "gap",
      showSymbol: false,
      silent: true,
      tooltip: { show: false },
      lineStyle: { opacity: 0 },
      areaStyle: { color: t.palette[1], opacity: 0.14 },
      z: 1,
    },
    {
      name: "Training loss",
      type: "line",
      data: epochs.map((e, i) => [e, trainLoss[i]]),
      showSymbol: false,
      lineStyle: { width: 3.5, color: t.palette[0] },
    },
    {
      name: "Validation loss",
      type: "line",
      data: epochs.map((e, i) => [e, valLoss[i]]),
      showSymbol: false,
      lineStyle: { width: 3.5, color: t.palette[1] },
    },
    {
      name: "Optimal stopping point",
      type: "scatter",
      data: [[minValLossEpoch, minValLoss]],
      symbolSize: 16,
      itemStyle: {
        color: "transparent",
        borderColor: t.ink,
        borderWidth: 2.5,
      },
      z: 10,
      tooltip: { show: false },
      markLine: {
        symbol: "none",
        silent: true,
        lineStyle: { color: t.ink, type: "dashed", width: 1.5, opacity: 0.5 },
        label: {
          formatter: `Min val loss · epoch ${minValLossEpoch}`,
          color: t.inkSoft,
          fontSize: 13,
          position: "insideEndTop",
        },
        data: [{ xAxis: minValLossEpoch }],
      },
    },
  ],
});

Retrieve this implementation

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

Part of Training Loss Curve on anyplot.ai.

Other implementations