用于繪圖的R語言擴展包:ggplot2
I. 導論
1 什么是ggplot2
ggplot2是用于繪圖的R語言擴展包,其理念根植于《Grammar of Graphics》一書。它將繪圖視為一種映射,即從數學空間映射到圖形元素空間。例如將不同的數值映射到不同的色彩或透明度。該繪圖包的特點在于并不去定義具體的圖形(如直方圖,散點圖),而是定義各種底層組件(如線條、方塊)來合成復雜的圖形,這使它能以非常簡潔的函數構建各類圖形,而且默認條件下的繪圖品質就能達到出版要求。
2 與lattice包的比較
ggplot2和lattice都屬于高級的格點繪圖包,初學R語言的朋友可能會在二者選擇上有所疑惑。從各自特點上來看,lattice入門較容易,作圖速度較快,圖形函數種類較多,比如它可以進行三維繪圖,而ggplot2就不能。ggplot2需要一段時間的學習,但當你跨過這個門檻之后,就能體會到它的簡潔和優雅,而且ggplot2可以通過底層組件構造前所未有的圖形,你所受到的限制只是你的想象力。
建議兩種繪圖包都可以研究一下。如果時間緊張,需要在一兩天之內為論文做一張圖,那么推薦用lattice,如果時間充裕,推薦學習ggplot2。
3 基本概念
- 圖層(Layer):如果你用過photoshop,那么對于圖層一定不會陌生。一個圖層好比是一張玻璃紙,包含有各種圖形元素,你可以分別建立圖層然后疊放在一起,組合成圖形的最終效果。圖層可以允許用戶一步步的構建圖形,方便單獨對圖層進行修改、增加統計量、甚至改動數據。
- 標度(Scale):標度是一種函數,它控制了數學空間到圖形元素空間的映射。一組連續數據可以映射到X軸坐標,也可以映射到一組連續的漸變色彩。一組分類數據可以映射成為不同的形狀,也可以映射成為不同的大小。
- 坐標系統(Coordinate):坐標系統控制了圖形的坐標軸并影響所有圖形元素,最常用的是直角坐標軸,坐標軸可以進行變換以滿足不同的需要,如對數坐標。其它可選的還有極坐標軸。
- 位面(Facet):很多時候需要將數據按某種方法分組,分別進行繪圖。位面就是控制分組繪圖的方法和排列形式。
4 一個例子
下面用ggplot2包內帶的汽車測試數據(mpg)來舉個例子,用到的三個變量分別是發動機容量(displ)、高速公路上的每加侖行駛里數(hwy)、汽缸數目(cyl)。首先加載ggplot2包,然后用ggplot定義第一層即數據來源。其中aes參數非常關鍵,它將displ映射到X軸,將hwy映射到Y軸,將cyl變為分類數據后映射為不同的顏色。然后使用+號添加了兩個新的圖層,第二層是加上了散點,第三層是加上了loess平滑曲線。
library(ggplot2) p <- ggplot(data=mpg,aes(x=displ,y=hwy,colour=factor(cyl))) p + geom_point() + geom_smooth()

上圖是對幾種不同汽缸的數據分別平滑,如果需要對整體數據進行平滑,可將colour參數設置在散點圖層內而非第一層,這樣第三層的平滑圖形就不會受到colour參數的影響。
p <- ggplot(mpg,aes(x=displ,y=hwy)) p + geom_point(aes(colour=factor(cyl))) + geom_smooth()

II. 圖層控制與直方圖
ggplot2使用圖層將各種圖形元素逐步添加組合,從而形成最終結果。第一層必須是原始數據層,其中data參數控制數據來源,注意數據形式只能是數據框格式。aes參數控制了對哪些變量進行圖形映射,以及映射方式,aes是Aesthetic的縮寫。
下面我們來繪制一個直方圖作為示例。數據集仍采取mpg,對hwy變量繪制直方圖。首先加載了擴展包,然后用ggplot函數建立了第一層,hwy數據映射到X軸上;使用+號增加了第二層,即直方圖對象層。此時p被視為一種層對象,使用summary函數可得到關于它的更多信息,print(p)命令即可進行繪圖。
p <- ggplot(data = mpg,aes(x = hwy)) p <- p + geom_histogram() summary(p)
data: manufacturer, model, displ, year, cyl, trans, drv, cty, hwy, fl, class [234x11] mapping: x = hwy faceting: facet_grid(. ~ ., FALSE) ----------------------------------- geom_histogram: stat_bin: position_stack: (width = NULL, height = NULL)
上面的信息告訴我們,p對象含有兩層,第一層數據層描述了變量和映射方式,第二層是直方圖對象(geom_histogram),geom表示幾何對象,它是ggplot中重要的圖層控制對象,因為它負責圖形渲染的類型。geom_histogram是圖形渲染類型的一種,其它類型可參見官網。
每個geom對象都需要有數據輸入,數據可以從第一層中自動讀取,也可以在aes參數中直接設置。而且每個geom還默認搭配某種統計變換(stat),geom_histogram的默認統計變換是stat_bin。它負責對數據進行分組計數。
下面我們嘗試兩種更為復雜的直方圖,首先將數據按照year這個變量劃分為兩組,用不同的顏色繪制直方圖,而且用頻率而非計數來刻畫Y軸,并添加密度曲線。
p <- ggplot(mpg,aes(hwy)) p + geom_histogram(position = 'identity', alpha=0.5, aes(y = ..density.., fill = factor(year))) + stat_density(geom = 'line', position = 'identity', aes(colour = factor(year)))

