11 Truyền đạt
11.1 Giới thiệu
Trong Chương 10, bạn đã học cách sử dụng biểu đồ như công cụ khám phá. Khi tạo biểu đồ khám phá, bạn biết—ngay trước khi nhìn—biểu đồ sẽ hiển thị biến nào. Bạn tạo mỗi biểu đồ cho một mục đích, xem nhanh, rồi chuyển sang biểu đồ tiếp theo. Trong hầu hết phân tích, bạn sẽ tạo row chục hoặc row trăm biểu đồ, phần lớn bị bỏ ngay.
Giờ bạn đã hiểu dữ liệu, bạn cần truyền đạt sự hiểu biết đến người khác. Khán giả có thể không có kiến thức nền tảng như bạn và không đầu tư sâu vào dữ liệu. Để giúp người khác nhanh chóng xây dựng mô hình tinh thần tốt về dữ liệu, bạn cần đầu tư nỗ lực đáng kể để biểu đồ tự giải thích nhất có thể. Trong chương này, bạn sẽ học một số công cụ ggplot2 cung cấp cho việc đó.
Chương này tập trung vào công cụ bạn cần để tạo đồ họa tốt. Chúng tôi giả sử bạn biết mình muốn gì, và chỉ cần biết cách thực hiện. Vì vậy, chúng tôi rất khuyến nghị kết hợp chương này với sách visualization tổng quát. Chúng tôi đặc biệt thích The Truthful Art của Albert Cairo. Cuốn sách đó không dạy cơ chế tạo visualization, mà tập trung vào những gì cần suy nghĩ để tạo đồ họa hiệu quả.
11.1.1 Điều kiện tiên quyết
Trong chương này, chúng ta sẽ tập trung vào ggplot2 một lần nữa. Chúng ta cũng sẽ dùng một chút dplyr để xử lý dữ liệu, scales để ghi đè mặc định về break, nhãn, phép biến đổi và bảng màu, và một số package ggplot2, bao gồm ggrepel (https://ggrepel.slowkow.com) của Kamil Slowikowski và patchwork (https://patchwork.data-imaginist.com) của Thomas Lin Pedersen. Đừng quên cài đặt các package đó bằng install.packages() nếu bạn chưa có.
11.2 Nhãn
Nơi dễ nhất để bắt đầu khi chuyển đồ họa khám phá thành đồ họa trình bày là với nhãn tốt. Bạn thêm nhãn bằng function labs().
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = class)) +
geom_smooth(se = FALSE) +
labs(
x = "Engine displacement (L)",
y = "Highway fuel economy (mpg)",
color = "Car type",
title = "Fuel efficiency generally decreases with engine size",
subtitle = "Two seaters (sports cars) are an exception because of their light weight",
caption = "Data from fueleconomy.gov"
)
Mục đích của tiêu đề biểu đồ là tóm tắt phát hiện chính. Tránh tiêu đề chỉ mô tả biểu đồ là gì, ví dụ “Biểu đồ phân tán dung tích động cơ theo hiệu suất nhiên liệu”.
Nếu bạn cần thêm văn bản, có hai nhãn hữu ích khác: subtitle thêm chi tiết bổ sung bằng phông chữ nhỏ hơn dưới tiêu đề và caption thêm văn bản ở góc dưới bên phải, thường dùng để mô tả nguồn dữ liệu. Bạn cũng có thể dùng labs() để thay tiêu đề trục và chú giải. Thường nên thay tên biến ngắn bằng mô tả chi tiết hơn, và bao gồm đơn vị.
Có thể dùng phương trình toán thay vì string văn bản. Chỉ cần thay "" bằng quote() và đọc về các tùy chọn trong ?plotmath:

11.2.1 Bài tập
Tạo biểu đồ dữ liệu nhiên liệu với
title,subtitle,caption,x,y, và nhãncolortùy chỉnh.-
Tái tạo biểu đồ sau dùng dữ liệu nhiên liệu. Lưu ý cả màu và hình dạng điểm thay đổi theo loại hệ dẫn động.

