Categories: R

R 使用 ggplot2 繪製長條圖教學與範例

介紹如何使用 R 的 ggplot2 套件繪製高品質的長條圖(bar plot)。

基本長條圖

準備資料

在繪製長條圖之前,先準備好類型名稱 type 與數值 value 的對應表:

# 準備繪製長條圖的資料
my.df <- data.frame(
  type = c("A", "B", "C"),
  value = c(5.6, 7.2, 3.1)
)

查看建立好的資料:

# 查看資料
my.df
  type value
1    A   5.6
2    B   7.2
3    C   3.1

如果原始資料是類別型的,想要計算各類別的出現次數,可以使用 table 函數:

# 類別型原始資料
my.cat.data <- c("A", "C", "B", "C", "A", "A",  "C", "A", "B", "A")

# 計算各類別出現次數
my.cat.df <- data.frame(table(my.cat.data))

# 查看資料
my.cat.df
  my.cat.data Freq
1           A    5
2           B    2
3           C    3

繪製長條圖

若要使用 ggplot2 套件繪製長條圖,可以使用 geom_bar() 這個幾何圖形:

library(ggplot2)

# 基本長條圖
p <- ggplot(data = my.df, aes(x = type, y = value)) +
  geom_bar(stat = "identity")
p
基本長條圖

如果想要繪製橫向的長條圖,可以加上 coord_flip() 將 X 軸與 Y 軸對調,翻轉圖形:

# X 軸與 Y 軸對調
p + coord_flip()
X 軸與 Y 軸對調

排序

若要依據對應的數值來排序類別,可以使用 reorder() 重新排序類別:

# 依據類別對應的數值排序
p <- ggplot(data = my.df, aes(x = reorder(type, value), y = value)) +
  geom_bar(stat = "identity")
p
依據類別對應的數值排序

若要將 X 軸的各類別以反向的方式排序,可以使用 scale_x_discrete() 搭配 limits = rev 參數:

# 反向排序
p + scale_x_discrete(limits = rev)
反向排序

由於這裡使用了 reorder() 重新排序類別,所以 X 軸的標示文字也會自動跟著改變,若要自行指定 X 軸的標示文字,可以使用 xlab() 來處理。

調整寬度

若要調整長條圖的寬度,可以使用 geom_bar()width 參數:

# 調整長條圖寬度
p <- ggplot(data = my.df, aes(x = type, y = value)) +
  geom_bar(stat = "identity", width = 0.5)
p
調整長條圖寬度

調整顏色

若要調整長條圖的顏色,可以使用 geom_bar()fill 參數指定十六進位的色碼,或是顏色名稱(可用 colors() 查詢 R 中可用的顏色名稱):

# 調整長條圖顏色
p <- ggplot(data = my.df, aes(x = type, y = value)) +
  geom_bar(stat = "identity", fill = "#6ab04c")
p
調整長條圖顏色

亦可根據不同的 type 設定不同顏色:

# 根據不同的 type 設定不同顏色
p <- ggplot(data = my.df, aes(x = type, y = value, fill = type)) +
  geom_bar(stat = "identity")
p
根據不同的 type 設定不同顏色

使用 Dark2 色盤:

# 使用 Dark2 色盤
p + scale_fill_brewer(palette = "Dark2")
使用 Dark2 色盤

若要查詢可用的色盤,可以參考 scale_colour_brewer 函數的文件,或使用 RColorBrewer 套件的 display.brewer.all 直接顯示每個色盤:

# 查詢可用的色盤
library(RColorBrewer)
display.brewer.all()

我們也可以自行定義色盤:

# 使用自訂色盤
p + scale_fill_manual(values = c("#999999", "#E69F00", "#56B4E9"))
使用自訂色盤

自訂色盤也可以用來標示特定的資料,例如將特別的類別設定為紅色,而其餘設定為灰色。

# 標示特定資料
p + scale_fill_manual(values = c("#999999", "#990000", "#999999")) +
  theme(legend.position = "none") # 不顯示圖例說明
標示特定資料

加入標示文字

若要在長條圖中以文字標示個別的數值,可以使用 geom_text() 並指定要標示的文字內容,同時以 vjustsize 微調文字的位置與大小:

# 長條圖加上標示文字(外部)
p <- ggplot(data = my.df, aes(x = type, y = value)) +
  geom_bar(stat = "identity") +
  geom_text(aes(label = value), vjust = -0.3, size = 5.5) +
  ylim(c(0, 8)) # 避免文字超出繪圖範圍
p
長條圖加上標示文字(外部)

若要將文字放在長條圖內部,可以改變 vjust 的移動方向,並以 color 指定適合的文字顏色:

# 長條圖加上標示文字(內部)
p <- ggplot(data = my.df, aes(x = type, y = value)) +
  geom_bar(stat = "identity") +
  geom_text(aes(label = value), vjust = 1.6, size = 5.5, color = "white")
p
長條圖加上標示文字(內部)

分組長條圖

準備資料

準備具有組別資訊的資料。

# 準備繪製長條圖的資料,具有組別資訊
my.df2 <- data.frame(
  type = c("A", "B", "C", "A", "B", "C"),
  group = c("G1", "G1", "G1", "G2", "G2", "G2"),
  value = c(5.6, 7.2, 3.1, 7.8, 11.2, 2.1)
)

查看建立好的資料:

