《R語言實戰》第五部分第十九章-使用ggplot2進行高級繪圖學習筆記

前面所有的圖形都是利用R的基礎繪圖系統創建的,其實R的系統複雜,特別是圖形系統,還有grid、lattice和ggplot2軟體包也提供了圖形系統,克服了R基礎圖形系統的低效性,大大擴展了R的繪圖功能。特別是ggplot2軟體包,由大神Hadley Wickham提供。這個包極大地擴展了R繪圖的範疇,構建了完全不同的繪圖體系和語法系統,提高了圖形質量。毫不客氣的說,是用R進行數據可視化,特別是大數據可視化必須掌握的軟體包之一。本章的介紹也以ggplot2為重點,有興趣可以進一步閱讀Hadley Wickham本人撰寫的《ggplot2: Elegant Graphics for Data Analysis》。

1 R中的四種圖形系統

  • 基礎圖形系統:

由Ross Ihaka編寫,默認安裝

  • grid圖形系統:

由Paul Murrell(2011)編寫,從R1.8開始也默認安裝。grid圖形提供了一種比標準圖形系統更低水平的方法,圖形有很強的靈活性,但是沒有提供生成統計圖形以及完整繪圖的函數。對於軟體開發者非常有價值,數據分析師很少直接採用grid包來分析數據。進一步了解grid包可以訪問:Grid

  • lattice圖形系統

由Deepayan Sarkar(2008)編寫,可繪製Cleveland(1985,1993)所描述的網格圖形。lattice包基於grid包創建,在多元數據的可視化功能方面已經遠超Cleveland的原始方法。

  • ggplot2圖形系統

ggplot2包由Hadley Wickham(2009a)編寫,提供了一種基於Wilkinson(2005)所述圖形語法的圖形系統,Wickham(2009b)還對該語法進行了擴展。

ggplot2成為使用R進行數據可視化的重要工具。

以上四種圖形系統的載入方式有所不同:

考慮到ggplot2的強大功能以及在數據分析領域的流行性,本章接下來主要討論它的功能和使用,lattice包將在最後一章介紹。本章主要用三個數據集來介紹ggplot2的簡單功能,分別為lattice包中的singer數據集、mtcars數據集以及car包中的Salaries數據集。

2 ggplot2包介紹

ggplot2包實現了一個在R中基於全面一致的語法創建圖形時的系統,提供了在R中畫圖圖形創造的一致性,並為我們創建具有創新性和新穎性的圖表類型提供了可能。

ggplot2中各個函數創建的圖形用「+」串聯起來,然後每個函數修改自己的部分。舉例如下:

> ggplot(data = mtcars, aes(x = wt, y = mpg)) + geom_point() + labs(title = "Automobile Data", x = "Weight", y = "Miles Per Gallon")

作圖步驟分解如下:

  1. ggplot()函數初始化圖形並指定要用到的數據來源(mtcars數據集當中的wt和mpg變數)
  2. aes()函數指定每個變數所扮演的角色
  3. geom_point()函數在圖形當中畫點,創建了一幅散點圖
  4. labs()函數根據需要添加註釋

首先,ggplot()函數只是進行初始化,並對圖形進行設置,無實質性的圖形輸出,後面需要+一個或者多個幾何函數向圖中添加對象(以geom開頭),包括點、線、條、箱線圖和陰影區域。可以將上述代碼進行一些擴展,進一步展示一下ggplot2中的功能。

> library(ggplot2)> ggplot(data = mtcars, aes(x = wt, y = mpg)) + geom_point(pch = 17, color = "blue", size = 2) + geom_smooth(method = "lm", color = "red", linetype = 2) + labs(title="Automobile Data", x="Weight", y="Miles Per Gallon")

geom_point()函數當中設置了點的形狀為三角形(pch=17),大小加倍(size=2),並設置了顏色為藍色(color=「blue」);

geom_smooth()函數增加了一條按照線性擬合(method=「lm」)的平滑曲線,並設置了線型為虛線(linetype=2),顏色為紅色(color=「red」);