Lấy một biểu đồ khám phá bạn đã tạo trong tháng qua, và thêm tiêu đề mang tính mô tả để người khác dễ hiểu hơn.
11.3 Chú thích
Ngoài gắn nhãn cho các thành phần chính của biểu đồ, thường hữu ích khi gắn nhãn từng quan sát hoặc nhóm quan sát riêng lẻ. Công cụ đầu tiên là geom_text(). geom_text() tương tự geom_point(), nhưng có thêm aesthetic label. Điều này cho phép thêm nhãn văn bản vào biểu đồ.
Có hai nguồn nhãn. Thứ nhất, bạn có thể có tibble cung cấp nhãn. Trong biểu đồ sau chúng ta trích xuất xe có dung tích động cơ lớn nhất trong mỗi loại hệ dẫn động và lưu thành data frame mới label_info.
label_info <- mpg |>
group_by(drv) |>
arrange(desc(displ)) |>
slice_head(n = 1) |>
mutate(
drive_type = case_when(
drv == "f" ~ "front-wheel drive",
drv == "r" ~ "rear-wheel drive",
drv == "4" ~ "4-wheel drive"
)
) |>
select(displ, hwy, drv, drive_type)
label_info
#> # A tibble: 3 × 4
#> # Groups: drv [3]
#> displ hwy drv drive_type
#> <dbl> <int> <chr> <chr>
#> 1 6.5 17 4 4-wheel drive
#> 2 5.3 25 f front-wheel drive
#> 3 7 24 r rear-wheel driveRồi chúng ta dùng data frame mới để gắn nhãn trực tiếp ba nhóm, thay chú giải bằng nhãn đặt trên biểu đồ. Dùng argument fontface và size để tùy chỉnh giao diện nhãn. (theme(legend.position = "none") tắt tất cả chú giải — chúng ta sẽ nói thêm ngay.)
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
geom_point(alpha = 0.3) +
geom_smooth(se = FALSE) +
geom_text(
data = label_info,
aes(x = displ, y = hwy, label = drive_type),
fontface = "bold", size = 5, hjust = "right", vjust = "bottom"
) +
theme(legend.position = "none")
#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
Lưu ý cách dùng hjust (căn ngang) và vjust (căn dọc) để kiểm soát vị trí nhãn.
Tuy nhiên, biểu đồ comment ở trên khó đọc vì nhãn chồng chéo nhau và với điểm. Chúng ta có thể dùng function geom_label_repel() từ package ggrepel để giải quyết cả hai vấn đề. Gói mở rộng này tự động điều chỉnh nhãn để không chồng chéo:
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
geom_point(alpha = 0.3) +
geom_smooth(se = FALSE) +
geom_label_repel(
data = label_info,
aes(x = displ, y = hwy, label = drive_type),
fontface = "bold", size = 5, nudge_y = 2
) +
theme(legend.position = "none")
#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
Bạn cũng có thể dùng cùng ý tưởng để đánh dấu điểm nhất định bằng geom_text_repel() từ ggrepel. Lưu ý kỹ thuật tiện dụng khác: chúng ta thêm lớp thứ hai gồm điểm lớn, rỗng để đánh dấu rõ hơn.
potential_outliers <- mpg |>
filter(hwy > 40 | (hwy > 20 & displ > 5))
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
geom_text_repel(data = potential_outliers, aes(label = model)) +
geom_point(data = potential_outliers, color = "red") +
geom_point(
data = potential_outliers,
color = "red", size = 3, shape = "circle open"
)
Ngoài geom_text() và geom_label(), bạn có nhiều geom khác trong ggplot2 để comment biểu đồ. Một vài ý tưởng:
Dùng
geom_hline()vàgeom_vline()để thêm đường tham chiếu. Chúng tôi thường làm chúng dày (linewidth = 2) và trắng (color = white), vẽ dưới lớp dữ liệu chính. Điều này giúp dễ thấy mà không thu hút sự chú ý khỏi dữ liệu.Dùng
geom_rect()để vẽ hình chữ nhật quanh điểm quan tâm. Ranh giới được định nghĩa bởi aestheticxmin,xmax,ymin,ymax. Hoặc xem package ggforce, cụ thểgeom_mark_hull().Dùng
geom_segment()với argumentarrowđể vẽ mũi tên chỉ đến điểm. Dùng aestheticxvàycho vị trí bắt đầu,xendvàyendcho vị trí kết thúc.
Function tiện dụng khác để thêm comment là annotate(). Theo nguyên tắc chung, geom hữu ích cho đánh dấu tập con dữ liệu trong khi annotate() hữu ích cho thêm một hoặc vài phần tử comment.
Để minh họa annotate(), hãy tạo văn bản để thêm vào biểu đồ. Văn bản hơi dài nên dùng stringr::str_wrap() để tự động xuống dòng:
trend_text <- "Larger engine sizes tend to have lower fuel economy." |>
str_wrap(width = 30)
trend_text
#> [1] "Larger engine sizes tend to\nhave lower fuel economy."Rồi thêm hai lớp comment: một với label geom và một với segment geom. Aesthetic x và y trong cả hai định nghĩa nơi comment bắt đầu, và xend và yend trong segment định nghĩa vị trí kết thúc. Lưu ý segment được tạo kiểu mũi tên.

