Hình bài báo bằng ggplot2 cần bốn việc: một hàm chủ đề tối giản dùng chung cho mọi hình, cỡ chữ đặt theo điểm in thật qua base_size, ghép khung bằng patchwork, và xuất bằng ggsave() với bề rộng tính bằng milimét đúng cột tạp chí, dùng thiết bị cairo_pdf để giữ tiếng Việt.
Mặc định của ggplot2 đẹp trên màn hình, nhưng nền xám, chữ cỡ 11 và kích thước theo cửa sổ RStudio không hợp với trang tạp chí. Thay vì chỉnh từng hình, dựng một lần bộ thiết lập riêng rồi dùng lại. Mã trong bài đã chạy với ggplot2 4.0 và patchwork 1.3, dùng bộ dữ liệu mpg có sẵn để bạn thử ngay.
Một hàm chủ đề cho cả bài
Dựng từ chủ đề có sẵn
theme_bai <- function(co = 8) theme_classic(base_size = co) + theme(legend.position = 'bottom', strip.text = element_text(face = 'bold'), plot.tag = element_text(face = 'bold')). theme_classic() bỏ nền xám và lưới, giữ trục; theme_minimal() bỏ cả đường trục nhưng giữ lưới nhạt; chọn theo thói quen của ngành. Thêm + theme_bai() vào cuối mọi hình.
Đặt một lần cho cả phiên
theme_set(theme_bai()) ở đầu kịch bản áp chủ đề cho mọi hình vẽ sau đó mà không cần thêm vào từng hình. Lưu hàm chủ đề trong một tệp R/theme.R rồi gọi source() từ mọi kịch bản vẽ để luận văn hay bộ bài báo có hình đồng bộ.
Cỡ chữ đúng khi in: vì sao phải xuất đúng kích thước
base_size là cỡ chữ tính bằng điểm (pt) ở kích thước hình bạn khai khi lưu. Nếu lưu hình rộng 85 mm với base_size = 8, chữ trên giấy là đúng 8 pt khi tạp chí in hình ở bề rộng một cột. Nếu lưu hình rộng 250 mm rồi tạp chí thu nhỏ về 85 mm, chữ chỉ còn chưa tới 3 pt. Đây là lý do nhiều hình trong luận văn đọc không nổi khi in: hình được lưu theo kích thước cửa sổ trên màn hình rộng.
Hướng dẫn tác giả thường nêu cỡ chữ tối thiểu trong hình, khoảng 6 đến 8 pt ở cỡ in; theo đúng con số của tạp chí bạn nộp. Đường trục và đường dữ liệu cũng cần đủ dày: trong ggplot2 4, chỉnh độ dày đường bằng tham số linewidth (thay cho size với đường từ bản 3.4).
Nhãn tiếng Việt không bị vỡ
Viết nhãn trong labs
labs(x = 'Dung tích động cơ (lít)', y = 'Quãng đường trên một đơn vị nhiên liệu', colour = 'Dẫn động'). Lưu tệp kịch bản bằng mã UTF-8; RStudio mặc định như vậy với tệp mới.
Chọn thiết bị xuất
Thiết bị pdf() mặc định của R dùng bảng mã một byte, không có chữ tiếng Việt: khi chạy thử, R báo conversion failure on ... in 'mbcsToSbcs' cho từng chữ như đ, ơ, ị, và các chữ đó hiện thành dấu chấm. Xuất PDF bằng device = cairo_pdf, xuất PNG hoặc TIFF bằng device = ragg::agg_png hoặc ragg::agg_tiff; cả hai dùng phông hệ thống và nhúng phông vào PDF.
Chọn phông
Khai theme(text = element_text(family = 'Arial')) hoặc phông tạp chí yêu cầu, miễn phông đó đã cài trên máy và có đủ chữ tiếng Việt. Nếu thiết bị không tìm thấy phông, nó sẽ thay bằng phông khác; kiểm tệp PDF bằng pdffonts để biết phông nào thật sự được nhúng.
Trung bình và khoảng tin cậy: tự tính trước rồi mới vẽ
ggplot2 có stat_summary() để vẽ trung bình kèm khoảng sai số ngay trong hình, ví dụ stat_summary(fun.data = mean_se) cho trung bình và sai số chuẩn; các hàm như mean_cl_normal cho khoảng tin cậy lại cần thêm gói Hmisc. Tiện, nhưng con số nằm ẩn trong hình, khó đối chiếu với bảng kết quả.
Cách chắc hơn cho bài báo: tự tính bảng tóm tắt bằng dplyr::summarise() gồm trung bình, cận dưới, cận trên, cỡ mẫu từng nhóm, lưu bảng đó ra tệp, rồi vẽ bằng geom_pointrange(aes(ymin = can_duoi, ymax = can_tren)). Số trong hình và số trong văn bản lấy từ cùng một bảng, và chú thích hình ghi được chính xác khoảng sai số là gì.
Ghép khung bằng patchwork
Với hai hình p1 (biểu đồ phân tán) và p2 (biểu đồ hộp), patchwork dùng toán tử: p1 | p2 đặt cạnh nhau, p1 / p2 xếp chồng, (p1 | p2) / p3 kết hợp. Đánh nhãn A, B, C cho từng khung: + plot_annotation(tag_levels = 'A'). Gom chú giải trùng của các khung về một chỗ: + plot_layout(guides = 'collect').
Một chi tiết cú pháp: toán tử & áp một thành phần chủ đề cho mọi khung, khác với + chỉ áp cho khung cuối. Ví dụ đưa chú giải chung xuống dưới: h <- (p1 | p2) + plot_layout(guides = 'collect') + plot_annotation(tag_levels = 'A') & theme(legend.position = 'bottom').
Chỉnh tỷ lệ chiều rộng các khung bằng plot_layout(widths = c(2, 1)). Giữ trục cùng thang giữa các khung khi người đọc cần so sánh, bằng cách khai cùng giới hạn trục cho từng hình.
Một hình mẫu từ đầu đến cuối
Hình hai khung trong bài, đã chạy thử với bộ mpg: khung A là biểu đồ phân tán p1 <- ggplot(mpg, aes(displ, hwy, colour = drv)) + geom_point(size = 0.8) + labs(x = 'Dung tích động cơ (lít)', y = 'Mức tiêu hao', colour = 'Dẫn động') + scale_colour_viridis_d(end = 0.85) + theme_bai(). Tham số end = 0.85 bỏ phần vàng quá sáng ở cuối bảng viridis, để điểm không chìm trên nền trắng.
Khung B là biểu đồ hộp theo loại xe: p2 <- ggplot(mpg, aes(class, hwy)) + geom_boxplot(outlier.size = 0.5) + labs(x = NULL, y = 'Quãng đường') + theme_bai() + theme(axis.text.x = element_text(angle = 45, hjust = 1)). Nhãn trục hoành xoay 45 độ khi tên nhóm dài; nếu tên quá dài, đổi sang cột ngang bằng cách đảo hai trục thay vì xoay chữ.
Ghép và lưu như các mục sau. Cỡ điểm, cỡ điểm ngoại lai, độ dày đường đều đặt nhỏ hơn mặc định vì hình sẽ in ở bề rộng thật, không phóng lên.
Sắp nhóm, định dạng số và chú thích
ggplot2 xếp nhóm theo thứ tự mức của factor, mặc định là thứ tự chữ cái. Sắp theo giá trị bằng forcats::fct_reorder(nhom, diem, .fun = median) trong aes(); giữ thứ tự tự nhiên như nhóm tuổi bằng cách khai levels khi tạo factor.
Bài tiếng Việt thường dùng dấu chấm phân cách hàng nghìn và dấu phẩy thập phân. Gói scales định dạng nhãn trục theo kiểu đó: scale_y_continuous(labels = scales::label_number(big.mark = '.', decimal.mark = ',')); phần trăm dùng scales::label_percent(decimal.mark = ','). Kiểm lại với quy định của tạp chí: bài tiếng Anh dùng kiểu ngược lại.
Tiêu đề và chú thích hình nên để trong văn bản bài, không đặt bằng labs(title = ...): tạp chí dàn chú thích riêng, và tiêu đề trong hình chiếm chỗ của dữ liệu.
Xuất đúng kích thước và định dạng
Các lệnh ggsave() đã chạy thử cho một hình hai khung rộng 174 mm:
| Mục đích | Lệnh | Ghi chú |
|---|---|---|
| PDF vector, nhúng phông | ggsave('hinh1.pdf', h, width = 174, height = 80, units = 'mm', device = cairo_pdf) | Dùng cho biểu đồ |
| TIFF cho tạp chí yêu cầu ảnh điểm | ggsave('hinh1.tiff', h, width = 174, height = 80, units = 'mm', dpi = 600, compression = 'lzw') | DPI theo hướng dẫn tạp chí |
| PNG cho bản thảo, trình chiếu | ggsave('hinh1.png', h, width = 174, height = 80, units = 'mm', dpi = 300, device = ragg::agg_png) | Nhẹ, xem nhanh |
| Một cột | width = 85 (mm), giữ nguyên base_size | Chữ vẫn đúng cỡ in |
Đưa kích thước vào biến ở đầu kịch bản, ví dụ MOT_COT <- 85, HAI_COT <- 174, rồi dùng lại; đổi tạp chí chỉ cần sửa hai con số.
Lỗi hay gặp với hình ggplot2
- Bấm
Exporttrong khung Plots của RStudio: kích thước theo cửa sổ, khó lặp lại. Luôn dùngggsave()trong mã. - Lưu hình xong mới đổi
base_sizeđể chữ to hơn, thay vì giảm kích thước lưu về đúng cột. - Chú giải màu mặc định với cặp đỏ – xanh lá; dùng
scale_colour_viridis_d()hoặc bảng Okabe–Ito. - Nhãn trục để nguyên tên biến như
hwy,displ. - Dùng
ggsave()không khai đối tượng, hàm sẽ lưu hình vẽ gần nhất, có khi không phải hình bạn muốn.
Câu hỏi thường gặp
theme_classic và theme_minimal khác nhau thế nào?
theme_classic giữ đường trục, bỏ lưới, giống hình trong nhiều tạp chí khoa học tự nhiên. theme_minimal bỏ đường trục, giữ lưới nhạt, hợp khi người đọc cần ước lượng giá trị. Chọn theo thông lệ của ngành và tạp chí.
Có cần gói ngoài để ghép hình ngoài patchwork không?
Không bắt buộc. cowplot và gridExtra cũng ghép được, nhưng patchwork có cú pháp toán tử ngắn, gom chú giải và đánh nhãn khung dễ. Chọn một gói và dùng thống nhất.
Làm sao thêm ký hiệu toán học, chỉ số dưới vào nhãn?
Dùng biểu thức của R qua hàm expression hoặc bquote, ví dụ đơn vị có mũ hai. Gói ggtext cho phép viết nhãn bằng cú pháp Markdown đơn giản như chữ nghiêng, chỉ số trên dưới.
Hình nhiều khung bị chú giải lặp lại thì sửa sao?
Thêm plot_layout(guides = 'collect') để patchwork gom chú giải giống nhau của các khung về một chỗ. Các khung phải dùng cùng thang màu và cùng tên chú giải thì mới gom được.
ggplot2 bản 4 có làm hỏng mã cũ không?
Phần lớn mã cũ vẫn chạy. Bản 4 viết lại phần lõi bằng hệ lớp S7 và có một số thay đổi về chủ đề; nếu hình khác trước, đọc trang tin thay đổi của gói và kiểm lại các tham số đã bị thay thế.