由于我将需要在R中进行很多不同的绘制,因此我试图在准备数据时增加一些逻辑(添加与美观相对应的列名),并在绘制本身中减少逻辑。
请考虑以下默认虹膜图:
library(ggplot2)
library(data.table)
scatter <- ggplot(data=iris, aes(x = Sepal.Length, y = Sepal.Width))
scatter + geom_point(aes(color=Species, shape=Species))
现在,我制作了一个修改后的虹膜数据,其列名与所需的美感相匹配:
iris2 <- as.data.table(iris)
iris2 <- iris2[,.(x=Sepal.Length, y=Sepal.Width, color=Species,
shape=Species)]
我想以某种方式来绘制函数,使其基本上只稍微动态地构建以下命令,因此您可以使用数据中提供的所有美感。
ggplot(data, aes(x=x, y=y)) + geom_point(aes(color=color, shape=shape))
自从我阅读了有关非标准评估,表达式和引用的所有内容以来,已经很长时间了,并且我注意到rlang和quosure(cheatsheet)有了相当大的发展。 [这个]问题很有帮助,但并不能解决我想从数据中推断出美学的事实。
最后,我尝试了很多东西,并查看了aes内部。在那里,我看到了:
exprs <- rlang::enquos(x = x, y = y, ...)
我认为这就是我进行所有尝试的原因:
ggplot(iris2, aes(x=x, y=y)) +
geom_point(aes(rlang::quo(expr(color=color))))
由于aes试图“启用”我的抵押,因此无法解决问题。
问题,是否有任何方法可以根据数据内容以动态方式向aes提供参数(因此您事先不知道需要哪种美学?
如果我的问题还不够清楚,最后我做了一件有用的事情,只有我感觉这完全没有必要,因为我不知道/不知道正确的做事方法。所以下面的东西有效,并且是我的想法,但是我的想法不喜欢我必须修改aes:
下面的代码块是独立的,无需上面的代码块即可执行。
library(data.table)
library(ggplot2)
library(rlang)
iris2 <- as.data.table(iris)
iris2 <- iris2[,.(x=Sepal.Length, y=Sepal.Width, color=Species, shape=Species)]
myaes <- function (x, y, myquo=NULL, ...) {
exprs <- rlang::enquos(x = x, y = y, ...)
exprs <- c(exprs, myquo)
is_missing <- vapply(exprs, rlang::quo_is_missing, logical(1))
aes <- ggplot2:::new_aes(exprs[!is_missing], env = parent.frame())
ggplot2:::rename_aes(aes)
}
generalPlot <- function(data, f=geom_point,
knownaes=c('color'=expr(color), 'shape'=expr(shape))){
myquo <- list()
for(i in names(knownaes)){
if(i %in% names(data)){
l <- list(rlang::quo(!!knownaes[[i]]))
names(l) <- i
myquo <- c(myquo, l)
}
}
ggplot(data, aes(x=x, y=y)) +
f(myaes(myquo=myquo))
}
generalPlot(iris2[,.(x, y, color)])
generalPlot(iris2[,.(x, y, color, shape)])
答案 0 :(得分:1)
因此,如果您的数据作为“颜色”或“形状”列,您只想将其映射到颜色或形状美观?我认为更简单的方法是
generalPlot <- function(data, f=geom_point, knownaes=c('color', 'shape')) {
match_aes <- intersect(names(data), knownaes)
my_aes_list <- purrr::set_names(purrr::map(match_aes, rlang::sym), match_aes)
my_aes <- rlang::eval_tidy(quo(aes(!!!my_aes_list)))
ggplot(data, aes(x=x, y=y)) +
f(mapping=my_aes)
}
那你就可以做
generalPlot(iris2[,.(x, y)])
generalPlot(iris2[,.(x, y, color)])
generalPlot(iris2[,.(x, y, color, shape)])
,并且不需要其他myaes
功能。
我不得不使用eval_tidy
感到很惊讶,但是由于某些原因,您似乎无法将!!!
与aes()
一起使用。
x <- list(color=sym("color"))
ggplot(iris2, aes(x,y)) + geom_point(aes(!!!x))
# Error: Can't use `!!!` at top level
(已通过ggplot2_3.1.0
测试)
答案 1 :(得分:1)
您可以使用此自定义函数来解析输入数据名称,并生成一个aes
文本字符串,该字符串将传递给eval()
。
generateAES <- function(foo) {
eval(parse(text = paste0("aes(",
paste(
lapply(foo, function(i) paste(i, "=", i)),
collapse = ","),
")"
)))
}
您可以将其用于:
ggplot(iris2, generateAES(colnames(iris2))) +
geom_point()
或使用管道:
library(magrittr)
iris2 %>%
ggplot(generateAES(colnames(.))) +
geom_point()
generateAES
的输出为aes
,如:
Aesthetic mapping:
* `x` -> `x`
* `y` -> `y`
* `colour` -> `color`
* `shape` -> `shape`
从文本字符串"aes(x = x,y = y,color = color,shape = shape)"