默認情況下,平滑曲線包括在95%的置信區間內(較暗帶)。

ggplot2包還提供了分組和刻面(faceting)的功能,並使用因子來定義組或面。還是以mtcars數據集為例。

第一步將am、vs和cyl變數因子化:

mtcars$am <- factor(mtcars$am, levels = c(0,1), labels = c("Automatic", "Manual"))mtcars$vs <- factor(mtcars$vs, levels=c(0,1), labels=c("V-Engine", "Straight Engine"))mtcars$cyl <- factor(mtcars$cyl)

然後利用下面代碼繪圖:

> library(ggplot2)> ggplot(data = mtcars, aes(x = hp, y = mpg, shape = cyl, color = cyl)) + geom_point(size = 3) + facet_grid(am~vs) + labs(title = "Automobile Data by Engine Type", x = "Horsepower", y = "Miles Per Gallon")>

分組指的是在一個圖形中顯示兩組或多組觀察結果,在本例中,cyl是分組變數;而刻面是指在單獨、並排的圖形上顯示觀察組,在本例中am和vs是刻面變數。刻面適合於只有兩種情況的變數,而分組更適合三個及以上的變數。

ggplot2功能強大,同時強大也帶來了複雜性。不過幸運的是,它裡面有默認的設置和語言的簡化設計,可以讓我們的介紹變得容易。本章的注意介紹思路如下:

  1. 介紹幾何函數及其對應創建的圖形類型;
  2. 詳細了解aes()函數,以及如何利用它來對數據進行分組;
  3. 討論刻面和網格圖形的簡歷;
  4. 調整ggplot2圖形的外觀。

3 用幾何函數指定圖的類型

前面的例子裡面已經看到,ggplot()函數只指定要繪製的數據源和變數,在視覺上如何表示需要藉助於幾何函數。下表列出了比較常用的幾何函數以及常用的選項。

前面提到的一些圖形函數都可以用上表的幾何函數進行替代,以下分別為生成直方圖和箱線圖的代碼:

> data(singer, package = "lattice")> ggplot(singer, aes(x = height)) + geom_histogram()> ggplot(singer, aes(x = voice.part, y = height)) + geom_boxplot()>

創建直方圖只需要指定x變數,geom_histgrom()函數在y變數沒有指定時默認對y軸變數進行計數,不過創建箱線圖時變數x和y都需要指定。

每個幾何函數都具有一組可以用來修改圖形的選項,常見的選項見下表:

我們用Salaries數據集來驗證這些選項的使用,代碼如下:

> data(Salaries, package = "car")> library(ggplot2)> ggplot(Salaries, aes(x = rank, y = salary)) + + geom_boxplot(fill = "cornflowerblue",+ color = "black",notch = TRUE) + + geom_point(position = "jitter",color = "blue", alpha = .5) + + geom_rug(side = "l", color = "black")

該圖顯示了不同學術地位對應薪水的缺口箱線圖。使用選項進行了顏色設置,填充設置等,還在左側繪製了一個地毯圖指示薪水的一般擴散。

到此時我們略微領略到不同幾何函數的組合使用最好地展現了ggplot2包的真正力量。再用singer數據集舉個例子:

> library(ggplot2)> data(singer, package="lattice")> ggplot(singer, aes(x=voice.part, y=height)) ++ geom_violin(fill="lightblue") ++ geom_boxplot(fill="lightgreen", width=.2)

這段簡單的代碼將箱線圖和小提琴圖有機結合到一起形成一個新的圖形,發揮了各自圖形的特點,箱線圖展示了在singer數據框中每個音部的25%、50%和75%分位數得分和任意的異常值。對於每個聲部身高範圍上的得分分布,小提琴圖展示了更多視覺線索。

4 分組

分組——在一個圖中畫出兩個或者更多組的觀察值有助於理解數據,R中通常用分類變數的因子來定義組。ggplot2通過將一個或多個帶有諸如形狀、顏色、填充、尺寸和線類型的視覺特徵的分組變數來實現分組,具體由ggplot()聲明中的aes()函數負責。

