Free data template
Simple forecast
A trend plus weekly pattern fitted to daily sales, the next 4 weeks forecast and a check against the last weeks.
It opens with this template loaded and runs in your browser. You don't need an account to use it; a free account saves your work and exports it.
The job it does
For planning stock, staff or budget: a transparent baseline forecast before anyone reaches for a complex model. It comes with its own checks, so after you change it you can see at a glance that it still does the job.
How to use it with your own data
Load your daily numbers as a CSV called daily (columns date, value).
What's inside
This is the template exactly as the Data Lab opens it, read-only. Open it to run it, change it and export it.
- 3 notebook cells
- Data: the retail sample database (Mangrove Market: stores, customers, orders, payments)
Planning stock, staff or a budget needs a forecast, and a transparent baseline comes first: a straight-line trend times a factor for each day of the week. The notebook checks itself on the last 4 weeks it was not fitted on (the average daily error, mape_pct), then forecasts the next 4 weeks with a chart.
Your own data: load a CSV file called daily with the columns date and value, one row per day, and Run.
- The notebook runs top to bottom without errors
- forecast has 28 rows
- forecast.forecast has no empty values
- A line chart plots forecast
-- Revenue per day from June to November 2025 (delivered orders)
select o.ordered_at::date as date,
(sum(i.qty * i.unit_price_cents) / 100.0)::float8 as value
from orders o
join order_items i on i.order_id = o.id
where o.status = 'delivered'
and o.ordered_at >= '2025-06-01' and o.ordered_at < '2025-12-01'
group by 1
order by 1import numpy as np
# Your own data: load a CSV file called "daily" (columns date, value) and it is used instead.
src = (daily if "daily" in globals() else sales_daily).copy()
src.columns = ["date", "value"]
src["date"] = pd.to_datetime(src["date"])
src = src.sort_values("date").reset_index(drop=True)
src["t"] = np.arange(len(src))
src["dow"] = src["date"].dt.dayofweek
def fit(df):
"""A straight-line trend, times a factor per day of the week."""
slope, intercept = np.polyfit(df["t"], df["value"], 1)
season = (df["value"] / (intercept + slope * df["t"])).groupby(df["dow"]).mean()
return slope, intercept, season
def predict(model, t, dow):
slope, intercept, season = model
return (intercept + slope * np.asarray(t)) * season.reindex(np.asarray(dow)).to_numpy()
# check it first: fit on all but the last 4 weeks, forecast them, and measure the error
train, test = src.iloc[:-28], src.iloc[-28:]
check = predict(fit(train), test["t"], test["dow"])
mape_pct = round(float((abs(test["value"] - check) / test["value"]).mean() * 100), 2)
print(f"On the last 4 weeks the forecast was off by {mape_pct}% a day on average.")# the next 4 weeks, from a model fitted on all the data
model = fit(src)
days = pd.date_range(src["date"].iloc[-1] + pd.Timedelta(days=1), periods=28)
t = np.arange(len(src), len(src) + 28)
forecast = pd.DataFrame({"date": days.strftime("%Y-%m-%d"), "forecast": predict(model, t, days.dayofweek).round(2)})
recent = src.tail(56)
plot = pd.concat([
pd.DataFrame({"date": recent["date"].dt.strftime("%Y-%m-%d"), "actual": recent["value"].round(2), "forecast": np.nan}),
forecast.assign(actual=np.nan),
], ignore_index=True)
chart(plot, x="date", y=["actual", "forecast"], kind="line", title="Revenue per day: the last 8 weeks and the next 4")
forecastThe lesson behind it
Learn why it works, with a podcast and a quiz for each lesson.
More data templates
KPI dashboard notebook
Weekly revenue, orders, average basket and active customers, with a chart per KPI.
A/B test readout
Conversion per variant, the lift, a confidence interval and a plain-language verdict.