HOWTO · R

如何在 R 的 ggplot2 中修改座標軸刻度標籤

說明如何修改 ggplot2 離散軸與連續軸的刻度標籤、設定格式,並解決長標籤重疊問題。

若刻度來自因子或字元資料,使用 scale_x_discrete(labels = ...) 重新命名;若是數值刻度,使用 scale_x_continuous(breaks = ..., labels = ...) 設定位置與格式。旋轉等外觀調整應放在 theme(axis.text.x = element_text(...))labs(x = ...) 修改的是座標軸標題,不是刻度標籤。要處理縱軸時,把這些函式中的 x 換成 y

範例需要 R 與 ggplot2;連續軸範例還使用 scales 套件格式化標籤。程式已在 R 4.1.2、ggplot2 3.3.5 與 scales 1.1.1 中驗證。這裡使用的尺度引數也存在於目前的 ggplot2,但不同版本的佈景主題細節可能略有差異。

工作 ggplot2 設定
修改座標軸標題 labs(x = "Title")labs(y = "Title")
重新命名因子或字元刻度 scale_x_discrete(labels = ...)
設定數值刻度位置與文字 scale_x_continuous(breaks = ..., labels = ...)
旋轉刻度文字或設定樣式 theme(axis.text.x = element_text(...))
格式化 Date scale_x_date(breaks = ..., labels = ...)

建立基準 ggplot2 圖表

以下持續使用同一個小型資料框,方便清楚比較每項修改。plan 欄是因子,因此 ggplot2 為它建立離散 x 軸;orders 欄是數值,因此使用連續 y 軸。

library(ggplot2)

plan_sales <- data.frame(
  plan = factor(
    c("starter", "standard", "premium", "enterprise"),
    levels = c("starter", "standard", "premium", "enterprise")
  ),
  orders = c(180, 250, 210, 140)
)

base_plot <- ggplot(plan_sales, aes(x = plan, y = orders)) +
  geom_col(fill = "#2c7fb8", width = 0.7) +
  labs(x = "Plan", y = "Orders") +
  theme_minimal(base_size = 16)

base_plot
ggsave(
  "ggplot-default-axis-tick-labels.png",
  plot = base_plot, width = 7.4, height = 4.82, dpi = 100, bg = "white"
)

顯示未修改之 x 軸與 y 軸刻度標籤的預設 ggplot2 圖表。

基準圖在 x 軸顯示四個已儲存的因子值,並在 y 軸顯示自動選取的數值刻度。labs(x = "Plan") 設定 x 軸標題「Plan」,不會改寫 starterstandard 等刻度文字。

選擇尺度前,應檢查映射變數,不要根據圖形外觀猜測。str(plan_sales$plan) 會顯示因子,str(plan_sales$orders) 則顯示數值向量。即使分類代碼看似 "1""2",因子仍是離散型;即使目前只有幾個不重複值,數值欄仍是連續型。只有當新型別符合資料的實際意義時才轉換型別。

重新命名離散軸刻度標籤並調整順序

在離散尺度中,應成對指定 breakslabelsbreaks 選擇要顯示刻度的底層資料值,labels 提供這些位置印出的文字。明確配對可避免尺度順序改變後標籤錯位。

以下也示範如何安全調整分類順序:先在資料副本中變更因子層級,再把同一序列傳給 breaks。具名標籤向量讓映射關係在執行前就清楚可見。

plan_order <- c("premium", "standard", "starter", "enterprise")
plan_names <- c(
  premium = "Premium",
  standard = "Standard",
  starter = "Starter",
  enterprise = "Enterprise"
)

ordered_sales <- plan_sales
ordered_sales$plan <- factor(ordered_sales$plan, levels = plan_order)

discrete_plot <- ggplot(ordered_sales, aes(x = plan, y = orders)) +
  geom_col(fill = "#2c7fb8", width = 0.7) +
  scale_x_discrete(
    breaks = plan_order,
    labels = plan_names[plan_order]
  ) +
  labs(x = "Plan", y = "Orders") +
  theme_minimal(base_size = 16)

