Skip to content

Commit 0eefe7f

Browse files
sbfnkclaude
andcommitted
Extract quantiles from Julia forecast intervals for R plotting
The forecast_to_r_dict() Julia helper was setting intervals and quantiles to nothing, preventing scoringutils::plot_predictions() from working with prediction intervals. Changes: - Extract interval bounds from fc.intervals Dict and convert to quantile format - Calculate quantile levels from confidence levels (e.g., 95% → 0.025, 0.975) - Include median (0.5 quantile) if present - Return quantiles as matrix (horizons × quantile_levels) and quantile_levels vector This enables probabilistic forecast visualization with scoringutils::plot_predictions(). Note: Users need to re-run setup_ForecastBaselines() after updating to load new helpers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 64508f7 commit 0eefe7f

File tree

1 file changed

+47
-3
lines changed

1 file changed

+47
-3
lines changed

inst/julia/forecast_helpers.jl

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,53 @@ function forecast_to_r_dict(fc)
4545
result["truth"] = to_r_compatible(fc.truth)
4646
result["model_name"] = String(fc.model_name)
4747

48-
# Skip complex types (intervals, trajectories) for now
49-
# These would need recursive conversion if needed
50-
result["intervals"] = nothing
48+
# Extract quantiles from intervals if present
49+
if fc.intervals !== nothing && !isempty(fc.intervals)
50+
# intervals is a Dict{Float64, Matrix{Float64}}
51+
# keys are levels (e.g., 0.95), values are matrices with lower/upper bounds
52+
# We need to convert this to quantile format
53+
54+
levels = sort(collect(keys(fc.intervals)))
55+
n_horizons = length(fc.horizon)
56+
57+
# Build quantile levels and quantile matrix
58+
quantile_levels = Float64[]
59+
quantiles_list = Vector{Float64}[]
60+
61+
for level in levels
62+
interval_matrix = fc.intervals[level]
63+
# interval_matrix has shape (n_horizons, 2) with columns [lower, upper]
64+
# lower quantile = (1 - level) / 2
65+
# upper quantile = 1 - (1 - level) / 2
66+
lower_q = (1.0 - level) / 2.0
67+
upper_q = 1.0 - lower_q
68+
69+
push!(quantile_levels, lower_q)
70+
push!(quantile_levels, upper_q)
71+
push!(quantiles_list, vec(interval_matrix[:, 1])) # lower bounds
72+
push!(quantiles_list, vec(interval_matrix[:, 2])) # upper bounds
73+
end
74+
75+
# Add median if present
76+
if fc.median !== nothing
77+
push!(quantile_levels, 0.5)
78+
push!(quantiles_list, to_r_compatible(fc.median))
79+
end
80+
81+
# Sort by quantile level and arrange as matrix
82+
perm = sortperm(quantile_levels)
83+
quantile_levels = quantile_levels[perm]
84+
quantiles_list = quantiles_list[perm]
85+
86+
# Convert to matrix: rows = horizons, cols = quantile levels
87+
result["quantiles"] = hcat(quantiles_list...) # Shape: (n_horizons, n_quantile_levels)
88+
result["quantile_levels"] = quantile_levels
89+
else
90+
result["quantiles"] = nothing
91+
result["quantile_levels"] = nothing
92+
end
93+
94+
# Skip trajectories for now
5195
result["trajectories"] = nothing
5296

5397
return result

0 commit comments

Comments
 (0)