Call setup_data from parent class

帅比萌擦擦* 提交于 2019-12-11 10:47:56

问题


Backround

I was reading this excellent answer on how to place self adjusting text into bars: Resizeable text grobs inside bars

After reading a bit on ggproto and especially the vignette on Extending ggplot I was wondering why the author had to define the setup_data routine as follows:

GeomFit <- ggproto("GeomFit", GeomRect,
               setup_data = function(data, params) {
                 data$width <- data$width %||%
                   params$width %||% (resolution(data$x, FALSE) * 0.9)
                 transform(data,
                           ymin = pmin(y, 0), ymax = pmax(y, 0),
                           xmin = x - width / 2, xmax = x + width / 2, width = NULL
                 )
               })

Because this is essentially a copy paste from ggplot2::GeomBar:

GeomBar$setup_data
# <ggproto method>
#   <Wrapper function>
#     function (...) 
# f(...)

#   <Inner function (f)>
#     function (data, params) 
# {
#     data$width <- data$width %||% params$width %||% (resolution(data$x, 
#         FALSE) * 0.9)
#     transform(data, ymin = pmin(y, 0), ymax = pmax(y, 0), xmin = x - 
#         width/2, xmax = x + width/2, width = NULL)
# }

So I thought I could replace this simply by:

GeomFit <- ggproto("GeomFit", GeomRect,
                   setup_data = function(self, data, params)
                      ggproto_parent(GeomBar, self)$setup_data(data, params))

This approach works, but I have my doubts whether this may lead to some unwanted behaviour simply becasue the parent class of GeomFit is GeomRect and not GeomBar.

Question

Is it ok (in the sense of: there are no conditions where this may cause a problem) to use ggproto_parent to call a function from a class which is not the parent class of my ggproto object? Why does ggproto_parent have a parent argument in the first place? Shouldn't the parent be anyways determined by the second argument of ggproto?


回答1:


I'm not involved in the ggplot2 package's development, but I'll take a stab at this since it's been a week & no one else has posted so far...

Below are the relevant function definitions I copied off ggplot2's GitHub page:

ggproto_parent <- function(parent, self) {
  structure(list(parent = parent, self = self), class = "ggproto_parent")
}

`$.ggproto_parent` <- function(x, name) {
  res <- fetch_ggproto(.subset2(x, "parent"), name)
  if (!is.function(res)) {
    return(res)
  }

  make_proto_method(.subset2(x, "self"), res)
}

From the first function, we can deduce that ggproto_parent(GeomBar, self) in this case would return a list of two items, list(parent = GeomBar, self = self) (where self resolves to GeomFit). This list is passed to the second function as x.

The second function then searches within the x[["parent"]] for a method corresponding to the given name, in this case setup_data (fetch_ggproto), and associates it with x[["self"]] if the function in question includes a self parameter (make_proto_method).

Neither function checks for the parent of GeomFit (which can be accessed at GeomFit$super()), so I don't think having GeomBar instead of GeomRect in ggproto_parent() really matters.


That said, I would probably have used something like this:

GeomFit <- ggproto("GeomFit", GeomRect,
                   setup_data = .subset2(GeomBar, "setup_data"))

or this:

GeomFit <- ggproto("GeomFit", GeomRect,
                   setup_data = environment(GeomBar$setup_data)$f)

Which make for shorter code.



来源:https://stackoverflow.com/questions/55282193/call-setup-data-from-parent-class

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!