Chú thích là công cụ mạnh mẽ để truyền đạt phát hiện chính và đặc điểm thú vị. Giới hạn duy nhất là trí tưởng tượng (và sự kiên nhẫn định vị comment cho đẹp)!
11.3.1 Bài tập
Dùng
geom_text()với vị trí vô cực để đặt văn bản ở bốn góc biểu đồ.Dùng
annotate()để thêm point geom ở giữa biểu đồ cuối mà không cần tạo tibble. Tùy chỉnh hình dạng, kích thước, hoặc màu sắc.Nhãn
geom_text()tương tác với facet thế nào? Làm sao thêm nhãn vào một facet? Làm sao đặt nhãn khác nhau cho mỗi facet? (Gợi ý: Nghĩ về tập dữ liệu được truyền vàogeom_text().)Đối số nào của
geom_label()kiểm soát giao diện hộp nền?Bốn argument của
arrow()là gì? Chúng hoạt động thế nào? Tạo string biểu đồ minh họa các tùy chọn quan trọng nhất.
11.4 Thang đo
Cách thứ ba để cải thiện biểu đồ cho truyền đạt là điều chỉnh scale (scale). Thang đo kiểm soát cách mapping aesthetic hiển thị trực quan.
11.4.1 Thang đo mặc định
Thông thường, ggplot2 tự động thêm scale. Ví dụ, khi bạn gõ:
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = class))ggplot2 tự động thêm scale mặc định phía sau:
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = class)) +
scale_x_continuous() +
scale_y_continuous() +
scale_color_discrete()Lưu ý quy ước đặt tên scale: scale_ theo sau bởi tên aesthetic, rồi _, rồi tên scale. Thang đo mặc định được đặt tên theo loại biến: continuous, discrete, datetime, hoặc date. scale_x_continuous() đặt giá trị số displ trên trục x liên tục, scale_color_discrete() chọn màu cho mỗi class, v.v. Có nhiều scale không mặc định bạn sẽ học dưới đây.
Thang đo mặc định được chọn kỹ để hoạt động tốt với nhiều đầu vào. Tuy nhiên, bạn có thể muốn ghi đè mặc định vì hai lý do:
Bạn muốn chỉnh một số parameter của scale mặc định, như thay đổi break trên trục hoặc nhãn chú giải.
Bạn muốn thay thế hoàn toàn scale, dùng thuật toán khác. Thường bạn làm tốt hơn mặc định vì hiểu dữ liệu hơn.
11.4.2 Vạch trục và khóa chú giải
Gộp lại, trục và chú giải được gọi là hướng dẫn (guide). Trục dùng cho aesthetic x và y; chú giải dùng cho mọi thứ khác.
Có hai argument chính ảnh hưởng giao diện vạch trục và khóa chú giải: breaks và labels. Breaks kiểm soát vị trí vạch, hoặc giá trị liên kết với khóa. Labels kiểm soát nhãn văn bản của mỗi vạch/khóa. Cách dùng phổ biến nhất của breaks là ghi đè lựa chọn mặc định:
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
geom_point() +
scale_y_continuous(breaks = seq(15, 40, by = 5))
Bạn có thể dùng labels tương tự (vector ký tự cùng độ dài với breaks), nhưng cũng có thể đặt thành NULL để ẩn nhãn. Điều này hữu ích cho bản đồ, hoặc khi không thể chia sẻ số tuyệt đối. Bạn cũng có thể dùng breaks và labels cho chú giải. Với scale rời rạc cho biến phân loại, labels có thể là list đặt tên.
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
geom_point() +
scale_x_continuous(labels = NULL) +
scale_y_continuous(labels = NULL) +
scale_color_discrete(labels = c("4" = "4-wheel", "f" = "front", "r" = "rear"))
Đối số labels kết hợp với function gắn nhãn từ package scales cũng hữu ích để định dạng số thành tiền tệ, phần trăm, v.v. Biểu đồ bên trái hiển thị gắn nhãn mặc định với label_dollar(), thêm ký hiệu đô la và dấu phẩy phân cách row nghìn. Biểu đồ bên phải tùy chỉnh thêm bằng cách chia giá trị cho 1.000 và thêm hậu tố “K” cùng break tùy chỉnh. Lưu ý breaks dùng scale gốc của dữ liệu.
# Trái
ggplot(diamonds, aes(x = price, y = cut)) +
geom_boxplot(alpha = 0.05) +
scale_x_continuous(labels = label_dollar())
# Phải
ggplot(diamonds, aes(x = price, y = cut)) +
geom_boxplot(alpha = 0.05) +
scale_x_continuous(
labels = label_dollar(scale = 1/1000, suffix = "K"),
breaks = seq(1000, 19000, by = 6000)
)

