扩展 ggplot 自有几何对象:适应默认比例尺

3

背景

在阅读了如何扩展ggplot的精彩回答相应的文献之后,我试图理解如何扩展 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参数中设置多个和添加因子。这里有一个例子。当人们希望图形不被扩展时,这经常出现。在最近的版本中,您可以使用expand_scale仅在一个方向上扩展轴?expand_scale是一个不错的起点。 - Gregor Thomas
2
我不知道初始轴范围如何在内部确定扩展。(这就是为什么我只是评论而不回答的原因。) - Gregor Thomas
1
根据我的理解,比例范围是基于数据范围进行训练的。如果您检查layer_data(p),则y值的范围为1-5,因此这就是图形的比例范围。 - Z.Lin
ggplot如何知道它需要查找哪个范围?使用相同的数据,基于我的映射,我可以得到非常不同的范围:d <- data.frame(x = rep(1:10, 10), y = sample(3, 100, TRUE)): p <- ggplot(d, aes(x = x)); p + geom_bar() vs p + geom_bar(aes(y=y), stat = "identity")。因此,只有在我们知道在geom中使用哪些映射之后,我们才能确定绘图的范围。-> 1. 哪个函数负责确定范围?2. 从哪个函数调用他的函数? - thothal
1
@thothal,这将是Layout中的 train_position 函数。当我挖掘 ggplot 对象时,我喜欢使用的一个技巧是在 ggplot2:::ggplot_build.ggplotggplot2:::ggplot_gtable.ggplot_built(也就是 ggplotGrob() 的两个阶段) 中运行调试,并检查每个步骤的输出,以找到感兴趣的现象 (在这种情况下是比例尺创建) 发生的位置。不过要小心,兔子洞可能会变得非常非常深... - Z.Lin
+1,这正是我目前正在做的事情,还有很多要学习的。感谢您的另一个答案,我现在能够在不同的Geom*内部函数上使用debug了。我想我找到了一个丑陋的解决方法,我会将其发布供以后参考。 - thothal
1个回答

2

最初的回答

借助@Z.Lin的帮助,我发现了一种丑陋的hack方法来调试ggplot代码。以下是为了以后参考而想出这种相当丑陋的hack的方式:

如何实现

在调试debug(ggplot2:::ggplot_build.ggplot)时,我了解到罪魁祸首可以在FacetNull$train_scales中找到(在我没有facet的情况下制作的图表中,其他类似于FacetGrid的facet也是按照相似的方式工作的)。我通过debug(environment(FacetNull$train_scales)$f)了解到这一点,而我是从另一个线程中的Z.Lin的答案中学到这一点的。

一旦我能够调试ggproto对象,我就能看到在这个函数中比例尺被训练的位置。基本上,该函数查看与特定比例尺相关的美学,然后查看这些美学是否存在于图层数据中。(关于这些信息最初在哪里设置,请问有什么想法吗?)

我发现一个名为ymax_final的字段(根据这张表格,它仅用于stat_boxplot),它是被考虑设置比例尺的字段之一。有了这个信息,很容易通过将setup_data中的这个字段设置为适当的值来找到一个丑陋的hack。

代码

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)
                   }
)

结果

带标签的条形图

开放性问题

如果您没有手动定义轴比例,那么它们在哪里设置?我猜这些与缩放相关的字段被设置了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接