在之前的一系列gglot2绘制条形图、折线图和散点图后,有网友问如何使用ggplot2绘制饼图。其实ggplot2并没有类似于geom_pie()这样的函数实现饼图的绘制,但ggplot2有一个理念,就是通过极坐标变换绘制饼图,下文就教大家一步步绘制精美的饼图。
饼图在ggplot2中就是通过极坐标变换获得,在绘制饼图之前需要绘制堆叠的条形图,通过将条形图进行极坐标变换后,就能实现饼图绘制了。
library(ggplot2)
type <- c('A','B','C','D','E','F','G')
nums <- c(10,23,8,33,12,40,60)
df <- data.frame(type = type, nums = nums)
#绘制条形图
p <- ggplot(data = df, mapping = aes(x = 'Content', y = nums, fill = type)) + geom_bar(stat = 'identity', position = 'stack')
p
#堆叠的条形图绘制完后,接下来就需要进行极坐标变换了,ggplot2中coord_polar()函数可以非常方便的实现极坐标变换。
p + coord_polar(theta = 'y')
发现饼图中间有一个空心圆,这有点不像常见的饼图啊,不急,这里只需稍稍改动原条形图的宽度就可以啦,这里将宽度设置为1。
#绘制条形宽度为1的条形图
p <- ggplot(data = df, mapping = aes(x = 'Content', y = nums, fill = type)) + geom_bar(stat = 'identity', position = 'stack', width = 1)
p
#绘制无空心点的饼图
p + coord_polar(theta = 'y')
好,一个完整的饼图绘制完了,咦?饼图周围还有多余的数字(0,50,100,150)、标签(“Content”,nums)、刻度(Content)和横杠(-),这我该如何清除呢?
#这里的标签其实就是坐标轴的标签,可以通过labs()函数将其清除。
p + coord_polar(theta = 'y') + labs(x = '', y = '', title = '')
很好,标签(“Content”,nums)已经被清除了,那起眼的刻度值(Content)、(0,50,100,150)和横杠(-)又该如何清除呢?其实刻度(Content)、(0,50,100,150)和横杠(-)在原条形图中就是x轴和y轴的刻度值及刻度标记,可以通过theme()的方法将他们清除掉。
p + coord_polar(theta = 'y') + labs(x = '', y = '', title = '') + theme(axis.text = element_blank())
p + coord_polar(theta = 'y') + labs(x = '', y = '', title = '') + theme(axis.text = element_blank()) + theme(axis.ticks = element_blank())
大功告成,一个饼图就这样一步步实现了。有人会问,你这个饼图蛮好看的,就是有一点不好,我不知道各个部分各占多少百分比啊。这是一个非常好的问题,接下来就看看如何给这个饼图绘制百分比。
第一种方法,将百分比直接显示在图例中,这种方式适合分类较多的情况。
#先来看看如何将这样的百分比(10.2%)表示出来
label_value <- paste('(', round(df$nums/sum(df$nums) * 100, 1), '%)', sep = '')
label_value
[1] "(5.4%)" "(12.4%)" "(4.3%)" "(17.7%)" "(6.5%)" "(21.5%)"
[7] "(32.3%)"
#下面还需要为这些百分比值对应到各个组。
label <- paste(df$type, label_value, sep = '')
label
[1] "A(5.4%)" "B(12.4%)" "C(4.3%)" "D(17.7%)" "E(6.5%)" "F(21.5%)"
[7] "G(32.3%)"
好!接下来就是将这些百分比标签放到图例中。
p + coord_polar(theta = 'y') + labs(x = '', y = '', title = '') + theme(axis.text = element_blank()) + theme(axis.ticks = element_blank()) + scale_fill_discrete(labels = label)
第二种方法,直接将百分比放到各自的饼区中。
#首先去掉图例
p + coord_polar(theta = 'y') + labs(x = '', y = '', title = '') + theme(axis.text = element_blank()) + theme(axis.ticks = element_blank()) + theme(legend.position = "none")
p + coord_polar(theta = 'y') + labs(x = '', y = '', title = '') + theme(axis.text = element_blank()) + theme(axis.ticks = element_blank()) + theme(legend.position = "none") + geom_text(aes(y = df$nums/2 + c(0, cumsum(df$nums)[-length(df$nums)]), x = sum(df$nums)/150, label = label))
这里需要说明的是,x = sum(df$nums)/150是需要不断调整的,分母越小,标签离饼图越远,分母越大,标签月挤到一起。下面放两个特例:
p + coord_polar(theta = 'y') + labs(x = '', y = '', title = '') + theme(axis.text = element_blank()) + theme(axis.ticks = element_blank()) + theme(legend.position = "none") + geom_text(aes(y = df$nums/2 + c(0, cumsum(df$nums)[-length(df$nums)]), x = sum(df$nums)/50, label = label))
p + coord_polar(theta = 'y') + labs(x = '', y = '', title = '') + theme(axis.text = element_blank()) + theme(axis.ticks = element_blank()) + theme(legend.position = "none") + geom_text(aes(y = df$nums/2 + c(0, cumsum(df$nums)[-length(df$nums)]), x = sum(df$nums)/300, label = label))
有人还想问,可不可以绘制环形图呀?没问题啊,当然可以,只需将条形图的宽度调整到小于1就可以了,还记得之前的第一张饼图中间有一个空心白圈吗?就是因为默认的条形宽度为0.9导致的。
ggplot(data = df, mapping = aes(x = 'Content', y = nums, fill = type)) + geom_bar(stat = 'identity', position = 'stack', width = 0.5) + coord_polar(theta = 'y') + labs(x = '', y = '', title = '') + theme(axis.text = element_blank()) + theme(axis.ticks = element_blank()) + theme(legend.position = "none") + geom_text(aes(y = df$nums/2 + c(0, cumsum(df$nums)[-length(df$nums)]), x = sum(df$nums)/180, label = label))
简单吧,真心的小凯斯啊~
对于饼图的绘制就说到这里,如果你想绘制3D饼图,ggplot2就不是一个很好的选择,因为其目前还无法实现3D功能。
参考资料
http://www.bubuko.com/infodetail-1036150.html