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 | 1144.0 | 1464.0 | 1812.0 | 3010.0 | 4200.0 | 8011.0 | no |
| 2 | DRC reported cases | new this week | 0.0 | 67.0 | 387.0 | 735.0 | 1933.0 | 3123.0 | 6934.0 | no |
| 3 | DRC suspected deaths | cumulative by T+7 | 246.0 | 267.0 | 354.0 | 462.0 | 798.0 | 1157.0 | 2357.0 | no |
| 4 | DRC suspected deaths | new this week | 0.0 | 21.0 | 108.0 | 216.0 | 552.0 | 911.0 | 2111.0 | no |
| 5 | DRC confirmed cases | cumulative by T+7 | 4567.0 | 4174.0 | 4337.0 | 4483.0 | 4728.0 | 4925.0 | 5366.0 | yes |
| 6 | DRC confirmed cases | new this week | 594.0 | 201.0 | 364.0 | 510.0 | 755.0 | 952.0 | 1393.0 | yes |
| 7 | DRC confirmed deaths | cumulative by T+7 | 2128.0 | 267.0 | 354.0 | 462.0 | 798.0 | 1157.0 | 2072.0 | no |
| 8 | DRC confirmed deaths | new this week | 327.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 271.0 | no |
| 9 | DRC recovered | cumulative by T+7 | 918.0 | 776.0 | 792.0 | 826.0 | 938.0 | 1062.0 | 1455.0 | yes |
| 10 | DRC recovered | new this week | 142.0 | 0.0 | 16.0 | 50.0 | 162.0 | 286.0 | 679.0 | yes |
| 11 | DRC isolation beds | occupancy at T+7 | 570.0 | 605.0 | 696.0 | 751.0 | 853.0 | 926.0 | 1022.0 | no |
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.62 | 0.823 | 3.74 | 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.5 | 0.758 | 4.06 | missing | missing | 666.38 | 166.85 | 0.0 | 1.0 | 1.0 | 0.31 |
| 3 | 2026-07-01 | confirmed cases | joint | 4 | 15862.8 | 77.9 | 0.583 | 2.85 | 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.0 | 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 | 2 | 143.83 | 1.35 | 0.187 | 1.52 | missing | missing | 136.73 | 0.0 | 7.1 | 1.0 | 1.0 | -0.14 |
| 7 | 2026-07-23 | confirmed cases | joint | 2 | 142.1 | 1.33 | 0.149 | 1.21 | 0.99 | 0.8 | 135.46 | 5.4 | 1.25 | 1.0 | 1.0 | 0.02 |
| 8 | 2026-07-25 | confirmed cases | confirmed | 2 | 178.33 | 3.99 | 0.208 | 3.67 | missing | missing | 176.3 | 1.95 | 0.08 | 1.0 | 1.0 | 0.03 |
| 9 | 2026-07-25 | confirmed cases | joint | 2 | 104.13 | 2.33 | 0.124 | 2.2 | 0.58 | 0.6 | 103.61 | 0.52 | 0.0 | 1.0 | 1.0 | 0.04 |
| 10 | 2026-07-26 | confirmed cases | confirmed | 2 | 146.77 | 3.46 | 0.206 | 3.88 | 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.55 | 0.127 | 2.4 | 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.75 | 0.161 | 2.33 | 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.32 | 0.127 | 1.84 | 0.85 | 0.79 | 109.85 | 4.32 | 0.0 | 1.0 | 1.0 | 0.12 |
| 14 | 2026-07-31 | confirmed cases | confirmed | 1 | 119.08 | 2.78 | 0.205 | 2.74 | missing | missing | 119.04 | 0.04 | 0.0 | 1.0 | 1.0 | 0.01 |
| 15 | 2026-07-31 | confirmed cases | joint | 1 | 88.67 | 2.07 | 0.15 | 2.01 | 0.74 | 0.73 | 78.09 | 10.58 | 0.0 | 1.0 | 1.0 | 0.18 |
| 16 | 2026-08-01 | confirmed cases | confirmed | 1 | 97.35 | 3.2 | 0.189 | 3.42 | missing | missing | 97.16 | 0.19 | 0.0 | 1.0 | 1.0 | 0.02 |
| 17 | 2026-08-01 | confirmed cases | joint | 1 | 69.38 | 2.28 | 0.119 | 2.15 | 0.71 | 0.63 | 65.6 | 3.78 | 0.0 | 1.0 | 1.0 | 0.13 |
| 18 | 2026-08-02 | confirmed cases | confirmed | 1 | 91.77 | 2.24 | 0.163 | 2.12 | missing | missing | 89.22 | 0.0 | 2.55 | 1.0 | 1.0 | -0.11 |
| 19 | 2026-08-02 | confirmed cases | joint | 1 | 78.02 | 1.9 | 0.124 | 1.62 | 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.05 | 0.164 | 0.95 | 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.84 | 0.12 | 0.69 | 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.45 | 0.167 | 2.61 | missing | missing | 94.7 | 0.0 | 0.15 | 1.0 | 1.0 | -0.02 |
| 23 | 2026-08-04 | confirmed cases | joint | 1 | 69.68 | 1.8 | 0.116 | 1.81 | 0.73 | 0.7 | 68.48 | 1.2 | 0.0 | 1.0 | 1.0 | 0.07 |
| 24 | 2026-06-07 | confirmed deaths | joint | 4 | 120.57 | 0.99 | 0.725 | 1.07 | missing | missing | 117.8 | 0.0 | 2.76 | 1.0 | 1.0 | -0.11 |
| 25 | 2026-06-10 | confirmed deaths | joint | 4 | 144.92 | 1.1 | 0.598 | 1.06 | missing | missing | 140.54 | 3.76 | 0.62 | 1.0 | 1.0 | 0.02 |
| 26 | 2026-07-01 | confirmed deaths | joint | 4 | 17196.0 | 79.42 | 0.549 | 1.2 | missing | missing | 17103.1 | 92.89 | 0.0 | 1.0 | 1.0 | 0.28 |
| 27 | 2026-07-06 | confirmed deaths | joint | 4 | 197.2 | 0.89 | 0.871 | 2.28 | missing | missing | 110.35 | 0.0 | 86.85 | 0.25 | 1.0 | -0.49 |
| 28 | 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 |
| 29 | 2026-07-23 | confirmed deaths | confirmed_deaths | 2 | 239.07 | 6.17 | 0.334 | 3.77 | missing | missing | 158.26 | 80.82 | 0.0 | 0.5 | 1.0 | 0.45 |
| 30 | 2026-07-23 | confirmed deaths | joint | 2 | 135.15 | 3.49 | 0.485 | 5.47 | 0.57 | 1.45 | 70.75 | 0.0 | 64.4 | 1.0 | 1.0 | -0.48 |
| 31 | 2026-07-25 | confirmed deaths | confirmed_deaths | 2 | 97.98 | 3.79 | 0.214 | 3.06 | missing | missing | 95.02 | 2.96 | 0.0 | 1.0 | 1.0 | 0.1 |
| 32 | 2026-07-25 | confirmed deaths | joint | 2 | 127.95 | 4.95 | 0.495 | 7.09 | 1.31 | 2.31 | 46.77 | 0.0 | 81.18 | 0.0 | 1.0 | -0.58 |
| 33 | 2026-07-26 | confirmed deaths | confirmed_deaths | 2 | 105.51 | 4.78 | 0.222 | 3.93 | missing | missing | 104.48 | 1.04 | 0.0 | 1.0 | 1.0 | 0.06 |
| 34 | 2026-07-26 | confirmed deaths | joint | 2 | 144.07 | 6.53 | 0.53 | 9.36 | 1.37 | 2.38 | 43.58 | 0.0 | 100.49 | 0.0 | 1.0 | -0.68 |
| 35 | 2026-07-27 | confirmed deaths | confirmed_deaths | 2 | 123.88 | 4.15 | 0.226 | 2.8 | missing | missing | 110.53 | 13.35 | 0.0 | 1.0 | 1.0 | 0.19 |
| 36 | 2026-07-27 | confirmed deaths | joint | 2 | 133.97 | 4.49 | 0.523 | 6.48 | 1.08 | 2.31 | 51.31 | 0.0 | 82.66 | 0.0 | 1.0 | -0.62 |
| 37 | 2026-07-31 | confirmed deaths | confirmed_deaths | 1 | 67.74 | 3.43 | 0.237 | 3.24 | missing | missing | 67.46 | 0.0 | 0.28 | 1.0 | 1.0 | -0.03 |
| 38 | 2026-07-31 | confirmed deaths | joint | 1 | 101.18 | 5.12 | 0.551 | 7.51 | 1.49 | 2.32 | 29.49 | 0.0 | 71.69 | 0.0 | 1.0 | -0.71 |
| 39 | 2026-08-01 | confirmed deaths | confirmed_deaths | 1 | 56.75 | 1.69 | 0.193 | 1.5 | missing | missing | 56.75 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 |
| 40 | 2026-08-01 | confirmed deaths | joint | 1 | 121.96 | 3.64 | 0.697 | 5.4 | 2.15 | 3.61 | 27.83 | 0.0 | 94.13 | 0.0 | 1.0 | -0.74 |
| 41 | 2026-08-02 | confirmed deaths | confirmed_deaths | 1 | 70.73 | 2.45 | 0.252 | 2.37 | missing | missing | 69.5 | 0.0 | 1.23 | 1.0 | 1.0 | -0.08 |
| 42 | 2026-08-02 | confirmed deaths | joint | 1 | 96.07 | 3.33 | 0.496 | 4.66 | 1.36 | 1.97 | 33.23 | 0.0 | 62.84 | 0.0 | 1.0 | -0.66 |
| 43 | 2026-08-03 | confirmed deaths | confirmed_deaths | 1 | 60.78 | 1.09 | 0.231 | 1.06 | missing | missing | 54.93 | 0.0 | 5.85 | 1.0 | 1.0 | -0.2 |
| 44 | 2026-08-03 | confirmed deaths | joint | 1 | 109.99 | 1.97 | 0.613 | 2.82 | 1.81 | 2.65 | 34.89 | 0.0 | 75.1 | 0.0 | 1.0 | -0.59 |
| 45 | 2026-08-04 | confirmed deaths | confirmed_deaths | 1 | 68.66 | 3.95 | 0.27 | 4.89 | missing | missing | 60.32 | 0.0 | 8.34 | 1.0 | 1.0 | -0.24 |
| 46 | 2026-08-04 | confirmed deaths | joint | 1 | 132.46 | 7.62 | 0.687 | 12.43 | 1.93 | 2.54 | 28.47 | 0.0 | 103.99 | 0.0 | 1.0 | -0.74 |
| 47 | 2026-07-01 | isolation beds | joint | 4 | 90.19 | 1.5 | 0.138 | 1.54 | missing | missing | 13.48 | 0.0 | 76.71 | 0.0 | 0.0 | -0.99 |
| 48 | 2026-07-06 | isolation beds | joint | 4 | 42.87 | 0.62 | 0.066 | 0.63 | missing | missing | 21.07 | 0.0 | 21.8 | 0.0 | 1.0 | -0.64 |
| 49 | 2026-07-08 | isolation beds | joint | 4 | 54.75 | 1.42 | 0.073 | 1.42 | missing | missing | 11.67 | 43.08 | 0.0 | 0.0 | 1.0 | 0.8 |
| 50 | 2026-07-23 | isolation beds | joint | 2 | 77.69 | 2.93 | 0.097 | 2.8 | 1.13 | 0.84 | 24.83 | 52.86 | 0.0 | 0.0 | 1.0 | 0.64 |
| 51 | 2026-07-23 | isolation beds | treatment | 2 | 68.88 | 2.6 | 0.116 | 3.33 | missing | missing | 56.15 | 0.0 | 12.73 | 1.0 | 1.0 | -0.29 |
| 52 | 2026-07-25 | isolation beds | joint | 2 | 92.94 | 2.27 | 0.119 | 2.17 | 1.74 | 1.32 | 25.43 | 67.51 | 0.0 | 0.0 | 1.0 | 0.68 |
| 53 | 2026-07-25 | isolation beds | treatment | 2 | 53.37 | 1.3 | 0.09 | 1.65 | missing | missing | 52.99 | 0.02 | 0.37 | 1.0 | 1.0 | -0.04 |
| 54 | 2026-07-26 | isolation beds | joint | 2 | 85.22 | 3.89 | 0.11 | 3.57 | 1.46 | 1.07 | 29.67 | 55.55 | 0.0 | 0.0 | 1.0 | 0.62 |
| 55 | 2026-07-26 | isolation beds | treatment | 2 | 58.45 | 2.67 | 0.102 | 3.34 | missing | missing | 57.7 | 0.46 | 0.29 | 1.0 | 1.0 | 0.01 |
| 56 | 2026-07-27 | isolation beds | joint | 2 | 76.07 | 3.49 | 0.097 | 3.25 | 1.22 | 0.88 | 33.44 | 42.62 | 0.0 | 0.0 | 1.0 | 0.55 |
| 57 | 2026-07-27 | isolation beds | treatment | 2 | 62.4 | 2.86 | 0.11 | 3.69 | missing | missing | 61.76 | 0.0 | 0.64 | 1.0 | 1.0 | -0.07 |
| 58 | 2026-07-31 | isolation beds | joint | 1 | 65.32 | 2.73 | 0.082 | 2.57 | 0.87 | 0.62 | 36.11 | 29.21 | 0.0 | 0.0 | 1.0 | 0.53 |
| 59 | 2026-07-31 | isolation beds | treatment | 1 | 75.1 | 3.14 | 0.133 | 4.13 | missing | missing | 72.21 | 0.0 | 2.89 | 1.0 | 1.0 | -0.12 |
| 60 | 2026-08-01 | isolation beds | joint | 1 | 48.07 | 2.03 | 0.061 | 1.8 | 0.62 | 0.43 | 35.68 | 12.39 | 0.0 | 1.0 | 1.0 | 0.34 |
| 61 | 2026-08-01 | isolation beds | treatment | 1 | 76.99 | 3.25 | 0.144 | 4.21 | missing | missing | 76.79 | 0.0 | 0.2 | 1.0 | 1.0 | -0.04 |
| 62 | 2026-08-02 | isolation beds | joint | 1 | 74.44 | 4.09 | 0.095 | 3.7 | 0.99 | 0.7 | 38.35 | 36.09 | 0.0 | 0.0 | 1.0 | 0.6 |
| 63 | 2026-08-02 | isolation beds | treatment | 1 | 75.18 | 4.13 | 0.136 | 5.3 | missing | missing | 74.35 | 0.0 | 0.83 | 1.0 | 1.0 | -0.05 |
| 64 | 2026-08-03 | isolation beds | joint | 1 | 54.95 | 3.09 | 0.07 | 2.81 | 0.73 | 0.53 | 36.92 | 18.03 | 0.0 | 1.0 | 1.0 | 0.41 |
| 65 | 2026-08-03 | isolation beds | treatment | 1 | 74.86 | 4.2 | 0.133 | 5.32 | missing | missing | 74.86 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 |
| 66 | 2026-08-04 | isolation beds | joint | 1 | 142.95 | 2.07 | 0.213 | 1.93 | 1.5 | 1.25 | 33.51 | 109.44 | 0.0 | 0.0 | 1.0 | 0.88 |
| 67 | 2026-08-04 | isolation beds | treatment | 1 | 95.26 | 1.38 | 0.17 | 1.54 | missing | missing | 90.62 | 4.64 | 0.0 | 1.0 | 1.0 | 0.12 |
| 68 | 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 |
| 69 | 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 |
| 70 | 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 |
| 71 | 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 |
| 72 | 2026-07-01 | recovered | joint | 4 | 10457.7 | 153.97 | 0.539 | 1.89 | missing | missing | 10409.1 | 48.57 | 0.0 | 1.0 | 1.0 | 0.29 |
| 73 | 2026-07-06 | recovered | joint | 4 | 85.76 | 0.86 | 0.407 | 0.93 | missing | missing | 68.39 | 0.0 | 17.37 | 1.0 | 1.0 | -0.33 |
| 74 | 2026-07-08 | recovered | joint | 4 | 63.08 | 0.8 | 0.292 | 1.05 | missing | missing | 44.51 | 0.0 | 18.57 | 1.0 | 1.0 | -0.38 |
| 75 | 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 |
| 76 | 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 | 13 | 130.7 | 2.35 | 0.185 | 2.3 | missing | missing | 126.59 | 0.43 | 3.68 | 1.0 | 1.0 | -0.06 |
| 2 | confirmed cases | joint | 33 | 2262.23 | 14.79 | 0.377 | 2.23 | 0.77 | 0.7 | 2142.59 | 119.52 | 0.12 | 0.73 | 1.0 | 0.3 |
| 3 | confirmed deaths | confirmed_deaths | 13 | 112.12 | 3.75 | 0.244 | 2.71 | missing | missing | 95.81 | 15.1 | 1.21 | 0.92 | 1.0 | 0.08 |
| 4 | confirmed deaths | joint | 33 | 2211.79 | 18.0 | 0.634 | 1.9 | 1.13 | 2.24 | 2145.55 | 11.72 | 54.53 | 0.48 | 1.0 | -0.36 |
| 5 | isolation beds | joint | 25 | 72.03 | 1.72 | 0.099 | 1.64 | 1.19 | 0.88 | 23.69 | 32.58 | 15.76 | 0.08 | 0.84 | 0.18 |
| 6 | isolation beds | treatment | 13 | 67.97 | 2.36 | 0.119 | 2.94 | missing | missing | 65.08 | 0.43 | 2.46 | 1.0 | 1.0 | -0.07 |
| 7 | onset reports | joint | 2 | 114.26 | 0.39 | 0.454 | 0.08 | 1.0 | 0.96 | 45.94 | 63.9 | 4.42 | 0.5 | 1.0 | 0.28 |
| 8 | onset reports | onsets | 2 | 113.73 | 0.39 | 0.475 | 0.09 | missing | missing | 63.87 | 40.58 | 9.28 | 0.5 | 1.0 | 0.18 |
| 9 | recovered | joint | 12 | 3535.5 | 43.15 | 0.413 | 1.24 | 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 | 9 | 97.24 | 2.2 | 0.183 | 2.26 | missing | missing | 93.97 | 0.03 | 3.25 | 1.0 | 1.0 | -0.08 |
| 2 | confirmed cases | 7 | joint | 14 | 117.06 | 2.93 | 0.293 | 3.22 | 0.76 | 0.69 | 95.46 | 21.42 | 0.18 | 0.79 | 1.0 | 0.23 |
| 3 | confirmed cases | 14 | confirmed | 4 | 205.99 | 2.54 | 0.191 | 2.4 | missing | missing | 200.0 | 1.34 | 4.65 | 1.0 | 1.0 | -0.02 |
| 4 | confirmed cases | 14 | joint | 9 | 301.8 | 3.9 | 0.346 | 3.39 | 0.79 | 0.71 | 232.7 | 68.95 | 0.16 | 0.78 | 1.0 | 0.26 |
| 5 | confirmed cases | 21 | joint | 5 | 987.69 | 4.13 | 0.504 | 2.02 | missing | missing | 756.12 | 231.57 | 0.0 | 0.6 | 1.0 | 0.42 |
| 6 | confirmed cases | 28 | joint | 5 | 13072.0 | 25.17 | 0.537 | 1.25 | missing | missing | 12698.8 | 373.21 | 0.0 | 0.6 | 1.0 | 0.46 |
| 7 | confirmed deaths | 7 | confirmed_deaths | 9 | 68.79 | 2.42 | 0.232 | 2.26 | missing | missing | 63.41 | 3.63 | 1.74 | 1.0 | 1.0 | 0.01 |
| 8 | confirmed deaths | 7 | joint | 14 | 87.74 | 3.62 | 0.718 | 5.72 | 1.45 | 2.42 | 35.11 | 0.4 | 52.23 | 0.29 | 1.0 | -0.52 |
| 9 | confirmed deaths | 14 | confirmed_deaths | 4 | 209.62 | 6.3 | 0.273 | 4.37 | missing | missing | 168.72 | 40.9 | 0.0 | 0.75 | 1.0 | 0.25 |
| 10 | confirmed deaths | 14 | joint | 9 | 167.41 | 2.83 | 0.585 | 2.99 | 0.89 | 1.89 | 93.79 | 3.87 | 69.76 | 0.44 | 1.0 | -0.38 |
| 11 | confirmed deaths | 21 | joint | 5 | 432.87 | 1.9 | 0.558 | 0.9 | missing | missing | 371.55 | 21.83 | 39.49 | 0.6 | 1.0 | -0.14 |
| 12 | confirmed deaths | 28 | joint | 5 | 13617.9 | 33.33 | 0.566 | 0.64 | missing | missing | 13521.9 | 47.4 | 48.58 | 1.0 | 1.0 | -0.09 |
| 13 | isolation beds | 7 | joint | 12 | 75.22 | 2.0 | 0.101 | 1.86 | 1.06 | 0.79 | 26.47 | 37.58 | 11.16 | 0.17 | 0.92 | 0.37 |
| 14 | isolation beds | 7 | treatment | 9 | 73.06 | 2.53 | 0.13 | 3.13 | missing | missing | 69.66 | 0.52 | 2.88 | 1.0 | 1.0 | -0.07 |
| 15 | isolation beds | 14 | joint | 7 | 74.67 | 1.97 | 0.099 | 1.84 | 1.57 | 1.17 | 23.11 | 39.19 | 12.36 | 0.0 | 0.86 | 0.22 |
| 16 | isolation beds | 14 | treatment | 4 | 56.51 | 1.97 | 0.096 | 2.48 | missing | missing | 54.77 | 0.23 | 1.51 | 1.0 | 1.0 | -0.07 |
| 17 | isolation beds | 21 | joint | 3 | 54.83 | 1.03 | 0.081 | 1.03 | missing | missing | 16.37 | 10.55 | 27.91 | 0.0 | 0.67 | -0.29 |
| 18 | isolation beds | 28 | joint | 3 | 70.36 | 1.24 | 0.111 | 1.33 | missing | missing | 21.24 | 19.19 | 29.92 | 0.0 | 0.67 | -0.25 |
| 19 | onset reports | 7 | joint | 2 | 114.26 | 0.39 | 0.454 | 0.08 | 1.0 | 0.96 | 45.94 | 63.9 | 4.42 | 0.5 | 1.0 | 0.28 |
| 20 | onset reports | 7 | onsets | 2 | 113.73 | 0.39 | 0.475 | 0.09 | missing | missing | 63.87 | 40.58 | 9.28 | 0.5 | 1.0 | 0.18 |
| 21 | recovered | 7 | joint | 3 | 26.96 | 2.06 | 0.319 | 1.68 | missing | missing | 20.93 | 1.28 | 4.76 | 1.0 | 1.0 | -0.18 |
| 22 | recovered | 14 | joint | 3 | 89.7 | 2.13 | 0.393 | 1.56 | missing | missing | 68.01 | 5.81 | 15.87 | 1.0 | 1.0 | -0.23 |
| 23 | recovered | 21 | joint | 3 | 297.16 | 3.5 | 0.422 | 1.24 | missing | missing | 269.9 | 16.05 | 11.2 | 1.0 | 1.0 | -0.09 |
| 24 | recovered | 28 | joint | 3 | 13728.2 | 73.2 | 0.517 | 0.94 | missing | missing | 13670.5 | 41.62 | 16.09 | 1.0 | 1.0 | -0.06 |
| 25 | 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 |
| 26 | 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.62 | 0.823 | 3.74 | 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.5 | 0.758 | 4.06 | missing | missing | 666.38 | 166.85 | 0.0 | 1.0 | 1.0 | 0.31 |
| 3 | 2026-07-01 | confirmed cases | joint | 4 | 15862.8 | 77.9 | 0.583 | 2.85 | 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.0 | 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 | 2 | 143.83 | 1.35 | 0.187 | 1.52 | missing | missing | 136.73 | 0.0 | 7.1 | 1.0 | 1.0 | -0.14 |
| 7 | 2026-07-23 | confirmed cases | joint | 2 | 142.1 | 1.33 | 0.149 | 1.21 | 0.99 | 0.8 | 135.46 | 5.4 | 1.25 | 1.0 | 1.0 | 0.02 |
| 8 | 2026-07-25 | confirmed cases | confirmed | 2 | 178.33 | 3.99 | 0.208 | 3.67 | missing | missing | 176.3 | 1.95 | 0.08 | 1.0 | 1.0 | 0.03 |
| 9 | 2026-07-25 | confirmed cases | joint | 2 | 104.13 | 2.33 | 0.124 | 2.2 | 0.58 | 0.6 | 103.61 | 0.52 | 0.0 | 1.0 | 1.0 | 0.04 |
| 10 | 2026-07-26 | confirmed cases | confirmed | 2 | 146.77 | 3.46 | 0.206 | 3.88 | 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.55 | 0.127 | 2.4 | 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.75 | 0.161 | 2.33 | 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.32 | 0.127 | 1.84 | 0.85 | 0.79 | 109.85 | 4.32 | 0.0 | 1.0 | 1.0 | 0.12 |
| 14 | 2026-07-31 | confirmed cases | confirmed | 1 | 119.08 | 2.78 | 0.205 | 2.74 | missing | missing | 119.04 | 0.04 | 0.0 | 1.0 | 1.0 | 0.01 |
| 15 | 2026-07-31 | confirmed cases | joint | 1 | 88.67 | 2.07 | 0.15 | 2.01 | 0.74 | 0.73 | 78.09 | 10.58 | 0.0 | 1.0 | 1.0 | 0.18 |
| 16 | 2026-08-01 | confirmed cases | confirmed | 1 | 97.35 | 3.2 | 0.189 | 3.42 | missing | missing | 97.16 | 0.19 | 0.0 | 1.0 | 1.0 | 0.02 |
| 17 | 2026-08-01 | confirmed cases | joint | 1 | 69.38 | 2.28 | 0.119 | 2.15 | 0.71 | 0.63 | 65.6 | 3.78 | 0.0 | 1.0 | 1.0 | 0.13 |
| 18 | 2026-08-02 | confirmed cases | confirmed | 1 | 91.77 | 2.24 | 0.163 | 2.12 | missing | missing | 89.22 | 0.0 | 2.55 | 1.0 | 1.0 | -0.11 |
| 19 | 2026-08-02 | confirmed cases | joint | 1 | 78.02 | 1.9 | 0.124 | 1.62 | 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.05 | 0.164 | 0.95 | 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.84 | 0.12 | 0.69 | 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.45 | 0.167 | 2.61 | missing | missing | 94.7 | 0.0 | 0.15 | 1.0 | 1.0 | -0.02 |
| 23 | 2026-08-04 | confirmed cases | joint | 1 | 69.68 | 1.8 | 0.116 | 1.81 | 0.73 | 0.7 | 68.48 | 1.2 | 0.0 | 1.0 | 1.0 | 0.07 |
| 24 | 2026-06-07 | confirmed deaths | joint | 4 | 120.57 | 0.99 | 0.725 | 1.07 | missing | missing | 117.8 | 0.0 | 2.76 | 1.0 | 1.0 | -0.11 |
| 25 | 2026-06-10 | confirmed deaths | joint | 4 | 144.92 | 1.1 | 0.598 | 1.06 | missing | missing | 140.54 | 3.76 | 0.62 | 1.0 | 1.0 | 0.02 |
| 26 | 2026-07-01 | confirmed deaths | joint | 4 | 17196.0 | 79.42 | 0.549 | 1.2 | missing | missing | 17103.1 | 92.89 | 0.0 | 1.0 | 1.0 | 0.28 |
| 27 | 2026-07-06 | confirmed deaths | joint | 4 | 197.2 | 0.89 | 0.871 | 2.28 | missing | missing | 110.35 | 0.0 | 86.85 | 0.25 | 1.0 | -0.49 |
| 28 | 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 |
| 29 | 2026-07-23 | confirmed deaths | confirmed_deaths | 2 | 239.07 | 6.17 | 0.334 | 3.77 | missing | missing | 158.26 | 80.82 | 0.0 | 0.5 | 1.0 | 0.45 |
| 30 | 2026-07-23 | confirmed deaths | joint | 2 | 135.15 | 3.49 | 0.485 | 5.47 | 0.57 | 1.45 | 70.75 | 0.0 | 64.4 | 1.0 | 1.0 | -0.48 |
| 31 | 2026-07-25 | confirmed deaths | confirmed_deaths | 2 | 97.98 | 3.79 | 0.214 | 3.06 | missing | missing | 95.02 | 2.96 | 0.0 | 1.0 | 1.0 | 0.1 |
| 32 | 2026-07-25 | confirmed deaths | joint | 2 | 127.95 | 4.95 | 0.495 | 7.09 | 1.31 | 2.31 | 46.77 | 0.0 | 81.18 | 0.0 | 1.0 | -0.58 |
| 33 | 2026-07-26 | confirmed deaths | confirmed_deaths | 2 | 105.51 | 4.78 | 0.222 | 3.93 | missing | missing | 104.48 | 1.04 | 0.0 | 1.0 | 1.0 | 0.06 |
| 34 | 2026-07-26 | confirmed deaths | joint | 2 | 144.07 | 6.53 | 0.53 | 9.36 | 1.37 | 2.38 | 43.58 | 0.0 | 100.49 | 0.0 | 1.0 | -0.68 |
| 35 | 2026-07-27 | confirmed deaths | confirmed_deaths | 2 | 123.88 | 4.15 | 0.226 | 2.8 | missing | missing | 110.53 | 13.35 | 0.0 | 1.0 | 1.0 | 0.19 |
| 36 | 2026-07-27 | confirmed deaths | joint | 2 | 133.97 | 4.49 | 0.523 | 6.48 | 1.08 | 2.31 | 51.31 | 0.0 | 82.66 | 0.0 | 1.0 | -0.62 |
| 37 | 2026-07-31 | confirmed deaths | confirmed_deaths | 1 | 67.74 | 3.43 | 0.237 | 3.24 | missing | missing | 67.46 | 0.0 | 0.28 | 1.0 | 1.0 | -0.03 |
| 38 | 2026-07-31 | confirmed deaths | joint | 1 | 101.18 | 5.12 | 0.551 | 7.51 | 1.49 | 2.32 | 29.49 | 0.0 | 71.69 | 0.0 | 1.0 | -0.71 |
| 39 | 2026-08-01 | confirmed deaths | confirmed_deaths | 1 | 56.75 | 1.69 | 0.193 | 1.5 | missing | missing | 56.75 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 |
| 40 | 2026-08-01 | confirmed deaths | joint | 1 | 121.96 | 3.64 | 0.697 | 5.4 | 2.15 | 3.61 | 27.83 | 0.0 | 94.13 | 0.0 | 1.0 | -0.74 |
| 41 | 2026-08-02 | confirmed deaths | confirmed_deaths | 1 | 70.73 | 2.45 | 0.252 | 2.37 | missing | missing | 69.5 | 0.0 | 1.23 | 1.0 | 1.0 | -0.08 |
| 42 | 2026-08-02 | confirmed deaths | joint | 1 | 96.07 | 3.33 | 0.496 | 4.66 | 1.36 | 1.97 | 33.23 | 0.0 | 62.84 | 0.0 | 1.0 | -0.66 |
| 43 | 2026-08-03 | confirmed deaths | confirmed_deaths | 1 | 60.78 | 1.09 | 0.231 | 1.06 | missing | missing | 54.93 | 0.0 | 5.85 | 1.0 | 1.0 | -0.2 |
| 44 | 2026-08-03 | confirmed deaths | joint | 1 | 109.99 | 1.97 | 0.613 | 2.82 | 1.81 | 2.65 | 34.89 | 0.0 | 75.1 | 0.0 | 1.0 | -0.59 |
| 45 | 2026-08-04 | confirmed deaths | confirmed_deaths | 1 | 68.66 | 3.95 | 0.27 | 4.89 | missing | missing | 60.32 | 0.0 | 8.34 | 1.0 | 1.0 | -0.24 |
| 46 | 2026-08-04 | confirmed deaths | joint | 1 | 132.46 | 7.62 | 0.687 | 12.43 | 1.93 | 2.54 | 28.47 | 0.0 | 103.99 | 0.0 | 1.0 | -0.74 |
| 47 | 2026-07-01 | isolation beds | joint | 4 | 90.19 | 1.5 | 0.138 | 1.54 | missing | missing | 13.48 | 0.0 | 76.71 | 0.0 | 0.0 | -0.99 |
| 48 | 2026-07-06 | isolation beds | joint | 4 | 42.87 | 0.62 | 0.066 | 0.63 | missing | missing | 21.07 | 0.0 | 21.8 | 0.0 | 1.0 | -0.64 |
| 49 | 2026-07-08 | isolation beds | joint | 4 | 54.75 | 1.42 | 0.073 | 1.42 | missing | missing | 11.67 | 43.08 | 0.0 | 0.0 | 1.0 | 0.8 |
| 50 | 2026-07-23 | isolation beds | joint | 2 | 77.69 | 2.93 | 0.097 | 2.8 | 1.13 | 0.84 | 24.83 | 52.86 | 0.0 | 0.0 | 1.0 | 0.64 |
| 51 | 2026-07-23 | isolation beds | treatment | 2 | 68.88 | 2.6 | 0.116 | 3.33 | missing | missing | 56.15 | 0.0 | 12.73 | 1.0 | 1.0 | -0.29 |
| 52 | 2026-07-25 | isolation beds | joint | 2 | 92.94 | 2.27 | 0.119 | 2.17 | 1.74 | 1.32 | 25.43 | 67.51 | 0.0 | 0.0 | 1.0 | 0.68 |
| 53 | 2026-07-25 | isolation beds | treatment | 2 | 53.37 | 1.3 | 0.09 | 1.65 | missing | missing | 52.99 | 0.02 | 0.37 | 1.0 | 1.0 | -0.04 |
| 54 | 2026-07-26 | isolation beds | joint | 2 | 85.22 | 3.89 | 0.11 | 3.57 | 1.46 | 1.07 | 29.67 | 55.55 | 0.0 | 0.0 | 1.0 | 0.62 |
| 55 | 2026-07-26 | isolation beds | treatment | 2 | 58.45 | 2.67 | 0.102 | 3.34 | missing | missing | 57.7 | 0.46 | 0.29 | 1.0 | 1.0 | 0.01 |
| 56 | 2026-07-27 | isolation beds | joint | 2 | 76.07 | 3.49 | 0.097 | 3.25 | 1.22 | 0.88 | 33.44 | 42.62 | 0.0 | 0.0 | 1.0 | 0.55 |
| 57 | 2026-07-27 | isolation beds | treatment | 2 | 62.4 | 2.86 | 0.11 | 3.69 | missing | missing | 61.76 | 0.0 | 0.64 | 1.0 | 1.0 | -0.07 |
| 58 | 2026-07-31 | isolation beds | joint | 1 | 65.32 | 2.73 | 0.082 | 2.57 | 0.87 | 0.62 | 36.11 | 29.21 | 0.0 | 0.0 | 1.0 | 0.53 |
| 59 | 2026-07-31 | isolation beds | treatment | 1 | 75.1 | 3.14 | 0.133 | 4.13 | missing | missing | 72.21 | 0.0 | 2.89 | 1.0 | 1.0 | -0.12 |
| 60 | 2026-08-01 | isolation beds | joint | 1 | 48.07 | 2.03 | 0.061 | 1.8 | 0.62 | 0.43 | 35.68 | 12.39 | 0.0 | 1.0 | 1.0 | 0.34 |
| 61 | 2026-08-01 | isolation beds | treatment | 1 | 76.99 | 3.25 | 0.144 | 4.21 | missing | missing | 76.79 | 0.0 | 0.2 | 1.0 | 1.0 | -0.04 |
| 62 | 2026-08-02 | isolation beds | joint | 1 | 74.44 | 4.09 | 0.095 | 3.7 | 0.99 | 0.7 | 38.35 | 36.09 | 0.0 | 0.0 | 1.0 | 0.6 |
| 63 | 2026-08-02 | isolation beds | treatment | 1 | 75.18 | 4.13 | 0.136 | 5.3 | missing | missing | 74.35 | 0.0 | 0.83 | 1.0 | 1.0 | -0.05 |
| 64 | 2026-08-03 | isolation beds | joint | 1 | 54.95 | 3.09 | 0.07 | 2.81 | 0.73 | 0.53 | 36.92 | 18.03 | 0.0 | 1.0 | 1.0 | 0.41 |
| 65 | 2026-08-03 | isolation beds | treatment | 1 | 74.86 | 4.2 | 0.133 | 5.32 | missing | missing | 74.86 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 |
| 66 | 2026-08-04 | isolation beds | joint | 1 | 142.95 | 2.07 | 0.213 | 1.93 | 1.5 | 1.25 | 33.51 | 109.44 | 0.0 | 0.0 | 1.0 | 0.88 |
| 67 | 2026-08-04 | isolation beds | treatment | 1 | 95.26 | 1.38 | 0.17 | 1.54 | missing | missing | 90.62 | 4.64 | 0.0 | 1.0 | 1.0 | 0.12 |
| 68 | 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 |
| 69 | 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 |
| 70 | 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 |
| 71 | 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 |
| 72 | 2026-07-01 | recovered | joint | 4 | 10457.7 | 153.97 | 0.539 | 1.89 | missing | missing | 10409.1 | 48.57 | 0.0 | 1.0 | 1.0 | 0.29 |
| 73 | 2026-07-06 | recovered | joint | 4 | 85.76 | 0.86 | 0.407 | 0.93 | missing | missing | 68.39 | 0.0 | 17.37 | 1.0 | 1.0 | -0.33 |
| 74 | 2026-07-08 | recovered | joint | 4 | 63.08 | 0.8 | 0.292 | 1.05 | missing | missing | 44.51 | 0.0 | 18.57 | 1.0 | 1.0 | -0.38 |
| 75 | 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 |
| 76 | 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.45 | 0.435 | 2.18 | 339.44 | 289.46 | 0.0 | 0.36 | 1.0 | 0.6 |
| 5 | 2026-07-16 | confirmed cases | 3 | 192.87 | 0.41 | 0.157 | 0.29 | 190.39 | 2.15 | 0.33 | 1.0 | 1.0 | 0.02 |
| 6 | 2026-07-18 | confirmed cases | 3 | 246.76 | 0.87 | 0.172 | 0.62 | 222.52 | 24.24 | 0.0 | 1.0 | 1.0 | 0.15 |
| 7 | 2026-07-19 | confirmed cases | 3 | 299.44 | 1.3 | 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.86 | 0.167 | 0.61 | 211.22 | 35.08 | 0.0 | 1.0 | 1.0 | 0.2 |
| 9 | 2026-07-24 | confirmed cases | 2 | 159.85 | 1.8 | 0.152 | 1.45 | 134.55 | 25.3 | 0.0 | 1.0 | 1.0 | 0.29 |
| 10 | 2026-07-25 | confirmed cases | 2 | 202.9 | 4.2 | 0.185 | 3.05 | 150.18 | 52.72 | 0.0 | 1.0 | 1.0 | 0.34 |
| 11 | 2026-07-26 | confirmed cases | 2 | 146.91 | 3.2 | 0.146 | 2.53 | 130.2 | 16.71 | 0.0 | 1.0 | 1.0 | 0.24 |
| 12 | 2026-07-27 | confirmed cases | 2 | 155.94 | 2.65 | 0.16 | 1.95 | 140.24 | 15.7 | 0.0 | 1.0 | 1.0 | 0.26 |
| 13 | 2026-07-28 | confirmed cases | 2 | 145.08 | 1.85 | 0.139 | 1.54 | 132.78 | 12.3 | 0.0 | 1.0 | 1.0 | 0.19 |
| 14 | 2026-07-31 | confirmed cases | 1 | 114.33 | 2.73 | 0.176 | 2.45 | 89.95 | 24.38 | 0.0 | 1.0 | 1.0 | 0.38 |
| 15 | 2026-08-04 | confirmed cases | 1 | 80.42 | 1.99 | 0.127 | 1.9 | 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 | 3 | 284.9 | 1.39 | 1.813 | 4.24 | 58.64 | 0.0 | 226.27 | 0.0 | 1.0 | -0.78 |
| 21 | 2026-07-18 | confirmed deaths | 3 | 246.71 | 1.96 | 1.746 | 7.58 | 72.18 | 0.0 | 174.54 | 0.0 | 1.0 | -0.72 |
| 22 | 2026-07-19 | confirmed deaths | 3 | 230.8 | 2.09 | 1.648 | 8.62 | 83.42 | 0.0 | 147.38 | 0.0 | 1.0 | -0.66 |
| 23 | 2026-07-20 | confirmed deaths | 3 | 264.86 | 1.95 | 1.987 | 8.09 | 73.14 | 0.0 | 191.72 | 0.0 | 1.0 | -0.68 |
| 24 | 2026-07-24 | confirmed deaths | 2 | 223.69 | 9.76 | 2.697 | 46.64 | 41.38 | 0.0 | 182.31 | 0.0 | 1.0 | -0.78 |
| 25 | 2026-07-25 | confirmed deaths | 2 | 212.11 | 8.57 | 2.7 | 38.68 | 47.24 | 0.0 | 164.87 | 0.0 | 1.0 | -0.68 |
| 26 | 2026-07-26 | confirmed deaths | 2 | 255.72 | 11.78 | 3.247 | 59.42 | 31.75 | 0.0 | 223.96 | 0.0 | 1.0 | -0.78 |
| 27 | 2026-07-27 | confirmed deaths | 2 | 248.36 | 9.51 | 3.106 | 43.69 | 37.0 | 0.0 | 211.36 | 0.0 | 1.0 | -0.71 |
| 28 | 2026-07-28 | confirmed deaths | 2 | 278.3 | 5.5 | 2.979 | 27.67 | 38.3 | 0.0 | 239.99 | 0.0 | 1.0 | -0.76 |
| 29 | 2026-07-31 | confirmed deaths | 1 | 208.21 | 10.37 | 3.717 | 48.68 | 10.04 | 0.0 | 198.17 | 0.0 | 1.0 | -0.77 |
| 30 | 2026-08-04 | confirmed deaths | 1 | 287.67 | 15.65 | 4.994 | 83.6 | 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 | 3 | 71.56 | 2.78 | 0.092 | 2.56 | 17.54 | 54.02 | 0.0 | 0.0 | 1.0 | 0.61 |
| 33 | 2026-07-18 | isolation beds | 3 | 77.34 | 2.57 | 0.101 | 2.43 | 15.73 | 61.61 | 0.0 | 0.0 | 1.0 | 0.64 |
| 34 | 2026-07-19 | isolation beds | 3 | 104.5 | 3.98 | 0.135 | 3.76 | 19.04 | 85.46 | 0.0 | 0.0 | 1.0 | 0.68 |
| 35 | 2026-07-20 | isolation beds | 3 | 89.56 | 3.63 | 0.114 | 3.37 | 16.46 | 73.1 | 0.0 | 0.0 | 1.0 | 0.67 |
| 36 | 2026-07-24 | isolation beds | 2 | 95.45 | 4.57 | 0.119 | 4.25 | 7.07 | 88.39 | 0.0 | 0.0 | 1.0 | 0.85 |
| 37 | 2026-07-25 | isolation beds | 2 | 132.76 | 3.04 | 0.169 | 2.89 | 9.86 | 122.9 | 0.0 | 0.0 | 0.5 | 0.86 |
| 38 | 2026-07-26 | isolation beds | 2 | 123.61 | 5.12 | 0.157 | 4.72 | 15.36 | 108.25 | 0.0 | 0.0 | 0.5 | 0.81 |
| 39 | 2026-07-27 | isolation beds | 2 | 95.61 | 4.53 | 0.121 | 4.17 | 27.89 | 67.72 | 0.0 | 0.0 | 1.0 | 0.66 |
| 40 | 2026-07-28 | isolation beds | 2 | 198.85 | 2.65 | 0.268 | 2.36 | 30.38 | 168.47 | 0.0 | 0.0 | 0.5 | 0.9 |
| 41 | 2026-07-31 | isolation beds | 1 | 149.98 | 6.31 | 0.182 | 5.74 | 33.1 | 116.88 | 0.0 | 0.0 | 0.0 | 0.9 |
| 42 | 2026-08-04 | isolation beds | 1 | 169.73 | 2.5 | 0.251 | 2.3 | 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 | 1 | 47.52 | 0.11 | 0.117 | 0.02 | 45.92 | 0.0 | 1.6 | 1.0 | 1.0 | -0.11 |
| 46 | 2026-07-31 | onset reports | 1 | 78.09 | 0.23 | 0.188 | 0.03 | 54.83 | 23.26 | 0.0 | 1.0 | 1.0 | 0.36 |
| 47 | 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 |
| 48 | 2026-07-16 | recovered | 3 | 99.86 | 1.13 | 0.476 | 1.23 | 95.4 | 0.0 | 4.46 | 1.0 | 1.0 | -0.12 |
| 49 | 2026-07-18 | recovered | 3 | 108.04 | 3.0 | 0.445 | 2.75 | 105.09 | 2.95 | 0.0 | 1.0 | 1.0 | 0.1 |
| 50 | 2026-07-19 | recovered | 3 | 119.04 | 3.07 | 0.467 | 3.15 | 117.97 | 1.07 | 0.0 | 1.0 | 1.0 | 0.08 |
| 51 | 2026-07-20 | recovered | 3 | 114.75 | 2.73 | 0.406 | 2.63 | 114.34 | 0.41 | 0.0 | 1.0 | 1.0 | 0.05 |
| 52 | 2026-07-24 | recovered | 2 | 89.56 | 4.57 | 0.379 | 3.25 | 83.96 | 5.6 | 0.0 | 1.0 | 1.0 | 0.18 |
| 53 | 2026-07-25 | recovered | 2 | 88.3 | 4.83 | 0.355 | 3.15 | 83.85 | 4.44 | 0.0 | 1.0 | 1.0 | 0.14 |
| 54 | 2026-07-26 | recovered | 2 | 69.22 | 3.27 | 0.364 | 2.89 | 68.7 | 0.0 | 0.52 | 1.0 | 1.0 | -0.06 |
| 55 | 2026-07-27 | recovered | 2 | 99.21 | 3.67 | 0.446 | 3.11 | 98.13 | 0.0 | 1.08 | 1.0 | 1.0 | -0.08 |
| 56 | 2026-07-28 | recovered | 2 | 82.95 | 1.25 | 0.348 | 0.92 | 81.82 | 0.47 | 0.66 | 1.0 | 1.0 | -0.0 |
| 57 | 2026-07-31 | recovered | 1 | 65.74 | 1.95 | 0.358 | 1.36 | 65.03 | 0.71 | 0.0 | 1.0 | 1.0 | 0.09 |
| 58 | 2026-08-04 | recovered | 1 | 45.37 | 2.13 | 0.412 | 3.19 | 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 | 200 | 553.29 | 1.64 | 0.324 | 0.32 | 334.44 | 218.82 | 0.02 | 0.64 | 1.0 | 0.41 |
| 2 | confirmed deaths | 200 | 202.31 | 1.68 | 1.593 | 1.04 | 82.71 | 0.86 | 118.73 | 0.4 | 0.98 | -0.42 |
| 3 | isolation beds | 68 | 109.4 | 0.91 | 0.161 | 0.61 | 26.2 | 64.72 | 18.49 | 0.03 | 0.85 | 0.37 |
| 4 | onset reports | 6 | 93.95 | 0.21 | 0.184 | 0.03 | 57.42 | 36.16 | 0.37 | 0.67 | 1.0 | 0.3 |
| 5 | recovered | 68 | 123.18 | 1.42 | 0.427 | 0.43 | 111.04 | 11.5 | 0.63 | 1.0 | 1.0 | 0.12 |
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.18 |
| 2 | confirmed cases | 14 | 53 | 225.65 | 1.0 | 0.188 | 0.22 | 188.59 | 37.06 | 0.0 | 1.0 | 1.0 | 0.27 |
| 3 | confirmed cases | 21 | 48 | 614.86 | 1.37 | 0.412 | 0.32 | 356.77 | 258.08 | 0.0 | 0.42 | 1.0 | 0.53 |
| 4 | confirmed cases | 28 | 44 | 1455.72 | 2.11 | 0.614 | 0.36 | 799.89 | 655.83 | 0.0 | 0.0 | 1.0 | 0.71 |
| 5 | confirmed deaths | 7 | 55 | 210.33 | 9.46 | 3.593 | 5.39 | 9.56 | 0.0 | 200.76 | 0.0 | 0.91 | -0.84 |
| 6 | confirmed deaths | 14 | 53 | 233.35 | 3.53 | 1.565 | 1.26 | 66.2 | 0.0 | 167.15 | 0.15 | 1.0 | -0.59 |
| 7 | confirmed deaths | 21 | 48 | 185.9 | 1.13 | 0.562 | 0.29 | 105.42 | 0.36 | 80.11 | 0.58 | 1.0 | -0.22 |
| 8 | confirmed deaths | 28 | 44 | 172.8 | 0.67 | 0.25 | 0.1 | 169.27 | 3.53 | 0.0 | 1.0 | 1.0 | 0.1 |
| 9 | isolation beds | 7 | 22 | 111.85 | 2.81 | 0.144 | 1.51 | 17.28 | 94.57 | 0.0 | 0.0 | 0.55 | 0.83 |
| 10 | isolation beds | 14 | 20 | 109.25 | 2.4 | 0.147 | 1.31 | 21.05 | 88.19 | 0.0 | 0.1 | 1.0 | 0.67 |
| 11 | isolation beds | 21 | 15 | 89.74 | 0.46 | 0.146 | 0.34 | 32.01 | 37.1 | 20.64 | 0.0 | 1.0 | 0.06 |
| 12 | isolation beds | 28 | 11 | 131.59 | 0.42 | 0.243 | 0.37 | 45.45 | 0.0 | 86.14 | 0.0 | 1.0 | -0.69 |
| 13 | onset reports | 7 | 4 | 63.37 | 0.18 | 0.169 | 0.03 | 47.42 | 15.39 | 0.56 | 0.75 | 1.0 | 0.18 |
| 14 | onset reports | 14 | 2 | 155.1 | 0.25 | 0.213 | 0.03 | 77.4 | 77.7 | 0.0 | 0.5 | 1.0 | 0.54 |
| 15 | recovered | 7 | 22 | 49.1 | 3.34 | 0.402 | 2.42 | 47.12 | 0.57 | 1.42 | 1.0 | 1.0 | -0.0 |
| 16 | recovered | 14 | 20 | 108.23 | 2.03 | 0.407 | 0.52 | 104.96 | 2.84 | 0.43 | 1.0 | 1.0 | 0.07 |
| 17 | recovered | 21 | 15 | 150.74 | 1.17 | 0.438 | 0.3 | 142.74 | 7.77 | 0.22 | 1.0 | 1.0 | 0.14 |
| 18 | recovered | 28 | 11 | 260.94 | 1.12 | 0.499 | 0.21 | 206.71 | 54.22 | 0.0 | 1.0 | 1.0 | 0.43 |
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.45 | 0.435 | 2.18 | 339.44 | 289.46 | 0.0 | 0.36 | 1.0 | 0.6 |
| 5 | 2026-07-16 | confirmed cases | 3 | 192.87 | 0.41 | 0.157 | 0.29 | 190.39 | 2.15 | 0.33 | 1.0 | 1.0 | 0.02 |
| 6 | 2026-07-18 | confirmed cases | 3 | 246.76 | 0.87 | 0.172 | 0.62 | 222.52 | 24.24 | 0.0 | 1.0 | 1.0 | 0.15 |
| 7 | 2026-07-19 | confirmed cases | 3 | 299.44 | 1.3 | 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.86 | 0.167 | 0.61 | 211.22 | 35.08 | 0.0 | 1.0 | 1.0 | 0.2 |
| 9 | 2026-07-24 | confirmed cases | 2 | 159.85 | 1.8 | 0.152 | 1.45 | 134.55 | 25.3 | 0.0 | 1.0 | 1.0 | 0.29 |
| 10 | 2026-07-25 | confirmed cases | 2 | 202.9 | 4.2 | 0.185 | 3.05 | 150.18 | 52.72 | 0.0 | 1.0 | 1.0 | 0.34 |
| 11 | 2026-07-26 | confirmed cases | 2 | 146.91 | 3.2 | 0.146 | 2.53 | 130.2 | 16.71 | 0.0 | 1.0 | 1.0 | 0.24 |
| 12 | 2026-07-27 | confirmed cases | 2 | 155.94 | 2.65 | 0.16 | 1.95 | 140.24 | 15.7 | 0.0 | 1.0 | 1.0 | 0.26 |
| 13 | 2026-07-28 | confirmed cases | 2 | 145.08 | 1.85 | 0.139 | 1.54 | 132.78 | 12.3 | 0.0 | 1.0 | 1.0 | 0.19 |
| 14 | 2026-07-31 | confirmed cases | 1 | 114.33 | 2.73 | 0.176 | 2.45 | 89.95 | 24.38 | 0.0 | 1.0 | 1.0 | 0.38 |
| 15 | 2026-08-04 | confirmed cases | 1 | 80.42 | 1.99 | 0.127 | 1.9 | 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 | 3 | 284.9 | 1.39 | 1.813 | 4.24 | 58.64 | 0.0 | 226.27 | 0.0 | 1.0 | -0.78 |
| 21 | 2026-07-18 | confirmed deaths | 3 | 246.71 | 1.96 | 1.746 | 7.58 | 72.18 | 0.0 | 174.54 | 0.0 | 1.0 | -0.72 |
| 22 | 2026-07-19 | confirmed deaths | 3 | 230.8 | 2.09 | 1.648 | 8.62 | 83.42 | 0.0 | 147.38 | 0.0 | 1.0 | -0.66 |
| 23 | 2026-07-20 | confirmed deaths | 3 | 264.86 | 1.95 | 1.987 | 8.09 | 73.14 | 0.0 | 191.72 | 0.0 | 1.0 | -0.68 |
| 24 | 2026-07-24 | confirmed deaths | 2 | 223.69 | 9.76 | 2.697 | 46.64 | 41.38 | 0.0 | 182.31 | 0.0 | 1.0 | -0.78 |
| 25 | 2026-07-25 | confirmed deaths | 2 | 212.11 | 8.57 | 2.7 | 38.68 | 47.24 | 0.0 | 164.87 | 0.0 | 1.0 | -0.68 |
| 26 | 2026-07-26 | confirmed deaths | 2 | 255.72 | 11.78 | 3.247 | 59.42 | 31.75 | 0.0 | 223.96 | 0.0 | 1.0 | -0.78 |
| 27 | 2026-07-27 | confirmed deaths | 2 | 248.36 | 9.51 | 3.106 | 43.69 | 37.0 | 0.0 | 211.36 | 0.0 | 1.0 | -0.71 |
| 28 | 2026-07-28 | confirmed deaths | 2 | 278.3 | 5.5 | 2.979 | 27.67 | 38.3 | 0.0 | 239.99 | 0.0 | 1.0 | -0.76 |
| 29 | 2026-07-31 | confirmed deaths | 1 | 208.21 | 10.37 | 3.717 | 48.68 | 10.04 | 0.0 | 198.17 | 0.0 | 1.0 | -0.77 |
| 30 | 2026-08-04 | confirmed deaths | 1 | 287.67 | 15.65 | 4.994 | 83.6 | 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 | 3 | 71.56 | 2.78 | 0.092 | 2.56 | 17.54 | 54.02 | 0.0 | 0.0 | 1.0 | 0.61 |
| 33 | 2026-07-18 | isolation beds | 3 | 77.34 | 2.57 | 0.101 | 2.43 | 15.73 | 61.61 | 0.0 | 0.0 | 1.0 | 0.64 |
| 34 | 2026-07-19 | isolation beds | 3 | 104.5 | 3.98 | 0.135 | 3.76 | 19.04 | 85.46 | 0.0 | 0.0 | 1.0 | 0.68 |
| 35 | 2026-07-20 | isolation beds | 3 | 89.56 | 3.63 | 0.114 | 3.37 | 16.46 | 73.1 | 0.0 | 0.0 | 1.0 | 0.67 |
| 36 | 2026-07-24 | isolation beds | 2 | 95.45 | 4.57 | 0.119 | 4.25 | 7.07 | 88.39 | 0.0 | 0.0 | 1.0 | 0.85 |
| 37 | 2026-07-25 | isolation beds | 2 | 132.76 | 3.04 | 0.169 | 2.89 | 9.86 | 122.9 | 0.0 | 0.0 | 0.5 | 0.86 |
| 38 | 2026-07-26 | isolation beds | 2 | 123.61 | 5.12 | 0.157 | 4.72 | 15.36 | 108.25 | 0.0 | 0.0 | 0.5 | 0.81 |
| 39 | 2026-07-27 | isolation beds | 2 | 95.61 | 4.53 | 0.121 | 4.17 | 27.89 | 67.72 | 0.0 | 0.0 | 1.0 | 0.66 |
| 40 | 2026-07-28 | isolation beds | 2 | 198.85 | 2.65 | 0.268 | 2.36 | 30.38 | 168.47 | 0.0 | 0.0 | 0.5 | 0.9 |
| 41 | 2026-07-31 | isolation beds | 1 | 149.98 | 6.31 | 0.182 | 5.74 | 33.1 | 116.88 | 0.0 | 0.0 | 0.0 | 0.9 |
| 42 | 2026-08-04 | isolation beds | 1 | 169.73 | 2.5 | 0.251 | 2.3 | 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 | 1 | 47.52 | 0.11 | 0.117 | 0.02 | 45.92 | 0.0 | 1.6 | 1.0 | 1.0 | -0.11 |
| 46 | 2026-07-31 | onset reports | 1 | 78.09 | 0.23 | 0.188 | 0.03 | 54.83 | 23.26 | 0.0 | 1.0 | 1.0 | 0.36 |
| 47 | 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 |
| 48 | 2026-07-16 | recovered | 3 | 99.86 | 1.13 | 0.476 | 1.23 | 95.4 | 0.0 | 4.46 | 1.0 | 1.0 | -0.12 |
| 49 | 2026-07-18 | recovered | 3 | 108.04 | 3.0 | 0.445 | 2.75 | 105.09 | 2.95 | 0.0 | 1.0 | 1.0 | 0.1 |
| 50 | 2026-07-19 | recovered | 3 | 119.04 | 3.07 | 0.467 | 3.15 | 117.97 | 1.07 | 0.0 | 1.0 | 1.0 | 0.08 |
| 51 | 2026-07-20 | recovered | 3 | 114.75 | 2.73 | 0.406 | 2.63 | 114.34 | 0.41 | 0.0 | 1.0 | 1.0 | 0.05 |
| 52 | 2026-07-24 | recovered | 2 | 89.56 | 4.57 | 0.379 | 3.25 | 83.96 | 5.6 | 0.0 | 1.0 | 1.0 | 0.18 |
| 53 | 2026-07-25 | recovered | 2 | 88.3 | 4.83 | 0.355 | 3.15 | 83.85 | 4.44 | 0.0 | 1.0 | 1.0 | 0.14 |
| 54 | 2026-07-26 | recovered | 2 | 69.22 | 3.27 | 0.364 | 2.89 | 68.7 | 0.0 | 0.52 | 1.0 | 1.0 | -0.06 |
| 55 | 2026-07-27 | recovered | 2 | 99.21 | 3.67 | 0.446 | 3.11 | 98.13 | 0.0 | 1.08 | 1.0 | 1.0 | -0.08 |
| 56 | 2026-07-28 | recovered | 2 | 82.95 | 1.25 | 0.348 | 0.92 | 81.82 | 0.47 | 0.66 | 1.0 | 1.0 | -0.0 |
| 57 | 2026-07-31 | recovered | 1 | 65.74 | 1.95 | 0.358 | 1.36 | 65.03 | 0.71 | 0.0 | 1.0 | 1.0 | 0.09 |
| 58 | 2026-08-04 | recovered | 1 | 45.37 | 2.13 | 0.412 | 3.19 | 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 | 2 | 143.83 | 1.35 | 0.187 | 1.52 | missing | missing | 136.73 | 0.0 | 7.1 | 1.0 | 1.0 | -0.14 |
| 2 | 2026-07-25 | confirmed cases | confirmed | 2 | 178.33 | 3.99 | 0.208 | 3.67 | missing | missing | 176.3 | 1.95 | 0.08 | 1.0 | 1.0 | 0.03 |
| 3 | 2026-07-26 | confirmed cases | confirmed | 2 | 146.77 | 3.46 | 0.206 | 3.88 | 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.75 | 0.161 | 2.33 | missing | missing | 134.26 | 0.74 | 0.08 | 1.0 | 1.0 | 0.02 |
| 5 | 2026-07-31 | confirmed cases | confirmed | 1 | 119.08 | 2.78 | 0.205 | 2.74 | missing | missing | 119.04 | 0.04 | 0.0 | 1.0 | 1.0 | 0.01 |
| 6 | 2026-08-01 | confirmed cases | confirmed | 1 | 97.35 | 3.2 | 0.189 | 3.42 | missing | missing | 97.16 | 0.19 | 0.0 | 1.0 | 1.0 | 0.02 |
| 7 | 2026-08-02 | confirmed cases | confirmed | 1 | 91.77 | 2.24 | 0.163 | 2.12 | 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.05 | 0.164 | 0.95 | 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.45 | 0.167 | 2.61 | missing | missing | 94.7 | 0.0 | 0.15 | 1.0 | 1.0 | -0.02 |
| 10 | 2026-07-23 | confirmed deaths | confirmed_deaths | 2 | 239.07 | 6.17 | 0.334 | 3.77 | missing | missing | 158.26 | 80.82 | 0.0 | 0.5 | 1.0 | 0.45 |
| 11 | 2026-07-25 | confirmed deaths | confirmed_deaths | 2 | 97.98 | 3.79 | 0.214 | 3.06 | missing | missing | 95.02 | 2.96 | 0.0 | 1.0 | 1.0 | 0.1 |
| 12 | 2026-07-26 | confirmed deaths | confirmed_deaths | 2 | 105.51 | 4.78 | 0.222 | 3.93 | missing | missing | 104.48 | 1.04 | 0.0 | 1.0 | 1.0 | 0.06 |
| 13 | 2026-07-27 | confirmed deaths | confirmed_deaths | 2 | 123.88 | 4.15 | 0.226 | 2.8 | missing | missing | 110.53 | 13.35 | 0.0 | 1.0 | 1.0 | 0.19 |
| 14 | 2026-07-31 | confirmed deaths | confirmed_deaths | 1 | 67.74 | 3.43 | 0.237 | 3.24 | missing | missing | 67.46 | 0.0 | 0.28 | 1.0 | 1.0 | -0.03 |
| 15 | 2026-08-01 | confirmed deaths | confirmed_deaths | 1 | 56.75 | 1.69 | 0.193 | 1.5 | missing | missing | 56.75 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 |
| 16 | 2026-08-02 | confirmed deaths | confirmed_deaths | 1 | 70.73 | 2.45 | 0.252 | 2.37 | missing | missing | 69.5 | 0.0 | 1.23 | 1.0 | 1.0 | -0.08 |
| 17 | 2026-08-03 | confirmed deaths | confirmed_deaths | 1 | 60.78 | 1.09 | 0.231 | 1.06 | missing | missing | 54.93 | 0.0 | 5.85 | 1.0 | 1.0 | -0.2 |
| 18 | 2026-08-04 | confirmed deaths | confirmed_deaths | 1 | 68.66 | 3.95 | 0.27 | 4.89 | missing | missing | 60.32 | 0.0 | 8.34 | 1.0 | 1.0 | -0.24 |
| 19 | 2026-07-23 | isolation beds | treatment | 2 | 68.88 | 2.6 | 0.116 | 3.33 | missing | missing | 56.15 | 0.0 | 12.73 | 1.0 | 1.0 | -0.29 |
| 20 | 2026-07-25 | isolation beds | treatment | 2 | 53.37 | 1.3 | 0.09 | 1.65 | missing | missing | 52.99 | 0.02 | 0.37 | 1.0 | 1.0 | -0.04 |
| 21 | 2026-07-26 | isolation beds | treatment | 2 | 58.45 | 2.67 | 0.102 | 3.34 | missing | missing | 57.7 | 0.46 | 0.29 | 1.0 | 1.0 | 0.01 |
| 22 | 2026-07-27 | isolation beds | treatment | 2 | 62.4 | 2.86 | 0.11 | 3.69 | missing | missing | 61.76 | 0.0 | 0.64 | 1.0 | 1.0 | -0.07 |
| 23 | 2026-07-31 | isolation beds | treatment | 1 | 75.1 | 3.14 | 0.133 | 4.13 | missing | missing | 72.21 | 0.0 | 2.89 | 1.0 | 1.0 | -0.12 |
| 24 | 2026-08-01 | isolation beds | treatment | 1 | 76.99 | 3.25 | 0.144 | 4.21 | missing | missing | 76.79 | 0.0 | 0.2 | 1.0 | 1.0 | -0.04 |
| 25 | 2026-08-02 | isolation beds | treatment | 1 | 75.18 | 4.13 | 0.136 | 5.3 | missing | missing | 74.35 | 0.0 | 0.83 | 1.0 | 1.0 | -0.05 |
| 26 | 2026-08-03 | isolation beds | treatment | 1 | 74.86 | 4.2 | 0.133 | 5.32 | missing | missing | 74.86 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 |
| 27 | 2026-08-04 | isolation beds | treatment | 1 | 95.26 | 1.38 | 0.17 | 1.54 | missing | missing | 90.62 | 4.64 | 0.0 | 1.0 | 1.0 | 0.12 |
| 28 | 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 |
| 29 | 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 |
| 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 | 13 | 130.7 | 2.35 | 0.185 | 2.3 | missing | missing | 126.59 | 0.43 | 3.68 | 1.0 | 1.0 | -0.06 |
| 2 | confirmed deaths | confirmed_deaths | 13 | 112.12 | 3.75 | 0.244 | 2.71 | missing | missing | 95.81 | 15.1 | 1.21 | 0.92 | 1.0 | 0.08 |
| 3 | isolation beds | treatment | 13 | 67.97 | 2.36 | 0.119 | 2.94 | missing | missing | 65.08 | 0.43 | 2.46 | 1.0 | 1.0 | -0.07 |
| 4 | onset reports | onsets | 2 | 113.73 | 0.39 | 0.475 | 0.09 | missing | missing | 63.87 | 40.58 | 9.28 | 0.5 | 1.0 | 0.18 |
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 | 9 | 97.24 | 2.2 | 0.183 | 2.26 | missing | missing | 93.97 | 0.03 | 3.25 | 1.0 | 1.0 | -0.08 |
| 2 | confirmed cases | 14 | confirmed | 4 | 205.99 | 2.54 | 0.191 | 2.4 | missing | missing | 200.0 | 1.34 | 4.65 | 1.0 | 1.0 | -0.02 |
| 3 | confirmed deaths | 7 | confirmed_deaths | 9 | 68.79 | 2.42 | 0.232 | 2.26 | missing | missing | 63.41 | 3.63 | 1.74 | 1.0 | 1.0 | 0.01 |
| 4 | confirmed deaths | 14 | confirmed_deaths | 4 | 209.62 | 6.3 | 0.273 | 4.37 | missing | missing | 168.72 | 40.9 | 0.0 | 0.75 | 1.0 | 0.25 |
| 5 | isolation beds | 7 | treatment | 9 | 73.06 | 2.53 | 0.13 | 3.13 | missing | missing | 69.66 | 0.52 | 2.88 | 1.0 | 1.0 | -0.07 |
| 6 | isolation beds | 14 | treatment | 4 | 56.51 | 1.97 | 0.096 | 2.48 | missing | missing | 54.77 | 0.23 | 1.51 | 1.0 | 1.0 | -0.07 |
| 7 | onset reports | 7 | onsets | 2 | 113.73 | 0.39 | 0.475 | 0.09 | missing | missing | 63.87 | 40.58 | 9.28 | 0.5 | 1.0 | 0.18 |
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 | 2 | 143.83 | 1.35 | 0.187 | 1.52 | missing | missing | 136.73 | 0.0 | 7.1 | 1.0 | 1.0 | -0.14 |
| 2 | 2026-07-25 | confirmed cases | confirmed | 2 | 178.33 | 3.99 | 0.208 | 3.67 | missing | missing | 176.3 | 1.95 | 0.08 | 1.0 | 1.0 | 0.03 |
| 3 | 2026-07-26 | confirmed cases | confirmed | 2 | 146.77 | 3.46 | 0.206 | 3.88 | 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.75 | 0.161 | 2.33 | missing | missing | 134.26 | 0.74 | 0.08 | 1.0 | 1.0 | 0.02 |
| 5 | 2026-07-31 | confirmed cases | confirmed | 1 | 119.08 | 2.78 | 0.205 | 2.74 | missing | missing | 119.04 | 0.04 | 0.0 | 1.0 | 1.0 | 0.01 |
| 6 | 2026-08-01 | confirmed cases | confirmed | 1 | 97.35 | 3.2 | 0.189 | 3.42 | missing | missing | 97.16 | 0.19 | 0.0 | 1.0 | 1.0 | 0.02 |
| 7 | 2026-08-02 | confirmed cases | confirmed | 1 | 91.77 | 2.24 | 0.163 | 2.12 | 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.05 | 0.164 | 0.95 | 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.45 | 0.167 | 2.61 | missing | missing | 94.7 | 0.0 | 0.15 | 1.0 | 1.0 | -0.02 |
| 10 | 2026-07-23 | confirmed deaths | confirmed_deaths | 2 | 239.07 | 6.17 | 0.334 | 3.77 | missing | missing | 158.26 | 80.82 | 0.0 | 0.5 | 1.0 | 0.45 |
| 11 | 2026-07-25 | confirmed deaths | confirmed_deaths | 2 | 97.98 | 3.79 | 0.214 | 3.06 | missing | missing | 95.02 | 2.96 | 0.0 | 1.0 | 1.0 | 0.1 |
| 12 | 2026-07-26 | confirmed deaths | confirmed_deaths | 2 | 105.51 | 4.78 | 0.222 | 3.93 | missing | missing | 104.48 | 1.04 | 0.0 | 1.0 | 1.0 | 0.06 |
| 13 | 2026-07-27 | confirmed deaths | confirmed_deaths | 2 | 123.88 | 4.15 | 0.226 | 2.8 | missing | missing | 110.53 | 13.35 | 0.0 | 1.0 | 1.0 | 0.19 |
| 14 | 2026-07-31 | confirmed deaths | confirmed_deaths | 1 | 67.74 | 3.43 | 0.237 | 3.24 | missing | missing | 67.46 | 0.0 | 0.28 | 1.0 | 1.0 | -0.03 |
| 15 | 2026-08-01 | confirmed deaths | confirmed_deaths | 1 | 56.75 | 1.69 | 0.193 | 1.5 | missing | missing | 56.75 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 |
| 16 | 2026-08-02 | confirmed deaths | confirmed_deaths | 1 | 70.73 | 2.45 | 0.252 | 2.37 | missing | missing | 69.5 | 0.0 | 1.23 | 1.0 | 1.0 | -0.08 |
| 17 | 2026-08-03 | confirmed deaths | confirmed_deaths | 1 | 60.78 | 1.09 | 0.231 | 1.06 | missing | missing | 54.93 | 0.0 | 5.85 | 1.0 | 1.0 | -0.2 |
| 18 | 2026-08-04 | confirmed deaths | confirmed_deaths | 1 | 68.66 | 3.95 | 0.27 | 4.89 | missing | missing | 60.32 | 0.0 | 8.34 | 1.0 | 1.0 | -0.24 |
| 19 | 2026-07-23 | isolation beds | treatment | 2 | 68.88 | 2.6 | 0.116 | 3.33 | missing | missing | 56.15 | 0.0 | 12.73 | 1.0 | 1.0 | -0.29 |
| 20 | 2026-07-25 | isolation beds | treatment | 2 | 53.37 | 1.3 | 0.09 | 1.65 | missing | missing | 52.99 | 0.02 | 0.37 | 1.0 | 1.0 | -0.04 |
| 21 | 2026-07-26 | isolation beds | treatment | 2 | 58.45 | 2.67 | 0.102 | 3.34 | missing | missing | 57.7 | 0.46 | 0.29 | 1.0 | 1.0 | 0.01 |
| 22 | 2026-07-27 | isolation beds | treatment | 2 | 62.4 | 2.86 | 0.11 | 3.69 | missing | missing | 61.76 | 0.0 | 0.64 | 1.0 | 1.0 | -0.07 |
| 23 | 2026-07-31 | isolation beds | treatment | 1 | 75.1 | 3.14 | 0.133 | 4.13 | missing | missing | 72.21 | 0.0 | 2.89 | 1.0 | 1.0 | -0.12 |
| 24 | 2026-08-01 | isolation beds | treatment | 1 | 76.99 | 3.25 | 0.144 | 4.21 | missing | missing | 76.79 | 0.0 | 0.2 | 1.0 | 1.0 | -0.04 |
| 25 | 2026-08-02 | isolation beds | treatment | 1 | 75.18 | 4.13 | 0.136 | 5.3 | missing | missing | 74.35 | 0.0 | 0.83 | 1.0 | 1.0 | -0.05 |
| 26 | 2026-08-03 | isolation beds | treatment | 1 | 74.86 | 4.2 | 0.133 | 5.32 | missing | missing | 74.86 | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 |
| 27 | 2026-08-04 | isolation beds | treatment | 1 | 95.26 | 1.38 | 0.17 | 1.54 | missing | missing | 90.62 | 4.64 | 0.0 | 1.0 | 1.0 | 0.12 |
| 28 | 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 |
| 29 | 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 |
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 | 3316.0 | 11843.0 | 24612.0 | 122568.0 | 325104.0 | 3.29286e6 |
| 2 | deaths (DRC) | 19741.0 | 27310.0 | 32900.0 | 49327.0 | 65124.0 | 113411.0 |
| 3 | cases (DRC) | 23440.0 | 26104.0 | 28605.0 | 36432.0 | 44752.0 | 78722.0 |
| 4 | confirmed (DRC) | 33798.0 | 41924.0 | 47987.0 | 63453.0 | 80877.0 | 136872.0 |
| 5 | isolation (DRC) | 8066.0 | 9509.0 | 10555.0 | 13058.0 | 15664.0 | 24817.0 |
| 6 | onsets (DRC) | 12272.0 | 19025.0 | 25343.0 | 41489.0 | 57115.0 | 101965.0 |
| 7 | joint | 6991.0 | 7878.0 | 8570.0 | 10324.0 | 11543.0 | 14550.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) | 4567 (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}:
11470.434558356505
17647.852872812644
19841.619673568635
16946.124751239546
13530.867115782401
11635.628573918137
10888.649245206483
11983.99351336981
11288.146504532713
10552.984530730319
10378.828520469007
7343.688782650602
7083.921673545357
7671.450633419554
7199.792887167545
7998.698375876502
7904.939728261323
7790.105936716705
6963.787279927257
6524.903346143492
7151.304827678792
7248.075844876781
7904.391775317243
7710.802288195973
8725.181522984749
8530.675133279758
9186.960004660341
7389.255897040006
7733.355097778021
10113.44608724201
8124.801751482269
9303.48865624667
9399.196350613716
9659.795544293436
13127.516229768908
8015.840954921742
9314.317137654658
7821.488346183867
9632.649324852217
9996.415742567291
9024.32450791996
9375.949651256684
12993.883351113163
12048.138463235691
11087.543659493349
9377.996017391642
9562.547389169933
10891.39352708183
12479.977953181718
11083.50770962046
8363.74793910918
10246.31056438247
11277.456245237421
11073.028633009073
15138.533280544452
12309.31334194566
17105.017154191155
15060.699665478875
17658.430920471856
11867.193848958908
8476.534047674772
10302.437453926617
8641.58115144213
12311.102798248645
9101.938153433255
11318.23107433699
9964.748012555241
12207.082317602597
9269.384872861652
6540.0110266846505
7657.584742729918
6806.696371458162
6718.734383654959
7121.759364525644
8009.650913046976
8562.419886228718
8218.342448021038
7219.49843453378
6553.849400545668
7169.942297617953
6133.135041097059
6315.018058132472
7034.30375092659
6788.826974775935
7791.47392233857
7085.9327837199235
7367.207389641797
7212.827139824482
8370.267431136897
8148.863246159572
9695.451353327982
8169.950129488801
6903.469849507669
9194.019187105065
9350.854073828674
9146.7136923431
9922.106379824874
7804.123332173352
8240.025653476418
8497.238087539874
8273.337673839078
8362.315985656773
8411.876972175058
9161.881735311968
12082.155793336566
9740.928851755769
8470.393454019568
7131.052466721089
7774.254272264608
8720.756597902064
7997.291413909275
7739.230519373332
9434.926553177298
9906.683391042065
9844.537018390603
12283.477577817772
8483.60323189627
9952.978885709907
8682.007809913683
8201.27329833232
8342.09634306206
10849.04612223225
9737.911187072355
11392.000426108765
9263.129949104268
12862.181364027207
8624.982315848267
7698.653026042852
7306.647748702779
8079.004160765482
8382.662071005634
6159.6616113838245
10258.581434839072
9314.76743036206
12032.67608902322
8397.225260857178
11037.299307097304
10152.67251502942
8531.196587235532
7880.279277373684
7822.80660052159
7517.456029244223
7271.669750274472
9048.119704521527
9282.63327510678
7222.629004076914
6985.555400362133
6729.52650242002
6457.4032507363645
6528.2549107053665
8733.527271396419
7469.032956449368
8991.611779232247
8039.4249106382795
8393.872730187722
7302.2085572723
9776.751957057626
10720.539135064464
8524.261275724657
6230.82006123389
10465.580224111925
7891.130460778127
8023.062664863127
10068.61128899371
9774.153143602833
9687.10409221395
12741.717255737361
13981.596832757943
9065.856280832148
7855.563088265608
9083.975293301737
9617.420437626866
10427.883398116312
10018.84559505466
13185.383499963085
10409.224997191557
13069.397261530807
11456.295841226234
11114.649475778733
10377.677040743523
9603.607705051598
10327.936294973957
10193.276847288413
9425.203439020333
10426.054134470985
12796.366464655539
9698.80835464121
7632.234573188497
7639.01754397523
8361.468983156401
7817.866174783315
9339.854430727743
7736.331390013123
8146.399248798154
11629.89775894495
7173.581724715031
7383.1496003718685
7694.196307030368
7933.7576991447395
9935.823917427317
9508.6742968621
8907.668846724457
9414.452271799555
10722.250352218802
9281.831946956292
8649.42612294801
9071.590073494655
7547.557120173624
8028.489874660446
6790.867148926102
7219.615177150186
8693.697692259497
9877.00424691551
8719.269039259627
8137.590810493594
8891.847886185604
9176.593506134008
12982.47348266019
8329.754731249166
10446.727749962942
9194.21636593267
8488.218226229805
9221.135065997398
9430.637521620587
7884.993714767032
7981.719310792603
7925.57055579704
9372.292687072077
8725.945091770704
10640.534035719518
11958.870449300628
16228.031024774833
11875.193642688042
11469.297973192924
12362.482765847839
12376.686630946619
7273.792337655598
6547.651355515894
6591.333452504169
8635.735162769392
7995.377557854011
7291.570235976039
7306.911378261249
7457.695303528274
6804.304679051519
9719.918259632625
7521.575875500336
8521.317761394654
7802.988795300116
8558.890640692247
7768.34665896699
7828.184440215491
7304.704013752854
7806.76931233583
8501.42726585547
10158.384627225056
14178.635564975792
8218.0459744922
7355.035388329058
7184.432755222432
13059.079979405751
10944.812096030746
12309.813555290155
11816.9334929417
14020.856808897248
11359.684548190015
7951.599531079462
8446.99723879314
7915.863756036016
7642.860157136096
8200.616006102598
10576.769108984447
9975.25721077406
9483.291813593149
9080.874269316493
7858.58655874567
8555.964908162603
8574.435338586949
7749.32288331217
7607.91929324167
10518.720137132921
10478.791891780898
13753.833489512945
9690.814809832564
8921.160065249598
11817.705030215537
10580.938772352529
10259.718988200764
10415.096775069409
8603.482912978527
9377.228552255425
8795.398287349926
8923.605275283788
8782.313460599818
7983.428529062681
7045.73154385247
8912.783736302146
9898.877765280891
9364.226185433186
11104.273434899555
9565.079596641042
16300.68075319957
11856.97666587357
8984.658382339356
9688.29156064713
8438.187997706375
8246.937286831551
9508.531366788715
9551.307036586777
8827.22760247249
8173.092908444735
8920.130743479072
8495.214338901944
8426.61877177679
7667.443355272255
6168.2814720081105
8795.094040183207
8283.802690881379
11103.018819348345
10786.97199366885
9517.587334360449
9273.83307505195
10473.534274013231
7275.106781136707
8118.723720554992
7580.488489634395
8604.583800695007
7345.621586989206
7468.131138946896
9494.830734673837
6994.380055963225
7230.7463738743645
7585.372588149527
7974.04678092275
7438.692855176513
9519.746528059859
8960.429176918133
7681.908368751849
8086.230763230881
10787.398002796781
9307.756600193794
7730.549724541536
8988.26075916602
6098.96618963552
6355.4310749937085
7070.963433747034
7122.929227725176
7550.973831097331
9575.396861631187
14418.674436436773
9077.763495181225
11084.998916590284
9302.362906443435
9020.387407294926
8341.369269735671
9695.718704988312
8538.562801603239
8038.47456478877
11390.78132235118
11408.261660531656
9217.510633199507
11585.117683646327
8022.805145488282
11141.78509342215
10014.914292051813
11292.388344402672
9577.90621668032
10723.673634674487
9460.889344647401
11981.532594700904
9696.621816230954
13140.874565031807
7868.773384916161
9679.876994060518
6575.217051474084
6724.381755549946
7584.848857263356
6627.624471184898
7123.525528980531
7810.843218313852
8340.50651790811
8576.141276196326
9710.008570980077
8612.058810621973
8012.764684609119
7375.403950403218
6287.120500920186
7735.345844692861
8234.193376811952
8116.314061449641
10066.502133302025
11878.469511006559
10359.432394629088
10142.309832557245
7862.176675354602
8101.922317256901
10335.335027700705
10263.466074528602
8253.964204331689
9164.303643359954
6923.780748580175
7451.429902131897
5971.295305050322
7382.469712164665
8139.24262888894
7838.595922655787
7178.957850775545
7876.222813340969
8717.534251892126
9902.776932672088
10830.752646204257
7548.948137458147
7940.033575638925
7947.692981541783
5942.544347220783
7063.731563365567
7135.292064967398
5851.658907279822
6175.775493083874
6643.64424255374
6319.900789804125
9670.723075430085
9925.028768259734
11358.262842603941
11741.925424314712
8586.363586116284
9781.927042208798
15257.306563997767
9946.780032190403
7189.207060215672
9011.560872512893
7775.489190883804
8064.689665186008
7136.920753124348
7723.363396902433
8149.343482725584
6598.611311240025
7193.463156724747
6742.96883292356
6418.038025919264
8209.118590296624
8131.313804124679
7518.263550925819
7590.71545462456
8847.212303047192
8444.395159413738
7138.0949876083105
7534.761655129724
7246.162856011721
11610.99861007339
21478.924818810458
12102.709780088213
11751.084468981697
9158.553986765592
9202.937056065544
8993.46698857077
9344.512956155724
9046.63918924729
11378.690542060123
9926.02818097181
9389.481767059182
7371.898826458279
7292.498425562162
7304.631860141676
6828.611230747649
8392.72041569773
7403.122278637507
6724.591968725394
10933.81595178106
6283.834499439581
8092.879743817521
6045.514082698286
6018.665559426347
6780.180222222722
9134.461010046973
8693.717310216327
8832.04247080115
8940.648549268368
10779.375014065285
11751.70956642081
9515.913423995718
7241.397279880713
8263.34160752154
8176.138342068046
7395.137098184386
10015.81413473404
12530.246012526777
10113.76067811589
9359.422719345252
8434.840715414975
9414.877828941479
12386.012060712384
9308.035323617733
6731.343068934151
7452.012758281711
8432.310056099648
7907.0324679176565
7043.606523613414
8086.1389038354055
9003.666672306194
6825.450623624853
10888.420185975549
10929.799220001149
7466.927370457726
6878.661989445836
7489.231836171677
6994.010395290496
6990.097941415526
7079.522433669575
6785.609213673625
6666.385658768065
6760.009092399052
13900.486491505939
10191.61045035578
8664.831362140461
7829.412820822347
9078.289461175142
12608.974767728612
8562.065979568846
10296.630748817453
13917.712308554506
8681.042295260826
8348.74858641874
7624.719647919449
8106.892515172932
12164.68552216857
9371.988142278466
9063.428848678577
8184.450317441601
8476.808742985675
7090.685186852457
5490.083677662255
9854.675874189505
6424.667930561883
8204.498315983305
8323.138259442801
8978.449833301403
11032.938045309567
14558.569287506903
6480.141105633644
10724.947476964982
8590.422598835361
9747.813457499773
8893.949949149233
6823.968938056461
7474.583862293313
8733.132065890371
10349.796787742536
10257.046484207656
10135.52151166347
7647.109141713755
7911.825234383504
15438.838203214425
8418.355119143305
9299.591525337291
14209.554056925035
11046.413834471716
9276.771615267244
10732.454156828135
9275.839984927534
12026.883234514542
8543.905763418603
7525.470729002792
8611.67401685673
8728.348957050624
10975.423344004992
8135.064216464076
8285.696505584974
8575.739514873876
7663.5903789971035
9458.394315993612
12826.506303930644
7865.423250039602
10543.795172652164
10117.176925638445
8605.003750430982
7427.491107526343
6974.9756767162235
13528.6052878315
6626.163910214662
7392.751597219963
9484.43497709696
7003.711407640945
5883.952041926352
7457.158928469295
10619.210909440653
10392.848094915607
7002.774042842268
6573.976819582421
6175.790831706767
9552.306996071582
8912.719569834431
8181.204452542623
8217.539416153659
9196.467521800521
7748.349554782235
7335.299237913286
13286.745582454358
10657.366357312922
11064.165489319343
6564.377006728112
7526.922033420688
10240.681824103225
11312.285250213383
6727.536787714884
11081.004087630325
6845.783795185666
7672.0421656609415
5906.8096673976515
6413.242854342971
11218.21912514674
7282.362235896431
6725.763131896914
7899.655146682789
6243.920914897018
6494.097635405847
16721.83011599198
9173.21823786553
7169.5146999884955
11072.007893595926
14650.192840458143
7818.641754053388
8329.883297281716
11071.675425103684
8662.093047104318
13289.772086096362
9264.112697802037
7799.846905086368
7732.365770913777
9086.365974429671
9238.178214460246
11733.706706470297
9215.748257699013
9181.894435035421
8481.1939548651
9671.304877086026
7914.388775935753
9781.051582859045
8719.41184462173
11404.363343928559
9001.545372888653
8933.489365070478
7964.842002001552
7350.213585693367
15530.435765832213
8673.861276189331
7221.709628232372
5686.768991906578
12370.758052676343
10731.668677865138
7754.925733598549
7316.369980953159
9818.152109754423
7793.566411842692
6664.294717953022
14755.838558913658
8762.60423306944
10934.533835703856
7711.511436175632
8734.019961385047
8306.307690124488
9060.312519156132
14231.622225425735
6935.535869744885
8718.375303099989
7184.22039025565
8575.867418344898
7274.529229910949
6870.003824862587
14428.476133330601
12501.917129153542
8262.995279739638
7524.955078511903
7587.998504075663
8979.550906023023
8309.906813963837
8864.475140836987
7565.638499582271
8455.633123962583
8445.805780194893
8253.76283336377
7226.4282721604695
8283.633459485583
10737.363196031165
8277.359090119722
7727.311111228579
7886.131314040654
10433.883922309427
9029.903076623066
10087.752566089268
8307.663475962623
9375.927627955132
7819.355586058477
8563.861367521718
7630.2979360966165
8319.239280115176
7527.677042811451
10571.555512573263
7646.849283328561
9021.775627608764
10488.400652858376
8161.261118203704
9688.87862353141
8183.389139628398
9373.27136681133
11764.848584578964
10769.239975850563
7921.276589106514
8654.527458556799
10079.027338274682
10671.696939146948
12483.989903297626
7336.828269593766
11864.530856386855
12190.629013562702
10078.384383743394
9538.21517523596
7556.632792467154
9312.538231270812
8020.555599732681
8742.860327514505
9605.217917249287
10430.798743754856
10201.613218959406
6197.90713739825
8069.705971815565
7891.10305815581
6369.208378650274
8518.842557601809
5773.5620133568455
8334.292857968501
6531.276909770767
10687.44391440346
8099.438904937511
8453.611432479202
8164.6779901500295
8545.291386489876
6648.393000702346
7878.417189749862
8971.065599323934
7980.833567922395
9213.879340285199
10228.73010460394
7981.07515105513
10565.671208799527
10751.637321866006
11441.16964226457
9116.835210688874
9419.140120293847
9368.696876673186
11399.512704359413
8157.964014603891
12552.992616276906
9243.730645840214
8029.491328468883
7436.122015229488
8893.492274943379
8717.789917876757
6734.083445708015
8415.25607322002
9556.693417362238
10768.519951760358
9263.166240074675
7509.061136954393
8406.920611866943
7810.647095436902
8703.311033129428
12051.904471517628
11436.867633241267
8603.661727648521
8562.916654028386
7437.12552319722
7155.691482871512
10243.48318895143
9903.462959676755
9781.462600998522
8268.137610560094
10528.214651349484
8609.767317176793
7488.474973129615
8878.175309222841
9424.999577320612
6925.788983673197
6599.205327890588
10050.630808492744
9244.135832084467
11236.007500019143
9895.183815590355
6873.901136117553
6676.7075462012
6140.174115426491
10636.870545510312
7927.1408958584525
13177.93673813071
13692.051959214852
8863.954931818373
9999.4565702812
7822.4191406261225
10177.448475705507
23010.730229321332
6227.914911594655
7924.50422002433
6021.236976127832
8782.059400768585
9801.388593909898
8274.333608210956
9402.857650733997
10604.376633638874
10514.961939317875
8136.131861303404
7695.018791658209
8750.343195412515
13887.566959431108
10138.167593392873
10349.24775201668
9386.837537894036
9701.320171826637
10085.322942534367
8380.926668657994
7802.37969384282
11647.060865810157
11343.557059763638
6868.011980614077
12217.861067613892
11330.519014242784
7073.798511684181
10528.884611916026
7827.360279672586
7351.704129986214
6185.123079697612
10820.60533426527
6620.474512209989
11442.94019176909
9497.933820014132
9568.132730785977
8182.745265776267
6281.009784582323
10206.985527213796
12251.561325624853
11428.033235924044
8274.784113250791
8122.692071796326
8898.936600139557
7577.226526077441
8151.4281651220335
6734.979218920781
9251.225673137416
11092.778442212983
9129.70798090559
8391.150664935241
9551.439967294584
7694.390592141872
9171.217854406987
7628.371378105852
11414.918784702186
8469.020064391922
9089.041785929085
7394.357163095162
7227.571679644795
7947.236171015138
6856.726723496992
10521.970538872221
11436.302610302533
8107.451061165572
14603.415867705386
7261.425336140777
12618.730527520589
7274.3388200443815
13573.277326568856
8132.24044417844
8052.880350340318
9294.886099156842
11724.475466334541
12307.607520348449
8109.2519411554085
9912.829543928814
9103.026173988408
8628.145927594443
7607.568343087471
6515.673726825748
6348.750606121307
6482.610402907932
10019.399984941498
9525.28299304805
11573.94791767558
7390.268346673133
7318.697506313203
8651.583707797052
7387.418310936691
7825.933427582545
9168.840693356366
9505.328886511516
8313.797266419451
12094.13499844391
8541.479077934315
8825.06664419282
10005.978700424828
10735.715591182363
6862.252382927998
7741.869940699019
7767.507602682423
11578.473495111322
9564.191196642532
10274.66986841471
9941.579760726258
6511.673662701443
7247.810531421767
7969.522741630305
7029.066359138765
8880.3310819865
7093.973095258437
7087.429134177531
11556.4206111176
7135.703713243964
9291.966720013988
6750.1614508378625
8238.292872864913
8292.556890773989
10777.01175751811
7214.247718367718
7650.713142434376
10175.232526887683
7273.360178603195
9363.070271223083
9031.082023348998
8825.414779423541
9944.142050890547
8661.613237640822
9030.01116283714
8977.177135132664
8337.56601288842
10141.850334339602
8546.618623453181
7410.515074782262
6572.347340125307
10083.609269058421
12654.637979443547
11554.172750677219
7121.933861273288
10439.88131675033
8660.384631888535
8512.0120356354
9538.636274253677
9201.508108840835
6761.557954421337
8449.598647745126
9234.271120987107
6686.902174732928
7998.82878768579
9335.195003258706
9793.698753380144
7511.6997674706145
7040.272253499823
8574.417023127731
8710.889726264822
9855.234442726523
7333.271390876398
7074.90737382472
7567.028797634303
7478.819856001589
8661.678431165836
9686.365620656681
10380.927261088596
10909.16114126585
11846.913189403962
7601.6838272205405
8354.527228487183
12205.27856229888
6669.8545818673365
7801.38293467816
9900.023646481075
7456.090708871705
9392.341214454817
9171.50778068918
7182.033412097328
7776.702509908223
8747.492267816275
7267.472492994599
7004.983685255049
7308.658504641303
8605.037774331216
6729.641478971638
15265.768267500302
7678.69443706525
7665.185344445105
8024.504324958378
13004.357203635522
11699.41947840393
10191.595188321702
13159.863220726136
9394.067116753497
9427.537640184984
10055.990865507494
8253.500233500139
8365.577232126088
8327.59314790924
8595.724831372749
8352.102341714275
8447.66423767584
9078.305961792837Delay-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) | 6991.0 | 7878.0 | 8570.0 | 10324.0 | 11543.0 | 14550.0 |
| 2 | community pathway | 6591.0 | 7452.0 | 8068.0 | 9381.0 | 10441.0 | 12744.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) | 6991.0 | 7878.0 | 8570.0 | 10324.0 | 11543.0 | 14550.0 |
| 2 | community pathway | 6591.0 | 7452.0 | 8068.0 | 9381.0 | 10441.0 | 12744.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}:
158.02098089232808
157.20378323750958
156.7214645281194
156.94710606742476
157.18261124183513
156.7328096126251
157.93970004353324
158.69206400625333
159.15739213200698
159.27076527534982
160.66841822829085
162.50717069869359
163.3300259922954
162.84451868230127
163.22517201232154
168.75411809987287
169.07624537299927
171.01233137973634
169.3917800857485
168.69449013148648
168.40718016542445
170.67447883561636
168.36754131972236
168.00612290173808
171.7962885778236
171.46036584519697
171.89344746144008
171.56920253157793
172.5239003508964
172.01423694894734
167.6915596924522
167.36711869413614
168.58738618766475
167.36816428301765
167.1783730616879
168.62208859923683
168.28011754340633
169.3384541721774
168.815265525258
169.05339545675727
169.1995197901862
169.96734966943686
172.42812554249633
172.42555039982514
172.98102077774715
172.88412326614062
174.65262953106875
171.81074925803566
170.07766401269814
171.769023348718
171.51741399318863
171.53418612619004
167.50017493043615
166.34505023972784
166.4408019643705
171.2816944154837
171.35519234417794
170.8995251539172
171.91194739553922
171.48056459293514
171.40064356443915
170.65009829387108
172.05913954441198
177.48313486232914
178.02248840433475
180.59880092289006
178.55544802619923
175.8429007057311
190.25173238776722
189.02187705274457
188.77146727744486
188.67064665900372
189.4305723569034
184.40039712673803
183.69649719290697
178.9102243142333
183.83041100477672
181.8037927344053
177.07709325255678
177.2785935227879
181.30853963932964
180.95597503091807
181.28425712130633
181.11724287210245
181.82676370753887
181.7560681331142
182.99645315942394
183.0322219718995
185.8636044850718
182.40469862326742
183.4413853791606
183.55479533164845
185.68897056854945
183.7307613447239
182.0974633325615
180.94744991161411
181.07734252973535
182.51789454659496
175.44833601301184
174.94639992994922
173.30465993591994
165.44887487305567
165.52546401484568
164.92496480488057
166.3457245789316
166.23814504477488
165.7568668599562
165.34813053650183
164.12849654364925
165.54850811891737
165.44369726597043
165.96969647811187
166.89962865319075
166.86804783219907
163.4832461397036
162.5285842499559
160.45419194852406
160.2034012559394
159.8394166535572
159.21263860742954
158.2221415741522
156.93846381302248
157.0971952413064
158.25987440585345
159.5402511485567
160.2473336615123
159.87141525009355
159.7842701569874
161.9719450621246
161.3643736822273
163.25973263538117
165.27040699924265
167.56663205462405
167.58360938984785
164.4333334330545
163.753629961011
163.75673140183463
163.69636642788524
164.1678182055815
166.24308641568334
166.52450219964692
168.32088312784032
168.5544270534707
168.60614197288433
168.64472620891226
168.22764546302508
169.55943762965563
168.61840283895904
168.54272590154702
168.2962332636297
167.49177957348596
165.71353617260468
165.98286007835233
166.16577639363706
166.67692483214043
165.81118122886699
165.52409272939786
161.45256501461182
160.98893213260752
160.4781491257292
160.29777069252614
159.32231184244705
158.10409506790575
159.34379410199813
161.62813669101243
165.28578654459693
165.39715948282876
164.68043507300695
163.39312723222457
163.40606030046456
164.05481440436148
165.49595393676037
165.44429768979535
163.58345478274495
162.850931751146
163.94130788964384
163.84761448070174
164.42699805486674
163.46187750332746
163.0267886550926
162.35141462257215
161.92440949870542
161.48409116736923
160.74978599892037
160.0300664337302
160.02075471253949
160.057955042209
159.70212546571966
160.77998121493178
161.4880581616213
162.09892250145157
163.4113302037565
163.5606314978775
165.46569165712606
164.2617112159365
166.28407669309027
166.91591865145196
166.56812967833446
166.92319552634407
166.44366717518832
165.61912366400418
166.69951784073874
166.38715479667732
167.13908414058577
166.7962250963652
168.02338478650208
168.98901192377429
175.09840433614352
174.9544547931889
173.5150194097956
173.6074000573049
174.83634420808076
170.70066848704758
171.90124281093426
171.789367435623
171.21570938618254
172.33461266196127
170.14819682379826
170.34708062141453
174.35550593833838
176.1354450828338
176.30271500386357
175.01192491943715
175.02203119586153
175.60783796447393
176.78354587863714
176.9254620549822
176.09526125022316
180.79585225942833
180.9714935324358
182.22838299507762
185.5654282613586
186.29536013034027
180.21320536194412
181.82760048274884
182.08248724878717
180.16528075922903
183.95363400374933
184.31218587578206
180.68299577290475
175.99317140580422
174.47669762651003
176.05582154413418
177.284117144665
176.93984159725724
178.46477009761247
181.2381735962279
181.94835402399525
182.5366916188546
180.4907749841567
179.63703974324517
176.37018963816143
173.3000695086201
168.9441152742455
167.66672399280358
167.95658547873828
165.5714981980655
164.9993755863287
164.69164555629135
164.397016541412
165.39177162771807
165.64964146880595
165.32384052649869
165.29007442211793
165.78214147577063
165.27371524005818
164.79459304156012
165.37113828151732
166.9695326474536
169.737532036773
169.62559156244905
169.16297724101557
168.56780986857518
170.04121327299274
171.0083073492275
170.96955900106488
171.6995082433353
168.6396359221463
167.3168338702965
167.69837318474868
169.30607148871448
164.88526125324387
165.9107743754839
165.73807332501622
167.46764199049295
165.82563089854125
166.69591327759082
166.71432163989365
165.81300266537795
163.6785918388205
164.78410532001902
165.0401899321963
164.9405168760966
165.11743977749583
163.92248942853715
163.98908409318307
162.26549040476016
163.4865147150009
162.61925721461938
163.26296856342884
163.24225562918645
162.40581094942098
162.07922781957419
161.78995039988638
159.7113177268513
160.08751624556595
158.2163467485866
157.62089238098233
157.80330435863306
157.63275880106983
156.8993126272616
157.82626722182147
157.8070853648112
156.83114341192254
156.9558365751694
156.69133617946918
156.7549069311426
156.8554511789298
157.45068194268939
156.68457540294145
156.9485610505586
157.29933124422777
157.4595297333726
157.2653515765165
157.19326948960065
157.91012393737077
157.5356854282301
158.3383964796586
158.54115835394487
158.45902133568296
158.0765261209543
158.1646819122082
160.38919638962093
160.402269016214
160.54522809244324
158.86593459935645
158.70703706773665
159.53169977681878
158.7686941757069
158.19944162890093
157.94620707355182
159.28622027549397
159.78961594560187
158.4763893177664
158.21839041697822
158.80788186428532
158.77867131364263
158.667104488981
158.04025492384656
158.47080730104352
158.43651832269933
160.7629706411339
161.90466581269266
158.08408596975642
157.91241263302135
156.30239504461147
155.8439103075837
156.335111234818
154.93653871410828
155.57311917500078
154.88320992638822
154.79838363154835
154.19767776316615
154.33409526799176
154.05948391028096
153.3058789729905
153.00582909327824
152.94709644877267
152.57675861365718
153.069758053494
153.4693684380373
152.99502344328005
151.55358546470916
151.7583015660765
151.6798608570876
151.42717485654714
151.1769643551453
151.23805259078347
151.45000529510597
151.55255746145943
151.47045409875756
151.39995783348232
151.40945415050675
151.63050444132395
151.3267192803324
151.31769433976396
151.03680267044845
150.87429798439663
150.70453167812525
150.4229046659612
150.3399814441803
150.69928968213017
150.97094770314942
150.9639469349555
151.73228084318094
152.79560941312818
153.42413862136223
153.05842489823726
153.22507070484002
152.7198416372631
152.22650307147805
152.93157275047807
152.46967366024245
152.91828238256215
152.82558757552832
153.16319435636726
153.66356003751554
153.76335204810613
153.01996466535397
152.89152478852122
153.24606552108335
154.99163818843596
155.39781435854437
154.4468578490037
154.34498305866
154.21209050111997
154.07957329682034
154.76422055839978
154.09628470524797
154.3301285104573
154.3729228883853
155.0445166928529
154.90118045917617
154.82512541509124
155.14817064981926
155.53915054165563
153.5973547621087
153.88748619372603
153.9231659339313
153.99733569704932
153.9598147718059
154.020784165146
154.44171850255543
154.49314557915727
153.64705122586255
155.66315832681335
155.98463570315386
156.2284907486025
154.75397960114375
154.60388213974917
155.35663303578656
154.96158210432853
154.56503296286684
155.05364125320344
155.15848477794574
154.92383651772187
155.25212345470783
156.49824561660387
156.4310007549449
156.0869911327026
156.3128671904041
157.24151456735933
157.74122218031798
157.94461689510874
158.29248210307975
157.1421300093728
157.12537817337898
158.94969139565185
158.64916464510134
158.1397778647846
158.42032964090592
157.9242028248231
156.4032984059578
155.19448296404224
155.88305088254313
156.23710378885684
156.6083840639231
157.0890894284569
157.27982043356076
156.99829952199482
157.37847274098124
156.5097370696423
158.84444896484243
161.5792798901828
162.47850841588277
162.72104444354235
161.76028302116748
160.8434227208878
159.92999835162632
157.68905804135116
157.2834225480598
157.2343312137648
156.6645258030818
155.55998133559984
155.76184049727038
155.29537260050026
157.83172601620817
157.45945779140902
157.4829382782321
159.11846290367188
157.64400932510026
158.446099715186
158.22566364000724
158.28325753598216
158.8589851803877
160.18009636229397
160.22842761571638
159.93636051533502
159.18518118669684
159.84287964164932
144.0390090045195
144.61384402879344
144.50684376071445
144.43034483230917
144.18155223856093
144.77540535162393
147.35007300963133
145.47845551893022
146.0294996421644
144.39487503536526
145.38084277532894
144.89629317934885
144.78596846755636
146.38517253815698
145.77074736699586
144.7075439987068
144.72155708625584
145.74403758421857
146.11372026853968
152.75856174454222
156.30279101362416
160.34019444680683
154.54481065259347
149.97611461094226
157.04932711321584
158.9353099304267
156.49686558589525
151.64104310652868
156.45835006686676
151.4025014204163
152.80745350818177
155.0125933208377
156.2652741561268
156.42403844893659
160.05135117705993
157.48724360362684
154.03217190716492
152.01044564666012
152.94206757626586
156.36405149440247
158.5505260598161
161.17503213188576
170.5481065830473
156.89899376672255
158.11870807887414
161.15899257168067
146.7795716453653
143.9082755819603
144.60893075262024
144.91921261887285
144.39251328405177
144.43569797766463
145.6257766322963
144.83763361076748
144.83004657279184
143.86815246525993
143.05197872738384
144.0266848179323
143.0665850205165
145.02828786619864
144.2114841304806
147.26576545203005
148.44292053186203
151.99638677863493
152.53564543279305
147.77040999988068
147.40536732339552
146.03629173008093
148.34049786728974
150.97038557304933
153.39679280769627
147.47750510421616
149.18747753764242
145.00301850210633
144.0610832249039
144.36111146921584
145.09613725450046
147.08689606671223
156.86630306197742
153.9814404400286
164.32053931898167
153.39217263362474
147.25234103194356
146.515144684049
153.6638787819767
152.46198343286974
152.14080419684512
147.06147436152125
145.98624745913742
143.48755094216824
146.07769983805474
147.57578084080404
148.94663803304627
144.9126519177158
144.9675689312181
145.9108900210673
146.25734863751245
144.16422333758695
146.25163613001132
145.9302018879033
145.63514181148676
144.26762432835537
147.10058286444573
147.91998905347242
148.04804550743762
148.4204834661866
146.26818430900855
145.49390979472767
146.01239649178663
145.5864778336538
145.05472096650618
144.9293891470111
145.44169623733976
146.9307358570254
148.32669590251825
150.69924357629986
148.85790007465013
148.41689481520896
149.6268452880995
149.99349076605097
149.49880047775883
154.49489434824648
154.08401907997947
155.66733089206534
158.979098923418
156.5515065979196
158.31348706498812
154.8175052960472
155.92582521572996
161.8352413807972
154.72359608655805
155.5549824257197
157.25312629647337
153.51383357869915
148.58527722011357
149.43521007634854
149.75477918135545
149.6213402221436
147.7867252567954
146.80272184004286
144.8380559147412
144.6453652301855
144.38532435968972
149.2647734600096
152.12290875517783
151.13321257562174
152.3470310945061
156.75734564893654
150.82325601359832
159.7999388792774
157.16651924077513
153.49378937269805
150.31037588904996
155.70204536318445
152.32863235629287
157.7706993025488
156.80732370968641
150.675280332164
154.40812460888634
149.3202553466312
149.58616926850917
149.94251844126157
147.64268299503985
151.28570359536397
153.2845036687903
163.73607800141053
144.09227895240332
144.61609414542107
145.3697001106989
150.32838481455195
150.53367747478774
150.45817848053449
152.88827392166013
155.73110768939497
149.17963507474244
148.40639513270068
149.29529306416353
160.8089470203859
159.2142067737057
165.34863126731747
157.21116201258945
154.6475820737525
163.31396415442828
161.39827137370565
151.11171774687455
150.5698686766129
159.42611291880075
152.58666911018057
152.13374008138115
148.4267602851391
150.9312840903675
150.10427397942547
168.48842103085715
151.9705181070451
147.7101266420969
150.44627346930056
150.81719948537918
152.41326262758744
152.56097077519908
150.39728000112993
150.96828847171062
151.8826527710014
155.2153559116344
155.64766906428397
159.30747857815453
155.89727182287436
159.40143490409986
159.7077447725781
156.03903007288082
150.77439610968028
153.61929272030486
155.081699531794
151.83925210720545
156.80718824500826
157.29199898094566
152.97369686958922
162.9681134229188
157.1725236781293
157.12865106057268
156.07159265965785
153.08625586175543
154.27387525658153
156.60424244439835
152.7585306996998
157.64567736841357
155.43432798126727
153.5619987926183
158.10789318127263
155.65723742372123
154.19768465097465
155.97905508335728
163.9617700219114
163.2242595349633
153.89483227253822
151.2383094926776
150.23157324162537
155.6193078248445
161.50604733917174
159.31299470197013
154.7004265567914
162.36563719524702
160.5841147487959
157.65977372440835
153.0498117001309
153.26144084188704
149.7595091667424
158.05469432795442
154.51753173900815
173.58844274298502
147.47058635974827
146.1868259049439
146.1413938559865
143.25659218599324
143.1982284048209
144.43419359611323
143.61513521763672
143.64876234523112
145.7266312294139
147.31984223928936
147.79889870346148
150.75930509185991
152.5061762973123
152.53254022813059
169.96564582091014
155.88785756748715
156.49313480276766
165.17206592155335
159.7180471244608
168.2592733089065
169.9486514065345
162.0224201570181
158.3131604641391
160.16735014344863
153.26619728762432
148.37222530392913
148.81598081624045
154.91043702957595
166.89252700999458
165.39287992376327
168.49323862557193
157.79525167234448
152.81799626963914
156.75564353090414
156.05614309303104
156.3738913034779
155.1288181425091
157.52967284106154
153.731797244856
157.7676808269977
159.91379493236943
152.41906357328017
147.74642065255503
149.20832834832007
148.86597753013928
144.8176183300216
155.89490742472537
154.38308633501006
157.6272936219149
160.00711451662482
159.60240244542945
153.6968752658499
165.09585950937657
157.0678879136034
162.41600976747048
165.02779617460078
148.29314327961066
147.8475741667646
147.90489296891235
152.88653478691324
155.74322204339563
162.828803217496
157.5881801364995
158.8788742090137
159.43086105241596
171.6206023609736
171.49500567702032
161.34123571432036
164.99939053041248
163.58149407285708
162.3056347162394
162.4815266386199
163.11525853907972
162.55502250843728
158.12766831715197
151.65149490147328
149.00012500694385
149.47623380261555
148.89976063003192
147.21332100504847
145.8920609455311
151.12651777367378
153.50167794223245
151.99983051765344
153.70362278698371
152.81192624685644
151.9885898931378
148.34010648321038
148.96897667938492
148.26635528158306
150.01097850645834
146.87129385654205
145.435548444139
146.33520008857235
145.94713639957425
145.26328394905897
146.80868109116508
144.47524174479153
144.300093408601
146.90150274151569
145.82890043837207
146.67642891411708
147.19604161154692
148.24577582280904
147.4903632905165
147.589128376837
144.39135071965586
148.19808313252562
147.67517743733205
147.71484974030375
151.263974099195
151.39080873588648
150.11617146077526
150.15425540954362
148.45018272794087
153.33342849662105
157.0329207712164
159.6883170090647
153.7258419883424
155.86411757077107
158.50384971067643
169.9517954367192
150.55328684177903
162.38555241533487
163.60371707836129
159.8896112976756
157.5625114609149
150.33547415504086
149.3870819075719
153.17106189557708
153.92923933510372
157.64931939561836
157.02483309752455
160.55867967998276
172.10292518817744
170.7316412469798
175.30855042537667
172.36922291596676
170.60313978908962
167.7000551919514
166.1529666086001
163.43573917141077
159.16348529020124
155.63173241728376
156.5768470187734
144.9769981989961
144.27365478738378
145.21528678955127
144.97508450840078
144.74445363002334
143.4611526642096
144.71329510086767
146.4869267737821
145.64119499552632
147.1875612657144
145.1333753179138
144.5769671183969
144.70356774567475
149.30405225970037
150.35323138927242
151.9196030845873
152.24381004817107
148.0360437540558
154.15767875895628
154.85253472022254
148.15346937280347
149.62815575042038
155.96453627260502
158.51676210516996
160.21065973504716
158.44130838570143
158.06539798918476
168.97581522511047
159.64838171953969
162.9450785029756
163.09162855523732
167.73708092797932
161.88351404525108
166.4244347596869
162.27857482101672
165.42328797396112
167.70916625264977
171.361454863111
170.55826850987066
165.04960753565464
148.11738191400786
157.4485638127882
151.4167798154781
159.1145530673488
160.7130193509013
170.8584855270875
176.97527413146582
186.95144895975358
181.56824513313978
164.21402425821086
154.2782394343815
155.93512319949937
152.78121821003919
157.43378854361254
164.43741122449484
171.07096657781966
163.7962665882708
166.71589546685334
175.84118886557172
187.1604344641283
177.187567472038
174.59637440569952
188.78392467473103
208.06732492497378
202.17601162199088
176.01408194919125
176.24297079877462
168.32590854485298
157.8709117503635
171.39762585740502
180.03106408358204
182.61739010447047
178.35060894616598
180.48953302588336
169.95564831768456
166.364324202711
157.7397917988547
159.31904538913713
156.64632620555903
153.6790287447003
153.83459612279688
156.51163290437532
154.64878475158534
161.50792812549454
154.15915982579597
150.60196156127455
151.34497705182883
150.16989455282206
147.72002838646551
148.46511509098636
145.63038871116723
149.85550084126746
148.33527471257693
150.13799704249772
145.88765360159712
145.940654615753
145.47047281164802
146.5659752087796
147.43378859107503
146.205395177043
145.89637184585146
146.28238670828932
147.82142338340105
149.37114734031033
153.52565384962563
150.51874410687003The 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) | 6991.0 | 7878.0 | 8570.0 | 10324.0 | 11543.0 | 14550.0 |
| 2 | Exponential growth | 7051.0 | 8333.0 | 9102.0 | 10427.0 | 11187.0 | 12552.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) | 6991.0 | 7878.0 | 8570.0 | 10324.0 | 11543.0 | 14550.0 |
| 2 | Exponential growth | 7051.0 | 8333.0 | 9102.0 | 10427.0 | 11187.0 | 12552.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) | 137.0 | 140.0 | 143.0 | 150.0 | 155.0 | 167.0 |
| 2 | Exponential growth | 145.0 | 150.0 | 154.0 | 162.0 | 167.0 | 180.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) | 137.0 | 140.0 | 143.0 | 150.0 | 155.0 | 167.0 |
| 2 | Exponential growth | 145.0 | 150.0 | 154.0 | 162.0 | 167.0 | 180.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)