Tôi muốn nói chống lại cách thông thường để làm bánh nướng trong ggplot2, đó là vẽ một thanh xếp chồng lên nhau trong các tọa độ cực. Trong khi tôi đánh giá cao sự sang trọng toán học của phương pháp đó, nó gây ra tất cả các loại đau đầu khi cốt truyện không nhìn khá theo cách nó được cho là. Đặc biệt, điều chỉnh chính xác kích thước của chiếc bánh có thể khó khăn. (Nếu bạn không biết ý tôi là gì, hãy thử tạo một biểu đồ hình tròn kéo dài đến tận mép của bảng điều khiển.)
Tôi thích vẽ bánh trong hệ tọa độ Descartes bình thường, sử dụng geom_arc_bar()
từ ggforce . Nó đòi hỏi một chút công việc phụ ở mặt trước, bởi vì chúng ta phải tự tính toán góc độ, nhưng điều đó dễ dàng và mức độ kiểm soát mà chúng tôi nhận được kết quả là đáng giá hơn. Tôi đã sử dụng phương pháp này trong câu trả lời trước here và here.
Các dữ liệu (từ câu hỏi):
dat = read.table(text = "Channel Volume Cnt
AGENT high 8344
AGENT medium 5448
AGENT low 23823
KIOSK high 19275
KIOSK medium 13554
KIOSK low 38293", header=TRUE)
Mã bánh vẽ:
library(ggplot2)
library(ggforce)
library(dplyr)
# calculate the start and end angles for each pie
dat_pies <- left_join(dat,
dat %>%
group_by(Channel) %>%
summarize(Cnt_total = sum(Cnt))) %>%
group_by(Channel) %>%
mutate(end_angle = 2*pi*cumsum(Cnt)/Cnt_total, # ending angle for each pie slice
start_angle = lag(end_angle, default = 0), # starting angle for each pie slice
mid_angle = 0.5*(start_angle + end_angle)) # middle of each pie slice, for the text label
rpie = 1 # pie radius
rlabel = 0.6 * rpie # radius of the labels; a number slightly larger than 0.5 seems to work better,
# but 0.5 would place it exactly in the middle as the question asks for.
# draw the pies
ggplot(dat_pies) +
geom_arc_bar(aes(x0 = 0, y0 = 0, r0 = 0, r = rpie,
start = start_angle, end = end_angle, fill = Volume)) +
geom_text(aes(x = rlabel*sin(mid_angle), y = rlabel*cos(mid_angle), label = Cnt),
hjust = 0.5, vjust = 0.5) +
coord_fixed() +
scale_x_continuous(limits = c(-1, 1), name = "", breaks = NULL, labels = NULL) +
scale_y_continuous(limits = c(-1, 1), name = "", breaks = NULL, labels = NULL) +
facet_grid(Channel~.)
Để cho thấy lý do tại sao tôi nghĩ rằng phương pháp này là mạnh hơn rất nhiều so với thông thường (coord_polar()
) cách tiếp cận, giả sử chúng ta muốn các nhãn ở bên ngoài của chiếc bánh chứ không phải bên trong. Điều này tạo ra một vài vấn đề, chẳng hạn như chúng tôi sẽ phải điều chỉnh hjust
và vjust
tùy thuộc vào mặt của chiếc bánh mà nhãn rơi xuống, và chúng tôi cũng phải làm cho bảng điều khiển rộng hơn cao để tạo không gian cho nhãn trên bên mà không tạo ra không gian quá mức trên và dưới.Giải quyết những vấn đề trong cách tiếp cận cực phối hợp không phải là niềm vui, nhưng đó là tầm thường trong tọa độ Descartes:
# generate hjust and vjust settings depending on the quadrant into which each
# label falls
dat_pies <- mutate(dat_pies,
hjust = ifelse(mid_angle>pi, 1, 0),
vjust = ifelse(mid_angle<pi/2 | mid_angle>3*pi/2, 0, 1))
rlabel = 1.05 * rpie # now we place labels outside of the pies
ggplot(dat_pies) +
geom_arc_bar(aes(x0 = 0, y0 = 0, r0 = 0, r = rpie,
start = start_angle, end = end_angle, fill = Volume)) +
geom_text(aes(x = rlabel*sin(mid_angle), y = rlabel*cos(mid_angle), label = Cnt,
hjust = hjust, vjust = vjust)) +
coord_fixed() +
scale_x_continuous(limits = c(-1.5, 1.4), name = "", breaks = NULL, labels = NULL) +
scale_y_continuous(limits = c(-1, 1), name = "", breaks = NULL, labels = NULL) +
facet_grid(Channel~.)
giải pháp mới nhất của tôi cho vấn đề này là tránh các biểu đồ pie bất cứ khi nào có thể :-) – topchef