zl程序教程

您现在的位置是:首页 >  其他

当前栏目

77-R可视化13-多个ggplot图象映射实现以假乱真的dodge+stack效果

2023-04-18 16:51:13 时间

前言

粉丝给我发来一张非常有意思的图:

乍一看这个图还蛮简单的。

但难点其实有的,比如怎么画出这种,即是dodge 又是stack 的赶脚。

一起来复现一下吧。

开始上手

直接假数据造起:

a1 <- data.frame(
  counts = c(53, 40, 59, 39),
  type1 = c(rep("NK",2), rep("TC",2)),
  type2 = rep(c("YM", "YF"), 2)
)

a2 <- data.frame(
  counts = c(105, 64, 128,66),
  type1 = c(rep("NK",2), rep("TC",2)),
  type2 = rep(c("OM", "OF"), 2)
)

直接画起:

ggplot() + geom_col(data = a1, 
                    aes(type1, counts, fill = type2),
                    position = "dodge") + 
  geom_col(data = a2, aes(type1, counts, fill = type2),
           position = "dodge", alpha = 0.8) +
  geom_text(data = a2, 
            aes(type1, counts,fill = type2, label = counts),
            position = position_dodge(0.9), vjust = -0.8) + 
  geom_text(data = a1, 
            aes(type1, counts,fill = type2, label = counts),
            position = position_dodge(0.9), vjust = -0.8)

本来想颜色让你们自己调的发现,还有一个技术点:重叠的颜色ggplot 会变成两种颜色对应的合成色,这样就和legand 中的不符了。这里需要手动替换一下,最终代码如下:


ggplot() + geom_col(data = a1, 
                    aes(type1, counts, fill = type2),
                    position = "dodge") + 
  geom_col(data = a2, aes(type1, counts, fill = type2),
           position = "dodge", alpha = 0.5) +
  geom_text(data = a2, 
            aes(type1, counts,fill = type2, label = counts),
            position = position_dodge(0.9), vjust = -0.8) + 
  geom_text(data = a1, 
            aes(type1, counts,fill = type2, label = counts),
            position = position_dodge(0.9), vjust = -0.8) + 
  ggthemes::theme_economist() + 
  # 在这个网站找颜色https://colorbrewer2.org/
  scale_fill_manual(values = c("#fc9272", "#9ecae1", "#de2d26","#3182bd"))

然而,合成色的问题依旧没有解决。

原因在于,这个图层的映射,不应该是矮的在高的下面,而应该是高的在矮的下面(先画a2 再画a1):

ggplot() + 
  geom_col(data = a2, aes(type1, counts, fill = type2),
           position = "dodge", alpha = 0.5) +
  geom_col(data = a1, 
                    aes(type1, counts, fill = type2),
                    position = "dodge") +
  geom_text(data = a2, 
            aes(type1, counts,fill = type2, label = counts),
            position = position_dodge(0.9), vjust = -0.8) + 
  geom_text(data = a1, 
            aes(type1, counts,fill = type2, label = counts),
            position = position_dodge(0.9), vjust = -0.8) + 
  ggthemes::theme_economist() + 
  # 在这个网站找颜色https://colorbrewer2.org/
  scale_fill_manual(values = c("#fc9272", "#9ecae1", "#de2d26","#3182bd"))
  

下面开始技术总结:

  • 一定注意绘图的顺序,永远是先画高的,再画矮的,并且text 的标记,最后画;
  • 检验有没有合理顺序的标准是,你就看legend 颜色和真实颜色是否对应的,比如第一个出图结果里的,颜色,明显不对;
  • 在text 中,建立的映射要考虑fill(对应col 中的,如果是color 则也是color);
  • 在https://colorbrewer2.org/ 选择合适的颜色,关于颜色,我也会专门出一个系列;

有同学可能要问了,这个高的人家减了你为啥没减,很显然,这样会造成误会,你明明身处64,数值却显示24,搞鬼哦。

当然你要非头铁的话,ggtext 的label 调整一下,反正我不教你了。

后话

感觉我有点像王刚啊,喜欢做完菜来个技术总结,hhh。

另外,这个图我采取了和作者不同的处理方式:

不难发现,作者大的柱状图实际上底下空了一截,这里有两个猜想:

  • 它实际上也是像我一样画的,只是ggtext 刻意减去了小的,并且通过color 产生视觉上错觉;
  • 它确实是第二个图层映射的时候,底下空了一截。

那么如果是猜想二,这种横空的柱状图该怎么画呢?

请各位思考一下。因为没有什么应用价值,这个坑暂时不填。