--- title: 【R 語言與統計資料分析】Ch5:R 繪圖與 ggplot2、plotly 實戰 image: https://ppt.cc/fnT4xx@.png --- # 【R 語言與統計資料分析】Ch5:R 繪圖與 ggplot2、plotly 實戰 # 5.1 什麼是圖表? **圖表** (Charts/Graphs) 是透過視覺化手段來呈現數據、統計數字或複雜概念的工具,旨在**簡化資訊**並**凸顯資料間的結構、趨勢與差異**。 ## 5.1.1 數據圖表 **數據圖表** (Chart) 為帶有量化數據的圖形或圖案,即具圖像化的資料表,用以使讀者方便理解大量數據,以及數據之間的關係。如:圓餅圖、長條圖、直方圖、折線圖等各式統計圖表。 <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/r1VqrYNwWg.png" width="200"> <br> <span style="color: gray; font-size: 0.8em;">圓餅圖就是一種數據圖表</span> </div> ## 5.1.2 資訊圖表 **資訊圖表** (Infographics) 其英文顧名思義為「資訊」 (information) 以及「圖表」(graphic) 所結合而成的複合單字,指資料、資訊或知識的視覺化表現形式。目的為清楚準確的解釋或表達甚為複雜且大量的資訊,被廣泛應用在各式各樣的文件檔案上。 <div style="text-align: center;"> <img src="https://www.ydn.com.tw/api/ugc_imagehandler.ashx?NFID=906464" width="300"> <br> <span style="color: gray; font-size: 0.8em;">由中央氣象署發布的資訊圖表</span> </div> ## 5.1.3 圖表的 TOP 原則 #### Target(對象):圖表是給誰看的? 我們必須優先確認受眾是誰,再進一步決定圖表的呈現的深度與複雜度。在設計時,或許可以透過顏色、標記或直接在標題寫出結論,引導受眾在最短時間內抓到重點。 #### Object(目的):希望傳達出什麼訊息或達成什麼目的? 釐清目的能決定圖表的類型選擇與敘事方式,比如針對不同的資料型態,使用對應的圖表進行敘事;對主管報告,優先提供決策所需的資訊等等。 #### Place(場合):圖表用什麼形式展現? 圖表呈現的場合是相當重要的,會直接影響圖表的「視覺設計細節」,如: 放在正式文件、內部會議簡報、社群媒體文案,還是 E-mail 附件等等。若是現場簡報,圖表應簡潔並由講者輔助;若是電子文件,圖表必須具備自我解釋能力(Self-explanatory)。 # 5.2 在 R 中用 `Base` 繪製圖表 ## 5.2.1 用 `par()` 開始處理畫布 #### 用 `mar` 控制邊界 <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/BJMAhqEwZg.png" width="350"> <br> <span style="color: gray; font-size: 0.8em;">mar = c(下, 左, 上, 右)</span> </div> ```R # mar = c(下, 左, 上, 右) # 邊界超小,圖片超大 par(mar = c(1,1,1,1) ) boxplot(iris$Sepal.Width ~ iris$Species, ylab = "Sepal width (cm)", main = "Anderson's Iris Data") # 邊界超大,圖片超小 par(mar = c(15,15,15,15) ) boxplot(iris$Sepal.Width ~ iris$Species, ylab = "Sepal width (cm)", main = "Anderson's Iris Data") ``` #### 用 `mfcol` 與 `mfrow` 來合併繪圖 在進行圖片繪製時,常常會需要將多張圖片放置在一起排版,此事就可以使用 `mfcol` 與 `mfrow` 來進行版面的規劃。`mfcol` 為依照「**直行**」的方向進行排列,而 `mfrow` 為依照「**橫列**」的方向進行排列。 ```R # mfcol 的範例 par(mfcol = c(3,2)) #指形成一個 3x2 的繪圖矩陣 boxplot(iris$Sepal.Width ~ iris$Species, main = "Plot A") boxplot(iris$Sepal.Width ~ iris$Species, main = "Plot B") boxplot(iris$Sepal.Width ~ iris$Species, main = "Plot C") boxplot(iris$Sepal.Width ~ iris$Species, main = "Plot D") boxplot(iris$Sepal.Width ~ iris$Species, main = "Plot E") boxplot(iris$Sepal.Width ~ iris$Species, main = "Plot F") ``` ```R # mfrow 的範例 par(mfrow = c(3,2)) #指形成一個 3x2 的繪圖矩陣 boxplot(iris$Sepal.Width ~ iris$Species, main = "Plot A") boxplot(iris$Sepal.Width ~ iris$Species, main = "Plot B") boxplot(iris$Sepal.Width ~ iris$Species, main = "Plot C") boxplot(iris$Sepal.Width ~ iris$Species, main = "Plot D") boxplot(iris$Sepal.Width ~ iris$Species, main = "Plot E") boxplot(iris$Sepal.Width ~ iris$Species, main = "Plot F") ``` 在執行 `par(mfcol = c(3,2))` 或 `par(mfrow = c(3,2))` 後,畫圖的布局就已被更改,下次若要繪圖,一樣會從繪圖區的左上角依序繪製。 若要恢復成單一圖表狀態,可使用 `par(mfcol = c(1,1))` 更改布局或是使用 `dev.off()` 來恢復成預設狀態。 #### 用 `layout` 做不對稱排版 除了對稱的排版之外,我們也會使用不對稱的排版。舉例來說,我們可能會想要凸顯某一張圖作為重點,而其他圖片作為此議題的補充,此時就會想把重點圖片作放大,其餘部分就可以做為陪襯。 關於 `layout()` 函數的應用,與矩陣呈現的形式息息相關,我們直接以實際案例作介紹: ``` matrix(c(1,1,2,3),2,2) #先看矩陣長什麼樣子 layout(matrix(c(1,1,2,3),2,2)) boxplot(iris$Sepal.Width ~ iris$Species, main = "Plot A") boxplot(iris$Sepal.Width ~ iris$Species, main = "Plot B") boxplot(iris$Sepal.Width ~ iris$Species, main = "Plot C") ``` <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/HkjkjjNPZg.png" width="300"> <br> <span style="color: gray; font-size: 0.8em;">用 layout() 做不對稱排版</span> </div> ## 5.2.3 圖形基本設定 在 `par()` 中,我們也可以控制畫圖的細節部分,如線條樣式、顏色等等,此外也可以在如 `plot()` 等繪圖函數中進行設定。 - `lwd`:線條粗度 - `type`:點與點間連線樣式 - `lty`:線條樣式 - `cex`:字體大小 - `pch`:點的樣式 - `font`:控制粗體斜體 - `col`:顏色控制, <div style="text-align: center;"> <img src="https://r-graph-gallery.com/6-graph-parameters-reminder_files/figure-html/thecode-1.png" width="300"> <br> <span style="color: gray; font-size: 0.8em;">R 繪圖設定代碼</span> </div> 在色彩方面,可以使用不同的代碼,在 R 中都可以去解讀: - 文字名稱:如 "red"、"skyblue"、"gold"。R 內建超過 600 種顏色名稱(可用 `colors()` 查看)。 - 十六進位碼:如 "#FF5733",適合與網頁設計或品牌色對接。 - 數字代號:1=黑, 2=紅, 3=綠, 4=藍 ...。 ```R # 產生測試數據 x <- 1:10 y <- x^2 # 繪圖 plot(x, y, main = "Analysis", # main xlab = "(sec)", # xlab ylab = "(Value)", # ylab col = "darkorange", # col pch = 21, # pch (使用帶邊框的圓) bg = "yellow", # 配合 pch=21 的填充色 cex = 2, # cex (放大點的大小) type = "b", # 同時畫點和線 (both) lty = 2, # lty (使用虛線) lwd = 2) # 加粗線條 ``` <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/BJrxraEv-l.png" width="300"> <br> </div> ## 5.2.3 基本繪圖補充 在 [Ch2](https://hackmd.io/@wwwh0225/H1ImLs9rZg#24-%E6%95%B8%E6%93%9A%E6%B4%9E%E5%AF%9F%EF%BC%9A%E6%95%98%E8%BF%B0%E7%B5%B1%E8%A8%88%E8%88%87%E7%B9%AA%E5%9C%96%E6%87%89%E7%94%A8) 中,我們已有稍微提到繪圖相關的程式碼,我們在此做一些小補充。 當我們畫好一張圖後,若要進行修改,在 R 中是比較困難的。在 R 中的繪圖是類似「疊圖」的方式進行繪製,因此若一步做錯,整張圖就需要重新再繪製一次。 讓我們以與前面章節同樣的一張圖做延伸: <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/BJrxraEv-l.png" width="200"> <br> </div> - 加上「**點**」:`points(x,y)` ```R points(6,60,pch = 11) ``` - 加上「**線段**」:`lines(x,y)` ```R #畫上兩點 x1 <- c(2,4) y1 <- c(80,80) points(x1,y1 ,pch = 15) #連起來 lines(x1,y1) ``` - 加上「**文字**」:`text(x,y,labels)` ```R text(8,20,"GOOD") #在 (8,20) 寫字 ``` - 加上「**直線**」:`abline(a,b)` 為 $y=a+bx$ 的直線 ```R #加上 45度 直線 abline(1,1) #加上水平線 abline(h = 50) #加上垂直線 abline(v = 5) ``` <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/rk6cfAVDWl.png" width="300"> <br> </div> ## 5.2.4 中文字體處理 在進行 R 語言中的繪圖時,中文字體有時會出現顯示異常的情形,我們以下列程式碼為例: ```R curve(dnorm(x, mean = 0, sd = 1), from = -3, to = 3, col = "blue", # 線條顏色 lwd = 2, # 線條寬度 main = "標準常態分佈 N(0,1) pdf", xlab = "z 分數", ylab = "機率密度") ``` <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/ByUMURVvbl.png" width="300"> <br> <span style="color: gray; font-size: 0.8em;">有時候中文字體會顯示不出來</span> </div> 這時,我們必須強制指定一個中文字體 (`family`),讓 R 語言可以正確地進行渲染編碼。 ```R # 以 Mac 電腦為例 curve(dnorm(x, mean = 0, sd = 1), from = -3, to = 3, col = "blue", # 線條顏色 lwd = 2, # 線條寬度 main = "標準常態分佈 N(0,1) pdf", xlab = "z 分數", ylab = "機率密度", family = "STKaiti") # 此處填寫字體名稱 ``` <div style="text-align: center;"> <img src="https://ppt.cc/fSJMGx@.png" width="350"> <br> <span style="color: gray; font-size: 0.8em;">指定中文字體後就可以正確顯示</span> </div> 找尋字體名稱的方法,可以參考[此網址](https://r-lover.com/tutorial/visualization/chinese-in-ggplot2/#%E5%9C%A8Windows%E7%B3%BB%E7%B5%B1%E4%B8%AD%E5%91%88%E7%8F%BE%E4%B8%AD%E6%96%87%E5%AD%97%E9%AB%94)。 # 5.3 用 `ggplot2` 套件進行繪圖 `ggplot2` 是由 Hadley Wickham 開發,基於 Leland Wilkinson 的 「圖形語法」(Grammar of Graphics) 理論,而它的核心思想是:任何圖表都可以拆解成相同的基本組件。 <div style="text-align: center;"> <img src="https://ggplot2.tidyverse.org/articles/ggplot2_files/figure-html/overview_graphic-1.png" width="350"> <br> <span style="color: gray; font-size: 0.8em;">ggplot2 的圖層概念</span> </div> 繪製一張 ggplot2 圖表就像疊加投影片的圖層,基本概念如下: $$\text{ggplot}(\text{data}) + \text{aes}(\text{mappings}) + \text{geom_xxx}()$$ 若要使用 `ggplot2` 套件,需要在 R 中先下載此套件: ```R # 下載套件 install.packages("ggplot2") ``` ```R # 呼叫套件 library(ggplot2) ``` 在 `ggplot2` 中,許多的設定都已被模組化寫好,讓我們以實際案例來介紹 `ggplot2` 的強大之處。 ## 5.3.1 直方圖 我們使用 `geom_histogram` 來繪製直方圖。 我們在此使用美國高中生的身高資料,請先載入套件後,使用 `heights` 資料集。由於 `heights` 資料集內的身高為英吋單位,我們在此先轉換為公分單位。 ``` library(dslabs) #載入套件中的資料集 # 如果沒有此套件,請執行 install.packages("dslabs") # 觀看查詢前 6 筆資料 heights$height_cm <- heights$height * 2.54 #英吋換成公分 head(heights) ``` <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/Bye2fFHDbx.png" width="200"> <br> <span style="color: gray; font-size: 0.8em;">身高資料 (cm)</span> </div> 接著,我們將男生與女生的身高分佈統一畫在同一張圖內。這跟先前所使用的 `par()` 設定不同,`par()` 的並圖是分別畫完一張圖後放入設定好的空間;而 `ggplot2` 是在內部會依據類別的數量自動規劃圖形的合併與呈現規劃。此處的 `facet_wrap` 與 `fill = sex` 就是扮演這個角色。 由於中文字型需要被另外設定,我們需要在 `theme` 中加入指定字體的程式碼,如:`element_text(family = "PingFang TC")`,各台電腦所要對應的字體就如同前述,大家可以測試看看。 ```R ggplot(heights, aes(x = height_cm, fill = sex)) + geom_histogram(binwidth = 5, color = "black", alpha = 0.7) + # 設定 binwidth 和透明度 facet_wrap(~ sex, scales = "free_y") + # 依據 sex 拆圖,scales="free_y" 讓y軸範圍各自調整 labs( title = "男生與女生身高分佈直方圖", subtitle = "分別顯示", x = "身高 (cm)", y = "人數 (Count)", fill = "性別" ) + theme_minimal() + scale_fill_manual(values = c("Female" = "salmon", "Male" = "skyblue")) + # 手動設定顏色 theme(text = element_text(family = "PingFang TC")) # 設定文字字體 ``` <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/SkWbmKBwbl.png" width="340"> <br> <span style="color: gray; font-size: 0.8em;">依照性別繪製直方圖</span> </div> ## 5.3.2 長條圖 在 `ggplot2`,我們使用 `geom_bar` 來繪製長條圖,以下使用 `mpg` 資料集,裡面搜集了許多關於不同品牌汽車油耗的資料。 ```R # 觀察前 6 筆資料 head(mpg) ``` 依照汽車品牌繪製長條圖,由於某些品牌名稱較長,我們設定品牌名稱會旋轉 45 度後呈現: ```R # 長條圖 ggplot(mpg, aes(x = manufacturer)) + geom_bar(fill = "steelblue") + theme_minimal() + labs(title = "各品牌汽車數量長條圖", x = "品牌", y = "數量") + theme(axis.text.x = element_text(angle = 45, hjust = 1), text = element_text(family = "PingFang TC")) # 設定文字字體 ``` <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/HkpcUtBvZe.png" width="400"> <br> <span style="color: gray; font-size: 0.8em;">汽車品牌長條圖</span> </div> 若我們想要依照不同車型上色,一樣是在 `aes()` 中加入 `fill = class`。 ```R # 以車型分類 ggplot(mpg, aes(x = manufacturer, fill = class)) + geom_bar() + scale_fill_brewer(palette = "Set3")+ # 顏色調色盤 theme_minimal() + labs(title = "各品牌之車型組成長條圖", x = "品牌", y = "數量", fill = "車型類別") + theme(axis.text.x = element_text(angle = 45, hjust = 1), text = element_text(family = "PingFang TC")) # 設定文字字體 ``` <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/r1aK8KSv-e.png" width="400"> <br> <span style="color: gray; font-size: 0.8em;">汽車品牌長條圖 - 以類別分組</span> </div> ## 5.3.3 散佈圖 在 ggplot 繪製散佈圖也是十分簡單,只要將 x 軸 與 y 軸對應的座標點匯入即可: ``` # 散佈圖 ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) + geom_point(size = 3) + # 設定點的大小 theme_minimal() + # 使用簡潔主題 labs(title = "Iris 鳶尾花花萼長寬散佈圖", x = "花萼長度 (Sepal Length)", y = "花萼寬度 (Sepal Width)") + theme(text = element_text(family = "PingFang TC")) # 設定文字字體 ``` <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/BJ9Q_KBD-g.png" width="400"> <br> <span style="color: gray; font-size: 0.8em;">鳶尾花散佈圖</span> </div> 如果我們想要把「圖例」移到下方怎麼辦呢? 善用 ChatGPT、Gemini 等工具!!! ```R # AI 修訂 ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) + geom_point(size = 3) + # 設定點的大小 theme_minimal() + # 使用簡潔主題 labs(title = "Iris 鳶尾花花萼長寬散佈圖", x = "花萼長度 (Sepal Length)", y = "花萼寬度 (Sepal Width)") + theme(legend.position = "bottom") #圖例放在最下面 ``` <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/r1fYWVLvWx.png" width="400"> <br> <span style="color: gray; font-size: 0.8em;">鳶尾花散佈圖</span> </div> 此外,`ggplot2` 也可以很簡單地插入變數間的迴歸線,用以表示資料之間的關聯趨勢。 ```R # 加入預測線 ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) + geom_point(size = 3) + # 設定點的大小 theme_minimal() + # 使用簡潔主題 labs(title = "Iris 鳶尾花花萼長寬散佈圖", x = "花萼長度 (Sepal Length)", y = "花萼寬度 (Sepal Width)") + theme(text = element_text(family = "PingFang TC"))+ # 設定文字字體 geom_smooth(method = "lm", color = "black") # 畫出一條整體的黑色預測線 ``` <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/S1DvOKBvbg.png" width="400"> <br> <span style="color: gray; font-size: 0.8em;">鳶尾花散佈圖與迴歸直線</span> </div> 先前,我們曾介紹 `pair()` 函數,用來直接繪製所有資料兩兩間的關係,在 `ggplot2` 的世界裡,我們可以套用 `GGally` 套件,可以給予我們更豐富的分析視角。 `GGally` 除了提供散佈圖之外,還會回報變數間的相關係數、核密度估計 (kernel density estimation, KDE) 以及長條圖及盒狀圖等圖形。 ```R # 安裝並載入套件 install.packages("GGally") ``` ```R library(GGally) # 記得執行 library(ggplot2) # 記得執行 ggpairs(iris, aes(color = Species, alpha = 0.5), title = "GGally 矩陣圖:包含相關係數與分佈") + theme_bw() + theme(text = element_text(family = "PingFang TC")) # 設定文字字體 ``` ![image](https://hackmd.io/_uploads/HkY3LYHv-x.png) ## 5.3.4 熱力圖 熱力圖 (Heatmap) 是一種用顏色表示數值大小的二維圖表,適合用在矩陣型資料 (如:時間 × 地點 → 銷售額)、數值變數之間的相關係數等情境。 我們以 `mtcars` 資料集為例,顯示 32 款不同汽車的性能數據: ```R # 先閱讀資料 head(mtcars) ``` 我們希望觀察資料間相關係數的強弱關係,透過熱力圖將相關係數矩陣視覺化: ```R library(ggplot2) library(reshape2) # 若無此套件,請記得下載install.packages("reshape2") # 取數值欄位 num_mtcars <- Filter(is.numeric, mtcars) # 計算相關係數 cor_mat <- cor(num_mtcars) # 用 melt 轉長表 long_df <- melt(cor_mat) print(head(long_df)) # 畫 heatmap ggplot(long_df, aes(x = Var1, y = Var2, fill = value)) + geom_tile() + scale_fill_gradient2(low="blue", mid="white", high="red", limits=c(-1,1)) + labs(title="mtcars Correlation Heatmap", fill="Correlation") + theme_minimal() ``` <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/SJj2jPvPWx.png" width="400"> <br> <span style="color: gray; font-size: 0.8em;">相關係數熱力圖</span> </div> ## 5.3.4 折線圖 折線圖是分析時間資料常會用到的圖形,我們以航空業資料 `AirPassengers` 來做介紹,我們先將其轉為 `dataframe` 格式後再行繪圖。 ```R df_air <- data.frame( Year = as.numeric(floor(time(AirPassengers))), Month = as.numeric(cycle(AirPassengers)), Passengers = as.numeric(AirPassengers) ) # 將月份數字轉為英文縮寫 (如 1 轉為 Jan) df_air$Month_Name <- factor(month.abb[df_air$Month], levels = month.abb) head(df_air) ``` <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/BkUhSVIvWe.png" width="200"> <br> <span style="color: gray; font-size: 0.8em;">依照年份、月份分類的航空業旅客資料</span> </div> 接下來,讓我們依照年分畫出對應的折線圖: ```R # 折線圖 ggplot(df_air, aes(x = Month_Name, y = Passengers, group = Year, color = factor(Year))) + geom_line(size = 1) + # 畫出折線 geom_point(size = 1.5) + # 加入數據點,方便觀察每個月的數值 scale_color_viridis_d() + # 使用 viridis 調色盤,顏色過渡較自然且專業 theme_minimal() + # 使用簡潔主題 labs( title = "AirPassengers 每月乘客數年度變化圖", subtitle = "觀察各月份在不同年份的增長趨勢", x = "月份", y = "乘客數", color = "年份" # 圖例名稱 ) + theme( legend.position = "right", # 圖例放在右側 plot.title = element_text(face = "bold", size = 14), text = element_text(family = "PingFang TC") ) ``` <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/HyhOOFBP-e.png" width="400"> <br> <span style="color: gray; font-size: 0.8em;">依照年份、月份分類的航空業旅客數折線圖</span> </div> ## 5.3.5 標題位置調整 從我們畫的這幾張圖中,可以看到 `ggplot2` 對於圖表標題的預設是於左上方開始進行呈現。但我們常常會希望進行標題置中,那此時就需要於 `theme()` 中設定 `plot.title = element_text(hjust = 0.5)`,`hjust = 0.5` 是置中的意思,預設的位置是在 0。 ```R # 散佈圖 ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) + geom_point(size = 3) + # 設定點的大小 theme_minimal() + # 使用簡潔主題 labs(title = "Iris 鳶尾花花萼長寬散佈圖", x = "花萼長度 (Sepal Length)", y = "花萼寬度 (Sepal Width)") + theme(text = element_text(family = "PingFang TC"), # 設定文字字體 plot.title = element_text(hjust = 0.5)) # 置中標題 ``` <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/H195_FSPZe.png" width="400"> <br> <span style="color: gray; font-size: 0.8em;">標題置中的鳶尾花散佈圖</span> </div> # 5.4 `plotly` 套件應用 `plotly` 是一個基於 JavaScript (plotly.js) 的繪圖庫,就像是一個儀表板一樣,我們可以透過滑鼠與資料進行互動,或是對圖表進行縮放等直觀性操作。 ```R # 下載套件 install.packages("plotly") ``` ## 5.4.1 `plotly` 內建寫法 我們可以透過 `plot_ly()` 函數去進行圖表的繪製,但這又得讓我們重新學一個繪圖的語法。 ```R plot_ly(data = iris, x = ~Sepal.Length, y = ~Sepal.Width, color = ~Species, type = "scatter", mode = "markers") ``` ## 5.4.1 使用 `ggplotly` 進行轉換 在 R 語言中,`plotly` 最強大的地方在於能透過 `ggplotly()` 函數與 `ggplot2` 無縫接軌。我們只需要照常繪製 `ggplot2` 圖形,再用 `ggplotly()` 包起來,靜態圖瞬間變成互動圖。 <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/rJektFBDWx.png" width="400"> <br> <span style="color: gray; font-size: 0.8em;">ggplotly</span> </div> ```R # 範例1 library(ggplot2) library(plotly) # 先畫一個標準的 ggplot p <- ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) + geom_point() + theme_minimal() # 轉化為互動模式 ggplotly(p) ``` ```R # 範例2 library(ggplot2) library(plotly) # 折線圖轉為 plotly lp <- ggplot(df_air, aes(x = Month_Name, y = Passengers, group = Year, color = factor(Year))) + geom_line(size = 1) + # 畫出折線 geom_point(size = 1.5) + # 加入數據點,方便觀察每個月的數值 scale_color_viridis_d() + # 使用 viridis 調色盤,顏色過渡較自然且專業 theme_minimal() + # 使用簡潔主題 labs( title = "AirPassengers 每月乘客數年度變化圖", subtitle = "觀察各月份在不同年份的增長趨勢", x = "月份", y = "乘客數", color = "年份" # 圖例名稱 ) + theme( legend.position = "right", # 圖例放在右側 plot.title = element_text(face = "bold", size = 14), text = element_text(family = "PingFang TC") ) ggplotly(lp) ``` # 5.5 盡信書,不如無書 ## 5.5.1 Y 軸的陷阱 我們在進行資料時,目的就是希望能夠更直觀的去認識資料,但有時總是會有一些「**狀況**」是我們身為圖表繪製者以及讀者都要去注意的。 #### 折線圖的案例 <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/HJKUAwvw-l.png" width="400"> <br> <span style="color: gray; font-size: 0.8em;">不同 Y 軸起點對視覺造成的影響</span> </div> ``` # 安裝套件(如未安裝) # install.packages("patchwork") library(ggplot2) library(patchwork) #如未安裝,請執行 install.packages("patchwork") # 範例資料 df <- data.frame( year = 2015:2022, value = c(100, 102, 103, 105, 104, 106, 107, 108) ) # 圖 1:Y 軸截斷 p1 <- ggplot(df, aes(x = year, y = value)) + geom_line(linewidth = 1) + geom_point(size = 3) + scale_y_continuous(limits = c(98, 106)) + labs( title = "Y 軸截斷,成長被誇大", x = "年份", y = "數值" ) + theme_minimal() # 圖 2:完整 Y 軸 p2 <- ggplot(df, aes(x = year, y = value)) + geom_line(linewidth = 1) + geom_point(size = 3) + scale_y_continuous(limits = c(0, 110)) + labs( title = "完整期間 + Y 軸從 0 開始", x = "年份", y = "數值" ) + theme_minimal() # 使用 patchwork 並排 p1 + p2 ``` #### 長條圖的案例 <div style="text-align: center;"> <img src="https://hackmd.io/_uploads/SydgZdDv-l.png" width="400"> <br> <span style="color: gray; font-size: 0.8em;">不同 Y 軸起點對視覺造成的影響</span> </div> ```R # 載入套件 library(ggplot2) library(patchwork) # 建立資料 df <- data.frame( 城市 = c("桃園市", "新北市", "台南市", "高雄市", "台中市", "台北市"), COVID盛行率 = c(301, 300, 285, 275, 271, 223) ) # 統一顏色 bar_color <- "#2c7fb8" # 圖 1:完整 Y 軸從 0 開始 p1 <- ggplot(df, aes(x = reorder(城市, -COVID盛行率), y = COVID盛行率)) + geom_col(fill = bar_color) + geom_text(aes(label = COVID盛行率), vjust = -0.5) + scale_y_continuous(limits = c(0, 320)) + labs( title = "Y 軸從 0 開始", x = "城市", y = "盛行率 (每十萬人)" ) + theme_minimal() + theme(text = element_text(family = "PingFang TC")) # 圖 2:Y 軸從 200 開始(截斷) p2 <- ggplot(df, aes(x = reorder(城市, -COVID盛行率), y = COVID盛行率)) + geom_col(fill = bar_color) + geom_text(aes(label = COVID盛行率), vjust = -0.5) + coord_cartesian(ylim = c(200, 320)) + # ← 改這裡 labs( title = "Y 軸從 200 開始(截斷)", x = "城市", y = "盛行率 (每十萬人)" ) + theme_minimal() + theme(text = element_text(family = "PingFang TC")) # 並排 p1 + p2 ``` ## 5.5.2 不要使用雙 Y 軸 在資料視覺化中,很多人會想把兩組數據放在同一張圖上,使用雙 Y 軸。然而,這種做法通常會**帶來誤導與理解成本**。以下是三個主要原因: 1. 容易製造「假相關」 2. 比例可被任意操弄 3. 增加讀者認知負擔 <div style="text-align: center;"> <img src="https://image-cdn.learnin.tw/bnextmedia/image/album/2017-03/img-1490241486-76436.jpg?w=1200&output=webp" width="400"> <br> <span style="color: gray; font-size: 0.8em;">雙軸圖與並排的差別<p>資料來源:《Google必修的圖表簡報術》,商業周刊出版</span> </div> # 參考資料 1. 陳旭昇(2024),資料分析的統計學基礎:使用R語言,東華書局 2. 林建甫 Jeff Lin(2020),[R 資料科學與統計](https://bookdown.org/jefflinmd38/r4biost) 3. Gareth James, Daniela Witten, Trevor Hastie, Robert Tibshirani. (2017). An Introduction to Statistical Learning: With Applications in R. New York: Springer. 4. 陳基國(2024). 基礎統計與R語言. 台北:五南圖書出版股份有限公司 5. 劉奕酉(2022)。[【數據思維】Chart.Guide 視覺化圖表的學習網站,告訴你如何正確的選擇與使用圖表?](https://vocus.cc/article/61d65794fd8978000153e662) 6. Phillips(2026). [YaRrr! The Pirate’s Guide to R](https://nathanieldphillips-yarrr.share.connect.posit.cloud/)