Show full Gaussian probability tooltip

This commit is contained in:
2569718930@qq.com
2026-06-07 13:02:16 +08:00
parent f66127da44
commit 27e4f1efe0
2 changed files with 52 additions and 18 deletions
@@ -77,8 +77,8 @@ export function TemperatureTooltipContent({
</div> </div>
)} )}
{probabilityRows.length > 0 && ( {probabilityRows.length > 0 && (
<div className={rows.length > 0 ? "mt-1.5 grid gap-1 border-t border-slate-100 pt-1.5" : "grid gap-1"}> <div className={rows.length > 0 ? "mt-1.5 grid max-h-[260px] gap-1 overflow-y-auto border-t border-slate-100 pt-1.5 pr-1" : "grid max-h-[260px] gap-1 overflow-y-auto pr-1"}>
{probabilityRows.slice(0, 8).map((item) => ( {probabilityRows.map((item) => (
<div key={item.key} className="flex min-w-[160px] items-center justify-between gap-4"> <div key={item.key} className="flex min-w-[160px] items-center justify-between gap-4">
<span className="inline-flex items-center gap-1.5 text-violet-700"> <span className="inline-flex items-center gap-1.5 text-violet-700">
<span className="h-2 w-2 rounded-full" style={{ backgroundColor: item.color }} /> <span className="h-2 w-2 rounded-full" style={{ backgroundColor: item.color }} />
@@ -118,6 +118,18 @@ function buildTooltipRows(
.filter((item): item is TooltipRow => item !== null); .filter((item): item is TooltipRow => item !== null);
} }
function formatProbabilityRangeValue(value: number) {
return Number(value.toFixed(1)).toString();
}
function formatProbabilityRangeLabel(
lower: number,
upper: number,
tempSymbol: string,
) {
return `${formatProbabilityRangeValue(lower)}-${formatProbabilityRangeValue(upper)}${tempSymbol}`;
}
function buildTooltipProbabilityRows( function buildTooltipProbabilityRows(
probabilityOverlay: ProbabilityOverlay | null | undefined, probabilityOverlay: ProbabilityOverlay | null | undefined,
tempSymbol: string, tempSymbol: string,
@@ -135,18 +147,20 @@ function buildTooltipProbabilityRows(
}); });
} }
const topBand = [...probabilityOverlay.bands] rows.push(
.filter((band) => validNumber(band.probability) !== null) ...[...probabilityOverlay.bands]
.sort((a, b) => b.probability - a.probability)[0]; .filter((band) => validNumber(band.probability) !== null && band.probability > 0)
if (topBand) { .sort((a, b) => a.lower - b.lower)
const probabilityPct = Math.round(topBand.probability * 100); .map((band) => {
rows.push({ const probabilityPct = Math.round(band.probability * 100);
key: topBand.key, return {
label: topBand.label, key: band.key,
value: `${probabilityPct}%`, label: formatProbabilityRangeLabel(band.lower, band.upper, tempSymbol),
color: "#a78bfa", value: `${probabilityPct}%`,
}); color: "#a78bfa",
} };
}),
);
return rows; return rows;
} }
@@ -61,6 +61,15 @@ export function runTests() {
engine: "legacy", engine: "legacy",
muLine: { value: 27.4, label: "Gaussian μ 27.4°C" }, muLine: { value: 27.4, label: "Gaussian μ 27.4°C" },
bands: [ bands: [
{
key: "legacy_probability_26_0",
value: 26,
lower: 25.5,
upper: 26.5,
probability: 0.18,
label: "26°C 18%",
opacity: 0.08,
},
{ {
key: "legacy_probability_27_0", key: "legacy_probability_27_0",
value: 27, value: 27,
@@ -70,6 +79,15 @@ export function runTests() {
label: "27°C 42%", label: "27°C 42%",
opacity: 0.13, opacity: 0.13,
}, },
{
key: "legacy_probability_28_0",
value: 28,
lower: 27.5,
upper: 28.5,
probability: 0.31,
label: "28°C 31%",
opacity: 0.11,
},
], ],
}, },
"°C", "°C",
@@ -77,13 +95,15 @@ export function runTests() {
); );
assert( assert(
probabilityRows.length === 2, probabilityRows.length === 4,
"temperature tooltip should show Gaussian μ and the leading probability bucket as compact context", "temperature tooltip should show Gaussian μ and every available probability bucket as compact context",
); );
assert( assert(
probabilityRows.some((row) => row.key === "legacy_probability_mu" && row.value === "27.4°C") && probabilityRows.some((row) => row.key === "legacy_probability_mu" && row.value === "27.4°C") &&
probabilityRows.some((row) => row.key === "legacy_probability_27_0" && row.value === "42%"), probabilityRows.some((row) => row.key === "legacy_probability_26_0" && row.label === "25.5-26.5°C" && row.value === "18%") &&
"temperature tooltip should format Gaussian μ and probability values without drawing a full probability band on the main chart", probabilityRows.some((row) => row.key === "legacy_probability_27_0" && row.label === "26.5-27.5°C" && row.value === "42%") &&
probabilityRows.some((row) => row.key === "legacy_probability_28_0" && row.label === "27.5-28.5°C" && row.value === "31%"),
"temperature tooltip should format the full Gaussian probability distribution by temperature range without drawing it on the main chart",
); );
const projectRoot = process.cwd(); const projectRoot = process.cwd();