我意识到很多人会遇到使用 for 循环生成此图而不是首选 R 方法来融合数据的问题,但考虑到我已经很接近了,请幽默一下。
我有多个数据集,我想循环这些数据集并生成一个代表所有数据集的列的图。到目前为止我已经做到了:
singleden <- function (){
line_list <- vector("list", length(paths))
for (i in (1:length(paths))) {
# dirname <- dirname(paths[i])
# len <- nchar(dirname)
# corename <- (substr(dirname, 97, len))
line_list[[i]] <- geom_line(data = datas[[i]], aes(x = year, y = density, group =1),
stat="identity", color = color[i])
}
label_list <- vector("list", length(paths))
for (i in (1:length(paths))) {
name <- basename(dirname(paths[i]))
# directname <- dirname(paths[i])
# #print(paths[i])
# #print(directname)
#
# name <- (substr(directname, 97, len))
label_list[[i]] <- geom_label_repel(data = datas[[i]] %>% filter (year == min(year)),
aes(label = name, y = density, x = year), color = color[i])
}
ggplot() + line_list + label_list
}
线条绘制正确,一切都很好
但是,添加 label_list 会生成仅包含列表最后一个值的标签。不知何故,我的两个列表在用 ggplot 绘制时似乎没有对齐。列表本身存储了打印时我期望的正确数字和值
我尝试对行和标签使用单个 for 循环,遇到了同样的问题。想知道我是否需要以某种方式将列表配对在一起,但不清楚我该如何做到这一点
这个问题是由于惰性评估造成的,并且存在很多问题,人们在使用
for
循环时遇到同样的问题。参见例如“for”循环仅添加最终的 ggplot 层以解释问题。
在您的情况下,通过将
label = name
移动到 aes()
之外,很可能可以避免此问题。
使用基于
gapminder
数据集的最小可重现示例:
library(gapminder)
library(ggplot2)
library(ggrepel)
library(dplyr, warn=FALSE)
set.seed(123)
datas <- gapminder |>
filter(country %in% sample(levels(gapminder$country), 5)) |>
rename(density = lifeExp) |>
split(~country, drop = TRUE)
color <- gapminder::country_colors[names(datas)]
paths <- file.path(names(datas), names(datas))
singleden <- function() {
line_list <- vector("list", length(paths))
for (i in (1:length(paths))) {
line_list[[i]] <- geom_line(
data = datas[[i]], aes(x = year, y = density, group = 1),
stat = "identity", color = color[i]
)
}
label_list <- vector("list", length(paths))
for (i in (1:length(paths))) {
name <- basename(dirname(paths[i]))
label_list[[i]] <- geom_label_repel(
data = datas[[i]] %>% filter(year == min(year)),
aes(y = density, x = year), color = color[i], label = name
)
}
ggplot() + line_list + label_list
}
singleden()
但是,一般来说,我建议使用
lapply
通过“循环”创建 list
的绘图或图层,这通常可以避免这个问题:
singleden2 <- function() {
line_label_list <- lapply(
seq_along(paths), \(i) {
name <- basename(dirname(paths[i]))
list(
geom_line(
data = datas[[i]], aes(x = year, y = density, group = 1),
stat = "identity", color = color[i]
),
geom_label_repel(
data = datas[[i]] %>% filter(year == min(year)),
aes(label = name, y = density, x = year), color = color[i]
)
)
}
)
ggplot() + line_label_list
}
singleden2()
但是根据我对您想要实现的目标的理解,我的首选选择是将您的数据集列表绑定到一个数据集并仅使用一个
geom_line
和 geom_label_repel
进行绘图:
names(datas) <- names(color) <- basename(dirname(paths))
datas |>
bind_rows(.id = "name") |>
ggplot(aes(x = year, y = density, group = name, color = name)) +
geom_line() +
geom_label_repel(
data = ~ filter(., year == min(year), .by = name),
aes(label = name), direction = "y", show.legend = FALSE
) +
scale_color_manual(values = color, guide = "none")