【问题标题】:Using discrete custom color in a plotly heatmap在绘图热图中使用离散的自定义颜色
【发布时间】:2017-07-20 08:25:03
【问题描述】:

我正在尝试生成一个plotlyheatmap,我希望通过离散比例指定颜色。

这就是我的意思:

生成具有 2 个聚类的数据并分层聚类:

require(permute)
set.seed(1)
mat <- rbind(cbind(matrix(rnorm(2500,2,1),nrow=25,ncol=500),matrix(rnorm(2500,-2,1),nrow=25,ncol=500)),
             cbind(matrix(rnorm(2500,-2,1),nrow=25,ncol=500),matrix(rnorm(2500,2,1),nrow=25,ncol=500)))
rownames(mat) <- paste("g",1:50,sep=".")
colnames(mat) <- paste("s",1:1000,sep=".")
hc.col <- hclust(dist(t(mat)))
dd.col <- as.dendrogram(hc.col)
col.order <- order.dendrogram(dd.col)
hc.row <- hclust(dist(mat))
dd.row <- as.dendrogram(hc.row)
row.order <- order.dendrogram(dd.row)
mat <- mat[row.order,col.order]

mat 中的值划分为间隔并为每个间隔设置颜色:

require(RColorBrewer)
mat.intervals <- cut(mat,breaks=6)
interval.mat <- matrix(mat.intervals,nrow=50,ncol=1000,dimnames=list(rownames(mat),colnames(mat)))
interval.cols <- brewer.pal(6,"Set2")
names(interval.cols) <- levels(mat.intervals)

使用ggplot2 我以这种方式绘制heatmap(也让legend 指定离散的颜色和相应的范围):

require(reshape2)
interval.df <- reshape2::melt(interval.mat,varnames=c("gene","sample"),value.name="expr")
require(ggplot2)
ggplot(interval.df,aes(x=sample,y=gene,fill=expr))+
  geom_tile(color=NA)+theme_bw()+
  theme(strip.text.x=element_text(angle=90,vjust=1,hjust=0.5,size=6),panel.spacing=unit(0.025,"cm"),legend.key=element_blank(),plot.margin=unit(c(1,1,1,1),"cm"),legend.key.size=unit(0.25,"cm"),panel.border=element_blank(),strip.background=element_blank(),axis.ticks.y=element_line(size=0.25))+
  scale_color_manual(drop=FALSE,values=interval.cols,labels=names(interval.cols),name="expr")+
  scale_fill_manual(drop=FALSE,values=interval.cols,labels=names(interval.cols),name="expr")

给出:

这是我尝试使用plotly 生成它:

plot_ly(z=mat,x=colnames(mat),y=rownames(mat),type="heatmap",colors=interval.cols)

给出:

这些数字并不相同。在ggplot2 图中,与plotly 图相比,集群更加明显。

有什么方法可以对plotly 命令进行参数化以提供更类似于ggplot2 图的内容?

另外,是否可以使 plotly 图例离散 - 类似于 ggplot2 图中的图例?

现在假设我想facet 集群。在ggplot2 的情况下,我会这样做:

require(dplyr)
facet.df <- data.frame(sample=c(paste("s",1:500,sep="."),paste("s",501:1000,sep=".")),facet=c(rep("f1",500),rep("f2",500)),stringsAsFactors=F)
interval.df <- left_join(interval.df,facet.df,by=c("sample"="sample"))
interval.df$facet <- factor(interval.df$facet,levels=c("f1","f2"))

然后绘制:

ggplot(interval.df,aes(x=sample,y=gene,fill=expr))+facet_grid(~facet,scales="free",space="free",switch="both")+
  geom_tile(color=NA)+labs(x="facet",y="gene")+theme_bw()+
  theme(strip.text.x=element_text(angle=90,vjust=1,hjust=0.5,size=6),panel.spacing=unit(0.05,"cm"),plot.margin=unit(c(1,1,1,1),"cm"),legend.key.size=unit(0.25,"cm"),panel.border=element_blank(),strip.background=element_blank(),axis.ticks.y=element_line(size=0.25))+
  scale_color_manual(drop=FALSE,values=interval.cols,labels=names(interval.cols),name="expr")+
  scale_fill_manual(drop=FALSE,values=interval.cols,labels=names(interval.cols),name="expr")

这给出了:

因此这些簇被panel.spacing 分隔,看起来更加明显。有什么办法可以通过plotly 实现这种刻面?

【问题讨论】:

  • ggplotly怎么样?
  • 对于这些维度,将 ggplot 转换为使用 ggplotly 进行绘图需要不合理的时间(很多很多分钟) - 不太实用

标签: r ggplot2 heatmap plotly


【解决方案1】:

question 59516054 中提供了一种创建离散颜色中断的好方法 . 鉴于提供的Z_Breaks 函数,您可以使用该函数将colorbar 刻度标签居中在每个框的中间:

tickpos <- function(nFactor) {
    pos <- unique((head(Z_Breaks(nFactor), -1)) + head(Z_Breaks(nFactor))[2] / 2) * (nFactor - 1)
}

然后将其分配给colorbartickval 参数:

colorbar <- list(tickvals = tickpos(nFactor), ticktext = names(colours))

