R語言初心者的GGplot2懶人包──長條圖範本

2023/01/28閱讀時間約 18 分鐘
  在這個大數據的年代,想碰數據的人除了Excel之外,R語言幾乎是免不了要打交道的東西了。
  在R語言資料視覺化的文章或教學中,GGplot2是極常被提及的套件。R語言內建有繪圖功能,但很多人認為GGplot2更加直覺好用(也可能更美觀,但我想這是見仁見智)。
  GGplot2確實功能強大,但相關教學有些零碎。英語教學相當豐富,然而對於不善於英語的人來說,要搞清楚GGplot2的操作會是充滿挫折與壓力的過程。
  初學GGplot2的時候,一直很希望有一種懶人模板,告訴我什麼指令會控制什麼就好,這樣我就複製貼上然後改一改就行了。當然有很多類似的文章,但往往缺乏一些我希望可以有的功能或者可以操作的物件。
  東拼西湊的,終於完成了還算滿意的長條圖(與並列長條圖)。雖然距離摸熟GGplot還差得遠,但希望留下這些摸索的紀錄。
如果可以節省到誰的時間那就太好了。

本次所繪製的圖

  先把本次做出來的圖放上來。
資料來源:文化部文化參與及消費調查,2016~2021年
  以下會放上程式碼與code的解釋,要做類似的圖時可以根據需求自己稍作修改。
  未來還有可能要做更細緻的圖,所以程式碼還有機會繼續更新以包含更多項目。

所用資料集

  以下為本次所用的資料集,來源於文化部文化調查問卷資料。因為之前所做的專案,擷取了其中一小部分而來的。
  GGplot2所用的資料結構是data frame,由於這篇文章是針對ggplot2所寫,關於R語言如何操作data frame或者如何整理資料就不贅述。網路上已有相當豐富的中文資源,或者購買相關書籍也可以更完整的學習。
  上面這張圖包含了三種數值:1. x軸的年齡類別 (共有11組)。2. y軸的人數比例。3. 區分淺綠色與深綠色的類別 (一年內是否去過博物館的人)。
  以上三種數值都需要各自成為一個data frame中的欄位。以下為data frame的資料結構:
# 一個data frame,age為x軸,Freq為y軸,place_YesNo0為分組變數
#(不同顏色的長條)
# 這個資料集的名稱為ageDiff,主要用這個資料集來作圖
   place_YesNo0 age  Freq
1             0   1  5.07
2             1   1  6.39
3             0   2  8.22
4             1   2 12.15
5             0   3  7.79
6             1   3  9.94
7             0   4  7.44
8             1   4  9.01
9             0   5  7.74
10            1   5 10.86
11            0   6  8.16
12            1   6 11.17
13            0   7  8.32
14            1   7  9.27
15            0   8  9.58
16            1   8  8.55
17            0   9  9.74
18            1   9  6.97
19            0  10 10.46
20            1  10  6.84
21            0  11 17.48
22            1  11  8.86
# 另有一個資料集叫做ageDiff_n,這是各組的人數(N),也會用到
    0     1 
28323 22325 

作圖程式碼與解釋

  以下段落的撰寫方式是「程式碼解釋」對應後面的程式碼。因為這個筆記的目的是類似模板的功能,對於ggplot的基礎解釋就不會太多。

  ggplot作圖,首先設定底層畫布。
  指定資料集為ageDiff、對應於x、y軸的欄位、用來區分長條圖顏色 (fill) 的欄位。
  小提醒
  視覺圖當中有許多種屬性,就是指例如x軸分組、顏色、大小、形狀等等的特性。
  當我們把資料的欄位放在aes() 裡面時,就是要求ggplot根據某個欄位來繪製該屬性,這叫做mapping。
  例如下方的意思就是:x軸請根據age欄位來畫 (那個as.factor的指令是將age轉換成類別資料),y軸請根據Freq欄位來畫,填色請根據place_YesNo0欄位來畫。
  當這些屬性沒有放在aes()當中時,就不是mapping,而是直接指定該屬性的值 (看不懂這句可以直接跳過)。
ggplot(ageDiff, 
    aes(x = as.factor(age), y = Freq, fill = place_YesNo0)) +

  要畫長條圖的話,用geom_col()指令。裡面的position參數設定為"dodge",繪製成並列長條圖。不設定的話,則會變成堆疊長條圖。
