A time series plot that displays historical observed data followed by a forecast projection with confidence intervals or uncertainty bands. The plot clearly distinguishes between the historical period and the forecast period using a vertical line marker, with shaded bands representing different confidence levels (typically 80% and 95%). This visualization is essential for communicating prediction uncertainty in forecasting applications, helping stakeholders understand both the expected values and the range of possible outcomes.

// anyplot.ai
// timeseries-forecast-uncertainty: Time Series Forecast with Uncertainty Band
// Library: highcharts 12.6.0 | JavaScript 22.23.2
// Quality: 91/100 | Created: 2026-09-02
const t = window.ANYPLOT_TOKENS;
// --- Data (in-memory, deterministic LCG — no seeded RNG in the browser) ----
let seed = 42;
function nextRandom() {
seed = (seed * 1103515245 + 12345) & 0x7fffffff;
return seed / 0x7fffffff;
}
const HIST_MONTHS = 36; // 3 years of monthly history
const FORECAST_MONTHS = 12; // 1-year-ahead forecast
const FORECAST_START_INDEX = HIST_MONTHS - 1; // forecast overlaps the last actual point
const TOTAL_MONTHS = HIST_MONTHS + FORECAST_MONTHS;
const START_YEAR = 2023;
const START_MONTH = 8; // September, 0-indexed
const timestamps = [];
for (let i = 0; i < TOTAL_MONTHS; i++) {
timestamps.push(Date.UTC(START_YEAR, START_MONTH + i, 1));
}
const BASELINE = 110; // thousand sessions
const GROWTH_PER_MONTH = 1.6;
const SEASONAL_AMPLITUDE = 18;
const actualSeries = [];
const forecastSeries = [];
const base80 = [];
const band80 = [];
const base95 = [];
const band95 = [];
for (let i = 0; i < TOTAL_MONTHS; i++) {
const trend = BASELINE + GROWTH_PER_MONTH * i;
const seasonal = SEASONAL_AMPLITUDE * Math.sin((2 * Math.PI * (i % 12)) / 12 - Math.PI / 2);
const expected = trend + seasonal;
const ts = timestamps[i];
if (i <= FORECAST_START_INDEX) {
const noise = (nextRandom() - 0.5) * 14;
actualSeries.push([ts, Math.round((expected + noise) * 10) / 10]);
} else {
actualSeries.push([ts, null]);
}
if (i >= FORECAST_START_INDEX) {
const horizon = i - FORECAST_START_INDEX;
const point = Math.round(expected * 10) / 10;
forecastSeries.push([ts, point]);
const spread80 = 6 + 2.4 * Math.sqrt(horizon + 1);
const spread95 = 10 + 4.1 * Math.sqrt(horizon + 1);
base80.push([ts, Math.round((point - spread80) * 10) / 10]);
band80.push([ts, Math.round(spread80 * 2 * 10) / 10]);
base95.push([ts, Math.round((point - spread95) * 10) / 10]);
band95.push([ts, Math.round(spread95 * 2 * 10) / 10]);
} else {
forecastSeries.push([ts, null]);
base80.push([ts, null]);
band80.push([ts, null]);
base95.push([ts, null]);
band95.push([ts, null]);
}
}
function hexToRgba(hex, alpha) {
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
}
const actualColor = t.palette[0]; // brand green — always first series
const forecastColor = t.palette[1]; // canonical position 2
const band80Color = hexToRgba(forecastColor, 0.38); // 80% CI — darker, tighter band
const band95Color = hexToRgba(forecastColor, 0.2); // 95% CI — lighter, wider band
// --- Chart -------------------------------------------------------------------
const TITLE = "timeseries-forecast-uncertainty · javascript · highcharts · anyplot.ai";
const TITLE_FONTSIZE = Math.max(15, Math.round(22 * Math.min(1, 67 / TITLE.length)));
Highcharts.chart("container", {
chart: {
type: "line",
backgroundColor: "transparent",
animation: false,
style: { fontFamily: "inherit" },
},
credits: { enabled: false },
colors: t.palette,
title: {
text: TITLE,
style: { color: t.ink, fontSize: `${TITLE_FONTSIZE}px`, fontWeight: "600" },
},
xAxis: {
type: "datetime",
lineColor: t.inkSoft,
tickColor: t.inkSoft,
gridLineColor: t.grid,
labels: { style: { color: t.inkSoft, fontSize: "14px" } },
plotLines: [
{
value: timestamps[FORECAST_START_INDEX],
color: t.inkSoft,
width: 2,
dashStyle: "Dash",
zIndex: 5,
label: {
text: "Forecast start",
rotation: 0,
y: 20,
style: { color: t.inkSoft, fontSize: "13px" },
},
},
],
},
yAxis: {
reversedStacks: false, // keep the invisible base series at the bottom of the stack
title: {
text: "Website sessions (thousands)",
style: { color: t.inkSoft, fontSize: "16px" },
},
gridLineColor: t.grid,
labels: { style: { color: t.inkSoft, fontSize: "14px" } },
},
tooltip: {
shared: true,
backgroundColor: t.elevatedBg,
borderColor: t.grid,
style: { color: t.ink, fontSize: "13px" },
valueSuffix: "k",
xDateFormat: "%b %Y",
},
legend: {
itemStyle: { color: t.inkSoft, fontSize: "14px" },
itemHoverStyle: { color: t.ink },
},
plotOptions: {
series: { animation: false },
line: { marker: { enabled: false } },
area: { stacking: "normal", marker: { enabled: false }, animation: false },
},
series: [
{
name: "95% confidence",
type: "area",
data: base95,
stack: "ci95",
color: "transparent",
lineWidth: 0,
fillOpacity: 0,
enableMouseTracking: false,
showInLegend: false,
},
{
name: "95% confidence",
type: "area",
data: band95,
stack: "ci95",
color: band95Color,
lineWidth: 0,
enableMouseTracking: false,
legendIndex: 3,
},
{
name: "80% confidence",
type: "area",
data: base80,
stack: "ci80",
color: "transparent",
lineWidth: 0,
fillOpacity: 0,
enableMouseTracking: false,
showInLegend: false,
},
{
name: "80% confidence",
type: "area",
data: band80,
stack: "ci80",
color: band80Color,
lineWidth: 0,
enableMouseTracking: false,
legendIndex: 2,
},
{
name: "Historical",
type: "line",
data: actualSeries,
color: actualColor,
lineWidth: 3,
legendIndex: 0,
},
{
name: "Forecast",
type: "line",
data: forecastSeries,
color: forecastColor,
lineWidth: 2.5,
dashStyle: "Dash",
legendIndex: 1,
},
],
});
Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/timeseries-forecast-uncertainty/highcharts/code. Any spec id and library id listed in llms-full.txt fit the same URL shape; every URL below is complete and callable.
{
"spec_id": "timeseries-forecast-uncertainty",
"language": "javascript",
"library": "highcharts",
"page": "https://anyplot.ai/timeseries-forecast-uncertainty/javascript/highcharts",
"hub": "https://anyplot.ai/timeseries-forecast-uncertainty",
"code_json": "https://api.anyplot.ai/specs/timeseries-forecast-uncertainty/highcharts/code",
"spec_json": "https://api.anyplot.ai/specs/timeseries-forecast-uncertainty",
"render_light_png": "https://storage.googleapis.com/anyplot-images/plots/timeseries-forecast-uncertainty/javascript/highcharts/plot-light.png",
"render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/timeseries-forecast-uncertainty/javascript/highcharts/plot-dark.png",
"interactive_light_html": "https://storage.googleapis.com/anyplot-images/plots/timeseries-forecast-uncertainty/javascript/highcharts/plot-light.html",
"interactive_dark_html": "https://storage.googleapis.com/anyplot-images/plots/timeseries-forecast-uncertainty/javascript/highcharts/plot-dark.html",
"quality_score": 91.0,
"license": "MIT",
"guide": "https://anyplot.ai/llms.txt"
}Part of Time Series Forecast with Uncertainty Band on anyplot.ai.