Chuyển đến nội dung chính

Facets cho ggplot2 trong R

Trong hướng dẫn này, bạn sẽ học cách tận dụng tối đa các hàm facetting của ggplot.
Đã cập nhật 5 thg 10, 2026  · 8 phút đọc

Khám phá cùng AI

ChatGPTClaudePerplexity

Giới thiệu

Với facetting, bạn có thể tạo các biểu đồ nhiều khung (multi-panel) và kiểm soát cách thang đo của một khung liên hệ với thang đo của khung khác.

Sử dụng Facet đơn giản

Nếu bạn đã quen với ggplot2, bạn sẽ biết cấu trúc cơ bản của một lời gọi tới hàm ggplot(). Để bắt đầu với ggplot2, bạn có thể xem  khóa học ggplot2 của chúng tôi. Khi gọi ggplot, bạn cung cấp nguồn dữ liệu, thường là một data frame, rồi yêu cầu ggplot ánh xạ các biến khác nhau trong nguồn dữ liệu tới các thuộc tính thẩm mỹ khác nhau, như vị trí trục x hoặc y hay màu sắc của điểm hoặc cột. Với facets, bạn có thêm một cách để ánh xạ các biến. Để minh họa, bạn sẽ sử dụng bộ dữ liệu sau, bao gồm một số chỉ số kinh tế cho một số quốc gia. Phần lớn là các biến thể của GDP, Tổng sản phẩm quốc nội của mỗi quốc gia.

 print(econdata)
##   Country  GDP_nom  GDP_PPP GDP_nom_per_capita GDP_PPP_per_capita
## 1     USA 19390600 19390600              59501              59495
## 2  Canada  1652412  1769270              45077              48141
## 3   China 12014610 23159107               8643              16807
## 4   Japan  4872135  5428813              38440              42659
## 5  France  2583560  2835746              39869              43550
## 6 Germany  3684816  4170790              44550              50206
## 7  Sweden  3684816   520937              53218              51264
## 8 Ireland   333994   343682              70638              72632
##   GNI_per_capita        Region
## 1          58270 North America
## 2          42870 North America
## 3           8690          Asia
## 4          38550          Asia
## 5          37970        Europe
## 6          43490        Europe
## 7          52590        Europe
## 8          55290        Europe

Các biến sau có trong dữ liệu:

Country: Tự giải thích!

GDP_nom: Tổng sản phẩm quốc nội theo giá danh nghĩa bằng USD

GDP_PPP: Tổng sản phẩm quốc nội đã điều chỉnh theo sức mua tương đương

GDP_nom_per_capita: Tổng sản phẩm quốc nội theo giá danh nghĩa bằng USD tính trên đầu người

GDP_PPP_per_capita: Tổng sản phẩm quốc nội đã điều chỉnh theo sức mua tương đương tính trên đầu người

GNI_per_capita: Tổng thu nhập quốc dân của mỗi quốc gia tính trên đầu người.

Region: khu vực trên thế giới nơi quốc gia đó tọa lạc.

Đầu tiên, hãy vẽ một biểu đồ cột đơn giản về GDP danh nghĩa của mỗi quốc gia.

ggplot(econdata, aes(x=Country, y=GDP_nom))+
  geom_bar(stat='identity', fill="forest green")+
  ylab("GDP (nominal)")
plot

Bạn cũng có thể vẽ một biến khác, GDP đã điều chỉnh theo PPP.

ggplot(econdata, aes(x=Country, y=GDP_PPP))+
  geom_bar(stat='identity', fill="forest green")+
  ylab("GDP (PPP)")
plot

Điều này cho bạn một biểu đồ thứ hai, tách biệt, tương tự biểu đồ trước nhưng sử dụng biến khác. Giả sử bạn muốn vẽ cả GDP (danh nghĩa) và GDP (PPP) cùng nhau. Bạn sẽ dùng facetting để làm điều đó. Trước hết, bạn cần định dạng lại dữ liệu, chuyển từ dạng "rộng" với mỗi biến ở một cột sang dạng "dài", trong đó bạn dùng một cột cho giá trị đo và một cột khóa cho biết mỗi hàng đang dùng thước đo nào.

econdatalong <- gather(econdata, key="measure", value="value", c("GDP_nom", "GDP_PPP"))

Khi dữ liệu đã ở định dạng này, bạn có thể sử dụng biến khóa để vẽ với facets. Hãy dựng một biểu đồ đơn giản, hiển thị cả GDP danh nghĩa (từ biểu đồ đầu) và GDP (PPP) (từ biểu đồ thứ hai). Để làm vậy, bạn chỉ cần sửa mã để thêm +facet_wrap() và chỉ định rằng ~measure, biến khóa của chúng ta, sẽ được dùng để facet.

