一、簡介
ggplot2是R語言中四大著名繪圖框架之一,且因為其極高的參數設置自由度和圖像的美學感,即使其繪圖速度不是很快,但絲毫不影響其成為R中最受歡迎的繪圖框架;ggplot2的作者是現任Rstudio首席科學家的Hadley Wickham,ggplot2基於Leland Wilkinson在Grammar of Graphics(圖形的語法)中提出的理論,取首字母縮寫再加上plot,於是得名ggplot,末尾的2是因為Hadley寫包的一個習慣——對先前的版本不滿意便寫一個新版本的名稱不變僅在末尾加上2,如reshape2等;
按照《圖形的語法》一書中的觀點,一張統計圖形就是從數據到點、線或方塊等幾何對象的顏色、形狀或大小等圖形屬性的一個映射,其中還可能包含對數據進行統計變換(如求均值或方差),最后將這個映射繪制在一定的坐標系中就得到了我們需要的圖形。圖中可能還有分組,就是生成關於數據的不同子集的圖形。使用ggplot2繪圖的過程就是選擇合適的幾何對象、圖形屬性和統計變換來充分暴露數據中所含有的信息的過程;
因為ggplot2繪圖語法風格的迥然不同,使得其學習成本比其他繪圖包(包括基礎繪圖框架)要高不少,在剛開始上手的時候可能稍有難度(而且官網的幫助內容比較不友好),而本文也是我在日常使用和與別人交流中摸索和總結出來的,將對ggplot2的繪圖語法和繪圖部件進行介紹,並附以常用的一些圖形示例;
下面我們就來探索ggplot2的神奇之處~
二、從qplot開始
2.1 基礎圖形
用慣了基礎的繪圖函數之后,突然轉到ggplot2的繪圖風格,或多或少會有些摸不着頭腦,因此我們先從ggplot2中的qplot方法開始,這是一種語法規則和參數設置介於常規plot與ggplot2之間的一種繪圖函數;
與plot相似,qplot()的基本參數是x、y,分別代表所要繪制圖像的x軸與y軸,並且為了和數據框高度契合(我也十分鼓勵將變量都放進數據框中規整起來),qplot還提供了參數data,控制傳入的數據框名稱,這樣在qplot()中涉及數據框中變量的參數就可以直呼其名而不用加$;
在介紹qplot能夠繪制的其他幾何圖像之前,我們先來理解一下其默認的模式——繪制散點圖,以ggplot2中自帶數據集diamonds作為示例,這是一個關於50000多顆圓切鑽石各個指標的數據集,變量說明如下:
變量名 | 變量說明 |
price | 鑽石價格 |
carat | 鑽石重量 |
cut | 鑽石切削水平 |
color | 鑽石顏色 |
clarity | 鑽石的透明度 |
x | 鑽石長度 |
y | 鑽石寬度 |
z | 鑽石高度 |
depth | 深度百分比 |
table | 鑽石正上頂點距離最寬頂點距離 |
我們以探究鑽石重量carat與其對應價格price間關系為目的作圖:
library(ggplot2) data <- diamonds qplot(carat, price, data=data)
可以看出,qplot的默認圖像類型是散點圖,我們還可以對qplot中的數據參數傳入一些函數或計算式的:
qplot(log(carat), log(price), data=data)
qplot(carat, x*y*z, data=data)
同樣的,我們也可以對圖中的散點設置顏色、大小、形狀等參數,與plot不同的是,qplot中可以使用更加豐富的內容和更自由的賦參方法,我們可以傳入類別型數據,qplot會自動將其識別並分配對應到不同的顏色和不同的尺寸:
qplot(carat, price, data=data, colour=color)
qplot(carat, price, data=data, shape=cut)
而對於diamonds這種數量稍顯龐大的數據集,很多點在畫板上被重疊到一起,因此並不能正確的體現數據的情況,好在qplot中提供了控制散點透明度的參數alpha,通常會傳入I(分數)形式的參數代表基礎圖形的透明度,在散點圖形重疊的地方會進行透明度的無損累加使得其顏色變得很深:
qplot(carat ,price, data=data, alpha=I(1/20))
2.2 更多幾何圖像
上述的散點圖只是qplot中的參數geom的默認參數point(當x與y都有傳入值時的默認值,只有x傳入時是hist圖),這個參數用來控制圖形類型,值得一提的是,他幾乎涵蓋了所有的圖像類型,例如:
2.2.1 擬合曲線
當geom='smooth'時,將會擬合出一條平滑的曲線以及它的置信區間范圍:
qplot(carat, price,data=data,geom='smooth')
如果你希望散點和擬合圖共存時,可在geom中傳入向量形式來組合各個圖層,這也是ggplot2的繪圖思想的一個體現,以疊加繪圖元素的形式繪制一幅圖像:
qplot(carat, price, data=data, geom=c('point','smooth'))
若不想繪制置信區間,則可以設置se=FALSE:
而關於擬合曲線的形式,可以通過method參數自行確定,比如我們希望擬合出一條線性曲線,則可以傳入method='lm':
qplot(carat, price, data=data, geom=c('point','smooth'), method='lm')
也可以與其他包聯動起來,如在加載MASS包的情況下,傳入method='rlm',便可以以一種對異常值不敏感的擬合方式繪制擬合直線:
library(MASS) qplot(carat, price, data=data, geom=c('point','smooth'), method='rlm')
2.2.2 箱線圖
箱線圖作為一種經典的統計圖像,它以數據的五數概括作為特征對數據進行可視化,在qplot中,當傳入x為類別型變量,y為數值型變量時,通過傳入geom='boxplot',可以繪制出分組箱線圖,例如下面繪制鑽石顏色color與每顆鑽石每克拉價格price/carat的分組箱線圖:
qplot(color, price/carat, data=data, geom='boxplot')
我們還可以通過傳入參數colour來控制點與箱線邊框的顏色、通過傳入參數fill來控制箱線圖填充的顏色:
qplot(color, price/carat, data=data, geom='boxplot', alpha=I(1/5), colour=color, fill=color)
2.2.3 擾動點圖
僅通過箱線圖可能只能了解到五數概括的情況,而想要在類似的圖像結構中看出所有點的分布情況,可以選擇擾動點圖;
我們傳入geom='jitter'來繪制擾動點圖,這里我們增加透明度參數以更加真實地看出樣本點在各分組內的分布情況:
qplot(color, price/carat, data=data, geom='jitter', alpha=I(1/5))
我們還可以通過傳入colour參數來控制點的顏色:
qplot(color, price/carat, data=data, geom='jitter', alpha=I(1/5), color=color)
2.2.4 直方圖
通過傳入geom='histogram'可以來繪制直方圖,並利用參數binwidth來控制組距:
qplot(carat, data=data, geom='histogram', binwidth=1)
qplot(carat, data=data, geom='histogram', binwidth=0.01)
通過傳入參數fill來在一幅圖上繪制分組后的重疊的直方圖:
qplot(carat, data=data, geom='histogram', fill=color)
2.2.5 密度直線圖
通過傳入geom='density'來繪制密度直線圖:
qplot(carat, data=data, geom='density')
傳入colour來繪制分組的多條密度直線圖:
qplot(carat, data=data, geom='density', colour=color)
傳入fill來控制每個曲線下的填充顏色:
2.2.6 條形圖
設置geom='bar'可以繪制條形圖,當傳入單個離散類別型數據時,可以自動繪制每個類別的頻數統計條形圖:
qplot(color, data=data, geom='bar', fill=color)
2.2.7 時間序列圖
通過設置geom='line'可繪制線型圖,當傳入x為時間型數據時,即繪制出時間序列圖:
data("economics") data <- economics qplot(date, unemploy/pop, data=data, geom='line')
2.2.8 路徑圖
有時候我們關注的是某些變量之間的對應變化情況,這種時候路徑圖就可以實現,通過設置geom='path':
qplot(unemploy/pop, uempmed,data=data, geom=c('point','path'))
2.2.9 分面
有時候,我們希望繪制的不是同樣樣式的不同分組圖像在一幅圖上反復繪制的情況,,而是希望根據分組產生一頁多圖的形式,通過設置參數facets=sep_var~.可以實現,其中sep_var為分組依據的變量,例如下面我們以鑽石顏色為分組依據:
qplot(price,data=data, geom='density', facets = color~., colour=color)
2.2.10 其他參數
除了上面特殊的一些圖像外,qplot中還有很多基本的參數,如:
xlim,ylim:設置x軸與y軸的顯示區間
log:傳入字符型,用於控制將哪個軸轉成對數軸,'x'和'y'分別代表x軸與y軸,'xy'代表兩個軸都進行變化
main:設置圖形的主標題
xlab,ylab:設置x軸與y軸的名稱
三、ggplot2的圖形圖層語法
圖形圖層語法是ggplot2的語法基礎,它使得圖形的重復更新變得更簡單靈活,在遇到新問題時也許只需要照搬之前堆砌成的一個優美圖形全部代碼再稍加修改即可直接使用,下面我們就對ggplot2的語法規則進行探索:
3.1 ggplot2的繪圖過程
我們先來看一下ggplot2的繪圖過程:
僅根據上面的圖,你心中一定很是疑惑,沒關系,請你先短暫瀏覽上面這個過程,下面我們對這個過程進行一系列拆分,再回過頭來理解這個過程(接下來會連續使用到mpg數據集);
3.1.1 圖層
圖層,就是生成在基礎圖床上的一種圖形,它表現了信息的一種特點,例如:
library(ggplot2) data(mpg) data <- mpg qplot(displ, hwy, data=data)
這里,我們使用的圖層是散點層,也就是圖中的散點,目前為止它是我們這幅圖的第一層圖層,接下來,我們再添加上一層圖層:
qplot(displ, hwy, data=data)+
geom_smooth()
心細的你一定發現了,我們這里不同於前面傳入geom=c()的形式定義多個圖層,而是在先前函數的基礎上,+geom_smooth(),實現了圖層的疊加,類似的,我們還可以疊加更多圖層,雖然這看起來毫無意義。。。但請記住這種用法,這是疊加圖層的基礎;
qplot(displ, hwy, data=data)+ geom_smooth()+ geom_line()
3.1.2 標度
標度控制數據到圖形屬性的映射,每一個屬性都需要由標度x,y來驅動,才能實現從指定數據——指定圖層的映射,對應的,colour,shape等參數,也是由標度進行控制,再映射到對應圖層上的對應樣式顏色的變換,而ggplot2有一個特性,當傳入的屬性值非正常輸入時,譬如colour中輸入的是data中某列類別型變量時,整個繪圖過程不會有異常,因為ggplot2內部非常“寬容”地對類別型變量進行了標度轉換,如下例:
qplot(displ, hwy, data=data, colour=drv)+ geom_smooth()+ geom_line()
drv是一列字符型的數據,有f、r、4三種類型,坦白的說,若不是在這里進行繪圖,你很難將他們與顏色聯系在一起,但是這里他們的的確確被轉換為常規的顏色,換成shape也是一樣:
qplot(displ, hwy, data=data, shape=drv)
3.1.3 坐標系
坐標系即coord,可將對象的位置映射到圖形平面上,ggplot2中繪制的通常為2D圖像,即圖像的位置信息由(x,y)決定,且通常為笛卡爾坐標系,用得較少的是極坐標系和各種地圖坐標系;
坐標系最大的特點是,它可以同時影響所有的位置變量,譬如說,條形圖在笛卡爾坐標系中是規規矩矩的條形,但在極坐標系中,條形就變成了一個個扇形,據此可以構造南丁格爾玫瑰圖,如下例:
這是笛卡爾坐標系下的柱形圖:
qplot(cyl,data=data, geom='bar', fill=factor(cyl))
我們將其坐標軸更新為極坐標系,語法規則也比較明了,就是coord_polor():
qplot(cyl,data=data, geom='bar', fill=factor(cyl))+ coord_polar()
3.1.4 分面
分面前面也說過,是通過數據框中的某個特征為依據,構建不同的分塊圖形來展示數據的不同子集:
qplot(displ, hwy, data=data, facets = .~cyl, colour=factor(cyl))
3.1.5 數據結構
ggplot2通過其特殊的圖形語法,將整個圖形相關元素編碼到R的列表數據結構中,而一個完整的圖形對象就是一個由數據、映射、圖層、標度、坐標和分面組成的列表:
> p <- qplot(displ, hwy, data=data, + facets = .~cyl, + colour=factor(cyl)) > > summary(p) data: manufacturer, model, displ, year, cyl, trans, drv, cty, hwy, fl, class [234x11] mapping: colour = factor(cyl), x = displ, y = hwy faceting: <ggproto object: Class FacetGrid, Facet> compute_layout: function draw_back: function draw_front: function draw_labels: function draw_panels: function finish_data: function init_scales: function map: function map_data: function params: list render_back: function render_front: function render_panels: function setup_data: function setup_params: function shrink: TRUE train: function train_positions: function train_scales: function super: <ggproto object: Class FacetGrid, Facet> ----------------------------------- geom_point: na.rm = FALSE stat_identity: na.rm = FALSE position_identity
而對於ggplot2中的繪圖,有兩種方式:一是在qplot中一步到位配置好所有的參數以產出所需的圖像;另一種是利用ggplot逐層定義繪圖部件,並用加號連接,保存到一個對象里,再使用print這個對象的方法將其呈現在屏幕上,或是用ggsave函數將圖像文件按照設置的尺寸保存在外存里,用summary查看其數據結構,
3.2 通過ggplot()用圖層來構建圖像
前面我們依次介紹了ggplot2圖層語法中的各種主要結構,但僅使用了qplot()進行繪圖,其局限性是只能使用在qplot()中定義的一個數據集和對應的一組圖形屬性映射,若希望將不同的數據通過不同的圖層構建方式來展現在一張圖上,就需要使用ggplot()函數,該函數有兩個主要的參數,對應了數據和圖形屬性映射,這兩個參數將作為接下來繪圖的默認參數,直到在新加的圖層中設定了新的參數,默認值才會被修改‘;其中,數據指定繪圖所使用的默認數據框且必須是數據框;映射的設定則與qplot非常相似,只需要將圖形屬性和變量名放到函數aes()內即可,但要注意,這里不像qplot默認的圖層為散點圖,使用ggplot時如果不+geom_部分,則沒有圖層會被創建,例如:
library(ggplot2) data(mpg) data <- mpg #未加上圖層部件 p <- ggplot(data=data, aes(displ, hwy)) print(p)
#加上圖層部件 p <- ggplot(data=data, aes(displ, hwy))+ geom_point() print(p)
3.2.1 圖層
在定義了基礎的ggplot()后,我們通過+圖層函數的方式添加圖層,這里只介紹快捷函數的方式,其主要形式為geom_XXX(mapping,...,stat,position),其中mapping是可選的圖形屬性映射,若想要在圖層中展現新的數據和參數,則可以在geom_XXX()中指明aes()形式的mapping即可:
p <- ggplot(data=data, aes(displ, hwy))+ geom_point(mapping = aes(shape=factor(cyl)))+ geom_smooth(mapping = aes(displ,hwy,colour=factor(cyl))) print(p)
上面的示例中,我們在ggplot中創建了基礎的數據映射之后,又接連添加了兩個圖層,第一個圖層繪制出以因子轉化后的cyl為shape的散點圖,第二個圖層繪制出以因子轉化后的cyl為colour的光滑擬合曲線,這時summary我們的p也可以觀察到分圖層的各圖層信息:
我們還可以使用更多的擴展包來豐富ggplot2圖層內的參數:
library(scales) p <- ggplot(data,aes(displ,hwy))+ geom_smooth(method='lm', se=F, colour=alpha('steelblue',0.5), size=2)+ geom_point() print(p)
3.2.2 數據
ggplot2只接受數據框輸入,而且,對於一個已經創建好的基於數據框1的繪圖對象p,可以用p %+% 數據框2 的形式直接替代原來的數據集:
library(ggplot2) data <- mtcars p <- ggplot(data = data,aes(mpg,wt, colour=cyl))+ geom_point()+ labs(title='變換前')+ theme(plot.title = element_text(hjust = 0.5)) p #對原數據集數據內容進行改造 mtcars <- transform(mtcars, mpg = mpg^2) p %+% mtcars + labs(title='變換后')+ theme(plot.title = element_text(hjust = 0.5))
*這里labs用於修改標題,theme(plot.title=element_text(hjust=0.5))用於決定標題居中
要注意的是,轉換后的數據集中若涉及連續型與離散型間的轉換,就需要注意一下,因為有些圖在這種情況會因為不兼容的原因而繪圖失敗。
3.2.3 關於aes映射需要注意的一些情況
1、aes中設置colour與aes外設置colour不同
在aes外面設置colour時,是正常的參數,沒有強制標度轉換的過程,如下:
p <- ggplot(data=data,aes(mpg,wt))+ geom_point(color='darkblue') p
而在aes內部設置colour時,它會將傳入的代表顏色的字符型'darkblue'當成一個變量來看待,由於其為單個字符串,於是便被映射為色輪上的起點也即是紅色:
p <- ggplot(data=data,aes(mpg,wt))+ geom_point(aes(colour='darkblue')) p
由此你可以看出,aes中的參數都是會依據變量類型進行標度轉換的;
2、每次新圖層中的數據都是在ggplot()中默認值的修改
在ggplot()中已經設置過aes(x,y)之后,后續圖層則僅需要根據實際需求修改部分,比如我在新的圖層中僅需要改變y,則只需要在該圖層語句中aes(y=new_y)即可;
3.2.4 幾何對象
所謂幾何對象,簡稱geom,我們在前面也提到過,並多次使用過,它控制生成的圖像類型;
3.2.5 位置調整
位置調整指的是對該層中的元素位置進行微調,ggplot2中所有可用的位置調整參數如下:
名稱 | 描述 |
dodge | 禁止重疊,並排放置 |
fill | 堆疊元素並將高度放縮為1 |
identity | 不做任何調整(就像神經網絡里的identity激活函數一樣) |
jitter | 給點添加擾動避免重合 |
stack | 將圖形元素堆疊起來 |
而上述這些位置參數通常是應用在條形圖中,下面一一進行展示:
p <- ggplot(data,aes(am,fill=factor(cyl)))+ geom_bar(position = 'dodge')+ labs(title='並排放置時')+ theme(plot.title = element_text(hjust=0.5)) p
p <- ggplot(data,aes(am,fill=factor(cyl)))+ geom_bar(position = 'fill')+ labs(title='高度放縮為1時')+ theme(plot.title = element_text(hjust=0.5)) p
p <- ggplot(data,aes(factor(am),fill=factor(cyl)))+ geom_bar(position = 'identity')+ labs(title='不做任何處理時')+ theme(plot.title = element_text(hjust=0.5)) p
p <- ggplot(data,aes(factor(am),fill=factor(cyl)))+ geom_bar(position = 'jitter')+ labs(title='添加隨機擾動時')+ theme(plot.title = element_text(hjust=0.5)) p
p <- ggplot(data,aes(factor(am),fill=factor(cyl)))+ geom_bar(position = 'stack')+ labs(title='堆疊時')+ theme(plot.title = element_text(hjust=0.5)) p
以上就是關於ggplot2的基本內容,如有筆誤,望指出。