如何在 ggplot 函数中传递可选参数
How To Pass An Optional Parameter Inside a function of ggplot
我想将 plot1
函数中的 ybreak
参数设为可选。如果未指定此参数(NULL
条件),那么我只想 return g
ggplot,否则使用自定义 ybreak
。我通过引用类似的答案尝试了以下代码,但它不起作用。
plot1 <- function(df, x, y, ybreak = NULL) {
g <- ggplot(df, aes_string(x = x, y = y))
if (is.na(ybreak) == F) {
g + scale_y_continuous(breaks = ybreak)
}
else {
g
}
}
plot1(mtcars, x = "mpg", y = "disp")
plot1(mtcars, x = "mpg", y = "disp", ybreak = seq(70, 500, by = 50))
> plot1(mtcars, x = "mpg", y = "disp")
Error in if (is.na(ybreak) == F) { : argument is of length zero
> plot1(mtcars, x = "mpg", y = "disp", ybreak = seq(70, 500, by = 50))
Warning message:
In if (is.na(ybreak) == F) { :
the condition has length > 1 and only the first element will be used
第一种情况:ybreak = NULL
is.na(NULL)
Returns:
logical(0)
因此(因为 logical(0) 什么都不是):
is.na(NULL) == FALSE
Returns:
logical(0)
但是如果我们使用 is.null
(NULL
什么都不是)而不是 is.na
(NA
是 什么(只是不是数字)):
is.null(NULL)
Returns:
[1] TRUE
然后:
is.null(NULL) == FALSE
[1] FALSE
第二种情况: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
但我们可以使用 all
一次检查多个布尔值:
if (all(is.na(seq(70, 500, by = 50)) == FALSE)) print("something")
l[1] "something"
注意:请参阅下面的编辑
R 的省略号或三点功能旨在处理可选参数。如果您的函数将有更多可选参数,这可能很有用。在您提供的示例中,按以下方式构造输入参数。
plot1 <- function(df, x, y, ...) {
}
处理 ...
以查找特定变量名可能有点棘手,但使用函数 eval
、substitute
和 alist
可以提供帮助有了这个。添加以下行会将可选参数放入列表中。
plot1 <- function(df, x, y, ...) {
args <- eval(substitute(alist(...)))
inputs <- purrr::map(args, as.list)
}
注意:需要 purrr
包。
要评估所有可选参数以查找特定名称,您可以使用与上述类似的代码。这是完整的例子。
library(ggplot2)
plot1 <- function(df, x, y, ...) {
# eval inputs
args <- eval(substitute(alist(...)))
inputs <- purrr::map(args, as.list)
print(args)
print(inputs)
# define base plot
g <- ggplot(df, aes_string(x = x, y = y)) + geom_point()
# return chart with breaks only if optional arguments are present
# and if ybreaks exists
if (length(inputs) > 0 && !is.na(inputs$ybreak)) {
# rebuild seq
breaks <- inputs$ybreak
new_seq <- seq(breaks[[2]], breaks[[3]], by = breaks$by)
# add to chart
g <- g + scale_y_continuous(breaks = new_seq)
}
# return chart
return(g)
}
如果您有多个可选参数,请将 is.na(inputs$ybreak)
条件嵌套在 length(inputs) > 0
中。由于仅当提交了一个或多个可选参数时才需要评估可选参数。
根据您的功能以及您打算如何使用它,您可以使用更简单的方法,例如:
plot1 <- function(df, x, y, ...) {
args <- list(ybreaks = ..1)
}
但是,对于包或生产代码,以前的方法可能是更好的选择。
有关详细信息,请参阅 Advanced R: Chapter 6 Functions
编辑:
原回复仍然有效。但是,我想建议一种处理可选参数的替代方法。 rlang
包中的函数 list2
和 dots_list
更易于使用,并且可以更好地控制省略号 ...
。例如,plot1
函数将重组为:
plot1 <- function(df, x, y, ...) {
- args <- eval(substitute(alist(...)))
- inputs <- purrr::map(args, as.list)
+ args <- rlang::list2(...)
# evaluate arguments using
# args$my_optional_argument or
# args[["my_optional_argument"]]
}
希望对您有所帮助!
我想将 plot1
函数中的 ybreak
参数设为可选。如果未指定此参数(NULL
条件),那么我只想 return g
ggplot,否则使用自定义 ybreak
。我通过引用类似的答案尝试了以下代码,但它不起作用。
plot1 <- function(df, x, y, ybreak = NULL) {
g <- ggplot(df, aes_string(x = x, y = y))
if (is.na(ybreak) == F) {
g + scale_y_continuous(breaks = ybreak)
}
else {
g
}
}
plot1(mtcars, x = "mpg", y = "disp")
plot1(mtcars, x = "mpg", y = "disp", ybreak = seq(70, 500, by = 50))
> plot1(mtcars, x = "mpg", y = "disp")
Error in if (is.na(ybreak) == F) { : argument is of length zero
> plot1(mtcars, x = "mpg", y = "disp", ybreak = seq(70, 500, by = 50))
Warning message:
In if (is.na(ybreak) == F) { :
the condition has length > 1 and only the first element will be used
第一种情况:ybreak = NULL
is.na(NULL)
Returns:
logical(0)
因此(因为 logical(0) 什么都不是):
is.na(NULL) == FALSE
Returns:
logical(0)
但是如果我们使用 is.null
(NULL
什么都不是)而不是 is.na
(NA
是 什么(只是不是数字)):
is.null(NULL)
Returns:
[1] TRUE
然后:
is.null(NULL) == FALSE
[1] FALSE
第二种情况: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
但我们可以使用 all
一次检查多个布尔值:
if (all(is.na(seq(70, 500, by = 50)) == FALSE)) print("something")
l[1] "something"
注意:请参阅下面的编辑
R 的省略号或三点功能旨在处理可选参数。如果您的函数将有更多可选参数,这可能很有用。在您提供的示例中,按以下方式构造输入参数。
plot1 <- function(df, x, y, ...) {
}
处理 ...
以查找特定变量名可能有点棘手,但使用函数 eval
、substitute
和 alist
可以提供帮助有了这个。添加以下行会将可选参数放入列表中。
plot1 <- function(df, x, y, ...) {
args <- eval(substitute(alist(...)))
inputs <- purrr::map(args, as.list)
}
注意:需要 purrr
包。
要评估所有可选参数以查找特定名称,您可以使用与上述类似的代码。这是完整的例子。
library(ggplot2)
plot1 <- function(df, x, y, ...) {
# eval inputs
args <- eval(substitute(alist(...)))
inputs <- purrr::map(args, as.list)
print(args)
print(inputs)
# define base plot
g <- ggplot(df, aes_string(x = x, y = y)) + geom_point()
# return chart with breaks only if optional arguments are present
# and if ybreaks exists
if (length(inputs) > 0 && !is.na(inputs$ybreak)) {
# rebuild seq
breaks <- inputs$ybreak
new_seq <- seq(breaks[[2]], breaks[[3]], by = breaks$by)
# add to chart
g <- g + scale_y_continuous(breaks = new_seq)
}
# return chart
return(g)
}
如果您有多个可选参数,请将 is.na(inputs$ybreak)
条件嵌套在 length(inputs) > 0
中。由于仅当提交了一个或多个可选参数时才需要评估可选参数。
根据您的功能以及您打算如何使用它,您可以使用更简单的方法,例如:
plot1 <- function(df, x, y, ...) {
args <- list(ybreaks = ..1)
}
但是,对于包或生产代码,以前的方法可能是更好的选择。
有关详细信息,请参阅 Advanced R: Chapter 6 Functions
编辑:
原回复仍然有效。但是,我想建议一种处理可选参数的替代方法。 rlang
包中的函数 list2
和 dots_list
更易于使用,并且可以更好地控制省略号 ...
。例如,plot1
函数将重组为:
plot1 <- function(df, x, y, ...) {
- args <- eval(substitute(alist(...)))
- inputs <- purrr::map(args, as.list)
+ args <- rlang::list2(...)
# evaluate arguments using
# args$my_optional_argument or
# args[["my_optional_argument"]]
}
希望对您有所帮助!