Sensitivity and comparison analyses
This page continues the main analysis from the one-week-ahead forecast onward: forecast validation, forecast scoring across releases, the reproduction number by release, the outbreak size each data stream implies alone, how the estimate has evolved across releases, comparisons with McCabe et al. and Chamla et al., and the delay and tree-prior sensitivity re-fits. It renders from the same fitted chains as the main analysis, loaded through the shared setup, so no model is re-fit here beyond the frozen re-fits and the optional sensitivity re-fits below.
Load packages, data and fitted chains
# Shared setup: packages, observations, the fit registry and every model fit
# (loaded from the content-addressed cache). See docs/examples/_setup.jl.
using BVDOutbreakSize
include(joinpath(pkgdir(BVDOutbreakSize), "docs", "examples", "_setup.jl"))45Forecast validation
How last week's forecast held up against the data since observed, using the frozen re-fit and one-week projection defined in forecast-versus-frozen evaluation. The frozen fit also conditions on the isolation beds, so the projected bed occupancy is scored against the beds held a week later. The bed validation is weak at a one-week-back freeze. The reported occupancy rate starts only on 9 June, so the capacity has no implied-capacity anchor and rides its random walk back to the freeze date. This widens the projected bed interval. Unlike the scores further down, the confirmed new-count rows here keep any retrospective harmonisation step the week contained. This means a week holding one reads high against a forecast that never predicted it.
Fit one week back and validate the one-week-ahead forecast
# frozen_lastweek and frozen_lastweek_streams are computed in the setup
# block above.
# `obs_recovered` is passed so the frozen fit's forecast carries a
# `recovered_new` column (materialised only when the recovered origin is
# given), letting the recovered stream be scored against the observed count
# below like the other streams.
# The onset grid is the one the FROZEN fit saw, not the live one, so the
# validation forecast carries an `onset reports` row scored on the triangle
# the frozen fit was actually fitted to.
_val_onset_days = frozen_lastweek.o.onset_curve_history.onset_days
_val_grid_start = isempty(_val_onset_days) ? nothing :
minimum(_val_onset_days)
_val_grid_end = isnothing(_val_grid_start) ? nothing :
max(maximum(frozen_lastweek.o.onset_curve_history.report_days),
_val_grid_start)
validation_forecast = forecast_reported(frozen_lastweek.chn;
horizon = 7,
obs_cases = frozen_lastweek.o.reported_cases,
obs_deaths = frozen_lastweek.o.total_deaths,
obs_confirmed = frozen_lastweek.o.confirmed_cases,
obs_confirmed_deaths = frozen_lastweek.o.confirmed_deaths,
obs_recovered = frozen_lastweek.o.recovered_cases,
grid_n = frozen_lastweek.o.n,
onset_grid_start = _val_grid_start, onset_grid_end = _val_grid_end);
# Each frozen individual (single-stream) fit's own one-week-ahead new-count
# forecast at the same cut-off as `frozen_lastweek`, from
# [`forecast_stream`](@ref) (the same per-stream forecaster
# `stream_forecasts.csv` uses), so the validation plots below can show the
# individual fit alongside the joint rather than the joint alone. Recovered
# has no individual fit and is absent here, as it is throughout this report.
function _validation_individual_new(sid, stream::Symbol, obs_value)
f = frozen_lastweek_streams[sid]
bp = f.o.n - f.o.who_first_sitrep_days
return Float64.(forecast_stream(f.chn, stream; horizon = 7,
obs_value = obs_value, n = f.o.n, breakpoint = bp,
rt_start = 1, rt_walk_start = 1))
end
validation_individual = (;
cases_new = _validation_individual_new(
"cases", :reported_cases,
frozen_lastweek_streams["cases"].o.reported_cases),
deaths_new = _validation_individual_new(
"deaths", :suspected_deaths,
frozen_lastweek_streams["deaths"].o.total_deaths),
confirmed_new = _validation_individual_new(
"confirmed", :confirmed_cases,
frozen_lastweek_streams["confirmed"].o.confirmed_cases),
confirmed_deaths_new = _validation_individual_new(
"confirmed_deaths", :confirmed_deaths,
frozen_lastweek_streams["confirmed_deaths"].o.confirmed_deaths))
# The frozen individual (treatment-only) fit's own bed-occupancy forecast,
# anchored on the beds occupied at ITS OWN cut-off (the frozen fit's own
# `o`, not the current `obs`), matching how the joint frozen forecast is
# itself anchored.
_validation_iso_obs = let f = frozen_lastweek_streams["treatment"]
isempty(f.o.isolation_history.counts) ? 0.0 :
Float64(f.o.isolation_history.counts[end])
end
validation_individual_isolation = _validation_individual_new(
"treatment", :isolation_beds, _validation_iso_obs)
# The observed beds at the current cut-off (the forecast target), so the
# frozen-fit bed forecast is scored against what the beds actually held.
_obs_beds = isempty(obs.isolation_history.counts) ? missing :
obs.isolation_history.counts[end]
# Same observed/baseline keying as the plot below, so the table covers every
# fitted count stream (cumulative and new-count rows) plus the bed level.
validation_table = forecast_vs_truth(validation_forecast;
observed = (cases_cum = obs.reported_cases,
deaths_cum = obs.total_deaths,
confirmed_cum = obs.confirmed_cases,
confirmed_deaths_cum = obs.confirmed_deaths,
recovered_cum = obs.recovered_cases),
baseline = (cases_cum = frozen_lastweek.o.reported_cases,
deaths_cum = frozen_lastweek.o.total_deaths,
confirmed_cum = frozen_lastweek.o.confirmed_cases,
confirmed_deaths_cum = frozen_lastweek.o.confirmed_deaths,
recovered_cum = frozen_lastweek.o.recovered_cases),
isolation = _obs_beds);Forecast-versus-observed validation table
| Row | Stream | Quantity | Observed | Lower 90% | Lower 60% | Lower 30% | Upper 30% | Upper 60% | Upper 90% | Within 90% PI |
|---|---|---|---|---|---|---|---|---|---|---|
| String | String | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | String | |
| 1 | DRC reported cases | cumulative by T+7 | 1077.0 | 1184.0 | 1466.0 | 1843.0 | 2954.0 | 4136.0 | 7627.0 | no |
| 2 | DRC reported cases | new this week | 0.0 | 107.0 | 389.0 | 766.0 | 1877.0 | 3059.0 | 6550.0 | no |
| 3 | DRC suspected deaths | cumulative by T+7 | 246.0 | 270.0 | 349.0 | 464.0 | 795.0 | 1135.0 | 2136.0 | no |
| 4 | DRC suspected deaths | new this week | 0.0 | 24.0 | 103.0 | 218.0 | 549.0 | 889.0 | 1890.0 | no |
| 5 | DRC confirmed cases | cumulative by T+7 | 4945.0 | 4484.0 | 4652.0 | 4772.0 | 5007.0 | 5209.0 | 5633.0 | yes |
| 6 | DRC confirmed cases | new this week | 651.0 | 190.0 | 358.0 | 478.0 | 713.0 | 915.0 | 1339.0 | yes |
| 7 | DRC confirmed deaths | cumulative by T+7 | 2325.0 | 270.0 | 349.0 | 464.0 | 795.0 | 1135.0 | 2077.0 | no |
| 8 | DRC confirmed deaths | new this week | 365.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 117.0 | no |
| 9 | DRC recovered | cumulative by T+7 | 1040.0 | 849.0 | 869.0 | 908.0 | 1031.0 | 1142.0 | 1546.0 | yes |
| 10 | DRC recovered | new this week | 191.0 | 0.0 | 20.0 | 59.0 | 182.0 | 293.0 | 697.0 | yes |
| 11 | DRC isolation beds | occupancy at T+7 | 730.0 | 627.0 | 709.0 | 765.0 | 862.0 | 918.0 | 963.0 | yes |
The observation panels histogram the one-week-ahead forecast made from the frozen fit: a cumulative and a new-count panel for each fitted count stream the forecast carries (reported cases, suspected deaths, confirmed cases, confirmed deaths and recovered). The 90% predictive interval is shaded, and the count observed by the current cut-off is a dashed black rule. Each stream draws only when the forecast carries its column, so a fit observing fewer streams shows fewer panels. Where a stream has its own individual (single-stream) fit, that fit's forecast from the same frozen cut-off is overlaid as a dotted density alongside the joint's histogram. Recovered has no individual fit and draws the joint alone.
Forecast-versus-observed plot
# Observed cumulative at the target date per stream, keyed by the forecast's
# cumulative column; `baseline` is each stream's origin cumulative (the frozen
# cut-off), so the new-count panel is scored against observed minus origin.
validation_fig = plot_forecast_vs_truth(validation_forecast;
observed = (cases_cum = obs.reported_cases,
deaths_cum = obs.total_deaths,
confirmed_cum = obs.confirmed_cases,
confirmed_deaths_cum = obs.confirmed_deaths,
recovered_cum = obs.recovered_cases),
baseline = (cases_cum = frozen_lastweek.o.reported_cases,
deaths_cum = frozen_lastweek.o.total_deaths,
confirmed_cum = frozen_lastweek.o.confirmed_cases,
confirmed_deaths_cum = frozen_lastweek.o.confirmed_deaths,
recovered_cum = frozen_lastweek.o.recovered_cases),
individual = validation_individual);The bed panel scores last week's projected occupancy against the beds occupied now (the dashed rule), with the individual (treatment-only) fit's own projection overlaid as a dotted density alongside the joint.
Bed forecast-versus-observed plot
validation_beds_fig = plot_forecast_beds_vs_truth(validation_forecast;
isolation = _obs_beds, individual = validation_individual_isolation);The latent quantities are not observed, so they are scored distribution against distribution: what the frozen fit forecast for the past week's new infections, onsets and deaths against what the current fit now estimates for the same window.
Forecast-versus-now latent plot
# Current fit's draws of the new latent counts over the past week, the last
# seven days of each cumulative-trajectory deterministic.
function _now_new(chn, key)
mat = chn[key]
trajs = [collect(v) for v in vec(collect(mat))]
return Float64[t[end] - t[max(1, length(t) - 7)] for t in trajs]
end
now_latent = (;
infections_new = _now_new(chn_joint, :cumulative_infections),
onsets_new = _now_new(chn_joint, :cumulative_onsets),
deaths_latent_new = _now_new(chn_joint, :cumulative_expected_deaths))
validation_latent_fig = plot_forecast_vs_truth_latent(
validation_forecast; now = now_latent);Forecast scoring across releases
Every release's saved one- to four-week-ahead forecast is scored against the data observed since, against a persistence baseline and, where one exists, the stream's own individual fit as well as the joint. See forecast scoring against a persistence baseline for how the scores, the relative skill and the baseline are built. Recovered has no individual fit of its own, so its comparison is the baseline against the joint only. Reported cases and suspected deaths stopped being updated by the situation reports partway through the outbreak, and exports' confirmed-detection series is anchored to an earlier cut-off. Exports therefore contributes no scored forecast, and reported cases and suspected deaths each rest on exactly one matched forecast, a single window rather than a settled sample.
Only a minority of the daily releases examined contribute a row to the table below, each a reconstruction of an earlier model version rather than the current fit. The table below is therefore not a verdict on the current fit. One reconstruction is dropped from scoring entirely: its chain forecasts a near-zero median at every horizon and stream, with the upper predictive tail occasionally reaching five- and six-digit values. This is the signature of a chain that failed to sample properly rather than a genuine forecast, so the scoring script flags and excludes it. The releases that carry the current model's own individual-stream forecasts are too recent for their targets to be observed yet. This is why the comparison against each stream's individual fit is still empty. It will populate once those targets resolve. Every row also rests on one to a handful of matched forecasts, shown as its own count rather than rounded away. A ratio here should therefore be read as an early signal rather than a settled result.
The symptom-onset stream is scored on the new reported count each vintage adds rather than on its level, because every vintage rereads the whole figure. Its printed total therefore moves with the scan error as well as with late reporting. It appears only from the release that first carried it. Its intervals are dominated by that scan error rather than by epidemic uncertainty, so read its skill against the baseline rather than its coverage.
Load and summarise the cross-release forecast scores
# scripts/score_releases.jl writes these after the fits. The committed files
# are header-only until a release carries the asset, so the common path
# reads a real file to a zero-row frame; the typed `schema` is the fallback
# for a file that is absent entirely, since CSV.read throws on a missing
# path and would take the whole docs build with it.
function _release_data(name, schema::NamedTuple)
path = joinpath(pkgdir(BVDOutbreakSize), "data", name)
isfile(path) && return CSV.read(path, DataFrame)
return DataFrame([k => T[] for (k, T) in pairs(schema)])
end
forecast_scores_df = _release_data("forecast_scores.csv",
(; release = String, made_date = Date, stream = String, horizon = Int,
target_date = Date, fit = String, crps = Float64,
log_crps = Float64, dispersion = Float64, overprediction = Float64,
underprediction = Float64, coverage_50 = Float64,
coverage_90 = Float64,
bias = Float64, n_samples = Int,
log_rel_to_baseline = Float64))
forecast_overlay_df = _release_data("forecast_overlay.csv",
(; release = String, made_date = Date, stream = String, horizon = Int,
target_date = Date, fit = String, observed = Float64,
median = Float64, lo30 = Float64, hi30 = Float64, lo60 = Float64,
hi60 = Float64, lo90 = Float64, hi90 = Float64))
# The headline table, one row per (stream, fit) pooled over every horizon
# and release; the by-horizon and by-release detail tables carry the same
# columns at a finer grain (see src/scoring.jl).
forecast_score_overview_table = forecast_score_overview(forecast_scores_df)
forecast_score_by_horizon_table = forecast_score_by_horizon(forecast_scores_df)
forecast_score_by_release_table = forecast_score_by_release(forecast_scores_df)| Row | made_date | stream | fit | n | crps | rel_to_baseline | log_crps | log_rel_to_baseline | rel_to_individual | log_rel_to_individual | dispersion | overprediction | underprediction | coverage_50 | coverage_90 | bias |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | String31 | String31 | Int64 | Float64 | Float64 | Float64 | Float64 | Float64? | Float64? | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | 2026-06-07 | confirmed cases | joint | 4 | 826.77 | 5.56 | 0.823 | 3.65 | missing | missing | 765.65 | 61.12 | 0.0 | 1.0 | 1.0 | 0.2 |
| 2 | 2026-06-10 | confirmed cases | joint | 4 | 833.23 | 6.47 | 0.758 | 3.93 | missing | missing | 666.38 | 166.85 | 0.0 | 1.0 | 1.0 | 0.31 |
| 3 | 2026-07-01 | confirmed cases | joint | 4 | 15862.8 | 78.7 | 0.583 | 2.91 | missing | missing | 15377.3 | 485.47 | 0.0 | 0.0 | 1.0 | 0.66 |
| 4 | 2026-07-06 | confirmed cases | joint | 4 | 421.28 | 1.4 | 0.269 | 1.01 | missing | missing | 311.85 | 109.43 | 0.0 | 0.5 | 1.0 | 0.49 |
| 5 | 2026-07-08 | confirmed cases | joint | 4 | 390.98 | 1.3 | 0.253 | 1.0 | missing | missing | 239.5 | 151.47 | 0.0 | 0.25 | 1.0 | 0.52 |
| 6 | 2026-07-23 | confirmed cases | confirmed | 3 | 219.98 | 1.0 | 0.193 | 1.07 | missing | missing | 214.98 | 0.27 | 4.73 | 1.0 | 1.0 | -0.08 |
| 7 | 2026-07-23 | confirmed cases | joint | 3 | 220.52 | 1.0 | 0.157 | 0.87 | 1.0 | 0.81 | 201.53 | 18.16 | 0.83 | 1.0 | 1.0 | 0.09 |
| 8 | 2026-07-25 | confirmed cases | confirmed | 3 | 252.73 | 2.11 | 0.21 | 2.13 | missing | missing | 251.36 | 1.3 | 0.07 | 1.0 | 1.0 | 0.02 |
| 9 | 2026-07-25 | confirmed cases | joint | 3 | 145.56 | 1.21 | 0.125 | 1.27 | 0.58 | 0.6 | 144.48 | 1.08 | 0.0 | 1.0 | 1.0 | 0.04 |
| 10 | 2026-07-26 | confirmed cases | confirmed | 2 | 146.77 | 3.3 | 0.206 | 3.61 | missing | missing | 131.93 | 0.0 | 14.84 | 1.0 | 1.0 | -0.22 |
| 11 | 2026-07-26 | confirmed cases | joint | 2 | 108.22 | 2.43 | 0.127 | 2.23 | 0.74 | 0.62 | 106.17 | 1.34 | 0.71 | 1.0 | 1.0 | 0.05 |
| 12 | 2026-07-27 | confirmed cases | confirmed | 2 | 135.07 | 2.58 | 0.161 | 2.23 | missing | missing | 134.26 | 0.74 | 0.08 | 1.0 | 1.0 | 0.02 |
| 13 | 2026-07-27 | confirmed cases | joint | 2 | 114.16 | 2.18 | 0.127 | 1.76 | 0.85 | 0.79 | 109.85 | 4.32 | 0.0 | 1.0 | 1.0 | 0.12 |
| 14 | 2026-07-31 | confirmed cases | confirmed | 2 | 189.02 | 3.98 | 0.206 | 3.37 | missing | missing | 186.09 | 2.93 | 0.0 | 1.0 | 1.0 | 0.05 |
| 15 | 2026-07-31 | confirmed cases | joint | 2 | 116.19 | 2.45 | 0.137 | 2.25 | 0.61 | 0.67 | 110.61 | 5.29 | 0.3 | 1.0 | 1.0 | 0.06 |
| 16 | 2026-08-01 | confirmed cases | confirmed | 2 | 159.75 | 3.42 | 0.19 | 3.31 | missing | missing | 159.3 | 0.45 | 0.0 | 1.0 | 1.0 | 0.03 |
| 17 | 2026-08-01 | confirmed cases | joint | 2 | 110.01 | 2.36 | 0.123 | 2.14 | 0.69 | 0.65 | 107.91 | 1.89 | 0.22 | 1.0 | 1.0 | 0.05 |
| 18 | 2026-08-02 | confirmed cases | confirmed | 1 | 91.77 | 2.59 | 0.163 | 2.48 | missing | missing | 89.22 | 0.0 | 2.55 | 1.0 | 1.0 | -0.11 |
| 19 | 2026-08-02 | confirmed cases | joint | 1 | 78.02 | 2.2 | 0.124 | 1.89 | 0.85 | 0.76 | 70.88 | 7.14 | 0.0 | 1.0 | 1.0 | 0.23 |
| 20 | 2026-08-03 | confirmed cases | confirmed | 1 | 88.1 | 1.17 | 0.164 | 1.06 | missing | missing | 87.14 | 0.0 | 0.96 | 1.0 | 1.0 | -0.06 |
| 21 | 2026-08-03 | confirmed cases | joint | 1 | 70.42 | 0.93 | 0.12 | 0.78 | 0.8 | 0.73 | 69.36 | 1.06 | 0.0 | 1.0 | 1.0 | 0.08 |
| 22 | 2026-08-04 | confirmed cases | confirmed | 1 | 94.85 | 2.93 | 0.167 | 3.08 | missing | missing | 94.7 | 0.0 | 0.15 | 1.0 | 1.0 | -0.02 |
| 23 | 2026-08-04 | confirmed cases | joint | 1 | 69.68 | 2.15 | 0.116 | 2.15 | 0.73 | 0.7 | 68.48 | 1.2 | 0.0 | 1.0 | 1.0 | 0.07 |
| 24 | 2026-08-07 | confirmed cases | confirmed | 1 | 103.83 | 1.56 | 0.193 | 1.6 | missing | missing | 91.73 | 0.0 | 12.1 | 1.0 | 1.0 | -0.21 |
| 25 | 2026-08-07 | confirmed cases | joint | 1 | 73.82 | 1.11 | 0.131 | 1.09 | 0.71 | 0.68 | 67.8 | 0.0 | 6.02 | 1.0 | 1.0 | -0.18 |
| 26 | 2026-06-07 | confirmed deaths | joint | 4 | 120.57 | 0.99 | 0.725 | 1.09 | missing | missing | 117.8 | 0.0 | 2.76 | 1.0 | 1.0 | -0.11 |
| 27 | 2026-06-10 | confirmed deaths | joint | 4 | 144.92 | 1.12 | 0.598 | 1.09 | missing | missing | 140.54 | 3.76 | 0.62 | 1.0 | 1.0 | 0.02 |
| 28 | 2026-07-01 | confirmed deaths | joint | 4 | 17196.0 | 79.91 | 0.549 | 1.21 | missing | missing | 17103.1 | 92.89 | 0.0 | 1.0 | 1.0 | 0.28 |
| 29 | 2026-07-06 | confirmed deaths | joint | 4 | 197.2 | 0.89 | 0.871 | 2.3 | missing | missing | 110.35 | 0.0 | 86.85 | 0.25 | 1.0 | -0.49 |
| 30 | 2026-07-08 | confirmed deaths | joint | 4 | 177.59 | 0.79 | 0.713 | 1.86 | missing | missing | 84.29 | 0.0 | 93.3 | 0.25 | 1.0 | -0.61 |
| 31 | 2026-07-23 | confirmed deaths | confirmed_deaths | 3 | 427.71 | 4.69 | 0.391 | 2.79 | missing | missing | 249.45 | 178.26 | 0.0 | 0.33 | 1.0 | 0.53 |
| 32 | 2026-07-23 | confirmed deaths | joint | 3 | 197.53 | 2.17 | 0.493 | 3.52 | 0.46 | 1.26 | 107.62 | 0.0 | 89.91 | 1.0 | 1.0 | -0.48 |
| 33 | 2026-07-25 | confirmed deaths | confirmed_deaths | 3 | 150.09 | 2.45 | 0.221 | 2.17 | missing | missing | 145.49 | 4.61 | 0.0 | 1.0 | 1.0 | 0.12 |
| 34 | 2026-07-25 | confirmed deaths | joint | 3 | 190.39 | 3.11 | 0.513 | 5.03 | 1.27 | 2.32 | 71.5 | 0.0 | 118.9 | 0.0 | 1.0 | -0.58 |
| 35 | 2026-07-26 | confirmed deaths | confirmed_deaths | 2 | 105.51 | 4.9 | 0.222 | 4.14 | missing | missing | 104.48 | 1.04 | 0.0 | 1.0 | 1.0 | 0.06 |
| 36 | 2026-07-26 | confirmed deaths | joint | 2 | 144.07 | 6.69 | 0.53 | 9.87 | 1.37 | 2.38 | 43.58 | 0.0 | 100.49 | 0.0 | 1.0 | -0.68 |
| 37 | 2026-07-27 | confirmed deaths | confirmed_deaths | 2 | 123.88 | 4.82 | 0.226 | 3.32 | missing | missing | 110.53 | 13.35 | 0.0 | 1.0 | 1.0 | 0.19 |
| 38 | 2026-07-27 | confirmed deaths | joint | 2 | 133.97 | 5.21 | 0.523 | 7.68 | 1.08 | 2.31 | 51.31 | 0.0 | 82.66 | 0.0 | 1.0 | -0.62 |
| 39 | 2026-07-31 | confirmed deaths | confirmed_deaths | 2 | 117.92 | 2.9 | 0.25 | 2.76 | missing | missing | 117.21 | 0.57 | 0.14 | 1.0 | 1.0 | 0.01 |
| 40 | 2026-07-31 | confirmed deaths | joint | 2 | 162.86 | 4.01 | 0.562 | 6.21 | 1.38 | 2.25 | 53.22 | 0.0 | 109.64 | 0.0 | 1.0 | -0.65 |
| 41 | 2026-08-01 | confirmed deaths | confirmed_deaths | 2 | 103.76 | 1.91 | 0.211 | 1.67 | missing | missing | 103.76 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 |
| 42 | 2026-08-01 | confirmed deaths | joint | 2 | 195.82 | 3.6 | 0.696 | 5.49 | 1.89 | 3.29 | 43.73 | 0.0 | 152.1 | 0.0 | 1.0 | -0.74 |
| 43 | 2026-08-02 | confirmed deaths | confirmed_deaths | 1 | 70.73 | 2.75 | 0.252 | 2.62 | missing | missing | 69.5 | 0.0 | 1.23 | 1.0 | 1.0 | -0.08 |
| 44 | 2026-08-02 | confirmed deaths | joint | 1 | 96.07 | 3.74 | 0.496 | 5.15 | 1.36 | 1.97 | 33.23 | 0.0 | 62.84 | 0.0 | 1.0 | -0.66 |
| 45 | 2026-08-03 | confirmed deaths | confirmed_deaths | 1 | 60.78 | 1.13 | 0.231 | 1.1 | missing | missing | 54.93 | 0.0 | 5.85 | 1.0 | 1.0 | -0.2 |
| 46 | 2026-08-03 | confirmed deaths | joint | 1 | 109.99 | 2.04 | 0.613 | 2.92 | 1.81 | 2.65 | 34.89 | 0.0 | 75.1 | 0.0 | 1.0 | -0.59 |
| 47 | 2026-08-04 | confirmed deaths | confirmed_deaths | 1 | 68.66 | 4.09 | 0.27 | 5.07 | missing | missing | 60.32 | 0.0 | 8.34 | 1.0 | 1.0 | -0.24 |
| 48 | 2026-08-04 | confirmed deaths | joint | 1 | 132.46 | 7.89 | 0.687 | 12.89 | 1.93 | 2.54 | 28.47 | 0.0 | 103.99 | 0.0 | 1.0 | -0.74 |
| 49 | 2026-08-07 | confirmed deaths | confirmed_deaths | 1 | 84.53 | 2.39 | 0.356 | 3.14 | missing | missing | 66.14 | 0.0 | 18.39 | 1.0 | 1.0 | -0.34 |
| 50 | 2026-08-07 | confirmed deaths | joint | 1 | 192.36 | 5.43 | 1.001 | 8.8 | 2.28 | 2.81 | 23.4 | 0.0 | 168.96 | 0.0 | 0.0 | -0.92 |
| 51 | 2026-07-01 | isolation beds | joint | 4 | 90.19 | 1.49 | 0.138 | 1.52 | missing | missing | 13.48 | 0.0 | 76.71 | 0.0 | 0.0 | -0.99 |
| 52 | 2026-07-06 | isolation beds | joint | 4 | 42.87 | 0.63 | 0.066 | 0.64 | missing | missing | 21.07 | 0.0 | 21.8 | 0.0 | 1.0 | -0.64 |
| 53 | 2026-07-08 | isolation beds | joint | 4 | 54.75 | 1.44 | 0.073 | 1.44 | missing | missing | 11.67 | 43.08 | 0.0 | 0.0 | 1.0 | 0.8 |
| 54 | 2026-07-23 | isolation beds | joint | 3 | 77.11 | 2.8 | 0.097 | 2.66 | 1.25 | 0.96 | 27.21 | 49.9 | 0.0 | 0.0 | 1.0 | 0.6 |
| 55 | 2026-07-23 | isolation beds | treatment | 3 | 61.65 | 2.24 | 0.101 | 2.76 | missing | missing | 51.16 | 0.0 | 10.49 | 1.0 | 1.0 | -0.27 |
| 56 | 2026-07-25 | isolation beds | joint | 3 | 88.4 | 2.08 | 0.113 | 2.01 | 1.81 | 1.41 | 28.7 | 59.69 | 0.0 | 0.33 | 1.0 | 0.61 |
| 57 | 2026-07-25 | isolation beds | treatment | 3 | 48.78 | 1.15 | 0.08 | 1.42 | missing | missing | 48.52 | 0.01 | 0.25 | 1.0 | 1.0 | -0.02 |
| 58 | 2026-07-26 | isolation beds | joint | 2 | 85.22 | 3.78 | 0.11 | 3.52 | 1.46 | 1.07 | 29.67 | 55.55 | 0.0 | 0.0 | 1.0 | 0.62 |
| 59 | 2026-07-26 | isolation beds | treatment | 2 | 58.45 | 2.59 | 0.102 | 3.29 | missing | missing | 57.7 | 0.46 | 0.29 | 1.0 | 1.0 | 0.01 |
| 60 | 2026-07-27 | isolation beds | joint | 2 | 76.07 | 3.79 | 0.097 | 3.49 | 1.22 | 0.88 | 33.44 | 42.62 | 0.0 | 0.0 | 1.0 | 0.55 |
| 61 | 2026-07-27 | isolation beds | treatment | 2 | 62.4 | 3.11 | 0.11 | 3.95 | missing | missing | 61.76 | 0.0 | 0.64 | 1.0 | 1.0 | -0.07 |
| 62 | 2026-07-31 | isolation beds | joint | 2 | 68.16 | 2.81 | 0.084 | 2.58 | 0.89 | 0.63 | 41.77 | 26.4 | 0.0 | 0.5 | 1.0 | 0.46 |
| 63 | 2026-07-31 | isolation beds | treatment | 2 | 76.85 | 3.17 | 0.133 | 4.08 | missing | missing | 72.5 | 0.0 | 4.35 | 1.0 | 1.0 | -0.16 |
| 64 | 2026-08-01 | isolation beds | joint | 2 | 59.18 | 2.17 | 0.075 | 1.89 | 0.77 | 0.52 | 45.02 | 14.16 | 0.0 | 1.0 | 1.0 | 0.33 |
| 65 | 2026-08-01 | isolation beds | treatment | 2 | 76.79 | 2.82 | 0.143 | 3.62 | missing | missing | 76.69 | 0.0 | 0.1 | 1.0 | 1.0 | -0.02 |
| 66 | 2026-08-02 | isolation beds | joint | 1 | 74.44 | 3.75 | 0.095 | 3.43 | 0.99 | 0.7 | 38.35 | 36.09 | 0.0 | 0.0 | 1.0 | 0.6 |
| 67 | 2026-08-02 | isolation beds | treatment | 1 | 75.18 | 3.78 | 0.136 | 4.91 | missing | missing | 74.35 | 0.0 | 0.83 | 1.0 | 1.0 | -0.05 |
| 68 | 2026-08-03 | isolation beds | joint | 1 | 54.95 | 2.77 | 0.07 | 2.57 | 0.73 | 0.53 | 36.92 | 18.03 | 0.0 | 1.0 | 1.0 | 0.41 |
| 69 | 2026-08-03 | isolation beds | treatment | 1 | 74.86 | 3.77 | 0.133 | 4.87 | missing | missing | 74.86 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 |
| 70 | 2026-08-04 | isolation beds | joint | 1 | 142.95 | 2.23 | 0.213 | 2.06 | 1.5 | 1.25 | 33.51 | 109.44 | 0.0 | 0.0 | 1.0 | 0.88 |
| 71 | 2026-08-04 | isolation beds | treatment | 1 | 95.26 | 1.49 | 0.17 | 1.65 | missing | missing | 90.62 | 4.64 | 0.0 | 1.0 | 1.0 | 0.12 |
| 72 | 2026-08-07 | isolation beds | joint | 1 | 41.49 | 1.3 | 0.056 | 1.3 | 0.48 | 0.38 | 35.7 | 0.0 | 5.79 | 1.0 | 1.0 | -0.25 |
| 73 | 2026-08-07 | isolation beds | treatment | 1 | 87.19 | 2.72 | 0.146 | 3.38 | missing | missing | 77.66 | 0.0 | 9.53 | 1.0 | 1.0 | -0.26 |
| 74 | 2026-08-02 | onset reports | joint | 1 | 52.82 | 0.11 | 0.14 | 0.02 | 0.65 | 0.49 | 43.98 | 0.0 | 8.84 | 1.0 | 1.0 | -0.29 |
| 75 | 2026-08-02 | onset reports | onsets | 1 | 81.88 | 0.18 | 0.283 | 0.05 | missing | missing | 63.32 | 0.0 | 18.56 | 1.0 | 1.0 | -0.28 |
| 76 | 2026-08-03 | onset reports | joint | 1 | 175.69 | 1.43 | 0.768 | 0.16 | 1.21 | 1.15 | 47.9 | 127.79 | 0.0 | 0.0 | 1.0 | 0.85 |
| 77 | 2026-08-03 | onset reports | onsets | 1 | 145.59 | 1.18 | 0.667 | 0.14 | missing | missing | 64.42 | 81.17 | 0.0 | 0.0 | 1.0 | 0.64 |
| 78 | 2026-08-04 | onset reports | joint | 1 | 167.42 | 2.04 | 0.94 | 0.21 | 1.41 | 1.26 | 52.38 | 115.04 | 0.0 | 0.0 | 1.0 | 0.86 |
| 79 | 2026-08-04 | onset reports | onsets | 1 | 118.93 | 1.45 | 0.747 | 0.17 | missing | missing | 70.02 | 48.91 | 0.0 | 0.0 | 1.0 | 0.51 |
| 80 | 2026-08-07 | onset reports | joint | 1 | 114.51 | 0.23 | 0.338 | 0.05 | 0.75 | 0.48 | 45.52 | 0.0 | 68.99 | 0.0 | 1.0 | -0.65 |
| 81 | 2026-08-07 | onset reports | onsets | 1 | 153.64 | 0.31 | 0.702 | 0.11 | missing | missing | 61.66 | 0.0 | 91.98 | 0.0 | 1.0 | -0.61 |
| 82 | 2026-07-01 | recovered | joint | 4 | 10457.7 | 153.44 | 0.539 | 1.87 | missing | missing | 10409.1 | 48.57 | 0.0 | 1.0 | 1.0 | 0.29 |
| 83 | 2026-07-06 | recovered | joint | 4 | 85.76 | 0.85 | 0.407 | 0.92 | missing | missing | 68.39 | 0.0 | 17.37 | 1.0 | 1.0 | -0.33 |
| 84 | 2026-07-08 | recovered | joint | 4 | 63.08 | 0.8 | 0.292 | 1.07 | missing | missing | 44.51 | 0.0 | 18.57 | 1.0 | 1.0 | -0.38 |
| 85 | 2026-05-18 | reported cases | joint | 1 | 231.14 | 0.48 | 1.87 | 0.3 | missing | missing | 61.15 | 0.0 | 169.99 | 0.0 | 1.0 | -0.66 |
| 86 | 2026-05-18 | suspected deaths | joint | 1 | 41.59 | 0.39 | 0.577 | 0.12 | missing | missing | 41.12 | 0.0 | 0.47 | 1.0 | 1.0 | -0.08 |
The headline pools every horizon and release into one row per stream and fit: the mean CRPS and its decomposition, coverage, bias, and the relative skill against the persistence baseline for every fit, on both the natural and the log scale. The joint row also carries relative skill against the stream's own individual fit where one exists. Column definitions are in forecast scoring against a persistence baseline.
| Row | stream | fit | n | crps | rel_to_baseline | log_crps | log_rel_to_baseline | rel_to_individual | log_rel_to_individual | dispersion | overprediction | underprediction | coverage_50 | coverage_90 | bias |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| String31 | String31 | Int64 | Float64 | Float64 | Float64 | Float64 | Float64? | Float64? | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | confirmed cases | confirmed | 18 | 169.88 | 1.9 | 0.19 | 1.98 | missing | missing | 165.83 | 0.72 | 3.33 | 1.0 | 1.0 | -0.05 |
| 2 | confirmed cases | joint | 38 | 1990.2 | 12.74 | 0.345 | 2.09 | 0.75 | 0.69 | 1884.9 | 105.0 | 0.29 | 0.76 | 1.0 | 0.26 |
| 3 | confirmed deaths | confirmed_deaths | 18 | 162.24 | 3.34 | 0.265 | 2.54 | missing | missing | 128.2 | 32.14 | 1.89 | 0.89 | 1.0 | 0.09 |
| 4 | confirmed deaths | joint | 38 | 1955.61 | 16.4 | 0.639 | 2.09 | 1.02 | 2.19 | 1875.4 | 10.17 | 70.03 | 0.45 | 0.97 | -0.4 |
| 5 | isolation beds | joint | 30 | 71.3 | 1.78 | 0.097 | 1.69 | 1.14 | 0.85 | 26.56 | 31.4 | 13.33 | 0.2 | 0.87 | 0.19 |
| 6 | isolation beds | treatment | 18 | 67.37 | 2.27 | 0.117 | 2.84 | missing | missing | 64.1 | 0.31 | 2.96 | 1.0 | 1.0 | -0.09 |
| 7 | onset reports | joint | 4 | 127.61 | 0.44 | 0.546 | 0.1 | 1.02 | 0.91 | 47.44 | 60.71 | 19.46 | 0.25 | 1.0 | 0.19 |
| 8 | onset reports | onsets | 4 | 125.01 | 0.43 | 0.599 | 0.11 | missing | missing | 64.85 | 32.52 | 27.64 | 0.25 | 1.0 | 0.06 |
| 9 | recovered | joint | 12 | 3535.5 | 42.87 | 0.413 | 1.23 | missing | missing | 3507.33 | 16.19 | 11.98 | 1.0 | 1.0 | -0.14 |
| 10 | reported cases | joint | 1 | 231.14 | 0.48 | 1.87 | 0.3 | missing | missing | 61.15 | 0.0 | 169.99 | 0.0 | 1.0 | -0.66 |
| 11 | suspected deaths | joint | 1 | 41.59 | 0.39 | 0.577 | 0.12 | missing | missing | 41.12 | 0.0 | 0.47 | 1.0 | 1.0 | -0.08 |
The same relative skill against the baseline, by horizon: one panel per stream, one series per fit role, on a log-scaled skill axis with the reference line at one. A fit that beats the baseline on average but not at every cut-off is visible as a series that crosses the line rather than sitting under it throughout.
forecast_relative_skill_fig = plot_forecast_relative_skill(
forecast_score_by_horizon_table);The same columns as a table, broken out by horizon, and again broken out by release and averaged across horizons, are behind the two dropdowns below.
Scores by horizon
| Row | stream | horizon | fit | n | crps | rel_to_baseline | log_crps | log_rel_to_baseline | rel_to_individual | log_rel_to_individual | dispersion | overprediction | underprediction | coverage_50 | coverage_90 | bias |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| String31 | Int64 | String31 | Int64 | Float64 | Float64 | Float64 | Float64 | Float64? | Float64? | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | confirmed cases | 7 | confirmed | 10 | 97.9 | 2.17 | 0.184 | 2.25 | missing | missing | 93.74 | 0.02 | 4.14 | 1.0 | 1.0 | -0.09 |
| 2 | confirmed cases | 7 | joint | 15 | 114.18 | 2.77 | 0.283 | 3.03 | 0.76 | 0.69 | 93.62 | 19.99 | 0.57 | 0.8 | 1.0 | 0.2 |
| 3 | confirmed cases | 14 | confirmed | 6 | 217.51 | 2.87 | 0.194 | 2.65 | missing | missing | 212.43 | 1.98 | 3.1 | 1.0 | 1.0 | 0.01 |
| 4 | confirmed cases | 14 | joint | 11 | 273.69 | 3.65 | 0.306 | 3.26 | 0.72 | 0.69 | 217.06 | 56.41 | 0.22 | 0.82 | 1.0 | 0.21 |
| 5 | confirmed cases | 21 | confirmed | 2 | 386.92 | 1.1 | 0.211 | 0.9 | missing | missing | 386.49 | 0.4 | 0.03 | 1.0 | 1.0 | 0.02 |
| 6 | confirmed cases | 21 | joint | 7 | 792.03 | 2.91 | 0.403 | 1.65 | 0.78 | 0.71 | 620.07 | 171.96 | 0.0 | 0.71 | 1.0 | 0.34 |
| 7 | confirmed cases | 28 | joint | 5 | 13072.0 | 25.22 | 0.537 | 1.26 | missing | missing | 12698.8 | 373.21 | 0.0 | 0.6 | 1.0 | 0.46 |
| 8 | confirmed deaths | 7 | confirmed_deaths | 10 | 70.36 | 2.55 | 0.244 | 2.47 | missing | missing | 63.68 | 3.27 | 3.41 | 1.0 | 1.0 | -0.03 |
| 9 | confirmed deaths | 7 | joint | 15 | 94.72 | 3.99 | 0.737 | 6.26 | 1.55 | 2.48 | 34.33 | 0.38 | 60.01 | 0.27 | 0.93 | -0.55 |
| 10 | confirmed deaths | 14 | confirmed_deaths | 6 | 192.89 | 4.38 | 0.264 | 3.38 | missing | missing | 165.43 | 27.46 | 0.0 | 0.83 | 1.0 | 0.18 |
| 11 | confirmed deaths | 14 | joint | 11 | 181.9 | 3.07 | 0.594 | 3.38 | 1.07 | 2.1 | 89.15 | 3.17 | 89.59 | 0.36 | 1.0 | -0.43 |
| 12 | confirmed deaths | 21 | confirmed_deaths | 2 | 529.65 | 3.18 | 0.37 | 1.76 | missing | missing | 339.13 | 190.52 | 0.0 | 0.5 | 1.0 | 0.41 |
| 13 | confirmed deaths | 21 | joint | 7 | 400.27 | 1.91 | 0.55 | 1.11 | 0.6 | 1.43 | 308.58 | 15.59 | 76.1 | 0.57 | 1.0 | -0.25 |
| 14 | confirmed deaths | 28 | joint | 5 | 13617.9 | 33.09 | 0.566 | 0.64 | missing | missing | 13521.9 | 47.4 | 48.58 | 1.0 | 1.0 | -0.09 |
| 15 | isolation beds | 7 | joint | 13 | 72.62 | 1.93 | 0.097 | 1.82 | 0.99 | 0.74 | 27.18 | 34.69 | 10.75 | 0.23 | 0.92 | 0.32 |
| 16 | isolation beds | 7 | treatment | 10 | 74.47 | 2.53 | 0.132 | 3.15 | missing | missing | 70.46 | 0.47 | 3.55 | 1.0 | 1.0 | -0.08 |
| 17 | isolation beds | 14 | joint | 9 | 73.77 | 2.09 | 0.096 | 1.93 | 1.3 | 0.95 | 29.28 | 34.88 | 9.62 | 0.22 | 0.89 | 0.25 |
| 18 | isolation beds | 14 | treatment | 6 | 63.54 | 2.27 | 0.11 | 2.86 | missing | missing | 61.41 | 0.15 | 1.98 | 1.0 | 1.0 | -0.08 |
| 19 | isolation beds | 21 | joint | 5 | 63.95 | 1.38 | 0.088 | 1.33 | 1.79 | 1.51 | 23.26 | 23.94 | 16.75 | 0.2 | 0.8 | 0.02 |
| 20 | isolation beds | 21 | treatment | 2 | 43.39 | 1.21 | 0.065 | 1.38 | missing | missing | 40.38 | 0.0 | 3.0 | 1.0 | 1.0 | -0.1 |
| 21 | isolation beds | 28 | joint | 3 | 70.36 | 1.28 | 0.111 | 1.37 | missing | missing | 21.24 | 19.19 | 29.92 | 0.0 | 0.67 | -0.25 |
| 22 | onset reports | 7 | joint | 4 | 127.61 | 0.44 | 0.546 | 0.1 | 1.02 | 0.91 | 47.44 | 60.71 | 19.46 | 0.25 | 1.0 | 0.19 |
| 23 | onset reports | 7 | onsets | 4 | 125.01 | 0.43 | 0.599 | 0.11 | missing | missing | 64.85 | 32.52 | 27.64 | 0.25 | 1.0 | 0.06 |
| 24 | recovered | 7 | joint | 3 | 26.96 | 2.13 | 0.319 | 1.72 | missing | missing | 20.93 | 1.28 | 4.76 | 1.0 | 1.0 | -0.18 |
| 25 | recovered | 14 | joint | 3 | 89.7 | 2.14 | 0.393 | 1.56 | missing | missing | 68.01 | 5.81 | 15.87 | 1.0 | 1.0 | -0.23 |
| 26 | recovered | 21 | joint | 3 | 297.16 | 3.47 | 0.422 | 1.23 | missing | missing | 269.9 | 16.05 | 11.2 | 1.0 | 1.0 | -0.09 |
| 27 | recovered | 28 | joint | 3 | 13728.2 | 72.35 | 0.517 | 0.92 | missing | missing | 13670.5 | 41.62 | 16.09 | 1.0 | 1.0 | -0.06 |
| 28 | reported cases | 7 | joint | 1 | 231.14 | 0.48 | 1.87 | 0.3 | missing | missing | 61.15 | 0.0 | 169.99 | 0.0 | 1.0 | -0.66 |
| 29 | suspected deaths | 7 | joint | 1 | 41.59 | 0.39 | 0.577 | 0.12 | missing | missing | 41.12 | 0.0 | 0.47 | 1.0 | 1.0 | -0.08 |
Scores by release
| Row | made_date | stream | fit | n | crps | rel_to_baseline | log_crps | log_rel_to_baseline | rel_to_individual | log_rel_to_individual | dispersion | overprediction | underprediction | coverage_50 | coverage_90 | bias |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | String31 | String31 | Int64 | Float64 | Float64 | Float64 | Float64 | Float64? | Float64? | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | 2026-06-07 | confirmed cases | joint | 4 | 826.77 | 5.56 | 0.823 | 3.65 | missing | missing | 765.65 | 61.12 | 0.0 | 1.0 | 1.0 | 0.2 |
| 2 | 2026-06-10 | confirmed cases | joint | 4 | 833.23 | 6.47 | 0.758 | 3.93 | missing | missing | 666.38 | 166.85 | 0.0 | 1.0 | 1.0 | 0.31 |
| 3 | 2026-07-01 | confirmed cases | joint | 4 | 15862.8 | 78.7 | 0.583 | 2.91 | missing | missing | 15377.3 | 485.47 | 0.0 | 0.0 | 1.0 | 0.66 |
| 4 | 2026-07-06 | confirmed cases | joint | 4 | 421.28 | 1.4 | 0.269 | 1.01 | missing | missing | 311.85 | 109.43 | 0.0 | 0.5 | 1.0 | 0.49 |
| 5 | 2026-07-08 | confirmed cases | joint | 4 | 390.98 | 1.3 | 0.253 | 1.0 | missing | missing | 239.5 | 151.47 | 0.0 | 0.25 | 1.0 | 0.52 |
| 6 | 2026-07-23 | confirmed cases | confirmed | 3 | 219.98 | 1.0 | 0.193 | 1.07 | missing | missing | 214.98 | 0.27 | 4.73 | 1.0 | 1.0 | -0.08 |
| 7 | 2026-07-23 | confirmed cases | joint | 3 | 220.52 | 1.0 | 0.157 | 0.87 | 1.0 | 0.81 | 201.53 | 18.16 | 0.83 | 1.0 | 1.0 | 0.09 |
| 8 | 2026-07-25 | confirmed cases | confirmed | 3 | 252.73 | 2.11 | 0.21 | 2.13 | missing | missing | 251.36 | 1.3 | 0.07 | 1.0 | 1.0 | 0.02 |
| 9 | 2026-07-25 | confirmed cases | joint | 3 | 145.56 | 1.21 | 0.125 | 1.27 | 0.58 | 0.6 | 144.48 | 1.08 | 0.0 | 1.0 | 1.0 | 0.04 |
| 10 | 2026-07-26 | confirmed cases | confirmed | 2 | 146.77 | 3.3 | 0.206 | 3.61 | missing | missing | 131.93 | 0.0 | 14.84 | 1.0 | 1.0 | -0.22 |
| 11 | 2026-07-26 | confirmed cases | joint | 2 | 108.22 | 2.43 | 0.127 | 2.23 | 0.74 | 0.62 | 106.17 | 1.34 | 0.71 | 1.0 | 1.0 | 0.05 |
| 12 | 2026-07-27 | confirmed cases | confirmed | 2 | 135.07 | 2.58 | 0.161 | 2.23 | missing | missing | 134.26 | 0.74 | 0.08 | 1.0 | 1.0 | 0.02 |
| 13 | 2026-07-27 | confirmed cases | joint | 2 | 114.16 | 2.18 | 0.127 | 1.76 | 0.85 | 0.79 | 109.85 | 4.32 | 0.0 | 1.0 | 1.0 | 0.12 |
| 14 | 2026-07-31 | confirmed cases | confirmed | 2 | 189.02 | 3.98 | 0.206 | 3.37 | missing | missing | 186.09 | 2.93 | 0.0 | 1.0 | 1.0 | 0.05 |
| 15 | 2026-07-31 | confirmed cases | joint | 2 | 116.19 | 2.45 | 0.137 | 2.25 | 0.61 | 0.67 | 110.61 | 5.29 | 0.3 | 1.0 | 1.0 | 0.06 |
| 16 | 2026-08-01 | confirmed cases | confirmed | 2 | 159.75 | 3.42 | 0.19 | 3.31 | missing | missing | 159.3 | 0.45 | 0.0 | 1.0 | 1.0 | 0.03 |
| 17 | 2026-08-01 | confirmed cases | joint | 2 | 110.01 | 2.36 | 0.123 | 2.14 | 0.69 | 0.65 | 107.91 | 1.89 | 0.22 | 1.0 | 1.0 | 0.05 |
| 18 | 2026-08-02 | confirmed cases | confirmed | 1 | 91.77 | 2.59 | 0.163 | 2.48 | missing | missing | 89.22 | 0.0 | 2.55 | 1.0 | 1.0 | -0.11 |
| 19 | 2026-08-02 | confirmed cases | joint | 1 | 78.02 | 2.2 | 0.124 | 1.89 | 0.85 | 0.76 | 70.88 | 7.14 | 0.0 | 1.0 | 1.0 | 0.23 |
| 20 | 2026-08-03 | confirmed cases | confirmed | 1 | 88.1 | 1.17 | 0.164 | 1.06 | missing | missing | 87.14 | 0.0 | 0.96 | 1.0 | 1.0 | -0.06 |
| 21 | 2026-08-03 | confirmed cases | joint | 1 | 70.42 | 0.93 | 0.12 | 0.78 | 0.8 | 0.73 | 69.36 | 1.06 | 0.0 | 1.0 | 1.0 | 0.08 |
| 22 | 2026-08-04 | confirmed cases | confirmed | 1 | 94.85 | 2.93 | 0.167 | 3.08 | missing | missing | 94.7 | 0.0 | 0.15 | 1.0 | 1.0 | -0.02 |
| 23 | 2026-08-04 | confirmed cases | joint | 1 | 69.68 | 2.15 | 0.116 | 2.15 | 0.73 | 0.7 | 68.48 | 1.2 | 0.0 | 1.0 | 1.0 | 0.07 |
| 24 | 2026-08-07 | confirmed cases | confirmed | 1 | 103.83 | 1.56 | 0.193 | 1.6 | missing | missing | 91.73 | 0.0 | 12.1 | 1.0 | 1.0 | -0.21 |
| 25 | 2026-08-07 | confirmed cases | joint | 1 | 73.82 | 1.11 | 0.131 | 1.09 | 0.71 | 0.68 | 67.8 | 0.0 | 6.02 | 1.0 | 1.0 | -0.18 |
| 26 | 2026-06-07 | confirmed deaths | joint | 4 | 120.57 | 0.99 | 0.725 | 1.09 | missing | missing | 117.8 | 0.0 | 2.76 | 1.0 | 1.0 | -0.11 |
| 27 | 2026-06-10 | confirmed deaths | joint | 4 | 144.92 | 1.12 | 0.598 | 1.09 | missing | missing | 140.54 | 3.76 | 0.62 | 1.0 | 1.0 | 0.02 |
| 28 | 2026-07-01 | confirmed deaths | joint | 4 | 17196.0 | 79.91 | 0.549 | 1.21 | missing | missing | 17103.1 | 92.89 | 0.0 | 1.0 | 1.0 | 0.28 |
| 29 | 2026-07-06 | confirmed deaths | joint | 4 | 197.2 | 0.89 | 0.871 | 2.3 | missing | missing | 110.35 | 0.0 | 86.85 | 0.25 | 1.0 | -0.49 |
| 30 | 2026-07-08 | confirmed deaths | joint | 4 | 177.59 | 0.79 | 0.713 | 1.86 | missing | missing | 84.29 | 0.0 | 93.3 | 0.25 | 1.0 | -0.61 |
| 31 | 2026-07-23 | confirmed deaths | confirmed_deaths | 3 | 427.71 | 4.69 | 0.391 | 2.79 | missing | missing | 249.45 | 178.26 | 0.0 | 0.33 | 1.0 | 0.53 |
| 32 | 2026-07-23 | confirmed deaths | joint | 3 | 197.53 | 2.17 | 0.493 | 3.52 | 0.46 | 1.26 | 107.62 | 0.0 | 89.91 | 1.0 | 1.0 | -0.48 |
| 33 | 2026-07-25 | confirmed deaths | confirmed_deaths | 3 | 150.09 | 2.45 | 0.221 | 2.17 | missing | missing | 145.49 | 4.61 | 0.0 | 1.0 | 1.0 | 0.12 |
| 34 | 2026-07-25 | confirmed deaths | joint | 3 | 190.39 | 3.11 | 0.513 | 5.03 | 1.27 | 2.32 | 71.5 | 0.0 | 118.9 | 0.0 | 1.0 | -0.58 |
| 35 | 2026-07-26 | confirmed deaths | confirmed_deaths | 2 | 105.51 | 4.9 | 0.222 | 4.14 | missing | missing | 104.48 | 1.04 | 0.0 | 1.0 | 1.0 | 0.06 |
| 36 | 2026-07-26 | confirmed deaths | joint | 2 | 144.07 | 6.69 | 0.53 | 9.87 | 1.37 | 2.38 | 43.58 | 0.0 | 100.49 | 0.0 | 1.0 | -0.68 |
| 37 | 2026-07-27 | confirmed deaths | confirmed_deaths | 2 | 123.88 | 4.82 | 0.226 | 3.32 | missing | missing | 110.53 | 13.35 | 0.0 | 1.0 | 1.0 | 0.19 |
| 38 | 2026-07-27 | confirmed deaths | joint | 2 | 133.97 | 5.21 | 0.523 | 7.68 | 1.08 | 2.31 | 51.31 | 0.0 | 82.66 | 0.0 | 1.0 | -0.62 |
| 39 | 2026-07-31 | confirmed deaths | confirmed_deaths | 2 | 117.92 | 2.9 | 0.25 | 2.76 | missing | missing | 117.21 | 0.57 | 0.14 | 1.0 | 1.0 | 0.01 |
| 40 | 2026-07-31 | confirmed deaths | joint | 2 | 162.86 | 4.01 | 0.562 | 6.21 | 1.38 | 2.25 | 53.22 | 0.0 | 109.64 | 0.0 | 1.0 | -0.65 |
| 41 | 2026-08-01 | confirmed deaths | confirmed_deaths | 2 | 103.76 | 1.91 | 0.211 | 1.67 | missing | missing | 103.76 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 |
| 42 | 2026-08-01 | confirmed deaths | joint | 2 | 195.82 | 3.6 | 0.696 | 5.49 | 1.89 | 3.29 | 43.73 | 0.0 | 152.1 | 0.0 | 1.0 | -0.74 |
| 43 | 2026-08-02 | confirmed deaths | confirmed_deaths | 1 | 70.73 | 2.75 | 0.252 | 2.62 | missing | missing | 69.5 | 0.0 | 1.23 | 1.0 | 1.0 | -0.08 |
| 44 | 2026-08-02 | confirmed deaths | joint | 1 | 96.07 | 3.74 | 0.496 | 5.15 | 1.36 | 1.97 | 33.23 | 0.0 | 62.84 | 0.0 | 1.0 | -0.66 |
| 45 | 2026-08-03 | confirmed deaths | confirmed_deaths | 1 | 60.78 | 1.13 | 0.231 | 1.1 | missing | missing | 54.93 | 0.0 | 5.85 | 1.0 | 1.0 | -0.2 |
| 46 | 2026-08-03 | confirmed deaths | joint | 1 | 109.99 | 2.04 | 0.613 | 2.92 | 1.81 | 2.65 | 34.89 | 0.0 | 75.1 | 0.0 | 1.0 | -0.59 |
| 47 | 2026-08-04 | confirmed deaths | confirmed_deaths | 1 | 68.66 | 4.09 | 0.27 | 5.07 | missing | missing | 60.32 | 0.0 | 8.34 | 1.0 | 1.0 | -0.24 |
| 48 | 2026-08-04 | confirmed deaths | joint | 1 | 132.46 | 7.89 | 0.687 | 12.89 | 1.93 | 2.54 | 28.47 | 0.0 | 103.99 | 0.0 | 1.0 | -0.74 |
| 49 | 2026-08-07 | confirmed deaths | confirmed_deaths | 1 | 84.53 | 2.39 | 0.356 | 3.14 | missing | missing | 66.14 | 0.0 | 18.39 | 1.0 | 1.0 | -0.34 |
| 50 | 2026-08-07 | confirmed deaths | joint | 1 | 192.36 | 5.43 | 1.001 | 8.8 | 2.28 | 2.81 | 23.4 | 0.0 | 168.96 | 0.0 | 0.0 | -0.92 |
| 51 | 2026-07-01 | isolation beds | joint | 4 | 90.19 | 1.49 | 0.138 | 1.52 | missing | missing | 13.48 | 0.0 | 76.71 | 0.0 | 0.0 | -0.99 |
| 52 | 2026-07-06 | isolation beds | joint | 4 | 42.87 | 0.63 | 0.066 | 0.64 | missing | missing | 21.07 | 0.0 | 21.8 | 0.0 | 1.0 | -0.64 |
| 53 | 2026-07-08 | isolation beds | joint | 4 | 54.75 | 1.44 | 0.073 | 1.44 | missing | missing | 11.67 | 43.08 | 0.0 | 0.0 | 1.0 | 0.8 |
| 54 | 2026-07-23 | isolation beds | joint | 3 | 77.11 | 2.8 | 0.097 | 2.66 | 1.25 | 0.96 | 27.21 | 49.9 | 0.0 | 0.0 | 1.0 | 0.6 |
| 55 | 2026-07-23 | isolation beds | treatment | 3 | 61.65 | 2.24 | 0.101 | 2.76 | missing | missing | 51.16 | 0.0 | 10.49 | 1.0 | 1.0 | -0.27 |
| 56 | 2026-07-25 | isolation beds | joint | 3 | 88.4 | 2.08 | 0.113 | 2.01 | 1.81 | 1.41 | 28.7 | 59.69 | 0.0 | 0.33 | 1.0 | 0.61 |
| 57 | 2026-07-25 | isolation beds | treatment | 3 | 48.78 | 1.15 | 0.08 | 1.42 | missing | missing | 48.52 | 0.01 | 0.25 | 1.0 | 1.0 | -0.02 |
| 58 | 2026-07-26 | isolation beds | joint | 2 | 85.22 | 3.78 | 0.11 | 3.52 | 1.46 | 1.07 | 29.67 | 55.55 | 0.0 | 0.0 | 1.0 | 0.62 |
| 59 | 2026-07-26 | isolation beds | treatment | 2 | 58.45 | 2.59 | 0.102 | 3.29 | missing | missing | 57.7 | 0.46 | 0.29 | 1.0 | 1.0 | 0.01 |
| 60 | 2026-07-27 | isolation beds | joint | 2 | 76.07 | 3.79 | 0.097 | 3.49 | 1.22 | 0.88 | 33.44 | 42.62 | 0.0 | 0.0 | 1.0 | 0.55 |
| 61 | 2026-07-27 | isolation beds | treatment | 2 | 62.4 | 3.11 | 0.11 | 3.95 | missing | missing | 61.76 | 0.0 | 0.64 | 1.0 | 1.0 | -0.07 |
| 62 | 2026-07-31 | isolation beds | joint | 2 | 68.16 | 2.81 | 0.084 | 2.58 | 0.89 | 0.63 | 41.77 | 26.4 | 0.0 | 0.5 | 1.0 | 0.46 |
| 63 | 2026-07-31 | isolation beds | treatment | 2 | 76.85 | 3.17 | 0.133 | 4.08 | missing | missing | 72.5 | 0.0 | 4.35 | 1.0 | 1.0 | -0.16 |
| 64 | 2026-08-01 | isolation beds | joint | 2 | 59.18 | 2.17 | 0.075 | 1.89 | 0.77 | 0.52 | 45.02 | 14.16 | 0.0 | 1.0 | 1.0 | 0.33 |
| 65 | 2026-08-01 | isolation beds | treatment | 2 | 76.79 | 2.82 | 0.143 | 3.62 | missing | missing | 76.69 | 0.0 | 0.1 | 1.0 | 1.0 | -0.02 |
| 66 | 2026-08-02 | isolation beds | joint | 1 | 74.44 | 3.75 | 0.095 | 3.43 | 0.99 | 0.7 | 38.35 | 36.09 | 0.0 | 0.0 | 1.0 | 0.6 |
| 67 | 2026-08-02 | isolation beds | treatment | 1 | 75.18 | 3.78 | 0.136 | 4.91 | missing | missing | 74.35 | 0.0 | 0.83 | 1.0 | 1.0 | -0.05 |
| 68 | 2026-08-03 | isolation beds | joint | 1 | 54.95 | 2.77 | 0.07 | 2.57 | 0.73 | 0.53 | 36.92 | 18.03 | 0.0 | 1.0 | 1.0 | 0.41 |
| 69 | 2026-08-03 | isolation beds | treatment | 1 | 74.86 | 3.77 | 0.133 | 4.87 | missing | missing | 74.86 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 |
| 70 | 2026-08-04 | isolation beds | joint | 1 | 142.95 | 2.23 | 0.213 | 2.06 | 1.5 | 1.25 | 33.51 | 109.44 | 0.0 | 0.0 | 1.0 | 0.88 |
| 71 | 2026-08-04 | isolation beds | treatment | 1 | 95.26 | 1.49 | 0.17 | 1.65 | missing | missing | 90.62 | 4.64 | 0.0 | 1.0 | 1.0 | 0.12 |
| 72 | 2026-08-07 | isolation beds | joint | 1 | 41.49 | 1.3 | 0.056 | 1.3 | 0.48 | 0.38 | 35.7 | 0.0 | 5.79 | 1.0 | 1.0 | -0.25 |
| 73 | 2026-08-07 | isolation beds | treatment | 1 | 87.19 | 2.72 | 0.146 | 3.38 | missing | missing | 77.66 | 0.0 | 9.53 | 1.0 | 1.0 | -0.26 |
| 74 | 2026-08-02 | onset reports | joint | 1 | 52.82 | 0.11 | 0.14 | 0.02 | 0.65 | 0.49 | 43.98 | 0.0 | 8.84 | 1.0 | 1.0 | -0.29 |
| 75 | 2026-08-02 | onset reports | onsets | 1 | 81.88 | 0.18 | 0.283 | 0.05 | missing | missing | 63.32 | 0.0 | 18.56 | 1.0 | 1.0 | -0.28 |
| 76 | 2026-08-03 | onset reports | joint | 1 | 175.69 | 1.43 | 0.768 | 0.16 | 1.21 | 1.15 | 47.9 | 127.79 | 0.0 | 0.0 | 1.0 | 0.85 |
| 77 | 2026-08-03 | onset reports | onsets | 1 | 145.59 | 1.18 | 0.667 | 0.14 | missing | missing | 64.42 | 81.17 | 0.0 | 0.0 | 1.0 | 0.64 |
| 78 | 2026-08-04 | onset reports | joint | 1 | 167.42 | 2.04 | 0.94 | 0.21 | 1.41 | 1.26 | 52.38 | 115.04 | 0.0 | 0.0 | 1.0 | 0.86 |
| 79 | 2026-08-04 | onset reports | onsets | 1 | 118.93 | 1.45 | 0.747 | 0.17 | missing | missing | 70.02 | 48.91 | 0.0 | 0.0 | 1.0 | 0.51 |
| 80 | 2026-08-07 | onset reports | joint | 1 | 114.51 | 0.23 | 0.338 | 0.05 | 0.75 | 0.48 | 45.52 | 0.0 | 68.99 | 0.0 | 1.0 | -0.65 |
| 81 | 2026-08-07 | onset reports | onsets | 1 | 153.64 | 0.31 | 0.702 | 0.11 | missing | missing | 61.66 | 0.0 | 91.98 | 0.0 | 1.0 | -0.61 |
| 82 | 2026-07-01 | recovered | joint | 4 | 10457.7 | 153.44 | 0.539 | 1.87 | missing | missing | 10409.1 | 48.57 | 0.0 | 1.0 | 1.0 | 0.29 |
| 83 | 2026-07-06 | recovered | joint | 4 | 85.76 | 0.85 | 0.407 | 0.92 | missing | missing | 68.39 | 0.0 | 17.37 | 1.0 | 1.0 | -0.33 |
| 84 | 2026-07-08 | recovered | joint | 4 | 63.08 | 0.8 | 0.292 | 1.07 | missing | missing | 44.51 | 0.0 | 18.57 | 1.0 | 1.0 | -0.38 |
| 85 | 2026-05-18 | reported cases | joint | 1 | 231.14 | 0.48 | 1.87 | 0.3 | missing | missing | 61.15 | 0.0 | 169.99 | 0.0 | 1.0 | -0.66 |
| 86 | 2026-05-18 | suspected deaths | joint | 1 | 41.59 | 0.39 | 0.577 | 0.12 | missing | missing | 41.12 | 0.0 | 0.47 | 1.0 | 1.0 | -0.08 |
Forecasts made at each release against the value observed since, one panel per stream and horizon, the observed value in black. The median and 90% interval are coloured by fit role: the persistence baseline, the stream's individual fit and the joint. The x-axis is the date each forecast was made, so an incident stream's observed window pairs unambiguously with the forecast that made it. Each panel's axis is cropped to a small multiple of what that stream actually reached, so one very wide interval cannot squash every other series flat. An interval or median too wide for the panel is clamped at the top and marked with an open triangle rather than silently cut off.
Forecasts-versus-now overlay
forecast_overlay_fig = plot_forecast_overlay(forecast_overlay_df);Frozen-fit forecast evaluation
The current model, frozen at earlier data cut-offs (see Forecast-versus-frozen evaluation), is scored the same way as the cross-release forecasts above, against the same persistence baseline. Only the joint model is scored here, so no individual single-stream fit appears in the tables and figures below. The May cut-offs predate the first reported bed occupancy and the first reported recoveries, so those windows are left unscored rather than scored against a series that had not started. The baseline carries a weaker data-vintage guarantee than the cross-release one, since its snapshot was taken weeks after the frozen cut-off and can hold later revisions to earlier days (see forecast scoring against a persistence baseline).
Load and summarise the frozen-fit forecast scores
frozen_scores_df = _release_data("forecast_scores_frozen.csv",
(; release = String, made_date = Date, stream = String, horizon = Int,
target_date = Date, fit = String, crps = Float64,
log_crps = Float64, dispersion = Float64, overprediction = Float64,
underprediction = Float64, coverage_50 = Float64,
coverage_90 = Float64,
bias = Float64, n_samples = Int,
log_rel_to_baseline = Float64))
frozen_overlay_df = _release_data("forecast_overlay_frozen.csv",
(; release = String, made_date = Date, stream = String, horizon = Int,
target_date = Date, fit = String, observed = Float64,
median = Float64, lo30 = Float64, hi30 = Float64, lo60 = Float64,
hi60 = Float64, lo90 = Float64, hi90 = Float64))
# The frozen evaluation never carries an individual single-stream fit
# (it scores only the joint model at past cut-offs), so the individual-fit
# comparison columns are dropped rather than shown as a column of missing.
frozen_score_overview_table = drop_individual_fit_columns(
forecast_score_overview(frozen_scores_df))
frozen_score_by_horizon_table = drop_individual_fit_columns(
forecast_score_by_horizon(frozen_scores_df))
frozen_score_by_release_table = drop_individual_fit_columns(
forecast_score_by_release(frozen_scores_df))
# `fit` is single-valued (`FROZEN_FIT`) by construction in every one of
# these tables, not just for the releases scored so far, so it is dropped
# from the display tables below as a degenerate column. The `..._table`
# frames above keep it and still feed the relative-skill plots, which read
# it to colour each series in the joint role.
frozen_score_overview_display = drop_degenerate_fit_column(
frozen_score_overview_table)
frozen_score_by_horizon_display = drop_degenerate_fit_column(
frozen_score_by_horizon_table)
frozen_score_by_release_display = drop_degenerate_fit_column(
frozen_score_by_release_table)| Row | made_date | stream | n | crps | rel_to_baseline | log_crps | log_rel_to_baseline | dispersion | overprediction | underprediction | coverage_50 | coverage_90 | bias |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | String31 | Int64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | 2026-05-20 | confirmed cases | 44 | 277.41 | 0.76 | 0.372 | 0.25 | 225.49 | 51.92 | 0.0 | 0.75 | 1.0 | 0.42 |
| 2 | 2026-05-23 | confirmed cases | 44 | 184.4 | 0.45 | 0.219 | 0.16 | 156.1 | 27.59 | 0.71 | 1.0 | 1.0 | 0.09 |
| 3 | 2026-05-27 | confirmed cases | 44 | 299.87 | 0.58 | 0.869 | 0.57 | 51.6 | 0.0 | 248.27 | 0.0 | 0.75 | -0.83 |
| 4 | 2026-06-08 | confirmed cases | 44 | 628.9 | 4.43 | 0.435 | 2.16 | 339.44 | 289.46 | 0.0 | 0.36 | 1.0 | 0.6 |
| 5 | 2026-07-16 | confirmed cases | 4 | 294.68 | 0.48 | 0.168 | 0.31 | 283.46 | 10.98 | 0.24 | 1.0 | 1.0 | 0.07 |
| 6 | 2026-07-18 | confirmed cases | 4 | 361.26 | 0.83 | 0.185 | 0.55 | 333.85 | 27.41 | 0.0 | 1.0 | 1.0 | 0.15 |
| 7 | 2026-07-19 | confirmed cases | 3 | 299.44 | 1.29 | 0.193 | 0.89 | 244.89 | 54.55 | 0.0 | 1.0 | 1.0 | 0.28 |
| 8 | 2026-07-20 | confirmed cases | 3 | 246.3 | 0.89 | 0.167 | 0.64 | 211.22 | 35.08 | 0.0 | 1.0 | 1.0 | 0.2 |
| 9 | 2026-07-24 | confirmed cases | 3 | 280.44 | 1.59 | 0.174 | 1.18 | 224.76 | 55.68 | 0.0 | 1.0 | 1.0 | 0.31 |
| 10 | 2026-07-25 | confirmed cases | 3 | 290.57 | 2.5 | 0.188 | 1.96 | 228.5 | 62.07 | 0.0 | 1.0 | 1.0 | 0.33 |
| 11 | 2026-07-26 | confirmed cases | 2 | 146.91 | 3.09 | 0.146 | 2.42 | 130.2 | 16.71 | 0.0 | 1.0 | 1.0 | 0.24 |
| 12 | 2026-07-27 | confirmed cases | 2 | 155.94 | 2.72 | 0.16 | 2.03 | 140.24 | 15.7 | 0.0 | 1.0 | 1.0 | 0.26 |
| 13 | 2026-07-28 | confirmed cases | 2 | 145.08 | 1.75 | 0.139 | 1.47 | 132.78 | 12.3 | 0.0 | 1.0 | 1.0 | 0.19 |
| 14 | 2026-07-31 | confirmed cases | 2 | 171.13 | 3.56 | 0.167 | 2.73 | 142.53 | 28.6 | 0.0 | 1.0 | 1.0 | 0.31 |
| 15 | 2026-08-04 | confirmed cases | 1 | 80.42 | 2.45 | 0.127 | 2.39 | 74.61 | 5.81 | 0.0 | 1.0 | 1.0 | 0.18 |
| 16 | 2026-05-20 | confirmed deaths | 44 | 34.75 | 0.35 | 0.399 | 0.19 | 21.15 | 0.0 | 13.6 | 0.82 | 1.0 | -0.34 |
| 17 | 2026-05-23 | confirmed deaths | 44 | 42.18 | 0.35 | 0.492 | 0.23 | 19.95 | 0.0 | 22.23 | 0.25 | 1.0 | -0.58 |
| 18 | 2026-05-27 | confirmed deaths | 44 | 123.65 | 0.84 | 1.796 | 0.92 | 5.6 | 0.0 | 118.05 | 0.0 | 0.0 | -0.97 |
| 19 | 2026-06-08 | confirmed deaths | 44 | 77.99 | 0.58 | 0.233 | 0.36 | 76.14 | 1.06 | 0.79 | 1.0 | 1.0 | -0.05 |
| 20 | 2026-07-16 | confirmed deaths | 4 | 337.0 | 1.13 | 1.618 | 3.35 | 83.74 | 0.0 | 253.25 | 0.0 | 1.0 | -0.75 |
| 21 | 2026-07-18 | confirmed deaths | 4 | 284.84 | 1.34 | 1.516 | 5.1 | 111.23 | 0.0 | 173.61 | 0.0 | 1.0 | -0.66 |
| 22 | 2026-07-19 | confirmed deaths | 3 | 230.8 | 2.18 | 1.648 | 8.89 | 83.42 | 0.0 | 147.38 | 0.0 | 1.0 | -0.66 |
| 23 | 2026-07-20 | confirmed deaths | 3 | 264.86 | 2.03 | 1.987 | 8.57 | 73.14 | 0.0 | 191.72 | 0.0 | 1.0 | -0.68 |
| 24 | 2026-07-24 | confirmed deaths | 3 | 255.36 | 3.24 | 2.172 | 18.06 | 80.45 | 0.0 | 174.91 | 0.33 | 1.0 | -0.68 |
| 25 | 2026-07-25 | confirmed deaths | 3 | 257.21 | 3.94 | 2.221 | 20.32 | 85.99 | 0.0 | 171.22 | 0.0 | 1.0 | -0.64 |
| 26 | 2026-07-26 | confirmed deaths | 2 | 255.72 | 10.9 | 3.247 | 54.62 | 31.75 | 0.0 | 223.96 | 0.0 | 1.0 | -0.78 |
| 27 | 2026-07-27 | confirmed deaths | 2 | 248.36 | 8.9 | 3.106 | 41.55 | 37.0 | 0.0 | 211.36 | 0.0 | 1.0 | -0.71 |
| 28 | 2026-07-28 | confirmed deaths | 2 | 278.3 | 5.76 | 2.979 | 28.42 | 38.3 | 0.0 | 239.99 | 0.0 | 1.0 | -0.76 |
| 29 | 2026-07-31 | confirmed deaths | 2 | 256.78 | 6.67 | 2.864 | 33.59 | 51.02 | 0.0 | 205.75 | 0.0 | 1.0 | -0.7 |
| 30 | 2026-08-04 | confirmed deaths | 1 | 287.67 | 16.37 | 4.994 | 88.29 | 1.53 | 0.0 | 286.14 | 0.0 | 0.0 | -0.93 |
| 31 | 2026-06-08 | isolation beds | 44 | 74.59 | 0.44 | 0.152 | 0.39 | 39.12 | 2.3 | 33.17 | 0.5 | 1.0 | -0.21 |
| 32 | 2026-07-16 | isolation beds | 4 | 73.22 | 2.56 | 0.096 | 2.45 | 20.01 | 53.22 | 0.0 | 0.0 | 1.0 | 0.6 |
| 33 | 2026-07-18 | isolation beds | 4 | 77.78 | 2.54 | 0.103 | 2.39 | 18.71 | 59.07 | 0.0 | 0.0 | 1.0 | 0.61 |
| 34 | 2026-07-19 | isolation beds | 3 | 104.5 | 3.97 | 0.135 | 3.72 | 19.04 | 85.46 | 0.0 | 0.0 | 1.0 | 0.68 |
| 35 | 2026-07-20 | isolation beds | 3 | 89.56 | 3.43 | 0.114 | 3.22 | 16.46 | 73.1 | 0.0 | 0.0 | 1.0 | 0.67 |
| 36 | 2026-07-24 | isolation beds | 3 | 84.72 | 3.2 | 0.106 | 2.99 | 8.44 | 76.28 | 0.0 | 0.0 | 1.0 | 0.78 |
| 37 | 2026-07-25 | isolation beds | 3 | 123.38 | 3.1 | 0.157 | 2.95 | 11.61 | 111.78 | 0.0 | 0.0 | 0.67 | 0.8 |
| 38 | 2026-07-26 | isolation beds | 2 | 123.61 | 5.85 | 0.157 | 5.36 | 15.36 | 108.25 | 0.0 | 0.0 | 0.5 | 0.81 |
| 39 | 2026-07-27 | isolation beds | 2 | 95.61 | 3.86 | 0.121 | 3.55 | 27.89 | 67.72 | 0.0 | 0.0 | 1.0 | 0.66 |
| 40 | 2026-07-28 | isolation beds | 2 | 198.85 | 2.77 | 0.268 | 2.47 | 30.38 | 168.47 | 0.0 | 0.0 | 0.5 | 0.9 |
| 41 | 2026-07-31 | isolation beds | 2 | 135.33 | 5.68 | 0.159 | 5.05 | 35.12 | 100.21 | 0.0 | 0.0 | 0.5 | 0.74 |
| 42 | 2026-08-04 | isolation beds | 1 | 169.73 | 2.83 | 0.251 | 2.6 | 31.9 | 137.83 | 0.0 | 0.0 | 0.0 | 0.95 |
| 43 | 2026-07-26 | onset reports | 2 | 94.33 | 0.2 | 0.193 | 0.03 | 65.22 | 29.11 | 0.0 | 0.5 | 1.0 | 0.43 |
| 44 | 2026-07-27 | onset reports | 2 | 124.72 | 0.27 | 0.205 | 0.03 | 56.66 | 67.74 | 0.32 | 0.5 | 1.0 | 0.34 |
| 45 | 2026-07-28 | onset reports | 2 | 148.65 | 0.31 | 0.236 | 0.04 | 61.39 | 86.46 | 0.8 | 0.5 | 1.0 | 0.36 |
| 46 | 2026-07-31 | onset reports | 2 | 100.67 | 0.17 | 0.158 | 0.03 | 75.72 | 24.96 | 0.0 | 1.0 | 1.0 | 0.33 |
| 47 | 2026-08-04 | onset reports | 1 | 151.09 | 1.84 | 0.882 | 0.2 | 43.53 | 107.56 | 0.0 | 0.0 | 1.0 | 0.8 |
| 48 | 2026-06-08 | recovered | 44 | 114.32 | 1.02 | 0.442 | 0.31 | 92.0 | 22.32 | 0.0 | 1.0 | 1.0 | 0.37 |
| 49 | 2026-07-16 | recovered | 4 | 139.34 | 1.09 | 0.469 | 1.08 | 135.5 | 0.0 | 3.84 | 1.0 | 1.0 | -0.1 |
| 50 | 2026-07-18 | recovered | 4 | 149.61 | 2.39 | 0.455 | 2.4 | 146.94 | 2.67 | 0.0 | 1.0 | 1.0 | 0.1 |
| 51 | 2026-07-19 | recovered | 3 | 119.04 | 2.84 | 0.467 | 2.79 | 117.97 | 1.07 | 0.0 | 1.0 | 1.0 | 0.08 |
| 52 | 2026-07-20 | recovered | 3 | 114.75 | 2.82 | 0.406 | 2.63 | 114.34 | 0.41 | 0.0 | 1.0 | 1.0 | 0.05 |
| 53 | 2026-07-24 | recovered | 3 | 136.27 | 3.11 | 0.4 | 2.6 | 131.19 | 5.08 | 0.0 | 1.0 | 1.0 | 0.16 |
| 54 | 2026-07-25 | recovered | 3 | 124.19 | 2.65 | 0.365 | 2.25 | 120.32 | 3.87 | 0.0 | 1.0 | 1.0 | 0.12 |
| 55 | 2026-07-26 | recovered | 2 | 69.22 | 3.39 | 0.364 | 3.05 | 68.7 | 0.0 | 0.52 | 1.0 | 1.0 | -0.06 |
| 56 | 2026-07-27 | recovered | 2 | 99.21 | 3.36 | 0.446 | 2.76 | 98.13 | 0.0 | 1.08 | 1.0 | 1.0 | -0.08 |
| 57 | 2026-07-28 | recovered | 2 | 82.95 | 1.14 | 0.348 | 0.86 | 81.82 | 0.47 | 0.66 | 1.0 | 1.0 | -0.0 |
| 58 | 2026-07-31 | recovered | 2 | 111.84 | 2.37 | 0.369 | 1.54 | 108.04 | 3.8 | 0.0 | 1.0 | 1.0 | 0.12 |
| 59 | 2026-08-04 | recovered | 1 | 45.37 | 2.35 | 0.412 | 3.48 | 41.7 | 0.0 | 3.67 | 1.0 | 1.0 | -0.16 |
The headline frozen table pools one row per stream across cut-offs and horizons, scored against the persistence baseline on both scales, with the CRPS decomposition, coverage and bias columns described above. There is no model column, since only one model is scored.
| Row | stream | n | crps | rel_to_baseline | log_crps | log_rel_to_baseline | dispersion | overprediction | underprediction | coverage_50 | coverage_90 | bias |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| String31 | Int64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | confirmed cases | 205 | 511.9 | 1.5 | 0.289 | 0.29 | 332.73 | 179.15 | 0.02 | 0.73 | 1.0 | 0.36 |
| 2 | confirmed deaths | 205 | 231.42 | 1.87 | 1.683 | 1.13 | 89.33 | 0.34 | 141.75 | 0.32 | 0.98 | -0.49 |
| 3 | isolation beds | 73 | 107.0 | 0.93 | 0.152 | 0.6 | 24.62 | 69.1 | 13.29 | 0.01 | 0.86 | 0.45 |
| 4 | onset reports | 9 | 120.87 | 0.26 | 0.274 | 0.05 | 62.39 | 58.23 | 0.25 | 0.56 | 1.0 | 0.41 |
| 5 | recovered | 73 | 134.07 | 1.49 | 0.426 | 0.45 | 124.91 | 8.52 | 0.64 | 1.0 | 1.0 | 0.1 |
The same relative skill against the baseline, by horizon, for the frozen cut-offs.
frozen_relative_skill_fig = plot_forecast_relative_skill(
frozen_score_by_horizon_table);The same columns as a table, broken out by horizon, and again broken out by frozen cut-off, are behind the two dropdowns below.
Scores by horizon
| Row | stream | horizon | n | crps | rel_to_baseline | log_crps | log_rel_to_baseline | dispersion | overprediction | underprediction | coverage_50 | coverage_90 | bias |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| String31 | Int64 | Int64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | confirmed cases | 7 | 55 | 93.32 | 1.36 | 0.146 | 0.34 | 83.14 | 10.1 | 0.09 | 1.0 | 1.0 | 0.19 |
| 2 | confirmed cases | 14 | 54 | 226.26 | 1.02 | 0.178 | 0.21 | 191.43 | 34.83 | 0.0 | 1.0 | 1.0 | 0.26 |
| 3 | confirmed cases | 21 | 50 | 574.93 | 1.29 | 0.349 | 0.28 | 369.32 | 205.61 | 0.0 | 0.6 | 1.0 | 0.45 |
| 4 | confirmed cases | 28 | 46 | 1279.21 | 1.83 | 0.526 | 0.32 | 757.28 | 521.93 | 0.0 | 0.22 | 1.0 | 0.59 |
| 5 | confirmed deaths | 7 | 55 | 210.33 | 9.46 | 3.593 | 5.36 | 9.56 | 0.0 | 200.76 | 0.0 | 0.91 | -0.84 |
| 6 | confirmed deaths | 14 | 54 | 254.73 | 3.87 | 1.707 | 1.41 | 70.93 | 0.0 | 183.8 | 0.07 | 1.0 | -0.63 |
| 7 | confirmed deaths | 21 | 50 | 229.71 | 1.4 | 0.736 | 0.39 | 118.4 | 0.0 | 111.31 | 0.5 | 1.0 | -0.33 |
| 8 | confirmed deaths | 28 | 46 | 231.13 | 0.86 | 0.401 | 0.17 | 174.7 | 1.53 | 54.9 | 0.78 | 1.0 | -0.08 |
| 9 | isolation beds | 7 | 22 | 111.85 | 2.84 | 0.144 | 1.5 | 17.28 | 94.57 | 0.0 | 0.0 | 0.55 | 0.83 |
| 10 | isolation beds | 14 | 21 | 113.12 | 2.45 | 0.148 | 1.32 | 21.73 | 91.39 | 0.0 | 0.05 | 1.0 | 0.68 |
| 11 | isolation beds | 21 | 17 | 87.43 | 0.49 | 0.13 | 0.33 | 26.24 | 49.4 | 11.8 | 0.0 | 1.0 | 0.27 |
| 12 | isolation beds | 28 | 13 | 114.51 | 0.42 | 0.2 | 0.35 | 39.57 | 15.73 | 59.21 | 0.0 | 1.0 | -0.32 |
| 13 | onset reports | 7 | 5 | 80.92 | 0.27 | 0.312 | 0.06 | 46.64 | 33.82 | 0.45 | 0.6 | 1.0 | 0.3 |
| 14 | onset reports | 14 | 4 | 170.81 | 0.26 | 0.227 | 0.04 | 82.07 | 88.74 | 0.0 | 0.5 | 1.0 | 0.56 |
| 15 | recovered | 7 | 22 | 49.1 | 3.29 | 0.402 | 2.4 | 47.12 | 0.57 | 1.42 | 1.0 | 1.0 | -0.0 |
| 16 | recovered | 14 | 21 | 115.64 | 2.12 | 0.405 | 0.53 | 112.19 | 3.04 | 0.41 | 1.0 | 1.0 | 0.07 |
| 17 | recovered | 21 | 17 | 169.29 | 1.35 | 0.433 | 0.33 | 164.78 | 4.32 | 0.19 | 1.0 | 1.0 | 0.1 |
| 18 | recovered | 28 | 13 | 261.57 | 1.15 | 0.49 | 0.24 | 224.98 | 36.29 | 0.3 | 1.0 | 1.0 | 0.3 |
Scores by frozen cut-off
| Row | made_date | stream | n | crps | rel_to_baseline | log_crps | log_rel_to_baseline | dispersion | overprediction | underprediction | coverage_50 | coverage_90 | bias |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | String31 | Int64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | 2026-05-20 | confirmed cases | 44 | 277.41 | 0.76 | 0.372 | 0.25 | 225.49 | 51.92 | 0.0 | 0.75 | 1.0 | 0.42 |
| 2 | 2026-05-23 | confirmed cases | 44 | 184.4 | 0.45 | 0.219 | 0.16 | 156.1 | 27.59 | 0.71 | 1.0 | 1.0 | 0.09 |
| 3 | 2026-05-27 | confirmed cases | 44 | 299.87 | 0.58 | 0.869 | 0.57 | 51.6 | 0.0 | 248.27 | 0.0 | 0.75 | -0.83 |
| 4 | 2026-06-08 | confirmed cases | 44 | 628.9 | 4.43 | 0.435 | 2.16 | 339.44 | 289.46 | 0.0 | 0.36 | 1.0 | 0.6 |
| 5 | 2026-07-16 | confirmed cases | 4 | 294.68 | 0.48 | 0.168 | 0.31 | 283.46 | 10.98 | 0.24 | 1.0 | 1.0 | 0.07 |
| 6 | 2026-07-18 | confirmed cases | 4 | 361.26 | 0.83 | 0.185 | 0.55 | 333.85 | 27.41 | 0.0 | 1.0 | 1.0 | 0.15 |
| 7 | 2026-07-19 | confirmed cases | 3 | 299.44 | 1.29 | 0.193 | 0.89 | 244.89 | 54.55 | 0.0 | 1.0 | 1.0 | 0.28 |
| 8 | 2026-07-20 | confirmed cases | 3 | 246.3 | 0.89 | 0.167 | 0.64 | 211.22 | 35.08 | 0.0 | 1.0 | 1.0 | 0.2 |
| 9 | 2026-07-24 | confirmed cases | 3 | 280.44 | 1.59 | 0.174 | 1.18 | 224.76 | 55.68 | 0.0 | 1.0 | 1.0 | 0.31 |
| 10 | 2026-07-25 | confirmed cases | 3 | 290.57 | 2.5 | 0.188 | 1.96 | 228.5 | 62.07 | 0.0 | 1.0 | 1.0 | 0.33 |
| 11 | 2026-07-26 | confirmed cases | 2 | 146.91 | 3.09 | 0.146 | 2.42 | 130.2 | 16.71 | 0.0 | 1.0 | 1.0 | 0.24 |
| 12 | 2026-07-27 | confirmed cases | 2 | 155.94 | 2.72 | 0.16 | 2.03 | 140.24 | 15.7 | 0.0 | 1.0 | 1.0 | 0.26 |
| 13 | 2026-07-28 | confirmed cases | 2 | 145.08 | 1.75 | 0.139 | 1.47 | 132.78 | 12.3 | 0.0 | 1.0 | 1.0 | 0.19 |
| 14 | 2026-07-31 | confirmed cases | 2 | 171.13 | 3.56 | 0.167 | 2.73 | 142.53 | 28.6 | 0.0 | 1.0 | 1.0 | 0.31 |
| 15 | 2026-08-04 | confirmed cases | 1 | 80.42 | 2.45 | 0.127 | 2.39 | 74.61 | 5.81 | 0.0 | 1.0 | 1.0 | 0.18 |
| 16 | 2026-05-20 | confirmed deaths | 44 | 34.75 | 0.35 | 0.399 | 0.19 | 21.15 | 0.0 | 13.6 | 0.82 | 1.0 | -0.34 |
| 17 | 2026-05-23 | confirmed deaths | 44 | 42.18 | 0.35 | 0.492 | 0.23 | 19.95 | 0.0 | 22.23 | 0.25 | 1.0 | -0.58 |
| 18 | 2026-05-27 | confirmed deaths | 44 | 123.65 | 0.84 | 1.796 | 0.92 | 5.6 | 0.0 | 118.05 | 0.0 | 0.0 | -0.97 |
| 19 | 2026-06-08 | confirmed deaths | 44 | 77.99 | 0.58 | 0.233 | 0.36 | 76.14 | 1.06 | 0.79 | 1.0 | 1.0 | -0.05 |
| 20 | 2026-07-16 | confirmed deaths | 4 | 337.0 | 1.13 | 1.618 | 3.35 | 83.74 | 0.0 | 253.25 | 0.0 | 1.0 | -0.75 |
| 21 | 2026-07-18 | confirmed deaths | 4 | 284.84 | 1.34 | 1.516 | 5.1 | 111.23 | 0.0 | 173.61 | 0.0 | 1.0 | -0.66 |
| 22 | 2026-07-19 | confirmed deaths | 3 | 230.8 | 2.18 | 1.648 | 8.89 | 83.42 | 0.0 | 147.38 | 0.0 | 1.0 | -0.66 |
| 23 | 2026-07-20 | confirmed deaths | 3 | 264.86 | 2.03 | 1.987 | 8.57 | 73.14 | 0.0 | 191.72 | 0.0 | 1.0 | -0.68 |
| 24 | 2026-07-24 | confirmed deaths | 3 | 255.36 | 3.24 | 2.172 | 18.06 | 80.45 | 0.0 | 174.91 | 0.33 | 1.0 | -0.68 |
| 25 | 2026-07-25 | confirmed deaths | 3 | 257.21 | 3.94 | 2.221 | 20.32 | 85.99 | 0.0 | 171.22 | 0.0 | 1.0 | -0.64 |
| 26 | 2026-07-26 | confirmed deaths | 2 | 255.72 | 10.9 | 3.247 | 54.62 | 31.75 | 0.0 | 223.96 | 0.0 | 1.0 | -0.78 |
| 27 | 2026-07-27 | confirmed deaths | 2 | 248.36 | 8.9 | 3.106 | 41.55 | 37.0 | 0.0 | 211.36 | 0.0 | 1.0 | -0.71 |
| 28 | 2026-07-28 | confirmed deaths | 2 | 278.3 | 5.76 | 2.979 | 28.42 | 38.3 | 0.0 | 239.99 | 0.0 | 1.0 | -0.76 |
| 29 | 2026-07-31 | confirmed deaths | 2 | 256.78 | 6.67 | 2.864 | 33.59 | 51.02 | 0.0 | 205.75 | 0.0 | 1.0 | -0.7 |
| 30 | 2026-08-04 | confirmed deaths | 1 | 287.67 | 16.37 | 4.994 | 88.29 | 1.53 | 0.0 | 286.14 | 0.0 | 0.0 | -0.93 |
| 31 | 2026-06-08 | isolation beds | 44 | 74.59 | 0.44 | 0.152 | 0.39 | 39.12 | 2.3 | 33.17 | 0.5 | 1.0 | -0.21 |
| 32 | 2026-07-16 | isolation beds | 4 | 73.22 | 2.56 | 0.096 | 2.45 | 20.01 | 53.22 | 0.0 | 0.0 | 1.0 | 0.6 |
| 33 | 2026-07-18 | isolation beds | 4 | 77.78 | 2.54 | 0.103 | 2.39 | 18.71 | 59.07 | 0.0 | 0.0 | 1.0 | 0.61 |
| 34 | 2026-07-19 | isolation beds | 3 | 104.5 | 3.97 | 0.135 | 3.72 | 19.04 | 85.46 | 0.0 | 0.0 | 1.0 | 0.68 |
| 35 | 2026-07-20 | isolation beds | 3 | 89.56 | 3.43 | 0.114 | 3.22 | 16.46 | 73.1 | 0.0 | 0.0 | 1.0 | 0.67 |
| 36 | 2026-07-24 | isolation beds | 3 | 84.72 | 3.2 | 0.106 | 2.99 | 8.44 | 76.28 | 0.0 | 0.0 | 1.0 | 0.78 |
| 37 | 2026-07-25 | isolation beds | 3 | 123.38 | 3.1 | 0.157 | 2.95 | 11.61 | 111.78 | 0.0 | 0.0 | 0.67 | 0.8 |
| 38 | 2026-07-26 | isolation beds | 2 | 123.61 | 5.85 | 0.157 | 5.36 | 15.36 | 108.25 | 0.0 | 0.0 | 0.5 | 0.81 |
| 39 | 2026-07-27 | isolation beds | 2 | 95.61 | 3.86 | 0.121 | 3.55 | 27.89 | 67.72 | 0.0 | 0.0 | 1.0 | 0.66 |
| 40 | 2026-07-28 | isolation beds | 2 | 198.85 | 2.77 | 0.268 | 2.47 | 30.38 | 168.47 | 0.0 | 0.0 | 0.5 | 0.9 |
| 41 | 2026-07-31 | isolation beds | 2 | 135.33 | 5.68 | 0.159 | 5.05 | 35.12 | 100.21 | 0.0 | 0.0 | 0.5 | 0.74 |
| 42 | 2026-08-04 | isolation beds | 1 | 169.73 | 2.83 | 0.251 | 2.6 | 31.9 | 137.83 | 0.0 | 0.0 | 0.0 | 0.95 |
| 43 | 2026-07-26 | onset reports | 2 | 94.33 | 0.2 | 0.193 | 0.03 | 65.22 | 29.11 | 0.0 | 0.5 | 1.0 | 0.43 |
| 44 | 2026-07-27 | onset reports | 2 | 124.72 | 0.27 | 0.205 | 0.03 | 56.66 | 67.74 | 0.32 | 0.5 | 1.0 | 0.34 |
| 45 | 2026-07-28 | onset reports | 2 | 148.65 | 0.31 | 0.236 | 0.04 | 61.39 | 86.46 | 0.8 | 0.5 | 1.0 | 0.36 |
| 46 | 2026-07-31 | onset reports | 2 | 100.67 | 0.17 | 0.158 | 0.03 | 75.72 | 24.96 | 0.0 | 1.0 | 1.0 | 0.33 |
| 47 | 2026-08-04 | onset reports | 1 | 151.09 | 1.84 | 0.882 | 0.2 | 43.53 | 107.56 | 0.0 | 0.0 | 1.0 | 0.8 |
| 48 | 2026-06-08 | recovered | 44 | 114.32 | 1.02 | 0.442 | 0.31 | 92.0 | 22.32 | 0.0 | 1.0 | 1.0 | 0.37 |
| 49 | 2026-07-16 | recovered | 4 | 139.34 | 1.09 | 0.469 | 1.08 | 135.5 | 0.0 | 3.84 | 1.0 | 1.0 | -0.1 |
| 50 | 2026-07-18 | recovered | 4 | 149.61 | 2.39 | 0.455 | 2.4 | 146.94 | 2.67 | 0.0 | 1.0 | 1.0 | 0.1 |
| 51 | 2026-07-19 | recovered | 3 | 119.04 | 2.84 | 0.467 | 2.79 | 117.97 | 1.07 | 0.0 | 1.0 | 1.0 | 0.08 |
| 52 | 2026-07-20 | recovered | 3 | 114.75 | 2.82 | 0.406 | 2.63 | 114.34 | 0.41 | 0.0 | 1.0 | 1.0 | 0.05 |
| 53 | 2026-07-24 | recovered | 3 | 136.27 | 3.11 | 0.4 | 2.6 | 131.19 | 5.08 | 0.0 | 1.0 | 1.0 | 0.16 |
| 54 | 2026-07-25 | recovered | 3 | 124.19 | 2.65 | 0.365 | 2.25 | 120.32 | 3.87 | 0.0 | 1.0 | 1.0 | 0.12 |
| 55 | 2026-07-26 | recovered | 2 | 69.22 | 3.39 | 0.364 | 3.05 | 68.7 | 0.0 | 0.52 | 1.0 | 1.0 | -0.06 |
| 56 | 2026-07-27 | recovered | 2 | 99.21 | 3.36 | 0.446 | 2.76 | 98.13 | 0.0 | 1.08 | 1.0 | 1.0 | -0.08 |
| 57 | 2026-07-28 | recovered | 2 | 82.95 | 1.14 | 0.348 | 0.86 | 81.82 | 0.47 | 0.66 | 1.0 | 1.0 | -0.0 |
| 58 | 2026-07-31 | recovered | 2 | 111.84 | 2.37 | 0.369 | 1.54 | 108.04 | 3.8 | 0.0 | 1.0 | 1.0 | 0.12 |
| 59 | 2026-08-04 | recovered | 1 | 45.37 | 2.35 | 0.412 | 3.48 | 41.7 | 0.0 | 3.67 | 1.0 | 1.0 | -0.16 |
The frozen forecasts made at each cut-off against the value observed since, one panel per stream and horizon, the observed value in black. Each panel carries the frozen forecast and the persistence baseline, coloured as in the cross-release overlay above, and the x-axis is the cut-off each forecast was made from. The same per-panel axis crop and overflow marker applies here.
Frozen-fit forecasts-versus-now overlay
frozen_overlay_fig = plot_forecast_overlay(frozen_overlay_df);The frozen re-fits below freeze the renewal data to an earlier cut-off and re-fit, so that a change driven by newer data can be distinguished from one driven by a change of method. Each uses the full headline settings: 1000 draws across two chains.
Freeze the renewal data to a cut-off and re-fit
# Frozen re-fits and released_df are prepared in the setup block above.Individual fits against the baseline
This section repeats the cross-release forecast scoring from Forecast scoring across releases above, filtered to each stream's own individual fit rather than the joint, against the same persistence baseline. Recovered has no individual fit, so it does not appear here. These are the individual-fit rows of the cross-release scores above, not a separate computation. As in Forecast scoring across releases above, every table and figure in this section is currently empty for the same reason. It will populate once those targets resolve.
Individual-fit rows of the cross-release scores
individual_score_overview_table = forecast_score_overview_table[
forecast_score_overview_table.fit .!= "joint", :]
individual_score_by_horizon_table = forecast_score_by_horizon_table[
forecast_score_by_horizon_table.fit .!= "joint", :]
individual_score_by_release_table = forecast_score_by_release_table[
forecast_score_by_release_table.fit .!= "joint", :]| Row | made_date | stream | fit | n | crps | rel_to_baseline | log_crps | log_rel_to_baseline | rel_to_individual | log_rel_to_individual | dispersion | overprediction | underprediction | coverage_50 | coverage_90 | bias |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | String31 | String31 | Int64 | Float64 | Float64 | Float64 | Float64 | Float64? | Float64? | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | 2026-07-23 | confirmed cases | confirmed | 3 | 219.98 | 1.0 | 0.193 | 1.07 | missing | missing | 214.98 | 0.27 | 4.73 | 1.0 | 1.0 | -0.08 |
| 2 | 2026-07-25 | confirmed cases | confirmed | 3 | 252.73 | 2.11 | 0.21 | 2.13 | missing | missing | 251.36 | 1.3 | 0.07 | 1.0 | 1.0 | 0.02 |
| 3 | 2026-07-26 | confirmed cases | confirmed | 2 | 146.77 | 3.3 | 0.206 | 3.61 | missing | missing | 131.93 | 0.0 | 14.84 | 1.0 | 1.0 | -0.22 |
| 4 | 2026-07-27 | confirmed cases | confirmed | 2 | 135.07 | 2.58 | 0.161 | 2.23 | missing | missing | 134.26 | 0.74 | 0.08 | 1.0 | 1.0 | 0.02 |
| 5 | 2026-07-31 | confirmed cases | confirmed | 2 | 189.02 | 3.98 | 0.206 | 3.37 | missing | missing | 186.09 | 2.93 | 0.0 | 1.0 | 1.0 | 0.05 |
| 6 | 2026-08-01 | confirmed cases | confirmed | 2 | 159.75 | 3.42 | 0.19 | 3.31 | missing | missing | 159.3 | 0.45 | 0.0 | 1.0 | 1.0 | 0.03 |
| 7 | 2026-08-02 | confirmed cases | confirmed | 1 | 91.77 | 2.59 | 0.163 | 2.48 | missing | missing | 89.22 | 0.0 | 2.55 | 1.0 | 1.0 | -0.11 |
| 8 | 2026-08-03 | confirmed cases | confirmed | 1 | 88.1 | 1.17 | 0.164 | 1.06 | missing | missing | 87.14 | 0.0 | 0.96 | 1.0 | 1.0 | -0.06 |
| 9 | 2026-08-04 | confirmed cases | confirmed | 1 | 94.85 | 2.93 | 0.167 | 3.08 | missing | missing | 94.7 | 0.0 | 0.15 | 1.0 | 1.0 | -0.02 |
| 10 | 2026-08-07 | confirmed cases | confirmed | 1 | 103.83 | 1.56 | 0.193 | 1.6 | missing | missing | 91.73 | 0.0 | 12.1 | 1.0 | 1.0 | -0.21 |
| 11 | 2026-07-23 | confirmed deaths | confirmed_deaths | 3 | 427.71 | 4.69 | 0.391 | 2.79 | missing | missing | 249.45 | 178.26 | 0.0 | 0.33 | 1.0 | 0.53 |
| 12 | 2026-07-25 | confirmed deaths | confirmed_deaths | 3 | 150.09 | 2.45 | 0.221 | 2.17 | missing | missing | 145.49 | 4.61 | 0.0 | 1.0 | 1.0 | 0.12 |
| 13 | 2026-07-26 | confirmed deaths | confirmed_deaths | 2 | 105.51 | 4.9 | 0.222 | 4.14 | missing | missing | 104.48 | 1.04 | 0.0 | 1.0 | 1.0 | 0.06 |
| 14 | 2026-07-27 | confirmed deaths | confirmed_deaths | 2 | 123.88 | 4.82 | 0.226 | 3.32 | missing | missing | 110.53 | 13.35 | 0.0 | 1.0 | 1.0 | 0.19 |
| 15 | 2026-07-31 | confirmed deaths | confirmed_deaths | 2 | 117.92 | 2.9 | 0.25 | 2.76 | missing | missing | 117.21 | 0.57 | 0.14 | 1.0 | 1.0 | 0.01 |
| 16 | 2026-08-01 | confirmed deaths | confirmed_deaths | 2 | 103.76 | 1.91 | 0.211 | 1.67 | missing | missing | 103.76 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 |
| 17 | 2026-08-02 | confirmed deaths | confirmed_deaths | 1 | 70.73 | 2.75 | 0.252 | 2.62 | missing | missing | 69.5 | 0.0 | 1.23 | 1.0 | 1.0 | -0.08 |
| 18 | 2026-08-03 | confirmed deaths | confirmed_deaths | 1 | 60.78 | 1.13 | 0.231 | 1.1 | missing | missing | 54.93 | 0.0 | 5.85 | 1.0 | 1.0 | -0.2 |
| 19 | 2026-08-04 | confirmed deaths | confirmed_deaths | 1 | 68.66 | 4.09 | 0.27 | 5.07 | missing | missing | 60.32 | 0.0 | 8.34 | 1.0 | 1.0 | -0.24 |
| 20 | 2026-08-07 | confirmed deaths | confirmed_deaths | 1 | 84.53 | 2.39 | 0.356 | 3.14 | missing | missing | 66.14 | 0.0 | 18.39 | 1.0 | 1.0 | -0.34 |
| 21 | 2026-07-23 | isolation beds | treatment | 3 | 61.65 | 2.24 | 0.101 | 2.76 | missing | missing | 51.16 | 0.0 | 10.49 | 1.0 | 1.0 | -0.27 |
| 22 | 2026-07-25 | isolation beds | treatment | 3 | 48.78 | 1.15 | 0.08 | 1.42 | missing | missing | 48.52 | 0.01 | 0.25 | 1.0 | 1.0 | -0.02 |
| 23 | 2026-07-26 | isolation beds | treatment | 2 | 58.45 | 2.59 | 0.102 | 3.29 | missing | missing | 57.7 | 0.46 | 0.29 | 1.0 | 1.0 | 0.01 |
| 24 | 2026-07-27 | isolation beds | treatment | 2 | 62.4 | 3.11 | 0.11 | 3.95 | missing | missing | 61.76 | 0.0 | 0.64 | 1.0 | 1.0 | -0.07 |
| 25 | 2026-07-31 | isolation beds | treatment | 2 | 76.85 | 3.17 | 0.133 | 4.08 | missing | missing | 72.5 | 0.0 | 4.35 | 1.0 | 1.0 | -0.16 |
| 26 | 2026-08-01 | isolation beds | treatment | 2 | 76.79 | 2.82 | 0.143 | 3.62 | missing | missing | 76.69 | 0.0 | 0.1 | 1.0 | 1.0 | -0.02 |
| 27 | 2026-08-02 | isolation beds | treatment | 1 | 75.18 | 3.78 | 0.136 | 4.91 | missing | missing | 74.35 | 0.0 | 0.83 | 1.0 | 1.0 | -0.05 |
| 28 | 2026-08-03 | isolation beds | treatment | 1 | 74.86 | 3.77 | 0.133 | 4.87 | missing | missing | 74.86 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 |
| 29 | 2026-08-04 | isolation beds | treatment | 1 | 95.26 | 1.49 | 0.17 | 1.65 | missing | missing | 90.62 | 4.64 | 0.0 | 1.0 | 1.0 | 0.12 |
| 30 | 2026-08-07 | isolation beds | treatment | 1 | 87.19 | 2.72 | 0.146 | 3.38 | missing | missing | 77.66 | 0.0 | 9.53 | 1.0 | 1.0 | -0.26 |
| 31 | 2026-08-02 | onset reports | onsets | 1 | 81.88 | 0.18 | 0.283 | 0.05 | missing | missing | 63.32 | 0.0 | 18.56 | 1.0 | 1.0 | -0.28 |
| 32 | 2026-08-03 | onset reports | onsets | 1 | 145.59 | 1.18 | 0.667 | 0.14 | missing | missing | 64.42 | 81.17 | 0.0 | 0.0 | 1.0 | 0.64 |
| 33 | 2026-08-04 | onset reports | onsets | 1 | 118.93 | 1.45 | 0.747 | 0.17 | missing | missing | 70.02 | 48.91 | 0.0 | 0.0 | 1.0 | 0.51 |
| 34 | 2026-08-07 | onset reports | onsets | 1 | 153.64 | 0.31 | 0.702 | 0.11 | missing | missing | 61.66 | 0.0 | 91.98 | 0.0 | 1.0 | -0.61 |
| Row | stream | fit | n | crps | rel_to_baseline | log_crps | log_rel_to_baseline | rel_to_individual | log_rel_to_individual | dispersion | overprediction | underprediction | coverage_50 | coverage_90 | bias |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| String31 | String31 | Int64 | Float64 | Float64 | Float64 | Float64 | Float64? | Float64? | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | confirmed cases | confirmed | 18 | 169.88 | 1.9 | 0.19 | 1.98 | missing | missing | 165.83 | 0.72 | 3.33 | 1.0 | 1.0 | -0.05 |
| 2 | confirmed deaths | confirmed_deaths | 18 | 162.24 | 3.34 | 0.265 | 2.54 | missing | missing | 128.2 | 32.14 | 1.89 | 0.89 | 1.0 | 0.09 |
| 3 | isolation beds | treatment | 18 | 67.37 | 2.27 | 0.117 | 2.84 | missing | missing | 64.1 | 0.31 | 2.96 | 1.0 | 1.0 | -0.09 |
| 4 | onset reports | onsets | 4 | 125.01 | 0.43 | 0.599 | 0.11 | missing | missing | 64.85 | 32.52 | 27.64 | 0.25 | 1.0 | 0.06 |
The same relative skill against the baseline, by horizon, one panel per stream (dataset), for each stream's own individual fit.
individual_relative_skill_fig = plot_forecast_relative_skill(
individual_score_by_horizon_table;
empty_message = "Empty: the releases that carry the current model's " *
"own individual-stream forecasts are too recent for their " *
"targets to be observed yet. Not a missing forecast.");The same columns as a table, broken out by horizon, and again broken out by release, are behind the two dropdowns below.
Scores by horizon
| Row | stream | horizon | fit | n | crps | rel_to_baseline | log_crps | log_rel_to_baseline | rel_to_individual | log_rel_to_individual | dispersion | overprediction | underprediction | coverage_50 | coverage_90 | bias |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| String31 | Int64 | String31 | Int64 | Float64 | Float64 | Float64 | Float64 | Float64? | Float64? | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | confirmed cases | 7 | confirmed | 10 | 97.9 | 2.17 | 0.184 | 2.25 | missing | missing | 93.74 | 0.02 | 4.14 | 1.0 | 1.0 | -0.09 |
| 2 | confirmed cases | 14 | confirmed | 6 | 217.51 | 2.87 | 0.194 | 2.65 | missing | missing | 212.43 | 1.98 | 3.1 | 1.0 | 1.0 | 0.01 |
| 3 | confirmed cases | 21 | confirmed | 2 | 386.92 | 1.1 | 0.211 | 0.9 | missing | missing | 386.49 | 0.4 | 0.03 | 1.0 | 1.0 | 0.02 |
| 4 | confirmed deaths | 7 | confirmed_deaths | 10 | 70.36 | 2.55 | 0.244 | 2.47 | missing | missing | 63.68 | 3.27 | 3.41 | 1.0 | 1.0 | -0.03 |
| 5 | confirmed deaths | 14 | confirmed_deaths | 6 | 192.89 | 4.38 | 0.264 | 3.38 | missing | missing | 165.43 | 27.46 | 0.0 | 0.83 | 1.0 | 0.18 |
| 6 | confirmed deaths | 21 | confirmed_deaths | 2 | 529.65 | 3.18 | 0.37 | 1.76 | missing | missing | 339.13 | 190.52 | 0.0 | 0.5 | 1.0 | 0.41 |
| 7 | isolation beds | 7 | treatment | 10 | 74.47 | 2.53 | 0.132 | 3.15 | missing | missing | 70.46 | 0.47 | 3.55 | 1.0 | 1.0 | -0.08 |
| 8 | isolation beds | 14 | treatment | 6 | 63.54 | 2.27 | 0.11 | 2.86 | missing | missing | 61.41 | 0.15 | 1.98 | 1.0 | 1.0 | -0.08 |
| 9 | isolation beds | 21 | treatment | 2 | 43.39 | 1.21 | 0.065 | 1.38 | missing | missing | 40.38 | 0.0 | 3.0 | 1.0 | 1.0 | -0.1 |
| 10 | onset reports | 7 | onsets | 4 | 125.01 | 0.43 | 0.599 | 0.11 | missing | missing | 64.85 | 32.52 | 27.64 | 0.25 | 1.0 | 0.06 |
Scores by release
| Row | made_date | stream | fit | n | crps | rel_to_baseline | log_crps | log_rel_to_baseline | rel_to_individual | log_rel_to_individual | dispersion | overprediction | underprediction | coverage_50 | coverage_90 | bias |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | String31 | String31 | Int64 | Float64 | Float64 | Float64 | Float64 | Float64? | Float64? | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | 2026-07-23 | confirmed cases | confirmed | 3 | 219.98 | 1.0 | 0.193 | 1.07 | missing | missing | 214.98 | 0.27 | 4.73 | 1.0 | 1.0 | -0.08 |
| 2 | 2026-07-25 | confirmed cases | confirmed | 3 | 252.73 | 2.11 | 0.21 | 2.13 | missing | missing | 251.36 | 1.3 | 0.07 | 1.0 | 1.0 | 0.02 |
| 3 | 2026-07-26 | confirmed cases | confirmed | 2 | 146.77 | 3.3 | 0.206 | 3.61 | missing | missing | 131.93 | 0.0 | 14.84 | 1.0 | 1.0 | -0.22 |
| 4 | 2026-07-27 | confirmed cases | confirmed | 2 | 135.07 | 2.58 | 0.161 | 2.23 | missing | missing | 134.26 | 0.74 | 0.08 | 1.0 | 1.0 | 0.02 |
| 5 | 2026-07-31 | confirmed cases | confirmed | 2 | 189.02 | 3.98 | 0.206 | 3.37 | missing | missing | 186.09 | 2.93 | 0.0 | 1.0 | 1.0 | 0.05 |
| 6 | 2026-08-01 | confirmed cases | confirmed | 2 | 159.75 | 3.42 | 0.19 | 3.31 | missing | missing | 159.3 | 0.45 | 0.0 | 1.0 | 1.0 | 0.03 |
| 7 | 2026-08-02 | confirmed cases | confirmed | 1 | 91.77 | 2.59 | 0.163 | 2.48 | missing | missing | 89.22 | 0.0 | 2.55 | 1.0 | 1.0 | -0.11 |
| 8 | 2026-08-03 | confirmed cases | confirmed | 1 | 88.1 | 1.17 | 0.164 | 1.06 | missing | missing | 87.14 | 0.0 | 0.96 | 1.0 | 1.0 | -0.06 |
| 9 | 2026-08-04 | confirmed cases | confirmed | 1 | 94.85 | 2.93 | 0.167 | 3.08 | missing | missing | 94.7 | 0.0 | 0.15 | 1.0 | 1.0 | -0.02 |
| 10 | 2026-08-07 | confirmed cases | confirmed | 1 | 103.83 | 1.56 | 0.193 | 1.6 | missing | missing | 91.73 | 0.0 | 12.1 | 1.0 | 1.0 | -0.21 |
| 11 | 2026-07-23 | confirmed deaths | confirmed_deaths | 3 | 427.71 | 4.69 | 0.391 | 2.79 | missing | missing | 249.45 | 178.26 | 0.0 | 0.33 | 1.0 | 0.53 |
| 12 | 2026-07-25 | confirmed deaths | confirmed_deaths | 3 | 150.09 | 2.45 | 0.221 | 2.17 | missing | missing | 145.49 | 4.61 | 0.0 | 1.0 | 1.0 | 0.12 |
| 13 | 2026-07-26 | confirmed deaths | confirmed_deaths | 2 | 105.51 | 4.9 | 0.222 | 4.14 | missing | missing | 104.48 | 1.04 | 0.0 | 1.0 | 1.0 | 0.06 |
| 14 | 2026-07-27 | confirmed deaths | confirmed_deaths | 2 | 123.88 | 4.82 | 0.226 | 3.32 | missing | missing | 110.53 | 13.35 | 0.0 | 1.0 | 1.0 | 0.19 |
| 15 | 2026-07-31 | confirmed deaths | confirmed_deaths | 2 | 117.92 | 2.9 | 0.25 | 2.76 | missing | missing | 117.21 | 0.57 | 0.14 | 1.0 | 1.0 | 0.01 |
| 16 | 2026-08-01 | confirmed deaths | confirmed_deaths | 2 | 103.76 | 1.91 | 0.211 | 1.67 | missing | missing | 103.76 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 |
| 17 | 2026-08-02 | confirmed deaths | confirmed_deaths | 1 | 70.73 | 2.75 | 0.252 | 2.62 | missing | missing | 69.5 | 0.0 | 1.23 | 1.0 | 1.0 | -0.08 |
| 18 | 2026-08-03 | confirmed deaths | confirmed_deaths | 1 | 60.78 | 1.13 | 0.231 | 1.1 | missing | missing | 54.93 | 0.0 | 5.85 | 1.0 | 1.0 | -0.2 |
| 19 | 2026-08-04 | confirmed deaths | confirmed_deaths | 1 | 68.66 | 4.09 | 0.27 | 5.07 | missing | missing | 60.32 | 0.0 | 8.34 | 1.0 | 1.0 | -0.24 |
| 20 | 2026-08-07 | confirmed deaths | confirmed_deaths | 1 | 84.53 | 2.39 | 0.356 | 3.14 | missing | missing | 66.14 | 0.0 | 18.39 | 1.0 | 1.0 | -0.34 |
| 21 | 2026-07-23 | isolation beds | treatment | 3 | 61.65 | 2.24 | 0.101 | 2.76 | missing | missing | 51.16 | 0.0 | 10.49 | 1.0 | 1.0 | -0.27 |
| 22 | 2026-07-25 | isolation beds | treatment | 3 | 48.78 | 1.15 | 0.08 | 1.42 | missing | missing | 48.52 | 0.01 | 0.25 | 1.0 | 1.0 | -0.02 |
| 23 | 2026-07-26 | isolation beds | treatment | 2 | 58.45 | 2.59 | 0.102 | 3.29 | missing | missing | 57.7 | 0.46 | 0.29 | 1.0 | 1.0 | 0.01 |
| 24 | 2026-07-27 | isolation beds | treatment | 2 | 62.4 | 3.11 | 0.11 | 3.95 | missing | missing | 61.76 | 0.0 | 0.64 | 1.0 | 1.0 | -0.07 |
| 25 | 2026-07-31 | isolation beds | treatment | 2 | 76.85 | 3.17 | 0.133 | 4.08 | missing | missing | 72.5 | 0.0 | 4.35 | 1.0 | 1.0 | -0.16 |
| 26 | 2026-08-01 | isolation beds | treatment | 2 | 76.79 | 2.82 | 0.143 | 3.62 | missing | missing | 76.69 | 0.0 | 0.1 | 1.0 | 1.0 | -0.02 |
| 27 | 2026-08-02 | isolation beds | treatment | 1 | 75.18 | 3.78 | 0.136 | 4.91 | missing | missing | 74.35 | 0.0 | 0.83 | 1.0 | 1.0 | -0.05 |
| 28 | 2026-08-03 | isolation beds | treatment | 1 | 74.86 | 3.77 | 0.133 | 4.87 | missing | missing | 74.86 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 |
| 29 | 2026-08-04 | isolation beds | treatment | 1 | 95.26 | 1.49 | 0.17 | 1.65 | missing | missing | 90.62 | 4.64 | 0.0 | 1.0 | 1.0 | 0.12 |
| 30 | 2026-08-07 | isolation beds | treatment | 1 | 87.19 | 2.72 | 0.146 | 3.38 | missing | missing | 77.66 | 0.0 | 9.53 | 1.0 | 1.0 | -0.26 |
| 31 | 2026-08-02 | onset reports | onsets | 1 | 81.88 | 0.18 | 0.283 | 0.05 | missing | missing | 63.32 | 0.0 | 18.56 | 1.0 | 1.0 | -0.28 |
| 32 | 2026-08-03 | onset reports | onsets | 1 | 145.59 | 1.18 | 0.667 | 0.14 | missing | missing | 64.42 | 81.17 | 0.0 | 0.0 | 1.0 | 0.64 |
| 33 | 2026-08-04 | onset reports | onsets | 1 | 118.93 | 1.45 | 0.747 | 0.17 | missing | missing | 70.02 | 48.91 | 0.0 | 0.0 | 1.0 | 0.51 |
| 34 | 2026-08-07 | onset reports | onsets | 1 | 153.64 | 0.31 | 0.702 | 0.11 | missing | missing | 61.66 | 0.0 | 91.98 | 0.0 | 1.0 | -0.61 |
Outbreak size estimated by each data stream
Each data stream constrains the latent outbreak size differently. The table below puts the posteriors over the infection count side by side, the single-stream fits and the joint, to show what each stream implies alone and what the joint adds.
Per-stream infection-count table
streams_C_table = streams_table(
"exports" => posterior_C_exports,
"deaths (DRC)" => posterior_C_deaths,
"cases (DRC)" => posterior_C_cases,
"confirmed (DRC)" => posterior_C_confirmed,
"isolation (DRC)" => posterior_C_treatment,
"onsets (DRC)" => posterior_C_onsets,
"joint" => posterior_C_joint);| Row | Stream | Lower 90% | Lower 60% | Lower 30% | Upper 30% | Upper 60% | Upper 90% |
|---|---|---|---|---|---|---|---|
| String | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | exports | 3184.0 | 10943.0 | 26440.0 | 130691.0 | 375903.0 | 3.11655e6 |
| 2 | deaths (DRC) | 20067.0 | 29181.0 | 37070.0 | 56801.0 | 73918.0 | 126298.0 |
| 3 | cases (DRC) | 24712.0 | 27690.0 | 30917.0 | 40375.0 | 51525.0 | 98515.0 |
| 4 | confirmed (DRC) | 35273.0 | 43573.0 | 50179.0 | 65704.0 | 84270.0 | 142550.0 |
| 5 | isolation (DRC) | 8336.0 | 9824.0 | 10949.0 | 14264.0 | 17322.0 | 30398.0 |
| 6 | onsets (DRC) | 17014.0 | 26130.0 | 35013.0 | 59907.0 | 85155.0 | 137207.0 |
| 7 | joint | 7983.0 | 9241.0 | 10172.0 | 12058.0 | 13333.0 | 16383.0 |
The first figure shows each single-stream fit's cumulative-infection trajectory projected to the cut-off, with a dotted rule in each stream's colour marking where its data stops and the ribbon beyond it becomes a forward projection.
Per-stream projected-trajectory plot
# Per-draw cumulative-infection trajectory carried by each single-stream
# fit out to the cut-off on day `n`, so streams whose data ends earlier are
# still projected to today.
function _cuminf(chn)
mat = chn[:cumulative_infections]
return [collect(v) for v in vec(collect(mat))]
end
# Grid day a stream's data last reports, used for the dotted rule. The
# suspected case and death histories freeze at 26 May; exports and confirmed
# run to the cut-off.
_last_day(days) = isempty(days) ? nothing : maximum(days)
stream_traj_fig = plot_stream_trajectories(
[
(; label = "exports", trajs = _cuminf(chn_exports),
last_day = _last_day(vcat(obs.export_case_days,
obs.export_death_days)), colour = :seagreen),
(; label = "deaths (DRC)", trajs = _cuminf(chn_deaths),
last_day = _last_day(obs.deaths_history.days),
colour = :firebrick),
(; label = "cases (DRC)", trajs = _cuminf(chn_cases),
last_day = _last_day(obs.reported_history.days),
colour = :steelblue),
(; label = "confirmed (DRC)", trajs = _cuminf(chn_confirmed),
last_day = _last_day(obs.confirmed_history.days),
colour = :goldenrod),
(; label = "isolation (DRC)", trajs = _cuminf(chn_treatment),
last_day = _last_day(obs.isolation_history.days),
colour = :darkorange),
(; label = "onsets (DRC)", trajs = _cuminf(chn_onsets),
last_day = _last_day(obs.onset_curve_history.report_days),
colour = :mediumpurple)];
n = obs.n, seeding = obs.seeding);The second figure is the posterior density of each fit's cumulative infection count at the cut-off. The x-axis is scaled to a multiple of the joint-fit 90% upper bound so the bulk of the streams stays visible rather than being flattened by the wide, ill-defined confirmed-only tail.
Cut-off infection-count density plot
# Scale the x-axis to twice the joint-fit 90% upper bound, so the joint and
# the streams that track it read clearly while the confirmed-only tail runs
# off the axis rather than dominating it.
density_xmax = 2.0 * quantile(posterior_C_joint, 0.95)
cumulative_density_fig = plot_cumulative_cases(
"exports" => posterior_C_exports,
"deaths (DRC)" => posterior_C_deaths,
"cases (DRC)" => posterior_C_cases,
"confirmed (DRC)" => posterior_C_confirmed,
"isolation (DRC)" => posterior_C_treatment,
"onsets (DRC)" => posterior_C_onsets,
"joint" => posterior_C_joint;
scenarios = [], xmax = density_xmax);Estimate evolution across releases
How the outbreak-size estimate has moved as situation reports accrued, three series on one calendar axis. The estimate published at each release is in blue, drawn as a median with nested 30/60/90% interval bars because each release is its own fit rather than one continuous model. The current model frozen at earlier cut-offs is in red, reusing fits already made for the McCabe and Chamla comparisons and the forecast validation. The current model on current data is the green band, drawn day by day so the latest estimate reads against the earlier points. Dotted vertical rules mark the release dates. The published series switches from a closed-form integral model to a renewal model on 7 June, so a step there can reflect the change of method rather than of data.
Released estimates and the current-model frozen re-fits
# Released median and 30/60/90% intervals per release, from
# `data/released_estimates.csv`. Each tuple is
# `(date, median, lo30, hi30, lo60, hi60, lo90, hi90)`.
release_evolution = [(string(r.date), r.median, r.lo30, r.hi30, r.lo60, r.hi60,
r.lo90, r.hi90) for r in eachrow(released_df)]
# The current model frozen at earlier cut-offs, each its own discrete
# estimate: the matched-McCabe cut-offs (20, 23, 27 May) already computed
# for the matched-in-time comparison below, the 8 June Chamla
# confirmed-case anchor computed for the Chamla comparison, and the
# one-week-back validation fit (`frozen_lastweek`, at `validation_cutoff`)
# already computed for the forecast validation above. All are reused here so
# the current-model estimate at those earlier cut-offs reads against the
# released overlay, including a recent point one week before the cut-off.
# No extra fits are run. Each tuple carries the median and 30/60/90%
# credible bounds from the frozen draws; `round_fn` rounds to a whole count
# for outbreak size, and is passed through unrounded for a continuous
# quantity such as R0.
function _ci369(xs; round_fn = x -> round(Int, x))
q(p) = round_fn(quantile(xs, p))
(q(0.5), q(0.35), q(0.65), q(0.20), q(0.80), q(0.05), q(0.95))
end
frozen_by_cutoff[validation_cutoff] = frozen_lastweek
# The cut-offs every frozen fit above was made at, shared by the
# outbreak-size and R0 by-release overlays below.
_frozen_matched_cutoffs = sort(union(frozen_cutoffs,
[validation_cutoff, default_chamla_cutoff()]))
frozen_matched = [(c, _ci369(frozen_C(c))...) for c in _frozen_matched_cutoffs]
# The current-data, current-model estimate as the cumulative-infection
# trajectory over the day grid (one calendar date per grid day, day 1 is
# the seeding date), summarised by per-day 30/60/90% credible bounds. This
# is the same latent quantity the cumulative-trajectory figure shows, so
# the current estimate rises over time on the release-date axis instead of
# sitting flat. Drawn against calendar dates, it lines up with the
# release and frozen points.
infection_trajectory = let
mat = chn_joint[:cumulative_infections]
trajs = [collect(v) for v in vec(collect(mat))]
# Only over the comparison window — from the earliest release date to the
# cut-off — not back to the seeding date.
start_day = obs.n - value(obs.cutoff - Date(release_evolution[1][1]))
days = max(start_day, 1):obs.n
dates = [obs.seeding + Day(d - 1) for d in days]
q(d, p) = quantile(Float64[t[d] for t in trajs], p)
(dates,
[q(d, 0.35) for d in days], [q(d, 0.65) for d in days],
[q(d, 0.20) for d in days], [q(d, 0.80) for d in days],
[q(d, 0.05) for d in days], [q(d, 0.95) for d in days])
end
evolution_fig = plot_estimate_evolution(release_evolution;
renewal = frozen_matched,
renewal_label = "Current model frozen at earlier cut-offs",
trajectory = infection_trajectory,
title = "Outbreak-size estimate as data accrued");Reproduction number estimated by each data stream
The reproduction number each stream implies on its own, one panel per stream with the joint fit overlaid in grey as the reference.
Per-stream implied-Rt plot
# The per-stream fits walk Rt from day 1 (the default `rt_start`), while the
# joint walks from `RT_WALK_LEAD` days before the first situation report; the
# shared `display_start` is the joint renewal start so every stream reads over
# the same established window. `ramp` matches the joint Rt figure.
_rt_walk_start_joint = clamp(_BREAKPOINT - RT_WALK_LEAD, _rt_start_plot, obs.n);
stream_rt_fig = plot_rt_streams(
[
(; label = "exports", chn = chn_exports, rt_start = 1,
rt_walk_start = 1, colour = :seagreen),
(; label = "deaths (DRC)", chn = chn_deaths, rt_start = 1,
rt_walk_start = 1, colour = :firebrick),
(; label = "cases (DRC)", chn = chn_cases, rt_start = 1,
rt_walk_start = 1, colour = :steelblue),
(; label = "confirmed (DRC)", chn = chn_confirmed, rt_start = 1,
rt_walk_start = 1, colour = :goldenrod),
(; label = "isolation (DRC)", chn = chn_treatment, rt_start = 1,
rt_walk_start = 1, colour = :darkorange),
(; label = "onsets (DRC)", chn = chn_onsets, rt_start = 1,
rt_walk_start = 1, colour = :mediumpurple)];
joint = (; label = "joint", chn = chn_joint, rt_start = _rt_start_plot,
rt_walk_start = _rt_walk_start_joint),
n = obs.n, breakpoint = _BREAKPOINT,
as_of_date = string(obs.cutoff), seeding = obs.seeding,
display_start = _rt_start_plot, ramp = RT_INTERVENTION_RAMP);Reproduction number by release
The reproduction number estimated at each release, the same kind of release-by-release picture as the outbreak-size evolution above. Each release's cut-off reproduction number
Reproduction number per release with the current-fit band
rt_release_df = CSV.read(
joinpath(pkgdir(BVDOutbreakSize), "data", "rt_by_release.csv"), DataFrame)
rt_release = [(string(r.date), r.median, r.lo30, r.hi30, r.lo60, r.hi60,
r.lo90, r.hi90) for r in eachrow(rt_release_df)]
# The current fit's daily Rt over its established window, summarised per day
# into a 30/60/90% band, reusing the same walk reconstruction the Rt figure
# uses so the band lines up with the per-release points on the calendar axis.
# The band is drawn only from the first release date onward, so it spans the
# same window as the per-release estimates rather than extending back to the
# renewal start. The first release day is the earliest date in
# `rt_by_release.csv` as a grid day; the walk is still reconstructed from the
# renewal start `_rt_start_plot` (the model knot grid) and the window is
# clamped into the reconstructed range so the quantiles never hit masked days.
rt_release_trajectory = let
rt_walk_start = clamp(_BREAKPOINT - RT_WALK_LEAD, _rt_start_plot, obs.n)
mat = reconstruct_rt(chn_joint; n = obs.n, breakpoint = _BREAKPOINT,
rt_start = _rt_start_plot, rt_walk_start = rt_walk_start,
ramp = RT_INTERVENTION_RAMP)
first_release_day = clamp(
value(minimum(rt_release_df.date) - obs.seeding) + 1,
_rt_start_plot, obs.n)
days = first_release_day:obs.n
dates = [obs.seeding + Day(d - 1) for d in days]
q(d, p) = quantile(collect(skipmissing(@view mat[:, d])), p)
(dates,
[q(d, 0.35) for d in days], [q(d, 0.65) for d in days],
[q(d, 0.20) for d in days], [q(d, 0.80) for d in days],
[q(d, 0.05) for d in days], [q(d, 0.95) for d in days])
end
rt_evolution_fig = plot_estimate_evolution(rt_release;
trajectory = rt_release_trajectory,
ylabel = "Reproduction number",
title = "Reproduction number as data accrued",
released_label = "Released estimate (per project release)",
trajectory_label = "Current model, current data",
refline = 1.0);Reproduction number by release and dataset
The same release-by-release reproduction number split into one panel per dataset, so each dataset's history reads against the others and against the joint. Panels share a calendar axis and a y range, and
Reproduction number per release by fit
# Schema of the per-release, per-fit estimate tables written by
# scripts/score_releases.jl from each release's stream_estimates.csv.
_by_stream_schema = (; release = String, date = Date, fit = String,
median = Float64, lo30 = Float64, hi30 = Float64, lo60 = Float64,
hi60 = Float64, lo90 = Float64, hi90 = Float64)
# Fits in a fixed order, the joint first, so the panels do not reshuffle
# between builds. Labels match the per-stream table above (in "Outbreak
# size estimated by each data stream"). Recovered is absent because it
# has no individual fit.
_fit_order = ["joint", "cases", "deaths", "confirmed", "confirmed_deaths",
"treatment", "onsets", "exports"]
_fit_labels = Dict("joint" => "joint", "cases" => "cases (DRC)",
"deaths" => "deaths (DRC)", "confirmed" => "confirmed (DRC)",
"confirmed_deaths" => "confirmed deaths (DRC)",
"treatment" => "isolation (DRC)", "onsets" => "onsets (DRC)",
"exports" => "exports")
# Group a per-fit estimate table into the label => tuples pairs the faceted
# plot takes, keyed on the date so the mixed release tag shapes
# (`results-v1.9.0` and `results-1243`) never reach the axis.
function _fit_groups(df)
return [get(_fit_labels, f, f) =>
[(string(r.date), r.median, r.lo30, r.hi30, r.lo60, r.hi60,
r.lo90, r.hi90) for r in eachrow(df) if r.fit == f]
for f in _fit_order]
end
# Per-fit reproduction-number trajectory, reconstructing the walk exactly as
# `plot_rt_streams` does per stream.
function _stream_rt_trajectory(chn, dates; rt_start, rt_walk_start)
mat = reconstruct_rt(chn; n = obs.n, breakpoint = _BREAKPOINT,
rt_start = rt_start, rt_walk_start = rt_walk_start,
ramp = RT_INTERVENTION_RAMP)
first_date = isempty(dates) ? obs.seeding : minimum(dates)
first_day = clamp(value(first_date - obs.seeding) + 1, rt_start, obs.n)
days = first_day:obs.n
ds = [obs.seeding + Day(d - 1) for d in days]
q(d, p) = quantile(collect(skipmissing(@view mat[:, d])), p)
(ds,
[q(d, 0.35) for d in days], [q(d, 0.65) for d in days],
[q(d, 0.20) for d in days], [q(d, 0.80) for d in days],
[q(d, 0.05) for d in days], [q(d, 0.95) for d in days])
end
# The single-stream chains and their renewal-walk starts, keyed on the fit
# id the per-release tables use. Both the joint walk start and the day-1
# per-stream starts are the ones the per-stream implied-Rt figure above
# uses, so the bands here match it. Confirmed deaths has no trajectory
# here: its panel still draws its release points alone.
_stream_chains = (
"joint" => (; chn = chn_joint, rt_start = _rt_start_plot,
rt_walk_start = _rt_walk_start_joint),
"cases" => (; chn = chn_cases, rt_start = 1, rt_walk_start = 1),
"deaths" => (; chn = chn_deaths, rt_start = 1, rt_walk_start = 1),
"confirmed" => (; chn = chn_confirmed, rt_start = 1, rt_walk_start = 1),
"treatment" => (; chn = chn_treatment, rt_start = 1, rt_walk_start = 1),
"onsets" => (; chn = chn_onsets, rt_start = 1, rt_walk_start = 1),
"exports" => (; chn = chn_exports, rt_start = 1, rt_walk_start = 1))
# Build a fit label => trajectory dictionary from a per-release table,
# restricted to the fits `_stream_chains` names. A fit with no row in `df`
# gets no trajectory, so its panel still draws its release points alone.
function _rt_trajectories(df)
trajs = Dict{String, Any}()
for (fid, cfg) in _stream_chains
fdates = df.date[df.fit .== fid]
isempty(fdates) && continue
trajs[get(_fit_labels, fid, fid)] = _stream_rt_trajectory(
cfg.chn, fdates; rt_start = cfg.rt_start,
rt_walk_start = cfg.rt_walk_start)
end
return trajs
end
rt_stream_df = _release_data("rt_by_release_by_stream.csv",
_by_stream_schema)
rt_stream_fig = plot_evolution_by_group(_fit_groups(rt_stream_df);
trajectories = _rt_trajectories(rt_stream_df),
ylabel = "Reproduction number",
title = "Reproduction number as data accrued, by dataset",
released_label = "Released estimate (per release)",
refline = 1.0,
empty_note = "No per-dataset reproduction numbers saved yet.");Basic reproduction number by release
The basic reproduction number
Basic reproduction number per release with frozen re-fits and the current-fit band
# Per-release R0 points from r0_by_release.csv, read through the typed
# fallback so a missing or header-only file (until a release carries
# `rt_state.log_R0` in its posterior draws) does not break the build. The
# schema mirrors rt_by_release.csv.
_r0_schema = (; release = String, date = Date, median = Float64,
lo30 = Float64, hi30 = Float64, lo60 = Float64, hi60 = Float64,
lo90 = Float64, hi90 = Float64)
r0_release_df = _release_data("r0_by_release.csv", _r0_schema)
r0_release = [(string(r.date), r.median, r.lo30, r.hi30, r.lo60, r.hi60,
r.lo90, r.hi90) for r in eachrow(r0_release_df)]
# The current model frozen at earlier cut-offs, one discrete estimate per
# cut-off, reusing the same frozen fits `frozen_matched` above already
# computed. No extra fits are run. Each tuple carries the median and
# 30/60/90% credible bounds of that frozen fit's own R0 draws, unrounded
# since R0 is continuous.
frozen_r0_matched = [(c, _ci369(frozen_R0(c); round_fn = identity)...)
for c in _frozen_matched_cutoffs]
# The current fit's R0 posterior is a single distribution rather than a
# daily series, so it summarises into a flat 30/60/90% reference band. The
# window runs from the earliest mark on the axis, the first frozen cut-off
# or release point, to the current cut-off, so the band reads behind both
# series rather than only their recent end.
r0_reference = let
draws = r0_walk_draws(chn_joint)
q(p) = quantile(draws, p)
first_date = min(minimum(Date.(_frozen_matched_cutoffs)),
isempty(r0_release_df.date) ? obs.cutoff :
minimum(r0_release_df.date))
dates = [first_date, obs.cutoff]
(dates, fill(q(0.35), 2), fill(q(0.65), 2), fill(q(0.20), 2),
fill(q(0.80), 2), fill(q(0.05), 2), fill(q(0.95), 2))
end
r0_evolution_fig = plot_estimate_evolution(r0_release;
renewal = frozen_r0_matched,
renewal_label = "Current model frozen at earlier cut-offs",
trajectory = r0_reference,
ylabel = "Basic reproduction number",
title = "Basic reproduction number as data accrued",
released_label = "Released estimate (per project release)",
trajectory_label = "Current model, current data",
refline = 1.0);Basic reproduction number by release and dataset
The basic reproduction number estimated at each release, one panel per fit, the by-dataset counterpart of the figure above. Panels share a calendar axis and a y range, and
Basic reproduction number per release by fit
# Per-fit R0 flat reference band, the by-dataset counterpart of
# `r0_reference` above, a single distribution rather than a daily walk, so
# each fit's band is flat across its own release window. `r0_walk_draws`
# probes for the walk base, so a single-stream model built without its own
# renewal walk drops its band instead of erroring.
function _r0_stream_trajectory(chn, dates)
draws = r0_walk_draws(chn)
isnothing(draws) && return nothing
q(p) = quantile(draws, p)
first_date = isempty(dates) ? obs.seeding : minimum(dates)
ds = [first_date, obs.cutoff]
(ds, fill(q(0.35), 2), fill(q(0.65), 2), fill(q(0.20), 2),
fill(q(0.80), 2), fill(q(0.05), 2), fill(q(0.95), 2))
end
# Build a fit label => trajectory dictionary from a per-release R0 table,
# restricted to the fits `_stream_chains` names, the same restriction the
# reproduction-number-by-dataset trajectories use. A fit with no row in
# `df`, or whose chain carries no walk base, gets no trajectory, so its
# panel still draws its release points alone.
function _r0_trajectories(df)
trajs = Dict{String, Any}()
for (fid, cfg) in _stream_chains
fdates = df.date[df.fit .== fid]
isempty(fdates) && continue
traj = _r0_stream_trajectory(cfg.chn, fdates)
isnothing(traj) || (trajs[get(_fit_labels, fid, fid)] = traj)
end
return trajs
end
r0_stream_df = _release_data("r0_by_release_by_stream.csv",
_by_stream_schema)
r0_stream_fig = plot_evolution_by_group(_fit_groups(r0_stream_df);
trajectories = _r0_trajectories(r0_stream_df),
ylabel = "Basic reproduction number",
title = "Basic reproduction number as data accrued, by dataset",
released_label = "Released estimate (per release)",
refline = 1.0,
empty_note = "No per-dataset basic reproduction numbers saved yet.");Comparison with McCabe et al.
Our model is a discrete-time renewal model with a time-varying reproduction number and every data stream fitted jointly. McCabe et al. published their estimates as scenarios at fixed situation-report cut-offs, each scenario carrying a 95% confidence interval. We show all three, the 18 May report, the 20 May update and the 27 May Lancet publication, as one panel each, with their intervals kept. Within a panel each method and scenario family is a single line, carrying its sweep over the nuisance assumptions: the case-fatality ratio, the geographic window and the doubling time. The geographic-spread scenarios come from exported cases and travel volume. Their back-calculation-from-deaths scenarios differ between the reports, since the 18 May report used 88 reported deaths and the 20 May update 131. The 20 May update also corrected the case-fatality ratios. McCabe's scenarios estimate cumulative cases at their report dates, though their report is not fully explicit about whether this is symptomatic cases or all infections. We take the like-for-like quantity to be our cumulative symptom onsets on the same dates, not the latent infections (which include the not-yet-symptomatic) or our current cut-off total. We read our value off the joint fit's cumulative-onset trajectory at the grid day for each report date, and show it with its credible interval. Each scenario sits beside our estimate for the date it was made: the 18 May report against our 18 May value, the 20 May update against our 20 May value, and the 27 May Lancet publication against our 27 May value.
McCabe scenarios with uncertainty against our estimates
function _ci90row(xs)
(round(Int, quantile(xs, 0.5)),
round(Int, quantile(xs, 0.05)),
round(Int, quantile(xs, 0.95)))
end
# Our modelled cumulative symptom onsets on a McCabe report date, read off
# the joint fit's per-draw `cumulative_onsets` trajectory. The grid runs to
# the cut-off on day `n`, so the day-index for a date is `n` minus the days
# from that date back to the cut-off (`grid_day("2026-06-07") = n`,
# `"2026-05-20") = n - 18`, `"2026-05-18") = n - 20`).
_onset_trajs = let mat = chn_joint[:cumulative_onsets]
[collect(v) for v in vec(collect(mat))]
end
# Inverse of `grid_date(day) = obs.cutoff - Day(obs.n - day)`: the day-index
# whose calendar date is `date`, using `value` (imported above) for the
# day count rather than the non-exported `Dates.date2epochdays`.
_grid_day(date) = obs.n - value(obs.cutoff - Date(date))
function _ours_on(date)
d = _grid_day(date)
_ci90row(Float64[t[d] for t in _onset_trajs])
end
# Our matched cumulative-onset estimate for each report date, keyed by date so
# it lands beside that vintage's scenarios in its own panel.
mccabe_ours = Dict(
"2026-05-18" => _ours_on("2026-05-18"),
"2026-05-20" => _ours_on("2026-05-20"),
"2026-05-27" => _ours_on("2026-05-27"))
# One panel per report date; within a panel each method-and-family is one row,
# with the case-fatality / window / doubling-time sweep dodged onto that single
# line, so the ~40 scenarios keep their intervals without becoming ~40 rows.
matched_comparison_fig = plot_scenario_comparison(REPORT_SCENARIOS_CI;
ours = mccabe_ours,
date_titles = ["2026-05-18" => "18 May report",
"2026-05-20" => "20 May update",
"2026-05-27" => "27 May (Lancet)"],
xlabel = "Cumulative cases");The McCabe scenarios are outbreak-size estimates, the same quantity our renewal model and the released integral model report. Their 95% confidence intervals come from exact negative-binomial counts for the geographic-spread method and a Poisson likelihood profile for the back-calculation from deaths.
Frozen-fit C_T intervals (kept for the CSV export, not shown)
# The estimate-evolution figure above already shows how the size estimate
# shifts as data accrues, so the side-by-side frozen-fit table is no longer
# rendered in the report; it is kept only to populate the published
# `frozen_matched_cutoffs.csv` export.
frozen_streams_table = streams_table(
"frozen 20 May" => frozen_C("2026-05-20"),
"frozen 23 May" => frozen_C("2026-05-23"),
"frozen 27 May" => frozen_C("2026-05-27"),
"frozen 8 June" => frozen_C(default_chamla_cutoff()),
"current data" => posterior_C_joint);Comparison with Chamla et al.
A second group, Chamla et al. (Chamla et al., 2026) at the World Health Organization Regional Office for Africa, published a stochastic compartmental model of the same outbreak on 25 June 2026. Their model is a discrete-time susceptible-exposed-infectious-recovered-dead ensemble, recalibrated by simulation filtering to the laboratory-confirmed case series and anchored on the 598 confirmed cases reported by 8 June. It is then run forward to project the confirmed-case trajectory under a low, central and high transmissibility scenario.
Their published quantity is the cumulative confirmed-case count, with the reporting fraction held at one, so it does not adjust for the cases that are infected but never laboratory-confirmed. This is a different quantity from the cumulative cases this analysis and McCabe et al. estimate, which include the unconfirmed and unascertained. It therefore sits below them: a floor on the true size rather than an estimate of it. The like-for-like comparison is therefore against our own confirmed-case projection, not against our cumulative infection count.
We compare forward projections rather than refitting to their assumptions. We take our fit frozen at 8 June, the exact date of their confirmed-case calibration anchor. We roll its confirmed-case stream forward to the dates Chamla report, using the same machinery as the one-week-ahead forecast. Setting our projection, their projection and the confirmed cases observed since on one timeline shows how each projection has held up against the data.
Project the 8 June fit forward and assemble the Chamla comparison
# The 8 June frozen joint fit matches Chamla's confirmed-case calibration
# anchor exactly and carries the confirmed-case testing history through then,
# so we roll its confirmed-case stream forward with the one-week-ahead forecast
# machinery to the dates Chamla report.
chamla_anchor = frozen_by_cutoff["2026-06-08"]
# Our projected cumulative confirmed cases at a horizon of `h` days past the
# 8 June cut-off: a forward `forecast_reported` run (its reproduction number
# left to keep evolving), summarised as (median, 5%, 95%).
function _our_confirmed_h(h)
fc = forecast_reported(chamla_anchor.chn;
horizon = h,
obs_cases = chamla_anchor.o.reported_cases,
obs_deaths = chamla_anchor.o.total_deaths,
obs_confirmed = chamla_anchor.o.confirmed_cases,
obs_confirmed_deaths = chamla_anchor.o.confirmed_deaths)
return _ci90row(float.(fc.confirmed_cum))
end
# Our projection at Chamla's forward report dates (10 and 24 June, week 12):
# the anchor day is the fitted confirmed total at 8 June, each later date a
# forward forecast. Reused for the matched-date table and the week-12 figure.
chamla_fan = map(["2026-06-08", "2026-06-10", "2026-06-24"]) do d
h = value(Date(d) - chamla_anchor.cutoff)
row = h == 0 ?
(chamla_anchor.o.confirmed_cases, chamla_anchor.o.confirmed_cases,
chamla_anchor.o.confirmed_cases) : _our_confirmed_h(h)
(d, row...)
end
_fan_at(date) =
let r = first(x for x in chamla_fan if x[1] == date)
(r[2], r[3], r[4])
end
ours_10jun = _fan_at("2026-06-10")
ours_24jun = _fan_at("2026-06-24")
# Observed confirmed cases over the comparison window: the daily cumulative
# series read off the chain's grid from 18 May (Chamla's first projected point)
# to the cut-off.
chamla_obs_series = let
ds = [grid_date(d) for d in obs.confirmed_history.days]
cs = obs.confirmed_history.counts
[(string(ds[i]), cs[i]) for i in eachindex(ds) if ds[i] >= Date("2026-05-18")]
end
# Chamla's central confirmed-case projection over the comparison window; their
# later, far-larger horizons are noted in the text rather than plotted so the
# window stays legible.
chamla_central_window = CHAMLA_CONFIRMED_CENTRAL[1:4]
chamla_projection_fig = plot_projection_comparison(;
external = chamla_central_window,
ours = chamla_fan,
observed = chamla_obs_series,
external_label = "Chamla et al. central (R₀=1.71)",
ours_label = "Our projection (from 8 June)",
observed_label = "Observed confirmed",
title = "Confirmed-case projections versus observed, from mid-May");By 24 June their central scenario projected just under a thousand confirmed cases, and their low and high scenarios ranged from roughly 870 to 1360. The figure below sets that week-12 scenario spread beside our 8 June projection for the same date and the confirmed count observed by the cut-off, so each reads against their three scenarios at a glance.
Week-12 (24 June) scenario spread against ours and observed
chamla_w12_rows = vcat(
[(label, m, lo, hi) for (label, m, lo, hi) in CHAMLA_CONFIRMED_W12],
[("Our projection (from 8 June)", ours_24jun...)],
[("Observed by 23 June cut-off", obs.confirmed_cases,
obs.confirmed_cases, obs.confirmed_cases)])
chamla_w12_groups = vcat(fill("Chamla et al. scenarios", 3),
["Our projection"], ["Observed"])
chamla_w12_fig = plot_estimate_comparison(chamla_w12_rows;
xlabel = "Cumulative confirmed cases by 24 June",
groups = chamla_w12_groups,
group_colours = ["Chamla et al. scenarios" => :steelblue,
"Our projection" => :firebrick,
"Observed" => :black]);The matched-date numbers behind these figures are in the dropdown below, with the observed column taken to the 23 June cut-off.
Matched-date projection numbers (10 and 24 June)
chamla_comparison_table = let
fmt(t) = string(t[1], " (", t[2], "–", t[3], ")")
central(date) =
let r = first(x for x in CHAMLA_CONFIRMED_CENTRAL
if x[1] == date)
fmt((r[2], r[3], r[4]))
end
DataFrame(
"Date" => ["10 June", "24 June"],
"Chamla central (90% PI)" => [central("2026-06-10"),
central("2026-06-24")],
"Our projection (90% CrI)" => [fmt(ours_10jun), fmt(ours_24jun)],
"Observed confirmed" => [
string(freeze_observations("2026-06-10").confirmed_cases),
string(obs.confirmed_cases) * " (23 June)"])
end;| Row | Date | Chamla central (90% PI) | Our projection (90% CrI) | Observed confirmed |
|---|---|---|---|---|
| String | String | String | String | |
| 1 | 10 June | 648 (470–812) | 680 (618–825) | 676 |
| 2 | 24 June | 990 (709–1293) | 1684 (868–4131) | 4945 (23 June) |
Beyond the comparison window their central scenario continues to roughly 8200 confirmed cases by mid-September, with the high scenario far higher. Those longer projections are not set against data here.
Reproduction number behind the projection
The forward projection above is carried by the reproduction-number trajectory our 8 June fit estimated, a quantity we report in its own right rather than as a comparison. The figure shows that trajectory, the time-varying reproduction number from the renewal walk with its credible intervals, as the fit saw it at 8 June. It declines over the weeks leading to the cut-off, and that decline is what bends the projected trajectory away from sustained early growth.
Reproduction number as estimated by the 8 June fit
# Reconstruct the reproduction-number trajectory the 8 June fit estimated,
# mirroring the current-data R_t figure but with the frozen vintage's own grid,
# breakpoint and renewal start.
chamla_rt_obs = chamla_anchor.o
chamla_rt_breakpoint = chamla_rt_obs.n - chamla_rt_obs.who_first_sitrep_days
chamla_rt_start = clamp(
chamla_rt_obs.n - round(Int, chamla_rt_obs.tmrca_days) + RENEWAL_START_LEAD,
1, chamla_rt_obs.n)
chamla_rt_fig = plot_rt(chamla_anchor.chn;
n = chamla_rt_obs.n, breakpoint = chamla_rt_breakpoint,
rt_start = chamla_rt_start,
rt_walk_start = clamp(chamla_rt_breakpoint - RT_WALK_LEAD,
chamla_rt_start, chamla_rt_obs.n),
as_of_date = string(chamla_rt_obs.cutoff),
seeding = chamla_rt_obs.seeding, ramp = RT_INTERVENTION_RAMP);Delay sensitivity
The death stream dates the outbreak from how far deaths lag symptom onset, so the assumed onset-to-death delay sets the implied infection count. The baseline uses the hospital-pathway delay from the Isiro 2012 line-list reanalysis (onset to admission then admission to death, implied mean about 12 d). We re-fit the joint model under the community-pathway delay from the same reanalysis: the delay for deaths that occur in the community without a recorded admission. This delay is shorter (implied mean about 8 d). Both pathways come from the line list, so this varies the actual delay assumption rather than an arbitrary scenario. The re-fit uses the full headline settings: 1000 draws across two chains.
The infection count to date shifts with the assumed delay, and the table and overlaid densities below show how far.
Re-fit the joint under the community-pathway onset-to-death delay
# The sensitivity re-fits (community-delay variant) are
# defined in the fit registry (`docs/fits/registry.jl`) and loaded through the cache
# (when enabled) in the setup block above.
posterior_C_community_delay = RUN_SENSITIVITY ?
vec(Array(chn_joint_community_delay[:C_T])) : nothing1000-element Vector{Float64}:
10632.537206424577
11283.607026976368
11624.93993988455
10829.293391015963
12267.495308879432
8890.281119643525
12813.026935068274
10826.548809773532
6828.659822583069
7952.333528985428
10680.810642709106
11652.367362672732
13607.803761135647
13029.233854630284
14542.476324907155
14123.691028190924
10896.61303922698
11207.137483097056
11412.640213474711
9251.299669325388
11714.381611850406
13393.943349278177
13517.649138686867
10046.862580092937
12874.139971998518
12587.001986383784
9885.239860165055
12981.993614672736
10051.519599617845
11151.170139318561
10422.070692351026
10413.929782808475
8199.656278014085
8356.99843446822
7574.741381002474
8726.34535009154
8714.17366309482
8637.33245506873
12910.218529644864
14298.136400751911
8115.048371640211
8646.928786817412
10676.974748447956
8963.425700993817
8403.726802475961
8730.79824053098
8696.330271693532
6966.065041912457
9118.200099971013
7892.555544922882
13418.619376045588
12072.898881056299
10769.447096202945
10099.209616792907
12656.544911596093
11187.788243620613
9566.519029213094
8361.597419733462
8206.169646419286
8660.57343355256
9111.102655808232
8956.332036147685
9092.567973943755
10866.399910821372
15240.468687345538
11540.560278438137
9568.142788504118
13364.179711319834
10536.658986208768
11861.70520191364
7271.953939288677
8831.800012668926
8624.694891837975
8381.728427635571
11768.105652862943
9229.338244745106
10126.342439097427
8493.577538822412
10124.969228167478
10410.153943815652
13752.900927178358
13079.082033854336
11976.276019228137
11266.317360108715
13604.234964934582
12009.125837038944
7947.559132193963
7433.131384673237
14941.989422319582
9313.695265961715
8874.46840839478
9916.443172805486
12195.166128814313
7507.3893485317885
8378.819478939182
7915.79153326147
8923.70904033543
16103.272663837168
10936.814156006372
8117.25242558596
8357.328521926207
9198.542714006293
10159.122851706037
8539.438170002051
8224.295290584161
8441.062854059668
12076.521087491223
10513.33561915695
7817.714172405614
8460.59139610297
8886.895669259879
8883.478292595675
9366.950088854514
9208.038113412396
15598.755521914138
11004.474665877748
10080.833863547654
10204.033368616852
7466.616413974688
8111.312596718938
8849.935982723355
8726.438404874752
8869.26606802902
6863.431468612496
7673.771902948694
9481.55867149255
8908.71357626398
10157.371417627055
9572.892351015402
16451.95073525203
11150.697069714592
14876.128768152768
9640.156416786587
14750.321747101709
7658.008297343092
12526.957318037721
11737.195764610158
12473.963447459713
15217.260372775345
15191.570441419939
8552.250298151303
10705.733203634656
8964.925078540859
9119.537487474841
11152.20372597219
9171.10298992843
7644.26783511409
7976.760057385417
8365.707754584742
11802.270628511911
12333.826154933959
8600.266810743577
10007.401089522838
10952.100464815983
9802.742244422505
8414.13288857385
8868.188032524617
9506.970482123828
8821.174856965252
8373.655536677448
7753.400025416013
8150.65363390765
10297.146198441083
9417.243868546517
8925.354564359817
13473.17992777221
8831.14640717416
13147.424953777645
20308.7457023023
15118.351385654014
14368.980508505716
11085.24048985388
10369.773640703197
11588.981579617212
11020.330477061723
13801.608437553645
15246.208367288988
13105.862635301137
14347.019872368928
9204.51712839386
9399.606442274653
9410.724349210792
8172.362704028965
9850.121162182279
10602.168407376488
10108.007701531025
11260.20784372248
11726.664797233449
9258.831925514916
15301.745509545748
8344.108746051292
9576.909008858225
14007.129558485702
14929.148553588973
12984.686795154863
9021.943562929038
14934.792584949186
11826.847467736206
9509.523449453536
10469.997022453388
8841.116315592664
8401.665843398605
10996.205992009385
11624.900784175737
9836.237611783405
10680.57945424421
9334.87237599776
9312.807616954498
12424.334918424827
8126.056976042746
8359.951587330259
9572.245262601393
8690.896645278899
10255.9048125615
9878.596295978157
9107.00105820004
7261.435760375273
9614.480266997456
10173.21625038175
9270.266524270084
12960.668455049028
9658.912756089332
11197.6093036021
11028.772524815047
8263.60633518175
14612.385462153961
9422.178702950894
9049.185234047698
10863.751490558692
9589.767450231162
12744.236903664067
11680.340151468052
12325.413860811774
10706.992583732695
8630.106172915124
8479.378417209255
7904.064770552455
9187.079531410322
8382.20271179638
8508.78027025349
19880.434942334345
16408.640590343428
15293.136101107491
12263.44368682357
16095.874898772725
14564.579060032553
9621.091394428504
8704.550723842493
10753.873195235285
8636.763183127656
10843.491576167175
12411.141831036784
8740.468493159864
13775.506367501206
9969.756207372531
12805.86257263569
10332.43096250318
8769.716140295433
9608.82449884646
13379.90645509437
14492.016651020813
8843.636294990923
10921.859737058341
9472.049260723019
15589.41424151006
14876.529543045694
11728.196803173847
13001.348682294629
11601.141129840707
8641.95992405505
13587.096059383188
8178.044590114791
9732.22885197648
11397.832778402319
9301.946707974967
8234.209921430262
8369.092530896212
8511.923134818604
9012.747533807635
7203.545058883268
6978.893330783769
7201.156006644664
7525.871091745492
9693.252307828803
8848.707030553533
12397.79971187136
7491.305514407672
14787.65374345456
15732.286905559213
14614.49352052011
14268.452538011428
11014.033988312232
12242.240091133055
10062.80491756324
11525.27067480459
8470.29438731237
8521.682181918355
7741.086486859099
7816.521652564639
10794.505341814696
8141.883329390777
9715.620804089489
15166.909403319323
16129.15561930787
10452.66693405797
11880.266596928968
7908.906778917018
8268.81960400472
12635.881334360893
12031.841435149903
9221.256216886213
9956.938539582456
12819.075728311347
11315.506510654237
11823.01365405847
15002.107395066598
13511.816860642473
11161.029005364948
15927.619209678993
10797.126200957033
9176.944327064044
10388.37240611718
10244.05185495981
8843.21263433318
9988.371604183232
8884.378445905139
10292.956929216989
14106.517707917308
9362.180118488704
11774.591401459726
12620.5282666053
10378.44826851118
13132.294444693147
11659.138332094242
10655.628386273489
13471.45748533711
8652.753067831369
9044.87387136503
14205.268928327381
15070.615467628257
14192.010139057444
18513.651674957837
16641.876016292503
9980.08496674658
10691.061300989635
11058.535500182363
9137.221944626086
15201.797576255109
6701.282790187535
10047.794125712213
10721.2141598196
10395.462290738375
11970.820718478868
10850.825990404604
9718.01001172335
9602.0230716591
9780.002620114927
11187.167867968123
11092.456688115522
10066.992290087846
11489.313469891595
9349.291785645459
9209.68338366366
9121.866478010921
11154.618478687315
14201.357658243987
8893.0157006176
9591.479974876906
7894.929758626521
10777.935642212926
13313.313670589068
12129.900206724406
10116.498701033432
10122.549251344471
13130.781689190228
10493.985491974412
10301.134194506427
9866.123742261825
8486.076131013882
8773.147681921537
12060.218948269841
8986.06268972074
7635.761118860175
10782.488245619923
10197.759526928588
8965.147329270478
8807.725019734362
8729.595944406125
8094.9080588173765
12988.851679150648
8701.664697281876
11643.055900075673
11626.013759289519
10898.020254897281
10120.954316784506
9143.501169784335
9617.729642048716
8585.848584641622
10677.866952784094
8885.23238685238
12099.941351679281
11064.936356355907
10907.113205221383
11188.828403587562
13851.183796434045
16652.75047201836
10747.308098361398
12386.852839526455
11688.008337495816
9169.108159973195
7409.48824382883
7260.900015677748
8798.904733733878
14433.909379778741
20850.106571344582
18176.662817087195
12596.674626953354
12858.439135890902
8921.495267413753
8288.249419961456
7906.389812917213
7335.438871459062
8480.069079105171
9193.763439191845
9350.809461082372
9849.423210695824
10237.582198263426
10730.538421762547
7154.309959914862
10346.867294287771
8634.972430218073
10520.787287691686
8293.598869425992
8338.369530354938
10996.26292265694
7862.661694238033
8975.805833895976
11315.710780413614
10117.607399053166
9796.842197029706
9494.738887302996
11312.37613495044
13903.99894103678
13027.779556936113
9614.491326946361
12174.499024179462
12248.637521765137
15308.794108346872
11133.85343484901
8788.248257463765
8193.699045436091
9011.929978698752
9960.345743775577
17835.87121854838
10985.382285872352
10466.6856569791
15178.171114401035
12105.461634733625
15131.35979693663
12258.085738590682
12987.281547520608
14862.978322175244
12564.35443069998
10465.987284139437
9966.366885434127
15606.990106033893
9527.798991468733
9459.183538036023
11433.04838774965
10649.18131653526
13615.52620378252
16240.981193717496
15513.564799681873
11982.03246788051
10331.030098233758
12640.72897379387
11417.319139081459
10249.010942439947
15850.085792641597
9570.399962045236
7820.917262111036
7529.16559722318
7665.226371910361
7449.949897228707
7648.113140997971
9020.835332808074
12814.835112325109
8391.860793567634
7290.286097722601
9131.285603459086
9223.395046247373
12081.379060031537
11251.462312798822
11027.896717511394
15722.968725172112
10202.783108308551
12162.312507371775
13275.664125513784
11055.382756374122
9221.4807316713
13690.502467570466
12695.409520104426
12409.022090661703
8676.590546328556
10519.97007842747
15312.340902258411
16535.413487744165
10434.257604767214
13211.786210435514
8588.319417717925
12906.971129682926
12500.01751521001
10454.62891623361
10508.097838295997
11050.05978550801
12626.208506438248
11160.905025759605
11195.40102800502
13872.57706937082
9986.253265160913
8540.522122175154
10820.06501763447
9022.25175473209
9204.227220974317
10691.937875557913
11323.490439876488
13058.828745225519
9346.278042484779
8177.170340265574
9011.283737707037
7143.174578043505
8981.987122945584
7698.156152148425
7818.292806764009
7356.418706450508
7742.359562204912
15446.70910364013
7714.989818377116
8461.90804797484
7462.336668159352
10893.724166731858
8852.147074716742
11259.309723988075
15562.579804026414
13185.61599598366
8904.297618482691
12809.69702437165
14283.581416742858
14106.059373506929
12086.9563765284
9871.663410741381
13240.424734574855
9235.471132357088
10078.795616965463
8666.869476429783
15953.62481132278
11969.67736114648
8147.589039035924
8155.349924606748
17577.92777947747
15270.780588486694
18297.542796716694
10035.599617204845
9701.95897188773
7071.0815443874935
17539.95636518836
18746.414005768856
13623.557938532778
8425.082668134568
7943.969603829746
12076.669311418618
7975.8359578054105
12130.828171542355
11564.607988674607
12970.818953300302
9751.457316803126
12553.291011452211
19173.712333295367
13600.287538870147
9020.873476852057
12138.927162860899
11499.795700726932
10361.222494662901
9556.556531680091
14404.454612358408
24705.71149067331
14987.79827416944
14546.603685068922
8801.856140487947
13194.51036007067
11989.267274571197
8767.429110974856
12036.85458421614
11060.583472750832
9540.739937513052
8044.802876632302
8770.564980375857
11521.378315673148
10260.914127259584
11718.118386354927
7218.4094054488
10812.943555501086
10434.380030220484
13570.530614173409
15690.758944769606
11222.423809035594
14413.815516093866
12930.113337561621
9556.496621249622
11295.308822950277
8546.766699386784
10564.826029338665
12324.736800395218
11461.396204163808
8799.82533036411
11149.488133204022
7358.484478212419
14010.204145140286
11124.72843073944
12793.153793948566
10697.044956137763
10879.178231236212
9962.10071795187
9523.078111537363
14334.19573653884
9789.1302113603
12148.57077556933
9917.140716601773
9219.749080325992
10384.932746143142
11341.209960081307
8098.157559712576
7971.743747934935
8515.613064254747
9839.621076490223
9322.150854446025
9694.215627210966
13077.865805934656
8847.962397398947
8550.351378034618
9595.863723206048
8617.74420434296
11562.244883946545
8844.26759833411
9347.778583697916
12092.727348513718
9207.013373086762
8152.68723081552
8107.743354607696
10593.199341833986
10592.501145316972
11789.730468315644
9100.868157785064
12009.686872926874
11571.302308498527
9845.4852013352
10293.034040382969
13269.812901833275
11268.998954147648
8692.57062642415
10207.536493301764
7622.715289864725
8949.522513749973
11336.546424782848
10804.936160573578
13846.714078099674
11855.933943541813
8948.621979862937
10879.286809672112
8800.644270223267
8360.033553477093
9500.324046910531
9871.615311678106
8886.69309619541
11835.62202888529
10269.576211199352
7240.805621989553
7512.6105860359885
9052.982779080794
11306.125230744141
8819.646142754998
11848.247773542535
7941.201293978249
17855.56957631434
11098.923064654318
13009.349192778585
8222.474803577628
9812.953201641823
13584.156066753503
8671.712897752106
11516.413594935086
14213.593326227558
10937.280640613366
12160.45675808198
11073.841772162656
8916.450306064711
10786.143964806894
9308.655749519641
10936.847236441685
9182.049495664034
13102.785098673625
10893.41149476199
9931.574869755923
10684.4216122282
10292.138433197042
8442.380253741401
12709.275838948142
11249.354099342427
17664.80648930463
14905.665623046589
16232.24928177066
7722.511442540008
15808.846443319868
7839.783636739974
24441.74094392399
11452.729770519627
13200.472916214381
9206.156492791368
9322.84522844477
12019.089787415467
9329.722948272689
10019.964064092112
9335.189299044257
12459.065631125464
12038.259252209988
10239.480067276549
9142.54847315636
7924.3213226760745
7632.71056097715
13664.628611181772
8524.029886535573
12606.175483158313
9355.344442692713
18360.181098822613
11386.905686453747
11322.93494754856
8155.998679898314
9932.950924197947
8762.063421712437
10296.723293416719
9110.095477959298
9618.467305090568
7373.678567320272
7707.7483231688975
9058.508423442983
10827.227193852596
10618.400819335899
13121.617903588785
10853.96715403711
16604.602390339503
11484.620183958748
9355.586061328344
8262.173946455023
10167.760942139425
10115.802729720586
9407.001343578086
9668.458560756779
8467.533348070607
9179.856830201448
11325.337035072298
8375.75650696404
11402.453509267094
10858.882412338677
11114.404502858433
9999.239099221346
9735.632579294232
12688.519366095954
8330.839421830833
10607.004472072767
11990.948330459922
11482.627425522449
11108.295901045096
9469.246403137122
10822.209549552535
11432.007987691535
10702.711038176782
9020.765359462132
11834.466911239619
11758.040207742328
8246.969446070107
11293.12056390893
11156.220987574263
7430.1870141257195
11518.402538022958
9818.74128786626
8185.129917032101
9272.328638498286
10749.227248333116
8103.5492546264995
12670.539619311376
12646.485566189793
15798.819278745883
7831.981252833917
10189.616863781954
7302.901508477077
9532.054036297799
7829.6694971906
8269.272058173487
11223.78135182403
14406.361982109995
11337.758616284225
11013.763979615222
8708.060981205432
17383.726213439782
10003.996690407816
15419.70233785188
11006.586613671287
13303.686405588482
11033.568097614607
8454.200791971183
8195.160546480649
11321.846574737754
8289.917204689353
11572.143043074806
10275.75507666526
9144.692450596718
7654.212435048704
10532.193461337698
10500.33344900911
12633.32234833739
14763.985644003675
8467.557010042308
11630.33958526073
8325.27168915592
9756.913640963889
10588.773581072179
7498.5887512225545
9081.514217970138
8144.438298276562
9128.596648602243
8485.84971579958
12025.706299041813
10522.945427912988
16280.413966663424
15636.720072925858
13130.018124610157
11203.61290925099
14343.350997375639
8861.14270757986
9543.76201535332
17597.60257407307
13933.364876581909
8846.801833683854
7644.437662094297
9775.940938356198
7970.947384330672
13244.124263780346
9397.15642389484
13206.760716548313
15140.33028701553
10407.640756694904
10173.28886782925
12144.95896780349
9763.986048453908
17747.2964328505
16321.877478108894
15620.185802303724
11887.69459675918
12492.15942859388
10270.931696605894
14385.53751603702
14380.594896261784
9864.567086840394
11996.501589894588
9612.818280448775
12710.143242882315
15941.757450628445
16210.32115707974
14515.331028824849
16688.323529725574
8089.179459899234
18502.273436203082
8637.454529249353
10029.544367821936
14998.216744117555
8533.250201970879
12174.782634995932
13252.963282700068
14612.003799634498
9455.01098776065
10888.289665217133
17192.772021442095
11492.6130649417
9896.089106995109
9947.826223123911
15193.195371378828
12214.803167775555
9518.766564066058
9416.108479923952
11349.246569060515
9595.476020473914
10334.454951771342
8857.242589146364
10077.3555264326
10234.659423416117
9307.612775676545
9036.02771456153
9215.339832642925
9800.294483856755
11025.91260143389
10904.111493421078
9335.572076506985
8587.296275275952
11034.699509130185
9746.597904166589
9452.150009457184
9295.251522626535
8556.495037639925
8940.289373799516
10418.44174228374
12085.908687817022
12042.139985041114
12058.091380627071
9761.48076099551
9179.215293951214
8941.984356584551
7913.354378692303
7726.54728851407
11010.715097032666
12638.015397076275
13770.969771476017
8839.541824162221
11779.75116647057
11157.203181663981
9953.342984564582
8435.6484455605
9688.29642821766
9156.345461341078
8922.787017989778
9098.056889202633
9447.14887805639
9816.531757845998
11605.821711641824
10104.747757200284
9978.354451179332
11649.704623255442
10727.143430344178
8313.704822816806
8567.466208389791
8251.921952041292
11620.090889730316
16312.45838834975
10541.96279752078
10607.8861551755
10865.592616449545
10812.329686648667
9432.30775183757
9622.312957002798
12930.534643488067
7900.80577219905
7813.664860327864
13695.170395172934
11808.25788449556
15460.701590354065
12205.592316440308
13482.132410200667
9434.183685529862
8860.475020219255
10048.03622969762
9684.073618657763
7469.376649960362
8602.291997027278
10112.728910430395
10346.00671831921
7564.21703429963
10271.935049762513
8103.672976272278
10716.292485544704
13242.287549230547
13349.367740406948
11608.275418650193
14072.496197403756
8666.972912371297
10396.522734564658
12542.932617427174
10615.963920383052
9030.648766161617
11909.128053678387
11299.18714521622
10493.824639514081
9457.65855033918
8613.494842627724
9160.616483003058
8022.808869548086
10642.801675255198
10156.546714407636
9749.78794131869
9918.19019100005
9068.312806243326
8470.220403341607
8034.229730646009
8168.154557240795
12381.057743209389
7727.610526876805
10215.399650953526
9302.87698561648
13533.44074128638
10088.850440992544
9156.879333951518
8672.119583794654Delay-sensitivity infection-count table
delay_sensitivity_table = RUN_SENSITIVITY ?
streams_table("baseline (hospital pathway)" => posterior_C_joint,
"community pathway" => posterior_C_community_delay) :
Markdown.md"_Delay sensitivity analysis not shown in this build._"| Row | Stream | Lower 90% | Lower 60% | Lower 30% | Upper 30% | Upper 60% | Upper 90% |
|---|---|---|---|---|---|---|---|
| String | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | baseline (hospital pathway) | 7983.0 | 9241.0 | 10172.0 | 12058.0 | 13333.0 | 16383.0 |
| 2 | community pathway | 7726.0 | 8713.0 | 9429.0 | 11254.0 | 12648.0 | 15590.0 |
| Row | Stream | Lower 90% | Lower 60% | Lower 30% | Upper 30% | Upper 60% | Upper 90% |
|---|---|---|---|---|---|---|---|
| String | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | baseline (hospital pathway) | 7983.0 | 9241.0 | 10172.0 | 12058.0 | 13333.0 | 16383.0 |
| 2 | community pathway | 7726.0 | 8713.0 | 9429.0 | 11254.0 | 12648.0 | 15590.0 |
Delay-sensitivity infection-count density plot
delay_sensitivity_fig = RUN_SENSITIVITY ?
plot_cumulative_cases(
"baseline (hospital pathway)" => posterior_C_joint,
"community pathway" => posterior_C_community_delay; scenarios = []) :
Markdown.md"_Delay sensitivity analysis not shown in this build._"Tree-prior sensitivity
The outbreak-age estimate depends on the coalescent tree prior assumed in the BEAST X analysis. The baseline uses the more flexible Skygrid non-parametric model, which dates the common ancestor to 15 March 2026 (
Re-fit the joint under the Exponential growth tree prior
# The Exponential-growth re-fit (and its `tmrca_days` offset) is defined in the fit
# registry (`docs/fits/registry.jl`) and loaded through the cache (when enabled) in the
# setup block above.
posterior_C_exp_growth = RUN_SENSITIVITY ?
vec(Array(chn_joint_exp_growth_clock[:C_T])) : nothing
T_skygrid = vec(Array(chn_joint[:T]))
T_exp_growth = RUN_SENSITIVITY ? vec(Array(chn_joint_exp_growth_clock[:T])) : nothing1000-element Vector{Float64}:
176.77001773167783
155.8872766419388
156.7366582844191
166.95166848419413
150.9787482711913
174.52077575595806
149.68048263898112
151.8034488833334
155.70722299439376
154.21107571327673
154.33356743567313
159.3389002135946
161.90942140519854
172.3388580345478
176.6043441730296
147.31680227702935
154.53796780470392
165.15158332660783
158.740001737569
155.43603692607454
154.21372012451928
163.900199892678
167.21483948742286
175.30466680315007
171.24250133920444
160.28037879518118
151.7576037235861
153.308120214451
152.97518384132846
150.37484684837148
161.5711088071252
168.19604690728798
147.7864240985308
146.19190852196013
158.84142182218054
175.34359797056308
160.74477911659596
163.3112227857894
150.00049117112394
152.14798549398736
151.10505405013927
163.11895996195582
174.57593951757124
148.324538578212
157.05843407477963
150.70487210466766
149.64523514245514
151.28794112931487
151.86166445669076
148.94348873656668
146.0411748823984
146.01709667488777
146.01951997629857
147.25455334857918
162.39858076610966
173.98373469334177
167.59266847375946
175.25054184557783
149.96382515398238
160.28157263973765
152.05935811132684
180.1547846852343
162.8918329328126
163.44264352865937
190.46127034867465
169.1013759653328
155.38348923669824
151.74328031444864
147.6692895515148
155.67988559019562
154.27324857482523
149.6200272174765
150.58929833163913
154.34104807296896
149.69837436934912
171.99606589351157
157.72472996948886
167.31904530935535
160.20070541694486
177.8525237343078
172.90506963692712
186.56829591521299
158.96972293819653
147.356371273177
146.74232850944094
172.2419729467857
169.36406100386165
146.47376332229297
166.99496749709306
146.79702588314427
156.3457604292784
155.66261617913062
149.60163325142594
163.37357598312062
158.89900743261197
160.68911580146064
156.75907143276692
173.39708402847953
163.5193989267077
151.57093156276912
151.41065023730283
166.75917737514692
165.82910247900548
155.5201974351333
157.03228099914048
156.5552028460723
157.30242095105154
149.30422332179668
157.77251212132222
163.17259385346497
172.56130169647753
146.42826376270094
149.51418856500476
200.65588976836506
237.10153585266457
185.32347325785477
153.38934819998096
163.5018542963483
146.21291496231794
151.69407757739407
163.8026904187604
152.10230950938885
173.48279867752404
152.66430875371984
150.2283982331994
149.8917736595448
162.7575864741246
147.55383507538647
164.39084310185694
165.33780159120872
157.61078252921027
165.6279186467571
169.35733342847627
149.30261096022548
173.15564616285533
148.44636764462217
157.68059900839103
152.31912605276514
151.2496138883874
161.34312245508977
158.24110475846976
164.52248158050503
158.06554744900018
154.4099207256037
157.21996687365893
154.4406745875022
154.87893173145872
155.15733668501724
160.81221698416417
160.2746266164244
157.20979430649592
162.99993319151847
153.53183038453722
166.49183296948627
147.47362656130306
153.0805104410947
148.0779958122016
153.99743356545713
158.20690239260387
170.49351949006052
153.0339764719149
147.82900707466487
148.07844085321875
165.0563117746911
154.96906990558998
152.59528361290234
161.74634737721223
154.14685177016602
154.68584689813784
162.91961736433612
161.69272431303614
148.98972542315985
160.98218954504395
156.560824660242
187.33197458669838
168.69209802565942
183.8154998361333
148.6983905192228
160.49599946240167
174.20721352099596
160.403741313638
164.91548864233928
162.07962807192501
152.40959547764288
177.0734642114972
158.44926501470238
155.61872871260135
163.58491121920974
147.99487028011583
147.5961944588906
162.12543595745717
156.98351990907514
146.60791026337378
181.77619206884637
158.2721219855763
155.85792884039722
151.5588122834508
149.3813903283446
161.78535716891705
157.60412248535684
146.19565038898506
146.39259257258584
183.82293120396886
159.16133543242253
154.05345371413296
154.2476744966096
166.33117014495218
152.19785266808444
170.0314592142055
166.8000012705309
160.4795691487917
154.41702864499524
175.45161070285167
154.22186202942862
162.8362541632726
179.6208700600539
147.32203847993418
147.99147892043604
174.94498766860912
175.56765151380597
147.74922486559285
150.26776941195112
155.01669607525736
150.4303858610333
150.68715381670285
153.1515717807405
155.6765924300872
163.12836865811454
146.72248019087675
180.39899602278732
146.8683921844142
182.9961695975313
166.40360112169628
150.06281232639824
151.2933616091089
159.59667023599837
156.20410538038098
151.3307968583434
166.64014217306664
150.85775151381608
154.6107283152922
147.33400292457176
159.1133304797428
158.35053922951883
152.62609394961325
154.46456970691796
155.685184531493
153.72518619992508
150.81379299078245
160.94323154922353
146.33683568167126
156.3324670730671
187.86536544494467
149.10979274240682
156.01571913173547
153.61858514817126
167.88906111390756
163.19966502474503
160.50075276034835
175.63613684587543
184.98876632378602
147.02403008974227
176.00323059778742
165.46766800914043
189.65792889497442
151.8930085746542
157.43225974071436
151.44950113985112
177.87233896366305
172.53419840667794
146.2285168990999
146.84011847708092
158.1039402668116
156.6432510396488
155.54100439536688
154.54964382711628
146.55600239829573
146.43082556594413
179.74365387501553
148.46494129033337
150.921943692843
154.78515618695124
160.54699590907228
153.67240939721393
149.44557872564556
157.0641482125325
146.0648894396985
165.91788396026328
147.88610782796675
156.48214174539112
146.30373747476997
146.461745477656
169.09434077866356
160.4747716896884
164.7781506698853
150.02396980226047
165.1799238834367
156.05230974678827
154.74964387109836
147.0142674042829
148.5355719342396
149.57955106278635
147.66399173622125
156.02000403877543
153.0546676486473
155.69059570292205
154.24479911600557
148.1617718396219
164.40830687957873
151.6698088788297
166.68886574396416
156.3075539574682
162.84478079641747
171.0473377263999
147.9241522850245
156.46344770864968
152.16191535164404
157.2090768585388
153.13900422674283
164.31231633138418
162.77778047852294
182.93140156918935
163.29282023894837
164.20375481341964
162.3909305004351
155.3987455101275
169.85948170812142
158.79315283646474
149.95046687096038
163.0422266271598
175.62406459446126
160.4368460457401
167.61044341213392
157.86800064137935
153.84417764655353
163.90363969414287
146.22620187494638
188.9943041557677
181.36584808137533
159.41615464449072
159.137856131204
146.5483013673094
149.6905045095846
159.88759059983485
147.30919294088085
161.50782515912826
149.09998610477533
148.0159029584606
170.23453029614106
146.57968498179721
152.3841720778359
174.04970307021014
171.3468292311719
158.33103423343863
150.2245342448141
167.6429090911228
162.2889480829364
158.38772098886085
150.70404313192734
148.72682196774164
178.93571245730072
155.3832504739094
152.82405909414746
169.1279797074787
150.14148846000614
151.33633461896522
151.5042391628916
149.27291447411142
158.5549434442178
156.58697132574184
165.3105731492485
153.0410750376517
147.1618863347038
164.02655001489182
161.1883173349328
180.98528251974125
163.96667813629952
152.6549418647895
152.99449161658288
164.08499375919075
158.81784133333954
150.91829803855165
154.48200417186476
164.47024871832238
173.60649405400417
175.0071526502551
161.75410372654534
148.77870988419838
165.91740751576032
148.9328212738668
170.296910331854
172.03615857123737
159.3493755249191
148.2684028319696
156.39055665932074
159.05659649553843
162.6640534595765
158.94039066700685
168.66945739439421
147.18577637559804
146.90404072200235
146.78187929529412
146.36049807282149
163.3993757648773
157.98960389115084
149.4766041113701
158.35812036203293
158.78675808674586
153.86816848216796
170.4812100115563
158.97983927587404
246.9720423110198
147.73014051418627
148.46304841807407
208.02607625426435
147.23990293077367
151.25424237585074
154.2238614441232
150.04357300644367
163.0068117620479
152.7905185505058
155.84378178377713
152.34912779348218
151.76375718537926
158.8416069991738
150.07951828253402
153.73378036577338
149.4165925261782
164.30407468780987
155.3418206231146
157.06643915270567
187.17858361911402
152.7475344580631
166.05318846313256
158.75661412406993
172.97378276316635
162.2295259587052
149.66140971363976
147.54856817825322
153.5759447487907
157.69507072407518
148.9444744572947
147.7784159093697
161.55666303879877
156.71204040259244
168.3546816026389
149.35265723980876
158.52580229014114
160.05605736608354
156.1588528572084
156.8925392720488
166.3644828556086
150.927300653618
172.40573834825585
163.32491557439036
160.48338720433804
148.99675886682473
150.3925304165074
151.11472635299697
148.72480421860854
172.44170786258672
149.27760909655908
168.73527186224192
158.24951391032803
174.509397893957
147.7472475162659
168.13765778814556
155.93951800012877
154.04801941340583
170.43182247037726
164.79864168624425
159.32805932658547
146.99840171895994
164.72457484523642
158.75075468404927
168.01516722168785
149.89867566290775
157.2386423307521
178.65445350325956
154.18781072370552
159.36395842139237
147.9144502742515
152.40815666734935
146.77013078861776
146.69219951993787
146.35988973222646
172.72952552358458
146.27593673358078
174.4506084659477
148.21740507576092
166.4718707203871
148.30141765583718
149.60169723125415
146.889041911465
147.8644574157206
160.86339486415906
159.73717887652754
150.0751900987007
146.63529145085815
146.51679104556484
163.46844702031368
149.1961685839912
174.53769908445514
155.67397346918835
153.87368998307983
155.34401021579873
160.53095686304755
158.2531305012295
154.64351829449657
146.02265503502068
151.89600160254508
152.09130079042956
170.10579707147747
182.29276486777871
152.08208198611047
147.91555795762318
148.6255665816708
157.41288752299917
150.07683171260163
158.27802348592994
146.60667065049137
146.35341044621924
146.35075755954415
146.14185194396555
151.47982390755445
146.89035355419895
146.94834812127027
152.01619768554494
159.86069667626592
179.0074905743219
157.36806464293036
154.84256482238328
149.86668618770014
166.78052450344506
154.82006311156638
150.6684420697413
159.4117407725174
147.69086078751027
174.80834934323974
149.2682801388315
163.73190924951768
160.86861693245947
176.33973591808876
175.10469445019964
165.45273406247807
189.03074505132594
174.5863349205008
150.73801611425142
156.12295886910724
149.55701362019425
164.82313192826552
147.3336219527844
146.71792903581786
156.93284060116054
166.88101959702317
169.2210309156849
159.59133167941104
160.79495911110314
146.95784582736576
146.26517987396437
146.47283182292298
162.68025366112403
164.75327497938008
157.7395968179917
158.11104014311567
153.3426484261353
151.62344022597614
150.535314359707
155.33535509293498
167.63140958774315
169.73153399330357
148.63268084912167
155.7288255973597
154.75755711921332
154.95202847195026
152.01663222298012
163.55309579790185
157.49176462370784
152.09536140262662
154.6794133118829
152.2666936639848
155.65730224978034
151.9364236162762
162.8211612851716
147.70084755474528
175.60382478953193
170.604418069815
166.95900495161672
158.63135476020798
153.5680817630697
156.5260843048813
158.47572728225487
185.9673067341113
173.7562167578593
156.2274459839258
159.12393979853454
158.8876852430036
156.8855405770451
148.91339751225095
162.28064313318527
146.41704341449054
168.8499795407857
146.48263967816342
149.18022304142335
148.3575199017037
166.16991421797002
154.0886197797327
164.04569875101677
149.1332544150588
149.38558703710814
152.60628726478024
191.663739760527
150.7300125712883
153.06574446931106
165.27793511016134
151.36694455238745
166.90037863302814
151.82520990263222
159.02071081872836
155.71189670876285
147.51911943719242
149.36654754434784
160.29142828090946
156.4605494779359
165.29258484211158
153.79859376927075
148.7437100661193
159.82947216447926
149.02279600068903
148.37322797153365
147.48979069726082
175.73761301145012
154.7295856826332
159.38205976765005
163.4876336336707
154.00829271781953
152.844485933075
146.40584660866153
146.54945152037783
174.03052240406353
168.7500905412031
162.8413773488646
200.97753843168314
161.85625165891003
151.6958789708551
152.63602915538044
165.91283253838844
161.2134337584614
151.32183634801243
147.08816913928348
147.09469727775544
149.6063581814641
150.55371059944926
164.7060766705111
146.561290227521
146.48907895576627
147.7253190713015
154.85752883892226
167.57653864761215
150.3100169981346
147.11564848868034
170.31736521102056
156.94555030673143
162.95128008391097
159.92412481573905
155.0420572822711
151.09453578674544
159.61582326524572
148.67229112713235
155.1552633011287
166.1639760716561
156.51971760095654
155.91683703390018
157.358136723489
153.42664000148125
156.55978675909628
165.40218624838346
150.82232054839346
148.50959727822794
160.0155324924972
156.1980381161773
154.51996659981765
165.12574998154017
150.43943845437067
150.65304378289233
162.23181815568017
155.76310318257066
158.22637248055793
146.98591028480524
164.4738505722141
150.52125482530897
147.46870561720456
156.65152049914985
170.36353063807414
149.68807855756455
149.95023265967632
165.44367812129266
160.72893041781887
156.98976897927292
154.77980191342002
158.26259005072734
150.60803194818547
150.84246579421836
161.39579334126603
149.45341555439364
149.25246166938774
153.46926650108372
148.43336227619517
147.77934348697082
152.2135693279528
163.41840104848308
150.68843098772197
149.69565780451288
161.6183774793292
147.59812638038426
151.34567309747538
174.78035739066422
165.10322788719466
148.62731480798718
156.7010749475124
169.50597972181205
147.225215417736
163.98543532526685
151.9727969268722
161.54296674324308
148.46817367522408
161.91841332151472
148.65219669846158
168.91165051743957
154.8760954656044
171.45588330327126
153.8774044393869
154.9610007546839
168.18671836954084
156.15949475295355
159.49747339247085
154.30351942188594
176.26469976566725
178.34226177379688
171.4181929939349
148.13338180201143
148.03285023509687
150.80750031429807
147.232982883016
156.55126128154808
153.50647015219667
156.3069995633464
171.72823561197757
151.6378712323902
151.85153018500426
158.74310898506673
147.88262149375325
156.55741350838989
161.19347299857668
150.9129148378944
147.71687822742604
153.38059666471284
151.36397841915726
157.72657485606268
147.51597326146657
174.20157468798763
148.02577076936018
159.73774675838328
154.57631858361606
154.7930788426704
170.0450150487462
150.38294951636692
169.18534752448667
156.32614947777637
164.05185713556438
149.40982227611997
152.9061385293419
156.76385248524076
153.52789245447784
173.11179375210747
148.7120804864518
147.5633263664137
174.89359569936647
149.13118699900969
165.26766903067073
157.29951178572202
168.86100017434183
157.6995944610166
148.50269123238186
155.82434059976882
154.30313038132186
153.2453887853356
147.1120981280486
187.60313150203214
164.72862110297513
159.87263733727818
150.50620642318984
156.3987381143103
154.03197376896176
164.18424446584066
157.95149108814607
152.09473402405314
154.12534176394942
153.00996961194346
178.82885859293583
150.8681515508503
158.8459043442532
157.83097794636845
154.90079511699895
163.85004442932583
158.02167884127934
151.65874343494082
163.9319061197434
155.36706259397198
147.90937482755157
182.71421845991176
149.47983704559138
171.32122258409362
153.8169111792431
157.0083353102646
182.43885091341957
152.24544672106282
161.96947754166303
159.81868621639495
157.21421218081582
161.84373579254324
148.90737449987316
150.23732383859786
151.28150776310957
159.72753463451332
155.61212512074638
160.67693343206025
179.1886489749841
152.0328969507715
152.78256649099953
162.0336808910675
155.29976087635865
169.67040263229373
170.25401876419247
167.4634077048767
161.28155697715658
151.9367090122645
150.31802282396418
155.8712048979831
162.02359963964017
156.5835398761137
147.34505259818215
162.4426687052106
149.25293472438068
187.60559425236966
159.3526974241259
154.14712208244217
159.72463934666445
160.81447420522392
147.70077434680078
147.95178639406694
154.07112446928966
161.66429819184484
148.1692078719704
162.72896292491188
148.1537410051027
160.15559198143373
179.85258778966823
164.13075876267487
158.1491253162305
151.62999968577557
159.18228652292765
173.87342954643702
163.5407949676357
155.41974320151851
155.74481900199348
152.4434669452478
162.6900109479091
162.74065054968156
199.7139994851814
162.62370888062497
154.31337317438576
147.9896622639774
161.7286099488556
155.62776526455465
169.8416715327802
154.1212376460965
157.69691824881772
152.9373386831959
156.72463018539773
170.95143090015347
150.59869122083663
146.20805863736402
164.73943281487547
152.74339313918594
155.99202455875601
156.91753401655072
148.96859811705752
170.39319479960957
150.2833487380185
148.61115923768267
181.53491236003381
151.61965692365945
152.38987285172504
149.68833660485606
161.86996023287097
167.02238392908592
151.3709057410067
162.07572044531204
173.2574321596995
158.72588001400496
153.69159003682765
167.7702940079365
160.67207961249173
154.24233362400994
155.78990134227539
162.50679427408755
155.50080776408845
152.6884682113158
158.16296150027665
171.6582645390768
165.91036490697073
152.6275167982024
161.8822441359894
150.43688728805785
165.10373611556196
149.16930110433645
150.62301780699548
149.74788224495126
149.8470057793134
146.99990410532112
159.42705202410355
146.6241298980043
179.4735656696624
153.04624173816063
167.72469338673434
162.20328188998252
151.07153436846815
165.92734618343033
150.837240225193
155.69084706759125
155.71179597528243
165.17305801488888
147.7953213888542
162.9471838581999
152.78470338379876
150.58090581824996
156.39817819634092
154.48401585023524
176.51358839720385
150.26171471888074
168.84331262077973
161.35585935468916
147.02950112292925
182.61257284889376
154.315420489491
164.99252561861542
157.9039922362013
161.31903896581397
160.78700309014917
173.72531298374645
166.5702610808224
163.179291429429
160.0386499138536
170.23493685036732
163.67465286930678
148.03561964235553
149.0350572625175
146.63386614609192
147.64628789330175
146.77130392370165
154.32638935131897
149.83712227300924
153.3318999234199
147.41009843948365
149.06348074592987
153.55282514659544
153.73056413657156
178.1215283998057
178.82311028325978
155.09505115097204
174.8206523093163
157.32893048335796
151.96525085803574
149.02786885754392
151.90130961199256
148.85152192487604
150.42544025396222
153.64916421888083
153.80749273737948
165.86355735788825
152.90177384485796
154.32244249622298
164.05878188368112
188.51869825313
153.89156532690947
149.91802389825824
148.96304408438502
149.80472758716922
156.7057313335247
162.6204134673359
150.61581400915958
171.30231549286054
162.16696736573377
156.60414166175548
163.92120976314214
158.28094304456386
169.21758007317553
156.4725309933671
169.44841458853165The infection count to date under the two tree priors, side by side. A slightly earlier common ancestor (Exponential growth) permits a marginally older outbreak, though the difference is small because the evolutionary rates are nearly identical.
Tree-prior infection-count table
clock_sensitivity_C_table = RUN_SENSITIVITY ?
streams_table("Skygrid (baseline)" => posterior_C_joint,
"Exponential growth" => posterior_C_exp_growth) :
Markdown.md"_Tree-prior sensitivity analysis not shown in this build._"| Row | Stream | Lower 90% | Lower 60% | Lower 30% | Upper 30% | Upper 60% | Upper 90% |
|---|---|---|---|---|---|---|---|
| String | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | Skygrid (baseline) | 7983.0 | 9241.0 | 10172.0 | 12058.0 | 13333.0 | 16383.0 |
| 2 | Exponential growth | 7798.0 | 8871.0 | 9682.0 | 11712.0 | 13167.0 | 16694.0 |
| Row | Stream | Lower 90% | Lower 60% | Lower 30% | Upper 30% | Upper 60% | Upper 90% |
|---|---|---|---|---|---|---|---|
| String | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | Skygrid (baseline) | 7983.0 | 9241.0 | 10172.0 | 12058.0 | 13333.0 | 16383.0 |
| 2 | Exponential growth | 7798.0 | 8871.0 | 9682.0 | 11712.0 | 13167.0 | 16694.0 |
Tree-prior infection-count density plot
clock_sensitivity_C_fig = RUN_SENSITIVITY ?
plot_cumulative_cases("Skygrid (baseline)" => posterior_C_joint,
"Exponential growth" => posterior_C_exp_growth; scenarios = []) :
Markdown.md"_Tree-prior sensitivity analysis not shown in this build._"The outbreak age, the number of days from seeding to the cut-off, under the two tree priors.
Tree-prior outbreak-age table
clock_sensitivity_T_table = RUN_SENSITIVITY ?
streams_table("Skygrid (baseline)" => T_skygrid,
"Exponential growth" => T_exp_growth; digits = 0) :
Markdown.md"_Tree-prior sensitivity analysis not shown in this build._"| Row | Stream | Lower 90% | Lower 60% | Lower 30% | Upper 30% | Upper 60% | Upper 90% |
|---|---|---|---|---|---|---|---|
| String | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | Skygrid (baseline) | 141.0 | 144.0 | 147.0 | 154.0 | 159.0 | 170.0 |
| 2 | Exponential growth | 147.0 | 150.0 | 153.0 | 160.0 | 165.0 | 177.0 |
| Row | Stream | Lower 90% | Lower 60% | Lower 30% | Upper 30% | Upper 60% | Upper 90% |
|---|---|---|---|---|---|---|---|
| String | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | |
| 1 | Skygrid (baseline) | 141.0 | 144.0 | 147.0 | 154.0 | 159.0 | 170.0 |
| 2 | Exponential growth | 147.0 | 150.0 | 153.0 | 160.0 | 165.0 | 177.0 |
Tree-prior outbreak-age density plot
clock_sensitivity_T_fig = RUN_SENSITIVITY ?
plot_density_overlay("Skygrid (baseline)" => T_skygrid,
"Exponential growth" => T_exp_growth;
xlabel = "Outbreak age (days before cut-off)",
title = "Posterior outbreak age by tree prior") :
Markdown.md"_Tree-prior sensitivity analysis not shown in this build._"Saving sensitivity results
The stream-comparison and frozen-fit tables and the per-stream reproduction number figure are written to the shared output directory. The main analysis writes the rest, so the combined release and summary dashboard pick up both pages' outputs.
Write sensitivity outputs
output_dir = get(ENV, "BVD_OUTPUT_DIR",
joinpath(pkgdir(BVDOutbreakSize), "output"))
mkpath(output_dir)
CSV.write(joinpath(output_dir, "cumulative_cases_by_stream.csv"),
streams_C_table)
CSV.write(joinpath(output_dir, "frozen_matched_cutoffs.csv"),
frozen_streams_table)
# The one-week-back validation forecast, in the same archive format as the
# release forecast, so the frozen "last week versus now" forecast is recorded
# as a release asset alongside the forecast it is scored against.
CSV.write(joinpath(output_dir, "forecast_validation.csv"),
forecast_archive([(7, validation_forecast)];
made_date = frozen_lastweek.o.cutoff, thin = 5))
# The per-stream reproduction-number figure for the summary dashboard; the
# main analysis writes the other three dashboard figures.
dashboard_dir = joinpath(
pkgdir(BVDOutbreakSize), "docs", "src", "summary_assets")
mkpath(dashboard_dir)
CairoMakie.save(joinpath(dashboard_dir, "rt_streams.png"), stream_rt_fig)