分類: R

R ggplot2 教學:圖層式繪圖

這裡介紹 ggplot 函數的基本圖層式繪圖使用方式。

ggplot 系統在繪圖時是以一種圖層式的概念在建立圖形的,每一張圖層上的資料可以有不同的來源、美學對應,而簡單版的 qplot 只允許單一資料來源以及一組美學對應,若要完全發揮 ggplot 系統的功能,就必須使用它的 ggplot 函數配合各式的圖層函數,這樣才能畫出更有彈性的圖形。

建立圖形物件

在使用 qplot 繪圖時,它其實自動幫使用者做了很多工作,從建立基本圖形物件、增加圖層到顯示繪圖結果等流程,以及選用各種的預設繪圖選項等,雖然這樣使用者非常方便就可以快速產生一張可用的圖形,不過同時也讓繪圖的彈性降低、可用的選項減少,無法繪製出比較複雜的圖形。

ggplot 系統上若要以標準的繪圖流程來畫圖,首先要使用 ggplot 這個函數來建立基本繪圖物件,其第一個 data 參數是指定資料來源的 data frame,而第二個 mapping 參數則是指定美學對應(aesthetic mapping),這兩個參數是設定繪圖的物件的預設值,若在這裡沒有設定的話,也可以在後續加入的圖層中再設定。

mapping 參數所指定的美學對應跟 qplot 中所使用的相同,只不過在這裡必須將對應的參數用 aes 函數包裝起來。下面這個範例是將 carat 變數對應到 x 軸、price 變數對應到 y 軸,而以顏色區隔 cut 變數。

my.plot <- ggplot(diamonds, aes(carat, price, colour = cut))

這裡建立的 my.plot 只是一個基本的繪圖物件,尚未包含任何圖層,所以還無法顯示任何圖形。

圖層

一個只包含 geom 參數的圖層是一個最簡單的圖層,其指定了繪製資料時所使用的幾何圖形。若在前面建立的繪圖物件上再加入一個 geom 指定為 point 的圖層,即可產生一張散佈圖:

my.plot <- my.plot + layer(
  geom = "point",
  stat = "identity",
  position = "identity",
  params = list(na.rm = FALSE)
)

這裡我們以加號(+)將圖層疊加至既有的繪圖物件上,被加入的新圖層會直接使用該繪圖物件上的資料來源以及美學對應參數。除了指定 geom 參數之外,另外還有兩個 statposition 參數也要自行指定,這兩個參數可用來指定統計轉換與細部的幾何圖形位置調整,若不需要特別的轉換與調整的話,就指定為 "identity"params 則是用來指定 geomstat 所需要的參數。

若要顯示圖形則將此繪圖物件輸出即可:

my.plot

ggplot 散佈圖

若要繪製直方圖的話,要指定的參數就會稍微複雜一些:

my.plot2 <- ggplot(diamonds, aes(x = carat))
my.plot2 <- my.plot2 + layer(
  geom = "bar",
  stat = "bin",
  position = "identity",
  params = list(
    fill = "steelblue",
    binwidth = 0.2,
    na.rm = FALSE
  )
)
my.plot2

ggplot 直方圖

在產生直方圖時,我們需要使用 bin 這個統計轉換來計算直方圖每個 bin 的數值,然後再使用 bar 這個 geom 呈現圖形,標準的圖層建立程序可以讓使用者有很大的彈性,但相對上需要的操作也相當繁瑣。

為了簡化繪圖的工作,ggplot 系統上提供了非常多建立圖層用的簡化圖層函數,在使用者取用 geom 的同時也自動加上預設的 statposition,同樣的在取用 stat 時也會伴隨預設的 geom,使用者只需要很直覺地指定少量的參數即可。

ggplot 中的簡化圖層函數都是以 geom_*stat_* 的方式命名的,通常從函數的名稱就可以看出其作用為何。改用簡化圖層函數之後,建立 ggplot 圖層的動作就會變得很簡單,以上面繪製直方圖的範例來說,若以 geom_histogram 這個繪製直方圖的簡化圖層函數改寫後,就會變成這樣:

my.plot3 <- ggplot(diamonds, aes(x = carat))
my.plot3 <- my.plot3 +
  geom_histogram(binwidth = 0.2, fill = "steelblue")
my.plot3

產生的圖形相同,但是操作卻簡單很多。

大部分的 ggplot 的簡化圖層函數都有一些共通的參數:

  • mapping:指定美學對應,指定時需要以 aes 函數包裝,若沒有指定則會使用繪圖物件的預設值。
  • data:指定資料來源的 data frame,通常都會省略,並直接使用繪圖物件的預設值。
  • ...geomstat 所使用的參數,例如直方圖的 bin 寬度等。
  • geomstat:自行指定要使用的 geomstat,改變預設的設定。
  • position:指定細部的資料位置調整。

以上這些參數都可以省略,不指定的話就會使用內部的預設值。

ggplot 函數與圖層函數的參數順序有些小差異,在 ggplot 中第一個參數是 data、第二個是 mapping,但是在圖層函數中剛好相反,這樣的設計是因為一般在使用 ggplot 繪圖時,通常都會在 ggplot 中指定資料,而加入圖層時只會指定美學對應的參數。

ggplot 的圖層可以直接加在 ggplotqplot 所產生的繪圖物件上,事實上 qplot 只是將建立繪圖物件與加入圖層的動作包裝成一個函數而已,其效果跟 ggplot 函數是相同的。

以下是幾種 ggplotqplot 的寫法比較。

# 做法一
ggplot(msleep, aes(sleep_rem / sleep_total, awake)) +
geom_point()
# 做法二
qplot(sleep_rem / sleep_total, awake, data = msleep)

加入平滑曲線的範例:

# 做法一
qplot(sleep_rem / sleep_total, awake, data = msleep) +
geom_smooth()
# 做法二
qplot(sleep_rem / sleep_total, awake, data = msleep,
geom = c("point", "smooth"))
# 做法三
ggplot(msleep, aes(sleep_rem / sleep_total, awake)) +
geom_point() + geom_smooth()

儲存在變數當中的 ggplot 繪圖物件可以使用 summary 查看其內容,透過這種方式可以在不需要把圖形畫出來的情況下檢查圖形的細節:

my.plot4 <- ggplot(msleep, aes(sleep_rem / sleep_total, awake))
summary(my.plot4)
data: name, genus, vore, order, conservation, sleep_total, sleep_rem,
  sleep_cycle, awake, brainwt, bodywt [83x11]
mapping:  x = sleep_rem/sleep_total, y = awake
faceting: facet_null()
my.plot4 <- my.plot4 + geom_point()
summary(my.plot4)
data: name, genus, vore, order, conservation, sleep_total, sleep_rem,
  sleep_cycle, awake, brainwt, bodywt [83x11]
mapping:  x = sleep_rem/sleep_total, y = awake
faceting: facet_null() 
-----------------------------------
geom_point: na.rm = FALSE
stat_identity: na.rm = FALSE
position_identity

ggplot 的圖層本身就是一種 R 的物件,也可以儲存在變數當中,減少重複的程式碼,例如我們可以用不同的資料來源來建立多個繪圖物件,然後套用相同的圖層,若後來要更換圖層時,也僅需要更改一個地方。以下的範例中我們建立了一個圖層,套用在不同的繪圖物件上。

bestfit <- geom_smooth(method = "lm", se = F,
  color = alpha("steelblue", 0.5), size = 2)
qplot(sleep_rem, sleep_total, data = msleep) + bestfit
qplot(awake, brainwt, data = msleep, log = "y") + bestfit
qplot(bodywt, brainwt, data = msleep, log = "xy") + bestfit

Page: 1 2 3 4

G. T. Wang

個人使用 Linux 經驗長達十餘年,樂於分享各種自由軟體技術與實作文章。

Share
Published by
G. T. Wang

Recent Posts

光陽 KYMCO GP 125 機車接電發動、更換電瓶記錄

本篇記錄我的光陽 KYMCO ...

2 年 ago

[開箱] YubiKey 5C NFC 實體金鑰

本篇是 YubiKey 5C ...

2 年 ago

[DIY] 自製竹火把

本篇記錄我拿竹子加上過期的苦茶...

3 年 ago