rfunctionvignettetsibble

In R, the same code cannot be knit out in package Vignette file. "list" object cannot be coerced to type integer


This question is about generate_msts() function in package GRATIS.

I add some new stuff (make the function has options to transform its output into a lovely tsibble format or keep the original ‘list’ format) and prepare update to CRAN.

New code add as below (detail of the codes with example shown at the bottom of the question)

I wonder should I get tsibble a index? But the generated data seems like do not have a index?

  output <- if (output_format == "list") {
    res                                    #this is output name defined before
  } else if (output_format == "tsibble") {
    as_tsibble(res)
  }
  return(output)
}

And as a guidance, I update the corresponding example for this function in Vignette. Then things become wired.

If I did not save the generated time series output (e.g. x <- my_function()), the vignette cannot knit out. (However, I can use this function directly in an independent normal RMD file)

Use this code directly can show output inside RStudio, but cannot be knit out.

my_function(seasonal.periods = c(7, 365), n = 800, nComp = 2,output_format="tsibble")

enter image description here

Error in Fun(X[[i]],...): 'list' object cannot be coerced to type 'integer' Calls: <Anonymous>... 
as.data.frame -> head  -> head.data.frame -> lappy -> FUN Execution halted.

But, this works fine. It can knit out the vignette and shows head of tsibble.

x <- my_function(seasonal.periods = c(7, 365), n = 800, nComp = 2,output_format="tsibble")
head(x)

However, this is very inconvenience to save it each time before you can use it. I wonder if this is because there is any default setting I used in package or vignette does not change? Or there is some extra step I need to do after I change the function inside R package? Or even the if else content I add need to be improved?

I have tried devtools::document("C:/Users/mreal/Documents/GitHub/package_name");devtools::install("C:/Users/mreal/Documents/GitHub/package_name") to update the re-build function. But this still does not help vignette.

I also tried rm(list=ls()) in console. It does not work as well

Code I used in vignette is as below

Github link:

https://github.com/BocongZhao823/gratis/blob/master/vignettes/QuickStart.Rmd

---
title: "Introduction to gratis"
author: "Bocong Zhao"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Introduction to gratis}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

{r initial, echo = FALSE, cache = FALSE, results = 'hide'}
library(knitr)
opts_chunk$set(
  warning = FALSE, message = FALSE, echo = TRUE,
  fig.width = 7, fig.height = 6, fig.align = 'centre',
  comment = "#>"
)
original <- options("tibble.print_min")
options(tibble.print_min = 5)
# <---- Do stuff with changed option, e.g. print some tibbles ----> 
options(tibble.print_min = original)


{r, message=FALSE, include = FALSE}
library(forecast)
library(tsibble)

{r setup}
# load package
library(gratis)

## Generate mutiple seasonal time series

Time series can exhibit multiple seasonal pattern of different length, especially when series observed at a high frequency such as daily or hourly data.

We use function **generate_msts()** to generate mutiple seasonal time series.

**Definitions**

Here are the definitions of parameter settings in function generate_msts():

|parameter settings | Definition|
|:----|:-----|
|seasonal.periods | a vector of seasonal periods of the time series to be generated|
|nComp|number of mixing components when simulating time series using MAR models|
|n    |length of the generated time series|

**Example**

Suppose we want to use MAR model to generate a time series with **2** mixing components and the length **800** from random parameter spaces. Particularly, this time series has two seasonal periods **7** and **365**.

{r fig.height = 6, fig.width = 7}
# Generate mutiple seasonal time series with 'tsibble' output format
x <- generate_msts(seasonal.periods = c(7, 365), n = 800, nComp = 2,output_format="tsibble")
head(x)

**Plot time series**

{r fig.height = 6, fig.width = 7}
# Generate mutiple seasonal time series with 'list' output format
x <- generate_msts(seasonal.periods = c(7, 365), n = 800, nComp = 2,output_format="list")
autoplot(x)

(generated.R file) The R code used inside a package is as below

** Github link**

https://github.com/BocongZhao823/gratis/blob/master/R/generate_ts.R

#' Generate mutiple seasonal time series from random parameter spaces of the mixture autoregressive (MAR) models.
#'
#' Generate mutiple seasonal time series from random parameter spaces of the mixture autoregressive (MAR) models.
#' @param seasonal.periods a vector of seasonal periods of the time series to be generated.
#' @param n length of the generated time series.
#' @param nComp number of mixing components when simulating time series using MAR models.
#' @param output_format An optional argument which allows to choose output format between "list" and "tsibble"
#' @return a time series with multiple seasonal periods.
#' @export
#' @examples
#' x <- generate_msts(seasonal.periods = c(7, 365), n = 800, nComp = 2, output_format= "list")
#' forecast::autoplot(x)
generate_msts <- function(seasonal.periods = c(7, 365), n = 800, nComp = NULL,output_format="list") {
  x.list <- map(seasonal.periods, function(p) {
    generate_ts(n.ts = 1, freq = p, n = n, nComp = nComp)$N1$x
  })
  names(x.list) <- paste0("Season", seasonal.periods)
  x.list[1:(length(x.list) - 1)] <- lapply(x.list[1:(length(x.list) - 1)], function(x) {
    x - trendcycle(stl(x, "per"))
  })
  weights <- msts_weights(length(seasonal.periods))
  res <- as_tibble(scale(x.list %>% bind_cols())[, ]) %>%
    mapply("*", ., weights) %>%
    as_tibble() %>%
    mutate(x = rowSums(.)) %>%
    select(x) %>%
    msts(seasonal.periods = seasonal.periods)
  # New content
  output <- if (output_format == "list") {
    res
  } else if (output_format == "tsibble") {
    as_tsibble(res)
  }
  return(output)
}

