ggplot2 dựng biểu đồ từ các lớp
ggplot2 là package vẽ biểu đồ được dùng rộng rãi nhất của R, và người ta mê nó vì một ý tưởng thiết kế: ngữ pháp đồ họa (grammar of graphics). Base R cho bạn mỗi loại biểu đồ một hàm (plot(), hist(), barplot()), hàm nào cũng có bộ đối số riêng. ggplot2 thì cho bạn một nhóm nhỏ các thành phần ghép được với nhau: một bộ dữ liệu, một ánh xạ từ cột sang thuộc tính hình ảnh, và các lớp vẽ, kết hợp bằng + thành bất kỳ biểu đồ nào. Học ngữ pháp một lần, và mọi loại biểu đồ mới chỉ là cùng một câu với một từ được thay đổi. Thêm nữa, các mặc định (nền xám, trục hợp lý, chú giải tự động) trông đã đủ chỉn chu mà không cần chỉnh gì.
Đây là package bổ sung, nên cần cài một lần và nạp ở mỗi phiên làm việc:
install.packages("ggplot2") # once, on your machine
library(ggplot2) # at the top of every script that uses it
Một điều nên biết ngay từ đầu: ggplot2 cần một data frame (không phải các vector rời rạc), lý tưởng là ở dạng dài gọn gàng (tidy): mỗi hàng một quan sát, mỗi cột một biến. Nếu dữ liệu của bạn ở dạng rộng, xoay nó sang dạng dài trước thường làm biến mất thứ trông giống như một vấn đề về vẽ biểu đồ.
Mô hình tư duy: dữ liệu, ánh xạ, hình học
Mỗi biểu đồ ggplot trả lời ba câu hỏi, mỗi phần một câu:
- Dữ liệu: data frame nào?
ggplot(mtcars, ...) - Ánh xạ: cột nào điều khiển thuộc tính hình ảnh nào?
aes(x = wt, y = hp) - Hình học: các quan sát được vẽ ra như thế nào?
+ geom_point()
Đây là cấu trúc của nó, từng phần một:
ggplot(mtcars, aes(x = wt, y = hp)) +
geom_point()
ggplot(mtcars, ...)bắt đầu một biểu đồ có dữ liệu mặc định làmtcars. Chỉ riêng nó thì vẽ ra một khung xám trống, vì chưa có lớp nào.aes(x = wt, y = hp)là ánh xạ thẩm mỹ (aesthetic mapping): vị trí ngang lấy từ cộtwt, vị trí dọc lấy từhp. Để ý bạn viết tên cột trơn, không phảimtcars$wt: ánh xạ được tính bên trong dữ liệu bạn đã cung cấp.+ geom_point()thêm một lớp vẽ mỗi hàng thành một điểm. Dấu+thật sự là phép cộng các lớp: biểu đồ là một đối tượng bạn xây dần, và bạn có thể cộng thêm mãi (một geom khác, nhãn, theme), mỗi thứ bằng một dấu+nữa.
Chạy nó, bạn được đúng biểu đồ phân tán cân nặng so với mã lực như phiên bản base R trong hướng dẫn biểu đồ phân tán, trên nền xám với lưới trắng. Đổi geom_point() thành geom_line() và cùng ánh xạ đó trở thành biểu đồ đường: ngữ pháp đang làm đúng việc của nó.
Những geom bạn thật sự sẽ dùng
Chừng chục geom đủ cho gần như mọi việc hằng ngày:
geom_point() # scatter plot: two numeric variables
geom_line() # line chart: trends over an ordered variable
geom_col() # bar chart from pre-computed heights (needs y)
geom_bar() # bar chart that counts raw rows for you (no y)
geom_histogram() # distribution of one numeric variable (set binwidth)
geom_boxplot() # distributions compared across groups
geom_smooth() # fitted trend line; method = "lm" for straight
Các lớp chồng lên nhau, và đó là lúc ggplot2 bắt đầu vượt base R về khả năng diễn đạt: geom_point() + geom_smooth(method = "lm") là biểu đồ phân tán có đường hồi quy và dải tin cậy, chỉ trong một dòng dễ đọc. Vì biểu đồ là đối tượng, bạn cũng có thể lưu một bản gốc rồi rẽ nhánh từ nó:
p <- ggplot(mtcars, aes(x = wt, y = hp)) + geom_point()
p + geom_smooth(method = "lm") # one variant
p + geom_smooth() # another (loess curve)
Ánh xạ và thiết lập: nhầm lẫn kinh điển với aes()
Lỗi mà mọi người mới học ggplot2 đều mắc, thường ngay tuần đầu: đặt một màu cụ thể bên trong aes(). Quy tắc rất ngắn: bên trong aes() nghĩa là "thay đổi theo dữ liệu"; bên ngoài nghĩa là "thiết lập cố định", và hai vị trí đó làm những việc hoàn toàn khác nhau:
# MAPPING: color varies by a column - each cylinder count gets its own
# color, and a legend appears automatically
ggplot(mtcars, aes(x = wt, y = hp, color = factor(cyl))) +
geom_point(size = 2)
# SETTING: every point is literally steelblue - no legend, no mapping
ggplot(mtcars, aes(x = wt, y = hp)) +
geom_point(color = "steelblue", size = 2)
Và chính cái bẫy:
# WRONG: "blue" inside aes() is treated as data, not as a color
ggplot(mtcars, aes(x = wt, y = hp, color = "blue")) +
geom_point()
Đoạn này vẽ các điểm màu hồng cá hồi kèm một chú giải có duy nhất một mục mang nhãn "blue". Lý do: aes() ánh xạ cột sang thuộc tính, nên color = "blue" tạo ra một cột giả một nhóm, có giá trị là chữ "blue" ở mọi hàng, và ggplot gán cho nhóm đó màu mặc định đầu tiên của nó, tình cờ lại là màu hồng cá hồi ngả đỏ. Nếu ý bạn là "tô các điểm màu xanh", màu phải nằm ngoài ánh xạ: geom_point(color = "blue"). Cùng quy tắc này áp dụng cho size, shape, fill và alpha. (Để ý thêm factor(cyl) trong ví dụ ánh xạ: cyl là số, và bọc nó trong factor() yêu cầu mỗi nhóm một màu riêng thay vì một dải màu liên tục.)
Nhãn, facet và theme
labs() đặt tên cho mọi thứ ở một chỗ, và một biểu đồ chưa xong cho đến khi có nhãn thật sự:
ggplot(mtcars, aes(x = wt, y = hp, color = factor(cyl))) +
geom_point(size = 2) +
labs(title = "Horsepower vs. weight",
x = "Weight (1000 lbs)",
y = "Horsepower",
color = "Cylinders")
Facet là tính năng nổi bật của ggplot2: tách một biểu đồ thành nhiều biểu đồ nhỏ, mỗi nhóm một khung, dùng chung trục để các khung so sánh được một cách công bằng:
ggplot(mtcars, aes(x = wt, y = hp)) +
geom_point() +
facet_wrap(~ cyl)
Ba khung xuất hiện, mỗi khung cho xe 4, 6 và 8 xi lanh, xếp thành lưới với giá trị nhóm ghi phía trên mỗi khung. Trong base R, việc này là một màn tung hứng với par(mfrow) và giới hạn trục chung đặt tay; ở đây chỉ một dòng. Facet phát huy tốt nhất với dữ liệu gọn gàng, đó là lý do ggplot2 đi cùng một chuỗi xử lý dplyr tự nhiên đến vậy: lọc và tóm tắt, rồi chuyển thẳng kết quả vào ggplot().
Theme đổi kiểu dáng toàn bộ phần không phải dữ liệu chỉ bằng một lệnh gọi: + theme_minimal() (nền trắng gọn gàng), + theme_bw(), + theme_classic() (chỉ có trục, không lưới), hoặc mặc định nền xám. Chọn một theme cho mỗi dự án và giữ nhất quán: một báo cáo mà mọi hình dùng chung theme sẽ đọc như một tài liệu thống nhất thay vì một cuốn sổ cắt dán.
Lưu bằng ggsave(), và khi nào base R vẫn ổn
ggsave() ghi biểu đồ gần nhất ra đĩa, tự suy ra định dạng từ đuôi tệp:
ggsave("hp-vs-weight.png", width = 8, height = 5) # last plot shown
ggsave("hp-vs-weight.pdf", plot = p, width = 8, height = 5) # a saved object
width và height mặc định tính bằng inch; hãy đặt rõ ràng, vì cỡ chữ co giãn theo kích thước đầu ra và giá trị mặc định hiếm khi khớp với nơi hình sẽ được dùng.
Còn khi nào nên dùng: để xem nhanh một biến trong năm giây giữa lúc phân tích, plot() của base R và các hàm cùng loại gõ ít hơn và không cần thư viện nào: dùng ggplot2 ở mọi nơi chẳng được thưởng gì. ggplot2 đáng giá ngay khi một hình có nhóm, chú giải, facet hoặc có người xem: ngữ pháp này mở rộng được đến độ phức tạp mà vẽ biểu đồ bằng base R chỉ xử lý được rất vất vả.
Những điều cần nhớ
- ggplot2 ghép mọi biểu đồ từ dữ liệu + ánh xạ
aes()+ các lớp geom, nối bằng+; học ngữ pháp một lần, dùng lại cho mọi loại biểu đồ. aes()ánh xạ cột sang thuộc tính hình ảnh: tên cột trơn, được tính trong data frame của bạn.- Bên trong
aes()= thay đổi theo dữ liệu (và có chú giải); bên ngoài = thiết lập cố định.aes(color = "blue")là bug kinh điển. labs()cho tiêu đề,facet_wrap(~ group)cho các biểu đồ nhỏ,theme_minimal()và các theme khác để tạo kiểu,ggsave()với kích thước rõ ràng để xuất hình.- Xem nhanh một mình: base R. Có nhóm, facet hoặc người xem: ggplot2.
Chương vẽ biểu đồ đến đây là hết. Bước tiếp theo tự nhiên là thống kê mô tả, gắn con số cho những hình dạng mà các biểu đồ này cho thấy.
Câu hỏi thường gặp
ggplot2 trong R là gì?
ggplot2 là package vẽ biểu đồ phổ biến nhất của R. Thay vì mỗi loại biểu đồ một hàm, bạn ghép mọi biểu đồ từ cùng ba thành phần: một data frame, một ánh xạ aes() từ cột sang thuộc tính hình ảnh, và một hoặc nhiều lớp geom_*(), nối với nhau bằng +. Nó là một phần của tidyverse.
Cài đặt ggplot2 như thế nào?
Chạy install.packages("ggplot2") một lần, rồi đặt library(ggplot2) ở đầu mọi script dùng đến nó. Cài đặt đưa package vào máy bạn; library() nạp nó vào phiên làm việc hiện tại.
aes() trong ggplot2 làm gì?
aes() ánh xạ các cột dữ liệu sang thuộc tính hình ảnh: aes(x = wt, y = hp, color = factor(cyl)) nghĩa là vị trí ngang lấy từ wt, vị trí dọc lấy từ hp, và màu điểm lấy từ số xi lanh. Mọi thứ bên trong aes() thay đổi theo dữ liệu; mọi thứ bên ngoài là một thiết lập cố định.
Vì sao các điểm ggplot không có màu mình yêu cầu?
Bạn đã đặt màu bên trong aes(): aes(color = "blue") không đặt màu, mà ánh xạ một nhóm tự đặt tên là "blue", nên ggplot chọn màu mặc định của nó và thêm chú giải. Để đặt một màu cụ thể, hãy để nó bên ngoài ánh xạ: geom_point(color = "blue").