discrete_plot
ggsave(
  "ggplot-discrete-axis-tick-labels.png",
  plot = discrete_plot, width = 7.4, height = 4.82, dpi = 100, bg = "white"
)

重新命名並調整離散 x 軸類別順序的 ggplot2 圖表。

顯示順序應為 Premium、Standard、Starter、Enterprise。小寫資料值維持不變,改變的只有呈現方式。若同一規則適用於所有刻度,可使用標籤函式。例如 scale_x_discrete(labels = abbreviate) 會把所有刻度值傳給 base R 的 abbreviate()。自訂 function(x) 必須傳回與輸入等長的字元向量。

如果只需改名並保留現有順序,可省略 breaks,傳入涵蓋所有顯示值的具名向量,例如 c(starter = "Starter", standard = "Standard", premium = "Premium", enterprise = "Enterprise")。如果顯示集合與順序都有明確要求,上面的成對寫法較可靠。篩選資料後,請由左至右讀取 x 軸,並與此處列出的預期順序核對。

不要混用 breakslimits。離散尺度中的 breaks 只選擇顯示哪些刻度,不會改變尺度接受的類別;limits 則定義允許值與順序。範圍外的值會轉成遺失值,geom_col() 等圖層可能接著發出警告並移除對應資料列。若順序屬於資料意義,調整因子層級會更清楚;只有確實要排除值時才使用 limits

設定連續軸刻度位置與格式

數值軸需要連續尺度。把確切位置傳給 breaks,再把等長文字或格式化函式傳給 labels。若數值可能變動,函式較安全,因為 ggplot2 會以最終刻度位置呼叫它。

以下散佈圖把馬力刻度放在 100、200 與 300,並用 scales::label_number() 加上單位。繪圖前直接呼叫格式化函式,還可先檢查實際標籤文字。

hp_breaks <- c(100, 200, 300)
hp_formatter <- scales::label_number(suffix = " hp", accuracy = 1)
hp_formatter(hp_breaks)

continuous_plot <- ggplot(mtcars, aes(x = hp, y = mpg)) +
  geom_point(size = 3, color = "#d95f0e") +
  scale_x_continuous(
    breaks = hp_breaks,
    labels = hp_formatter
  ) +
  labs(x = "Engine power", y = "Fuel economy (mpg)") +
  theme_minimal(base_size = 16)

continuous_plot
ggsave(
  "ggplot-continuous-axis-tick-labels.png",
  plot = continuous_plot, width = 7.4, height = 4.82, dpi = 100, bg = "white"
)
[1] "100 hp" "200 hp" "300 hp"

自訂連續軸刻度位置與標籤格式的 ggplot2 圖表。

x 軸應恰好顯示這三個位置與標籤。數值 y 軸使用對應的 scale_y_continuous()。scales 中的其他格式化函式可顯示千分位、百分比、貨幣等;由於只改變標籤文字,資料仍維持數值型別。

當位置本身有意義時,應像這些馬力值一樣明確指定 breaks。如果只需控制格式,則省略 breaks,讓 ggplot2 依資料範圍選擇位置,只把格式化函式傳給 labels。不要為了加上後綴而先把數值欄轉成字串,否則尺度型別會改變,並可能依字典順序而非數值間距排列。格式化函式不會改變計算或資料點位置。

日期屬於另一種尺度。映射欄繼承 Date 時,應使用 scale_x_date() 或對應的 y 軸函式,不要強制套用數值或離散尺度。它需要適用於日期的刻度位置與格式,但 breakslabels 的職責相同。

旋轉重疊的刻度標籤

修改標籤內容與設定文字樣式是兩件事。文字正確但互相重疊時,保留原尺度並調整佈景主題中的 axis.text.x。這裡 angle = 35 會旋轉每個標籤,hjust = 1 將右緣對齊刻度位置;較大的基礎字級也讓窄圖較易閱讀。

channel_sales <- data.frame(
  channel = c(
    "North America Online",
    "Europe Retail Stores",
    "Asia Pacific Partners",
    "Latin America Direct"
  ),
  orders = c(260, 220, 195, 150)
)

