Spaces:
Running
Running
perf: add LRU caching layers and Gradio queue for concurrency
Browse files- app.py +2 -0
- src/leaderboard.py +179 -134
- src/tab.py +51 -139
app.py
CHANGED
|
@@ -65,5 +65,7 @@ with gr.Blocks(css=custom_css, head=custom_head) as demo:
|
|
| 65 |
# init_archive_tab(demo)
|
| 66 |
|
| 67 |
|
|
|
|
|
|
|
| 68 |
if __name__ == "__main__":
|
| 69 |
demo.launch()
|
|
|
|
| 65 |
# init_archive_tab(demo)
|
| 66 |
|
| 67 |
|
| 68 |
+
demo.queue(default_concurrency_limit=5)
|
| 69 |
+
|
| 70 |
if __name__ == "__main__":
|
| 71 |
demo.launch()
|
src/leaderboard.py
CHANGED
|
@@ -10,6 +10,7 @@ from src.about import DATASETS_DF, OVERALL_TABLE_COLUMNS, ALL_MODELS, RESULTS_RO
|
|
| 10 |
from src.hf_config import get_datasets_root, get_config_root
|
| 11 |
from src.utils import normalize_by_seasonal_naive
|
| 12 |
import ast
|
|
|
|
| 13 |
from timebench.evaluation.data import Dataset, get_dataset_settings, load_dataset_config
|
| 14 |
from pathlib import Path
|
| 15 |
|
|
@@ -83,6 +84,113 @@ def find_dataset_term_path(results_root, model_name, display_name):
|
|
| 83 |
|
| 84 |
return None
|
| 85 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
def load_test_windows(display_name, horizon, model_name="moirai_small", series=None, variate=None, window_id=None, parse_series=False):
|
| 87 |
"""
|
| 88 |
Load test window results from TIME NPZ files.
|
|
@@ -107,65 +215,30 @@ def load_test_windows(display_name, horizon, model_name="moirai_small", series=N
|
|
| 107 |
if dataset_term is None:
|
| 108 |
return None
|
| 109 |
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
metrics = np.load(metrics_path)
|
| 115 |
|
| 116 |
-
#
|
| 117 |
-
mase_arr = metrics["MASE"] # (num_series, num_windows, num_variates)
|
| 118 |
num_series, num_windows, num_variates = mase_arr.shape
|
| 119 |
|
| 120 |
-
#
|
|
|
|
| 121 |
series_names = None
|
| 122 |
variate_names = None
|
| 123 |
-
try:
|
| 124 |
-
# Use HF config to get dataset root (handles both local and HF Hub)
|
| 125 |
-
hf_dataset_root = str(get_datasets_root())
|
| 126 |
-
|
| 127 |
-
if os.path.exists(hf_dataset_root):
|
| 128 |
-
# Use HF config to get config root
|
| 129 |
-
config_root = get_config_root()
|
| 130 |
-
config_path = config_root / "datasets.yaml"
|
| 131 |
-
|
| 132 |
-
config = load_dataset_config(config_path) if config_path.exists() else {}
|
| 133 |
-
settings = get_dataset_settings(dataset_term, horizon, config)
|
| 134 |
-
|
| 135 |
-
prediction_length = settings.get("prediction_length")
|
| 136 |
-
test_length = settings.get("test_length")
|
| 137 |
-
|
| 138 |
-
# Load dataset with storage_path parameter
|
| 139 |
-
dataset_obj = Dataset(
|
| 140 |
-
name=dataset_term,
|
| 141 |
-
term=horizon,
|
| 142 |
-
prediction_length=prediction_length,
|
| 143 |
-
test_length=test_length,
|
| 144 |
-
storage_path=hf_dataset_root,
|
| 145 |
-
)
|
| 146 |
-
|
| 147 |
-
# Get series names (item_id)
|
| 148 |
-
if "item_id" in dataset_obj.hf_dataset.column_names:
|
| 149 |
-
series_names = dataset_obj.hf_dataset["item_id"]
|
| 150 |
-
else:
|
| 151 |
-
series_names = [dataset_obj.hf_dataset[i].get("item_id", f"item_{i}")
|
| 152 |
-
for i in range(len(dataset_obj.hf_dataset))]
|
| 153 |
-
|
| 154 |
-
# Get variate names
|
| 155 |
-
variate_names = dataset_obj.get_variate_names()
|
| 156 |
-
if variate_names is None:
|
| 157 |
-
# Univariate mode: variate names are same as series names
|
| 158 |
-
variate_names = series_names
|
| 159 |
-
except Exception as e:
|
| 160 |
-
print(f"Error loading Dataset for names: {e}")
|
| 161 |
-
|
| 162 |
-
# Create name to index mappings
|
| 163 |
series_name_to_idx = {}
|
| 164 |
variate_name_to_idx = {}
|
| 165 |
-
if
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
|
| 170 |
# Convert series and variate names to indices if they are names
|
| 171 |
series_idx_filter = None
|
|
@@ -219,9 +292,9 @@ def load_test_windows(display_name, horizon, model_name="moirai_small", series=N
|
|
| 219 |
"variate_name": variate_name,
|
| 220 |
"window_id": window_idx,
|
| 221 |
"MASE": float(mase_arr[series_idx, window_idx, variate_idx]),
|
| 222 |
-
"CRPS": float(
|
| 223 |
-
"MAE": float(
|
| 224 |
-
"MSE": float(
|
| 225 |
"model": model_name,
|
| 226 |
"series_idx": series_idx, # Keep for reference
|
| 227 |
"variate_idx": variate_idx, # Keep for reference
|
|
@@ -416,60 +489,22 @@ def get_dataset_leaderboard(
|
|
| 416 |
if df_filtered.empty:
|
| 417 |
return f"No results found for dataset '{display_name}' with horizons {horizons}.", pd.DataFrame(columns=["model"])
|
| 418 |
|
| 419 |
-
# Get dataset information (series count, variate count, freq)
|
| 420 |
dataset_info_msg = ""
|
| 421 |
try:
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
# Load Dataset to get series and variate counts
|
| 429 |
-
hf_dataset_root = str(get_datasets_root())
|
| 430 |
-
config_root = get_config_root()
|
| 431 |
-
config_path = config_root / "datasets.yaml"
|
| 432 |
-
|
| 433 |
-
if os.path.exists(hf_dataset_root) and config_path.exists():
|
| 434 |
-
config = load_dataset_config(config_path)
|
| 435 |
-
settings = get_dataset_settings(dataset_id, horizons[0] if horizons else "short", config)
|
| 436 |
-
|
| 437 |
-
dataset_obj = Dataset(
|
| 438 |
-
name=dataset_id,
|
| 439 |
-
term=horizons[0] if horizons else "short",
|
| 440 |
-
prediction_length=settings.get("prediction_length"),
|
| 441 |
-
test_length=settings.get("test_length"),
|
| 442 |
-
storage_path=hf_dataset_root,
|
| 443 |
-
)
|
| 444 |
-
|
| 445 |
-
# Get series count
|
| 446 |
-
if "item_id" in dataset_obj.hf_dataset.column_names:
|
| 447 |
-
series_names = dataset_obj.hf_dataset["item_id"]
|
| 448 |
-
# Convert to list if it's an array/Series to avoid ambiguity in boolean check
|
| 449 |
-
if isinstance(series_names, (np.ndarray, pd.Series)):
|
| 450 |
-
series_names = list(series_names)
|
| 451 |
-
elif not isinstance(series_names, list):
|
| 452 |
-
series_names = list(series_names) if hasattr(series_names, '__iter__') else [series_names]
|
| 453 |
-
# Use len() check instead of boolean check to avoid ambiguity
|
| 454 |
-
if len(series_names) > 0:
|
| 455 |
-
num_series = len(set(series_names))
|
| 456 |
-
else:
|
| 457 |
-
num_series = len(dataset_obj.hf_dataset)
|
| 458 |
-
else:
|
| 459 |
-
num_series = len(dataset_obj.hf_dataset)
|
| 460 |
-
|
| 461 |
-
# Get variate count
|
| 462 |
-
variate_names = dataset_obj.get_variate_names()
|
| 463 |
-
if variate_names is not None:
|
| 464 |
-
num_variates = len(variate_names)
|
| 465 |
-
else:
|
| 466 |
-
# UTS: each series is one variate
|
| 467 |
-
num_variates = 1
|
| 468 |
-
|
| 469 |
dataset_info_msg = f"📊 Dataset Info: {num_series} series, {num_variates} variates, freq={freq}"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 470 |
except Exception as e:
|
| 471 |
print(f"Error getting dataset info: {e}")
|
| 472 |
-
# If we can't get info, try to extract freq from dataset_id
|
| 473 |
if "/" in dataset_id:
|
| 474 |
_, freq = dataset_id.split("/", 1)
|
| 475 |
dataset_info_msg = f"📊 Dataset Info: freq={freq}"
|
|
@@ -577,6 +612,16 @@ def get_dataset_leaderboard(
|
|
| 577 |
def get_dataset_multilevel_leaderboard(display_name, series, variate, horizons, metric: str = "MASE"):
|
| 578 |
"""
|
| 579 |
Get leaderboard based on dataset, series, and variate selections.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 580 |
|
| 581 |
Logic:
|
| 582 |
0. If only dataset selected (series="---", variate="---"): return dataset-level results
|
|
@@ -587,12 +632,14 @@ def get_dataset_multilevel_leaderboard(display_name, series, variate, horizons,
|
|
| 587 |
display_name: Dataset display name from UI (will be converted to dataset_id)
|
| 588 |
series: Series name or "---" if not selected
|
| 589 |
variate: Variate name or "---" if not selected
|
| 590 |
-
|
| 591 |
metric: Metric for sorting
|
| 592 |
|
| 593 |
Returns:
|
| 594 |
tuple: (message, DataFrame)
|
| 595 |
"""
|
|
|
|
|
|
|
| 596 |
# Case 0: Only dataset selected - return both original and normalized metrics
|
| 597 |
if (series is None or series == "---" or series == "") and (variate is None or variate == "---" or variate == ""):
|
| 598 |
return get_dataset_leaderboard(display_name, horizons, metric)
|
|
@@ -606,28 +653,13 @@ def get_dataset_multilevel_leaderboard(display_name, series, variate, horizons,
|
|
| 606 |
if dataset_term is None:
|
| 607 |
return f"Dataset '{display_name}' not found.", pd.DataFrame(columns=["model", "MASE", "CRPS", "MAE", "MSE"])
|
| 608 |
|
| 609 |
-
# Check if dataset is UTS or MTS
|
| 610 |
is_uts = False
|
| 611 |
try:
|
| 612 |
-
|
| 613 |
-
|
| 614 |
-
if
|
| 615 |
-
|
| 616 |
-
config_path = config_root / "datasets.yaml"
|
| 617 |
-
|
| 618 |
-
config = load_dataset_config(config_path) if config_path.exists() else {}
|
| 619 |
-
settings = get_dataset_settings(dataset_term, horizons[0] if horizons else "short", config)
|
| 620 |
-
|
| 621 |
-
dataset_obj = Dataset(
|
| 622 |
-
name=dataset_term,
|
| 623 |
-
term=horizons[0] if horizons else "short",
|
| 624 |
-
prediction_length=settings.get("prediction_length"),
|
| 625 |
-
test_length=settings.get("test_length"),
|
| 626 |
-
storage_path=hf_dataset_root,
|
| 627 |
-
)
|
| 628 |
-
|
| 629 |
-
variate_names = dataset_obj.get_variate_names()
|
| 630 |
-
is_uts = (variate_names is None)
|
| 631 |
except Exception as e:
|
| 632 |
print(f"Error checking UTS/MTS: {e}")
|
| 633 |
|
|
@@ -678,9 +710,11 @@ def get_dataset_multilevel_leaderboard(display_name, series, variate, horizons,
|
|
| 678 |
|
| 679 |
|
| 680 |
|
|
|
|
| 681 |
def get_window_leaderboard(display_name, series, variate, window_id, horizon, metric: str = "MASE"):
|
| 682 |
"""
|
| 683 |
Get leaderboard for a specific test window.
|
|
|
|
| 684 |
|
| 685 |
Args:
|
| 686 |
display_name: Dataset display name from UI (will be converted to dataset_id)
|
|
@@ -723,24 +757,35 @@ def get_pattern_leaderboard(
|
|
| 723 |
) -> tuple[str, pd.DataFrame]:
|
| 724 |
"""
|
| 725 |
Filter variates by selected patterns and compute average metrics per model.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 726 |
|
| 727 |
Uses FEATURES_BOOL_DF (binarized features) to filter variates,
|
| 728 |
then joins with VARIATES_DF to get metrics.
|
| 729 |
|
| 730 |
Args:
|
| 731 |
-
|
| 732 |
-
|
| 733 |
-
- Features with "Any" selection are not included in the dict.
|
| 734 |
-
- Example: {"T_strength": 1, "S_strength": 0} means:
|
| 735 |
-
- T_strength must be 1 (has the feature)
|
| 736 |
-
- S_strength must be 0 (does not have the feature)
|
| 737 |
-
selected_horizons: List of horizons to include (e.g., ["short", "medium"])
|
| 738 |
|
| 739 |
Returns:
|
| 740 |
tuple: (message, leaderboard_df)
|
| 741 |
-
- message: Status message with matching count
|
| 742 |
-
- leaderboard_df: DataFrame with model metrics, sorted by MASE
|
| 743 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 744 |
from src.about import VARIATES_DF, FEATURES_DF, FEATURES_BOOL_DF, PATTERN_MAP
|
| 745 |
|
| 746 |
# Check if data is available
|
|
|
|
| 10 |
from src.hf_config import get_datasets_root, get_config_root
|
| 11 |
from src.utils import normalize_by_seasonal_naive
|
| 12 |
import ast
|
| 13 |
+
from functools import lru_cache
|
| 14 |
from timebench.evaluation.data import Dataset, get_dataset_settings, load_dataset_config
|
| 15 |
from pathlib import Path
|
| 16 |
|
|
|
|
| 84 |
|
| 85 |
return None
|
| 86 |
|
| 87 |
+
|
| 88 |
+
# =============================================================================
|
| 89 |
+
# Cached Helpers (Layer 1 & Layer 2)
|
| 90 |
+
# =============================================================================
|
| 91 |
+
|
| 92 |
+
@lru_cache(maxsize=20)
|
| 93 |
+
def _get_dataset_metadata(dataset_term, horizon):
|
| 94 |
+
"""
|
| 95 |
+
Load and cache Dataset metadata (series names, variate names, etc.).
|
| 96 |
+
|
| 97 |
+
This is the **Layer 1 cache** — the single most impactful optimization.
|
| 98 |
+
Creating a Dataset object loads an HF dataset from disk, which takes
|
| 99 |
+
hundreds of milliseconds. By caching the result, subsequent calls for
|
| 100 |
+
the same (dataset_term, horizon) return instantly.
|
| 101 |
+
|
| 102 |
+
Args:
|
| 103 |
+
dataset_term: Dataset term path, e.g. "Traffic/15T"
|
| 104 |
+
horizon: Horizon name ("short", "medium", "long")
|
| 105 |
+
|
| 106 |
+
Returns:
|
| 107 |
+
dict with keys: dataset_obj, series_names, variate_names, is_uts,
|
| 108 |
+
series_name_to_idx, variate_name_to_idx, num_windows, freq
|
| 109 |
+
or None on failure.
|
| 110 |
+
"""
|
| 111 |
+
try:
|
| 112 |
+
hf_dataset_root = str(get_datasets_root())
|
| 113 |
+
config_root = get_config_root()
|
| 114 |
+
config_path = config_root / "datasets.yaml"
|
| 115 |
+
|
| 116 |
+
config = load_dataset_config(config_path) if config_path.exists() else {}
|
| 117 |
+
settings = get_dataset_settings(dataset_term, horizon, config)
|
| 118 |
+
|
| 119 |
+
dataset_obj = Dataset(
|
| 120 |
+
name=dataset_term,
|
| 121 |
+
term=horizon,
|
| 122 |
+
prediction_length=settings.get("prediction_length"),
|
| 123 |
+
test_length=settings.get("test_length"),
|
| 124 |
+
storage_path=hf_dataset_root,
|
| 125 |
+
)
|
| 126 |
+
|
| 127 |
+
# Get series names
|
| 128 |
+
if "item_id" in dataset_obj.hf_dataset.column_names:
|
| 129 |
+
series_names = list(dataset_obj.hf_dataset["item_id"])
|
| 130 |
+
else:
|
| 131 |
+
series_names = [dataset_obj.hf_dataset[i].get("item_id", f"item_{i}")
|
| 132 |
+
for i in range(len(dataset_obj.hf_dataset))]
|
| 133 |
+
|
| 134 |
+
# Get variate names
|
| 135 |
+
variate_names = dataset_obj.get_variate_names()
|
| 136 |
+
is_uts = (variate_names is None)
|
| 137 |
+
if variate_names is not None:
|
| 138 |
+
variate_names = list(variate_names)
|
| 139 |
+
|
| 140 |
+
# Build name-to-index mappings
|
| 141 |
+
series_name_to_idx = {name: idx for idx, name in enumerate(series_names)}
|
| 142 |
+
variate_name_to_idx = {}
|
| 143 |
+
if variate_names is not None:
|
| 144 |
+
variate_name_to_idx = {name: idx for idx, name in enumerate(variate_names)}
|
| 145 |
+
|
| 146 |
+
# Window count & frequency
|
| 147 |
+
num_windows = dataset_obj.windows
|
| 148 |
+
freq = dataset_obj.freq
|
| 149 |
+
|
| 150 |
+
return {
|
| 151 |
+
"dataset_obj": dataset_obj,
|
| 152 |
+
"series_names": series_names,
|
| 153 |
+
"variate_names": variate_names, # None for UTS
|
| 154 |
+
"is_uts": is_uts,
|
| 155 |
+
"series_name_to_idx": series_name_to_idx,
|
| 156 |
+
"variate_name_to_idx": variate_name_to_idx, # empty dict for UTS
|
| 157 |
+
"num_windows": num_windows,
|
| 158 |
+
"freq": freq,
|
| 159 |
+
}
|
| 160 |
+
except Exception as e:
|
| 161 |
+
print(f"[_get_dataset_metadata] Error for {dataset_term}/{horizon}: {e}")
|
| 162 |
+
return None
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
@lru_cache(maxsize=100)
|
| 166 |
+
def _load_metrics_cached(model_name, dataset_term, horizon):
|
| 167 |
+
"""
|
| 168 |
+
Load and cache metrics.npz arrays for a specific (model, dataset, horizon).
|
| 169 |
+
|
| 170 |
+
This is the **Layer 2 cache**. Each call to np.load opens a file and
|
| 171 |
+
reads arrays from disk. In get_window_leaderboard, load_test_windows
|
| 172 |
+
is called once per model (~15 times), each loading the same-format
|
| 173 |
+
file. Caching avoids repeated disk I/O.
|
| 174 |
+
|
| 175 |
+
Args:
|
| 176 |
+
model_name: Model name (e.g. "moirai_small")
|
| 177 |
+
dataset_term: Dataset term path (e.g. "Traffic/15T")
|
| 178 |
+
horizon: Horizon name ("short", "medium", "long")
|
| 179 |
+
|
| 180 |
+
Returns:
|
| 181 |
+
dict mapping metric names to numpy arrays, or None if file missing.
|
| 182 |
+
"""
|
| 183 |
+
results_root = str(RESULTS_ROOT)
|
| 184 |
+
metrics_path = os.path.join(results_root, model_name, dataset_term, horizon, "metrics.npz")
|
| 185 |
+
if not os.path.exists(metrics_path):
|
| 186 |
+
return None
|
| 187 |
+
npz = np.load(metrics_path)
|
| 188 |
+
# Materialise into a plain dict so the NpzFile handle can be closed
|
| 189 |
+
result = {k: npz[k] for k in npz.files}
|
| 190 |
+
npz.close()
|
| 191 |
+
return result
|
| 192 |
+
|
| 193 |
+
|
| 194 |
def load_test_windows(display_name, horizon, model_name="moirai_small", series=None, variate=None, window_id=None, parse_series=False):
|
| 195 |
"""
|
| 196 |
Load test window results from TIME NPZ files.
|
|
|
|
| 215 |
if dataset_term is None:
|
| 216 |
return None
|
| 217 |
|
| 218 |
+
# --- Layer 2 cache: metrics npz ---
|
| 219 |
+
metrics_dict = _load_metrics_cached(model_name, dataset_term, horizon)
|
| 220 |
+
if metrics_dict is None:
|
| 221 |
+
return None
|
|
|
|
| 222 |
|
| 223 |
+
mase_arr = metrics_dict["MASE"] # (num_series, num_windows, num_variates)
|
|
|
|
| 224 |
num_series, num_windows, num_variates = mase_arr.shape
|
| 225 |
|
| 226 |
+
# --- Layer 1 cache: dataset metadata ---
|
| 227 |
+
metadata = _get_dataset_metadata(dataset_term, horizon)
|
| 228 |
series_names = None
|
| 229 |
variate_names = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
series_name_to_idx = {}
|
| 231 |
variate_name_to_idx = {}
|
| 232 |
+
if metadata is not None:
|
| 233 |
+
series_names = metadata["series_names"]
|
| 234 |
+
variate_names = metadata["variate_names"]
|
| 235 |
+
series_name_to_idx = metadata["series_name_to_idx"]
|
| 236 |
+
if metadata["is_uts"]:
|
| 237 |
+
# UTS mode: variate names are same as series names
|
| 238 |
+
variate_names = series_names
|
| 239 |
+
variate_name_to_idx = {name: idx for idx, name in enumerate(variate_names)}
|
| 240 |
+
else:
|
| 241 |
+
variate_name_to_idx = metadata["variate_name_to_idx"]
|
| 242 |
|
| 243 |
# Convert series and variate names to indices if they are names
|
| 244 |
series_idx_filter = None
|
|
|
|
| 292 |
"variate_name": variate_name,
|
| 293 |
"window_id": window_idx,
|
| 294 |
"MASE": float(mase_arr[series_idx, window_idx, variate_idx]),
|
| 295 |
+
"CRPS": float(metrics_dict["CRPS"][series_idx, window_idx, variate_idx]),
|
| 296 |
+
"MAE": float(metrics_dict["MAE"][series_idx, window_idx, variate_idx]),
|
| 297 |
+
"MSE": float(metrics_dict["MSE"][series_idx, window_idx, variate_idx]),
|
| 298 |
"model": model_name,
|
| 299 |
"series_idx": series_idx, # Keep for reference
|
| 300 |
"variate_idx": variate_idx, # Keep for reference
|
|
|
|
| 489 |
if df_filtered.empty:
|
| 490 |
return f"No results found for dataset '{display_name}' with horizons {horizons}.", pd.DataFrame(columns=["model"])
|
| 491 |
|
| 492 |
+
# Get dataset information (series count, variate count, freq) via cached metadata
|
| 493 |
dataset_info_msg = ""
|
| 494 |
try:
|
| 495 |
+
horizon_for_meta = horizons[0] if horizons else "short"
|
| 496 |
+
metadata = _get_dataset_metadata(dataset_id, horizon_for_meta)
|
| 497 |
+
if metadata is not None:
|
| 498 |
+
num_series = len(set(metadata["series_names"]))
|
| 499 |
+
num_variates = len(metadata["variate_names"]) if metadata["variate_names"] is not None else 1
|
| 500 |
+
freq = metadata["freq"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 501 |
dataset_info_msg = f"📊 Dataset Info: {num_series} series, {num_variates} variates, freq={freq}"
|
| 502 |
+
else:
|
| 503 |
+
if "/" in dataset_id:
|
| 504 |
+
_, freq = dataset_id.split("/", 1)
|
| 505 |
+
dataset_info_msg = f"📊 Dataset Info: freq={freq}"
|
| 506 |
except Exception as e:
|
| 507 |
print(f"Error getting dataset info: {e}")
|
|
|
|
| 508 |
if "/" in dataset_id:
|
| 509 |
_, freq = dataset_id.split("/", 1)
|
| 510 |
dataset_info_msg = f"📊 Dataset Info: freq={freq}"
|
|
|
|
| 612 |
def get_dataset_multilevel_leaderboard(display_name, series, variate, horizons, metric: str = "MASE"):
|
| 613 |
"""
|
| 614 |
Get leaderboard based on dataset, series, and variate selections.
|
| 615 |
+
Thin wrapper that converts mutable args to hashable types for caching.
|
| 616 |
+
"""
|
| 617 |
+
horizons_key = tuple(sorted(horizons)) if horizons else ()
|
| 618 |
+
return _get_dataset_multilevel_leaderboard_cached(display_name, series, variate, horizons_key, metric)
|
| 619 |
+
|
| 620 |
+
|
| 621 |
+
@lru_cache(maxsize=30)
|
| 622 |
+
def _get_dataset_multilevel_leaderboard_cached(display_name, series, variate, horizons_key, metric: str = "MASE"):
|
| 623 |
+
"""
|
| 624 |
+
Cached implementation of get_dataset_multilevel_leaderboard.
|
| 625 |
|
| 626 |
Logic:
|
| 627 |
0. If only dataset selected (series="---", variate="---"): return dataset-level results
|
|
|
|
| 632 |
display_name: Dataset display name from UI (will be converted to dataset_id)
|
| 633 |
series: Series name or "---" if not selected
|
| 634 |
variate: Variate name or "---" if not selected
|
| 635 |
+
horizons_key: Tuple of horizons (hashable)
|
| 636 |
metric: Metric for sorting
|
| 637 |
|
| 638 |
Returns:
|
| 639 |
tuple: (message, DataFrame)
|
| 640 |
"""
|
| 641 |
+
horizons = list(horizons_key)
|
| 642 |
+
|
| 643 |
# Case 0: Only dataset selected - return both original and normalized metrics
|
| 644 |
if (series is None or series == "---" or series == "") and (variate is None or variate == "---" or variate == ""):
|
| 645 |
return get_dataset_leaderboard(display_name, horizons, metric)
|
|
|
|
| 653 |
if dataset_term is None:
|
| 654 |
return f"Dataset '{display_name}' not found.", pd.DataFrame(columns=["model", "MASE", "CRPS", "MAE", "MSE"])
|
| 655 |
|
| 656 |
+
# Check if dataset is UTS or MTS using cached metadata
|
| 657 |
is_uts = False
|
| 658 |
try:
|
| 659 |
+
horizon_for_meta = horizons[0] if horizons else "short"
|
| 660 |
+
metadata = _get_dataset_metadata(dataset_term, horizon_for_meta)
|
| 661 |
+
if metadata is not None:
|
| 662 |
+
is_uts = metadata["is_uts"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 663 |
except Exception as e:
|
| 664 |
print(f"Error checking UTS/MTS: {e}")
|
| 665 |
|
|
|
|
| 710 |
|
| 711 |
|
| 712 |
|
| 713 |
+
@lru_cache(maxsize=30)
|
| 714 |
def get_window_leaderboard(display_name, series, variate, window_id, horizon, metric: str = "MASE"):
|
| 715 |
"""
|
| 716 |
Get leaderboard for a specific test window.
|
| 717 |
+
Cached because all arguments are hashable strings.
|
| 718 |
|
| 719 |
Args:
|
| 720 |
display_name: Dataset display name from UI (will be converted to dataset_id)
|
|
|
|
| 757 |
) -> tuple[str, pd.DataFrame]:
|
| 758 |
"""
|
| 759 |
Filter variates by selected patterns and compute average metrics per model.
|
| 760 |
+
Thin wrapper that converts mutable args to hashable types for caching.
|
| 761 |
+
"""
|
| 762 |
+
filters_key = frozenset(pattern_filters.items()) if pattern_filters else frozenset()
|
| 763 |
+
horizons_key = tuple(sorted(selected_horizons)) if selected_horizons else ()
|
| 764 |
+
return _get_pattern_leaderboard_cached(filters_key, horizons_key)
|
| 765 |
+
|
| 766 |
+
|
| 767 |
+
@lru_cache(maxsize=30)
|
| 768 |
+
def _get_pattern_leaderboard_cached(
|
| 769 |
+
filters_key: frozenset,
|
| 770 |
+
horizons_key: tuple,
|
| 771 |
+
) -> tuple[str, pd.DataFrame]:
|
| 772 |
+
"""
|
| 773 |
+
Cached implementation of get_pattern_leaderboard.
|
| 774 |
|
| 775 |
Uses FEATURES_BOOL_DF (binarized features) to filter variates,
|
| 776 |
then joins with VARIATES_DF to get metrics.
|
| 777 |
|
| 778 |
Args:
|
| 779 |
+
filters_key: frozenset of (pattern_name, required_value) pairs
|
| 780 |
+
horizons_key: tuple of horizon strings
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 781 |
|
| 782 |
Returns:
|
| 783 |
tuple: (message, leaderboard_df)
|
|
|
|
|
|
|
| 784 |
"""
|
| 785 |
+
# Convert back from hashable types
|
| 786 |
+
pattern_filters = dict(filters_key)
|
| 787 |
+
selected_horizons = list(horizons_key)
|
| 788 |
+
|
| 789 |
from src.about import VARIATES_DF, FEATURES_DF, FEATURES_BOOL_DF, PATTERN_MAP
|
| 790 |
|
| 791 |
# Check if data is available
|
src/tab.py
CHANGED
|
@@ -31,9 +31,10 @@ import json
|
|
| 31 |
import gradio as gr
|
| 32 |
from src.about import DATASET_CHOICES, ALL_MODELS, RESULTS_ROOT, FEATURES_DF, FEATURES_BOOL_DF, PATTERN_MAP
|
| 33 |
from src.leaderboard import (get_overall_leaderboard, get_dataset_multilevel_leaderboard,
|
| 34 |
-
get_window_leaderboard, get_pattern_leaderboard, resolve_dataset_id
|
|
|
|
| 35 |
from src.about import DATASETS_DF, ALL_HORIZONS
|
| 36 |
-
|
| 37 |
import numpy as np
|
| 38 |
import pandas as pd
|
| 39 |
from pathlib import Path
|
|
@@ -43,7 +44,7 @@ matplotlib.use('Agg') # Use non-interactive backend for Gradio
|
|
| 43 |
import yaml
|
| 44 |
import tempfile
|
| 45 |
|
| 46 |
-
|
| 47 |
from src.leaderboard import find_dataset_term_path
|
| 48 |
|
| 49 |
|
|
@@ -86,42 +87,17 @@ def update_series_and_variate(display_name):
|
|
| 86 |
gr.Dropdown(choices=["---"], value="---", label="Select Variate", interactive=True),
|
| 87 |
)
|
| 88 |
|
| 89 |
-
#
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
# horizon doesn't affect series and variate values, so use "short" directly
|
| 98 |
-
config = load_dataset_config(config_path)
|
| 99 |
-
settings = get_dataset_settings(dataset_term, "short", config)
|
| 100 |
-
|
| 101 |
-
prediction_length = settings.get("prediction_length")
|
| 102 |
-
test_length = settings.get("test_length")
|
| 103 |
-
|
| 104 |
-
dataset_obj = Dataset(
|
| 105 |
-
name=dataset_term,
|
| 106 |
-
term="short",
|
| 107 |
-
prediction_length=prediction_length,
|
| 108 |
-
test_length=test_length,
|
| 109 |
-
storage_path=hf_dataset_root, # Pass storage path directly
|
| 110 |
-
)
|
| 111 |
-
|
| 112 |
-
# Get series names
|
| 113 |
-
if "item_id" in dataset_obj.hf_dataset.column_names:
|
| 114 |
-
series_names = dataset_obj.hf_dataset["item_id"]
|
| 115 |
-
else:
|
| 116 |
-
series_names = [dataset_obj.hf_dataset[i].get("item_id", f"item_{i}")
|
| 117 |
-
for i in range(len(dataset_obj.hf_dataset))]
|
| 118 |
-
|
| 119 |
-
series_list = ["---"] + [str(name) for name in series_names]
|
| 120 |
|
| 121 |
-
|
| 122 |
-
variate_names = dataset_obj.get_variate_names()
|
| 123 |
|
| 124 |
-
if
|
| 125 |
# UTS mode: variate dropdown should be disabled
|
| 126 |
return (
|
| 127 |
gr.Dropdown(choices=series_list, value="---", label="Select Series", interactive=True),
|
|
@@ -129,7 +105,7 @@ def update_series_and_variate(display_name):
|
|
| 129 |
)
|
| 130 |
else:
|
| 131 |
# MTS mode: both dropdowns are enabled
|
| 132 |
-
variates_list = ["---"] + [str(name) for name in variate_names]
|
| 133 |
return (
|
| 134 |
gr.Dropdown(choices=series_list, value="---", label="Select Series", interactive=True),
|
| 135 |
gr.Dropdown(choices=variates_list, value="---", label="Select Variate", interactive=True),
|
|
@@ -234,52 +210,20 @@ def update_series_variate_and_window(display_name, horizon):
|
|
| 234 |
gr.Dropdown(choices=[], value=None, label="Select Testing Window", interactive=False),
|
| 235 |
)
|
| 236 |
|
| 237 |
-
#
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
config_root = get_config_root()
|
| 246 |
-
config_path = config_root / "datasets.yaml"
|
| 247 |
-
|
| 248 |
-
config = load_dataset_config(config_path) if config_path.exists() else {}
|
| 249 |
-
settings = get_dataset_settings(dataset_term, horizon, config)
|
| 250 |
-
|
| 251 |
-
prediction_length = settings.get("prediction_length")
|
| 252 |
-
test_length = settings.get("test_length")
|
| 253 |
-
|
| 254 |
-
# Load dataset
|
| 255 |
-
dataset_obj = Dataset(
|
| 256 |
-
name=dataset_term,
|
| 257 |
-
term=horizon,
|
| 258 |
-
prediction_length=prediction_length,
|
| 259 |
-
test_length=test_length,
|
| 260 |
-
storage_path=hf_dataset_root, # Pass storage path directly
|
| 261 |
-
)
|
| 262 |
-
|
| 263 |
-
# Get series names (item_id) from hf_dataset
|
| 264 |
-
if "item_id" in dataset_obj.hf_dataset.column_names:
|
| 265 |
-
series_names = dataset_obj.hf_dataset["item_id"]
|
| 266 |
-
else:
|
| 267 |
-
# Fallback: get from iterating
|
| 268 |
-
series_names = [dataset_obj.hf_dataset[i].get("item_id", f"item_{i}")
|
| 269 |
-
for i in range(len(dataset_obj.hf_dataset))]
|
| 270 |
-
|
| 271 |
-
# Get variate names
|
| 272 |
-
variate_names = dataset_obj.get_variate_names()
|
| 273 |
-
|
| 274 |
-
# Get window count
|
| 275 |
-
num_windows = dataset_obj.windows
|
| 276 |
-
windows = [str(i) for i in range(num_windows)]
|
| 277 |
|
| 278 |
-
|
| 279 |
-
series_list = [str(name) for name in series_names]
|
| 280 |
|
| 281 |
# Handle UTS (Univariate Time Series) vs MTS (Multivariate Time Series)
|
| 282 |
-
if
|
| 283 |
# UTS mode: each series is a single variate, so variate is always 0
|
| 284 |
return (
|
| 285 |
gr.Dropdown(choices=series_list, value=series_list[0], label="Select Series", interactive=True),
|
|
@@ -288,7 +232,7 @@ def update_series_variate_and_window(display_name, horizon):
|
|
| 288 |
)
|
| 289 |
else:
|
| 290 |
# MTS mode: multiple variates per series
|
| 291 |
-
variates_list = [str(name) for name in variate_names]
|
| 292 |
return (
|
| 293 |
gr.Dropdown(choices=series_list, value=series_list[0], label="Select Series", interactive=True),
|
| 294 |
gr.Dropdown(choices=variates_list, value=variates_list[0], label="Select Variate", interactive=True),
|
|
@@ -358,51 +302,25 @@ def plot_window_series(display_name, series, variate, window_id, horizon, select
|
|
| 358 |
print(f"📊 Applying inverse scale factor: {prediction_scale_factor}")
|
| 359 |
predictions_quantiles = predictions_quantiles.astype(np.float32) * prediction_scale_factor
|
| 360 |
|
| 361 |
-
#
|
| 362 |
-
|
| 363 |
-
|
| 364 |
-
|
| 365 |
-
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
hf_dataset_root = str(get_datasets_root())
|
| 369 |
-
print(f"📁 hf_dataset_root: {hf_dataset_root}, exists: {os.path.exists(hf_dataset_root)}")
|
| 370 |
-
|
| 371 |
-
# Use HF config to get config root
|
| 372 |
-
config_root = get_config_root()
|
| 373 |
-
config_path_yaml = config_root / "datasets.yaml"
|
| 374 |
-
print(f"📁 config_path_yaml: {config_path_yaml}, exists: {config_path_yaml.exists()}")
|
| 375 |
-
|
| 376 |
-
config = load_dataset_config(config_path_yaml) if config_path_yaml.exists() else {}
|
| 377 |
-
settings = get_dataset_settings(dataset_term, horizon, config)
|
| 378 |
-
print(f"⚙️ settings: {settings}")
|
| 379 |
-
|
| 380 |
-
prediction_length = settings.get("prediction_length")
|
| 381 |
-
test_length = settings.get("test_length")
|
| 382 |
-
|
| 383 |
-
print(f"📥 Loading Dataset: name={dataset_term}, term={horizon}, storage_path={hf_dataset_root}")
|
| 384 |
-
dataset_obj = Dataset(
|
| 385 |
-
name=dataset_term,
|
| 386 |
-
term=horizon,
|
| 387 |
-
prediction_length=prediction_length,
|
| 388 |
-
test_length=test_length,
|
| 389 |
-
storage_path=hf_dataset_root, # Pass storage path directly
|
| 390 |
-
)
|
| 391 |
-
print(f"✅ Dataset loaded: {len(dataset_obj.hf_dataset)} series")
|
| 392 |
|
| 393 |
-
|
| 394 |
-
dataset_freq =
|
| 395 |
-
|
|
|
|
|
|
|
| 396 |
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
series_names = dataset_obj.hf_dataset["item_id"]
|
| 400 |
-
else:
|
| 401 |
-
series_names = [dataset_obj.hf_dataset[i].get("item_id", f"item_{i}")
|
| 402 |
-
for i in range(len(dataset_obj.hf_dataset))]
|
| 403 |
|
| 404 |
-
|
| 405 |
-
|
| 406 |
if series in series_name_to_idx:
|
| 407 |
series_idx = series_name_to_idx[series]
|
| 408 |
print(f"✅ Found series '{series}' at index {series_idx}")
|
|
@@ -410,27 +328,21 @@ def plot_window_series(display_name, series, variate, window_id, horizon, select
|
|
| 410 |
series_idx = int(series)
|
| 411 |
print(f"⚠️ Series '{series}' not found in names, using int index {series_idx}")
|
| 412 |
|
| 413 |
-
#
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
if variate_names is not None:
|
| 417 |
-
# MTS mode: multiple variates per series
|
| 418 |
-
variate_name_to_idx = {name: idx for idx, name in enumerate(variate_names)}
|
| 419 |
-
if variate in variate_name_to_idx:
|
| 420 |
-
variate_idx = variate_name_to_idx[variate]
|
| 421 |
-
print(f"✅ Found variate '{variate}' at index {variate_idx}")
|
| 422 |
-
else:
|
| 423 |
-
variate_idx = int(variate)
|
| 424 |
-
print(f"⚠️ Variate '{variate}' not found in names, using int index {variate_idx}")
|
| 425 |
-
else:
|
| 426 |
-
# UTS mode: each series is a single variate, so variate_idx is always 0
|
| 427 |
variate_idx = 0
|
| 428 |
print(f"ℹ️ UTS mode, variate_idx=0")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 429 |
|
| 430 |
if series_idx is None:
|
| 431 |
series_idx = int(series)
|
| 432 |
if variate_idx is None:
|
| 433 |
-
# For UTS mode, variate_idx should be 0
|
| 434 |
try:
|
| 435 |
variate_idx = int(variate) if variate is not None else 0
|
| 436 |
except (ValueError, TypeError):
|
|
|
|
| 31 |
import gradio as gr
|
| 32 |
from src.about import DATASET_CHOICES, ALL_MODELS, RESULTS_ROOT, FEATURES_DF, FEATURES_BOOL_DF, PATTERN_MAP
|
| 33 |
from src.leaderboard import (get_overall_leaderboard, get_dataset_multilevel_leaderboard,
|
| 34 |
+
get_window_leaderboard, get_pattern_leaderboard, resolve_dataset_id,
|
| 35 |
+
_get_dataset_metadata)
|
| 36 |
from src.about import DATASETS_DF, ALL_HORIZONS
|
| 37 |
+
# get_datasets_root, get_config_root no longer needed here — handled by _get_dataset_metadata
|
| 38 |
import numpy as np
|
| 39 |
import pandas as pd
|
| 40 |
from pathlib import Path
|
|
|
|
| 44 |
import yaml
|
| 45 |
import tempfile
|
| 46 |
|
| 47 |
+
# Dataset, get_dataset_settings, load_dataset_config no longer needed here — handled by _get_dataset_metadata
|
| 48 |
from src.leaderboard import find_dataset_term_path
|
| 49 |
|
| 50 |
|
|
|
|
| 87 |
gr.Dropdown(choices=["---"], value="---", label="Select Variate", interactive=True),
|
| 88 |
)
|
| 89 |
|
| 90 |
+
# Use cached metadata (horizon doesn't affect series/variate values)
|
| 91 |
+
metadata = _get_dataset_metadata(dataset_term, "short")
|
| 92 |
+
if metadata is None:
|
| 93 |
+
return (
|
| 94 |
+
gr.Dropdown(choices=["---"], value="---", label="Select Series", interactive=True),
|
| 95 |
+
gr.Dropdown(choices=["---"], value="---", label="Select Variate", interactive=True),
|
| 96 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
|
| 98 |
+
series_list = ["---"] + [str(name) for name in metadata["series_names"]]
|
|
|
|
| 99 |
|
| 100 |
+
if metadata["is_uts"]:
|
| 101 |
# UTS mode: variate dropdown should be disabled
|
| 102 |
return (
|
| 103 |
gr.Dropdown(choices=series_list, value="---", label="Select Series", interactive=True),
|
|
|
|
| 105 |
)
|
| 106 |
else:
|
| 107 |
# MTS mode: both dropdowns are enabled
|
| 108 |
+
variates_list = ["---"] + [str(name) for name in metadata["variate_names"]]
|
| 109 |
return (
|
| 110 |
gr.Dropdown(choices=series_list, value="---", label="Select Series", interactive=True),
|
| 111 |
gr.Dropdown(choices=variates_list, value="---", label="Select Variate", interactive=True),
|
|
|
|
| 210 |
gr.Dropdown(choices=[], value=None, label="Select Testing Window", interactive=False),
|
| 211 |
)
|
| 212 |
|
| 213 |
+
# Use cached metadata
|
| 214 |
+
metadata = _get_dataset_metadata(dataset_term, horizon)
|
| 215 |
+
if metadata is None:
|
| 216 |
+
return (
|
| 217 |
+
gr.Dropdown(choices=[], value=None, label="Select Series", interactive=False),
|
| 218 |
+
gr.Dropdown(choices=[], value=None, label="Select Variate", interactive=False),
|
| 219 |
+
gr.Dropdown(choices=[], value=None, label="Select Testing Window", interactive=False),
|
| 220 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
|
| 222 |
+
windows = [str(i) for i in range(metadata["num_windows"])]
|
| 223 |
+
series_list = [str(name) for name in metadata["series_names"]]
|
| 224 |
|
| 225 |
# Handle UTS (Univariate Time Series) vs MTS (Multivariate Time Series)
|
| 226 |
+
if metadata["is_uts"]:
|
| 227 |
# UTS mode: each series is a single variate, so variate is always 0
|
| 228 |
return (
|
| 229 |
gr.Dropdown(choices=series_list, value=series_list[0], label="Select Series", interactive=True),
|
|
|
|
| 232 |
)
|
| 233 |
else:
|
| 234 |
# MTS mode: multiple variates per series
|
| 235 |
+
variates_list = [str(name) for name in metadata["variate_names"]]
|
| 236 |
return (
|
| 237 |
gr.Dropdown(choices=series_list, value=series_list[0], label="Select Series", interactive=True),
|
| 238 |
gr.Dropdown(choices=variates_list, value=variates_list[0], label="Select Variate", interactive=True),
|
|
|
|
| 302 |
print(f"📊 Applying inverse scale factor: {prediction_scale_factor}")
|
| 303 |
predictions_quantiles = predictions_quantiles.astype(np.float32) * prediction_scale_factor
|
| 304 |
|
| 305 |
+
# Use cached metadata for name-to-index mappings and Dataset object
|
| 306 |
+
metadata = _get_dataset_metadata(dataset_term, horizon)
|
| 307 |
+
if metadata is None:
|
| 308 |
+
print("❌ Failed to load dataset metadata")
|
| 309 |
+
fig = go.Figure()
|
| 310 |
+
fig.update_layout(title="Failed to load dataset metadata")
|
| 311 |
+
return fig, ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 312 |
|
| 313 |
+
dataset_obj = metadata["dataset_obj"]
|
| 314 |
+
dataset_freq = metadata["freq"]
|
| 315 |
+
test_length = dataset_obj._test_length
|
| 316 |
+
series_name_to_idx = metadata["series_name_to_idx"]
|
| 317 |
+
variate_name_to_idx = metadata["variate_name_to_idx"]
|
| 318 |
|
| 319 |
+
print(f"✅ Dataset loaded from cache: {len(dataset_obj.hf_dataset)} series")
|
| 320 |
+
print(f"📅 Dataset frequency: {dataset_freq}")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 321 |
|
| 322 |
+
# Convert series name to index
|
| 323 |
+
series_idx = None
|
| 324 |
if series in series_name_to_idx:
|
| 325 |
series_idx = series_name_to_idx[series]
|
| 326 |
print(f"✅ Found series '{series}' at index {series_idx}")
|
|
|
|
| 328 |
series_idx = int(series)
|
| 329 |
print(f"⚠️ Series '{series}' not found in names, using int index {series_idx}")
|
| 330 |
|
| 331 |
+
# Convert variate name to index
|
| 332 |
+
variate_idx = None
|
| 333 |
+
if metadata["is_uts"]:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 334 |
variate_idx = 0
|
| 335 |
print(f"ℹ️ UTS mode, variate_idx=0")
|
| 336 |
+
elif variate in variate_name_to_idx:
|
| 337 |
+
variate_idx = variate_name_to_idx[variate]
|
| 338 |
+
print(f"✅ Found variate '{variate}' at index {variate_idx}")
|
| 339 |
+
else:
|
| 340 |
+
variate_idx = int(variate)
|
| 341 |
+
print(f"⚠️ Variate '{variate}' not found in names, using int index {variate_idx}")
|
| 342 |
|
| 343 |
if series_idx is None:
|
| 344 |
series_idx = int(series)
|
| 345 |
if variate_idx is None:
|
|
|
|
| 346 |
try:
|
| 347 |
variate_idx = int(variate) if variate is not None else 0
|
| 348 |
except (ValueError, TypeError):
|