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 phasesraw <- 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 2024log_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.squareddt <-log(2) / r_estdt_lo <-log(2) / r_hi # Note: inverted because r_hi → smaller dtdt_hi <-log(2) / r_locat(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)
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.
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
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 | R² = %.3f | 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.
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.
Source Code
---title: "Dengue Epidemic Growth Rate & Doubling Time"subtitle: "Kenya · WHO AFRO Surveillance · 2024–2025"author: "Timothy Achala"date: todayformat: html: theme: flatly toc: true toc-depth: 3 toc-title: "Contents" code-fold: true code-tools: true fig-width: 9 fig-height: 5.5 self-contained: trueexecute: warning: false message: false echo: true---```{r setup}#| label: setup#| include: falselibrary(tidyverse)library(scales)library(broom)library(ggtext)library(patchwork)# ── Palette ──────────────────────────────────────────────────────────────────pal <-list(full ="#4B8BBE", # full seriesascend ="#E74C3C", # ascending phase highlightfit ="#F39C12", # exponential fitinflec ="#2ECC71", # inflection pointshade ="#FDECEA", # ribbon fillgrid ="grey92",text ="#2C3E50")theme_epi <-function() {theme_minimal(base_size =13) +theme(plot.title =element_markdown(face ="bold", colour = pal$text, size =15),plot.subtitle =element_markdown(colour ="grey45", size =11),plot.caption =element_text(colour ="grey60", size =9, hjust =0),axis.title =element_text(colour = pal$text, size =11),axis.text =element_text(colour ="grey40"),panel.grid.major =element_line(colour = pal$grid, linewidth =0.4),panel.grid.minor =element_blank(),legend.position ="bottom",legend.text =element_text(size =10),plot.margin =margin(12, 16, 12, 12) )}```## 1 · DataMonthly 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.```{r data}#| label: dataraw <-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 phasesraw <- 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")```---## 2 · Exponential Growth Model### 2.1 Model SpecificationDuring 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$$```{r model}#| label: model# ── Ascending phase subset ────────────────────────────────────────────────────asc <- raw %>%filter(phase =="Ascending phase") %>%mutate(t =row_number() -1, # t = 0 at May 2024log_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.squareddt <-log(2) / r_estdt_lo <-log(2) / r_hi # Note: inverted because r_hi → smaller dtdt_hi <-log(2) / r_locat(sprintf("Growth rate r : %.4f per month (95%% CI: %.4f – %.4f)\n", r_est, r_lo, r_hi))cat(sprintf("Doubling time : %.2f months (95%% CI: %.2f – %.2f)\n", dt, dt_lo, dt_hi))cat(sprintf("R² : %.4f\n", R2))cat(sprintf("Baseline C₀ : %.1f cases (May 2024)\n", C0_est))```### 2.2 Inflection PointFor 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.```{r inflection}#| label: inflectionasc <- 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))```---## 3 · Results Summary```{r results-table}#| label: results-tabletibble(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")```::: {.callout-note icon=false}## 📊 Key Findings- The **growth rate of `r round(r_est, 3)` per month** indicates rapid epidemic expansion during May–November 2024. - Cases were **doubling every ~`r round(dt, 1)` months**, confirming sustained, accelerating transmission. - The model explains **`r round(R2*100, 1)`% of variance** in log-transformed counts — an excellent fit for an epidemic growth model. - The **inflection point occurred in `r format(inflection_date, "%B %Y")`**, 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```{r fig-epi-curve}#| label: fig-epi-curve#| fig-cap: "**Figure 1.** Monthly dengue case counts, Kenya 2024–2025. The red-shaded region marks the ascending phase used for growth modelling."# Predicted ribbon for ascending phasepred_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 backgroundannotate("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 fitgeom_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 barsgeom_col(aes(fill = phase), width =22, colour ="white", linewidth =0.3) +# Inflection point markergeom_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()```### 4.2 Log-Linear Fit (Ascending Phase)```{r fig-loglinear}#| label: fig-loglinear#| fig-cap: "**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."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 | R² = %.3f | 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())```### 4.3 Observed vs. Fitted Cases```{r fig-obs-fit}#| label: fig-obs-fit#| fig-cap: "**Figure 3.** Observed cases vs. exponential model predictions across the ascending phase. Bars show 95% prediction intervals."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()```---## 5 · Interpretation### Growth DynamicsThe exponential growth model fit the ascending phase extremely well (**R² = `r round(R2*100,1)`%**), 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 `r round(r_est, 3)` per month** is epidemiologically meaningful: it means cases were increasing by approximately **`r round((exp(r_est)-1)*100, 1)`% each month** during this period. Translated into doubling time, every **~`r round(dt, 1)` 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 PointThe empirical inflection point in **`r format(inflection_date, "%B %Y")`** 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 ImplicationA doubling time of `r round(dt, 1)` 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 **`r round(856/149, 1)`× increase in 6 months** — underscores the need for early warning triggers and pre-emptive vector control before the long-rains season.---