In a package I am working on, I would like to use data from another package (say, "pckg"). That package is imported ("Imports: pckg" in DESCRIPTION and import(pckg) in NAMESPACE). In one of the functions, I have the following:
someFunc <- function() {
data(pckgdata)
foo <- pckgdata$whatever
}
This results in the following error message when checking the package:
someFunc: no visible binding for global variable ‘pckgdata’
someFunc : <anonymous>: no visible binding for global variable
‘pckgdata’
Undefined global functions or variables:
pckgdata
How should I correctly use data sets from other packages in my own package?
Here is the description of the answer from #hrbmstr (see comments to the question). In short: first, create a global variable holding a new environment. Then, load the data into that environment. Then, access the data through the global variable:
.myenv <- new.env(parent=emptyenv())
someFunc <- function() {
data("pckgdata", package="pckg", envir=.myenv)
foo <- .myenv$pckgdata$whatever
}
Related
I've the following Problem:
I'm using the opencpu package to provide my R Package as a web application. In my package I created a RefClass lets call that
.A <- setRefClass(
".A",
fields = c(
id = "integer",
text = "character"
)
)
plus a constructor function:
A <- function(id,text ){return(.A(id,text))}
and on top I wrote a method "toJSON" for the class and also provided an S4 method like this:
.A$methods(
toJSON = function(){
return(sprintf('{\"id\": %s, \"text\": %s}',id,text))
})
setMethod("toJSON", c(".A"),function(x,...){
x$toJSON()
})
So far everthing is fine. When I install the package and run opencpu, I can call the A method without a problem: (POST with parameters e.g.: {id: 123, text: "Hallo World"})
SERVERADRESS/ocpu/library/PACKAGENAME/R/A
But when I want the returned value to be directly converted into JSON I get the following error:
No method for S4 class:.A
A look at the opencpu site, tells that the procedure which is called in this case is:
library(jsonlite)
args <- fromJSON('{"id": 123, "text": "Hallo World"}')
output <- do.call(PKGNAME::A,args)
toJSON(output)
However this runs fine if I run it in a regular R session. But the error becomes reproducable if I change the last line from toJSON(output) to jsonlite::toJSON(output)
Hence I think this might be the problem and I was wundering if I can add my "toJSON" S4 method with signature ".A" to the Namespace of "jsonlite" within my package?
Any Ideas?
Setting default values for R functions is straightforward, e.g.
myfunction = function(x, k=42, c=1){
result = x*x + k - c
return(result)
}
Here, by default k=42, c=1, and x is a required argument.
I'm creating an R package whereby I would like the arguments to be default files. (In this case, these could either be variables loaded via .rda files, or actual text or csv files.)
To provide the path to a file in inst/extdata, the documentation recommends using the following:
http://r-pkgs.had.co.nz/inst.html
For example, to find inst/extdata/mydata.csv, you’d call
system.file("extdata", "mydata.csv", package = "mypackage")
What is the recommended way to create function arguments which default to a certain file?
I think directly linking to the files would be not the best approach, e.g.
do_something_with_data = function(file=system.file("extdata", "mydata.csv", package = "mypackage")){
data.table::fread(file)
...
}
Another approach could be to set all such arguments to NULL, and then use the default arguments if nothing else is used:
do_something_with_data2 = function(file=NULL){
if (is.null(file)){
file = system.file("extdata", "mydata.csv", package = "mypackage")
}
...
}
How do I create a set of R functions that all access the same private variable?
Let's say I want to create readSetting(key) and writeSetting(key,value) functions that both operate on the same hidden list settings. If I try it like so...
local( {
settings <- list()
readSetting <<- function ( key ) settings[[key]]
writeSetting <<- function ( key, value ) settings[[key]] = value
} )
...then readSetting and writeSetting are not visible outside of the local call. If I want them to be visible there, I have to first assign
readSetting <- writeSetting <- NULL
outside the local call. There must be a better way, because my code isn't DRY if I have to say in two different ways which variables are public.
(The context of this work is that I'm developing an R package, and this code will be in an auxiliary file loaded into the main file via source.)
This question is related to How to limit the scope of the variables used in a script? but the answers there do not solve my problem.
You can simulate somthing like that using R6Class package and the following very rough code:
Privates <- R6Class("Privates",
public=list(
readSetting = function(key) {
private$settings[[key]]
},
writeSetting = function(key,value) {
private$settings[[key]] <<- value
}
),
private=list(
settings = list()
)
)
a <- Privates$new()
a$writeSetting("a",4)
a$readSetting("a")
Directly reading o setting the a$setting would not work.
I want to make an R package called my_package with the following with the following behavior:
library(my_package)
my_package::get_username() # should throw error "no username set"
my_package::set_username("john doe")
my_package::get_username() # should print "john doe"
I'm not sure how to do this. I tried with the following inside an R file test.R and using source('test.R') it works. But I don't know what would be the proper way to do this when creating a package.
pkg_env <- new.env()
pkg_env$username <- NULL
set_username <- function(username) {
pkg_env$username <- username
}
get_username <- function() {
if (is.null(pkg_env$username)) {
print("ERROR")
} else {
print(pkg_env$username)
}
}
The easiest way of doing what you want is to use options. For example, in devtools, you can set a variety of options using this technique - package?devtools
If you want to use environments, then you need to create the environment when the package is loaded, using the .onLoad function
I'm struggling to assign a namespace variable inside of a function. Consider this example using the CRAN package "qcc": qcc() generates a plot, but
the display options of that plot are controlled by qcc.options().
When working in global, everything is fine:
library(qcc)
qcc.options(bg.margin="red") # sets margin background colour, i.e.
# qcc:::.qcc.options$bg.margin is "red"
qcc(rnorm(100), type = "xbar.one") # generates a plot with red margin
But when working in the local environment of a function, qcc and qcc.options seem to use the namespace differently:
foo <- function(x){
qcc.options(bg.margin=x)
qcc(rnorm(100), type = "xbar.one")
}
foo("green") # generates a default plot with grey margins
Here is an ugly hack:
foo <- function(x){
old.qcc.options <- get(".qcc.options", asNamespace("qcc"))
assign(".qcc.options", qcc.options(bg.margin=x), asNamespace("qcc"))
res <- qcc(rnorm(100), type = "xbar.one")
assign(".qcc.options", old.qcc.options, asNamespace("qcc"))
invisible(res)
}
foo("green")
Of course, the scoping issues would be better solved by changing qcc.options. You should contact the package maintainer about that.
This is because of where qcc.options stores its .qcc.options variable. Working in global, this is qcc:::.qcc.options, but when you're inside a function, it is storing it in a local variable just called .qcc.options, thus when you try to use plot.qcc (called by qcc) it retrieves options from the global (non-exported) qcc:::.qcc.options rather than the local .qcc.options.
Here's a function that shows what's happening with the options:
bar <- function(x){
pre <- qcc:::.qcc.options
pre.marg <- qcc.options("bg.margin")
qcc.options(bg.margin=x)
post1 <- qcc:::.qcc.options
post2 <- .qcc.options
post.marg <- qcc.options("bg.margin")
qcc(rnorm(100), type = "xbar.one")
list(pre,post1,post2,pre.marg,post.marg)
}
bar('green')
If you look at the results, you'll see that qcc.options creates the local variable and changes its value of bg.margin to "green" but this isn't the object that's subsequently referenced by plot.qcc.
Seems like you should request some code modifications from the package maintainer because this is probably not the best setup.
EDIT: A workaround is to use assignInNamespace to use the local variable to overwrite the global one. (Obviously, this then changes the parameter globally and would affect all subsequent plots unless the parameter is updated.)
foo <- function(x){
qcc.options(bg.margin=x)
assignInNamespace('.qcc.options',.qcc.options,ns='qcc')
qcc(rnorm(100), type = "xbar.one")
}
foo('green')