簡體   English   中英

如何使用條件標簽在循環中制作多個 ggplots

[英]How to make multiple ggplots in a loop with conditional labels

  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) 相同:標簽”,並且不確定如何解決該問題。

你可以像這樣達到你想要的結果:

  1. 雖然在大多數情況下使用df[,i]會起作用,但不推薦使用,並且確實存在不起作用的情況。 相反,如果您想通過字符串引用變量,您可以使用所謂的.data代詞,即使用.data[[i]]

  2. 要獲得條件標簽,您可以將ifelse(.data[[i]] <= cutoff, Name, "")映射到aes() (!!) 內的label美學上。

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 <- rownames(x) ,它可以映射到x (我想這就是為什么你得到一個錯誤信息)。 之后,您可以使用data = dplyr::filter(df, .data[[i]] <= 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"
    ))

另一種方法是創建一個繪圖函數,然后將該函數應用於每個“值”,例如

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)

Value1_plot.png

Value2_plot.png

Value3_plot.png

這種方法是否對您有用取決於您的用例。 在我自己的工作中,我必須一次生成多達 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()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM