【问题标题】:How to make multiple ggplots in a loop with conditional labels如何使用条件标签在循环中制作多个 ggplots
【发布时间】:2020-10-13 21:35:52
【问题描述】:
  Name      Value1     Value2     Value3
1   A1 -0.05970872 -1.1651404  1.3516952
2   A2  0.44143488 -0.7270722 -1.9870423
3   A3  0.34616897 -0.3891095  0.9123736
4   A4  0.49289331  1.3957877 -0.2689896
5   A5 -1.39354557  0.9429327  1.0719274

我有上面的数据框,我想在 ggplot2 中为它生成四个图表,每个图表的 x 轴作为“名称”列,y 轴作为其他列的值。虽然 x 轴不需要有“刻度线”,但如果 y 轴低于截止值,例如 0,我确实想有条件地用它们对应的“名称”列值的名称标记点。下面是我的代码使用 R 中的基本绘图函数通过循环函数自动生成图形。我附上了一张示例图。

cutoff = 0
df = read.csv("Book4.csv", header = TRUE)
list = rownames(df)
for(i in names(df)){
  png(filename = paste(i,".png"))
  plot(df[,i],
       main = i, 
       ylab = "Values",
       xlab = "Names",
       col = ifelse(df[,i]<cutoff, 'red', 'gray'),
       pch = ifelse(df[,i] < cutoff, 10, 1)
  )
  abline(cutoff, 0, col= "blue", lty=2)
  outlier = which(df[,i]<=cutoff)
  if (length(outlier)>0){
    text(outlier, df[outlier,i], list[outlier], cex=0.7, pos=2)
  }
  dev.off()
  
}

问题是这些图形标签通常是隐藏的,或者当我使用较大的数据集时会重叠,因此我无法读取它们。因此,我想使用 ggplot2 和函数 geom_text_repel 来重现它。我曾尝试使用 for 循环来执行此操作,但在使用 geom_text_repel 进行点标记时遇到了困难,因为我不确定如何有条件地使用它进行标记。我将制作超过 200 个 png,所以如果它可以自动化并以“Value1.png”、“Value2.png”等文件名输出,我将不胜感激。

这是我在下面的 ggplot 中的尝试

cutoff = 0
df = read.csv("Book4.csv", header = TRUE, row.names = 1)    
for(i in colnames(df)){
      png(filename = paste(i,".png"))
      outlier = which(df[,i]<=cutoff)
      print(ggplot(df, aes(x = rownames(df), y = df[,i])) +
              geom_point() + 
              geom_text_repel(data = df, label=outlier))
      dev.off()
    }

我不断收到错误消息“错误:美学必须是长度 1 或与数据 (5): 标签相同”,我不确定如何解决这个问题。

