R使用笔记: ggplot2

本笔记内容:
最近工作中遇到的分析需求:按照要求的分组画boxplotPcoA的散点图。对画各种图的实现方法,一些具体问题的解决方法等。

  • Long data和wide data之间的转换, 及其作用
  • 作图细节:box的颜色,散点分布,调整label的角度, 修改label: theme(), labs()等
  • 调整横坐标labels的顺序:设置factor中level的顺序
  • facet_grid(): 将一个Plot按照分组绘制多个Plot,并在theme()中设置它的属性
  • ggplot2的一些通用规律
  • PCoA:ade4和ggplot2
  • legend()用法
  • theme()快捷设置
  • 零碎的东西
  • 在boxplot之间连线
  • geom_bar()
  • geom_, geom_, geom_
  • scale_, scale_, scale_
  • error bar
  • 在geom_boxplot()中去掉outlier
  • 拼图之后加上一个总title
  • ggexport
  • ggsignif
  • geom_boxplot()画出来的box释义
  • stacked barchart和percentage stacked barchart
  • sankey flow
long data和wide data之间的转换, 及其作用

关于Long data和wide data之间的转换及其意义,我写过在python中的用法,见python学习:pandas学习笔记(三)中Pandas.melt()的用法。在这里是用R实现。一般ggplot2需要使用Long data. 比方说如下所示的数据cond1, cond2control你都想用ggplot2画boxplot出来,那必须转化为Long data, 把每个样本的测量值分一列,测得是cond1还是cond2一列。
了解更多参考这个链接

t <- read.table(header=TRUE, text='
  subject sex control cond1 cond2
        1   M     7.9  12.3  10.7
        2   F     6.3  10.6  11.1
        3   F     9.5  13.1  13.8
        4   M    11.5  13.4  12.9
 ')

t_long <- melt(t, id.vars = c('subject', 'sex')) # id.vars为不合并的列,即保留的列
t_long
   subject sex variable value
1        1   M  control   7.9
2        2   F  control   6.3
3        3   F  control   9.5
4        4   M  control  11.5
5        1   M    cond1  12.3
6        2   F    cond1  10.6
7        3   F    cond1  13.1
8        4   M    cond1  13.4
9        1   M    cond2  10.7
10       2   F    cond2  11.1
11       3   F    cond2  13.8
12       4   M    cond2  12.9
作图细节:box的颜色,散点分布等

以以上数据为例,按照variable的分组画三个boxplot:

ggplot(t_long, aes(x = variable, y = value)) + 
      geom_boxplot()
ggplot(t_long, aes(x = variable, y = value, fill = variable))  +  
     geom_boxplot() + geom_point(position = position_jitterdodge()) + 
     # 在box中加上点,让点随机排列,不要忘记用加号衔接
     
     scale_fill_brewer(palette = "Set3") +   # 使用brewer.pal中的调色盘
    
     theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) + 
     # theme()用来设置labels, 以及labels与各轴之间的角度
    
     labs(x = "condition", y = "condition_values")
     # 重命名labels

ggplot(t_long, aes(x = variable, y = value, fill = sex))  +  
     geom_boxplot(position = position_dodge(0.8)) + 
     # 因为把大boxplot拆分成两个,设置这两个小boxplot之间的距离
     geom_point(position = position_jitterdodge()) + 
     scale_fill_brewer(palette = "Set3") +   
     theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) + 
     labs(x = "condition", y = "condition_values")
 # ggplot(aes(fill = ))变化了,将每个variable拆分成sex的两个小组画图


可以参考这个链接,一个基础又详细的教程。

调整横坐标labels的顺序:设置factor中level的顺序
c <- t_long$value
t_long$variable <- factor(t_long$variable ,
     levels =unique(t_long$variable[order(-c)]))
# 让整个boxplot大致降序排列,需要将包含box类别的变量设置为factor,在level中设置为按照值来降序排列
# ....真是麻烦啊...如果有什么别的好办法还请告诉我

将boxplot降序或者升序排列,在fill = 变量非常多,把整个图拉的很长的情况下很有用,可以很明确的看出数据的规律。最好能在input dataframe的时候就把数据整理成一定顺序。

还有一个办法:

ggplot(t_long, aes(x = reorder(variable, value, FUN = median)), y = ...)
# 在ggplot的aes()里指定按照中位数大小排列
facet_grid():将一个Plot按照分组绘制多个Plot

使用一个R自带的数据集为例:data(ToothGrowth),这个数据集有两个分组,一个是supp, 一个是dose, 记得需要先把dose转化为factor再行后续操作。