ggplot(econdatalong, aes(x=Country, y=value))+
  geom_bar(stat='identity', fill="forest green")+
  facet_wrap(~measure)
plot

Cách này hoạt động, nhưng bạn sẽ thấy tên quốc gia bị dồn chật. Hãy sắp xếp lại các khung.

Tùy chỉnh bố cục và sắp xếp lại

Lệnh facet_wrap() sẽ tự động chọn số cột. Bạn có thể chỉ định trực tiếp bằng ncol=, như sau:

ggplot(econdatalong, aes(x=Country, y=value))+
  geom_bar(stat='identity', fill="forest green")+
  facet_wrap(~measure,  ncol=1)
plot

Bạn có thể nhận ra rằng các quốc gia trên trục x ở trên được sắp theo thứ tự chữ cái. Nếu muốn thay đổi, cách dễ nhất là đặt lại các mức (levels) của nhân tố Country. Hãy thực hiện việc sắp xếp lại này, sắp các quốc gia theo thứ tự GDP danh nghĩa tăng dần.

econdata$Country <- factor(econdata$Country, levels= econdata$Country[order(econdata$GDP_nom)])


econdatalong <- gather(econdata, key="measure", value="value", c("GDP_nom", "GDP_PPP"))


ggplot(econdatalong, aes(x=Country, y=value))+
  geom_bar(stat='identity', fill="forest green")+
  facet_wrap(~measure,  ncol=1)
plot

Bạn cũng có thể tùy chỉnh thêm, như chuyển nhãn facet sang bên trái bằng tham số strip.position.

ggplot(econdatalong, aes(x=Country, y=value))+
  geom_bar(stat='identity', fill="forest green")+
  facet_wrap(~measure,  ncol=1, strip.position = "left")
plot

Gắn nhãn cho Facet

Bạn có thể đã thấy các facet có tiêu đề ngắn đơn giản, lấy từ các mức của nhân tố measure. Hãy chỉnh gọn và đặt nhãn dễ nhìn hơn cho các facet. Để làm vậy, bạn sẽ tạo một hàm labeller đơn giản, variable_labeller, trả về tên phù hợp khi được yêu cầu một trong các giá trị của variable_names. Sau đó, bạn truyền hàm này vào tham số labeller của facet_wrap.

variable_names <- list(
  "GDP_nom" = "GDP (nominal)" ,
  "GDP_PPP" = "GDP (purchasing power parity)"
)


variable_labeller <- function(variable,value){
  return(variable_names[value])
}


ggplot(econdatalong, aes(x=Country, y=value))+
  geom_bar(stat='identity', fill="forest green")+
  facet_wrap(~measure,  ncol=1, labeller=variable_labeller)
plot

Tùy chỉnh thang đo và không gian

Hãy dựng một biểu đồ facet lớn hơn, sử dụng từng thước đo kinh tế.

econdatalong <- gather(econdata, key="measure", value="value", c( "GDP_nom" , "GDP_PPP" ,"GDP_nom_per_capita", "GDP_PPP_per_capita" ,"GNI_per_capita"))

variable_names <- list(
  "GDP_nom" = "GDP (nominal)" ,
  "GDP_PPP" = "GDP (purchasing power parity)",
  "GDP_nom_per_capita" = "GDP (nominal) per capita",
  "GDP_PPP_per_capita" = "GDP (purchasing power parity) per capita",
  "GNI_per_capita"  = "GNI per capita"
)


variable_labeller <- function(variable,value){
  return(variable_names[value])
}



ggplot(econdatalong, aes(x=Country, y=value))+
  geom_bar(stat='identity', fill="forest green")+
  facet_wrap(~measure,  ncol=1, labeller= variable_labeller)+
scale_y_continuous(breaks = pretty(econdatalong$value, n = 10))
plot

Thế này thì không ổn chút nào! Bạn không thể thấy giá trị ở ba khung. Tại sao vậy? Hãy xem dữ liệu gốc để hiểu lý do.

