【问题标题】:any possible way to retain secondary axis label when primary axis is updated更新主轴时保留辅助轴标签的任何可能方式
【发布时间】:2021-03-23 09:27:54
【问题描述】:

我在ggplot2 的辅助x 轴上显示一个标签,它按预期工作。

library(ggplot2)

p <-  ggplot(mtcars, aes(wt)) +
    geom_histogram() +
    scale_x_continuous(sec.axis = sec_axis(trans = ~., 
                                           labels = "median", 
                                            breaks = 3.2))

# label present 
p
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
#> Warning in min(x): no non-missing arguments to min; returning Inf
#> Warning in max(x): no non-missing arguments to max; returning -Inf

但如果我更新主要的x-axis,次要的x-axis 将被删除。

# label absent
p + scale_x_continuous(limits = c(1, 6), breaks = c(seq(1, 6, 1)))
#> Scale for 'x' is already present. Adding another scale for 'x', which will
#> replace the existing scale.
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
#> Warning: Removed 2 rows containing missing values (geom_bar).

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

我原以为它会更新,而不是删除(因为辅助轴是主轴的变换)。

是否有可能更新主轴,同时保留次轴信息?

附言 这是在包函数的上下文中,该函数默认在辅助轴上显示标签。然后,用户可以根据需要使用ggplot2 函数更新绘图。这意味着用户有时可以更改轴,我希望该功能仍然显示标签。我将更新我的问题以提供此上下文。

【问题讨论】:

    标签: r ggplot2


    【解决方案1】:

    如果您的转换是与主轴 1:1 的转换,则可以通过构建新指南来规避辅助轴问题。然后可以在guides() 函数中设置它,从而独立于 x 比例。下面是一个快速而肮脏的例子:

    library(ggplot2)
    
    fix_axis <- function(breaks, labels) {
      guide <- guide_axis()
      guide$breaks <- breaks
      guide$labels <- labels
      class(guide) <- c("guide", "fix_axis", "axis")
      guide
    }
    
    guide_train.fix_axis <- function(guide, scale, aesthetic = NULL) {
      guide <- NextMethod()
      key <- as.list(guide$key)
      key[[1]] <- key$.value <- guide$breaks
      key$.label <- guide$label
      guide$key <- list2DF(key) # requires R version >4
      guide
    }
    
    p <- ggplot(mtcars, aes(wt)) +
      geom_histogram() +
      guides(x.sec = fix_axis(3.2, "median"))
    
    # Scale can update without affecting secondary axis
    p + scale_x_continuous(limits = c(2, 5))
    #> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
    #> Warning: Removed 7 rows containing non-finite values (stat_bin).
    #> Warning: Removed 2 rows containing missing values (geom_bar).
    

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

    【讨论】:

    • 这是存放在后袋中的绝妙技巧 - 感谢 @teunbrand 提供的这个巧妙的解决方法!
    【解决方案2】:

    这可能不是一个给出解决方案的答案,但我认为最好显示问题的一些复杂性。

    您的调用当然是替换已经存在的刻度,这意味着原始scale_x_continuous 调用中的所有部分都将被转储,并且正在添加全新的刻度调用。这是ggplot2 的一部分,它完全隐藏在其代码中,可能不应该被篡改。

    如下所示,当您添加新比例时,ggplot 对象调用p$scales$add() 方法,该方法检查比例定义中是否已经存在任何新美学。这是一个新的比例层添加的x:x0 的完整列表。所有这些(我认为)都是规模工作所必需的:

    library(ggplot2)
    
    p <- ggplot() + scale_x_continuous()
    
    p$scales$add
    #> <ggproto method>
    #>   <Wrapper function>
    #>     function (...) 
    #> f(..., self = self)
    #> 
    #>   <Inner function (f)>
    #>     function (self, scale) 
    #> {
    #>     if (is.null(scale)) {
    #>         return()
    #>     }
    #>     prev_aes <- self$find(scale$aesthetics)
    #>     if (any(prev_aes)) {
    #>         scalename <- self$scales[prev_aes][[1]]$aesthetics[1]
    #>         message_wrap("Scale for '", scalename, "' is already present. Adding another scale for '", 
    #>             scalename, "', which will replace the existing scale.")
    #>     }
    #>     self$scales <- c(self$scales[!prev_aes], list(scale))
    #> }
    
    sc <- scale_x_continuous()
    
    sc$aesthetics
    #>  [1] "x"          "xmin"       "xmax"       "xend"       "xintercept"
    #>  [6] "xmin_final" "xmax_final" "xlower"     "xmiddle"    "xupper"    
    #> [11] "x0"
    
    p$scales$find(sc$aesthetics)
    #> [1] TRUE
    

    我建议您的解决方案可能会考虑定义另一个 ggproto object 来为辅助轴创建一种新类型的比例,该比例不会被检查现有比例的方法捕获。恐怕我自己对此的经验/知识就到此为止了!

    总的来说,您希望您的包用户能够使用scale_x_continuous 和其他正常的ggplot 函数,而不必担心它会破坏他们的图表。因此,定义一个新函数供用户在添加额外比例时使用可能不是最好的方法,现有的 ggplot scale_ 函数的工作方式最好不要管。

    reprex package (v1.0.0) 于 2021 年 3 月 23 日创建

    【讨论】:

      【解决方案3】:

      您是否有理由要更新轴,而不是首先定义主轴的限制/中断?如果没有,你可以这样做:

      ggplot(mtcars, aes(wt)) +
        geom_histogram() +
        scale_x_continuous(sec.axis = sec_axis(trans = ~., labels = "median", breaks = 3.2),
                           limits = c(1, 6), breaks = c(seq(1, 6, 1)))
      

      【讨论】:

      • 是的,这是在包函数的上下文中,该函数默认在辅助轴上显示标签。然后,用户可以根据需要使用ggplot2 函数更新绘图。这意味着用户有时可以更改轴,我希望该功能仍然显示标签。我将更新我的问题以提供此上下文。
      • 不幸的是,我不知道答案,因为我相信sec_axis() 只接受原始轴的一对一转换。希望其他人能够提供帮助。
      【解决方案4】:

      试试这个:

      ggplot(mtcars, aes(wt)) +
        geom_histogram() +
        scale_x_continuous(
          limits = c(1, 6),
          breaks = c(seq(1, 6, 1)),
          sec.axis = sec_axis(trans = ~ ., labels = "median", breaks = 3.2)
        )
      

      您的第二个 scale_x_continuous() 替换了第一个。

      【讨论】:

      • 请参阅附注。在我的问题中。
      猜你喜欢
      • 2020-11-22
      • 1970-01-01
      • 2022-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-20
      相关资源
      最近更新 更多