小提琴圖 (Violin Plot)是用來展示多組數(shù)據(jù)的分布狀態(tài)以及概率密度,是優(yōu)于箱線圖的一種統(tǒng)計圖形。他結(jié)合了箱線圖與密度圖,箱線圖位于小提琴圖內(nèi)部,兩側(cè)是數(shù)據(jù)的密度圖,能顯示出數(shù)據(jù)的多個細節(jié),而學(xué)會軟件來繪制精美的小提琴圖,則是科研中必備的手段。
一、前期準備
1. 所用軟件與版本:R 4.0.5
2. 所需R包:ggplot2 , cowplot, ggpub, magrittr
3. 示例數(shù)據(jù):iris數(shù)據(jù)集
二、繪制一張粗糙的violin plot
library(ggplot2)
p=iris %>% ggplot(aes(x=Species,y=Sepal.Length,fill=Species))+geom_violin()
p

這是針對iris數(shù)據(jù)集的Sepal.Length特征繪制的小提琴圖,大家調(diào)用ggolot函數(shù)就可以直接畫出來,其中x通常是因子列,y是要畫的特征,而fill是按照不同的類別分類填充,比如在這里fill=Species,說明按照Species(因子列,如果不是要提前用as.factor函數(shù)進行轉(zhuǎn)換),三個不同花的類別還選擇不同的顏色,這里沒有指定各自的顏色,ggolot默認是圖中的顏色。這時就有讀者問了,這哪里體現(xiàn)了箱線圖?別急,我們馬上添上去!
三、修圖
1. 去除后面背景,這里采用ggplot2中的bw主題
p=p+theme_bw()
2. 只顯示x軸和y軸,不顯示圖例
p=p+theme(legend.position="none",
axis.text.x = element_text(hjust = 0.5, vjust = 0.5),
axis.text.y = element_text(hjust = 0.5, vjust = 0.5),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_text( size=rel(1)),
panel.border = element_blank(),
axis.line = element_line(colour = "black",size=1)
)
3. 添加箱線圖
p=p+geom_boxplot(width=0.2,position=position_dodge(0.9),outlier.colour = NA,fill="white")
4. 改變默認顏色
color = c("#33B44A","#EE3536","#3A429B")
p=p+scale_fill_manual(values = color)
此時我們看下效果

這里給出完整代碼:
library(ggplot2)
color = c("#33B44A","#EE3536","#3A429B")
iris %>% ggplot(aes(x=Species,y=Sepal.Length,fill=Species))+geom_violin()+
geom_boxplot(width=0.2,position=position_dodge(0.9),outlier.colour = NA,fill="white")+
theme_bw()+
theme(legend.position="none",
axis.text.x = element_text(hjust = 0.5, vjust = 0.5),
axis.text.y = element_text(hjust = 0.5, vjust = 0.5),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_text( size=rel(1)),
panel.border = element_blank(),
axis.line = element_line(colour = "black",size=1)
)+scale_fill_manual(values = color)
四、添加不同類別間的pvalue
我們還想讓這張圖上顯示更多的信息:
● 添加比較兩組或多組的均值差異的pvalue
● 添加多組樣本的組間比較的pvalue
在這里我們運用Kruskal-Wallis檢驗和wilcox檢驗,具體原理,具體原理本文不做闡述,讀者請移步非參數(shù)統(tǒng)計的相關(guān)內(nèi)容。我們給出代碼,這里會用到ggpubr包。
library(ggplot2)
library(ggpubr)
color = c("#33B44A","#EE3536","#3A429B")
my_comparisons <- list( c("setosa", "versicolor"), c("versicolor", "virginica"), c("setosa", "virginica") )
iris %>% ggplot(aes(x=Species,y=Sepal.Length,fill=Species))+geom_violin()+
geom_boxplot(width=0.2,position=position_dodge(0.9),outlier.colour = NA,fill="white")+
theme_bw()+
theme(legend.position="none",
axis.text.x = element_text(hjust = 0.5, vjust = 0.5),
axis.text.y = element_text(hjust = 0.5, vjust = 0.5),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_text( size=rel(1)),
panel.border = element_blank(),
axis.line = element_line(colour = "black",size=1)
)+scale_fill_manual(values = color)+
stat_compare_means( comparisons = my_comparisons)+
stat_compare_means(label.y = 10)

我們還可以在stat_compare_means函數(shù)里面設(shè)置不同的參數(shù),這里默認使用wilcox檢驗,最后一個stat_compare_means函數(shù)還可以使用方差分析(method=""anova")。
關(guān)于為ggplot圖形添加pvalue更多的細節(jié),可以參考這位博主寫的文章:
數(shù)據(jù)可視化——R語言為ggplot圖形添加P值和顯著性水平_zhouhucheng00的博客-CSDN博客
五、多個小提琴圖組合
當我們想要畫多個特征,即多個小提琴圖組合成一張大圖,比如iris數(shù)據(jù)集中一共有四個特征,我們要將他們?nèi)堪凑丈厦娴漠嫹ㄙN在畫布上,通常我們用for循環(huán)處理,或者ggplot中有函數(shù)為facet_grid(),這里不做介紹(個人覺得在實際論文撰寫中,用facet_grid組合的圖形不是很好看)下面介紹我的處理方法,這里要用到cowplot包。
library(ggplot2)
library(ggpubr)
library(cowplot)
color = c("#33B44A","#EE3536","#3A429B")
my_comparisons <- list( c("setosa", "versicolor"), c("versicolor", "virginica"), c("setosa", "virginica") )
p=list()
sites = apply(iris[,-5], 2, function(x) max(x)+2.5)
for (i in colnames(iris)[1:4]) {
p[[i]]=iris %>% ggplot(aes_string(x="Species",y=i,fill="Species"))+geom_violin()+
geom_boxplot(width=0.1,position=position_dodge(0.9),outlier.colour = NA,fill="white")+
theme_bw()+
theme(legend.position="none",
axis.text.x = element_text(hjust = 0.5, vjust = 0.5),
axis.text.y = element_text(hjust = 0.5, vjust = 0.5),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_text( size=rel(1)),
panel.border = element_blank(),
axis.line = element_line(colour = "black",size=1)
)+scale_fill_manual(values = color)+
stat_compare_means( comparisons = my_comparisons)+
stat_compare_means(label.y = as.numeric(sites[i]))
}
plot_grid(plotlist = p,align = "h",labels = LETTERS[1:4])
ggsave("violin plots.pdf",height = 10,width = 10)

在這張圖的繪制中,由于用到了for循環(huán),我將aes改成了aes_string使得里面能以字符串的形式輸入,然后考慮到不同小提琴圖KW檢驗的pvalue位置要不同,所以在高度設(shè)置上我們?nèi)〔煌卣鞯淖畲笾?2.5,并且要使箱線圖都能在小提琴圖內(nèi)部,我們設(shè)置寬度為0.1,使得能兼顧到每一個小提琴圖。此外,最后的plot_grid函數(shù),我們制定align="h",表示按照行來組合圖形,并添加標號,當然也可以按列組合,具體可以查看plot_grid函數(shù)的相關(guān)參數(shù)。