不能在函数内部对 ggplot 使用分面
Cannot use faceting for ggplot inside a function
我正在尝试在函数中使用 ggplot
,但我无法生成
地块。具体来说,我想确定情节是否
将使用函数调用中的 facet_grid()
。这是我的数据:
mydf <- data.frame(
group = rep(c("g1", "g2"), each = 16, times = 1),
cluster = rep(c("c1", "c2"), each = 8, times = 2),
score1 = c(rnorm(n = 16, mean = 10, sd = 10), rnorm(n = 16, mean = 18, sd = 10)),
score2 = c(rnorm(n = 16, mean = 50, sd = 10), rnorm(n = 16, mean = 33, sd = 10))
)
函数如下:
myFunc <- function(data, group = NULL, group2, var1, var2) {
# So we don't need quotation marks in function call
arguments <- as.list(match.call())
var1 = eval(arguments$var1, data)
var2 = eval(arguments$var2, data)
group2 = eval(arguments$cluster, data)
grouping = eval(arguments$group, data)
# Make this graph if no faceting needed
if (length(grouping) == 0) {
means <- aggregate(cbind(var1, var2) ~ group2, FUN = mean, data = data)
ggplot(data, aes(x = var1, y = var2, color = group2, label = group2)) +
stat_ellipse(type = "norm", show.legend = FALSE, geom = "polygon", alpha = 0.1) +
geom_text(alpha = 0.5, show.legend = FALSE) +
geom_text(data = means, aes(x = var1, y = var2, color = group2))
# Use faceting
} else if (length(grouping) > 0) {
means <- aggregate(cbind(var1, var2) ~ grouping + group2, FUN = mean, data = data)
# Plot
ggplot(data, aes(x = var1, y = var2, color = group2, label = group2)) +
stat_ellipse(type = "norm", show.legend = FALSE, geom = "polygon", alpha = 0.1) +
geom_text(alpha = 0.5, show.legend = FALSE) +
geom_text(data = means, aes(x = var1, y = var2, color = group2)) +
facet_grid(. ~ grouping)
}
}
我是这样调用函数的:
myFunc(data = mydf, group = NULL, group2 = cluster, var1 = score1, var2 = score2)
myFunc(data = mydf, group = group, group2 = cluster, var1 = score1, var2 = score2)
两次调用分别给出以下错误:
# Error 1
Error: Aesthetics must be either length 1 or the same as the data (32): x, y, colour, label
# Error 2
Error in combine_vars(data, params$plot_env, cols, drop = params$drop) :
At least one layer must contain all variables used for facetting
可以通过手动构建绘图获得预期输出:
means <- aggregate(cbind(score1, score2) ~ group + cluster, FUN = mean, data = mydf)
# without facet
ggplot(mydf, aes(x = score1, y = score2, color = cluster, label = cluster)) +
stat_ellipse(type = "norm", show.legend = FALSE, geom = "polygon", alpha = 0.1) +
geom_text(alpha = 0.5, show.legend = FALSE) +
geom_text(data = means, aes(x = score1, y = score2, color = cluster))
# with facet
ggplot(mydf, aes(x = score1, y = score2, color = cluster, label = cluster)) +
stat_ellipse(type = "norm", show.legend = FALSE, geom = "polygon", alpha = 0.1) +
geom_text(alpha = 0.5, show.legend = FALSE) +
geom_text(data = means, aes(x = score1, y = score2, color = cluster)) +
facet_grid(. ~ group)
这是使用和不使用 facet_grid
的基本 stat_ellipse
图。我会让你添加装饰。此处列名保留为字符串,因此使用 aes_string
而不是 aes
,并使用 as.formula
将公式传递给函数。
myFunc <- function(df, var1, var2, group2, group1 = NULL) {
# Make this graph if no faceting needed
if (is.null(group1)) {
means_formula <- as.formula(paste(var1, "+", var2, "~", group2))
means <- aggregate(means_formula, FUN = mean, data = df)
p <- ggplot(df,
aes_string(x = var1, y = var2, color = group2, label = group2)) +
stat_ellipse(type = "norm", show.legend = FALSE,
geom = "polygon", alpha = 0.1)
}else{
means_formula <- as.formula(paste(var1,"+",var2,"~", group2,"+",group1))
means <- aggregate(means_formula, FUN = mean, data = df)
p <- ggplot(df,
aes_string(x = var1, y = var2, color = group2, label = group2)) +
stat_ellipse(type = "norm", show.legend = FALSE,
geom = "polygon", alpha = 0.1) +
facet_grid(as.formula(paste(".~ ",group1)))
}
print(p)
}
myFunc(df = mydf, var1 = "score1", var2 = "score2",
group2 = "cluster", group1 = NULL)
myFunc(df = mydf, var1 = "score1", var2 = "score2",
group2 = "cluster", group1 = "group")
首先,您将 group2
分配给函数范围 cluster
中不存在的变量。替换:group2 = eval(arguments$cluster, data)
为 group2 = eval(arguments$group2, data)
.
其次,您需要一个动态的 facet_grid
公式。当前您传递的 grouping 不是数据集中的实际字段。但是,由于您在函数参数中没有引号,您将需要检索函数参数 group
的字符串文字,这可以通过 deparse(substitute(...))
到 return "group"
.
考虑在其他函数变量列表的顶部附近添加:
grpname = deparse(substitute(group))
然后将 facet_grid
替换为动态 as.formula
字符串连接或 reformulate
:
facet_grid(as.formula(paste0(". ~ ", grpname)))
facet_grid(reformulate(grpname))
当然,所有的都可以动态 运行 带有引用的函数参数,如 @P-robot 所示。
- 使用
aes_
代替aes
- 在
aes_( )
中围绕变量名使用 substitute( )
- 在
facet_grid
中围绕变量名使用 vars({{ }})
参考:Hadley Wickam 的 ggplot2 书:https://ggplot2-book.org/programming.html\
第 19.4.1 节“间接引用变量”
library(ggplot2)
mydf <- data.frame(
group = rep(c("g1", "g2"), each = 16, times = 1),
cluster = rep(c("c1", "c2"), each = 8, times = 2),
score1 = c(rnorm(n = 16, mean = 10, sd = 10), rnorm(n = 16, mean = 18, sd = 10)),
score2 = c(rnorm(n = 16, mean = 50, sd = 10), rnorm(n = 16, mean = 33, sd = 10))
)
myFunc <- function(data, group = group, group2 = cluster, var1 = score1, var2 = score2) {
means <- aggregate(cbind(score1, score2) ~ group + cluster, FUN = mean, data = mydf)
ggplot(data, aes_(x = substitute(var1), y = substitute(var2),
color = substitute(group2), label = substitute(group2))) +
stat_ellipse(type = "norm", show.legend = FALSE, geom = "polygon", alpha = 0.1) +
geom_text(alpha = 0.5, show.legend = FALSE) +
geom_text(data = means, aes_(x = substitute(var1), y = substitute(var2),
color = substitute(group2))) +
facet_grid(cols = vars({{group}}))
}
myFunc(data = mydf, group = group, group2 = cluster, var1 = score1, var2 = score2)
使用 facet_grid:
的 ggplot2 函数的代表
library(ggplot2)
func1 <- function(data, var1, var2) {
ggplot(data, aes_(x = substitute(var1))) +
geom_histogram(bins = 30) +
facet_grid(rows = vars({{var2}}))
}
func1(mtcars, mpg, am)
由 reprex package (v2.0.1)
于 2022-03-26 创建
我正在尝试在函数中使用 ggplot
,但我无法生成
地块。具体来说,我想确定情节是否
将使用函数调用中的 facet_grid()
。这是我的数据:
mydf <- data.frame(
group = rep(c("g1", "g2"), each = 16, times = 1),
cluster = rep(c("c1", "c2"), each = 8, times = 2),
score1 = c(rnorm(n = 16, mean = 10, sd = 10), rnorm(n = 16, mean = 18, sd = 10)),
score2 = c(rnorm(n = 16, mean = 50, sd = 10), rnorm(n = 16, mean = 33, sd = 10))
)
函数如下:
myFunc <- function(data, group = NULL, group2, var1, var2) {
# So we don't need quotation marks in function call
arguments <- as.list(match.call())
var1 = eval(arguments$var1, data)
var2 = eval(arguments$var2, data)
group2 = eval(arguments$cluster, data)
grouping = eval(arguments$group, data)
# Make this graph if no faceting needed
if (length(grouping) == 0) {
means <- aggregate(cbind(var1, var2) ~ group2, FUN = mean, data = data)
ggplot(data, aes(x = var1, y = var2, color = group2, label = group2)) +
stat_ellipse(type = "norm", show.legend = FALSE, geom = "polygon", alpha = 0.1) +
geom_text(alpha = 0.5, show.legend = FALSE) +
geom_text(data = means, aes(x = var1, y = var2, color = group2))
# Use faceting
} else if (length(grouping) > 0) {
means <- aggregate(cbind(var1, var2) ~ grouping + group2, FUN = mean, data = data)
# Plot
ggplot(data, aes(x = var1, y = var2, color = group2, label = group2)) +
stat_ellipse(type = "norm", show.legend = FALSE, geom = "polygon", alpha = 0.1) +
geom_text(alpha = 0.5, show.legend = FALSE) +
geom_text(data = means, aes(x = var1, y = var2, color = group2)) +
facet_grid(. ~ grouping)
}
}
我是这样调用函数的:
myFunc(data = mydf, group = NULL, group2 = cluster, var1 = score1, var2 = score2)
myFunc(data = mydf, group = group, group2 = cluster, var1 = score1, var2 = score2)
两次调用分别给出以下错误:
# Error 1
Error: Aesthetics must be either length 1 or the same as the data (32): x, y, colour, label
# Error 2
Error in combine_vars(data, params$plot_env, cols, drop = params$drop) :
At least one layer must contain all variables used for facetting
可以通过手动构建绘图获得预期输出:
means <- aggregate(cbind(score1, score2) ~ group + cluster, FUN = mean, data = mydf)
# without facet
ggplot(mydf, aes(x = score1, y = score2, color = cluster, label = cluster)) +
stat_ellipse(type = "norm", show.legend = FALSE, geom = "polygon", alpha = 0.1) +
geom_text(alpha = 0.5, show.legend = FALSE) +
geom_text(data = means, aes(x = score1, y = score2, color = cluster))
# with facet
ggplot(mydf, aes(x = score1, y = score2, color = cluster, label = cluster)) +
stat_ellipse(type = "norm", show.legend = FALSE, geom = "polygon", alpha = 0.1) +
geom_text(alpha = 0.5, show.legend = FALSE) +
geom_text(data = means, aes(x = score1, y = score2, color = cluster)) +
facet_grid(. ~ group)
这是使用和不使用 facet_grid
的基本 stat_ellipse
图。我会让你添加装饰。此处列名保留为字符串,因此使用 aes_string
而不是 aes
,并使用 as.formula
将公式传递给函数。
myFunc <- function(df, var1, var2, group2, group1 = NULL) {
# Make this graph if no faceting needed
if (is.null(group1)) {
means_formula <- as.formula(paste(var1, "+", var2, "~", group2))
means <- aggregate(means_formula, FUN = mean, data = df)
p <- ggplot(df,
aes_string(x = var1, y = var2, color = group2, label = group2)) +
stat_ellipse(type = "norm", show.legend = FALSE,
geom = "polygon", alpha = 0.1)
}else{
means_formula <- as.formula(paste(var1,"+",var2,"~", group2,"+",group1))
means <- aggregate(means_formula, FUN = mean, data = df)
p <- ggplot(df,
aes_string(x = var1, y = var2, color = group2, label = group2)) +
stat_ellipse(type = "norm", show.legend = FALSE,
geom = "polygon", alpha = 0.1) +
facet_grid(as.formula(paste(".~ ",group1)))
}
print(p)
}
myFunc(df = mydf, var1 = "score1", var2 = "score2",
group2 = "cluster", group1 = NULL)
myFunc(df = mydf, var1 = "score1", var2 = "score2",
group2 = "cluster", group1 = "group")
首先,您将 group2
分配给函数范围 cluster
中不存在的变量。替换:group2 = eval(arguments$cluster, data)
为 group2 = eval(arguments$group2, data)
.
其次,您需要一个动态的 facet_grid
公式。当前您传递的 grouping 不是数据集中的实际字段。但是,由于您在函数参数中没有引号,您将需要检索函数参数 group
的字符串文字,这可以通过 deparse(substitute(...))
到 return "group"
.
考虑在其他函数变量列表的顶部附近添加:
grpname = deparse(substitute(group))
然后将 facet_grid
替换为动态 as.formula
字符串连接或 reformulate
:
facet_grid(as.formula(paste0(". ~ ", grpname)))
facet_grid(reformulate(grpname))
当然,所有的都可以动态 运行 带有引用的函数参数,如 @P-robot 所示。
- 使用
aes_
代替aes
- 在
aes_( )
中围绕变量名使用 - 在
facet_grid
中围绕变量名使用
substitute( )
vars({{ }})
参考:Hadley Wickam 的 ggplot2 书:https://ggplot2-book.org/programming.html\ 第 19.4.1 节“间接引用变量”
library(ggplot2)
mydf <- data.frame(
group = rep(c("g1", "g2"), each = 16, times = 1),
cluster = rep(c("c1", "c2"), each = 8, times = 2),
score1 = c(rnorm(n = 16, mean = 10, sd = 10), rnorm(n = 16, mean = 18, sd = 10)),
score2 = c(rnorm(n = 16, mean = 50, sd = 10), rnorm(n = 16, mean = 33, sd = 10))
)
myFunc <- function(data, group = group, group2 = cluster, var1 = score1, var2 = score2) {
means <- aggregate(cbind(score1, score2) ~ group + cluster, FUN = mean, data = mydf)
ggplot(data, aes_(x = substitute(var1), y = substitute(var2),
color = substitute(group2), label = substitute(group2))) +
stat_ellipse(type = "norm", show.legend = FALSE, geom = "polygon", alpha = 0.1) +
geom_text(alpha = 0.5, show.legend = FALSE) +
geom_text(data = means, aes_(x = substitute(var1), y = substitute(var2),
color = substitute(group2))) +
facet_grid(cols = vars({{group}}))
}
myFunc(data = mydf, group = group, group2 = cluster, var1 = score1, var2 = score2)
使用 facet_grid:
的 ggplot2 函数的代表library(ggplot2)
func1 <- function(data, var1, var2) {
ggplot(data, aes_(x = substitute(var1))) +
geom_histogram(bins = 30) +
facet_grid(rows = vars({{var2}}))
}
func1(mtcars, mpg, am)
由 reprex package (v2.0.1)
于 2022-03-26 创建