Electrino
Electrino

Reputation: 2900

Calling an object from a function in an R package?

This is confusing me, so I hope I can explain it well...

I have created an R-package, and within that package I have 3 scripts (toy examples are below). 1 of the scripts generates some data/calculations and the remaining 2 scripts contain different plotting functions. For example, the scripts in my package look something like this...

The 1st script genData.R creates a matrix of values, does a calculation and returns a data frame:

# Matrix Funtion with rows = r and columns = c:
xMat <- function(r, c){
  Mat <- matrix(runif(r*c, 0, 1), nrow=r)
  Mat <- Mat * 10
  colnames(Mat) <- paste0("x", 1:c)
  df <- data.frame(Mat)
  df
}

The remaining scripts are similar to each other, the only difference between them is the type of plot they produce. They both contain a call to xMat()to generate the data and then plot the data using a separate plotting function. The 1st plotting script plot1.R looks like so:

#' @param r no of rows
#' @param c no of cols
#' @import ggplot2
#' @export

xFunc <- function(r,c){
  Val <- xMat(r,c)
  xPlot(Val)
}

xPlot <- function(df){
  myData <- df
  p <- ggplot(myData, aes(x1, x2)) +
    geom_tile(aes(fill = x1))
  p
}

And similarly, the 2nd plotting function plot2.R script looks like so:

#' @param r no of rows
#' @param c no of cols
#' @import ggplot2
#' @import reshape
#' @export

xFunc.1 <- function(r,c){
  Val <- xMat(r,c)
  xPlot.1(Val)
}


xPlot.1 <- function(df){
  myData <- df
  df <-  melt(df)
  p <-ggplot(df, aes(x = df$variable, y = df$value)) + geom_line()
  p
}

What im trying to do is, if, say, I called the function xFunc() first, then it will call xMat() to generate the data etc.... but then afterwards, if I call xFunc.1, I don't want it to call xMat again and have to generate new data.

I want to be able to store the object df created by xMat and then when I call xFunc.1 it just retrieves the object df instead of having to do the data generation/calculations again. I have edited this question to reflect that I cannot store the object df in the global environment. CRAN do not allow modifications to the users environment. I have been experimenting with creating a local environment within the package using new.env(), but I'm not sure how to make this work?

I imagine it might look something like this:

if(xMat has not previously been run){
execute xMat
}else{
If xMat has been run then
retrieve the df object previously created by xMat
}

I hope I explained that clearly.... Any suggestions as to how I would do this?

Upvotes: 0

Views: 66

Answers (1)

David T
David T

Reputation: 2143

I'm assuming you're running these scripts in arbitrary order, and you're not restarting R. You could

if(! exists("myXMatDf")){
    myXMatDf <- xMat(r,c)}

But that gets error-prone if you forget which values of r and c you last used.

If you want to save rerunning xMat even when you've, say, rebooted your machine, you can write to a cache.

if(file.exists("cache/myXMatDf.RData"){
  load("cache/myXMatDf.RData")
} else {
  myXMatDf <- xMat(r,c)
  save(myXMatDf, r, c, file = "cache/myXMatDf.RData"
}

# NOT RUN #

P.S. on exists:

R > y
Error: object 'y' not found
R > exists("y")
[1] FALSE
R > y <- 8
R > y
[1] 8
R > exists("y")
[1] TRUE

exists takes a string. It tests whether there's anything in the environment by that name. Before you run your script the first time, myXMatDf isn't bound - it doesn't have a value. exists("myXMatDf") is FALSE. After you run your script myXMatDf is bound to a data frame. exists("myXMatDf") is TRUE.

Upvotes: 1

Related Questions