如果想將兩個直方圖分開繪制,也可以使用facet_grid參數,結果如下圖所示。
III. 位置調整與條形圖
位置調整(Position adjustments)是針對同一圖層內元素的位置進行微調的方法。它包括五種設置,分別是stack、dodge、fill、identity、jitter。
我們用條形圖來展示其用法,仍使用mpg數據集,其中用到的變量是class,即生產汽車的類型,以及year生產年份。下面的條形圖是將各類型的汽車數量進行匯集,并以年份作為分組變量。我們首先載入擴展包,然后用頻數表對數據進行大致的了解,最后繪制了四種條形圖。
library(ggplot2) with(mpg,table(class,year)) p <- ggplot(data=mpg,aes(x=class,fill=factor(year))) p + geom_bar(position='dodge') p + geom_bar(position='stack') p + geom_bar(position='fill') p + geom_bar(position='identity',alpha=0.3)



可以看到dodge方式是將不同年份的數據并列放置;stack方式是將不同年份數據推疊放置,這也是geom_bar的默認處理方式;fill方式和stack類似,但Y軸不再是計數,而是以百分比顯示;identity方式是不做任何改變直接顯示出來,所以需要設置透明度才能看得清楚。
geom_bar是繪制條狀幾何對象,所以也可以用不經匯集的原始數據進行繪圖。下面我們用2001到2010年間的美國GDP增長率舉個例子。
y=c(1.1,1.8,2.5,3.6,3.1,2.7,1.9,-0.1,-3.5,3.0) x=2001:2010 data=data.frame(x,y) p=ggplot(data,aes(x,y,fill=y)) p+geom_bar(stat="identity")+ geom_abline(intercept = 0, slope = 0,size=1,colour='gray')+ geom_text(aes(label=y),hjust=0.5, vjust=-0.5 )+ scale_y_continuous(limits=c(-3.8,4.2))+ labs(x='年份', y='GDP增長率%')+ opts(title = "美國GDP增長率")

IV. 散點圖
1 色彩和形狀的控制
數據特征不僅可以用坐標來表示,也可以用不同的色彩或形狀來表示。仍以mpg數據集為例,所用到的變量有cty(城市中行駛距離),hwy(高速路行駛距離),displ(排量大小),year(生產年份)
library(ggplot2) p <- ggplot(mpg, aes(cty, hwy)) p1 <- p + geom_point(aes(colour = factor(year),shape = factor(year), size = displ), alpha = 0.6, position = 'jitter') print(p1)
我們將1999年生產車型用紅色圓形表示,2008年用蘭色三角形表示,排量用圖形的大小表示,并且設置了透明度和jitter以避免樣本點之間的重疊。可觀察到2008年生產的大排量車型較多,從而油耗較高,單位油耗行駛距離較短。
2 坐標的控制
上圖右上角數據點較為稀疏,這種情況下可用對數變換。為了演示ggplot2對圖形坐標的控制,我們對X軸和Y軸均進行對數變換,然后對X軸的坐標顯示加以限制,只顯示X軸數據的均值,以及一倍標準差的坐標。
cty.mean=with(mpg,mean(cty)) cty.sd=with(mpg,sd(cty)) p1 + scale_x_continuous(trans='log',breaks=c(cty.mean-cty.sd,cty.mean,cty.mean+cty.sd), labels=c("high", "mean", "low")) + scale_y_continuous(trans='log')
3 文字說明
利用geom_text函數可添加文字說明以增強圖形的可讀性
p <- ggplot(mtcars, aes(x=wt, y=mpg,colour=factor(cyl),label=rownames(mtcars))) p + geom_text(hjust=0,vjust=-1,alpha=0.8)+ geom_point(size=3,aes(shape=factor(cyl)))

4 矩陣散點圖
ggplot2包中也提供了矩陣散點圖函數
plotmatrix(USArrests)+geom_smooth()

V. 時間序列
ggplot2包也能對時間序列數據繪圖,但在處理上需要有些注意的地方。下面我們以上證指數為例進行作圖,首先利用quantmod包從yahoo數據源獲取從1997年以來的數據,存于變量SSEC中,抽取收盤數字,然后分別提取時間數據和指數數值,繪圖結果如下圖。
library(quantmod) library(ggplot2) getSymbols('^SSEC',src='yahoo',from = '1997-01-01') close <- (Cl(SSEC)) time <- index(close) value <- as.vector(close) p <- ggplot(data.frame(time,value),aes(time,value)) p + geom_line()

我們希望能夠在圖中加入一些其它的說明元素,以豐富視圖中所包含的信息。這些信息包括用不同的顏色區塊來表示“江核心”和“胡核心”的執政時期,以及對中國證券市場的若干大事件進行標注。最后的代碼和結果如下。
yrng <- range(value) xrng <- range(time) data <- data.frame(start=as.Date(c('1997-01-01','2003-01-01')),end=as.Date(c('2002-12-30','2012-01-20')),core=c('jiang','hu')) timepoint <- as.Date(c('1999-07-02','2001-07-26','2005-04-29','2008-01-10','2010-03-31')) events <- c('證券法實施','國有股減持','股權分置改革','次貸危機爆發','融資融券試點') data2 <- data.frame(timepoint,events,stock=value[time %in% timepoint])
p + geom_line() + geom_rect(aes(NULL,NULL,xmin = start, xmax = end, fill = core),ymin = yrng[1],ymax=yrng[2],data = data) + scale_fill_manual(values = alpha(c('blue','red'),0.2)) + geom_text(aes(timepoint, stock, label = events),data = data2,vjust = -2,size = 5) + geom_point(aes(timepoint, stock),data = data2,size = 5,colour = alpha('red',0.5))