Function gắn nhãn tiện dụng khác là label_percent():
ggplot(diamonds, aes(x = cut, fill = clarity)) +
geom_bar(position = "fill") +
scale_y_continuous(name = "Percentage", labels = label_percent())
Một cách dùng breaks khác là khi có ít điểm dữ liệu và muốn đánh dấu chính xác nơi quan sát. Ví dụ, biểu đồ sau cho thấy mỗi tổng thống Mỹ bắt đầu và kết thúc nhiệm kỳ khi nào.
presidential |>
mutate(id = 33 + row_number()) |>
ggplot(aes(x = start, y = id)) +
geom_point() +
geom_segment(aes(xend = end, yend = id)) +
scale_x_date(name = NULL, breaks = presidential$start, date_labels = "'%y")
Lưu ý rằng chúng ta trích xuất biến start làm vector với presidential$start vì không thể dùng mapping aesthetic cho argument này. Cũng lưu ý rằng đặc tả break và label cho scale ngày và ngày-giờ hơi khác:
date_labelsnhận đặc tả định dạng, cùng dạng vớiparse_datetime().date_breaks(không hiển thị ở đây), nhận string như “2 days” hoặc “1 month”.
11.4.3 Bố cục chú giải
Bạn sẽ thường dùng breaks và labels để chỉnh trục. Dù chúng cũng hoạt động cho chú giải, có vài kỹ thuật khác hay dùng hơn.
Để kiểm soát vị trí tổng thể của chú giải, dùng thiết lập theme(). Chúng ta sẽ quay lại theme (theme) cuối chương, nhưng tóm tắt, chúng kiểm soát phần không phải dữ liệu. Thiết lập legend.position kiểm soát nơi chú giải được vẽ:
base <- ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = class))
base + theme(legend.position = "right") # mặc định
base + theme(legend.position = "left")
base +
theme(legend.position = "top") +
guides(color = guide_legend(nrow = 3))
base +
theme(legend.position = "bottom") +
guides(color = guide_legend(nrow = 3))



