【问题标题】:ggplot2 generate same plot for different variables in a for loopggplot2 为 for 循环中的不同变量生成相同的图
【发布时间】:2021-04-14 05:27:13
【问题描述】:

我正在尝试遍历仅包含数字的列表。对于每个循环,我将列从 char 转换为 numeric,然后尝试绘制它。我的代码的一个基本示例是:

library(ggtree) 
library(treeio)
library(tidyverse)
library(ggnewscale)
library(ggtreeExtra)
library(argparse)
library(RColorBrewer)
library(rlist)
library(stringr)

tree <- read.tree("/...") #PLEASE REPLACE THIS WITH THE LOCATION TO 'tree_newick.nwk'

tipcategories = read.csv("....", # PLEASE REPLACE THIS WITH THE LOCATION TO 'plot.tsv'
                     sep = " ",
                     header = TRUE,
                     stringsAsFactors = FALSE)

dd = as.data.frame(tipcategories)

p <- ggtree(tree) + ylim(-1, NA) + theme_tree2() 

p <- p %<+% dd + geom_tiplab(size=1)   

n <- 60
qual_col_pals = brewer.pal.info[brewer.pal.info$category == 'qual',]
col_vector = unlist(mapply(brewer.pal, qual_col_pals$maxcolors, 
rownames(qual_col_pals)))

columns = c("Column1", "Column2")

for (col in columns) {

  p <- p + new_scale_fill()

  dd[[col]] <- as.numeric(as.character(dd[[col]]))

  p <- p + geom_fruit(geom=geom_tile, mapping=aes(fill=dd[[col]]), width=2, offset=0.05) +
    scale_fill_continuous(name=col, low='blue', high='red')

}

p <- p + theme(legend.text = element_text(size = 5), legend.key.size = unit(0.3, 'cm'))

ggsave("....") # PLEASE REPLACE THIS WITH WHERE YOU WANT TO SAVE IT

树数据是(请放入文件中,并在读取树中用点替换文件名):

(((((((A:4,B:4):6,C:5):8,D:6):3,E:21):10,((F:4,G:12):14,H:8):13):13,((I:5,J:2):30,(K:11,L:11):2):17):4,M:56);

元数据文件(请在read.csv中放入文件并用点替换文件名):

Accession1 Column1 Column2   
A 10 130
B 20 120
C 30 110 
D 40 100
E 50 90
F 60 80 
G 70 70
H 80 60
I 90 50
J 100 40
K 110 30
L 120 20
M 130 10

上述内容仅适用于一列,但是,当尝试绘制 2 列时,第二列总是会覆盖第一列,并且第一列最终看起来与第二列完全相同。下图是程序正常运行的结果。

第一列(column1)实际上应该是这样的:

谁能提供有关如何解决此问题的帮助?

【问题讨论】:

  • 如果没有样本数据进行测试,很难提供帮助。见stackoverflow.com/questions/5963269/…
  • 您好,我很抱歉,因为我不知道您的意思。我希望它现在可以重现(否则请通知我)。
  • 您可以dput 数据以便更轻松地复制粘贴到 R 脚本中;)

标签: r


【解决方案1】:

重现您的案例确实需要很多时间,因为您有很多我没有使用的包:)

问题说明ggplot 在您调用 geom 并传递 datamapping aes 时不呈现任何图形。 ggplot 只存储对数据变量的名称引用。只有在渲染时它才真正获得价值和情节。在您的情况下,您传递引用 dd[[col]] 并且 col 通过 for 循环更改值,而 ggplot 始终引用 col 所以它结束渲染最后一列值的相同数据的两个条是 Column2 .您可以通过更改列的顺序并最后输入Column1 来验证这一点,然后您将看到Column1 的两个栏。

解决方案:为每个循环创建唯一引用

使用 dput 格式的数据进行初始设置

library(ggtree)
library(treeio)
library(tidyverse)
library(ggnewscale)
library(ggtreeExtra)
library(argparse)
library(RColorBrewer)
library(rlist)
library(stringr)