geom_col(position = "dodge") +

  geom_text() 用來設定資料標籤 (就是每個長條上面的那些數值)。aes() 中的label是數值所對應的欄位(通常跟上面的y軸相同),col是用來設定要用什麼欄位來區分標籤顏色(通常跟上面的fill一樣,或者不特別設定col就是黑色)。
  position一樣是要用dodge,但這裡用的是position_dodge() 的寫法,要指定width的數值。如果width是0,跟沒有dodge是一樣的意思,這時候兩組 (深、淺綠色) 的資料標籤就會重疊在一起。width越大,不同組之間的資料標籤錯開越多。設定為1是配合1080p的圖片設定的,需根據需要自行嘗試最適合的數值。
  vjust是要在垂直位置上做調整,預設顯示位置會重疊於長條圖上緣,vjust為負值表示往上調整。同樣要自己嘗試怎樣的數值最適合。
  size指的是標籤大小,預設是3.88,調成10比較適合1080p的圖。
  geom_text(aes(label = Freq, col = place_YesNo0), 
            position = position_dodge(width = 1), 
            vjust = -0.2, size = 10) +

  scale_x_discrete是拿來調整x軸的圖層。注意最後的discrete表示類別資料,在data frame裡面必須要是factor
  name是x軸的軸標題。
  labels是要顯示在座標軸上的標記名稱。
  小提醒:請記得順序務必要對應到資料中的factor排序,最好先用levels函數看一次factor的類別排序是如何。這部分需要熟悉factor資料類型,在這篇筆記裡面不會詳細解釋關於factor的操作。
scale_x_discrete(name = "年齡",
                 labels = c("15-19", "20-24", "25-29", 
                            "30-34", "35-39", "40-44",
                            "45-49", "50-54", "55-59",
                            "60-64", "65 up")
         ) +

  scale_y_continous是拿來調整y軸的圖層,大致上與x軸一樣,只是因為是連續變數,必須要用continous。
  limits只能用在continous上,限制這個軸的上下限,必須是個長度為2的數值向量。
  expand也必須是個長度為2的數值向量。如果用預設的方式畫圖,會發現x軸其實離長條有一點距離 (可以試試看把expand拿掉會發生什麼事?),把這個值設定為 c(0, 0) 就可以解決這問題。
  小補充:expand其實是將軸「延伸」一段距離的意思,這個向量的第一個值是要延伸幾倍,第二個值是要延伸幾單位。不管怎樣,就是會讓x軸離長條圖有一段距離 (因為y軸被「延伸」了),所以長條圖看起來像是飛在空中一樣。同樣的設定在x軸也是適用的。
  scale_y_continuous(name = "人數比例 (%)", 
            limits = c(0, 19),
                     expand = c(0, 0)
            ) +

  scale_fill_是拿來修改fill圖層用的,後面接manual,和discrete的差別在於manual是要由使用者自己指定數值 (就是下面的values),但discrete會自己從對應 (mapping) 的資料欄位抓數值。
  fill的數值 (value) 是什麼呢?就是不同組的長條圖要用什麼填色。下面的寫法是去抓RColorBrewer套件中,Paired調色板中的12個顏色,並指定要用第3到第4個顏色。不想這麼複雜的話其實直接用色碼或RGB的寫法就好 (範例附在程式碼後方)。
  namelabels用法同上,不贅述。注意因為fill圖層是指「要用哪一個欄位來區分長條」,在圖上其實是類似一個分組變數的意思,所以這裡的labels實際上會是圖例的名稱。
  小提示:有一種修改顏色的方法是使用scale_fill_brewer改。但這樣一來就不能用scale_fill_discrete修改圖例文字,因為scale_fill系列的圖層只能出現一個。本例使用manual的方式可以同時修改兩者。
  scale_fill_manual(values = RColorBrewer::brewer.pal(12, "Paired")[3:4],
                    name = "一年內去過博物館",
                    labels = c(paste("否, N = ", ageDiff_n[1]), 
                               paste("是, N = ", ageDiff_n[2])
                 )  
            ) +
