Dengue Epidemic Growth Rate & Doubling Time

Kenya · WHO AFRO Surveillance · 2024–2025

Author

Timothy Achala

Published

June 3, 2026

1 · Data

Monthly national dengue case counts downloaded from the WHO Disease Outbreak News Data Explorer (AFRO region filter). The dataset covers January 2024 – February 2025 for Kenya at Admin-0 resolution.

Code
raw <- tibble(
  date   = seq.Date(as.Date("2024-01-01"), by = "month", length.out = 14),
  cases  = c(0, 0, 0, 0, 149, 291, 369, 631, 738, 705, 856, 704, 855, 673)
)

# Mark epidemic phases
raw <- raw %>%
  mutate(
    month_label = format(date, "%b %Y"),
    phase = case_when(
      date <  as.Date("2024-05-01") ~ "Pre-epidemic (zero)",
      date <= as.Date("2024-11-01") ~ "Ascending phase",
      TRUE                          ~ "Plateau / Tail"
    )
  )

knitr::kable(
  raw %>% select(Month = month_label, Cases = cases, Phase = phase),
  caption = "**Table 1.** Monthly dengue case counts, Kenya 2024–2025"
)
Table 1. Monthly dengue case counts, Kenya 2024–2025
Month Cases Phase
Jan 2024 0 Pre-epidemic (zero)
Feb 2024 0 Pre-epidemic (zero)
Mar 2024 0 Pre-epidemic (zero)
Apr 2024 0 Pre-epidemic (zero)
May 2024 149 Ascending phase
Jun 2024 291 Ascending phase
Jul 2024 369 Ascending phase
Aug 2024 631 Ascending phase
Sept 2024 738 Ascending phase
Oct 2024 705 Ascending phase
Nov 2024 856 Ascending phase
Dec 2024 704 Plateau / Tail
Jan 2025 855 Plateau / Tail
Feb 2025 673 Plateau / Tail

2 · Exponential Growth Model

2.1 Model Specification

During the ascending phase (May – November 2024), epidemic case counts are expected to follow exponential growth:

\[ C(t) = C_0 \cdot e^{rt} \]

where:

  • \(C(t)\) = cumulative / incident cases at time \(t\) (months from May 2024)
  • \(C_0\) = baseline cases at \(t = 0\) (May 2024)
  • \(r\) = intrinsic growth rate (per month)
  • Doubling time \(= \dfrac{\ln 2}{r}\)

Linearising by taking the natural log gives a simple log-linear regression:

\[ \ln C(t) = \ln C_0 + r \cdot t \]

Code
# ── Ascending phase subset ────────────────────────────────────────────────────
asc <- raw %>%
  filter(phase == "Ascending phase") %>%
  mutate(t = row_number() - 1,          # t = 0 at May 2024
         log_cases = log(cases))

# ── Log-linear OLS fit ────────────────────────────────────────────────────────
fit_lm <- lm(log_cases ~ t, data = asc)
fit_tb <- tidy(fit_lm, conf.int = TRUE)

r_est     <- coef(fit_lm)[["t"]]
r_lo      <- fit_tb$conf.low[fit_tb$term == "t"]
r_hi      <- fit_tb$conf.high[fit_tb$term == "t"]
C0_est    <- exp(coef(fit_lm)[["(Intercept)"]])
R2        <- summary(fit_lm)$r.squared
dt        <- log(2) / r_est
dt_lo     <- log(2) / r_hi          # Note: inverted because r_hi → smaller dt
dt_hi     <- log(2) / r_lo

cat(sprintf(
  "Growth rate r  : %.4f per month (95%% CI: %.4f – %.4f)\n",
  r_est, r_lo, r_hi
))
Growth rate r  : 0.2753 per month (95% CI: 0.1566 – 0.3940)
Code
cat(sprintf(
  "Doubling time  : %.2f months (95%% CI: %.2f – %.2f)\n",
  dt, dt_lo, dt_hi
))
Doubling time  : 2.52 months (95% CI: 1.76 – 4.43)
Code
cat(sprintf("R²             : %.4f\n", R2))
R²             : 0.8767
Code
cat(sprintf("Baseline C₀    : %.1f cases (May 2024)\n", C0_est))
Baseline C₀    : 202.3 cases (May 2024)

2.2 Inflection Point

For a logistic epidemic model, the inflection point (transition from acceleration to deceleration) occurs where growth rate \(dC/dt\) is maximised — i.e. where the log-linear trend begins to flatten. We detect this empirically using first-differences of log cases and identify the month where the increment drops after reaching its peak.

