3

I am working on a package which has a function that relies on dplyr among many other packages. As suggested by H. Wickham in his R Packages book, I am including all the necessary packages under Imports in the Description file.

Imports:
  apaTables,
  data.table,
  dplyr,
  magrittr,
  plyr,
  rlang,
  sjstats,
  stats

And then using namespace in the function body (the details of the function are unnecessary here; all I want to emphasize is that I am using the recommended packagename::fun() format recommended by Hadley in his book):

#'
#' @title Confidence intervals for Partial Eta Squared
#' @name partialeta_sq_ci
#' @author Indrajeet Patil
#'
#' @param lm_object stats::lm linear model object
#' @param conf.level Level of confidence for the confidence interval
#' @importFrom magrittr %>%
#' @export

partialeta_sq_ci <- function(lm_object, conf.level = 0.95) {
  # get the linear model object and turn it into a matrix and turn row names into a variable called "effect"
  # compute partial eta-squared for each effect
  # add additional columns containing data and formula that was used to create these effects

  x <-
    dplyr::left_join(
      # details from the anova results
      x = data.table::setDT(x = as.data.frame(as.matrix(
        stats::anova(object = lm_object)
      )),
      keep.rownames = "effect"),
      # other information about the results (data and formula used, etc.)
      y = data.table::setDT(x = as.data.frame(
        cbind(
          "effsize" = sjstats::eta_sq(
            model = stats::anova(object = lm_object),
            partial = TRUE
          ),
          "data" = as.character(lm_object$call[3]),
          "formula" = as.character(lm_object$call[2])
        )
      ),
      keep.rownames = "effect"),
      # merge the two preceding pieces of information by the common element of Effect
      by = "effect"
    )
  # create a new column for residual degrees of freedom
  x$df2 <- x$Df[x$effect == "Residuals"]
  # remove sum of squares columns since they will not be useful
  x <-
    x %>%
    dplyr::select(.data = .,
                  -c(base::grep(pattern = "Sq", x = names(x))))
  # remove NAs, which would remove the row containing Residuals (redundant at this point)
  x <- na.omit(x)
  # rename to something more meaningful and tidy
  x <- plyr::rename(x = x,
                    replace = c("Df" = "df1",
                                "F value" = "F.value"))
  # rearrange the columns
  x <-
    x[, c("F.value",
          "df1",
          "df2",
          "effect",
          "effsize",
          "Pr(>F)",
          "data",
          "formula")]
  # convert the effect into a factor
  x$effect <- as.factor(x$effect)
  # for each type of effect, compute partial eta-squared confidence intervals, which would return a list
  ci_df <-
    plyr::dlply(
      .data = x,
      .variables = .(effect),
      .fun = function(data)
        apaTables::get.ci.partial.eta.squared(
          F.value = data$F.value,
          df1 = data$df1,
          df2 = data$df2,
          conf.level = conf.level
        )
    )
  # get elements from the effect size confidence intervals list into a neat dataframe
  ci_df <-
    plyr::ldply(
      .data = ci_df,
      .fun = function(x)
        cbind("LL" = x[[1]],
              "UL" = x[[2]])
    )
  # merge the dataframe containing effect sizes with the dataframe containing rest of the information
  effsize_ci <- base::merge(x = x,
                            y = ci_df,
                            by = "effect")
  # returning the final dataframe
  return(effsize_ci)

}

But when I build the package and use the function, it gives me the following error-

Error in x %>% dplyr::select(.data = ., -c(base::grep(pattern = "Sq",  : 
  could not find function "%>%"

What am I doing wrong?

P.S. In case you need more details, GitHub repository: https://github.com/IndrajeetPatil/ipmisc Function in question: https://github.com/IndrajeetPatil/ipmisc/blob/master/R/partialeta_sq_ci.R Description file: https://github.com/IndrajeetPatil/ipmisc/blob/master/DESCRIPTION

Indrajeet Patil
  • 4,673
  • 2
  • 20
  • 51
  • 2
    you are not importing the pipe operator `%>%`. I'd suggest adding the @importFrom tag for this particular case – RolandASc Feb 07 '18 at 16:28
  • 1
    @RolandASc Shouldn't adding `magrittr` to `Imports` in the `Description` file automatically take care of this? At any rate, I did add `#' @importFrom magrittr %>%` call to the function and I still get the same error. The error disappears only if I call `library(dplyr)`, but that's a big no-no for a function in R script inside a package. So not sure what I should do to get rid of this error. – Indrajeet Patil Feb 07 '18 at 16:56
  • 1
    Roxygen doesn‘t interact much with the DESCRIPTION file. To get imports into your NAMESPACE, you need to have them somewhere in tags. Did you re-run ‚roxygenize()‘ after adding the ‚@importFrom‘? Note that the pipe exists in ‚dplyr‘ as well, so if that‘s all you want from ‚magrittr‘, you could even drop that package – RolandASc Feb 07 '18 at 17:45
  • Huh, didn't know that! Okay, here is what's happening now: If I open the R package project in question in `Rstudio` and `roxygenize()`, the function works. But if I quit and re-enter the project and then use the function from the package *without* running `roxygenize()` first, it again gives the same error. I'm guessing I am missing some key functionality regarding how `roxygen2` is supposed to operate in a package environment. – Indrajeet Patil Feb 07 '18 at 19:53
  • Turns out this was the issue: https://stackoverflow.com/questions/29981439/rstudio-building-package-with-roxygen2-not-producing-namespace-file The NAMESPACE file that is created by default doesn't contain anything created by `roxygen2` and needs to be deleted and recreated. Not sure why this is so, but when I do that things start working again. – Indrajeet Patil Feb 07 '18 at 20:34
  • @RolandASc Is it possible for you to mark this as answered or duplicated so that this thread is closed? – Indrajeet Patil Feb 10 '18 at 16:52

2 Answers2

2

Summarizing to close, there were a few issues here:

  • using packagename::fun() is a good choice, but doesn't work well for operators. Especially with the pipe (%>%), using e.g. a function instead, would defeat it's purpose.

  • @importFrom tags are preferable to @import, as this is more narrow and explicit. Both of these affect the NAMESPACE file upon calling roxygen2::roxygenize(). Note however, that roxygen does not mess with user-defined NAMESPACE files, as it is often the case that people would rather take care of it manually themselves (e.g. when a package provides S3 classes and/or methods), and an overwrite by roxygen would then need to be undone. Deleting an existing NAMESPACE file would let roxygen re-create it. Roxygen typically adds a line to the NAMESPACE file to recognize whether it should update it or not:

    # Generated by roxygen2: do not edit by hand

  • The dependencies in the DESCRIPTION file are neither modified by roxygen, nor does roxygen add them to the NAMESPACE (note that this would else result in full package imports, which we would rather avoid through @importFrom). The DESCRIPTION file needs to be taken care of manually, making sure that the Imports: section covers all the packages used via the NAMESPACE, i.e. through @import and @importFrom, as well as via packagename::fun()

RolandASc
  • 3,863
  • 1
  • 11
  • 30
0

I'm solve this using the following in my DESCRIPTION file:

Depends: tidyverse, rlang

This load magrittr.

Alien
  • 116
  • 8