rotated_plot <- ggplot(channel_sales, aes(x = channel, y = orders)) +
  geom_col(fill = "#31a354", width = 0.65) +
  labs(x = "Sales channel", y = "Orders") +
  theme_minimal(base_size = 18) +
  theme(
    axis.text.x = element_text(angle = 35, hjust = 1, vjust = 1)
  )

rotated_plot
ggsave(
  "ggplot-rotated-axis-tick-labels.png",
  plot = rotated_plot, width = 7.4, height = 4.82, dpi = 100, bg = "white"
)

旋轉並對齊較長的 x 軸刻度標籤,以避免重疊的 ggplot2 圖表。

旋轉會保留每個類別名稱。如果仍然相互碰撞,縮短文字或加寬圖表通常比繼續增加角度更清楚。在已驗證的 ggplot2 3.3.5 環境中,scale_x_discrete(guide = guide_axis(n.dodge = 2)) 可把離散標籤錯開成兩列;目前 ggplot2 API 中也有這個函式。它適合保留水平文字,但會占用更多垂直空間。其他做法請參閱在 base R 或 ggplot2 中旋轉座標軸標籤

有意隱藏標籤、刻度線或刻度位置

這些設定並非同義,應根據要移除的物件選擇。

control_plot <- base_plot +
  theme_classic(base_size = 16)

labels_hidden <- control_plot +
  theme(axis.text.x = element_blank())

ticks_hidden <- control_plot +
  theme(axis.ticks.x = element_blank())

breaks_hidden <- control_plot +
  scale_x_discrete(breaks = NULL)

control_plot 使用會繪製短刻度線的 theme_classic(),因此每項變化都有可觀察的基準。labels_hidden 只移除 x 軸文字;ticks_hidden 只移除短刻度線,類別名稱仍會保留;breaks_hidden 讓尺度不產生主要 x 軸刻度位置,與之相連的標籤及刻度線都會消失。這些運算式都不會篩除 plan_sales 的資料列。

在尺度中設定 labels = NULL 會保留刻度位置但隱藏標籤。若尺度定義上就不應顯示標籤,可選擇它;若尺度仍有意義,只是不希望某個圖表佈景主題繪製文字,則使用 element_blank()。隱藏分類標籤可能讓讀者無法辨識長條或資料點,因此類別仍重要時,要提供直接註記或其他圖例。

這三個物件沒有存成圖片,因為可選取的程式碼與精確說明更容易比較。可在 R 主控台顯示 ticks_hidden,並與 control_plot 對照。三種結果的長條及高度都應維持不變,只有座標軸引導元素不同。若幾何圖形改變或出現移除資料列的警告,應檢查圖中其他位置的 limits 呼叫,而不是這裡的佈景主題設定。

排解錯誤或缺少的刻度標籤

如果 ggplot2 回報把連續值提供給離散尺度,或相反的情況,應先用 str() 檢查映射欄。因子與字元欄使用離散尺度,數值欄使用連續尺度,Date 與日期時間物件使用相應的日期尺度。不要只為消除錯誤而轉換資料;只有新型別符合值的真正意義時才轉換。

labels 使用字元向量時,務必與明確的 breaks 配對並保持長度一致。否則篩選、重新排序或新增類別後,標籤可能錯位。plan_names 這類具名映射會說明每個儲存值對應的顯示名稱。如果所有刻度值都套用同一轉換,函式可避免長度問題。

長條缺少或出現移除資料列警告時,原因通常是 limits 而不是 labels。請檢查尺度範圍是否漏掉資料中的值。若目標只是減少可見刻度標籤數量,應使用 breaks。有意縮放或控制範圍的做法,請參閱設定 ggplot2 座標軸範圍而不與刻度位置混淆

最後,確認要修改的是否其實是座標軸標題。labs(x = "Plan") 與 x 尺度的 name 引數會設定標題,labels 引數則控制刻度文字。區分這兩項職責,可避免標題已改變但類別名或數字標籤仍未變的困惑。

對多數圖表而言,應依映射資料型別選擇尺度,需要精確文字時成對設定 breakslabels,並只用 theme() 控制外觀。這樣既可讓座標軸修改結果可預期,也不會改變底層觀測值。