【讨论】:

    【解决方案2】:

    结合@Maximilian Peters 和@R.S. 的答案:

    数据:

    require(permute)
    set.seed(1)
    mat <- rbind(cbind(matrix(rnorm(2500,2,1),nrow=25,ncol=500),matrix(rnorm(2500,-2,1),nrow=25,ncol=500)),
                 cbind(matrix(rnorm(2500,-2,1),nrow=25,ncol=500),matrix(rnorm(2500,2,1),nrow=25,ncol=500)))
    rownames(mat) <- paste("g",1:50,sep=".")
    colnames(mat) <- paste("s",1:1000,sep=".")
    hc.col <- hclust(dist(t(mat)))
    dd.col <- as.dendrogram(hc.col)
    col.order <- order.dendrogram(dd.col)
    hc.row <- hclust(dist(mat))
    dd.row <- as.dendrogram(hc.row)
    row.order <- order.dendrogram(dd.row)
    mat <- mat[row.order,col.order]
    

    颜色:

    require(RColorBrewer)
    mat.intervals <- cut(mat,breaks=6)
    interval.mat <- matrix(mat.intervals,nrow=50,ncol=1000,dimnames=list(rownames(mat),colnames(mat)))
    require(reshape2)
    interval.df <- reshape2::melt(interval.mat,varnames=c("gene","sample"),value.name="expr")
    interval.cols <- brewer.pal(6,"Set2")
    names(interval.cols) <- levels(mat.intervals)
    interval.cols2 <- rep(interval.cols, each=ncol(mat))
    color.df <- data.frame(range=c(0:(2*length(interval.cols)-1)),colors=c(0:(2*length(interval.cols)-1)))
    color.df <- setNames(data.frame(color.df$range,color.df$colors),NULL)
    for (i in 1:(2*length(interval.cols))) {
      color.df[[2]][[i]] <- interval.cols[[(i + 1) / 2]]
      color.df[[1]][[i]] <-  i/(2*length(interval.cols))-(i %% 2)/(2*length(interval.cols))
    }
    

    绘图:

    plot_ly(z=c(interval.df$expr),x=interval.df$sample,y=interval.df$gene,colors=interval.cols2,type="heatmap",colorscale=color.df,
            colorbar=list(tickmode='array',tickvals=c(1:6),ticktext=names(interval.cols),len=0.2,outlinecolor="white",bordercolor="white",borderwidth=5,bgcolor="white"))
    

    如果有人能补充就太好了:

    1. 如何刻面或在刻面之间创建窄边框。
    2. 如何让colorbar 刻度标签准确地出现在colorbar 中每个框的中间

    【讨论】:

    • 关于 (2) 既然@MaximilianPeters 向我们展示了如何破解颜色条,您可以从 tickmode 检查到其他参数吗,阅读它似乎暗示有一种方法可以通过设置 tickmode 来做到这一点到“线性”并使用 0tick 和 dtick,虽然我没有尝试过。 plot.ly/r/reference/#scatter-marker-colorbar-tickmode
    • 我玩了一下,但失败了。因此,我的帖子针对的是有经验的人。如果我设法做对了,我会更新我的答案
    【解决方案3】:

    让我们得到一个离散的色阶

    df_colors = data.frame(range=c(0:11), colors=c(0:11))
    color_s <- setNames(data.frame(df_colors$range, df_colors$colors), NULL)
    for (i in 1:12) {
      color_s[[2]][[i]] <- interval.cols[[(i + 1) / 2]]
      color_s[[1]][[i]] <-  i / 12 - (i %% 2) / 12
    }
    

    通过设置ticktext 并挤压它(len=0.2)得到一个漂亮的颜色条

    colorbar=list(tickmode='array', tickvals=c(1:6), ticktext=levels(mat.intervals), len=0.2)
    

    所有需要添加到您的示例中的代码

    df_colors = data.frame(range=c(0:11), colors=c(0:11))
    color_s <- setNames(data.frame(df_colors$range, df_colors$colors), NULL)
    
    for (i in 1:12) {
      color_s[[2]][[i]] <- interval.cols[[(i + 1) / 2]]
      color_s[[1]][[i]] <-  i / 12 - (i %% 2) / 12
    }
    
    
    plot_ly(z=c(interval.df$expr), x=interval.df$sample, y=interval.df$gene, colorscale = color_s, type = "heatmap", hoverinfo = "x+y+z", colorbar=list(tickmode='array', tickvals=c(1:6), ticktext=levels(mat.intervals), len=0.2))
    

    【讨论】:

      【解决方案4】:

      我最初也在想同样的事情,那就是对渐变进行下采样,但强制更苛刻的过渡似乎至少可以使颜色更明显。

      interval.cols2 <- rep(interval.cols, each=1000)
      plot_ly(z=mat,x=colnames(mat),y=rownames(mat),type="heatmap",colors=interval.cols2)
      

      【讨论】:

      • 非常感谢@R.S.。知道如何分面吗?
      • Hmmnnn,我对 plot_ly 热图不太熟悉,但在 heatmap.2 中,例如您可以添加虚拟 NA 列或行向量,并将 NA 值的颜色分配设置为白色以引入分隔器。假设在 plot_ly 中有一个类似的选项,如果这是集群的结果,那么您需要找出切割的位置,或者如果事先知道列顺序,只需在之间添加一个 NA 向量(或矩阵) 2组。您还需要介绍"" colnames。
      猜你喜欢
      • 2016-06-25
      • 2023-04-01
      • 2020-10-21
      • 2015-02-19
      • 2012-03-31
      • 1970-01-01
      • 1970-01-01
      • 2017-02-25
      • 2020-06-21
      相关资源
      最近更新 更多