2 min read

在enrichplot中使用更好的Label

GO term 太长, enrichplot 好局促怎么办?

例如下面这个样子:

# 可重复运行的代码拿去
library(clusterProfiler)
library(org.Hs.eg.db)
library(ggplot2)

data(geneList, package = "DOSE")
gene <- names(geneList)[abs(geneList)>3]
gene.df <- bitr(gene, fromType = "ENTREZID",
        toType = c("ENSEMBL", "SYMBOL"),
        OrgDb = org.Hs.eg.db)

ego <- enrichGO(gene          = gene,
                universe      = names(geneList),
                OrgDb         = org.Hs.eg.db,
                ont           = "BP",
                pAdjustMethod = "BH",
                pvalueCutoff  = 0.01,
                qvalueCutoff  = 0.05,
                readable      = TRUE)

这个例子中, 有一个 “microtubule cytoskeleton …” 特别长, 事实上有些 GO term 比这还要长很多. 不巧在这个例子中没有出现, 那就拿它开刀吧.

dotplot(ego)

刀法比较犀利, 主要是定义一个短 label 的函数, 将其传递给 scale_y_discrete() 即可. 在输出ggplot 对象时做修改.

#' Truncate string vector of ggplot axis label
#'
#' @param label    a ordered string vector
#' @param maxLen   max length of character (nchar) to show in label
#' @param maxWord  max count of words allowed to show in label
#' @param pattern  Word separater
#' @param dot      If true, three dots will added to truncated label
#'
#' @return a vector of truncated strings
#' @export
#'
#' @examples
short_label <- function(label, maxLen = 50, maxWord = 5, pattern = " ", dot = TRUE){
  l <- strsplit(label, pattern)
  short_label <- vector("character",length(l))
  
  for (i in seq_along(l)){
    truncated <- FALSE
    s <- l[[i]]
    if (length(s) > maxWord){
      ll <- paste(s[1:maxWord], collapse = " ")
      truncated <- TRUE
    }
    else{
      ll <- paste(s, collapse = " ")
    }
    
    if (nchar(ll) > maxLen){
      ll <- substr(ll, 1, maxLen)
      truncated <- TRUE
    }
    
    if (dot & truncated) ll <- paste(ll, "...",sep = " ")
    
    short_label[[i]] <- ll
  }
  attr(short_label, "pos") <- attr(label,"pos")
  return(short_label)
}

默认最多显示 50 个字符, 5 个单词.

dotplot(ego) + scale_y_discrete(label=short_label)

如果最多只显示 3 个单词, 则可以写成这样:

dotplot(ego) + 
  scale_y_discrete(
    label=function(x)short_label(x,maxWord = 3)
    )

注意: short_label() 带参数和不带参数时具有不同的调用方法.

不满意 enrichplot x轴排序怎么破?

我觉得 compareCluster 的输出可能会更加有比较价值. 但是发现 x 轴的排序有时候会有一些问题.

compareCluster 只能根据其本来固有的顺序排序, 这在程序上没有问题. 但用起来可能情况比较复杂.

data("gcSample")

names(gcSample)
## [1] "X1" "X2" "X3" "X4" "X5" "X6" "X7" "X8"
set.seed(0)
names(gcSample) <- sample(seq(0,28,by=4),8)
names(gcSample)
## [1] "20" "0"  "12" "24" "4"  "16" "8"  "28"
ck <- compareCluster(geneClusters = gcSample, fun = "enrichKEGG")

比如下面的例子中, 我们是想让 x 轴依数字大小(Time)排序的. 但是由于这个顺序与 list 顺序不同, 导致结果差强人意.

dotplot(ck)

这只是一个 list 输入的例子, 可以通过改 name 变更顺序(就行我刚刚做的那样). 但是, 如果数据是放在 data.frame 中的, 存在多个分组条件, 每个条件按因子的 level 排好序. 那么由于 compareClusterdotplot 操作时会将其转变成 character, 顺序会丢失, 导致最终结果是按照字母顺序输出的.

这种情况下, 你去改原始数据都是没有用的(需要给程序打补丁).

为了解决这个问题, 强行在 在已经输出的ggplot 对象上修改.

由于 ggplot 隐式输出的是一个对象, 其数据可以访问和修改. 出来的图, 先改一下再保存不就可以了吗?

p <- dotplot(ck)

levels(p$data$Cluster)
## [1] "0\n(383)"  "12\n(187)" "24\n(405)" "4\n(445)"  "16\n(264)" "8\n(317)" 
## [7] "28\n(160)"
p$data$Cluster <- factor(p$data$Cluster, 
                         levels = c("0\n(245)", "4\n(359)",  "8\n(172)", "12\n(412)", "16\n(157)", "20\n(388)",    "24\n(301)"),
                         labels = c(0,4,8,12,16,20,24))

p + xlab("Time (h)") + scale_y_discrete(label=short_label)

这两种“骚操作”, 分别相当于基因表达时“转录后修饰”和“翻译后修饰”. 嗯, 是有这么个意思. 都是在 “biobabble” 公众号学到的, 结合具体问题分享一下. 共同进步吧!