【问题标题】:Extending ggplot with own geoms: Adapt default scale使用自己的几何扩展 ggplot:调整默认比例
【发布时间】:2019-08-22 18:40:08
【问题描述】:

背景

阅读this beautiful answer on how to extend ggplot 和the corresponding vignette 后,我试图了解如何扩展ggplot。

简而言之

我了解,这些部分是如何组合在一起的,但我错过了一个重要信息:ggplot 如何确定轴的默认范围?

代码

考虑以下玩具示例:

library(grid)
library(ggplot2)

GeomFit <- ggproto("GeomFit", GeomBar,
                   required_aes = c("x", "y"),
                   setup_data = .subset2(GeomBar, "setup_data"),
                   draw_panel = function(self, data, panel_scales, coord, width = NULL) {
                     bars <- ggproto_parent(GeomBar, self)$draw_panel(data,
                                                                      panel_scales, 
                                                                      coord)
                     coords <- coord$transform(data, panel_scales)    
                     tg <- textGrob("test", coords$x, coords$y * 2 - coords$ymin)
                     grobTree(bars, tg)
                   }
)

geom_fit <- function(mapping = NULL, data = NULL,
                     stat = "count", position = "stack",
                     ...,
                     width = NULL,
                     binwidth = NULL,
                     na.rm = FALSE,
                     show.legend = NA,
                     inherit.aes = TRUE) {

  layer(
    data = data,
    mapping = mapping,
    stat = stat,
    geom = GeomFit,
    position = position,
    show.legend = show.legend,
    inherit.aes = inherit.aes,
    params = list(
      width = width,
      na.rm = na.rm,
      ...
    )
  )
}

set.seed(1234567)
data_gd <- data.frame(x = letters[1:5], 
                      y = 1:5)

p <- ggplot(data = data_gd, aes(x = x, y = y, fill = x)) + 
  geom_fit(stat = "identity")

这会产生这个情节:

问题

如您所见,某些文本未显示。我假设ggplot 以某种方式计算轴的范围,因为它不知道我的textGrob 所需的额外空间。我该如何解决? (期望的结果相当于p + expand_limits(y = 10)

NB. 当然,我可以将问题推给最终用户,方法是要求添加手动比例。但理想情况下,我希望正确设置秤。

【问题讨论】:

  • ggplot 通过乘法和加法扩展数据的范围。用户可以在scale 函数的expand 参数中设置乘法和加法系数。 See here for an example。当人们想要the plot to not be expanded at all 时,通常会出现这种情况。在最近的版本中,您可以使用expand_scale to expand the axis in one direction only。 ?expand_scale 是一个不错的起点。
  • 我不知道在内部如何确定要扩展的初始轴范围。(这就是为什么我只是评论,而不是回答。)
  • 根据我的理解,规模范围是根据数据范围训练的。如果选中layer_data(p),y 值的范围是 1-5,这就是绘图的比例范围。
  • ggplot 如何知道它必须查找哪个范围?使用相同的数据,我可以根据我的映射得到完全不同的范围:d &lt;- data.frame(x = rep(1:10, 10), y = sample(3, 100, TRUE)):p &lt;- ggplot(d, aes(x = x)); p + geom_bar() vs p + geom_bar(aes(y=y), stat = "identity")。所以只有在我们知道我们在geom 中使用了哪些映射之后,我们才能确定绘图的范围。 -> 1.哪个函数负责确定范围? 2. 他的函数是从哪个函数调用的?
  • @thothal 那将是来自Layout 的train_position 函数。在挖掘 ggplot 对象时,我喜欢使用的一个技巧是在 ggplot2:::ggplot_build.ggplot 或 ggplot2:::ggplot_gtable.ggplot_built(ggplotGrob() 的两个阶段)上运行调试,并检查每个步骤中的输出以找到感兴趣的现象(在此案例规模创建)发生。不过要小心,兔子洞会变得非常非常深......

标签: r ggplot2 ggproto


【解决方案1】:

尤里卡

感谢@Z.Lin 在如何调试ggplot 代码方面的出色帮助,发现了一个丑陋的 hack。以下是我如何想出这个相当丑陋的 hack 以供将来参考:

我是如何到达那里的

在调试debug(ggplot2:::ggplot_build.ggplot) 时,我了解到罪魁祸首可以在FacetNull$train_scales 的某个地方找到(在我的情节中没有任何方面, FacetGrid 等其他方面的工作方式类似)。这是我通过debug(environment(FacetNull$train_scales)$f) 学到的,而这又是我在answer by Z.Lin in another thread 中学到的。

一旦我能够调试ggproto 对象,我就可以看到在这个函数中训练了尺度。基本上,该功能着眼于与特定比例相关的美学(不知道首先在哪里设置此信息,任何想法?)并查看这些美学中的哪些存在于图层数据中。

我看到一个字段ymax_final(根据this table - 仅用于stat_boxplot)是考虑设置比例的字段之一。有了这条信息,通过将setup_data 中的此字段设置为适当的值,很容易找到丑陋的黑客攻击。

代码

GeomFit <- ggproto("GeomFit", GeomBar,
                   required_aes = c("x", "y"),
                   setup_data = function(self, data, params) {
                      data <- ggproto_parent(GeomBar, self)$setup_data(data, params)
                      ## here's the hack: add a field which is not needed in this geom, 
                      ## but which is used by Facet*$train_scales which 
                      ## eventually sets up the scales
                      data$ymax_final <- 2 * data$y
                      data
                   }, 
                   draw_panel = function(self, data, panel_scales, coord, width = NULL) {
                     bars <- ggproto_parent(GeomBar, self)$draw_panel(data,
                                                                      panel_scales, 
                                                                      coord)
                     coords <- coord$transform(data, panel_scales)    
                     tg <- textGrob("test", coords$x, coords$y * 2 - coords$ymin)
                     grobTree(bars, tg)
                   }
)

结果

未决问题

如果您不手动定义(轴)刻度,它们在哪里设置?我猜那里设置了与缩放相关的字段。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-07
    • 2012-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-28
    • 1970-01-01
    相关资源
    最近更新 更多