Spaces:
Running
Running
Download src/static/explorer-plot.mjs from Salesforce/GIFT-Eval-CTX: direct link, hf CLI and curl.
- Browser
- Download file 6.54 kB
-
https://huggingface.co/spaces/Salesforce/GIFT-Eval-CTX/resolve/main/src/static/explorer-plot.mjs
- Command line
-
hf download hf://spaces/Salesforce/GIFT-Eval-CTX/src/static/explorer-plot.mjs
-
curl -L -o explorer-plot.mjs https://huggingface.co/spaces/Salesforce/GIFT-Eval-CTX/resolve/main/src/static/explorer-plot.mjs
6.54 kB
| // Use related colors to distinguish input variants of the same model. | |
| const methodColors = { | |
| seasonal_naive: "#7f7f7f", | |
| chronos_2: "#17becf", | |
| toto_2_0_313m: "#8c564b", | |
| moirai_2: "#d62728", | |
| timesfm_3: "#393b79", | |
| timebraid_6p7b_demo_rewrite_v1: "#3b82f6", | |
| claude_opus_4_8_hist_only: "#e377c2", | |
| claude_opus_4_8_hist_macro_micro: "#e377c2", | |
| gpt_5_6_sol_hist_only: "#2ca02c", | |
| gpt_5_6_sol_hist_macro: "#008c95", | |
| gpt_5_6_sol_hist_macro_micro: "#2ca02c", | |
| moirai_agent_hist_macro: "#bcbd22", | |
| moirai_agent_hist_macro_micro: "#7c9636", | |
| }; | |
| const eventColors = { impulse: "#c78463", sustained: "#8d76b5", recurrent: "#5a9d89", mean_shift: "#ba9953", amplitude: "#6f9cbd", onset: "#649b80", disappearance: "#ae8092", phase: "#ab9e58", period: "#858bc1" }; | |
| export function eventName(event) { | |
| let name = [event.family, event.subtype, event.direction].filter((value) => value != null && value !== "").join(" / ").replaceAll("_", " "); | |
| if (event.amplitude_trend) name += ` (inner ${event.amplitude_trend})`; | |
| else if (event.envelope_change) name += ` (envelope ${event.envelope_change})`; | |
| return name; | |
| } | |
| export function historySeries(history, context = 300) { | |
| const count = context === "all" ? history.length : Math.min(history.length, Number(context)); | |
| return { x: Array.from({ length: count }, (_, index) => index - count), y: history.slice(-count) }; | |
| } | |
| export function intervalGeometry(event) { | |
| return { center: (event.start + event.end) / 2, width: event.end - event.start + 1 }; | |
| } | |
| export function trendSegments(trend, horizon) { | |
| let start = 0; | |
| return (trend || []).map((segment, index) => { | |
| const end = index === trend.length - 1 ? horizon : Math.max(start + 1, Math.min(horizon, start + Math.round(segment.duration * horizon))); | |
| const result = { ...segment, start, end }; | |
| start = end; | |
| return result; | |
| }); | |
| } | |
| export function rankedMethods(forecasts) { | |
| return [...forecasts].sort((a, b) => a.mase - b.mase || a.id.localeCompare(b.id)); | |
| } | |
| export function makePlot(sample, selected, context = 300) { | |
| const history = historySeries(sample.history, context); | |
| const futureX = Array.from({ length: sample.n_horizon }, (_, i) => i); | |
| const predictions = rankedMethods(sample.forecasts).filter((method) => selected.has(method.id)); | |
| const nameCounts = new Map(); | |
| for (const method of sample.forecasts) nameCounts.set(method.name, (nameCounts.get(method.name) || 0) + 1); | |
| const extent = [...history.y, ...sample.future, ...predictions.flatMap((method) => method.forecast), ...sample.tsfm_average_forecast].filter((value) => value != null && Number.isFinite(value)); | |
| const low = Math.min(...extent), high = Math.max(...extent); | |
| const padding = (high - low || Math.abs(high) || 1) * .08; | |
| const bottom = low - padding, top = high + padding; | |
| const events = new Map(); | |
| for (const event of sample.micro) { | |
| const name = eventName(event); | |
| if (!events.has(name)) events.set(name, []); | |
| events.get(name).push(event); | |
| } | |
| const traces = [...events].map(([name, group], index) => ({ | |
| type: "bar", name, legendgroup: name, | |
| x: group.map((event) => intervalGeometry(event).center), | |
| width: group.map((event) => intervalGeometry(event).width), | |
| y: group.map(() => top - bottom), base: bottom, | |
| marker: { color: eventColors[group[0].subtype || group[0].family] || "#8298b1", opacity: .15, line: { width: 0 } }, | |
| customdata: group.map((event) => [event.start, event.end, event.intensity == null ? "—" : Number(event.intensity).toFixed(3)]), | |
| hovertemplate: `${name}<br>Future indices %{customdata[0]}–%{customdata[1]}<br>Intensity %{customdata[2]}<extra></extra>`, | |
| legendrank: 3 + index, | |
| })); | |
| const line = (name, x, y, color, dash, legendrank, width = 1.7) => ({ type: "scatter", mode: "lines", name, x, y, legendrank, connectgaps: false, line: { color, width, dash }, hovertemplate: `${name}<br>Step %{x}<br>Value %{y:.4g}<extra></extra>` }); | |
| traces.push(line("History", history.x, history.y, "#1f77b4", "solid", 0, 1.6)); | |
| traces.push(line("Future", futureX, sample.future, "#ff7f0e", "dash", 1, 2.4)); | |
| traces.push(line("TSFM average forecast", futureX, sample.tsfm_average_forecast, "#9467bd", "dot", 2)); | |
| for (const [index, method] of predictions.entries()) { | |
| const dash = method.id.endsWith("_hist_only") ? "dash" : "solid"; | |
| const name = nameCounts.get(method.name) > 1 ? `${method.name} (${method.input})` : method.name; | |
| traces.push(line(name, futureX, method.forecast, methodColors[method.id] || "#8c564b", dash, 3 + events.size + index)); | |
| } | |
| const shapes = [{ type: "line", x0: -.5, x1: -.5, y0: 0, y1: 1, yref: "paper", line: { color: "#a8b1bc", width: 1, dash: "dot" } }]; | |
| const annotations = []; | |
| const trendBand = { y0: 1.005, y1: 1.08, yref: "paper" }; | |
| const segments = trendSegments(sample.macro.trend, sample.n_horizon); | |
| if (segments.length) { | |
| annotations.push({ x: -.5, xref: "x", y: (trendBand.y0 + trendBand.y1) / 2, yref: "paper", xanchor: "right", yanchor: "middle", xshift: -8, text: "Macro trend:", showarrow: false, font: { size: 11, color: "#5b6877" } }); | |
| } | |
| for (const segment of segments) { | |
| shapes.push({ ...trendBand, type: "rect", x0: segment.start - .5, x1: segment.end - .5, fillcolor: { up: "#e5f1ec", down: "#f7e9df", flat: "#eef0f4" }[segment.direction] || "#eef0f4", line: { color: "#fff", width: 1 } }); | |
| annotations.push({ x: (segment.start + segment.end - 1) / 2, y: (trendBand.y0 + trendBand.y1) / 2, yref: "paper", xanchor: "center", yanchor: "middle", text: segment.direction, hovertext: `Macro trend: ${segment.direction}`, showarrow: false, font: { size: 11, color: "#5b6877" } }); | |
| } | |
| return { | |
| data: traces, | |
| layout: { | |
| height: 545, margin: { l: 65, r: 22, t: 55, b: 90 }, | |
| paper_bgcolor: "#fff", plot_bgcolor: "#fff", | |
| font: { family: "system-ui, sans-serif", color: "#687383", size: 11 }, | |
| xaxis: { title: { text: "Time Step" }, range: [-history.x.length - .5, sample.n_horizon - .5], gridcolor: "#eef1f4", zeroline: false }, | |
| yaxis: { title: { text: "Value" }, range: [bottom, top], gridcolor: "#eef1f4", zeroline: false }, | |
| legend: { orientation: "h", x: 0, y: -.17, yanchor: "top", font: { size: 10 }, traceorder: "normal", maxheight: .25 }, | |
| barmode: "overlay", bargap: 0, hovermode: "closest", shapes, annotations, | |
| uirevision: `${sample.id}/${context}`, dragmode: "zoom", | |
| }, | |
| config: { responsive: true, displaylogo: false, scrollZoom: false, modeBarButtonsToRemove: ["select2d", "lasso2d"] }, | |
| }; | |
| } | |