2
votes

I can define a S3 method like this :

`+.data.frame` <- function(e1,e2){"hello"}
iris + iris
# [1] "hello"

But this won't work if e2 is a gg object :

iris + geom_point()

Error in iris + geom_point() : non-numeric argument to binary operator

In addition: Warning message: Incompatible methods ("+.data.frame", "+.gg") for "+"

I think it has something to do with S4 methods but I'm confused. Can you explain what's at play and how to sort it out ?

desired output :

iris + geom_point()
# [1] "hello"
1

1 Answers

4
votes

This is actually not due to S4 methods but a method conflict. Neither geom_point() nor your data frame are S4 objects (isS4 on either of them returns FALSE), so S4 methods will not come into play.

The ggplot package defines a method for + on gg-classed objects, and you have just defined a method for data.frames. The trouble is, unlike most S3 generic functions, + takes the class of both arguments into account in selecting a method. In this case, it concludes that it could have legitimately chosen the gg method as well as the data.table method.

From the help page for "Ops" (of which "+" is a member):

The classes of both arguments are considered in dispatching any member of this group. For each argument its vector of classes is examined to see if there is a matching specific (preferred) or Ops method. If a method is found for just one argument or the same method is found for both, it is used. If different methods are found, there is a warning about ‘incompatible methods’: in that case or if no method is found for either argument the internal method is used.

So you see in this case, it falls through to the default + code, which doesn't know how to add data frames and gg objects, and returns an error saying as much.

To solve the issue, you may be able to write an S4 method with signature (data.frame,gg) (or perhaps (data.frame,ANY) but beware — it will only actually be called if one of the arguments is an S4 object (which data.frames are not by default). You may have to define your own class which contains data.frame (or, alternatively, contains gg) in order to trigger the method.