R語言最擅長繪圖。R語言最擅長的繪圖包是ggplot2,由于很多朋友沒有接觸過ggplot2,必須要對其語言方式有個初步的認識。所以入門學習是必須的。公眾號先前若干篇文章已經介紹ggplot2繪圖的基本方法(具體可以關注文末鏈接),為推動學習,今天介紹再次系統的一番。
ggplot2包是R的一個作圖用的最精彩的擴展包,它實現了“圖形的語法”,將一個作圖任務分解為若干個子任務,只要完成各個子任務就可以完成作圖。在作常用的圖形時,只需要兩個步驟:首先將圖形所展現的數據輸入到ggplot()函數中,然后調用某個geom_xxx()函數,指定圖形類型,如散點圖、曲線圖、盒形圖等。
如果需要進一步控制圖形細節,只要繼續調用其它函數,就可以控制變量值的表現方式(scale)、圖例、配色等。這使得我們很容易做出基本的圖形,在有需要時再深入學習,做出更為滿意的圖形。
與基本R中的作圖系統相比,?ggplot2的作圖有規律可循,作圖結果直接達到出版印刷質量,除了可以按照一些既定模式做出常見種類的圖形,也很容易將不同圖形種類組合在一起,或者設計新穎的圖形。基本R的作圖結果通常不夠美觀,如果要將不同種類圖形組合在一起比較困難,對設計新的圖形類型支持也不夠好。
ggplot2 的繪圖理念與基礎的繪圖有很大的不同,基礎的繪圖就好像是先鋪好畫布,然后在畫布上畫圖,是一個平面的,而ggplot2打破了這種畫圖的方式 ,采用了圖層的概念進行畫圖,先畫好基礎圖,然后再往上一層一層的疊加圖層,所以在進行ggplot2畫圖的時候,代碼中會有大量的“+”,這就是對于圖層的疊加。本章將大致的給大家介紹醫學數據應用ggplot2基本的結構。
ggplot2 圖層元素
1.數據(data):將要可視化的數據
2.映射(aes):數據中的變量值
3.幾何對象(geom):如bar條形圖,point散點圖
4. 統計變換(stats):對數據進行計算
5.標度(scale):變量以什么形狀、顏色映射到圖形上
6. 分面(facet):將數據拆開,進行分層畫圖
7. 主題(theme):主題設定,與數據無關的圖層可以通過這個函數實現。
8. 注釋 (annotate): 對圖形增加文字類的注釋
ggplot()圖層
ggplot ()圖層包括數據和映射。ggplot函數相當于一幅基本的畫布,畫者在上面繪制好坐標軸,設置好基本的格局和色彩、線條。
geom_XXX()?圖層
geom_XXX()?指的是我們要繪制的圖形類型,常見包括以下:
geom_point()繪制散點圖
geom_bar()繪制條形圖
geom_line()繪制線圖
geom_histogram()繪制直方圖
geom_boxplot() 繪制箱式圖
geom_density() 繪制概率密度函數
scale_?XXX 圖層
scale_?XXX?標度是一種函數,size對大小進行調整,shape對形狀進行調整,fill、col對顏色進行調整,可根據自己喜好調整
ggplot(data?=數據?,??aes(x?=變量1?,?y?=?變量2,col=變量3))?+
? ? ?geom_point(stat?=?'count',position=”dodge”)+ ?#計數、并排
? ? ?scale_fill_manual(values = c("顏色1","顏色2"))
facet_grid() 圖層
facet_grid(...)?對圖層進行分面,數據分成多個子集進行繪圖
ggplot(data?=數據?,??aes(x?=變量1?,?y?=?變量2,col=變量3))?+
geom_point(stat?=?'count',position=”dodge”)+
scale_colour_manual(values = c("顏色1","顏色2"))+
facet_grid(變量4~變量5) #要求變量屬于分類變量,分成多行多列的圖
theme() 圖層
theme()?是主題修改,是一個對繪圖精雕細琢的過程, 主要對標題、坐標軸標簽、圖例標簽等文字調整, 以及網格線、背景、軸的顏色搭配。
theme(plot.title =?element_text(size =?, color =, hjust =?, face =?))
ggplot2的作圖一般步驟為:
·?準備數據,一般為數據框,且一般為長表,即每個觀測時間占一行,每個觀測變量占一列。
·?載入R包,R包括可以通過tidyverse包整體載入。
·??將數據輸入到ggplot()函數中,并指定參與作圖的每個變量分別映射到哪些圖形特性,比如映射為x坐標、y坐標、顏色、形狀等。這些映射稱為aesthetic mappings或aesthetics。
很多人不明白所謂的映射。其實映射,通俗來講,就是告訴軟件,這幅圖所涉及到的變量,并且指出每個變量的用途。比如,x=gender,指的是x軸是性別;y=age,指的是y軸表示年齡大小,shape=location,指的是不同地區圖標的形狀不一樣(比如城市用星號,農村用三角)
·???選擇一個合適的圖形類型,函數名以geom_開頭,如geom_point()表示散點圖。圖形類型簡稱為geom。將ggplot()部分與geom_xxx()部分用加號連接。到此已經可以作圖,下面的步驟是進一步的細化設定。
·???設定適當的坐標系統,如coord_cartesian(),?scale_x_log10()等。仍用加號連接。
·????設定標題和圖例位置等,如labs()。仍用加號連接。
這個流程的一個大致的模板為:
p <-ggplot(data=<輸入數據框>,
? ???mapping=aes(<維度>=<變量名>,
? ? ?<維度>=<變量名>,?<...>))
p?+geom_<圖形類型>(<...>)?+
?scale_<映射>_<類型>(<...>)?+
?coord_<類型>(<...>)?+
?labs(<...>)
其中<...>表示額外的選項。變量p包含做出的圖形的所有數據與設定,變量名可以任意取。
我接下來講引用R語言自帶數據庫,以散點圖為例,進行ggplot2繪圖。
本文數據集來自gapminder擴展包的gapminder數據集,有若干個國家不同年份的一些數據,包括所屬洲、期望壽命、人口數、人均GDP。有1704個觀測和6個變量。數據庫的變量包括country(國家)?、continent(洲)、year(年)、lifeExp(期望壽命)、pop(人口數)、gdpPercap(人均GDP)
library(gapminder)
head(gapminder,?6)
# A tibble: 6 x 6
country???? continent? year lifeExp????? pop gdpPercap
?<fct>????? ?<fct>? ???<int>? ?<dbl>?? ?<int>??? ?<dbl>
1 Afghanistan Asia????? ?1952??? 28.8?8425333????? 779.
2 Afghanistan Asia????? ?1957??? 30.3?9240934????? 821.
3 Afghanistan Asia????? ?1962??? 32.0 10267083????? 853.
4 Afghanistan Asia????? ?1967??? 34.0 11537966?? ???836.
5 Afghanistan Asia????? ?1972??? 36.1 13079460????? 740.
6 Afghanistan Asia????? ?1977??? 38.4 14880372????? 786.
這個數據集有多個國家在多個年份的期望壽命與人均GDP值,作期望壽命對人均GDP的散點圖,每個國家的每個年份作為一個點。散點圖最重要的映射是x軸與y軸兩個維度。
1. 最基本的散點圖
首先調用繪圖基本函數ggplot()函數,指定數據集,將人均GDP映射到x軸,將期望壽命映射到y軸,結果保存為一個R變量:
p <-ggplot(data =?gapminder,
?mapping =aes(
???x =?gdpPercap,
???y =?lifeExp))
ggplot()的調用中,可以省略data =,?mapping =,?x =,?y =,寫成:
p <-ggplot(gapminder,?aes(gdpPercap, lifeExp))
ggplot函數,相當于一幅基本的畫布,畫者在上面繪制好坐標軸,設置好基本的格局和色彩、線條。
在如上指定了數據和映射后,只要用geom_xxx()指定一個圖形類型,并與ggplot()的結果用加號連接就可以作圖了,如:
p?+geom_point()
x、y軸是最常見的映射,也可以將變量映射為顏色、符號、線型等,這時不需要指定具體的顏色、符號、線型,而是將變量映射為這些圖形元素類型。
2. 更多的美圖
指定數據集、指定映射、選擇適當的圖形類型就可以做出基本的圖形,隨后可以逐步對坐標系、坐標系刻度、標簽與圖例、配色等進行改善。實際上,ggplot2包已經提供了十分合理的預設值,用戶只要進行一些必要的改動即可。
作圖步驟之間用加號連接,這是ggplot包特有的語法。例如,用相同的映射基于geom_smooth()?做出擬合曲線圖:
p?+geom_smooth()
## `geom_smooth()` using method ='gam' and formula 'y ~ s(x, bs = "cs")'
用相同的映射做出散點圖并疊加擬合曲線圖:
p?+geom_point()?+geom_smooth()
## `geom_smooth()` using method ='gam' and formula 'y ~ s(x, bs = "cs")'
geom_smooth()的默認設置調用了gam()函數來擬合曲線,可以用geom_smooth()的參數選擇不同的擬合方法,如直線擬合:
p?+geom_point()?+geom_smooth(method="lm")
注意geom_xxx()函數計算所需的變量值是從ggplot()函數保存在變量p中的信息提取的。
在以上的所有圖形中,?x軸變量(人均GDP)分布非正態,嚴重右偏,使得大多數散點重疊地分布在直角坐標系的左下角。將x軸用對數刻度可以改善,函數為scale_x_log10():
p?+geom_point()?+
?geom_smooth(method="gam")?+
?scale_x_log10()
廣義可加模型擬合的曲線基本是一條直線。注意,對數刻度實際上是對原始數據進行對數變換,而geom_smooth()的擬合計算是在對數變換之后進行的。
剛剛的圖形的橫坐標軸刻度不太友好,可以調用scales擴展包的適當函數進行改善,作為scale_x_log10()的labels選項:
p?+geom_point()?+
?geom_smooth(method="gam")?+
?scale_x_log10(labels=scales::dollar)
scale_xxx()的labels選項指定如何標出坐標刻度數字,參數值是一個函數對象,如果scales包中找不到適當的功能,可以自定義一個函數將數值轉換為字符串。?scales包提供了comma,??date,?dollar,??math,number,?ordinal,?pvalue,?scientific,?time?等坐標刻度值轉換函數。
4. 在geom_point()和geom_smooth()加點簡單元素
geom_xxx()函數接受許多關于顏色、透明度、符號、線型的設置參數。比如,下面的程序指定了散點的透明度,以及散點圖的顏色的粗細:
p <-ggplot(data=gapminder,
?mapping =aes(
???x =?gdpPercap,
???y =?lifeExp))
p?+geom_point(color="chartreuse4",alpha=0.5)?+
?geom_smooth(method="loess")?+
?scale_x_log10(labels=scales::dollar)
當然,也可以對geom_smooth()玩一把
p?+geom_point(color="chartreuse4",alpha=0.5)?+
?geom_smooth(color="cadetblue1",?se =FALSE,?size =2,?alpha =0.3)?
程序中size指定了線的以毫米為單位的粗細,?se = FALSE關閉了置信區間顯示。用alpha =設置了透明度,取0和1之間的值,數值越小越透明。在有許多個點時適當設置透明度可以比較好地顯示出重疊的點,重疊點越多點的顏色越深。雖然這里設置了固定的透明度,也可以在aes()中將透明度alpha映射到某個變量,使得該變量值大小用點的透明度表示。
畫線時可以用linetype參數指定線型,?0表示實線,?1到6分別表示不同的虛線線型。
最后,來一個下面用labs()函數給圖形加上適當的標題:
p?+geom_point(color="chartreuse4",alpha=0.5)?+
?geom_smooth(color="cadetblue1",?se =FALSE,?size =2,?alpha =0.3)?
labs(
???x ="人均GDP",
???y ="期望壽命(年數)",
???title ="經濟增長與期望壽命",
???subtitle ="數據點為每個國家每年",
???caption ="數據來源: gapminder"? )
3.顏色、符號、線型等映射
在ggplot()函數的mapping參數的aes()設定中將變量映射到x、y軸,顏色、符號、線型等圖形元素類型,也可以作為圖形設置將某些圖形元素設置為固定值。
例如,用不同顏色表示不同大洲,就是將continent變量映射到color:
p <-ggplot(data=gapminder,
?mapping =aes(
???x =?gdpPercap,
???y =?lifeExp,
???color =?continent))
程序中僅指定了將大洲映射到顏色維,并不具體指定所用的顏色。
作帶有局部多項式曲線擬合的散點圖:
p?+geom_point()?+
?geom_smooth(method="loess")?+
?scale_x_log10(labels=scales::dollar)
可以看出,不同散點用了不同顏色表示其continent變量的值,五個大洲分別進行了曲線擬合,曲線使用了不同顏色但置信域顏色相同,使得難以認讀。在圖形右側自動生成了顏色與continent變量值的對應關系圖例。
下面的圖形仍分不同大洲作曲線擬合,并將置信區間陰影的顏色也用不同大洲區分,方法是在aes()中將color和fill都指定為變量continent:
p <-ggplot(data=gapminder,
?mapping =aes(
???x =?gdpPercap,
???y =?lifeExp,
???color =?continent,
???fill =?continent))
p?+geom_point()?+
?geom_smooth(method="loess")?+
?scale_x_log10(labels=scales::dollar)
4. 在geom_xxx() 映射變量
在前面的一個例圖中,在ggplot()函數中將color和fill映射到了continent變量,使得不僅散點顏色代表了不同大洲,還使得每個大洲單獨擬合了曲線。如果希望所有大洲擬合同一條曲線怎么辦?
在必要時,可以在geom_xxx()函數中用mapping = aes(<...>)單獨指定變量映射。例如,下面的程序在geom_point()中將不同大洲映射為不同顏色,而不影響geom_smooth()中的顏色以及分組:
p <-ggplot(data=gapminder,
?mapping =aes(
???x =?gdpPercap,
???y =?lifeExp))
p?+geom_point(mapping =aes(color =?continent))?+
?geom_smooth(method="loess")?+
?scale_x_log10(labels=scales::dollar)
也可以將一個分類變量映射到不同繪圖符號。例如,取gapminder 2007年數據子集,將大洲映射到符號(shape):
p <- ggplot(data = filter(gapminder,year==2007),
??????????? mapping = aes(
????????????? x = gdpPercap,
????????????? y = lifeExp))
p + geom_point(mapping =aes(shape = continent), alpha = 0.4, size = 4) +
?scale_x_log10(labels=scales::dollar)
這種映射僅適用于點數比較少的情況,太多密密麻麻不好看(為此我們用了filter函數抽取2007年的數據),還用了size參數指定符號的大小(單位:毫米)。如果所有點使用同一符號并需要指定符號,可以在geom_point()中用shape參數指定,可以用0到25的整數值表示,比如19為實心點,也可以用字符串符號名稱表示,如"circle"表示實心點。參見ggplot2幫助目錄中的vignette ggplot2:ggplot2-specs。
也可以將連續變量映射為漸變色。除了表示二元函數的等值線圖以外這種方法并不利于讀者認讀。
例如,將人口數取自然對數映射為漸變色:
p <-ggplot(data=gapminder,
?mapping =aes(
???x =?gdpPercap,
???y =?lifeExp,
???color =log(pop)))
p?+geom_point()?+
?geom_smooth(method="loess")?+
?scale_x_log10(labels=scales::dollar)
5.小圖
前面所有國家的圖包含了過多的曲線, 使得圖形表現得很擁擠。可以將一個作圖區域拆分成若干個小塊, 稱為小圖(facet), 按照某一個或兩個分類變量的不同值將數據分為若干個子集, 每個數據子集分別在小圖上作圖。
對于上面的例子, 可以將每個大洲的圖形分別放置在一個小圖上。小圖不是一種變量映射, 而是一種圖形擺放方法, 所以不設置在aes()函數內, 而是用facet_wrap()函數規定。?程序如:
p <-ggplot(data=gapminder,
????????? ?????mapping =aes(
? ?????????????x = gdpPercap,
???????????? ???y = lifeExp,
???????????? color= continent))
p +geom_point() +
??? geom_smooth(method="loess") +
???? scale_x_log10(labels=scales::dollar)+
facet_wrap(~ continent, ncol = 2)
區分不同小圖的標簽寫在每個小圖的上方。可以用facet_wrap()參數strip_position和參數switch調整標簽的上下左右。
小圖之間默認公用了橫坐標和縱坐標且坐標范圍保持一致。如果不保持一致, 讀者可能會有誤解。但是x軸或y軸映射為分類變量且不同小圖的分類完全不同時, 可以令各小圖中該軸的取值不統一。facet_wrap()選項scales默認為"fixed", 即所有小圖的x軸、y軸都范圍一致, 取"free_x"則允許各小圖的x軸不統一,?"free_y"允許各小圖的y軸不統一,?"free"允許各小圖的x軸和y軸都不統一。
在facet_wrap()中可以用ncol參數指定小圖的列數, 用nrow指定小圖的行數。各個小圖的次序應該設定為一定的合理次序, 比如用來分類的變量本身有序, 或者令各小圖中的數據值有一定的增減次序。
6.總結
ggplot2的不僅僅是能夠做一些固定格式的圖形, 而是按照一種圖形語法構建圖形。小圖功能可以將數據集分成若干子集作多幅小圖, 每幅小圖中, 有可以分層, 每層有不同類型的圖, 各層疊加顯示在一起。所以,分層語法作圖結構如下:
有一個主要的數據集, 以及從數據集變量到坐標位置、顏色、填充、大小、符號等的映射關系(aesthetics);
有一到多個圖層, 比如散點圖和平滑曲線圖層, 每個圖層有幾何對象、必要的統計變換、位置調整, 還可以有額外的數據集以及額外的映射關系;
對每個映射關系有一個刻度(scaling), 對x、y維,一般需要線性變換,偶爾用到對數變換之類的其它變換, 顏色、填充等維度需要一些復雜的對應關系。無特殊需要時只要使用默認刻度;
有一個坐標系統, 如直角坐標系、極坐標系、球面坐標系等, 一般只要使用默認的坐標系統;
可以劃分小圖(facetting)。
利用繪圖語法既可以做出常見的統計圖形, 也可以做出各種新穎的圖形, 當然, 就像語法正確的語句不一定有意義, 用繪圖語法做得新穎圖形不一定有實際意義, 還是要按照可視化的一般原則做出能說服讀者的圖形