1. Introduce
ggplot2是R语言最流行的第三方扩展包,是RStudio首席科学家Hadley Wickham读博期间的作品,是R相比其他语言一个独领风骚的特点.包名中"gg"是grammar of graphics的简称,是一套优雅的绘图语法.
比较有条理的快速入门Click.
ggplot2这门绘图语言提供了一组概念.
- 数据:data
- 统计变换:stats
- 几何对象:geom
- 图形属性:aes
- 标尺:scale
- 图层:layer
- 坐标系:coord
- 分面:facet
我们举个具体的例子来解读这些概念.假设现在我们要对一批连续取值的数据绘制直方图.首先,要定义清楚需要几个分组或者每个分组的区间,根据分组定义统计落在这个分组里的个数,这个步骤就是把data 变为stats .然后,需要选定表达数据的几何对象,这个例子选用的是条块bar,这个步骤就是选geom .geom 有一堆属性需要设定,比如x、y、颜色等,称为aes ,哪个aes 由哪个stats 指定,需要指定一个映射关系mapping ,即指定谁对谁.知道谁对谁后,还需要知道怎么个对法,需要由scale 决定,比如stats的color字段取值为1应该对到什么颜色上,取值为2应该对到什么颜色上.这些完成了以后,统计图形的主体部分就成形了,但是假如我们希望在直方图上,再画一个概率密度曲线图,怎么办?ggplot2的思想非常精妙,把上面的主体部分称为一个图层layer ,一个统计图形可以拥有多个图层,每个图层叠加起来形成我们要的效果。接下来,再选定一个坐标系统coord ,一张统计图形plot 就做好了.假如我们有多组数据,每组数据都要按照相同的方法画一张图,每张图重复敲代码很繁琐,就可以使用分面facet快速绘制多张统计图形。这个过程用图形总结如下:
2. Example: volcano plot
现在我们重新绘制火山图.
2.1 导入数据
火山图使用的数据是差异表达数据.
R
deg_table = read.table(file = '24.DE_analysis/merge.DE_results',sep = '\t',header=T)
head(deg_table)
火山图只允许两组之间比较,所以要进行过滤.
R
filter(deg_table,sampleA=='Cs2',sampleB=='Cs1') %>%
arrange(desc(abs(log2FoldChange))) -> deg_sort
head(deg_sort)
2.2 绘图
类似matplotlib
,我们绘图首先可以先创建一个画布.
R
library(ggplot2)
ggplot(
data=deg_sort,
mapping = aes(x=log2FoldChange,y=padj)
)
接下来,把点画上去.也就是添加几何对象.但是注意一下, <math xmlns="http://www.w3.org/1998/Math/MathML"> y y </math>y轴按火山图需要取 <math xmlns="http://www.w3.org/1998/Math/MathML"> − l o g 10 -log_{10} </math>−log10.
R
ggplot(
data=deg_sort,
mapping = aes(x=log2FoldChange,y=-log10(padj))
) +
geom_point()#+表示加一个图层
接下来,是用颜色区分上下调、非差异基因的点.也就是上一节我们direction
那一列映射到不同颜色.我们先把列构造出来.
一个坑爹的点,R使用&&或者||会让一些包运行报错,所以只能使用&或者|
python果然天下第一
R
select(deg_sort,gene_id,sampleA,sampleB,log2FoldChange,pvalue,padj) %>%
mutate(direction = if_else(abs(log2FoldChange)>=1 & padj <= 0.05,
if_else(log2FoldChange >=1,'Up','Down'),'NS')) -> deg_direction
head(deg_direction)
R
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))
) + #aes表示映射
geom_point(aes(color=direction))
ggplot2
允许更换背景图.背景图也是一个图层.
R
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))
) + #aes表示映射
geom_point(aes(color=direction)) +
theme_dark()
2.3 中期总结
我们说的几何对象,实际是指要画什么图,比如柱状、条状等等.ggplot2提供了众多几何对象geom_xyz()
供大家选择。举两个常见的例子,geom_point()
用于表示两个连续变量之间的关系,几何形状是点;geom_bar()
用于表示x轴为离散变量,y轴为连续连续变量之间的关系,几何形状是条块.
每个几何对象都有自己的属性,这些属性的取值需要通过数据提供。数据与图形属性之间的映射关系称为mapping ,在ggplot2中用aes()
进行定义。常见的图形属性有:x
,y
,size
,color
,group
。图形属性的任意一项都可以用数据的某一个变量来表示。
ggplot2的绘图过程有点像Photoshop,有一个图层的理念,每个图层可以有自己的图形对象和图形属性,通过+
将不同图层叠加起来生成最后的统计图形.如果将数据定义在ggplot()
中,那么所有图层都可以共用这个数据;如果将数据定义在geom_xyz()
中,那么这个数据就只供这个几何对象使用.
3. Scale 与 mapping
前面提到aes()
设定了数据与图形属性的映射关系,但是数据怎么映射为属性,这就是标尺(Scales)的功能.
3.1 Example: Point Size
我们用上面的例子,举例一下设置点的大小.
R
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))
) + #aes表示映射
geom_point(aes(color=direction),size =3) +
theme_dark()
这里理解一下设置和映射的区别.我们写在aes
里的就是定义映射关系,而上面代码我们写在aes
外,就是设置全部点的大小都是3.
3.2 Example: legend sequence
看上图可以发现,图例的字符串是按字典序进行排列的.但如果我们要重新排序,就需要使用factor
,这里的factor
像是定义我们的排序规则.具体看代码.但实际上它是存储类别的数据,它定义一组数据的类别.
R
x = c('top','up','mask','mask','top','up')
# 按字典排序.
sort(x)
# "mask" "mask" "top" "top" "up" "up"
y = factor(x,levels=c('up','top','mask'))
sort(y)
[1] up up top top mask mask
Levels: up top mask
那么我们重新定义direction的顺序.
R
select(deg_sort,gene_id,sampleA,sampleB,log2FoldChange,pvalue,padj) %>%
mutate(direction = if_else(abs(log2FoldChange)>=1 & padj <= 0.05,
if_else(log2FoldChange >=1,'Up','Down'),'NS')) %>%
mutate(direction = factor(direction,levels=c('Up','Down','NS'))) -> deg_direction
#mutate修改列
# 重新画图,会发现顺序变了
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))
) + #aes表示映射
geom_point(aes(color=direction),size =3) +
theme_dark()
我们把列提取出来,会发现类型变了.
R
class(deg_direction$direction)
#factor
3.3 Example: Scale and color
接下来调整图例的颜色.这就涉及到scale
.对于任何一个图形属性,如x
,y
,alpha
,color
,fill
,linetype
,shape
,size
,ggplot2都提供以下四种标尺.
scale_*_continuous()
:将数据的连续取值映射为图形属性的取值scale_*_discrete()
:将数据的离散取值映射为图形属性的取值scale_*_identity()
:使用数据的值作为图形属性的取值scale_*_mannual()
:将数据的离散取值作为手工指定的图形属性的取值
在对图形属性进行映射之后,使用标尺可以控制这些属性的显示方式,比如坐标刻度,颜色属性等.
从下面代码来看,我们先是映射了不同direction
值和color
之间的关系,但是要具体指定关系需要用scale
指明.
R
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))) + #aes表示映射
geom_point(aes(color=direction),size =3) +
scale_color_manual(values = c('red','blue','grey')) +
scale_size(range = c(0.3,4)) + #规定了点的大小范围
theme_dark()
#这里将离散数值映射到图像属性
4. axis modify
4.1 axis scale
修改坐标轴的大小.其实是修改break参数.
R
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))) + #aes表示映射
geom_point(aes(color=direction,size=abs(log2FoldChange))) +
scale_color_manual(values = c('red','blue','grey'),name = 'difference express condition') +
scale_size(range = c(0.3,4),name = '|log2FoldChange|') + #规定了点的大小范围
scale_x_continuous(name = "log2(Fold Change)",breaks = seq(-5,5,1)) +
scale_y_continuous(name = "-log10(pvalue)") +
theme_dark()
#这里将离散数值映射到图像属性
4.2 title modify
标题在ggplot2
里,也叫引导元素,标题其实是修改X轴的映射方式.
R
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))) + #aes表示映射
geom_point(aes(color=direction,size=abs(log2FoldChange))) +
scale_color_manual(values = c('red','blue','grey'),name = 'difference express condition') +
scale_size(range = c(0.3,4),name = '|log2FoldChange|') + #规定了点的大小范围
scale_x_continuous(name = "log2(Fold Change)",breaks = seq(-5,5,1)) +
scale_y_continuous(name = "-log10(pvalue)") +
theme_dark()
#这里将离散数值映射到图像属性
修改title
其实有更简单的写法,但是本质还是上面的修改方式.
R
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))) + #aes表示映射
geom_point(aes(color=direction,size=abs(log2FoldChange))) +
scale_color_manual(values = c('red','blue','grey')) +
scale_size(range = c(0.3,4)) + #规定了点的大小范围
scale_x_continuous(breaks = seq(-5,5,1)) +
scale_y_continuous() +
labs(x = "log2(Fold Change)",y = "-log10(pvalue)",size = '|log2FoldChange|',color = 'difference express condition') +
theme_dark()
#这里将离散数值映射到图像属性
4.3 delete legends
我们也可以删除图例,使用show.legend = F
.
R
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))) + #aes表示映射
geom_point(aes(color=direction,size=abs(log2FoldChange)),show.legend = F) +
scale_color_manual(values = c('red','blue','grey')) +
scale_size(range = c(0.3,4)) + #规定了点的大小范围
scale_x_continuous(breaks = seq(-5,5,1)) +
scale_y_continuous() +
labs(x = "log2(Fold Change)",y = "-log10(pvalue)",size = '|log2FoldChange|',color = 'difference express condition') +
theme_dark()
#这里将离散数值映射到图像属性
5. 几何对象修改
5.1 添加参考线
举个例子,我们先横线,就需要添加geom_hline
函数,并使用yintercept
指定它的位置.
R
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))) + #aes表示映射
geom_point(aes(color=direction,size=abs(log2FoldChange)),show.legend = F) +
geom_hline(yintercept = -log10(0.05))+
scale_color_manual(values = c('red','blue','grey')) +
scale_size(range = c(0.3,4)) + #规定了点的大小范围
scale_x_continuous(breaks = seq(-5,5,1)) +
scale_y_continuous() +
labs(x = "log2(Fold Change)",y = "-log10(pvalue)",size = '|log2FoldChange|',color = 'difference express condition') +
theme_dark()
#这里将离散数值映射到图像属性
也可以修改线的样式.
R
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))) + #aes表示映射
geom_point(aes(color=direction,size=abs(log2FoldChange)),show.legend = F) +
geom_hline(yintercept = -log10(0.05),linetype = "dotdash")+
scale_color_manual(values = c('red','blue','grey')) +
scale_size(range = c(0.3,4)) + #规定了点的大小范围
scale_x_continuous(breaks = seq(-5,5,1)) +
scale_y_continuous() +
labs(x = "log2(Fold Change)",y = "-log10(pvalue)",size = '|log2FoldChange|',color = 'difference express condition') +
theme_dark()
#这里将离散数值映射到图像属性
接下来添加竖线,竖线需要添加两条,也就是使用geom_vline
函数.
R
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))) + #aes表示映射
geom_point(aes(color=direction,size=abs(log2FoldChange)),show.legend = F) +
geom_hline(yintercept = -log10(0.05),linetype = "dotdash",color='green')+
geom_vline(xintercept = c(-1,1),linetype = 'dotdash',color='green')+
scale_color_manual(values = c('red','blue','grey')) +
scale_size(range = c(0.3,4)) + #规定了点的大小范围
scale_x_continuous(breaks = seq(-5,5,1)) +
scale_y_continuous() +
labs(x = "log2(Fold Change)",y = "-log10(pvalue)",size = '|log2FoldChange|',color = 'difference express condition') +
theme_dark()
#这里将离散数值映射到图像属性
5.2 添加标签
已知新图层会继承背景图层的数据和映射关系.因为我们把aes(x=...,y=...)映射到背景图上,所以后面的图不需要指定x,y轴. 当我们想给每个点添加标签时,会继承背景图层的数据,也就是给背景图层的数据都加上标签,如果要修改必须重新赋值data
.
R
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))) + #aes表示映射
geom_point(aes(color=direction,size=abs(log2FoldChange)),show.legend = F) +
geom_text(aes(label=gene_id)) +#如果前面背景图没有指定x,y轴,这里就需要指定x,y轴
geom_hline(yintercept = -log10(0.05),linetype = "dotdash",color='green')+
geom_vline(xintercept = c(-1,1),linetype = 'dotdash',color='green')+
scale_color_manual(values = c('red','blue','grey')) +
scale_size(range = c(0.3,4)) + #规定了点的大小范围
scale_x_continuous(breaks = seq(-5,5,1)) +
scale_y_continuous() +
labs(x = "log2(Fold Change)",y = "-log10(pvalue)",size = '|log2FoldChange|',color = 'difference express condition') +
theme_dark()
#这里将离散数值映射到图像属性
画出来的图很辣眼睛,因此需要只选择一部分来画.这里只选择了前10个.
R
key_genes = c(deg_direction$gene_id[1:10])
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))) + #aes表示映射
geom_point(aes(color=direction,size=abs(log2FoldChange)),show.legend = F) +
geom_text(data=filter(deg_direction,gene_id==key_genes),aes(label=gene_id)) +
geom_hline(yintercept = -log10(0.05),linetype = "dotdash",color='green')+
geom_vline(xintercept = c(-1,1),linetype = 'dotdash',color='green')+
scale_color_manual(values = c('red','blue','grey')) +
scale_size(range = c(0.3,4)) + #规定了点的大小范围
scale_x_continuous(breaks = seq(-5,5,1)) +
scale_y_continuous() +
labs(x = "log2(Fold Change)",y = "-log10(pvalue)",size = '|log2FoldChange|',color = 'difference express condition') +
theme_dark()
#这里将离散数值映射到图像属性
#filter(deg_direction,gene_id %in% key_genes) 用这个也行
也可以将标签加到同色.主要是在映射处给color
赋值.
R
library(ggrepel)
key_genes = c(deg_direction$gene_id[1:10])
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))) + #aes表示映射
geom_point(aes(color=direction,size=abs(log2FoldChange)),show.legend = F) +
geom_text_repel(data=filter(deg_direction,gene_id==key_genes),size=3,aes(label=gene_id,color=direction),show.legend = F) +
geom_hline(yintercept = -log10(0.05),linetype = "dotdash",color='green')+
geom_vline(xintercept = c(-1,1),linetype = 'dotdash',color='green')+
scale_color_manual(values = c('red','blue','grey')) +
scale_size(range = c(0.3,4)) + #规定了点的大小范围
scale_x_continuous(breaks = seq(-5,5,1)) +
scale_y_continuous() +
labs(x = "log2(Fold Change)",y = "-log10(pvalue)",size = '|log2FoldChange|',color = 'difference express condition') +
theme_dark()
#这里将离散数值映射到图像属性
5.3 添加扰动
上图可以发现label
挡住了部分点,因此需要将label挪动一下位置,这种我们一般使用ggrepel
包.然后使用geom_text_repel
.
R
library(ggrepel)
key_genes = c(deg_direction$gene_id[1:10])
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))) + #aes表示映射
geom_point(aes(color=direction,size=abs(log2FoldChange)),show.legend = F) +
geom_text_repel(data=filter(deg_direction,gene_id==key_genes),aes(label=gene_id)) +
geom_hline(yintercept = -log10(0.05),linetype = "dotdash",color='green')+
geom_vline(xintercept = c(-1,1),linetype = 'dotdash',color='green')+
scale_color_manual(values = c('red','blue','grey')) +
scale_size(range = c(0.3,4)) + #规定了点的大小范围
scale_x_continuous(breaks = seq(-5,5,1)) +
scale_y_continuous() +
labs(x = "log2(Fold Change)",y = "-log10(pvalue)",size = '|log2FoldChange|',color = 'difference express condition') +
theme_dark()
#这里将离散数值映射到图像属性
5.4 添加黑框
我们可以给关键基因添加黑框,方便观察.黑框的本质也是在背景图上加点,同时我们shape
是用于指定形状.stroke
是调整厚度.可以参考这个Click.
R
library(ggrepel)
key_genes = c(deg_direction$gene_id[1:10])
ggplot(
data=deg_direction,
mapping = aes(x=log2FoldChange,y=-log10(padj))) + #aes表示映射
geom_point(aes(color=direction,size=abs(log2FoldChange)),show.legend = F) +
geom_point(data=filter(deg_direction,gene_id==key_genes),shape=21,color='black',
aes(fill=direction,size=abs(log2FoldChange),stroke=2),show.legend = F
)+
geom_text_repel(data=filter(deg_direction,gene_id==key_genes),size=3,aes(label=gene_id,color=direction),show.legend = F) +
geom_hline(yintercept = -log10(0.05),linetype = "dotdash",color='green')+
geom_vline(xintercept = c(-1,1),linetype = 'dotdash',color='green')+
scale_color_manual(values = c('red','blue','grey')) +
scale_fill_manual(values = c('red','blue','grey')) +
scale_size(range = c(0.3,4)) + #规定了点的大小范围
scale_x_continuous(breaks = seq(-5,5,1)) +
scale_y_continuous() +
labs(x = "log2(Fold Change)",y = "-log10(pvalue)",size = '|log2FoldChange|',color = 'difference express condition') +
theme_dark()
#这里将离散数值映射到图像属性
如果论文绘图,建议使用ggsci
.ggiraph
可以看作ggplot2
的扩展包,有时间可以学.