• R语言已解决
  • 求助:ggplot2::facet_grid()让每行中各图纵坐标轴范围按需而定

问题描述
ggplot::facet_grid()作图时,有时会因为数据量级差异太大,导致有些小图难以看清楚。虽然该函数有个scales参数,但是设置scales = "free"只能改变各列的纵坐标范围,而无法让行内各图的纵坐标轴范围根据需求而改变。具体代码和结果如下。

代码及结果

# 构建数据
mydata <- data.frame(city = rep(c("A", "B"), each = 4), 
                     var = rep(rep(c("a", "b"), each = 2), 2), 
                     time = rep(1:2, 4), 
                     value = c(1, 2, 10, 20, 3, 4, 300, 400))

# 作图
library(ggplot2)
ggplot(mydata) + geom_col(aes(time, value)) + 
  facet_grid(city ~ var)

结果如下:

可见左上、右上和左下图均因为量级太小而难以看清。

# facet_grid()的scales = "free"可让各列横纵坐标轴范围按需而定
ggplot(mydata) + geom_col(aes(time, value)) + 
  facet_grid(city ~ var, scales = "free")

结果如下:

现在上面一行的纵坐标轴根据需求做了调整,右上图可以看清了,但是左上和左下图仍然看不清楚。

想要解决这个办法,当然可以通过一些拼图包实现,比如说ggpubr或者patchwork包。

library(patchwork)
p1 <- ggplot(mydata[which(mydata$city == "A"), ]) + geom_col(aes(time, value)) + 
  facet_wrap(.~ var, scales = "free") + 
  labs(title = "(city A)")
p2 <- ggplot(mydata[which(mydata$city == "B"), ]) + geom_col(aes(time, value)) + 
  facet_wrap(.~ var, scales = "free") + 
  labs(title = "(city B)")
p1 / p2

结果是:

但是这样逻辑条理不如facet_grid()清晰,上下行的图也没有对齐得很好。想请教是否有更好的解决方案呢?

如果需要显示的数值相差极大,一个相对简单的方案是用对数轴,不过读图须谨慎:

library(ggplot2)
# 构建数据
mydata <- data.frame(city = rep(c("A", "B"), each = 4), 
                     var = rep(rep(c("a", "b"), each = 2), 2), 
                     time = rep(1:2, 4), 
                     value = c(1, 2, 10, 20, 3, 4, 300, 400))

# 作图
ggplot(mydata) + geom_col(aes(time, value)) + 
  facet_grid(city ~ var) + 
  scale_y_log10()

<sup>Created on 2021-11-20 by the reprex package (v2.0.1)</sup>

    Liechi 有道理,也想着是不是做点变换或者标准化来着。不过确实数据关系也会有变化,比如右下图的两个条差异就不那么大了。

    fenguoerbian Hadley的这个回答应该就是说……无法在facet_grid()的基础上实现我想要达到的效果吧。用facet_wrap()可以在每一行内实现纵坐标轴根据需求而定,之后还是需要通过拼图函数来组合小图。但是这种方法,正如帖子中最后一图所展示的,拼图之间上下对应的小图没法完全对齐:

      KANG1943

      library(ggplot2)
      ggplot(mydata) + geom_col(aes(time, value)) + 
        facet_wrap(city ~ var, scale = "free")

      你理解错了,我是说用facet_wrap配合scale参数就可以实现横向纵向坐标轴都是完全放开。只需要把你原来代码里facet_grid替换掉就行了,不需要自己再拼图。不过facet_wrap的标记方式似乎和facet_grid不完全一致。

        KANG1943
        另外想自己拼图不妨考虑cowplot

        library(tidyverse)
        library(cowplot)
        g1 <- ggplot(mydata %>% filter(var == "a", city == "A")) + 
            geom_col(aes(time, value)) + 
            labs(title = "city: A, var: a")
        
        g2 <- ggplot(mydata %>% filter(var == "b", city == "A")) + 
            geom_col(aes(time, value)) + 
            labs(title = "city: A, var: b")
        
        g3 <- ggplot(mydata %>% filter(var == "a", city == "B")) + 
            geom_col(aes(time, value)) + 
            labs(title = "city: B, var: a")
        
        g4 <- ggplot(mydata %>% filter(var == "b", city == "B")) + 
            geom_col(aes(time, value)) + 
            labs(title = "city: B, var: b")
        
        plot_grid(g1, g2, g3, g4, align = "hv")

        这里用align参数控制拼图的行列都对齐。

          6 天 后

          fenguoerbian 不好意思,原来是这个意思。确实可以将facet_grid()改成facet_wrap()然后通过指定行列来获得类似的拼图,有点像是将数字向量排列成一个矩阵的过程,不过横幅显示方式就比较冗杂就是了。谢谢哇!

          mydata <- data.frame(city = rep(c("A", "B"), each = 4),
          var = rep(rep(c("a", "b"), each = 2), 2),
          time = rep(1:2, 4),
          value = c(1, 2, 10, 20, 3, 4, 300, 400))

          作图

          library(ggplot2)
          ggplot(mydata) + geom_col(aes(time, value)) +
          facet_grid(city ~ var)

          library(ggh4x)
          ggplot(mydata) + geom_col(aes(time, value)) +
          facet_grid2(vars(city),vars(var),
          scales = 'free',
          independent = 'y',
          space = 'free_x')

          ggh4x 包,facet_grid2 解决坐标轴范围问题,各图y轴范围跟随数据变化。

            7 个月 后