Function out of my package only works after being copied/pasted...Why?

gianmarco

TS Contributor
#1
Hello,
as per title, I am trying to wrap my head around the issue I am experiencing.

I am working on a function out of my 'GmAMisc' package; the function is part of a new version which is currently under construction.

I am testing the new version, and I have hit 'install/reload', and all is ok. But there is a problem with one function: it does not work (i.e., it returns an error) when I try to run it for the first time; but if I copy/paste it in the R console, it works smoothly.

I know that from this description it is not easy to pinpoint the exact cause of the issue; I am just wondering if anyone here have ever experienced anything similar. I am wondering if that could be caused by possible conflict(s) between some functions on which my functions rests, or by conflicting behaviours between my package's dependencies....
What strikes me is the fact that, once the function's code is pasted into R, all works nicely.


Any hint is appreciated.

Best
Gm
 

Dason

Ambassador to the humans
#2
In the future please post the actual error you're receiving.

Are you sure your function is exported?
 

gianmarco

TS Contributor
#4
Thanks @Dason for replying back.
The package (working, if we exclude the windAver() function) is on GitHub.

The issue I was describing is with the abovementioned windAver() function: LINK

I have tried again, making some modifications (e.g., specifying from which dependency some confusing functions are actually coming from, using the operator :: ) but the issue is still there.

If one runs the function using the example I put in the function help documentation, the attached errors crop out. If I select the function's code and paste it into the R console, it works like it is supposed to do.....Needless to say, the code also works if one runs it line by line...

Confused.....

p.s.
part of the error messages are in Italian....sorry
 

Attachments

Last edited:

Dason

Ambassador to the humans
#5
Oh so you mean copying the internals of the function and pasting them directly as if you were running a script? I thought you meant copying the function definition and pasting that and then that fixed it.

Side note - can you make a reproducible example? And paste the code directly instead of using images? Thanks!
 

gianmarco

TS Contributor
#6
Sorry for not being clear, my bad.
I mean that, when you run the function, it does not work. If you copy and paste the whole function into R, and then you re-run the function (will all the need arguments), it works....

Toy dataset
C-like:
# simulate toy data
set.seed(12345)

monthA_speed <- raster(xmn=0,xmx=4,ymn=0,ymx=4,res=1)
monthA_speed[] <- runif(16, 5,15)
plot(monthA_speed, main="month A speed")
text(monthA_speed)

monthB_speed <- raster(xmn=0,xmx=4,ymn=0,ymx=4,res=1)
monthB_speed[] <- runif(16, 10,20)
plot(monthB_speed, main="month B speed")
text(monthB_speed)

monthA_dir <- raster(xmn=0,xmx=4,ymn=0,ymx=4,res=1)
monthA_dir[] <- runif(16, 0,369)
plot(monthA_dir, main="month A dir")
text(monthA_dir)

monthB_dir <- raster(xmn=0,xmx=4,ymn=0,ymx=4,res=1)
monthB_dir[] <- runif(16, 0,369)
plot(monthB_dir, main="month B dir")
text(monthB_dir)
Run the function (first time)
C-like:
# calculate the average wind speed and direction for the two toy datasets
res <- windAver(speed.data= c(monthA_speed, monthB_speed), dir.data= c(monthA_dir, monthB_dir))
It does not work, and the error messages are produced:

C-like:
Error messages:
Error in plot.window(...) : i valori di 'ylim' devono essere finiti
Inoltre: Warning messages:
1: In mean.default(u.comp) :
  argument is not numeric or logical: returning NA
2: In mean.default(v.comp) :
  argument is not numeric or logical: returning NA
3: In mean.default(speed.stack) :
  argument is not numeric or logical: returning NA
4: In min(x) : no non-missing arguments to min; returning Inf
5: In max(x) :
 Show Traceback
 
 Rerun with Debug
 Error in plot.window(...) : i valori di 'ylim' devono essere finiti