【问题讨论】:

    标签: r for-loop ggplot2


    【解决方案1】:

    你可以像这样达到你想要的结果:

    1. 虽然在大多数情况下使用df[,i] 会起作用,但不推荐使用它,并且确实存在不起作用的情况。相反,如果您想通过字符串引用变量,您可以使用所谓的.data 代词,即使用.data[[i]]

    2. 要获得条件标签,您可以将ifelse(.data[[i]] &lt;= cutoff, Name, "") 映射到label 美学内部aes()(!!)。

    library(ggplot2)
    library(ggrepel)
    
    cutoff <- 0
    
    for (i in colnames(df)) {
      png(filename = paste(i, ".png"))
      gg <- ggplot(df, aes(x = rownames(df), y = .data[[i]])) +
        geom_point() +
        geom_text_repel(aes(label = ifelse(.data[[i]] <= cutoff, Name, "")))
      print(gg)
      dev.off()
    }
    

    编辑首先。如果要使用过滤器,最好将行名作为新变量添加到数据集中,例如使用df$x &lt;- rownames(x),可以映射到x(我猜这就是你收到错误消息的原因)。之后您可以使用data = dplyr::filter(df, .data[[i]] &lt;= cutoff) 作为数据集。

    注意 但是,需要注意一个问题。如果您想添加另一个 geom_point 仅包含您的数据子集,则此方法很好。但是对于geom_text_repel,不建议这样做(这就是我使用ifelse 的原因)。原因是,geom_text_repel 只有知道全部数据才能做好。如果您只传递一个子集,那么标签通常会与子集数据中缺少的点重叠,因为geom_text_repel 不知道这些点在那里。

    df$x <- row.names(df)
    for (i in colnames(df)) {
      png(filename = paste(i, ".png"))
      gg <- ggplot(df, aes(x = x, y = .data[[i]])) +
        geom_point() +
        geom_text_repel(data = dplyr::filter(df, .data[[i]] <= cutoff), aes(x = x, y = .data[[i]], label = Name))
      print(gg)
      dev.off()
    }
    

    数据

    df <- structure(list(Name = c("A1", "A2", "A3", "A4", "A5"), Value1 = c(
          -0.05970872,
          0.44143488, 0.34616897, 0.49289331, -1.39354557
        ), Value2 = c(
          -1.1651404,
          -0.7270722, -0.3891095, 1.3957877, 0.9429327
        ), Value3 = c(
          1.3516952,
          -1.9870423, 0.9123736, -0.2689896, 1.0719274
        )), class = "data.frame", row.names = c(
          "1",
          "2", "3", "4", "5"
        ))
    

    【讨论】:

    • 谢谢!出于好奇,有什么方法可以使用“data=filter”而不是“ifelse”来实现这一点,如“geom_point(data=filter(df, .data[[i]]
    • 嗨,艾略特。我刚刚进行了编辑以包含使用过滤器的“版本”,以及您的错误的可能解决方案。关于不吸引人的结果......至少在示例数据和我的机器上,两种方法之间没有“没有”区别(标签的位置除外。请参阅我的注释)。最佳 S.
    【解决方案2】:

    另一种方法是创建一个绘图函数,然后将该函数应用于每个“值”,例如

    library(tidyverse)
    library(ggrepel)
    
    plot_data <- function(ValueX) {
      ValueX <- ensym(ValueX)
      ggplot(df, aes(y = !!ValueX,
                       x = Name)) +
        geom_text_repel(aes(label =  ifelse(!!ValueX < 0,
                            Name, NA))) +
        geom_point() +
        theme_bw(base_family = "Helvetica", base_size = 14) +
        ggtitle(ValueX) +
        theme(axis.ticks.x = element_blank(),
              legend.position = "none")
      ggsave(filename = paste(ValueX,
                             "plot.png",
                              sep = "_"),
             device = "png")
    }
    
    df <- readr::read_table("  Name      Value1     Value2     Value3
    1   A1 -0.05970872 -1.1651404  1.3516952
    2   A2  0.44143488 -0.7270722 -1.9870423
    3   A3  0.34616897 -0.3891095  0.9123736
    4   A4  0.49289331  1.3957877 -0.2689896
    5   A5 -1.39354557  0.9429327  1.0719274") %>% 
      select(-c(X1))
    
    ## Collate unaltered colnames into a vector
    vector_of_colnames <- colnames(df)[-1]
    
    ## Plot
    lapply(vector_of_colnames, plot_data)
    

    这种方法是否对您有用取决于您的用例。在我自己的工作中,我必须一次生成多达 35,000 个图,这种方法比使用循环具有优势,例如,我通常将图像整理成单个 pdf,而不是生成大量单独的文件(对于这个例子,一个文件 3 页,每页一个图):

    library(tidyverse)
    library(ggrepel)
    
    plot_data <- function(ValueX) {
      ValueX <- ensym(ValueX)
      ggplot(df, aes(y = !!ValueX,
                       x = Name)) +
        geom_text_repel(aes(label =  ifelse(!!ValueX < 0,
                            Name, NA))) +
        geom_point() +
        theme_bw(base_family = "Helvetica", base_size = 14) +
        ggtitle(ValueX) +
        theme(axis.ticks.x = element_blank(),
              legend.position = "none")
    }
    
    df <- readr::read_table("  Name      Value1     Value2     Value3
    1   A1 -0.05970872 -1.1651404  1.3516952
    2   A2  0.44143488 -0.7270722 -1.9870423
    3   A3  0.34616897 -0.3891095  0.9123736
    4   A4  0.49289331  1.3957877 -0.2689896
    5   A5 -1.39354557  0.9429327  1.0719274") %>% 
      select(-c(X1))
    
    ## Collate unaltered colnames into a vector
    vector_of_colnames <- colnames(df)[-1]
    
    pdf(file=paste0("All_plots.pdf"))
    lapply(vector_of_colnames, plot_data)
    dev.off()
    

    【讨论】:

    猜你喜欢
    • 2021-08-10
    • 2014-11-19
    • 1970-01-01
    • 1970-01-01
    • 2021-04-26
    • 1970-01-01
    • 1970-01-01
    • 2020-09-29
    • 2018-07-20
    相关资源
    最近更新 更多