如何跨几何对齐比例转换?

How to align scale transformation across geoms?

我有一个 geom_foo(),它将对输入数据进行一些转换,并且我有一个比例转换。我的问题是,这些在缩放方面并不像我预期的那样与其他 geom_* 一起工作。

为了说明该行为,请考虑 foo(),它将在问题末尾定义的 GeomFoosetup_data 方法中使用。

foo <- function(x, y) {
  data.frame(
    x = x + 2,
    y = y + 2
  )
}
foo(1, 1)

变压器是:

foo_trans <- scales::trans_new(
  name = "foo",
  transform = function(x) x / 5,
  inverse = function(x) x * 5
  )

鉴于此输入数据:

df1 <- data.frame(x = c(1, 2), y = c(1, 2))

这是一个基本情节:

library(ggplot2)
ggplot(df1, aes(x = x, y = y)) +
  geom_foo()

当我将转换应用于垂直比例时,我得到了这个

ggplot(df1, aes(x = x, y = y)) +
  geom_foo() +
  scale_y_continuous(trans = foo_trans)

我能说的是,y 轴限制计算为 11 = 1 + (2*5)12 = 2 + (2*5),其中 12df1$y,和 (2 * 5) 取自 setup_data 方法和 trans_foo.

我真正的问题是,我想添加一个带有标签的文本层。这些标签及其坐标来自另一个数据框,如下所示。

df_label <- foo(df1$x, df1$y)
df_label$label <- c("A", "B")

标签层和点层在相同的 x-y 位置上,没有进行比例变换

p <- ggplot(df1, aes(x = x, y = y)) +
  geom_foo(color = "red", size = 6) +
  geom_text(data = df_label, aes(x, y, label = label)) 
p

但是当我应用变换时,坐标不再匹配

p +
  scale_y_continuous(trans = foo_trans)

如何在转换后使图层在 x-y 坐标中匹配?谢谢


ggproto 对象:

GeomFoo <- ggproto("GeomFoo", GeomPoint,
  setup_data = function(data, params) {
    cols_to_keep <- setdiff(names(data), c("x", "y"))
    cbind(
      foo(data$x, data$y), 
      data[, cols_to_keep]
    )
  }
)

geom构造函数:

geom_foo <- function(mapping = NULL, data = NULL, ...,
                     na.rm = FALSE, show.legend = NA,
                     inherit.aes = TRUE) {
  layer(
    data = data,
    mapping = mapping,
    stat = "identity",
    geom = GeomFoo,
    position = "identity",
    show.legend = show.legend,
    inherit.aes = inherit.aes,
    params = list(
      na.rm = na.rm,
      ...
    )
  )
}

进行数据转换并不是 geom 的真正任务,而是 stat 的任务。也就是说,更大的问题是在调用 GeomFoo$setup_data() 方法之前应用了比例转换。我可以看到有两种方法可以完成这项任务。

  1. 在缩放转换之前应用foo()。我认为 geoms 或 stats 在 before scale transformation 之前无法访问数据。一个可能的地方是在 ggplot2:::Layer$setup_layer() 方法中。然而,这并没有导出,这可能意味着开发人员甚至在我们尝试之前就想阻止它。

  2. 逆比例变换,应用foo(),再次变换。为此,您需要一种可以访问秤的方法。 AFAIK,没有 geom 方法具有此访问权限。但是 Stat$compute_panel() 可以访问,所以我们可以使用它。

举一个 (2) 的例子,我认为你可以逃避以下问题:

StatFoo <- ggproto(
  "StatFoo", Stat,
  compute_panel = function(self, data, scales) {
    cols_to_keep <- setdiff(names(data), c("x", "y"))
    food <- foo(scales$x$trans$inverse(data$x), 
                scales$y$trans$inverse(data$y))
    cbind(
      data.frame(x = scales$x$trans$transform(food$x),
                 y = scales$y$trans$transform(food$y)),
      data[, cols_to_keep]
    )
  }
)

geom_foo <- function(mapping = NULL, data = NULL, ...,
                     na.rm = FALSE, show.legend = NA,
                     inherit.aes = TRUE) {
  layer(
    data = data,
    mapping = mapping,
    stat = StatFoo,
    geom = GeomPoint,
    position = "identity",
    show.legend = show.legend,
    inherit.aes = inherit.aes,
    params = list(
      na.rm = na.rm,
      ...
    )
  )
}

如果其他人对此有更好的想法,我也很想知道!