r - 用自己的 geoms 扩展 ggplot : Adapt default scale

标签 r ggplot2 ggproto

背景

阅读 this beautiful answer on how to extend ggplotthe 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")

产生这个情节: Barplot with text

问题

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

注意。 当然,我可以通过要求添加手动秤来将问题推给最终用户。但理想情况下,我希望正确设置秤。

最佳答案

Eureka

感谢@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 中的这个字段设置为适当的值,很容易找到一个丑陋的 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)
                   }
)

结果

Barplot with labels

未决问题

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

关于r - 用自己的 geoms 扩展 ggplot : Adapt default scale,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55457804/

相关文章:

r - data.table:是否可以合并 .SD 并按组返回一个新的 'sub data table'?

r - 为什么有些数据集需要我们做 `data(somedataset)` 才能使用?

r - 建立一个新的 geom_hurricane

r - 在 Jupyter 中安装 R 包

r - 在函数内访问函数中的变量

r - 如何在具有融化数据的ggplot中缩放密度图(针对多个变量)

r - 如何绘制空图?

r - 在R中如何使用ggplot绘制正态分布的尾部区域?

r - 使用雷达坐标将线段添加到ggplot2中的直方图中

r - ggplot2:将样本量信息添加到x轴刻度标签