下面以Salaries數據集為例討論分組的功能。

salaries數據框包含2008~2009學年大學教授的薪水,包含以下變數:

  • rank——助理教授、副教授、教授
  • sex——女性、男性
  • yrs.since.phd——獲得博士學位時間(年)
  • yrs.service——工作年限
  • salary——以美元計的九個月薪水

查看salary與rank之間的變化關係:

> data(Salaries, package = "car")> library(ggplot2)> ggplot(data = Salaries, aes(x = salary, fill = rank)) + geom_density(alpha = .3)>

上圖顯示了不同rank的salary密度曲線,用不同顏色進行了區分,並設置了一定的透明度(alpha)避免相互重疊。這裡的圖例是自動生成的,後面會講到如何自定義分組數據的圖例。

不難發現,salary隨著rank的增長而增長,但是也有明顯的重疊區域,有些助理教授的薪水也有教授的薪水相當,另外rank的增長,salary的範圍也在擴大。

接下來對sex和rank分組,看看yrs.since.phd和salary之間的關係:

> ggplot(data = Salaries, aes(x = yrs.since.phd, y = salary, color = rank, shape = sex)) + geom_point()

薪水有一個隨著畢業年數遞增的趨勢,但並無絕對的線性關係。

最後,用一個分組的條形圖按rank和sex來可視化教授的人數:

> ggplot(Salaries, aes(x=rank, fill=sex)) + geom_bar(position="dodge") + labs(title=position="dodge")> ggplot(Salaries, aes(x=rank, fill=sex)) + geom_bar(position="fill") + labs(title=position="fill")> ggplot(Salaries, aes(x=rank, fill=sex)) + geom_bar(position="fill") + labs(y = "proportion",title=position="fill")>

上述三個圖按不同的條形圖比較了教授數量,前面兩個圖可以看出教授的人數最多,女性教授的人數比其他rank的女性職員人數要多,但是從第三幅當中,女性教授在教授中的比例是最少的。

5 刻面

為了將清晰地顯示並排出現不同組的關係,我們引入了刻面。ggplot2包提供了facet_wrap()函數和facet_grid()函數來創建刻面圖,下表給出了相關語法,其中var、rowvar和colvar是因子。

再以singer數據為例,下面用刻面圖展示各聲部歌手的分布。

> data(singer, package = "lattice")> library(ggplot2)> ggplot(data = singer, aes(x = height)) + geom_histogram() + facet_wrap(~voice.part, nrow = 4)

再創建一個結合刻面和分組的圖:

> library(ggplot2)> ggplot(Salaries, aes(x = yrs.since.phd,y = salary, color = rank,shape = rank)) + geom_point() +facet_grid(.~sex)

最後再展示一下singer數據集當中每個聲部成員的身高分布,並利用核密度函數水平排列,分布配不同的顏色。代碼和圖形如下:

> data(singer, package = "lattice")> library(ggplot2)> ggplot(data=singer, aes(x=height, fill=voice.part)) + geom_density() + facet_grid(voice.part~.)

6 添加光滑曲線

ggplot2包提供了geom_smooth()函數來添加一系列的平滑曲線(線性、非線性和非參數)和置信區間對於的置信區域。geom_smooth()函數參數見下表:

用Salaries數據集檢驗博士畢業年數與薪水之間的關係,採用默認的95%置信區間的loess,代碼和圖形結果如下:

> data(Salaries, package = "car")> library(ggplot2)> ggplot(data = Salaries, aes(x = yrs.since.phd, y = salary)) + geom_smooth() +geom_point()`geom_smooth()` using method = loess

關係不是線性的,下面按性別擬合一個二次多項式回歸:

> ggplot(data=Salaries, aes(x=yrs.since.phd, y=salary,+ linetype=sex, shape=sex, color=sex)) ++ geom_smooth(method=lm, formula=y~poly(x,2),+ se=FALSE, size=1) ++ geom_point(size=2)