Code
asc <- asc %>%
  mutate(
    delta_log = c(NA, diff(log_cases)),
    is_inflection = (delta_log == max(delta_log, na.rm = TRUE))
  )

inflection_date <- asc$date[which(asc$is_inflection)]
inflection_case <- asc$cases[which(asc$is_inflection)]

cat(sprintf(
  "Empirical inflection point: %s (%d cases)\n",
  format(inflection_date, "%B %Y"), inflection_case
))
Empirical inflection point: June 2024 (291 cases)

3 · Results Summary

Code
tibble(
  Parameter          = c("Growth rate (r)", "Doubling time", "Baseline C₀ (May 2024)",
                         "Model R²", "Inflection point"),
  Estimate           = c(
    sprintf("%.4f/month", r_est),
    sprintf("%.2f months", dt),
    sprintf("%.0f cases", C0_est),
    sprintf("%.2f%%", R2 * 100),
    format(inflection_date, "%B %Y")
  ),
  `95% CI`           = c(
    sprintf("%.4f – %.4f", r_lo, r_hi),
    sprintf("%.2f – %.2f months", dt_lo, dt_hi),
    "—", "—", "—"
  )
) %>%
  knitr::kable(caption = "**Table 2.** Exponential growth model estimates")
Table 2. Exponential growth model estimates
Parameter Estimate 95% CI
Growth rate (r) 0.2753/month 0.1566 – 0.3940
Doubling time 2.52 months 1.76 – 4.43 months
Baseline C₀ (May 2024) 202 cases
Model R² 87.67%
Inflection point June 2024
📊 Key Findings
  • The growth rate of 0.275 per month indicates rapid epidemic expansion during May–November 2024.
  • Cases were doubling every ~2.5 months, confirming sustained, accelerating transmission.
  • The model explains 87.7% of variance in log-transformed counts — an excellent fit for an epidemic growth model.
  • The inflection point occurred in June 2024, when the per-month increment of log-cases peaked, signalling the transition from acceleration to deceleration of growth.

4 · Visualisations

4.1 Full Epidemic Curve with Ascending Phase Highlighted

Code
# Predicted ribbon for ascending phase
pred_df <- asc %>%
  mutate(
    fit_cases   = exp(predict(fit_lm)),
    fit_lo      = exp(predict(fit_lm, interval = "confidence")[, "lwr"]),
    fit_hi      = exp(predict(fit_lm, interval = "confidence")[, "upr"])
  )

ggplot(raw, aes(x = date, y = cases)) +
  # Shade ascending phase background
  annotate("rect",
    xmin = as.Date("2024-04-15"), xmax = as.Date("2024-11-15"),
    ymin = -Inf, ymax = Inf,
    fill = pal$shade, alpha = 0.7
  ) +
  # Confidence ribbon for fit
# Confidence ribbon for fit
  geom_ribbon(data = pred_df, aes(x = date, ymin = fit_lo, ymax = fit_hi),
              fill = pal$fit, alpha = 0.2, inherit.aes = FALSE) +
  # Exponential fit line (ascending only)
  geom_line(data = pred_df, aes(y = fit_cases),
            colour = pal$fit, linewidth = 1.2, linetype = "dashed") +
  # Full series bars
  geom_col(aes(fill = phase), width = 22, colour = "white", linewidth = 0.3) +
  # Inflection point marker
  geom_vline(xintercept = inflection_date,
             colour = pal$inflec, linewidth = 1, linetype = "dotdash") +
  annotate("label",
    x = inflection_date, y = 820,
    label = paste0("Inflection\n", format(inflection_date, "%b %Y")),
    colour = pal$inflec, fill = "white", size = 3.2,
    label.padding = unit(0.25, "lines"), label.size = 0.3
  ) +
  scale_fill_manual(
    values = c(
      "Pre-epidemic (zero)" = "grey70",
      "Ascending phase"     = pal$ascend,
      "Plateau / Tail"      = pal$full
    ),
    name = "Phase"
  ) +
  scale_x_date(date_labels = "%b\n%Y", date_breaks = "1 month") +
  scale_y_continuous(labels = comma, expand = expansion(mult = c(0, 0.08))) +
  labs(
    title    = "Kenya Dengue Epidemic Curve, 2024–2025",
    subtitle = "Monthly case counts · <span style='color:#E74C3C'>**Ascending phase**</span> highlighted · <span style='color:#F39C12'>**Dashed** = exponential fit</span>",
    x        = NULL,
    y        = "Monthly Cases",
    caption  = "Source: WHO AFRO Disease Data Explorer · Admin-0 resolution · Case definition: Total"
  ) +
  theme_epi()

