根据列数将可变长度字符串作为美学传递给 ggplot2
Pass a variable-length string as an aesthetic to ggplot2 based on number of columns
我希望能够根据矩阵中的列数构建一个字符串,并将其作为美学传递给 ggplot
。 aes_string()
函数似乎没有涵盖这一点。我想要这个的原因是我正在使用 ggalluvial
包,但复杂性比原则更重要。我的代码如下所示:
library(ggplot2)
library(ggalluvial)
my_alluvial_plot <- function(scores, n_groups = 5) {
score_names <- names(scores)
scr_mat <- data.matrix(scores)
n_cols <- ncol(scores)
# create ntiles of scores so that flow can be seen between groups
ranks <- apply(scr_mat, 2, function(x) {
rk <- dplyr::ntile(x, n_groups)
return(as.factor(rk))
})
to_plot <- data.frame(ranks)
# build the string for the aes() function
a_string <- ""
for (i in 1:n_cols) {
a_string <- paste0(a_string, "axis", i, " = to_plot[, ", i, "],")
}
# remove final comma
a_string <- substr(a_string, 1, nchar(a_string) - 1)
ggplot(to_plot,
aes(eval(a_string))) +
geom_alluvium(aes(fill = to_plot[, n_cols], width = 1/12)) +
geom_stratum(width = 1/12, fill = "black", color = "grey") +
scale_x_continuous(breaks = 1:n_cols, labels = score_names) +
scale_fill_brewer(type = "qual", palette = "Set1")
}
df <- data.frame(col1 = runif(10),
col2 = runif(10),
col3 = rnorm(10),
col4 = rnorm(10))
my_alluvial_plot(df)
这会产生一个空白图并出现以下错误:
Warning: Ignoring unknown aesthetics: width
Error: Discrete value supplied to continuous scale
基本上,我想构建一个可以支持任意数量列的冲积图,因此评估的 ggplot 代码最终会像
ggplot(to_plot,
aes(axis1 = data[, 1], axis2 = data[, 2], axis3 = data[, 3], ...))
但 eval()
或 parse()
都没有产生任何有意义的结果。 aes_string()
产生同样的问题。有没有办法系统地做到这一点?
你不能在像 "axis1 = col1, axis2 = col2"
这样的字符串上 运行 parse()
或 eval()
的原因是 本身就是一个字符串 不是有效的 R 代码。但是整个 ggplot
调用?那是可以解析的!
如果您像这样修改绘图调用,它会很好地生成冲积图:
gg_string <- paste0("ggplot(to_plot,
aes(", a_string, ")) +
geom_alluvium(aes(fill = to_plot[, n_cols], width = 1/12)) +
geom_stratum(width = 1/12, fill = 'black', color = 'grey') +
scale_x_continuous(breaks = 1:n_cols, labels = score_names) +
scale_fill_brewer(type = 'qual', palette = 'Set1')")
eval(parse(text = gg_string))
我希望能够根据矩阵中的列数构建一个字符串,并将其作为美学传递给 ggplot
。 aes_string()
函数似乎没有涵盖这一点。我想要这个的原因是我正在使用 ggalluvial
包,但复杂性比原则更重要。我的代码如下所示:
library(ggplot2)
library(ggalluvial)
my_alluvial_plot <- function(scores, n_groups = 5) {
score_names <- names(scores)
scr_mat <- data.matrix(scores)
n_cols <- ncol(scores)
# create ntiles of scores so that flow can be seen between groups
ranks <- apply(scr_mat, 2, function(x) {
rk <- dplyr::ntile(x, n_groups)
return(as.factor(rk))
})
to_plot <- data.frame(ranks)
# build the string for the aes() function
a_string <- ""
for (i in 1:n_cols) {
a_string <- paste0(a_string, "axis", i, " = to_plot[, ", i, "],")
}
# remove final comma
a_string <- substr(a_string, 1, nchar(a_string) - 1)
ggplot(to_plot,
aes(eval(a_string))) +
geom_alluvium(aes(fill = to_plot[, n_cols], width = 1/12)) +
geom_stratum(width = 1/12, fill = "black", color = "grey") +
scale_x_continuous(breaks = 1:n_cols, labels = score_names) +
scale_fill_brewer(type = "qual", palette = "Set1")
}
df <- data.frame(col1 = runif(10),
col2 = runif(10),
col3 = rnorm(10),
col4 = rnorm(10))
my_alluvial_plot(df)
这会产生一个空白图并出现以下错误:
Warning: Ignoring unknown aesthetics: width
Error: Discrete value supplied to continuous scale
基本上,我想构建一个可以支持任意数量列的冲积图,因此评估的 ggplot 代码最终会像
ggplot(to_plot,
aes(axis1 = data[, 1], axis2 = data[, 2], axis3 = data[, 3], ...))
但 eval()
或 parse()
都没有产生任何有意义的结果。 aes_string()
产生同样的问题。有没有办法系统地做到这一点?
你不能在像 "axis1 = col1, axis2 = col2"
这样的字符串上 运行 parse()
或 eval()
的原因是 本身就是一个字符串 不是有效的 R 代码。但是整个 ggplot
调用?那是可以解析的!
如果您像这样修改绘图调用,它会很好地生成冲积图:
gg_string <- paste0("ggplot(to_plot,
aes(", a_string, ")) +
geom_alluvium(aes(fill = to_plot[, n_cols], width = 1/12)) +
geom_stratum(width = 1/12, fill = 'black', color = 'grey') +
scale_x_continuous(breaks = 1:n_cols, labels = score_names) +
scale_fill_brewer(type = 'qual', palette = 'Set1')")
eval(parse(text = gg_string))