我想反对在 ggplot2 中制作馅饼的传统方法,即在极坐标中绘制堆叠的条形图。虽然我很欣赏这种方法在数学上的优雅,但当情节看起来不像它应该的样子时,它确实会引起各种头痛。特别是,精确调整饼图的大小可能很困难。(如果您不明白我的意思,请尝试制作一个一直延伸到绘图面板边缘的饼图。)
geom_arc_bar()
我更喜欢使用ggforce在正常的笛卡尔坐标系中绘制饼图。它需要在前端做一些额外的工作,因为我们必须自己计算角度,但这很容易,而且我们得到的控制水平非常值得。我在这里和这里以前的答案中使用了这种方法。
数据(来自问题):
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)
饼图代码:
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~.)
为了说明为什么我认为这种方法比传统的 ( coord_polar()
) 方法强大得多,假设我们希望将标签放在饼的外面而不是里面。这会产生一些问题,例如我们必须根据饼图的一侧调整标签落下的情况,hjust
而且vjust
我们必须使绘图面板的宽度大于高度,以便为侧面的标签腾出空间而不生成上下空间过大。在极坐标方法中解决这些问题并不有趣,但在笛卡尔坐标中却很简单:
# 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~.)