t <- data(ToothGrowth)
t$dose <- as.factor(t$dose)
p2 <- ggplot(t, aes(x = supp, y = len, fill = supp)) +
  geom_boxplot(position = position_dodge(0.8)) +
  geom_point(position = position_jitterdodge()) +
  scale_fill_brewer(palette = "Set3") +
  facet_grid(dose ~ .,scales = "free") +     # 按照dose的分组将plot分成3个不同的dose子plot; scales的意思是按照各分组数据的极限值设置各子plot的scale, 不统一。
  theme(axis.title = element_text(size = 15), 
        axis.text.x = element_text(size = 15), 
        axis.text.y = element_text(size =12),
        strip.text.y = element_text(size = 12),     # 调整不同子plot的标签字体大小
        panel.spacing = unit(1, "lines")) +         # 调整不同子plot之间距离大小
  labs(x = "", y = "")
不设置facet_grid的图
设置facet_grid形成子plot

更多参考以下链接:
http://www.sthda.com/english/wiki/ggplot2-customize-how-to-personalize-easily-ggplot2-graphs-in-r-statistical-software
http://www.sthda.com/english/wiki/ggplot2-facet-split-a-plot-into-a-matrix-of-panels

ggplot2的一些通用规律
ggplot(dataframe, aes(x = X, y = Y, fill = group, color = group)) +      
  # 设置了fill则将"可以fill的形状"填充起来,比方说椭圆,比方说boxplot, barplot等。不设置fill什么颜色则ggplot2默认填充。用scale_fill_**设置填充颜色
  # color用于设置点或者线的颜色,比方说boxplot的外框描线...

  + geom_point(aes(color = group), alpha = 0.8, size = 4) 
  # 在aes()中设置点的颜色,但是点的透明度,大小等属性注意在aes()之外设置
  # 在aes()之外,position = position_jitterdodge()将点按照分组分开

  + geom_boxplot()
  + scale_color_manual(values = c(xxx,xxx,xxx...))
  # scale_color_**用于自定义color的颜色,即点,线的颜色

  + scale_fill_manual(values = c(xxx, xxx, xxx...))
  # scale_fill_**用于自定义fill的颜色,即填充颜色

PCoA:ade4和ggplot2

ade4包:以距离矩阵为input, 用cmdscale()获取坐标轴位置,用s.class画图并按照分组聚类。可是没有坐标轴信息,也不知道这两维分别可以有多少variance explained

unifrac <- read.table(...)
meta <- read.csv(...)

mds <- cmdscale(unifrac,k = 2, eig = TRUE)

mds_m <- mds$points
group <- as.factor(meta$grouping)  # 把分组信息转化为Factor
plot_color <- brewer.pal(5,"Set2")[group]   # 便于给每个样本分组并上色
s.class(mds_m, col=unique(plot_color), cpoint = 1, fac = group, cstar = 1, cellipse = 1) 
# 按照分组形成聚类椭圆(wheel)
# 用fake data画的

ggplot2包:需要把metadata和cmdscale()得到的mds坐标合并为一个dataframe作为input, 并使用上面ade4包得到的mds$eig计算variance explained
可以参考一篇宏基因组公众号的文章: 扩增子统计绘图2散点图:Beta多样性

eig <- mds$eig
mds_df <- data.frame(mds_m)
mds_meta <- cbind(mds_df, meta)

# X1, X2为各点坐标信息的col_name,grouping为分组信息的col_name
# 都在mds_meta中

ggplot(mds_meta, aes(x = X1, y = X2)) +
  geom_point(aes(color = factor(grouping)), size = 3) +
  scale_color_discrete(name = "grouping") +
  stat_ellipse(aes(x = X1, y = X2, color = grouping), type = "norm") +
  labs(x = paste("PCoA 1 (", format(100*eig[1]/sum(eig), digits = 4), "%)",sep = ""), 
       y = paste("PCoA 2 (", format(100*eig[2]/sum(eig), digits = 4), "%)",sep = "")
  )
# 手动添加variance explained的label
legend()用法
group <- as.factor(data$group)
color <- brewer.pal(length(levels(group)), "Set1")

heatmap.2(x...)

par(lend = 1)
legend(0.88, 0.998,  # 也可以直接指定:“bottomright”, “bottom”, “bottomleft”, “left”, “topleft”, “top”, “topright”, “right”, “center”
       legend = levels(group),    # 指定legend中写什么字
       col = color,  #指定颜色
       lty = 1,      # 显示为直线型色块
       lwd = 10,     # 显示色块的宽度
       text.col = "black",# legend字体颜色
       pch = c(.., .., .....)  # 如果你的legend lty没有设置,想设置成不同形状不同颜色的legend,则使用pch指定色块的形状,具体代码对应的形状见下图
       cex = 0.8)    # 设置字体大小
pch对应的具体形状

参考连接:https://www.rdocumentation.org/packages/graphics/versions/3.5.0/topics/legend

theme()快捷设置

default为+ theme_gray()
常用 theme_classic(), 详见以下链接
http://ggplot2.tidyverse.org/reference/ggtheme.html
theme_classic(size = n)设置默认classic的主题中字体大小

如何去掉legend title/legend

ggplot() + theme(legend.title=element_blank())
theme(legend.position = "none")则去除legend