對男性來說,在博士畢業30年後薪水開始下降,女性賊從0~40年之間一直上升,但是在40年以上的暫時沒有數據。並且同等年數下通常男性拿到更高的薪水。

  • ggplot2包中的知識點:統計函數

ggplot2包中含有大量統計函數來計算所需要的量,從而生產更多的可視化數據。通常情況下,幾何函數隱式地調用統計函數,我們不需要直接處理這些問題。不過知道它們的存在是有用的。

比如geom_smooth()函數依賴於stat_smooth()函數來計算畫出一個擬合曲線及其置信限所需的數量。幫助頁面對於geom_smooth()函數的介紹是很少的,但對stat_smooth()函數的介紹包含大量有用的信息。在探索幾何函數如何工作和哪些選項可供選擇時,一定要檢查這個函數及其相關統計函數。

7 修改ggplot2圖形的外觀

7.1 坐標軸

通常ggplot2包自動創建的刻度線、刻度標記標籤和坐標軸標籤看起來還算不錯,但ggplot2包也提供了大量的自定義坐標軸的函數。

ggplot2的函數不僅區分x軸和y軸,還對軸線代表一個連續或離散變數(因子)也進行區分。下面對這些函數進行應用:

> data(Salaries, package = "car")> library(ggplot2)> ggplot(data=Salaries, aes(x=rank, y=salary, fill=sex)) + geom_boxplot() + scale_x_discrete(breaks=c("AsstProf", "AssocProf", "Prof"), labels=c("Assistant
Professor"
, "Associate
Professor"
, "Full
Professor"
)) + scale_y_continuous(breaks=c(50000, 100000, 150000, 200000), labels=c("$50K", "$100K", "$150K", "$200K")) + labs(title="Faculty Salary by Rank and Sex", x="", y="")>

7.2 圖例

同樣,ggplot2包能夠自動生成大部分情況下滿足需求的圖例,但在有些時候也需要進行自定義。標題和位置是最常用的定製圖例,此外還有顏色、形狀、尺寸等。

以下通過將fill=「mytitle」加到labs()函數來改變標題、並用theme()函數中的legend.position選項來控制標題位置來對上一幅圖進行調整。

> data(Salaries, package = "car")> library(ggplot2)> ggplot(data = Salaries, aes(x = rank, y = salary, fill = sex)) + geom_boxplot() + scale_x_discrete(breaks = c("AsstProf", "AssocProf", "Prof"), labels = c("Assinstant
Professor"
, "Associate
Professor"
, "Full
Professor"
)) + scale_y_continuous(breaks = c(50000, 100000, 150000, 200000), labels = c("$50K", "$100K", "$150K", "$200K")) + labs(title = "Faculty Salary by Rank and Gender", x = "", y = "", fill = "Gender") + theme(legend.position = c(.1, .8))>

theme()函數的legend.position = c(.1, .8)是指圖例位於分別距離左側邊緣10%和底部邊緣80%的位置。使用legend.position = "none"可以刪除圖例。

7.3 標尺

可以將標尺理解成一種空間上的坐標,在平面二維圖中提供給了一種x軸、y軸以外對變數大小以及分類的一種度量,標尺可以應用到連續變數也可以應用到離散變數。

連續型的標尺可以映射數值型的變數到圖的其他特徵。代碼和圖形如下:

> ggplot(mtcars, aes(x=wt, y=mpg, size=disp)) ++ geom_point(shape=21, color="black", fill="cornsilk") ++ labs(x="Weight", y="Miles Per Gallon",+ title="Bubble Chart", size="Engine
Displacement"
)

aes()函數中的size參數按要求對disp變數生成了連續型標尺,點的大小表示發動機的排量大小。

下面再舉一個離散型變數的例子。標尺可以將帶有因子水平的視覺線索關聯起來,比如顏色、形狀、線條類型、尺寸和透明度等。看以下代碼以及生成的圖形:

> data(Salaries, package = "car")> ggplot(data = Salaries, aes(x = yrs.since.phd, y = salary, color = rank)) + scale_color_manual(values = c("orange", "olivedrab", "navy")) + geom_point(size = 2)

scale_color_manual()函數來設定三個rank變數的點的顏色。

如果對於特定的顏色色弱,還可以通過scale_color_brewer()和scale_fill_brewer()函數來預先指定分得清的顏色集。可供選擇的顏色集可以通過以下代碼獲得:

> library(RColorBrewer)> display.brewer.all()

7.4 主題

theme()函數可以用來調整字體、背景、顏色和網格線等,主題可以一次使用,也可以保存起來在多個圖當中應用。看以下代碼的運行結果:

> data(Salaries, package="car")> library(ggplot2)> mytheme <- theme(plot.title=element_text(face="bold.italic", size="14", color="brown"), axis.title=element_text(face="bold.italic", size=10, color="brown"), axis.text=element_text(face="bold", size=9, color="darkblue"), panel.background=element_rect(fill="white", color="darkblue"), panel.grid.major.y=element_line(color="grey", linetype=1), panel.grid.minor.y=element_line(color="grey", linetype=2), panel.grid.minor.x=element_blank(), legend.position="top")> ggplot(Salaries, aes(x=rank, y=salary, fill=sex)) + geom_boxplot() + labs(title="Salary by Rank and Sex", x="Rank", y="Salary") + mytheme

mytheme主題分別制定了圖的標題、軸的標題以及坐標軸標籤的字體、顏色、字型大小。畫圖區域有白色的填充和深藍色的邊框。以及主水平網格和次水平網格的線型,並取消了垂直網格,另外將圖例展示在圖的頂部。theme()函數給了我們把控圖形的最終控制權。

7.5 多重圖

如果需要將多個ggplot2包的圖形放到單個圖形當中可以採用gridExtra包中的grid.arrange()函數。

> data(Salaries, package="car")> library(ggplot2)> p1 <- ggplot(data=Salaries, aes(x=rank)) + geom_bar()> p2 <- ggplot(data=Salaries, aes(x=sex)) + geom_bar()> p3 <- ggplot(data=Salaries, aes(x=yrs.since.phd, y=salary)) + geom_point()> library(gridExtra)> grid.arrange(p1, p2, p3, ncol=3)>

需要事先安裝gridExtra包,值得一提的是多重圖與刻面是有區別的,刻面是基於一個或多個分類變數創建一系列的圖,而多重圖只是將幾張不同的圖形放到一個圖形當中。

8 保存圖形

ggplot2創建的圖可以通過ggsave()函數保存,它的選項包括保存哪幅圖、保存在哪裡以什麼樣的方式,比如:

> myplot <- ggplot(data = mtcars, aes(x = mpg)) + geom_histogram()> ggsave(filename = "mygraph.png", plot = myplot, width = 5, height = 4)

除了png格式,我們還可以通過設定文件擴展名為ps、tex、jpeg、pdf、tiff、png、bmp、svg或wmf來保存為不同的格式。

如果忽略plot = 選項,則最近創建的圖形會被保存。

9 小結

ggplot2包旨在在R提供的基礎畫圖之外提供一個完整而全面的替代方案,它所提供的數據可視化方法目前在R中是不可替代的。

ggplot2包學習起來比較困難,好在有大量的資料,比如一系列ggplot2的函數及相應的例子可以在Function reference ? ggplot2上面找到,如果想了解ggplot2計算機圖形學上的實現機理,可以參閱Wickham本人的書。


推薦閱讀:

R語言數據清洗實戰——世界瀕危遺產地數據爬取案例
多層數據巧鑽取,業務盲點無處可躲~
珍藏,最全面+最完善的Excel條件格式使用手冊
世紀佳緣用戶畫像-Part1
leaflet在線地圖——常用熱力地圖

TAG:ggplot2 | R编程语言 | 数据可视化 |