# User defined ts-functions

## Writing ts-functions

It is straightforward to turn existing functions into functions that can deal with any ts-boxable object.

The `ts_` function is a constructor function for tsbox time series functions. It can be used to wrap any function that works with time series. The default is set to R base `"ts"` class, so wrapping functions for `"ts"` time series (or vectors or matrices) is as simple as:

    ts_rowsums <- ts_(rowSums)
    ts_rowsums(ts_c(mdeaths, fdeaths))

Note that `ts_` returns a function, which can be with or without a name. Let’ have a closer look at how `ts_rowsums` looks like:

    ts_rowsums
    #> function (x, ...)
    #> {
    #>     stopifnot(ts_boxable(x))
    #>     z <- rowSums(ts_ts(x), ...)
    #>     copy_class(z, x)
    #> }

This is how most ts-functions work. They use a specific converter function (here: `ts_ts`) to convert a ts-boxable object to the desired class. They then perform the main operation on the object (here: `rowSums`). Finally they convert the result back to the original class, using `copy_class`.

The resulting function has a `...` argument. You can use it to pass arguments to the underlying functions. E.g.,

    ts_rowsums(ts_c(mdeaths, fdeaths), na.rm = TRUE)

## Functions from external packages

Here is a slightly more complex example, which uses a post processing function:

    ts_prcomp <- ts_(function(x) predict(prcomp(x, scale = TRUE)))
    ts_prcomp(ts_c(mdeaths, fdeaths))

It is easy to make functions from external packages ts-boxable, by wrapping them into `ts_`.

    ts_dygraphs <- ts_(dygraphs::dygraph, class = "xts")
    ts_forecast <- ts_(function(x, ...) forecast::forecast(x, ...)$mean, vectorize = TRUE)
    ts_seas <- ts_(function(x, ...) seasonal::final(seasonal::seas(x, ...)), vectorize = TRUE)

    ts_dygraphs(ts_c(mdeaths, EuStockMarkets))
    ts_forecast(ts_c(mdeaths, fdeaths))
    ts_seas(ts_c(mdeaths, fdeaths))

If you are explicit about the namespace (e.g., `dygraphs::dygraph`), `ts_` recognized the package in use and delivers a meaningful message if the package is not installed.

Note that the `ts_` function deals with the conversion stuff, ‘vectorizes’ the function so that it can be used with multiple time series.

Let’ have another look at `ts_forecast`:

    ts_forecast
    #> function (x, ...)
    #> {
    #>     load_suggested("forecast")
    #>     ff <- function(x, ...) {
    #>         stopifnot(ts_boxable(x))
    #>         z <- (function(x, ...) forecast::forecast(ts_na_omit(x),
    #>             ...)$mean)(ts_ts(x), ...)
    #>         copy_class(z, x)
    #>     }
    #>     ts_apply(x, ff, ...)
    #> }

There three differences to the `ts_rowsum` example: First, the function requires the forecast package. If it is not installed, `load_suggested` will ask the user to do so. Second, the function in use is an anonymous function, `function(x) forecast::forecast(x, ...)$mean`, that also extracts the `$mean` component from the result. Third, the function is ‘vectorized’, using `ts_apply`. This causes the process to be repeated for each time series in the object.