---
title: "Time series"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Time series}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r setup, include = FALSE}
knitr::opts_chunk$set(collapse = FALSE, comment = "",
fig.width = 7, fig.height = 4, dpi = 96,
dev.args = list(bg = "transparent"))
# Console colour carries no meaning on a rendered page. pkgdown turns it on for
# its own build, and the escape sequences then reach the reader as literal text,
# so colour is switched off here for a plain vignette render and a site build
# alike. The fixed width keeps printed output inside the documentation column.
options(cli.num_colors = 1, cli.hyperlink = FALSE, crayon.enabled = FALSE,
width = 80)
# Figures on the package website sit on a warm off-white page in light mode and
# are inverted by pkgdown in dark mode, so an opaque background would read as a
# pale slab one way and a black plate the other. Two things paint one. The
# device
# canvas is made transparent by `dev.args` above, and theme_depictr() then
# inherits theme_minimal()'s white plot.background, which is drawn over that
# canvas, so it is cleared as each figure is printed. This is deliberately a
# vignette-level choice: theme_depictr() keeps its opaque background, which is
# what a figure saved for a paper wants.
transparent_bg <- ggplot2::theme(
plot.background = ggplot2::element_rect(fill = NA, colour = NA),
panel.background = ggplot2::element_rect(fill = NA, colour = NA)
)
knit_print.ggplot <- function(x, ...) knitr::normal_print(x + transparent_bg)
knit_print.patchwork <- function(x, ...) knitr::normal_print(x & transparent_bg)
library(depictr)
```
depictr provides a small, consistent set of time-series plots. The examples use
the bundled `monthly_sales` dataset: two product lines (`indoor` and `outdoor`),
each with six years of monthly observations carrying a trend, a twelve-month
seasonal cycle and noise.
## Plotting one or several series
`timeseries_plot()` accepts a `ts` object, a numeric vector or a data frame with
time, value and (optionally) group columns. Passing the long-form data frame with
a grouping column draws both series at once, each in its own colour, and a
moving-average overlay is one argument away.
```{r}
timeseries_plot(monthly_sales, time = date, value = sales, group = series,
rolling = 12, title = "Monthly sales by product line",
y_lab = "Units")
```
For the single-series views (decomposition, autocorrelation, the seasonal plot
and forecasting) we extract one line as a monthly `ts` object of frequency 12.
```{r}
indoor <- subset(monthly_sales, series == "indoor")
indoor <- indoor[order(indoor$date), ]
indoor_ts <- ts(indoor$sales, start = c(2018, 1), frequency = 12)
```
## Decomposition
`decompose_plot()` separates a seasonal series into trend, seasonal and
remainder components. Use `method = "stl"` (the default, loess-based) or
`method = "classical"`. Setting `confidence = TRUE` shades a band around the
smoothed trend, from the spread of the remainder, so the scale of the
unexplained variation is visible rather than implied by the line alone.
```{r, fig.height = 6}
decompose_plot(indoor_ts, confidence = TRUE, title = "Indoor sales, decomposed")
```
Classical decomposition instead holds the seasonal component fixed across the
whole series, where STL lets it evolve from year to year.
```{r, fig.height = 6}
decompose_plot(indoor_ts, method = "classical",
title = "Indoor sales, classical decomposition")
```
## Autocorrelation
`acf_plot()` draws the autocorrelation (or, with `type = "partial"`, the partial
autocorrelation) function, with approximate significance bounds. The spikes at
multiples of twelve are the annual seasonality.
```{r, fig.height = 3.4}
acf_plot(indoor_ts)
```
```{r, fig.height = 3.4}
acf_plot(indoor_ts, type = "partial")
```
## The seasonal pattern up close
`seasonal_plot()` draws a seasonal-subseries (cycle) plot: one small panel per
month, with the value traced across successive years and a reference line at each
month's mean. This shows the seasonal shape (differences *between* panels) and
the year-on-year trend within each month (the slope *inside* each panel) at the
same time, something a single overlaid line cannot do.
```{r, fig.height = 3.8}
seasonal_plot(indoor_ts, title = "Indoor sales: monthly subseries")
```
With `style = "season"` every year becomes its own line over the months on a
shared axis, which is handy for spotting an unusual year.
```{r, fig.height = 4}
seasonal_plot(indoor_ts, style = "season",
title = "Indoor sales: one line per year")
```
## Forecasting
`ts_forecast()` is a lightweight, dependency-free forecaster: it decomposes the
series with STL, extrapolates the recent trend, carries the seasonal pattern
forward and returns point forecasts with prediction intervals that widen with
the horizon.
```{r}
fc <- ts_forecast(indoor_ts, h = 18, level = 0.9)
head(fc)
```
Passing an integer horizon straight to `timeseries_plot()` overlays that forecast
on the history: the point forecast continues the line and the shaded ribbon shows
the (growing) 90% prediction interval.
```{r, fig.height = 4}
timeseries_plot(indoor_ts, forecast = 18, level = 0.9,
title = "Indoor sales with an 18-month forecast",
y_lab = "Units")
```
For a fully specified statistical model, fit it yourself (for example with
`forecast::forecast()`) and pass the resulting `time`/`fit`/`lwr`/`upr` columns
to `timeseries_plot(forecast = )` as a data frame.