tree <- structure(list(edge = structure(c(14L, 15L, 16L, 17L, 18L, 19L, 
  20L, 20L, 19L, 18L, 17L, 16L, 21L, 22L, 22L, 21L, 15L, 23L, 24L, 
  24L, 23L, 25L, 25L, 14L, 15L, 16L, 17L, 18L, 19L, 20L, 1L, 2L, 
  3L, 4L, 5L, 21L, 22L, 6L, 7L, 8L, 23L, 24L, 9L, 10L, 25L, 11L, 
  12L, 13L), .Dim = c(24L, 2L)), edge.length = c(4, 13, 10, 3, 
    8, 6, 4, 4, 5, 6, 21, 13, 14, 4, 12, 8, 17, 30, 5, 2, 2, 11, 
    11, 56), Nnode = 12L, tip.label = c("A", "B", "C", "D", "E", 
      "F", "G", "H", "I", "J", "K", "L", "M")), class = "phylo",
  order = "cladewise")

tipcategories <- structure(
  list(Accession1 = c("A", "B", "C", "D", "E", "F", "G", 
    "H", "I", "J", "K", "L", "M"), Column1 = c(10L, 20L, 30L, 40L, 
      50L, 60L, 70L, 80L, 90L, 100L, 110L, 120L, 130L), Column2 = c(130L, 
        120L, 110L, 100L, 90L, 80L, 70L, 60L, 50L, 40L, 30L, 20L, 10L
      ), X = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), 
    X.1 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA
    ), X.2 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
      NA)), class = "data.frame", row.names = c(NA, -13L))

您的代码带有绘图生成和修改,以避免在绘图中使用相同的变量,这会导致您在 OP 中遇到问题

dd <- as.data.frame(tipcategories)

p <- ggtree(tree) + ylim(-1, NA) + theme_tree2()

p <- p %<+% dd + geom_tiplab(size = 1)

n <- 60
qual_col_pals <- brewer.pal.info[brewer.pal.info$category == "qual", ]
col_vector <- unlist(mapply(
  brewer.pal, qual_col_pals$maxcolors,
  rownames(qual_col_pals)
))

columns <- c("Column1", "Column2")

for (col in columns) {
  p <- p + new_scale_fill()

  # assign the value of dd[[col]] into a new variable using the name column
  assign(col, as.numeric(as.character(dd[[col]])))
  
  # using bang bang (!!) & sym to reference the variable inside ggplot call
  # this allow the ggplot to reference to different variable when finally render
  # plot at the end
  p <- p + geom_fruit(geom = geom_tile, mapping = aes(fill = !!sym(col)),
    width = 2, offset = 0.05) +
    scale_fill_continuous(name = col, low = "blue", high = "red")
}

p <- p + theme(legend.text = element_text(size = 5),
  legend.key.size = unit(0.3, "cm"))

p

reprex package (v2.0.0) 于 2021-04-15 创建

【讨论】:

  • 在一个ggplot 中,每个aes 只能有一种类型,所以如果你已经有一个连续的fill,你就不能在同一个地块上有一个离散的fill。如果您问另一个更详细的问题以及您想要实现的目标,那么讨论可以做什么会更容易。
  • 过去我曾成功地手动绘制不同类型的比例尺(使用 new_scale_fill())。我不确定为什么它现在不起作用。无论如何,非常感谢您的回复,您提供的信息非常有用。
  • 在遇到您的问题之前,我没有使用太多 ggnewscale 包。我认为它可以锻炼。然后你可以尝试在scale_fill_continousscale_fill_discretescale_fill_manual基于当前col之间切换
  • 对不起,如果列中有字母怎么办。我试图在分配(col ...,)之前将字母转换为数字,但出现的错误是“离散值提供给连续比例”。我知道这是由于字母。我该如何解决这个问题?
  • 如果没有数据,很难确认该提议是否可行。由于 OP 是关于已经回答的图表,我认为您最好提出一个新问题,将范围缩小到您遇到的具体挑战,以便其他人可以更好地支持您。
猜你喜欢
  • 1970-01-01
  • 2021-04-17
  • 1970-01-01
  • 2016-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-07
相关资源
最近更新 更多