Show Gaussian probability buckets in model summary
This commit is contained in:
@@ -2,8 +2,10 @@ import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import {
|
||||
MODEL_SUMMARY_MODEL_COLUMNS,
|
||||
buildModelSummaryProbabilityColumns,
|
||||
buildModelSummaryRows,
|
||||
filterModelSummaryRows,
|
||||
formatModelSummaryProbability,
|
||||
formatModelSummaryLocalTime,
|
||||
formatModelSummaryTemp,
|
||||
hasModelSummaryForecastData,
|
||||
@@ -52,6 +54,12 @@ export function runTests() {
|
||||
JMA: 30.9,
|
||||
"AROME HD": 32.1,
|
||||
},
|
||||
distribution_full: [
|
||||
{ value: 31, model_probability: 0.16, range: "[30.5~31.5)" },
|
||||
{ value: 32, model_probability: 0.42, range: "[31.5~32.5)" },
|
||||
{ value: 33, model_probability: 0.31, range: "[32.5~33.5)" },
|
||||
],
|
||||
probability_engine: "legacy",
|
||||
},
|
||||
{
|
||||
city: "madrid",
|
||||
@@ -67,6 +75,10 @@ export function runTests() {
|
||||
ECMWF: 37,
|
||||
GFS: 38.2,
|
||||
},
|
||||
distribution_preview: [
|
||||
{ value: 35, probability: 0.18 },
|
||||
{ value: 36, probability: 0.52 },
|
||||
],
|
||||
},
|
||||
{
|
||||
city: "amsterdam",
|
||||
@@ -112,6 +124,22 @@ export function runTests() {
|
||||
assert(parisRow.models.HRRR === null, "missing models should be normalized to null");
|
||||
assert(parisRow.modelMedian === 32.1, "model median should use available model values only");
|
||||
assert(parisRow.modelSpread === 2.5, "model spread should use available model min/max only");
|
||||
assert(parisRow.gaussianMu === 32.2, "model summary should compute Gaussian mu from probability buckets");
|
||||
assert(parisRow.probabilityEngine === "legacy", "model summary should preserve probability engine metadata");
|
||||
assert(parisRow.probabilityBuckets.length === 3, "model summary should keep every probability bucket");
|
||||
assert(
|
||||
parisRow.probabilityBucketMap["31.5-32.5°C"]?.probability === 0.42 &&
|
||||
parisRow.topProbabilityBucketKey === "31.5-32.5°C",
|
||||
"model summary should map probability buckets and identify the top bucket",
|
||||
);
|
||||
const probabilityColumns = buildModelSummaryProbabilityColumns(summaryRows);
|
||||
assert(
|
||||
probabilityColumns.map((column) => column.key).join("|") ===
|
||||
"30.5-31.5°C|31.5-32.5°C|32.5-33.5°C|34.5-35.5°C|35.5-36.5°C",
|
||||
"model summary should expose dynamic probability bucket columns sorted by temperature",
|
||||
);
|
||||
assert(formatModelSummaryProbability(null) === "—", "missing probability should render as an em dash");
|
||||
assert(formatModelSummaryProbability(0.424) === "42%", "probability buckets should render as rounded percentages");
|
||||
assert(formatModelSummaryTemp(null, "°C") === "—", "missing model temperatures should render as an em dash");
|
||||
assert(formatModelSummaryTemp(32.16, "°C") === "32.2°C", "model temperatures should render to one decimal");
|
||||
assert(hasModelSummaryForecastData(summaryRows), "model summary should recognize populated forecast rows");
|
||||
@@ -176,6 +204,11 @@ export function runTests() {
|
||||
modelSummarySource.includes("MODEL_SUMMARY_MODEL_COLUMNS") &&
|
||||
modelSummarySource.includes("lastGoodSummaryRowsRef") &&
|
||||
modelSummarySource.includes("hasModelSummaryForecastData") &&
|
||||
modelSummarySource.includes("buildModelSummaryProbabilityColumns") &&
|
||||
modelSummarySource.includes("Gaussian μ") &&
|
||||
modelSummarySource.includes("高斯 μ") &&
|
||||
modelSummarySource.includes("topProbabilityBucketKey") &&
|
||||
modelSummarySource.includes("min-w-[96px]") &&
|
||||
modelSummarySource.includes("Local Time") &&
|
||||
modelSummarySource.includes("当地时间") &&
|
||||
!modelSummarySource.includes("Current High") &&
|
||||
|
||||
Reference in New Issue
Block a user