带圆圈的 R 热图

R heatmap with circles

我想在 R 中使用圆圈生成矩阵的热图可视化,以便让圆圈的颜色和直径都能提供信息。看起来像这样的东西:

这种绘图在某些计算生物学实验室中称为“泡泡糖图”,但我找不到 R function/package 来做。

有什么想法吗?谢谢!

不确定是否有提供这种开箱即用的软件包,但仅使用 ggplot2 就可以像这样实现:

library(ggplot2)

set.seed(42)

d <- data.frame(
  x = rep(paste("Team", LETTERS[1:8]), 4),
  y = rep(paste("Task", 1:4), each = 8),
  value = runif(32)
)

ggplot(d, aes(x, forcats::fct_rev(y), fill = value, size = value)) +
  geom_point(shape = 21, stroke = 0) +
  geom_hline(yintercept = seq(.5, 4.5, 1), size = .2) +
  scale_x_discrete(position = "top") +
  scale_radius(range = c(1, 15)) +
  scale_fill_gradient(low = "orange", high = "blue", breaks = c(0, .5, 1), labels = c("Great", "OK", "Bad"), limits = c(0, 1)) +
  theme_minimal() +
  theme(legend.position = "bottom", 
        panel.grid.major = element_blank(),
        legend.text = element_text(size = 8),
        legend.title = element_text(size = 8)) +
  guides(size = guide_legend(override.aes = list(fill = NA, color = "black", stroke = .25), 
                             label.position = "bottom",
                             title.position = "right", 
                             order = 1),
         fill = guide_colorbar(ticks.colour = NA, title.position = "top", order = 2)) +
  labs(size = "Area = Time Spent", fill = "Score:", x = NULL, y = NULL)

我写了一个替代函数来执行绘图,没有 ggplot 和 tidyverse。我很快就会上传到CRAN corto package。享受吧!

用法

inputp<-matrix(runif(1000),nrow=50)
inputn<-matrix(rnorm(1000),nrow=50)
colnames(inputp)<-colnames(inputn)<-paste0("Score",1:ncol(inputp))
rownames(inputp)<-rownames(inputn)<-paste0("Car",1:nrow(inputp))
par(las=2,mar=c(0,6,6,10))
bubblegum(inputp,inputn)

泡泡糖函数

require(gplots)
require(plotrix)
bubblegum<-function(
    inputp,
    inputn,
    pcr=0.1,
    grid=FALSE,
    reorder=FALSE,
    legend=TRUE,
    matrix2col=TRUE
) {
    if(nrow(inputp)!=nrow(inputn)|ncol(inputp)!=ncol(inputn)){
        warning("inputp and inpute have different sizes!")
    }
    
    ### Initialize
    rownumber<-nrow(inputp)
    colnumber<-ncol(inputp)
    
    ### Trasform the NESs into colors
    if(matrix2col){
        colconversion<-matrix2col(inputn,nbreaks=20)
        nescolors<-colconversion$colormatrix
    } else {
        nescolors<-inputn
    }

    #pradii<-0.3*(-log(inputp)/max(-log(inputp)))
    pradii<-inputp
    pradii[inputp>0.1]<-pcr*0
    pradii[inputp<=0.1]<-pcr*1
    pradii[inputp<0.05]<-pcr*2
    pradii[inputp<1E-5]<-pcr*3
    pradii[inputp<1E-10]<-pcr*4
    pradii[inputp<1E-20]<-pcr*5
    
    ### Order by sum NES
    sumnes<-apply(inputn,1,function(x){sum(abs(x))})
    if(reorder){
        neworder<-order(sumnes)
        pradii<-pradii[neworder,]
        nescolors<-nescolors[neworder,]
    } else {
        pradii<-pradii[nrow(pradii):1,]
        nescolors<-nescolors[nrow(nescolors):1,]
    }
    
    ### Plot
    #par(las=2,mar=c(0,20,6,0))
    plot(0,ylim=c(0,rownumber+1),xlim=c(0,colnumber+1),xaxt="n",yaxt="n",type="n",frame.plot=FALSE,xlab="",ylab="")#,xaxs="i",yaxs="i")
    if(grid){
        abline(h=1:rownumber,lty=2)
        abline(v=1:colnumber,lty=2)
    }
    for (i in (1:rownumber)) {
        for(j in 1:colnumber) {
            radius<-pradii[i,j]
            color<-nescolors[i,j]
            draw.circle(j,i,radius=radius,col=color,lwd=0.2)
        }
    }
    axis(3,at=1:colnumber,labels=colnames(pradii))
    axis(2,at=1:rownumber,labels=rownames(pradii),cex.axis=0.7)
    
    ### Enable things to be drawn outside the plot region
    par(xpd=TRUE)
    
    ### Title
    
    
    ### Legend
    if(legend){
        #legend(-colnumber,rownumber,c("group A", "group B"), pch = c(1,2), lty = c(1,2))
        legend("topright",inset=c(-0.1,0),legend=c(
            "<0.1","0.05","<1e-5","<1e-10","<1e-20"
        ), pch=c(21), title="FDR",pt.bg="white",horiz=FALSE,pt.cex=c(1,1.5,2,2.5,3))
    }
    
    if(matrix2col){
        extreme<-round(max(abs(inputn)),1)
        legend("bottomright", inset=c(-0.1,0),legend=c(
            -extreme,-extreme/2,0,extreme/2,extreme
        ), pch=c(21), title="Score",
        pt.bg=colconversion$col[c(1,5,10,15,19)],
        horiz=FALSE,pt.cex=3)
    }
    
    
}

###########################
matrix2col<-function(z,col1="navy",col2="white",col3="red3",nbreaks=100,center=TRUE){
    if(center){
        extreme=max(abs(z))+0.001
        breaks <- seq(-extreme, extreme, length = nbreaks)
    }else {
        breaks <- seq(min(z), max(z), length = nbreaks)
    }
    ncol <- length(breaks) - 1
    col <- colorpanel(ncol,col1,col2,col3)
    CUT <- cut(z, breaks=breaks)
    colorlevels <- col[match(CUT, levels(CUT))] # assign colors to heights for each point
    names(colorlevels)<-rownames(z)
    
    colormatrix<-matrix(colorlevels,ncol=ncol(z),nrow=nrow(z))
    dimnames(colormatrix)<-dimnames(z)
    return(list(colormatrix=colormatrix,col=col))
}