I copy and paste the whole function into R:
C-like:
windAver <- function (speed.data, dir.data){
  
  #create a raster stack from the input wind speed rasters
  speed.stack <- raster::stack(speed.data)
  
  #create a raster stack from the input wind direction rasters
  dir.stack <- raster::stack(dir.data)
  
  #build two empty list where we can store the data created by the following loop
  u.comp <- list()
  v.comp <- list()
  
  #calculate the u and v components that will be averaged in a subsequent step;
  #in each list, the first element of the list will store the component derived from the first wind speed raster and from the first wind direction raster;
  #the second element of the list will store the component derived form the second wind speed and from the second wind direction rasters, and so on
  for(i in 1:length(speed.data)){
    u.comp[[i]] <- raster::overlay(speed.stack[[i]], dir.stack[[i]], fun=function(x, y) -x * sin(2 * pi * y / 360) )
    v.comp[[i]] <- raster::overlay(speed.stack[[i]], dir.stack[[i]], fun=function(x, y) -x * cos(2 * pi * y / 360) )
  }
  
  #create raster stacks from the u and v component lists
  u.comp <- raster::stack(u.comp)
  v.comp <- raster::stack(v.comp)
  
  #calculate the average for the u and v components using the raster stacks
  mean.u.comp <- mean(u.comp)
  mean.v.comp <- mean(v.comp)
  
  #uses the averaged u and v components to get an average in degrees
  dir.average <- (atan2(mean.u.comp, mean.v.comp) * 360/2/pi) + 180
  
  #calculate the average wind speed using the wind speed raster stack
  speed.average <- mean(speed.stack)
  
  #plot the wind speed and direction rasters
  raster::plot(speed.average,
               main="Wind speed average",
               cex.main=0.90)
  
  raster::plot(dir.average,
               main="Wind direction average",
               cex.main=0.90)
  
  #create a list for the results
  results <- list("wind.speed.avrg"=speed.average,
                  "wind.dir.avrg"=dir.average)
  
  #export the raster as GTiff files
  raster::writeRaster(results$wind.speed.avrg, "wind_speed_avrg", format="GTiff", overwrite=TRUE)
  raster::writeRaster(results$wind.dir.avrg, "wind_direct_avrg", format="GTiff", overwrite=TRUE)
  
  return(results)
  
}
Upon executing the following again, the functions works:
C-like:
res <- windAver(speed.data= c(monthA_speed, monthB_speed), dir.data= c(monthA_dir, monthB_dir))
 

Dason

Ambassador to the humans
#7
I think the issue is that you're relying on "Depends" to bring the packages you use in instead of Imports. This can make the Namespace a bit harder to anticipate. Using `debug` it looks like the issue is that mean(u.comp) and mean(v.comp) are returning NA inside of your function when called from the package. Apparently it's not picking up that it should be dispatching to the Raster method of mean. This points me to NAMESPACE issues and thus my suggestion to use imports when possible.
 

gianmarco

TS Contributor
#8
Thanks for your comment.
Could you please elaborate a little more on "my suggestion to use imports when possible"? What does it mean using imports from a practical standopoint?

EDIT:
Am I supposed to modify the 'Description' file, and to switch from Depends to Imports?
 

Dason

Ambassador to the humans
#9
Here is the official documentation on declaring dependencies in R: https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Package-Dependencies

Here is a decent explanation of when to use imports/depends: https://stackoverflow.com/questions/8637993/better-explanation-of-when-to-use-imports-depends

Note that you would have to add something like @imports or @importsMethodsFrom - here is a roxygen2 vignette to help with that: https://cran.r-project.org/web/packages/roxygen2/vignettes/namespace.html
 

gianmarco

TS Contributor
#10
Uhmmm....I see....
I will read those documents for sure. What I got from a quick overview is that Imports is "safer" than Depends. Seems ok. But, am I right in understanding that, if I use Imports instead of Depends, I should always indicate within a function of mine to which package a function I rely on belongs to (using :: )?