【问题标题】:Create multiple separate heatmaps from a single matrix从单个矩阵创建多个单独的热图
【发布时间】:2012-10-16 22:34:10
【问题描述】:

我想将 42x42 矩阵可视化为 28 个单独的热图,每个热图都是 6x6 矩阵,其值绘制在颜色的顶部。我只需要矩阵的下半部分,我不想绘制任何被排除的东西。随后的 6x6 矩阵不应重叠,如下例所示:

d = as.matrix(read.table("http://dl.dropbox.com/u/2505196/matrix_posthoc_tukey.dat"))
d[upper.tri(d)] <- NA
d1 <- d[1:6, 1:6]
d2 <- d[1:6, 7:12]
d3 <- d[1:6, 13:18]
d4 <- d[1:6, 18:24]
#...etc, up to d28 <- d[37:42,37:42] 

我用来创建单个热图的代码如下所示:

#baseline to create a separated space for all 28 plots
par(mfrow=c(4,7), mar=c(2,2,4,1), oma=c(2,4,2,2))

#using `image` to create heatmap, with color breaks defined by specific values
#the code below create just single heatmap
image(x=1:6, y=1:6, axes = FALSE, ylab="", xlab="", d1, 
  breaks=c(min(d1,na.rm=TRUE), -5.45, -4.65, 4.65, 5.45, max(d1,na.rm=TRUE)),
  col=c("red","orange","white","orange","red"))
axis(2, 1:6, cex.axis = 0.7, las=1, tick=F)
axis(3, 1:6, cex.axis = 0.7, tick=F)
#create vertical and forizontal lines
abline(h=seq(0.5,6.5,1), v=seq(0.5,6.5,1))
#plot values from the specific matrix subset
for (i in 1:6)
   {
     for (j in 1:6)
       {
         txt <- sprintf("%0.1f", d1[i,j])
         text(i, j, txt, cex=0.7)
        }
   }

三个这样的热图如下所示:

这就是我卡住的地方。每次我将另一个图像添加到我的单页多热图集合时,我都必须手动更改 d 值。我不知道如何使用上面的代码创建一个很好的循环来同时绘制这些特定的矩阵子集。

ggplot2、lattice 的替代解决方案也受到欢迎,尽管我相信这里的主要问题是制作这一系列热图的良好循环。