# 查看資料
my.df2
  type group value
1    A    G1   5.6
2    B    G1   7.2
3    C    G1   3.1
4    A    G2   7.8
5    B    G2  11.2
6    C    G2   2.1

堆疊長條圖

若要根據組別資訊,繪製堆疊長條圖,可以將 fill 參數指定為組別的資訊,就會自動依據組別區分顏色:

# 根據組別資訊,繪製堆疊長條圖
p <- ggplot(data = my.df2, aes(x = type, y = value, fill = group)) +
  geom_bar(stat = "identity")
p
堆疊長條圖

並排長條圖

若要堆疊的長條圖改為並排顯示,可以將 geom_bar()position 設定為 position_dodge()

# 根據組別資訊,繪製並排長條圖
p <- ggplot(data = my.df2, aes(x = type, y = value, fill = group)) +
  geom_bar(stat = "identity", position = position_dodge())
p
並排長條圖

調整顏色

上面介紹過的顏色調整方式,都可以套用在這裡:

# 使用 Paired 色盤
p + scale_fill_brewer(palette = "Paired")
使用 Paired 色盤

加入標示文字

若要在並排長條圖加上標示文字,記得要將 geom_text() 中的 position 設為 position_dodge()

# 並排長條圖加上標示文字(外部)
p <- ggplot(data = my.df2, aes(x = type, y = value, fill = group)) +
  geom_bar(stat = "identity", position = position_dodge()) +
  geom_text(aes(label = value), vjust = -0.3, size = 4.0, position = position_dodge(0.9)) +
  ylim(c(0, 11.5)) # 避免文字超出繪圖範圍
p
並排長條圖加上標示文字(外部)

若要將文字放在長條圖內部,作法也是大同小異:

# 並排長條圖加上標示文字(內部)
p <- ggplot(data = my.df2, aes(x = type, y = value, fill = group)) +
  geom_bar(stat = "identity", position = position_dodge()) +
  geom_text(aes(label = value), vjust = 1.6, size = 4.0,
    color = "white", position = position_dodge(0.9))
p
並排長條圖加上標示文字(內部)

誤差棒

若要在長條圖中加上表示誤差的誤差棒(error bar),可以先準備好含有誤差資訊的資料:

# 準備繪製長條圖的資料,具有誤差資訊
my.df3 <- data.frame(
  type = c("A", "B", "C"),
  value = c(5.6, 7.2, 3.1),
  sd = c(0.44, 0.51, 0.32)
)

再使用 geom_errorbar() 加入誤差棒:

# 長條圖加上誤差棒
p <- ggplot(data = my.df3, aes(x = type, y = value)) +
  geom_bar(stat = "identity") +
  geom_errorbar(aes(ymin = value - sd, ymax = value + sd), width = 0.2)
p
長條圖加上誤差棒

誤差棒亦可用於並排的長條圖中:

# 準備繪製長條圖的資料,具有組別、誤差資訊
my.df4 <- data.frame(
  type = c("A", "B", "C", "A", "B", "C"),
  group = c("G1", "G1", "G1", "G2", "G2", "G2"),
  value = c(5.6, 7.2, 3.1, 7.8, 11.2, 2.1),
  sd = c(0.44, 0.51, 0.32, 0.52, 0.91, 0.21)
)

# 並排長條圖加上誤差棒
p <- ggplot(data = my.df4, aes(x = type, y = value, fill = group)) +
  geom_bar(stat = "identity", position = position_dodge()) +
  geom_errorbar(aes(ymin = value - sd, ymax = value + sd),
    width = 0.2, position = position_dodge(0.9))
p
並排長條圖加上誤差棒

正值與負值長條圖

ggplot2 套件也可以繪製含有負值的長條圖,首先準備含有負值的資料:

# 準備繪製長條圖的資料,含有負值
my.df5 <- data.frame(
  type = c("A", "B", "C", "D", "E", "F"),
  value = c(5.6, 7.2, 3.1, -0.9, -2.7, 4.5)
)

按照一般的方式將資料交給 geom_bar() 即可自動繪製出含有負值的長條圖:

# 含有負值的長條圖
p <- ggplot(data = my.df5, aes(x = type, y = value)) +
  geom_bar(stat = "identity")
p
含有負值的長條圖

若要以顏色區分正負值,可以透過 fill 來設定:

# 以顏色區分正負值
p <- ggplot(data = my.df5, aes(x = type, y = value, fill = value > 0)) +
  geom_bar(stat = "identity")
p
以顏色區分正負值

若要依據數值來排序類別,可以使用 reorder() 重新排序類別:

# 依據數值排序
p <- ggplot(data = my.df5, aes(x = reorder(type, value), y = value, fill = value > 0)) +
  geom_bar(stat = "identity")
p
依據數值排序

參考資料

Share
Published by
Office Guide

Recent Posts

Python 使用 PyAutoGUI 自動操作滑鼠與鍵盤

本篇介紹如何在 Python ...

1 年 ago

Ubuntu Linux 以 WireGuard 架設 VPN 伺服器教學與範例

本篇介紹如何在 Ubuntu ...

1 年 ago

Linux 網路設定 ip 指令用法教學與範例

本篇介紹如何在 Linux 系...

1 年 ago

Linux 以 Cryptsetup、LUKS 加密 USB 隨身碟教學與範例

介紹如何在 Linux 系統中...

1 年 ago