# ===========================================================================
# Simulated weights for the simulation of msts
# ===========================================================================
msts_weights <- function(n.periods) {
  gamma <- runif(n.periods, 0)
  weights <- gamma / sum(gamma)
  return(weights)
}

Solution

  • I tried to run this for you - my first guess was a NAMESPACE problem. But it seems also related to the generate_msts() function.

    I really don't think this has to do with first saving it to a variable x.

    Here are my findings:

    DOES NOT WORK:

    x <- generate_msts(seasonal.periods = c(7, 365), n = 800, nComp = 2,output_format="tsibble")
    
    x
    

    DOES NOT WORK:

    print(generate_msts(seasonal.periods = c(7, 365), n = 800, nComp = 2,output_format="tsibble"))
    

    DOES NOT WORK:

    x <- generate_msts(seasonal.periods = c(7, 365), n = 800, nComp = 2,output_format="tsibble")
    
    print(x)
    

    WORKS:

     head(generate_msts(seasonal.periods = c(7, 365), n = 800, nComp = 2,output_format="tsibble"))
    

    In the failure cases it is always the same error message as for you:

    Error: processing vignette 'QuickStart.Rmd' failed with diagnostics: 'list' object cannot be coerced to type 'integer'

    So since head(), str(), class() always worked for me and only print() did not work, I am assuming it is a problem with the print function. So your workaround with saving it into variable x only worked fine, because you did not call the print function.

    Also important the problem only occurred for me when using generate_msts() inside Rmarkdown. As I explain later this seems reasonable, since printing in knitr is different from printing on the console.

    When I alter your generate_msts() and rebuild the package:

    output <- if (output_format == "list") {
        res
      } else if (output_format == "tsibble") {
        tsibble(date = as.Date("2017-01-01") + 0:9,value = rnorm(10))
      }
    

    The Rmarkdown suddenly runs without an error.

    My guess would be it is a problem with the print() for your specific data in interaction with knitr.

    Printing in knitr seems to be different from printing on the console (might be why it works without rmarkdown)

    Here is a nice link about custom print methods and knitr: https://cran.r-project.org/web/packages/knitr/vignettes/knit_print.html

    Before knitr v1.6, printing objects in R code chunks basically emulates the R console.

    I could imagine the S3 method for knit_print from the tsibble package (which just uses all the printing methods from tibble?) might just not work properly for your specific dataset (I mean it worked for the tsibble I created with tsibble() ). But just a (wild?) guess...the error and behavior overall is really strange ...

    Edit: Here is also the R Markdown callstack for the error:

     1. ├─base::print(x)
      2. └─tibble:::print.tbl(x)
      3.   ├─cli::cat_line(format(x, ..., n = n, width = width, n_extra = n_extra))
      4.   │ └─base::paste0(..., collapse = "\n")
      5.   ├─base::format(x, ..., n = n, width = width, n_extra = n_extra)
      6.   └─tsibble:::format.tbl_ts(x, ..., n = n, width = width, n_extra = n_extra)
      7.     ├─base::format(trunc_mat(x, n = n, width = width, n_extra = n_extra))
      8.     └─tibble::trunc_mat(x, n = n, width = width, n_extra = n_extra)
      9.       ├─base::as.data.frame(head(x, n))
     10.       ├─utils::head(x, n)
     11.       └─utils:::head.data.frame(x, n)
     12.         └─base::lapply(...)
     13.           └─utils:::FUN(X[[i]], ...)
    

    Should be similar for you, but if you want to get this on your own, you have to the following commands to your rmarkdown document

    options(rlang_trace_top_env = rlang::current_env())
    options(error = function() {
      sink()
      print(rlang::trace_back(bottom = sys.frame(-1)), simplify = "none")
    })
    

    But as you can see in the callstack, the error is caused by base::print(x), which calls the S3 method tibble:::print.tbl(x), this method then internally calls tsibble:::format.tbl_ts, which calls tibble::trunc_mat, ... and somewhere inside the error is caused.

    Ok ... I followed this further down the road and ... what in the end messes inside these function calls, are the knitr options you set in the beginning.

    You write at the beginning of your rmarkdown:

    original <- options("tibble.print_min")
    options(tibble.print_min = 5)
    
    # <---- Do stuff with changed option, e.g. print some tibbles ----> 
    options(tibble.print_min = original)
    

    Change this to just:

    options(tibble.print_min = 5)
    

    Should work then.