Introduction

When a new infectious disease appears, the first question is always the same: how bad will it get, and when? Since the early twentieth century, mathematicians have answered this with compartmental models — they divide a population into groups and write down rules for how people move between them.

The simplest is SIR: everyone starts Susceptible, then moves to Infectious, then to Removed (recovered or deceased). It is elegant and captures the qualitative shape of an outbreak — a fast rise, a peak, a slow decline. But it has a flaw: in SIR, the moment you catch a pathogen you immediately become infectious yourself.

Real diseases rarely work that way. Influenza, COVID-19, measles — all have an incubation period during which you are infected but not yet contagious. You carry the pathogen, you feel nothing, and the world around you does not know the clock has started.

The SEIR model fixes this by inserting one compartment between S and I: E for Exposed. A person moves S→ES \to E when infected and E→IE \to I only after the incubation ends. That single delay changes the epidemic curve in ways that matter for every public-health decision.

Try It

The simulation below runs a discrete-time SEIR model on a population of 10 000. Adjust the sliders to change the transmission rate β\beta, the incubation rate σ\sigma (how fast exposed people become infectious), and the recovery rate γ\gamma.

<!-- SEIR simulation controls and chart canvas -->
<div class="controls">
  <label>
    <span>β — Transmission rate (contacts × probability):</span>
    <input type="range" id="beta" min="0.05" max="0.8" step="0.01" value="0.3">
    <span id="betaVal" class="val">0.30</span>
  </label>
  <label>
    <span>σ — Incubation rate (1/σ = incubation days):</span>
    <input type="range" id="sigma" min="0.05" max="1.0" step="0.01" value="0.2">
    <span id="sigmaVal" class="val">0.20</span>
  </label>
  <label>
    <span>γ — Recovery rate (1/γ = infectious days):</span>
    <input type="range" id="gamma" min="0.05" max="0.5" step="0.01" value="0.1">
    <span id="gammaVal" class="val">0.10</span>
  </label>
</div>
<canvas id="chart" width="560" height="260" aria-label="SEIR epidemic curve chart"></canvas>
<div id="info" class="info"></div>
<div class="legend">
  <span class="dot s"></span>Susceptible
  <span class="dot e"></span>Exposed
  <span class="dot i"></span>Infectious
  <span class="dot r"></span>Recovered