Nếu biểu đồ ngắn và rộng, đặt chú giải ở trên hoặc dưới; nếu cao và hẹp, đặt ở trái hoặc phải. Bạn cũng có thể dùng legend.position = "none" để ẩn chú giải hoàn toàn.
Để kiểm soát hiển thị từng chú giải, dùng guides() cùng guide_legend() hoặc guide_colorbar(). Ví dụ sau cho thấy hai thiết lập quan trọng: kiểm soát số row với nrow, và ghi đè aesthetic để điểm lớn hơn. Điều này đặc biệt hữu ích nếu dùng alpha thấp cho nhiều điểm.
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = class)) +
geom_smooth(se = FALSE) +
theme(legend.position = "bottom") +
guides(color = guide_legend(nrow = 2, override.aes = list(size = 4)))
#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
Lưu ý tên argument trong guides() khớp với tên aesthetic, giống như trong labs().
11.4.4 Thay thế scale
Thay vì chỉ chỉnh chi tiết, bạn có thể thay thế hoàn toàn scale. Hai loại scale hay muốn đổi nhất: scale vị trí liên tục và scale màu. Nguyên tắc tương tự áp dụng cho tất cả aesthetic khác.
Rất hữu ích khi vẽ phép biến đổi biến. Ví dụ, dễ thấy mối quan hệ chính xác giữa carat và price hơn nếu biến đổi log:
# Trái
ggplot(diamonds, aes(x = carat, y = price)) +
geom_bin2d()
#> `stat_bin2d()` using `bins = 30`. Pick better value `binwidth`.
# Phải
ggplot(diamonds, aes(x = log10(carat), y = log10(price))) +
geom_bin2d()
#> `stat_bin2d()` using `bins = 30`. Pick better value `binwidth`.

Tuy nhiên, nhược điểm là trục gắn nhãn giá trị đã biến đổi, khó đọc. Thay vì biến đổi trong mapping aesthetic, chúng ta có thể biến đổi bằng scale. Trực quan giống hệt, trừ việc trục gắn nhãn scale gốc.
ggplot(diamonds, aes(x = carat, y = price)) +
geom_bin2d() +
scale_x_log10() +
scale_y_log10()
#> `stat_bin2d()` using `bins = 30`. Pick better value `binwidth`.
Thang đo khác thường tùy chỉnh là màu. Thang đo phân loại mặc định chọn màu cách đều trên vòng màu. Thay thế hữu ích là scale ColorBrewer, được chỉnh tay để tốt hơn cho người mù màu. Hai biểu đồ dưới trông tương tự, nhưng đủ khác biệt để phân biệt được ngay cả với người mù màu đỏ-xanh.1
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = drv))
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = drv)) +
scale_color_brewer(palette = "Set1")

Đừng quên kỹ thuật đơn giản hơn để cải thiện tính tiếp cận. Nếu chỉ có vài màu, thêm mapping hình dạng dư thừa. Điều này cũng giúp biểu đồ đọc được khi in đen trắng.
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = drv, shape = drv)) +
scale_color_brewer(palette = "Set1")
Thang đo ColorBrewer được tài liệu tại https://colorbrewer2.org/ và có sẵn trong R qua package RColorBrewer. Hình 11.1 hiển thị tất cả bảng màu. Bảng màu tuần tự (trên) và phân kỳ (dưới) đặc biệt hữu ích nếu biến phân loại có thứ tự hoặc có “giữa”.
Khi có mapping giá trị-màu được định nghĩa sẵn, dùng scale_color_manual(). Ví dụ, nếu mapping đảng phái tổng thống đến màu, chúng ta muốn đỏ cho Cộng hòa và xanh cho Dân chủ:
presidential |>
mutate(id = 33 + row_number()) |>
ggplot(aes(x = start, y = id, color = party)) +
geom_point() +
geom_segment(aes(xend = end, yend = id)) +
scale_color_manual(values = c(Republican = "#E81B23", Democratic = "#00AEF3"))
Với màu liên tục, dùng scale_color_gradient() hoặc scale_fill_gradient() tích hợp sẵn. Nếu có scale phân kỳ, dùng scale_color_gradient2() cho phép gán màu khác nhau cho giá trị dương và âm.
Tùy chọn khác là scale màu viridis. Các nhà thiết kế Nathaniel Smith và Stéfan van der Walt đã tạo ra sơ đồ màu liên tục dễ nhận biết cho người mù màu và đồng nhất tri giác trong cả màu và đen trắng. Chúng có sẵn dạng liên tục (c), rời rạc (d), và phân bin (b) trong ggplot2.
df <- tibble(
x = rnorm(10000),
y = rnorm(10000)
)
ggplot(df, aes(x, y)) +
geom_hex() +
coord_fixed() +
labs(title = "Default, continuous", x = NULL, y = NULL)
ggplot(df, aes(x, y)) +
geom_hex() +
coord_fixed() +
scale_fill_viridis_c() +
labs(title = "Viridis, continuous", x = NULL, y = NULL)
ggplot(df, aes(x, y)) +
geom_hex() +
coord_fixed() +
scale_fill_viridis_b() +
labs(title = "Viridis, binned", x = NULL, y = NULL)