Figure 1: Figure 1. Monthly dengue case counts, Kenya 2024–2025. The red-shaded region marks the ascending phase used for growth modelling.

4.2 Log-Linear Fit (Ascending Phase)

Code
ggplot(asc, aes(x = t, y = log_cases)) +
  geom_smooth(method = "lm", colour = pal$fit, fill = pal$fit,
              alpha = 0.15, linewidth = 1.3) +
  geom_point(aes(colour = is_inflection), size = 5) +
  geom_text(aes(label = format(date, "%b")),
            vjust = -1, size = 3.2, colour = pal$text) +
  scale_colour_manual(
    values = c("FALSE" = pal$ascend, "TRUE" = pal$inflec),
    labels = c("FALSE" = "Ascending data point", "TRUE" = "Inflection point"),
    name   = NULL
  ) +
  scale_x_continuous(breaks = 0:6,
                     labels = format(asc$date, "%b '%y")) +
  labs(
    title    = "Log-Linear Fit · Ascending Phase (May – Nov 2024)",
    subtitle = sprintf(
      "ln C(t) = %.3f + **%.4f** · t &nbsp;&nbsp;|&nbsp;&nbsp; R² = %.3f &nbsp;&nbsp;|&nbsp;&nbsp; Doubling time = **%.2f months**",
      coef(fit_lm)[1], r_est, R2, dt
    ),
    x        = "Month (t = 0 → May 2024)",
    y        = "ln(Monthly Cases)",
    caption  = "Shaded band = 95% confidence interval of the fitted line"
  ) +
  theme_epi() +
  theme(plot.subtitle = element_markdown())

Figure 2: Figure 2. Log-linear regression on the ascending phase. A straight line on the log scale confirms exponential growth. Points deviating from the line indicate departure from pure exponential dynamics.

4.3 Observed vs. Fitted Cases

Code
pred_df %>%
  select(date, Observed = cases, Fitted = fit_cases, fit_lo, fit_hi) %>%
  pivot_longer(c(Observed, Fitted), names_to = "Series", values_to = "cases") %>%
  ggplot(aes(x = date, y = cases, colour = Series, shape = Series)) +
  geom_errorbar(
    data = pred_df,
    aes(x = date, ymin = fit_lo, ymax = fit_hi),
    inherit.aes = FALSE,
    colour = pal$fit, width = 5, linewidth = 0.7, alpha = 0.6
  ) +
  geom_line(linewidth = 1.2) +
  geom_point(size = 4) +
  scale_colour_manual(values = c(Observed = pal$ascend, Fitted = pal$fit)) +
  scale_shape_manual(values  = c(Observed = 16, Fitted = 17)) +
  scale_x_date(date_labels = "%b %Y") +
  scale_y_continuous(labels = comma) +
  labs(
    title    = "Observed vs. Exponential Model Fit",
    subtitle = "Ascending phase only · Error bars = 95% CI of fitted values",
    x        = NULL, y = "Monthly Cases", colour = NULL, shape = NULL,
    caption  = "Exponential model: C(t) = C₀ · exp(r · t)"
  ) +
  theme_epi()

Figure 3: Figure 3. Observed cases vs. exponential model predictions across the ascending phase. Bars show 95% prediction intervals.

5 · Interpretation

Growth Dynamics

The exponential growth model fit the ascending phase extremely well (R² = 87.7%), confirming that dengue transmission in Kenya during May–November 2024 followed near-classical epidemic dynamics with no significant deceleration early in the wave.

A growth rate of 0.275 per month is epidemiologically meaningful: it means cases were increasing by approximately 31.7% each month during this period. Translated into doubling time, every ~2.5 months the case burden doubled — indicating sustained, high-intensity community transmission likely driven by Aedes aegypti population dynamics coinciding with Kenya’s long rains (March–May) and short rains (October–December) seasons.

Inflection Point

The empirical inflection point in June 2024 marks the month when the per-month acceleration of cases was greatest — the steepest part of the epidemic curve on the log scale. After this point, while cases continued to rise, the rate of increase began to slow, suggesting some combination of:

  • Herd immunity accumulation in densely affected populations
  • Behavioural change or vector control interventions
  • Seasonal vector decline as conditions became less favourable for Aedes breeding

Public Health Implication

A doubling time of 2.5 months gives response teams a narrow intervention window. For reference, COVID-19 early waves had doubling times of 2–7 days; dengue’s monthly doubling reflects its slower transmission dynamics (mosquito-mediated, with extrinsic incubation period). Nevertheless, the scale from 149 cases in May to 856 in November — a 5.7× increase in 6 months — underscores the need for early warning triggers and pre-emptive vector control before the long-rains season.