</div>
/* Styles for the SEIR model demo */
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; color: #222; padding: .5rem; }
.controls { display: flex; flex-direction: column; gap: .4rem; margin-bottom: .6rem; }
label { display: flex; align-items: center; gap: .5rem; font-size: .85rem; }
label span:first-child { width: 13rem; flex-shrink: 0; }
input[type=range] { flex: 1; accent-color: #1d3557; }
.val { width: 3rem; text-align: right; font-variant-numeric: tabular-nums; }
canvas { display: block; width: 100%; max-width: 560px; border: 1px solid #dde3ea; border-radius: 8px; background: #f8fafc; }
.info { font-size: .85rem; margin-top: .5rem; color: #444; min-height: 2.2em; line-height: 1.5; }
.legend { display: flex; align-items: center; gap: .8rem; font-size: .8rem; margin-top: .4rem; flex-wrap: wrap; }
.dot { display: inline-block; width: 12px; height: 12px; border-radius: 50%; margin-right: .2rem; }
.dot.s { background: #457b9d; }
.dot.e { background: #e9c46a; }
.dot.i { background: #e63946; }
.dot.r { background: #2a9d8f; }
const i18nFmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// SEIR compartmental epidemic model — Susceptible, Exposed, Infectious, Recovered
// Parameters: beta=transmission rate, sigma=incubation rate, gamma=recovery rate
const N = 10000;
const DAYS = 200;
const COLORS = { S: '#457b9d', E: '#e9c46a', I: '#e63946', R: '#2a9d8f' };

// Run the SEIR model for DAYS time steps using Euler integration
function runSEIR(beta, sigma, gamma) {
  // Start: one infectious individual in a fully susceptible population
  let S = N - 1, E = 0, I = 1, R = 0;
  const ts = [], ts_E = [], ts_I = [], ts_S = [], ts_R = [];
  for (let d = 0; d <= DAYS; d++) {
    ts.push(d);
    ts_S.push(S / N);
    ts_E.push(E / N);
    ts_I.push(I / N);
    ts_R.push(R / N);
    // Discrete-time Euler step for the SEIR ODEs
    const newExposed = beta * S * I / N;
    const newInfectious = sigma * E;
    const newRecovered = gamma * I;
    S -= newExposed;
    E += newExposed - newInfectious;
    I += newInfectious - newRecovered;
    R += newRecovered;
  }
  return { ts, ts_S, ts_E, ts_I, ts_R };
}

// Draw the epidemic curves on the canvas
function draw() {
  const beta = parseFloat(document.getElementById('beta').value);
  const sigma = parseFloat(document.getElementById('sigma').value);
  const gamma = parseFloat(document.getElementById('gamma').value);
  document.getElementById('betaVal').textContent = beta.toFixed(2);
  document.getElementById('sigmaVal').textContent = sigma.toFixed(2);
  document.getElementById('gammaVal').textContent = gamma.toFixed(2);

  const { ts, ts_S, ts_E, ts_I, ts_R } = runSEIR(beta, sigma, gamma);

  const canvas = document.getElementById('chart');
  const ctx = canvas.getContext('2d');
  const W = canvas.width, H = canvas.height;
  const PAD = { top: 14, right: 14, bottom: 30, left: 40 };
  const cw = W - PAD.left - PAD.right;
  const ch = H - PAD.top - PAD.bottom;

  ctx.clearRect(0, 0, W, H);

  // Draw coordinate axes
  ctx.strokeStyle = '#c8d4de';
  ctx.lineWidth = 1;
  ctx.beginPath();
  ctx.moveTo(PAD.left, PAD.top);
  ctx.lineTo(PAD.left, PAD.top + ch);
  ctx.lineTo(PAD.left + cw, PAD.top + ch);
  ctx.stroke();

  // Draw horizontal percentage gridlines
  ctx.setLineDash([3, 3]);
  ctx.strokeStyle = '#dde3ea';
  for (let g = 0.25; g < 1; g += 0.25) {
    const y = PAD.top + ch - g * ch;
    ctx.beginPath();
    ctx.moveTo(PAD.left, y);
    ctx.lineTo(PAD.left + cw, y);
    ctx.stroke();
    ctx.fillStyle = '#888';
    ctx.font = '10px system-ui';
    ctx.textAlign = 'right';
    ctx.fillText((g * 100).toFixed(0) + '%', PAD.left - 4, y + 4);
  }
  ctx.setLineDash([]);

  // Draw day labels on the x-axis
  ctx.fillStyle = '#888';
  ctx.font = '10px system-ui';
  ctx.textAlign = 'center';
  for (let d = 0; d <= DAYS; d += 50) {
    const x = PAD.left + (d / DAYS) * cw;
    ctx.fillText(d, x, PAD.top + ch + 14);
  }

  // Draw S, E, I, R curves
  const series = [
    { data: ts_S, color: COLORS.S },
    { data: ts_E, color: COLORS.E },
    { data: ts_I, color: COLORS.I },
    { data: ts_R, color: COLORS.R }
  ];
  for (const { data, color } of series) {
    ctx.strokeStyle = color;
    ctx.lineWidth = 2;
    ctx.beginPath();
    for (let i = 0; i < ts.length; i++) {
      const x = PAD.left + (ts[i] / DAYS) * cw;
      const y = PAD.top + ch - data[i] * ch;
      i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
    }
    ctx.stroke();
  }

  // Compute summary statistics for the info bar
  const peakDay = ts_I.indexOf(Math.max(...ts_I));
  const peakPct = (Math.max(...ts_I) * 100).toFixed(1);
  const r0 = (beta / gamma).toFixed(2);
  const totalInfected = (ts_R[ts_R.length - 1] * 100).toFixed(1);
  const incubDays = (1 / sigma).toFixed(1);

  document.getElementById('info').innerHTML =
    i18nFmt('R₀ = %r0% · Peak infectious: %peak%% on day %day% · Mean incubation: %incub% days · Total infected: %total%%', { r0, peak: peakPct, day: peakDay, incub: incubDays, total: totalInfected });
}

// Re-draw whenever any slider moves
['beta', 'sigma', 'gamma'].forEach(id => {
  document.getElementById(id).addEventListener('input', draw);
});
draw();
Result
Console

Notice how decreasing σ\sigma — lengthening the incubation period — pushes the infectious peak to the right and reduces its height. The total number of people who eventually get infected barely changes, but the peak is stretched over a longer time, giving health systems more breathing room. This is the mathematical core of "flattening the curve."

The Real Complexity

The SEIR model is four coupled ordinary differential equations. With population NN and fractions S,E,I,RS, E, I, R summing to 1:

dSdt=−βSI\frac{dS}{dt} = -\beta S I

dEdt=βSI−σE\frac{dE}{dt} = \beta S I - \sigma E

dIdt=σE−γI\frac{dI}{dt} = \sigma E - \gamma I

dRdt=γI\frac{dR}{dt} = \gamma I

The three key parameters are:

  • β\beta — transmission rate: average contacts per day times the probability of transmission per contact.
  • σ\sigma — incubation rate: 1/σ1/\sigma is the mean incubation period in days (the average time spent in E).
  • γ\gamma — recovery rate: 1/γ1/\gamma is the mean infectious period in days.

The basic reproduction number R0=β/γR_0 = \beta / \gamma measures how many secondary cases one infectious person generates in a fully susceptible population. It does not depend on σ\sigma — the incubation period does not change whether an outbreak grows, only when and how sharply the peak arrives.

Why does E shift the peak? In SIR, new infections immediately swell the infectious pool. In SEIR, they first fill E, which acts as a buffer. The infectious compartment cannot rise faster than E empties, so the peak is delayed by roughly the mean incubation time 1/σ1/\sigma and is lower because II accumulates more slowly. Mathematically, the system's dominant eigenvalue is smaller (in magnitude) when σ\sigma is finite, giving a slower exponential growth phase.

The final-size equation — how many people eventually get infected — depends only on R0R_0 and the initial conditions, not on σ\sigma. Incubation rearranges when infections happen, not how many ultimately occur. That is both the model's power and its sobering message: flattening the curve does not make the outbreak smaller, only more manageable.

For comparison, see Bayesian inference, which is used to estimate β\beta, σ\sigma, and γ\gamma from real case data.

Where It Matters

The exposed compartment turns the SEIR model into one of the most widely used frameworks in public health and beyond:

  • Pandemic planning: SEIR (and its extensions) underpinned nearly every government projection during the COVID-19 pandemic, including the influential Imperial College model by Neil Ferguson's team (2020) that triggered lockdown decisions across Europe and North America.
  • Vaccination strategy: by reducing S, vaccination raises the herd-immunity threshold. SEIR tells planners how quickly coverage must grow to prevent a peak from overwhelming hospitals.
  • Contact tracing: the E compartment is exactly who contact tracing tries to find — people infected but not yet contagious, where isolation is still effective. The ratio 1/σ1/\sigma determines how long the window stays open.
  • Non-pharmaceutical interventions: reducing β\beta through mask use, distancing, or school closures lowers R0R_0 and stretches the curve — the model quantifies the trade-off between duration and peak height.
  • Computer-virus epidemics: the same equations model the spread of malware through networks, where EE captures machines carrying but not yet spreading a payload.
  • Ecological and agricultural outbreaks: plant diseases, crop blights, and animal epidemics all exhibit incubation periods that SEIR captures faithfully.

The SEIR model is a striking example of how a tiny structural change to a mathematical framework — one extra compartment — can change the policy conclusions derived from it. Compare this to how Bayesian inference is used to fit these models to real surveillance data and extract parameter estimates with uncertainty bounds.

Conclusion

The SEIR model is deceptively simple: four compartments, three rates, four equations. Yet the addition of E — the exposed, incubating, pre-contagious population — transforms a rough sketch of an epidemic into a tool precise enough to guide national policy.

The incubation period delays the peak, reduces its height, and defines the window during which contact tracing can still interrupt transmission. R0R_0 tells you whether an outbreak will grow; σ\sigma tells you when the worst will arrive and how sharply. Together they answer the hardest question in an epidemic: not just how bad, but how fast.

The next time you hear "flatten the curve," you are hearing σ\sigma at work — a single parameter stretching a wave across time, buying the days that health systems need to survive it.

Share this article

Pick a channel — or use your device's native share sheet.

Comments

Loading comments...

https://www.kipuhub.com/en/article/seir-model/Content licensed under CC BY-NC 4.0.