【问题讨论】:

    标签: r graphics matrix data-visualization heatmap


    【解决方案1】:

    这是一个相当复杂的绘图,但它可以很容易地由 R 中的标准图形库生成。这或多或少只是跟踪哪些索引进入哪个面板的问题。您提取d1d28 矩阵的方式可以自动化,因此您不必写出每一行。

    # Get the submatrices
    I <- unlist(lapply(0:6, function(a) a:6))
    J <- rep(0:6, 7:1)
    d2 <- mapply(function(i,j) d[1:6+6*i, 1:6+6*j], I, J, SIMPLIFY=FALSE)
    
    # Setup the layout and add an outer margin for the title and axis labels
    layout(matrix(c(1:28, 0, 0), 5, 6))
    par(oma=c(3,3,3,1), mar=c(2,2,1,1))
    
    # Plot all the matrices oriented the same way they appear in text
    # i.e. the first (vertical) dimension is plotted along the Y-axis
    for(k in 1:length(d2)){
        x <- 1:6+6*J[k]
        y <- 1:6+6*I[k]
    
        # Heatmap & grid
        image(x, y, t(d2[[k]][nrow(d2[[k]]):1,]), las=1, axes=FALSE,
              breaks=c(-1e10, -5.45, -4.65, 4.65, 5.45, 1e10),
              col=c("red","orange","white","orange","red"))
        xg <- apply(!is.na(d2[[k]]), 2, sum)
        yg <- rev(apply(!is.na(d2[[k]]), 1, sum))
        segments(c(x[1]-1, x)+.5, min(y)-.5,
                 c(x[1]-1, x)+.5, min(y)+c(6, yg)-.5, xpd=TRUE)
        segments(min(x)-.5,         c(y[1]-1, y)+.5,
                 min(x)+c(6,xg)-.5, c(y[1]-1, y)+.5, xpd=TRUE)
    
        # X & Y-axis values
        mtext(x, 1, .1, at=x, cex=.5)
        mtext(rev(y), 2, .2, at=y, las=1, cex=.5)
    
        # Values of each cell
        text(rep(x, each=6), rep(rev(y), 6),
         sub("NA", "", sprintf("%.2f", d2[[k]])), cex=.3)
    }
    
    # Add title and axis labels
    title("All 28 submatrices", outer=TRUE)
    mtext("Columns", outer=TRUE, 1, 1)
    mtext("Rows", outer=TRUE, 2, 1)
    

    每个单元格中的数字可能很小,但如果您将其绘制为 pdf 并放大它们可以阅读。 segments 函数的 xpd 参数抑制 R 将线条剪裁到绘图区域(否则外部线条会显得稍细)。

    【讨论】:

    • 示例图中的网格可以使用segments 添加,如果要在每个面板上方绘制x 轴数字,请将mtext(..., 1, ...) 更改为mtext(..., 3, ...)
    • 这很有前途。如何像在代码中一样在image 中进行颜色中断?你会如何在那里使用segments - 我不擅长循环的东西......
    • 怎么样?网格代码可能有点难以解释,但如果查看运行表达式,例如min(y)+c(6, yg)-.5,你会发现它只是获取每行开始和结束位置的一种方式。
    • 这是史诗般的伙伴,我一定会给你一些赏金代表。唯一不起作用的是它不会突出显示在制动器定义的范围内的负值(例如,在第二个面板中它是 -5.37、-5.86)。知道为什么吗?
    • 它确实突出了负值,但它使用与正值相同的颜色:) 这就是你写它的方式,所以我认为你对极端感兴趣,不管符号如何。所以把前两种颜色改成“蓝色”和“青色”什么的。很高兴你喜欢这个情节,我在工作中制作了大量情节,并认为你的情节很有趣。
    【解决方案2】:

    要拥有原始矩阵的 6x6 子数组,您可以执行以下操作:

    for (i in seq(1, 42, 6))
        for (j in seq(i, 42, 6)) {
            dsub = d[i:(i+5), j:(j+5)]
            ...
        }
    

    不过,我建议使用更好的方法来创建热图 - 而不是重新发明它。虽然我最喜欢的用于制作普通热图的包 - 正如你想要的单元格内的数字一样 - 是 pheatmap(= 漂亮的热图),但它不支持同一页面中的多个小热图。这只是pheatmap()输出的一个例子,你可以在安装并加载包后运行?pheatmap看到函数的帮助。

    要在同一页面中有多个热图,您可以使用ggplot2 包。这是how to make ggplot2 heatmapshaving multiple plots on the same page.的好手册

    【讨论】:

    • 您能否提供一个更详细的示例,说明您将如何在我的代码中使用您建议的循环?
    • 如果您打算使用自己的代码制作热图,您可以将其完全复制到循环体内。然后使用 dsub 作为您要为其制作热图的 6x6 矩阵(如原始代码的 d1、d2)
    • @GeekOnAcid 有什么问题? dsub 变量应该包含您想要的 6x6 数组。您可以在 dsub = ... 命令之后使用 print(dsub) 来查看结果。
    • 不,dsub 只给了我来自矩阵 d 前 6 行的单个序列。
    【解决方案3】:

    我认为您只需要一个嵌套循环,并且您的 d# 必须是一个数组(我将其称为子矩阵的 subs)。请原谅我的代码,因为我并不真正了解 R,而是这样的:

    for (row in 1:7)
      {
        for (col in 1:7)
          {
            subs[((row-1)*6)+j] <- d[ ((row-1)*6) + 1) : (row*6), (((col-1)*6) + 1) : (col*6)] 
          }
      }
    

    这将为您提供所有 49 个子矩阵。如果您只想要前 4 列子矩阵,则可以在循环中将 col 范围从 1:4。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多