summary(econdata)
##     Country     GDP_nom            GDP_PPP         GDP_nom_per_capita
##  Ireland:1   Min.   :  333994   Min.   :  343682   Min.   : 8643     
##  Canada :1   1st Qu.: 2350773   1st Qu.: 1457187   1st Qu.:39512     
##  France :1   Median : 3684816   Median : 3503268   Median :44814     
##  Germany:1   Mean   : 6027118   Mean   : 7202368   Mean   :44992     
##  Sweden :1   3rd Qu.: 6657754   3rd Qu.: 8919260   3rd Qu.:54789     
##  Japan  :1   Max.   :19390600   Max.   :23159107   Max.   :70638     
##  (Other):2                                                           
##  GDP_PPP_per_capita GNI_per_capita            Region
##  Min.   :16807      Min.   : 8690   Asia         :2  
##  1st Qu.:43327      1st Qu.:38405   Europe       :4  
##  Median :49174      Median :43180   North America:2  
##  Mean   :48094      Mean   :42215                    
##  3rd Qu.:53322      3rd Qu.:53265                    
##  Max.   :72632      Max.   :58270                    
##

Nếu xem từng cột, bạn sẽ thấy giá trị ở mỗi cột trải rộng qua vài bậc độ lớn. Mặc định, facetting sẽ dùng cùng giới hạn và phạm vi cho cả trục X và Y. Để thay đổi, bạn có thể thêm đoạn này vào mã facetting: scales="free_y" để mỗi facet dùng một thang đo y độc lập.

ggplot(econdatalong, aes(x=Country, y=value))+
  geom_bar(stat='identity', fill="forest green")+
  facet_wrap(~measure, scales="free_y", ncol=1,  labeller= variable_labeller)
plot

Tốt hơn nhiều. Mỗi facet giờ có trục y độc lập.

Dùng Facet để tạo phân nhóm

Bạn có thể đã nhận thấy bộ dữ liệu còn có biến Region, cho biết quốc gia đó thuộc khu vực nào. Bạn có thể dùng biến này để tô màu các cột theo khu vực như sau:

ggplot(econdatalong, aes(x=Country, y=value, fill=Region))+
  geom_bar(stat='identity')+
  facet_wrap(~measure, scales="free_y", ncol=1, labeller= variable_labeller)
plot

Tuy nhiên, điều này hơi rối. Sẽ tốt hơn nếu bạn có thể đặt mỗi khu vực vào một khung phụ riêng? Với facetting, bạn có thể! Ở đây bạn sẽ dùng facet_grid thay vì facet_wrap, vì nó giúp ánh xạ facets theo hai biến, Region và measure, trong đó hai biến này trải theo các hàng và cột của một lưới biểu đồ. Lưu ý bạn cũng đặt scales="free" và space="free", cho phép các khung khác nhau chiếm lượng không gian khác nhau. Bạn cũng cần tạo một hàm labeller mới, để tạo nhãn cho cả hàng và cột.

variable_names <- list(
  "GDP_nom" = "GDP \n(nominal)" ,
  "GDP_PPP" = "GDP \n(PPP)",
  "GDP_nom_per_capita" = "GDP (nominal)\n per capita",
  "GDP_PPP_per_capita" = "GDP (PPP)\n per capita",
  "GNI_per_capita"  = "GNI \nper capita"
)



region_names <- levels(econdata$Region)


variable_labeller2 <- function(variable,value){
  if (variable=='measure') {
  return(variable_names[value])
  } else {
    return(region_names)
  }
}

ggplot(econdatalong, aes(x=Country, y=value, fill=Region))+
  geom_bar(stat='identity')+
  facet_grid(measure~Region, scales="free", space="free_x",  labeller= variable_labeller2)
plot

Bây giờ thì rõ ràng hơn nhiều! Mỗi khu vực có một cột khung riêng, và mỗi thước đo có một hàng cột riêng.

Vậy là kết thúc hướng dẫn này. Hy vọng bạn thấy thú vị khi tìm hiểu về facets.

Nếu muốn tìm hiểu thêm về facets, hãy học khóa Trực quan hóa Dữ liệu lớn với Trelliscope của DataCamp.

Xem thêm Bắt đầu với Tidyverse: Hướng dẫn của chúng tôi.

Chủ đề
R
Khoa học Dữ liệu

Khóa học R

Khóa học

Nhập môn Ngôn ngữ lập trình R

4 giờ
3.1M
Nắm vững kiến thức cơ bản về phân tích dữ liệu trong R, gồm vectors, lists và data frames; luyện tập R với các data set thực tế.
Xem chi tiếtRight Arrow
Bắt Đầu Khóa Học
Xem thêmRight Arrow
Liên quan

blog

Claude Opus 4.6: Tính năng, Điểm chuẩn, Bài kiểm tra thực hành và hơn thế nữa

Mô hình mới nhất của Anthropic dẫn đầu ở mã hóa tác tử và lập luận phức tạp. Thêm vào đó, nó có cửa sổ ngữ cảnh 1M.
Matt Crabtree's photo

Matt Crabtree

10 phút

Xem ThêmXem Thêm