Lưu ý tất cả scale màu có hai biến thể: scale_color_*() và scale_fill_*() cho aesthetic color và fill tương ứng.
11.4.5 Phóng to
Có ba cách kiểm soát giới hạn biểu đồ:
- Điều chỉnh dữ liệu được vẽ.
- Đặt giới hạn trong mỗi scale.
- Đặt
xlimvàylimtrongcoord_cartesian().
Chúng ta sẽ minh họa các tùy chọn này. Biểu đồ trái hiển thị mối quan hệ giữa dung tích động cơ và hiệu suất nhiên liệu, tô màu theo hệ dẫn động. Biểu đồ phải hiển thị cùng biến, nhưng lọc dữ liệu. Lọc dữ liệu đã ảnh hưởng đến scale x và y cũng như đường cong trơn.
# Trái
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = drv)) +
geom_smooth()
# Phải
mpg |>
filter(displ >= 5 & displ <= 6 & hwy >= 10 & hwy <= 25) |>
ggplot(aes(x = displ, y = hwy)) +
geom_point(aes(color = drv)) +
geom_smooth()

So sánh với hai biểu đồ dưới: trái đặt limits trên scale, phải đặt trong coord_cartesian(). Thu hẹp limits tương đương lọc dữ liệu. Vì vậy, để phóng to vùng biểu đồ, tốt nhất dùng coord_cartesian().
# Trái
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = drv)) +
geom_smooth() +
scale_x_continuous(limits = c(5, 6)) +
scale_y_continuous(limits = c(10, 25))
# Phải
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = drv)) +
geom_smooth() +
coord_cartesian(xlim = c(5, 6), ylim = c(10, 25))

Mặt khác, đặt limits trên scale riêng lẻ hữu ích hơn khi muốn mở rộng giới hạn, ví dụ để đồng bộ scale giữa biểu đồ. Nếu trích xuất hai loại xe và vẽ riêng, khó so sánh vì cả ba scale khác nhau.
suv <- mpg |> filter(class == "suv")
compact <- mpg |> filter(class == "compact")
# Trái
ggplot(suv, aes(x = displ, y = hwy, color = drv)) +
geom_point()
# Phải
ggplot(compact, aes(x = displ, y = hwy, color = drv)) +
geom_point()

Cách khắc phục là chia sẻ scale, huấn luyện với limits của toàn bộ dữ liệu.
x_scale <- scale_x_continuous(limits = range(mpg$displ))
y_scale <- scale_y_continuous(limits = range(mpg$hwy))
col_scale <- scale_color_discrete(limits = unique(mpg$drv))
# Trái
ggplot(suv, aes(x = displ, y = hwy, color = drv)) +
geom_point() +
x_scale +
y_scale +
col_scale
# Phải
ggplot(compact, aes(x = displ, y = hwy, color = drv)) +
geom_point() +
x_scale +
y_scale +
col_scale

