问题
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