Skip to content

Commit 1b92b1c

Browse files
dashboard
1 parent c202745 commit 1b92b1c

10 files changed

Lines changed: 58 additions & 28 deletions

cybench/runs/analysis/build_global_insights_dashboard.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def write_insights_dashboard(
3333
*,
3434
output_root: Path,
3535
dest: Path,
36-
version: int = 1,
36+
version: int = 2,
3737
) -> Path:
3838
payload = build_insights_payload(output_root, version=version)
3939
if payload["n_rows"] == 0:
@@ -62,7 +62,7 @@ def main() -> int:
6262
default=Path("/lustre/backup/SHARED/AIN/agml/CY-Bench-dashboard"),
6363
help="GitHub Pages clone root (used when --dest is omitted)",
6464
)
65-
parser.add_argument("--version", type=int, default=1, help="Batch version tag (default: 1)")
65+
parser.add_argument("--version", type=int, default=2, help="Batch version tag (default: 2)")
6666
args = parser.parse_args()
6767

6868
dest = args.dest or (args.publish_root / "insights.html")

cybench/runs/analysis/build_model_family_radar_dashboard.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def write_model_family_radar_dashboard(
3434
*,
3535
output_root: Path,
3636
dest: Path,
37-
version: int = 1,
37+
version: int = 2,
3838
) -> Path:
3939
payload = build_radar_payload(output_root, version=version)
4040
if payload["n_rows"] == 0:
@@ -66,7 +66,7 @@ def main() -> int:
6666
default=Path("/lustre/backup/SHARED/AIN/agml/CY-Bench-dashboard"),
6767
help="GitHub Pages clone root (used when --dest is omitted)",
6868
)
69-
parser.add_argument("--version", type=int, default=1, help="Batch version tag (default: 1)")
69+
parser.add_argument("--version", type=int, default=2, help="Batch version tag (default: 2)")
7070
args = parser.parse_args()
7171

7272
dest = args.dest or (args.publish_root / "model_families.html")

cybench/runs/analysis/dashboard_targets.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
# Optional: uncomment ``include`` to pin a subset (also used by --mode planned).
1010

1111
defaults:
12-
version: 1
12+
version: 2
1313
output_root: /lustre/backup/SHARED/AIN/agml/output
1414
repo_root: /lustre/backup/SHARED/AIN/agml/AgML-CY-Bench-AAAI
1515
publish_root: /lustre/backup/SHARED/AIN/agml/CY-Bench-dashboard

cybench/runs/analysis/global_insights_lib.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@
1414

1515
_BASELINE_MODELS = frozenset({"average", "averageyieldmodel", "average_yield"})
1616

17-
# Lead time increases left → right (less season observed → more observed).
18-
BATCH_HORIZON_ORDER: tuple[str, ...] = ("qtr", "mid", "eos")
17+
# Lead time decreases left → right (less season observed → more observed).
18+
# Code: mid = 50% observed; qtr = cutoff at season_length/4 before EOS (~75% observed, 25% left); eos = ~100%.
19+
BATCH_HORIZON_ORDER: tuple[str, ...] = ("mid", "qtr", "eos")
1920

2021
HORIZON_DISPLAY_LABELS: dict[str, str] = {
21-
"qtr": "Quarter-season (~75%)",
22-
"mid": "Mid-season (~50%)",
23-
"eos": "End of season",
22+
"mid": "Mid-season (~50% observed)",
23+
"qtr": "Late season (~75% observed, 25% left)",
24+
"eos": "End of season (~100% observed)",
2425
}
2526

2627

cybench/runs/analysis/publish_dashboard_bundle.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@
7373
"eos": "End of season",
7474
"mid": "Mid-season",
7575
"mid_season": "Mid-season",
76-
"qtr": "Quarter-season (75%)",
77-
"quarter_season": "Quarter-season (75%)",
76+
"qtr": "Late season (75% observed)",
77+
"quarter_season": "Late season (75% observed)",
7878
}
7979

8080