Trong trường hợp này, bạn có thể dùng facet, nhưng kỹ thuật này hữu ích hơn khi muốn rải biểu đồ qua nhiều trang.
11.4.6 Bài tập
-
Tại sao mã sau không ghi đè scale mặc định?
df <- tibble( x = rnorm(10000), y = rnorm(10000) ) ggplot(df, aes(x, y)) + geom_hex() + scale_color_gradient(low = "white", high = "red") + coord_fixed() Đối số đầu tiên của mọi scale là gì? So sánh với
labs()?-
Thay đổi hiển thị nhiệm kỳ tổng thống bằng cách:
- Kết hợp hai biến thể tùy chỉnh màu và break trục x.
- Cải thiện hiển thị trục y.
- Gắn nhãn mỗi nhiệm kỳ bằng tên tổng thống.
- Thêm nhãn biểu đồ mang tính mô tả.
- Đặt break mỗi 4 năm (khó hơn tưởng!).
-
Đầu tiên, tạo biểu đồ sau. Rồi, sửa mã dùng
override.aesđể chú giải dễ thấy hơn.ggplot(diamonds, aes(x = carat, y = price)) + geom_point(aes(color = cut), alpha = 1/20)
11.5 Chủ đề
Cuối cùng, bạn có thể tùy chỉnh phần không phải dữ liệu với theme (theme):
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = class)) +
geom_smooth(se = FALSE) +
theme_bw()
ggplot2 bao gồm tám theme trong Hình 11.2, với theme_gray() là mặc định.2 Nhiều theme khác có trong package bổ trợ như ggthemes (https://jrnold.github.io/ggthemes). Bạn cũng có thể tạo theme riêng để phù hợp với phong cách công ty hoặc tạp chí.
Cũng có thể kiểm soát từng thành phần của theme, như kích thước và màu phông chữ trục y. Chúng ta đã thấy legend.position kiểm soát vị trí chú giải. Nhiều khía cạnh khác có thể tùy chỉnh bằng theme(). Ví dụ, trong biểu đồ dưới chúng ta thay đổi hướng chú giải và thêm viền đen. Tùy chỉnh hộp chú giải và phần tử tiêu đề được thực hiện với function element_*(). Các phần tử theme kiểm soát vị trí tiêu đề và comment là plot.title.position và plot.caption.position, được đặt thành "plot" để căn chỉnh với toàn bộ vùng biểu đồ.
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
geom_point() +
labs(
title = "Larger engine sizes tend to have lower fuel economy",
caption = "Source: https://fueleconomy.gov."
) +
theme(
legend.position = c(0.6, 0.7),
legend.direction = "horizontal",
legend.box.background = element_rect(color = "black"),
plot.title = element_text(face = "bold"),
plot.title.position = "plot",
plot.caption.position = "plot",
plot.caption = element_text(hjust = 0)
)
Để xem tổng quan tất cả thành phần theme(), xem trợ giúp ?theme. Cuốn sách ggplot2 cũng là nơi tuyệt vời cho chi tiết đầy đủ về theme.
11.5.1 Bài tập
- Chọn một theme từ package ggthemes và áp dụng cho biểu đồ cuối bạn đã tạo.
- Làm nhãn trục của biểu đồ thành màu xanh và in đậm.
11.6 Bố cục
Cho đến nay chúng ta nói về cách tạo và sửa một biểu đồ. Nếu bạn có nhiều biểu đồ muốn bố trí theo cách nhất định thì sao? Gói mở rộng patchwork cho phép kết hợp biểu đồ riêng lẻ thành cùng đồ họa. Chúng ta đã tải package này ở đầu chương.
Để đặt hai biểu đồ cạnh nhau, đơn giản cộng chúng. Lưu ý bạn cần tạo biểu đồ và lưu làm đối tượng (ví dụ p1 và p2). Rồi đặt cạnh nhau bằng +.
p1 <- ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
labs(title = "Plot 1")
p2 <- ggplot(mpg, aes(x = drv, y = hwy)) +
geom_boxplot() +
labs(title = "Plot 2")
p1 + p2
Lưu ý rằng chúng ta không dùng function mới từ patchwork. Thay vào đó, package thêm chức năng mới cho toán tử +.
Bạn cũng có thể tạo bố cục phức tạp. Dưới đây, | đặt p1 và p3 cạnh nhau và / đưa p2 xuống dòng tiếp theo.
p3 <- ggplot(mpg, aes(x = cty, y = hwy)) +
geom_point() +
labs(title = "Plot 3")
(p1 | p3) / p2
Ngoài ra, patchwork cho phép gom chú giải từ nhiều biểu đồ, tùy chỉnh vị trí chú giải cùng kích thước biểu đồ, và thêm tiêu đề, phụ đề, comment chung. Dưới đây chúng ta tạo 5 biểu đồ. Chúng ta tắt chú giải trên biểu đồ hộp và phân tán, gom chú giải cho biểu đồ mật độ lên trên bằng & theme(legend.position = "top"). Lưu ý dùng & thay vì + vì chúng ta sửa theme cho biểu đồ patchwork, không phải từng ggplot. Chú giải được đặt trong guide_area(). Cuối cùng, chúng ta tùy chỉnh chiều cao các thành phần – hướng dẫn cao 1, biểu đồ hộp 3, mật độ 2, và phân tán có facet 4.
p1 <- ggplot(mpg, aes(x = drv, y = cty, color = drv)) +
geom_boxplot(show.legend = FALSE) +
labs(title = "Plot 1")
p2 <- ggplot(mpg, aes(x = drv, y = hwy, color = drv)) +
geom_boxplot(show.legend = FALSE) +
labs(title = "Plot 2")
p3 <- ggplot(mpg, aes(x = cty, color = drv, fill = drv)) +
geom_density(alpha = 0.5) +
labs(title = "Plot 3")
p4 <- ggplot(mpg, aes(x = hwy, color = drv, fill = drv)) +
geom_density(alpha = 0.5) +
labs(title = "Plot 4")
p5 <- ggplot(mpg, aes(x = cty, y = hwy, color = drv)) +
geom_point(show.legend = FALSE) +
facet_wrap(~drv) +
labs(title = "Plot 5")
(guide_area() / (p1 + p2) / (p3 + p4) / p5) +
plot_annotation(
title = "City and highway mileage for cars with different drive trains",
caption = "Source: https://fueleconomy.gov."
) +
plot_layout(
guides = "collect",
heights = c(1, 3, 2, 4)
) &
theme(legend.position = "top")
Nếu bạn muốn tìm hiểu thêm về kết hợp và bố trí biểu đồ với patchwork, xem hướng dẫn trên trang web package: https://patchwork.data-imaginist.com.
11.6.1 Bài tập
-
Điều gì xảy ra nếu bỏ dấu ngoặc đơn trong bố cục sau? Bạn có thể giải thích tại sao?
p1 <- ggplot(mpg, aes(x = displ, y = hwy)) + geom_point() + labs(title = "Plot 1") p2 <- ggplot(mpg, aes(x = drv, y = hwy)) + geom_boxplot() + labs(title = "Plot 2") p3 <- ggplot(mpg, aes(x = cty, y = hwy)) + geom_point() + labs(title = "Plot 3") (p1 | p2) / p3 -
Dùng ba biểu đồ từ bài tập trước, tái tạo patchwork sau.

11.7 Tóm tắt
Trong chương này bạn đã học về thêm nhãn biểu đồ như tiêu đề, phụ đề, comment cũng như sửa nhãn trục mặc định, dùng comment để thêm văn bản hoặc đánh dấu điểm dữ liệu cụ thể, tùy chỉnh scale trục, và thay đổi theme biểu đồ. Bạn cũng đã học về kết hợp nhiều biểu đồ trong một đồ họa dùng cả bố cục đơn giản và phức tạp.
Dù bạn đã học cách tạo nhiều loại biểu đồ và tùy chỉnh bằng nhiều kỹ thuật, chúng ta mới chỉ chạm bề mặt những gì bạn có thể tạo với ggplot2. Nếu muốn hiểu toàn diện ggplot2, chúng tôi khuyến nghị đọc cuốn sách ggplot2: Elegant Graphics for Data Analysis. Tài nguyên hữu ích khác là R Graphics Cookbook của Winston Chang và Fundamentals of Data Visualization của Claus Wilke.
Bạn có thể dùng công cụ như SimDaltonism để mô phỏng mù màu.↩︎
Nhiều người thắc mắc tại sao theme mặc định có nền xám. Đây là lựa chọn có chủ đích vì nó đẩy dữ liệu lên phía trước trong khi vẫn hiển thị đường lưới. Đường lưới trắng dễ thấy (quan trọng vì chúng hỗ trợ đánh giá vị trí), nhưng ít ảnh hưởng thị giác. Nền xám tạo màu tương tự văn bản, đảm bảo đồ họa hòa hợp với tài liệu. Cuối cùng, nền xám tạo trường màu liên tục đảm bảo biểu đồ được nhận biết như một thực thể trực quan duy nhất.↩︎