查看: 616|回复: 4

[R语言] 标签糊成一坨?如何为图表添加“帅帅”的指引线?

[复制链接]
  • TA的每日心情

    2020.6.3 17:02
  • 签到天数: 28 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    管理员

    Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15

    主题
    153
    奥币
    1465
    积分
    1328
    注册时间
    2019.7.8
    在线时间
    243 小时

    发表于 2020.5.28 09:57:13 | 显示全部楼层 |阅读模式
    在Seurat的输出结果中,有一个展示表达量变化最大10个基因的图表令人印象深刻,如下图。关于该图表的具体内容参考之前《单细胞转录组学习笔记之Seurat 3.0(一)》一文。那么,常规散点图能不能画成这样效果?


    如果仍然使用针对单细胞数据高度定制的Seurat,显然是非常麻烦的。而使用ggplot2绘制类似这样的多标签图表,又容易出现“数据标签重叠”、超出绘图区域的标签“显示不全“和邻近数据点”指示不明“三大难题。
    于是ggrepel这个R包应用而生,它让文字标签周围产生“力场”,相互排斥,相互靠近的点会添加“指引线”避免指示不明。

    整个R包主要有两个用法几乎一样的函数geom_text_repel()和geom_label_repel(),可以把它们视作ggplot2中geom_text()的加强版,很显然,Seurat集成了这个R包。下面就仍以上图的数据为例,一起看下具体如何使用ggrepel吧!

    数据准备

    这里的范例数据表格是直接从《单细胞转录组学习笔记之Seurat 3.0(一)》一文中Seurat对象中导出的。为了方便大家练习,本文范例数据已上传到OmicShare论坛,登陆后下载即可。

    下载链接:https://www.omicshare.com/forum/thread-6312-1-1.html
    [AppleScript] 纯文本查看 复制代码
    [/align]
    [align=left]#读入数据:[/align]
    [align=left]var.df <- read.table("var.genes.xls",header = T,sep = "\t")[/align]
    [align=left]head(var.df,10)[/align]
    [align=left]


    [AppleScript] 纯文本查看 复制代码
    #载入dplyr包;
    library(dplyr)
    #按照variance.standardized这一列数值降序排列;
    var.genes<-arrange(var.df,desc(vst.variance.standardized))
    head(var.genes,10)
    为了检验这个包的性能,我这里选择绘制15个标签,当然选择展示20个也没问题。
    #提取TopN基因集:
    n <- 15
    topn <- head(var.genes$gene,n)
    topn
    #追加标签列;
    var.genes$labels <- ""
    var.genes$labels[1:n] <- topn
    head(var.genes,10)
    


    关于“散点”叠放细节调整,将数据改为升序排列,目的是先画非高变基因,关注Topn的基因最后再画,实现后者的散点置于“顶层”效果。

    [AppleScript] 纯文本查看 复制代码
    var.genes<-arrange(var.genes,vst.variance.standardized)
    


    添加箭头

    [AppleScript] 纯文本查看 复制代码
    #载入所需的画图主力R包;
    library(ggplot2)
    library(ggrepel)
    #常规的geom_text()函数的效果;
    p1 <- ggplot(data = var.genes,aes(log10(vst.mean),vst.variance.standardized,
    color=vst.variable,label=labels)) +
    geom_point()
    p1+geom_text(color="grey20",size=3)


    从上图我们可以看出,如果直接使用ggplot2的geom_text()函数会出现文本标签相互重叠的情况(虚线椭圆所示),也会出现标签对邻近的点指示不明的情况,如上图的CLU、NKG7基因。那么如何避免上述问题呢?我们先使用一下geom_text()函数的加强版:geom_text_repel()。

    [AppleScript] 纯文本查看 复制代码
    set.seed(100)
    p2 <- p1+geom_text_repel(color="grey20",size=3,point.padding = NA)
    p2


    geom_text_repel()和geom_label_repel()的核心参数:
    nudge_x/y:数据点与相应数据标签的距离,例如1表示标签在点右/上的1个单位处,而-2.2表示标签在点左/下2.2个单位处;
    direction:标签分布方向,x表水平分布,y 表示垂直分布,both 表示随机分布;
    segment.size:指定线段的粗细;
    point.padding:表示点周围的空余区域,决定连接线端点到到数据点中心的距离,单位为line。


    标签的“排斥”效果很不错,但是还不够“高大上”。接着,在垂直方向上给标签多一些偏移,并绘制箭头指引线。

    [AppleScript] 纯文本查看 复制代码
    p3 <- p1+geom_text_repel(force=20,color="grey20",size=3,point.padding = 0.5,hjust = 0.5,
    arrow = arrow(length = unit(0.01, "npc"), type = "open", ends = "last"),
    segment.color="grey20",segment.size=0.2,segment.alpha=0.8,nudge_y=1)
    
    p3


    关于为线段添加“箭头”,这里主要用到grid::arrow()函数,注意,它的参数只适于调整“整支箭的箭头”部分,如下:
    angle: 箭头的尖角的角度;
    length: 箭头尖角的长度;
    ends: "last", "first", "both", 指定线段的那端画箭头;
    type: "open"和"closed" 指定箭头是否为封闭的三角形。

    然后应用自定义主题,调整纵轴范围、散点颜色、图表主题等。

    [AppleScript] 纯文本查看 复制代码
    p3 + scale_y_continuous(breaks = c(0, 3, 6, 9, 12),limits = c(0, 12)) +
    xlab("Average expression") +
    ylab("Standardized variance") +
    scale_color_manual(values=c("#a2a9af", "#a8df65")) +
    theme_classic()+
    theme(plot.margin = unit(c(1,1,0.5,0.5),"cm"),
    legend.position = "none",
    axis.title = element_text(size = rel(1.2)),
    axis.text = element_text(size=rel(1)),
    axis.line = element_line(size = 0.5, colour = "grey30"))


    效果如下:


    分组标记

    上面的图表添加上箭头指引线,瞬间觉得最常见的散点图也变得“高大上”起来了呢。但对于“审美强迫症”来说,这些标签的排列还是有点乱,如何把他们排整齐呢?

    下面就增加点难度,以图表的中轴线为界,把两侧的标签整齐排列。具体实现方法就是根据横坐标将数据集分成两部分,分别指定标签的偏移距离和排列方式。比如这里以“0”为分界,使用subset()函数将数据框分成两部分,分两次添加文字标签。

    [AppleScript] 纯文本查看 复制代码
    p4 <- ggplot(data = var.genes,aes(log10(vst.mean),vst.variance.standardized,
    color=vst.variable,label=labels)) +
    geom_point() +
    geom_text_repel(
    data = subset(var.genes, log10(vst.mean) >= 0),
    nudge_x = 3 - log10(subset(var.genes, log10(vst.mean) >= 0)$vst.mean),
    color = "grey20",
    point.padding = NA,
    size = 3,
    segment.size = 0.2,
    segment.color = "grey50",
    direction = "y",
    hjust = 1
    ) +
    geom_text_repel(
    data = subset(var.genes, log10(vst.mean) < 0),
    nudge_x = -3 - log10(subset(var.genes, log10(vst.mean) < 0)$vst.mean),
    color = "grey20",
    point.padding = NA,
    size = 3,
    segment.size = 0.2,
    segment.color = "grey50",
    direction = "y",
    hjust = 0
    ) +
    scale_x_continuous(
    breaks = c(-3, -2, -1, 0, 1,2,3),
    limits = c(-3.5, 3.5))
    p4


    这里较难理解一点的是nudge_x(“标签”到“点”的水平距离)的设置,要想标签垂直对齐排列,需要为标签指定同样的横坐标,如本文的-3和3,只要用-3和3分别减去“点”的横坐标值就是对应的nudge_x值啦!当然这里的hjust参数也很重要,“0”表示文字左对齐,“0.5”表示文字居中,“1”表示文字右对齐。接着是图表的主题调整,方法同上。

    [AppleScript] 纯文本查看 复制代码
    p4 + scale_y_continuous(breaks = c(0, 3, 6, 9, 12),limits = c(0, 12)) +
    xlab("Average expression") +
    ylab("Standardized variance") +
    scale_color_manual(values=c("#a2a9af", "#a8df65")) +
    theme_classic()+
    theme(plot.margin = unit(c(1,1,0.5,0.5),"cm"),
    legend.position = "none",
    axis.title = element_text(size = rel(1.2)),
    axis.text = element_text(size=rel(1)),
    axis.line = element_line(size = 0.5, colour = "grey30"))
    


    如果觉得纯文字标签逼格还不够,我们还可以用圆角矩形标签的方式展示,这时候我们就用到了geom_label_repel()函数,参数与上文几乎一样,只需做简单调整。主要是通过fill参数调整矩形标签的颜色,其他不变。

    p5 <- ggplot(data = var.genes,aes(log10(vst.mean),vst.variance.standardized,
    color=vst.variable,label=labels)) +
    geom_point() +
    [AppleScript] 纯文本查看 复制代码
    geom_label_repel(
    data = subset(var.genes, log10(vst.mean) >= 0),
    nudge_x = 3 - log10(subset(var.genes, log10(vst.mean) >= 0)$vst.mean),
    color = "white",
    alpha = 0.9,
    point.padding = 0.5,
    size = 3,
    fill = "#96C93D",
    segment.size = 0.5,
    segment.color = "grey50",
    direction = "y",
    hjust = 1
    ) +
    geom_label_repel(
    data = subset(var.genes, log10(vst.mean) < 0),
    nudge_x = -3 - log10(subset(var.genes, log10(vst.mean) < 0)$vst.mean),
    color = "white",
    alpha = 0.9,
    point.padding = 0.5,
    size = 3,
    fill = "#9881F5",
    segment.size = 0.5,
    segment.color = "grey50",
    direction = "y",
    hjust = 0
    ) +
    scale_x_continuous(
    breaks = c(-3, -2, -1, 0, 1,2,3),
    limits = c(-3.5, 3.5))
    p5
    


    图表的主题调整同上。

    [AppleScript] 纯文本查看 复制代码
    p5 + scale_y_continuous(breaks = c(0, 3, 6, 9, 12),limits = c(0, 12)) +
    xlab("Average expression") +
    ylab("Standardized variance") +
    scale_color_manual(values=c("#a2a9af", "#ff85cb")) +
    theme_classic()+
    theme(plot.margin = unit(c(1,1,0.5,0.5),"cm"),
    legend.position = "none",
    axis.title = element_text(size = rel(1.2)),
    axis.text = element_text(size=rel(1)),
    axis.line = element_line(size = 0.5, colour = "grey30"))


    绘制效果如下:


    是不是好看多了?至此,添加个性化的标签无需Ai(Illustrator)也能批量自动完成啦!今天的内容就先到这里啦~



    本文作者:基迪奥-莫北



    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    新的一天加油!
    回复

    使用道具 举报

  • TA的每日心情
    yes!
    4 天前
  • 签到天数: 83 天

    连续签到: 1 天

    [LV.6]常住居民II

    中华鲟

    Rank: 5Rank: 5

    主题
    0
    奥币
    673
    积分
    506
    注册时间
    2017.6.6
    在线时间
    60 小时

    灌水之王


    发表于 2020.5.28 10:31:56 | 显示全部楼层
    好看,带劲
    新的一天加油!
    回复

    使用道具 举报

  • TA的每日心情
    吃饭
    2020.5.19 12:19
  • 签到天数: 173 天

    连续签到: 1 天

    [LV.7]常住居民III

    管理员

    Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15

    主题
    199
    奥币
    5136
    积分
    3019
    注册时间
    2017.7.3
    在线时间
    482 小时

    活跃会员荣誉管理


    发表于 2020.5.28 15:05:11 | 显示全部楼层
    新的一天加油!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    yes!
    2020.6.6 13:12
  • 签到天数: 198 天

    连续签到: 1 天

    [LV.7]常住居民III

    帝王蝶

    Rank: 4

    主题
    1
    奥币
    892
    积分
    278
    注册时间
    2016.8.25
    在线时间
    46 小时

    发表于 2020.5.28 22:06:00 | 显示全部楼层
    实用!赞赞赞
    新的一天加油!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    忙~
    前天 11:40
  • 签到天数: 23 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    钵水母

    Rank: 3Rank: 3

    主题
    0
    奥币
    155
    积分
    22
    注册时间
    2019.5.22
    在线时间
    21 小时

    发表于 2020.5.31 17:20:40 | 显示全部楼层
    本帖最后由 xmjy 于 2020.5.31 17:24 编辑

    你好:
    为什么我的做到 如下步骤的时候

    #追加标签列;
    var.genes$labels <- ""
    var.genes$labels[1:n] <- topn
    head(var.genes,10)

    添加的“labels”不是gene的字符串,而是数字。
    求解!!

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    快速回复 返回顶部 返回列表