【问题标题】:Is there a programatic way to pass specific ranges for the y-axis on a ggplot2 plot?是否有一种编程方式可以在 ggplot2 图上传递 y 轴的特定范围?
【发布时间】:2021-06-20 12:57:56
【问题描述】:

我有一些图是根据一些用户输入自动生成的。大多数情况下,情节运行良好。但是,一些用户要求确保在绘制数据的每一端始终有一个轴标签。例如,这个情节:

sample_data <-
  data.frame(
    x = rep(LETTERS[1:3], each = 3)
    , y = 1:9 + 0.5
  )


ggplot(
  sample_data
  , aes(x = x, y = y)) +
  stat_summary(
    fun = "mean"
  )

在顶点上方或底部下方没有标签。我可以使用expand_limits 轻松添加它们:

ggplot(
  sample_data
  , aes(x = x, y = y)) +
  stat_summary(
    fun = "mean"
  ) +
  expand_limits(y = c(2, 10))

然而,因为这些图是自动生成的,我不能每次都手动添加下一个轴点。我已经尝试将only.loose = TRUE 传递给labeling:extended,但这仍然不会改变显示的值(只要输入我想要的值):

ggplot(
  sample_data
  , aes(x = x, y = y)) +
  stat_summary(
    fun = "mean"
  ) +
  scale_y_continuous(breaks = breaks_extended(only.loose = TRUE))

此外,一些绘图比这更复杂(例如,有或没有置信区间、附加分组等),并且使用dplyr 为绘图准备数据并直接通过管道输入ggplot%&gt;%)。因此,即使是像重新计算值这样的事情也很重要。

事实上,即使在这种情况下,它也会失败,因为添加扩展点来捕获下一组标签会改变标签。

ggplot(
  sample_data
  , aes(x = x, y = y)) +
  stat_summary(
    fun = "mean"
  ) +
  scale_y_continuous(breaks = breaks_extended(n = 5
                                              , only.loose = TRUE)) +
  expand_limits(y =
                  sample_data %>%
                  group_by(x) %>%
                  summarise(my_mean = mean(y)) %>%
                  pull(my_mean) %>%
                  range() %>%
                  {labeling::extended(.[1], .[2], 5
                                      , only.loose = TRUE)}
                  )

这似乎是因为

labeling::extended(2.5, 8.5, 5, only.loose = TRUE)

以 1 为单位返回 2 到 9 的范围,而:

labeling::extended(2, 9, 5, only.loose = TRUE)

返回 2 到 10 x 2 的范围。不知何故,breaks_extended 加入了一些额外的变化,尽管我是否追踪它并没有太大变化。我可以通过先计算休息时间来解决这个问题,但是(再次)这是针对一组相当复杂的绘图。

我觉得我错过了一些明显的观点,但它一直在逃避我。

【问题讨论】:

    标签: r ggplot2 axis-labels


    【解决方案1】:

    受 teunbrand 启发,我构建了一个生成限制的函数,然后检查以确保扩展(包括 5% 缓冲区)不会改变 pretty 的输出

    my_lims_expand <- function(x){
      prev_pass <-
        range(pretty(x))
      
      curr_pass <-
        pretty(c(prev_pass[1] - 0.05 * diff(prev_pass)
                 , prev_pass[2] + 0.05 * diff(prev_pass)))
      
      last_under <-
        tail(which(curr_pass < min(x)), 1)
      
      first_over <-
        head(which(curr_pass > max(x)), 1)
      
      out <-
        range(curr_pass[last_under:first_over])
      
      confirm_out <-
        range(pretty(out))
      
      while(!all(out == confirm_out)){
        prev_pass <- curr_pass
        
        curr_pass <-
          pretty(c(prev_pass[1] - 0.05 * diff(prev_pass)
                   , prev_pass[2] + 0.05 * diff(prev_pass)))
        
        last_under <-
          tail(which(curr_pass < min(x)), 1)
        
        first_over <-
          head(which(curr_pass > max(x)), 1)
        
        out <-
          range(curr_pass[last_under:first_over])
        
        confirm_out <-
          range(pretty(out))
      }
      
      
      return(out)
    }
    

    然后,我可以将该函数用于limits

    ggplot(sample_data, 
           aes(x = x, y = y)) +
      stat_summary(
        fun = "mean"
      ) +
      scale_y_continuous(
        limits = my_lims_expand
        , breaks = pretty
      )
    

    生成所需的图:

    【讨论】:

      【解决方案2】:

      是的,有一种编程方式来设置 y 尺度的限制,即为limits 参数提供一个函数。它被赋予自然数据限制作为输入,然后您可以通过编程方式对其进行编辑。休息也是如此,除了输入是限制。

      下面的示例,这段代码的外观完全取决于您的规范。

      library(ggplot2)
      
      sample_data <- data.frame(
        x = rep(LETTERS[1:3], each = 3), 
        y = 1:9 + 0.5
      )
      
      
      ggplot(sample_data, 
             aes(x = x, y = y)) +
        stat_summary(
          fun = "mean"
        ) +
        scale_y_continuous(
          limits = function(x) {
            lower <- floor(x[1])
            lower <- ifelse(x[1] - lower < 0.5, lower - 1, lower)
            upper <- ceiling(x[2])
            upper <- ifelse(upper - x[2] <= 0.5, upper + 1, upper)
            c(lower, upper)
          },
          breaks = function(x) {
            scales::breaks_pretty()(x)
          }
        )
      #> Warning: Removed 3 rows containing missing values (geom_segment).
      

      reprex package (v1.0.0) 于 2021-03-23 创建

      【讨论】:

      • 谢谢。这让我更接近了。我已经阅读了limitsscale_y_continuous 文档,说它会删除指定限制之外的数据。但是,这似乎发生在 计算它在图上的点之后(这里取平均值)而不是之前。但是,因为我不知道漂亮的中断步长(数据跨越数量级),所以我无法对步长进行硬编码。取pretty(x) 的范围会失败,因为中断随后被计算为pretty(pretty(x +/- 5%diff))。我想我可以解决它,但需要一些技巧
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-20
      • 2013-03-28
      • 2020-11-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多