@@ -123,13 +123,18 @@ def prune_obsolete_dashboard_dirs(
123123
GitHub Pages artifacts are limited to 1 GB; keeping only the latest version per
124124
country×horizon avoids duplicate v1+v2 asset trees (~30% of the bundle).
125125
"""
126+
publish_root = publish_root.resolve()
126127
by_key: dict[tuple[str, str], list[tuple[int, Path]]] = {}
128+
n_dirs = 0
129+
n_matched = 0
127130
for child in publish_root.iterdir():
128131
if not child.is_dir() or child.name == "assets":
129132
continue
133+
n_dirs += 1
130134
parsed = parse_publish_slug(child.name)
131135
if parsed is None:
132136
continue
137+
n_matched += 1
133138
cc, hz, ver = parsed
134139
by_key.setdefault((cc, hz), []).append((ver, child))
135140

@@ -146,6 +151,23 @@ def prune_obsolete_dashboard_dirs(
146151
else:
147152
shutil.rmtree(path)
148153
print(f"[OK] pruned {path.name}")
154+
155+
if not removed:
156+
print(
157+
f"[INFO] publish-root={publish_root} · "
158+
f"{n_dirs} subdirs scanned · {n_matched} walk-forward slug(s) · "
159+
f"{len(by_key)} country×horizon keys"
160+
)
161+
if n_matched == 0:
162+
print(
163+
"[WARN] No folders matching "
164+
"'{cc}_walk_forward_{eos|mid|qtr}_vN'. "
165+
"Use the CY-Bench-dashboard git clone as --publish-root "
166+
"(e.g. /lustre/backup/SHARED/AIN/agml/CY-Bench-dashboard), "
167+
"not the AgML-CY-Bench-AAAI source tree."
168+
)
169+
elif all(len(e) == 1 for e in by_key.values()):
170+
print("[INFO] No obsolete versions: at most one vN per country×horizon.")
149171
return sorted(removed, key=lambda p: p.name)
150172

151173

cybench/runs/analysis/publish_pipeline_lib.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
_BATCH_HORIZON_LABELS: dict[str, str] = {
4747
"eos": "end-of-season",
4848
"mid": "mid-season",
49-
"qtr": "quarter-season (75%)",
49+
"qtr": "late season (75% observed, 25% left)",
5050
}
5151

5252

@@ -479,13 +479,12 @@ def filter_publish_targets(
479479
countries: list[str] | None = None,
480480
horizons: list[str] | None = None,
481481
version: int | None = None,
482-
keep_latest_version: bool = True,
482+
keep_latest_version: bool = False,
483483
) -> list[PublishTarget]:
484484
"""Narrow targets by country, horizon (eos|mid|qtr), and optional batch version.
485485
486-
When ``version`` is omitted and ``keep_latest_version`` is true (default), only the
487-
highest ``vN`` per (country, horizon) is kept — avoids publishing duplicate v1+v2
488-
bundles that blow the GitHub Pages 1 GB artifact limit.
486+
When ``keep_latest_version`` is true, only the highest ``vN`` per (country, horizon)
487+
is kept — use for GitHub Pages publish to avoid duplicate v1+v2 bundles.
489488
"""
490489
if countries:
491490
wanted = {c.upper() for c in countries}
@@ -949,7 +948,11 @@ def resolve_targets(
949948
targets = discover_baselines_batches(defaults.output_root, defaults=defaults)
950949

951950
targets = filter_publish_targets(
952-
targets, countries=countries, horizons=horizons, version=version
951+
targets,
952+
countries=countries,
953+
horizons=horizons,
954+
version=version,
955+
keep_latest_version=version is None,
953956
)
954957

955958
if mode == "all-available":

cybench/runs/viz/global_insights_template.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -412,9 +412,9 @@ <h3 style="font-size:1rem;margin:1rem 0 0.5rem;">Detail per country × model</h3
412412
}
413413

414414
const HORIZON_LABELS = DATA.horizon_labels || {
415-
qtr: "Quarter-season (~75%)",
416-
mid: "Mid-season (~50%)",
417-
eos: "End of season",
415+
mid: "Mid-season (~50% observed)",
416+
qtr: "Late season (~75% observed, 25% left)",
417+
eos: "End of season (~100% observed)",
418418
};
419419
const AVAILABLE_HORIZONS = (DATA.available_horizons && DATA.available_horizons.length)
420420
? DATA.available_horizons
@@ -889,7 +889,7 @@ <h3 style="font-size:1rem;margin:1rem 0 0.5rem;">Detail per country × model</h3
889889
svg += `<line x1="${x}" y1="${pad.t}" x2="${x}" y2="${height - pad.b}" stroke="#f0f1f3"/>`;
890890
svg += `<text x="${x}" y="${height - 28}" text-anchor="middle" font-size="11" fill="#1f2328">${hz.label || hz.id}</text>`;
891891
});
892-
svg += `<text x="${pad.l + innerW / 2}" y="${height - 6}" text-anchor="middle" font-size="11" fill="#1f2328">Forecast horizon (more season observed →)</text>`;
892+
svg += `<text x="${pad.l + innerW / 2}" y="${height - 6}" text-anchor="middle" font-size="11" fill="#1f2328">Season progress (more of season observed →)</text>`;
893893
svg += `<text x="14" y="${pad.t + innerH / 2}" text-anchor="middle" font-size="11" fill="#1f2328" transform="rotate(-90 14 ${pad.t + innerH / 2})">${yLabel}</text>`;
894894

895895
for (const fam of slice.families) {

cybench/runs/viz/model_family_radar_template.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,11 @@ <h2>World map</h2>
389389
render();
390390
});
391391

392-
const horizonLabels = DATA.horizon_labels || { eos: "End of season", mid: "Mid-season", qtr: "Quarter-season (~75%)" };
392+
const horizonLabels = DATA.horizon_labels || {
393+
eos: "End of season (~100% observed)",
394+
mid: "Mid-season (~50% observed)",
395+
qtr: "Late season (~75% observed, 25% left)",
396+
};
393397
Object.keys(DATA.by_horizon).forEach(hz => {
394398
const opt = document.createElement("option");
395399
opt.value = hz;

tests/runs/test_global_insights.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -447,8 +447,8 @@ def test_build_insights_payload_structure(tmp_path: Path):
447447
def _three_horizon_fixture(tmp_path: Path) -> pd.DataFrame:
448448
"""DE+FR with eos/mid/qtr; US only eos (excluded from curves)."""
449449
rows_by_hz = {
450-
"qtr": {"ridge": 0.28, "trend": 0.32, "xgboost": 0.26},
451-
"mid": {"ridge": 0.22, "trend": 0.30, "xgboost": 0.20},
450+
"mid": {"ridge": 0.30, "trend": 0.34, "xgboost": 0.28},
451+
"qtr": {"ridge": 0.22, "trend": 0.30, "xgboost": 0.20},
452452
"eos": {"ridge": 0.15, "trend": 0.28, "xgboost": 0.14},
453453
}
454454
for cc, hz in [("de", "eos"), ("de", "mid"), ("de", "qtr"), ("fr", "eos"), ("fr", "mid"), ("fr", "qtr")]:
@@ -527,15 +527,15 @@ def test_horizon_skill_curves_inner_join_countries():
527527
df = _three_horizon_fixture(Path(tmp))
528528
payload = build_horizon_skill_curves_payload(df)
529529
assert len(payload["horizons"]) == 3
530-
assert [h["id"] for h in payload["horizons"]] == ["qtr", "mid", "eos"]
530+
assert [h["id"] for h in payload["horizons"]] == ["mid", "qtr", "eos"]
531531
maize = payload["by_crop"]["maize"]
532532
assert maize["n_countries"] == 2
533533
assert set(maize["countries"]) == {"DE", "FR"}
534534
assert "US" in maize["excluded_countries"]
535535

536536
xgb = next(f for f in maize["families"] if f["model"] == "xgboost")
537537
nrmse_by_hz = {p["horizon"]: p["median_nrmse"] for p in xgb["points"]}
538-
assert nrmse_by_hz["qtr"] > nrmse_by_hz["mid"] > nrmse_by_hz["eos"]
538+
assert nrmse_by_hz["mid"] > nrmse_by_hz["qtr"] > nrmse_by_hz["eos"]
539539

540540

541541
def test_build_insights_payload_includes_qtr_and_curves(tmp_path: Path):

tests/runs/test_publish_pipeline.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def test_filter_publish_targets_by_version(tmp_path: Path):
135135
assert filtered[0].batch_name == "baselines_DE_eos_v2"
136136

137137

138-
def test_filter_publish_targets_keeps_latest_version_by_default(tmp_path: Path):
138+
def test_filter_publish_targets_keeps_latest_version_when_requested(tmp_path: Path):
139139
targets = [
140140
PublishTarget(country="DE", batch_horizon="eos", version=1, output_root=tmp_path),
141141
PublishTarget(country="DE", batch_horizon="eos", version=2, output_root=tmp_path),

0 commit comments

Comments
 (0)