Correct way to specifiy optional arguments in R functions
You could also use missing()
to test whether or not the argument y
was supplied:
fooBar <- function(x,y){
if(missing(y)) {
x
} else {
x + y
}
}
fooBar(3,1.5)
# [1] 4.5
fooBar(3)
# [1] 3
Optional parameters in R function
You should not trust on NA
when argument is expected to get value as data.frame
, list
etc. is.na
returns NA check for each element to those data structures. The better option could be to initialize your argument with NULL
and check with is.NULL
. Another option could be to use missing
function on dfInput
argument. Your function definition can be written as:
occInput <- function(fileInput, dfInput = NULL) {
if (is.NULL(dfInput)) occ.dat <- read.csv(file = fileInput)
else occ.dat <- dfInput
#manipulate the data in occ.dat
}
#OR you can just use missing function
occInput <- function(fileInput, dfInput) {
#Perform missing check
if (missing(dfInput)) occ.dat <- read.csv(file = fileInput)
else occ.dat <- dfInput
#manipulate the data in occ.dat
}
Passing in optional arguments to function in r
You can use the ...
argument (documented in ?dots
) to pass down arguments from a calling function. In your case, try this:
library(gbm)
library(ggplot2)
data('diamonds', package = 'ggplot2')
example_function <- function(n.trees = 5, ...){
gbm(formula = price~ ., n.trees = 5, data = diamonds, ...)
}
# Pass in the additional 'shrinkage' argument
example_function(n.trees = 5, shrinkage = 0.02)
## Distribution not specified, assuming gaussian
## gbm(formula = price ~ ., data = diamonds, n.trees = 5, shrinkage = 0.02)
## A gradient boosted model with gaussian loss function.
## 5 iterations were performed.
There were 9 predictors of which 2 had non-zero influence.
Passing in list of optional arguments in R
I think the most straightforward way to handle this kind of pattern is to give the function an extra_args
parameter that accepts an arbitrary list (and defaults to an empty list if you want to ignore it):
foo <- function(data, extra_args = list(), func = mean,
cross_depth = NULL, data_table = FALSE) {
# Do stuff
}
Which allows:
varx <- list("var1", "var2", "var3")
foo(data, varx, func = func, data_table = TRUE, cross_depth = 3)
Passing optional arguments with `...` to multiple functions; control argument matching?
1) Define do.call2
which is like do.call
except that it accepts unnamed arguments as well as named argument in the character vector accepted
which defaults to the formals in the function.
Note that the arguments of mean
do not include na.rm
-- it is slurped up by the dot dot dot argument -- but the mean.default
method does. Also primitive functions do not have formals so the accepted
argument must be specified explicitly for those rather than defaulted.
do.call2 <- function(what, args, accepted = formalArgs(what)) {
ok <- names(args) %in% c("", accepted)
do.call(what, args[ok])
}
# test
dat <- c(NA, 1:5)
meanLog <- function(x, ...){
y <- do.call2("log", list(x, ...), "base")
z <- do.call2("mean.default", list(y, ...))
return(z)
}
meanLog(dat, na.rm = TRUE, base = 2)
## [1] 1.381378
# check
mean(log(dat, base = 2), na.rm = TRUE)
## [1] 1.381378
2) Another possibility is to provide separate arguments for mean and log.
(A variation of that is to use dot dot dot for one of the functions and argument lists for the others. For example nls
in R uses dot dot dot but also uses a control
argument to specify other arguments.)
# test
dat <- c(NA, 1:5)
meanLog <- function(x, logArgs = list(), meanArgs = list()) {
y <- do.call("log", c(list(x), logArgs))
z <- do.call("mean", c(list(y), meanArgs))
return(z)
}
meanLog(dat, logArgs = list(base = 2), meanArgs = list(na.rm = TRUE))
## [1] 1.381378
# check
mean(log(dat, base = 2), na.rm = TRUE)
## [1] 1.381378
How To Pass An Optional Parameter Inside a function of ggplot
First case: ybreak = NULL
is.na(NULL)
Returns:
logical(0)
And therefore (because logical(0) is nothing):
is.na(NULL) == FALSE
Returns:
logical(0)
But if we use is.null
(NULL
is nothing) instead of is.na
(NA
is something (just not a number)) :
is.null(NULL)
Returns:
[1] TRUE
and then:
is.null(NULL) == FALSE
[1] FALSE
Second case: ybreak = seq(70, 500, by = 50)
is.na(seq(70, 500, by = 50))
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
if (is.na(seq(70, 500, by = 50)) == FALSE) print("something")
[1] "something"
Warning message:
In if (is.na(seq(70, 500, by = 50)) == FALSE) print("something") :
the condition has length > 1 and only the first element will be used
But we can use all
to check multiple booleans at once:
if (all(is.na(seq(70, 500, by = 50)) == FALSE)) print("something")
l[1] "something"
R: write function with optional arguments
You can do:
myfunction <- function(space, start_date, end_date, ..., optionalArgument4 = NULL){
args <- c(...)
filters <- paste(unlist(lapply(seq_along(args),
function(i) sprintf("SMALL_filter%s:{$sf%s:'%s'}",
i, i, args[i]))),
collapse = ",")
api_request <- paste0("https://myapi.com/getData?hello",
#NEEDED
"&space={s:'", space,"'}",
"&period={M:{start:'",start_date,"',end:'",end_date,"'}}",
#OPTIONAL
ifelse(filters=="","",sprintf("&filter={%s}",filters)),
ifelse(!is.null(optionalArgument4),
paste0("&segment=",optionalArgument4),"")
)
return(api_request)
}
You will have to name optionalArgument4
when calling the function:
space <- "earth"
start_date <- "2018-10"
end_date <- "2018-11"
optionalArgument1 <- "America"
optionalArgument2 <- "people"
optionalArgument3 <- "size"
optionalArgument4 <- "ocean"
myfunction(space, start_date, end_date, optionalArgument1, optionalArgument4 = optionalArgument4)
# [1] "https://myapi.com/getData?hello&space={s:'earth'}&period={M:{start:'2018-10',end:'2018-11'}}&filter={SMALL_filter1:{$sf1:'America'}}&segment=ocean"
Using optional arguments in R function
My suggestion
I think the | 10
part is causing the issue, and since when logbase
is 10, you get the same whether test evaluates to TRUE
or FALSE
, you can just remove it. I know you said in a comment this isn't working as expected, but it seems to for me - if it`s still not for you, feel free to comment.
fn1 <- function(x, logbase = NULL){
logbase <- ifelse(test = is.null(logbase), yes = 10, no = logbase)
out <- log(x = x, base = logbase)
return(out)
}
fn1(x = 10, logbase = NULL) # 1
fn1(x = 10, logbase = 2) # 3.321928
fn1(x = 10, logbase = exp(1)) # 2.302585
What the issue with your code was
The issue is anything with | 10
will always evaluate to TRUE
. This is because the |
operator will convert the arguments on both sides to logical
, so something like is.null(2) | 10
is equivalent to as.logical(is.null(2)) | as.logical(10)
which evaluates to F | T
which is T
.
To be clear, | 10
is not related to logbase. What you were looking for is presumably | logbase == 10
. This is fine, except when logbase is NULL
, you run into issues because NULL == 10
doesn't evaluate to T
or F
(it's logical(0)
).
You can fix this by using ||
, rather than |
, which would only evaluate logbase == 10
if is.null(logbase)
is FALSE
, because if the first half of a ||
is TRUE
, then it simply returns TRUE
without evaluating the second half.
Related Topics
R - Add Column That Counts Sequentially Within Groups But Repeats for Duplicates
Why Apply() Returns a Transposed Xts Matrix
Why and Where Are \N Newline Characters Getting Introduced to C()
More Than One Value for "Each" Argument in "Rep" Function
Sparklyr: How to Center a Spark Table Based on Column
How to Remove Unicode <U+00A6> from String
Change Colors in Ggpairs Now That Params Is Deprecated
Split Delimited Single Value Character Vector
How to Organize Large R Programs
Hosting and Setting Up Own Shiny Apps Without Shiny Server
Problems Installing the Devtools Package
R Apply Function with Multiple Parameters