# 補充:
# paste()是連接字串的函數
# 色碼寫法範例如下,記得加引號、井字號,英文用小寫:
c("#ababab", "#8b7355")
# RGB寫法範例如下:
c(rgb(0, 0, 1), rgb(255, 0, 0) )

  scale_color_則是為了修改color用的,因為前面的geom_text的顏色是color而不是fill,所以不會受到scale_fill_manual的影響。如果不設定color圖層,資料標籤的部分就會用預設的顏色顯示。
  guide = NULL是指不要把這個圖層顯示成圖例,不寫這個參數就會多一組圖例出來。
  (其實單純要修改text顏色的話,也可以把geom_text() 的col放在aes() 之外,並指定相應的顏色就可以了,就不需要特別用scale_color_manual來處理。)
  scale_color_manual(values = RColorBrewer::brewer.pal(12, "Paired")[3:4],
                     guide = NULL) +

  labs可以放圖表標題 (title)、副標題 (subtitle)、x和y軸標題 (x = "x name", y = "y name")、caption (就是範例圖右下角的文字) 等。
  由於軸標題上面已經處理過了,這邊就不寫,只寫圖表標題和caption。
  labs(title = "一年內有/無前往過博物館者的年齡分布",
       caption = paste("N = ", sum(ageDiff_n))) +

  theme就是拿來調整與資料無關的一些圖表元素
  panel.grid系列是拿來處理x軸和y軸的格線,設定為element_blank()就是不要格線的意思。這一系列參數可以分為x軸、y軸,兩軸又可以各自分為主格線和副格線,各自由不同名稱的參數來控制。如果要調整線段顏色、粗細或類型,用element_line (color = "blue", size = 12, linetype = 1) 並更換"blue"、12、1即可。
  panel.background是調整作圖區的背景,使用element_rect()來控制。
  axis.title是軸標題、axis.text是軸上的標記、axis.line是軸線、axis.ticks是軸線上有一個小小的線段,會標記出資料點所在的位置。
  legend系列就是控制圖例用的。
  plot.title是控制圖表標題,face是拿來控制要粗體、斜體還是粗斜體,hjust是控制水平位置,0為置左、0.5為置中、1為靠右對齊。margin是設定標題的邊緣空間,用一個長度為4的數值向量設定上、右、下、左,並指定距離單位。
  plot.caption是控制caption用的,那個plot.caption.position是指這個caption要在什麼範圍內對齊。指定"plot"就是在作圖區範圍對齊。
theme(panel.grid = element_blank(),
        panel.background = element_rect(fill = "White"),
        axis.title = element_text(size = 24),
        axis.text.x = element_text(size = 20),
        axis.line.x = element_line(linetype = 1),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        legend.title = element_text(size = 20),
        legend.text = element_text(size = 16),
        plot.title = element_text(size = 42, face = "bold", hjust = 0.5,
                                  margin = margin(1, 0, 0, 0, "cm")),
        plot.caption.position = "plot",
        plot.caption = element_text(size = 16, hjust = 1)
    )

以上是長條圖的模板,參數部分可以根據需求修改。想要更了解參數如何處理的話,善用help()可以得到更多資訊。
我也還在繼續了解ggplot2,可能有些地方並不是很正確,希望未來可以繼續修正。如果有什麼錯誤或者更好的寫法,歡迎留言多多交流~
不過單純的長條圖,也許用excel畫會比使用R還要更快一些。使用R來作圖應該是針對一些excel裡面很難畫出的圖形才是。
未來如果寫出其他類型的圖形範本,也會整理好筆記發成文章,但頻率就難以保證了。

可以參考的資源

這裡列出一些很好用的參考資源,不過是英文居多。
ggplot 2的各種圖形元素設定:https://r-charts.com/ggplot2/titles/
R語言中文教科書:
  1. R語言邁向Big Data之路──王者歸來(第二版),偏向從程式語言的角度切入,從0開始介紹R語言的操作與邏輯,相當完整。
    一般來說,從統計的角度切入的R語言教科書結構都有點零散,時常讓人有知其然而不知其所以然的問題。這本書可以解決這個困擾。

  2. 統計就是這麼輕鬆R:AI幫你寫好資料分析,著重於R語言在行為科學上的應用,範圍涵蓋常見的行為科學資料分析方法(如t test、ANOVA等)。
    對於R語言的基本操作著墨不多,但附有許多實用的程式碼工具,對於統計觀念的介紹完善並附有參考文獻。其中一章節專門講述ggplot2作圖套件,可以參考該章節的程式碼範例。
為什麼會看到廣告
19會員
26內容數
大學念文組,碩士班的報告突然要用統計了怎麼辦?沒學過統計怎麼寫量化學位論文?跟著統計書操作都沒問題,但報表都不知道在講什麼,也不知道做的分析到底對不對?作者在應用統計的路上跌跌撞撞也差不多十年了,希望有些心得可以幫助到有這些困擾的你。
留言0
查看全部
發表第一個留言支持創作者!