给boxplot加上统计检验结果及P值

https://www.r-bloggers.com/add-p-values-and-significance-levels-to-ggplots/

ggarrange() 把图组合在一起,公用legend

ggarrange(plotlist = plot_list, ncol = 4, common.legend = TRUE)
如果有一个list of plots, 可以用ggarrange(plotlist...)
合并在一起,且可以公用legend, 设置legend的位置。

boxplot(fill = )和scale_fill_manual()

往往要在boxplot(fill=)中设置了颜色才可以显示!那要scale_fill_manul多么鸡肋!要你何用!

在boxplot之间连线

详见这个链接

ggplot(..) +
   geom_line(aes(group = interaction(index, variable)) +...
# index将要连接的点联系在一起 
geom_bar()

geom_bar(position = 'fill'/'dodge')
举个栗子:

library(socviz) # 用这里的gss_sm数据集
ggplot(data= gss_sm, aes(x=bigregion,fill=religion)) + 
  geom_bar(position='fill')

ggplot(data= gss_sm, aes(x=bigregion,fill=religion)) + 
  geom_bar(position='dodge')

分别得到:

另外:

  1. geom_bar()geom_histogram()的区别:
    histogram用于查看单个变量的distribution,当然也可以把几个变量的distribution放在一张图里,比较他们的分布。
    bar图用于查看多个变量的计数/占比/数值大小。
  2. geom_bar(stat = "identity")geom_col() 是一样的,都表示把对应的y值直接plot出来,不用做任何stat summary
geom_,geom_,geom_...

geom_dotplot()
geom_smooth() 平滑曲线,或者线性的直线
geom_pointrange(ymin=.. ,ymax=...) 给点加上range,比方说Sd, 你必须先准备好sd的数据,不能指望ggplot2给你做好。这里可以注意与dplyr的结合使用,提高效率,减少中间变量。
facet_wrap(~ variable, scales = "free_y", ncol = 1) 注意scales的用法

scale_, scale_,scale_

ggplot(aes(...))的完整是ggplot(mapping = aes(x = .., y =.., color = ..., fill = ... ...)), 每个mapping中的东西,都具有一个scale. x和y是连续型变量,其scale交给scale_x_log10(), scale_x_continuous()来调整。像mapping中的color, fill ,shape等, 需要scale_color_discrete()等来调整,比如以下这个例子:

library(socviz)
data(organdata) # 示例数据
ggplot(organdata, aes(x=roads, y= donors, color= world)) +
    geom_point() 

ggplot(organdata, aes(x=roads, y= donors, color= world)) +
    geom_point() +
    scale_color_discrete(labels = c("Corporatist", "Liberal", "Social Democratic", "Unclassified")) + 
    labs(x = "Road Deaths", y = "Donor Procurement", color = "Welfare State")

# scale_color_manual(name = "XXX", values = XXXcolors)
error bar

在ggplot2中实现有很多种方法,包括:
geom_pointrange()
geom_linerange()
geom_crossbar()
geom_errorbar()

在geom_boxplot()中去掉outlier

geom_boxplot(outlier.shape = NA) + ...

拼图之后加上一个总title
annotate_figure(ggarrange(plotlist = plotlist))
ggexport

ggexport %>%与ggplot2的object无缝衔接

ggarrange(...) %>%
    ggexport(filename=XXX,height=XX, width=XXX)
ggsignif (geom_signif())
ggplot(...) +
  geom_signif(test = 'wilcox.test',
              comparisons = XXX,
              vjust=0,  # significant level横线和P值数字之间的距离
              textsize = 6, # p值数字的大小
              size=0.5, # 横线的粗细程度
              step_increase=0, # 根据bar的总长度的一定比例,确定每个significant level要上升多少
              y_position = XXX, # c(), 固定好每个significant level的y轴坐标,推荐使用这个
              annotations = XXX  # P值内容,也可以换成*,**,***...
              )
geom_boxplot()画出来的box释义

参考:https://waterdata.usgs.gov/blog/boxplots/

stacked barchart和percentage stacked barchart
# 数据:
specie <- c(rep("sorgho" , 3) , rep("poacee" , 3) , rep("banana" , 3) , rep("triticum" , 3) )
condition <- rep(c("normal" , "stress" , "Nitrogen") , 4)
value <- abs(rnorm(12 , 0 , 15))
data <- data.frame(specie,condition,value)
ggplot(data,aes(fill=condition,y=value,x=specie))+
  geom_bar(position = 'fill',stat = 'identity')
ggplot(data,aes(fill=condition,y=value,x=specie))+
  geom_bar(position = 'dodge',stat = 'identity')


参考这个连接

sankey flow

https://cran.r-project.org/web/packages/ggalluvial/vignettes/ggalluvial.html
http://corybrunson.github.io/ggalluvial/reference/geom_flow.html
https://stackoverflow.com/questions/9968433/sankey-diagrams-in-r

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容