使用for循环在单个ggplot上生成多条线

问题描述 投票:0回答:1

我意识到很多人会遇到使用 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
  
}


线条绘制正确,一切都很好

enter image description here

但是,添加 label_list 会生成仅包含列表最后一个值的标签。不知何故,我的两个列表在用 ggplot 绘制时似乎没有对齐。列表本身存储了打印时我期望的正确数字和值

enter image description here

我尝试对行和标签使用单个 for 循环,遇到了同样的问题。想知道我是否需要以某种方式将列表配对在一起,但不清楚我该如何做到这一点

r loops for-loop ggplot2
1个回答
0
投票

这个问题是由于惰性评估造成的,并且存在很多问题,人们在使用

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")

© www.soinside.com 2019 - 2024. All rights reserved.