3

In R, you often see plot() being used with very different kinds of data with very different default outcomes. plot() recognizes which object it is been given and uses the proper function according to this object.

In the example below plot() actually refers to ape::plot.phylo().

library(ape)
tree.owls <- 
  read.tree(text = 
              "(((Strix_aluco:4.2,Asio_otus:4.2):3.1, Athene_noctua:7.3):6.3,Tyto_alba:13.5);")
plot(tree.owls)

Question is: how do you know that in this case plot() refers to plot.phylo()? More generally, ss there a way to find out that would apply to any object being plotted (vector, df, list, S3, S4, etc.)?

  • 2
    You can check which method is used for cmombination and function, _G. Grothendieck_ actually wrote a nice function for this purpose: [R: how to find what S3 method will be called on an object?](https://stackoverflow.com/questions/42738851/r-how-to-find-what-s3-method-will-be-called-on-an-object). `findMethod(plot, tree.owls)` in your case. – jay.sf Jan 22 '20 at 18:09
  • @jay.sf trying that gives the following error: Error in getGeneric(f, where = where) : argument 'f' must be a string, generic function, or primitive: got an ordinary function – Jordan Hackett Jan 22 '20 at 18:21
  • 1
    @JordanHackett That message looks like it's coming from `methods::findMethod`. You should either overwrite that function with the one in the linked answer or create a function from that answer with a new name. It works for me that way, returning `[1] "plot.phylo"` – IceCreamToucan Jan 22 '20 at 18:25
  • 1
    @JordanHackett We could check your issue much better if you provide a minimal, self-contained, reproducible code, check that out: https://stackoverflow.com/a/5963610/6574038 – jay.sf Jan 22 '20 at 18:26
  • @IceCreamToucan awesome that was exactly the case thank you! Note I am not the OP but was also just interested in this problem. – Jordan Hackett Jan 22 '20 at 19:02
  • 1
    @jay.sf Thanks. this works great in cases were object is an S3. Doesn't seem to work when object is an S4? Eg.: `library(MSnbase); data(itraqdata);plot(itraqdata[[1]]);findMethod(plot,itraqdata[[1]])` tells me it is running `plot.default`, which I doubt it is the case? – Sebastien Renaut Jan 22 '20 at 19:23

2 Answers2

2

As other's have mentioned, this has to do with S3 method dispatch. You can check what the class of an object is with the class function. In this case it returns phylo.

A lot of generic functions have many methods. You can check all the methods by using methods("plot").

The source code for the plot function is

function (x, y, ...) 
UseMethod("plot")

and the UseMethod function will search for the available methods on the generic function given. If it can find the method, in this case plot.phylo then it will execute that method, otherwise it uses the next method or the default method.

So to reiterate, what method plot uses entirely depends on the class of the object, not so much if the object is a dataframe, vector, list, etc. Classes are convenient in guaranteeing a function will behave in an expected way.

To really make a point, you can define your own plot method too. Take this for example:

plot.foo <- function(x){
      str(x)
      plot(iris)
}

obj1 <- 1:3
class(obj1) <- "foo"
obj2 <- list(x = 2, y = 1:100)
class(obj2) <- "foo"

#No matter the object we pass, so long as the class if "foo",
# our custom plot method is called

plot(obj1)
#Class 'foo'  int [1:3] 1 2 3
plot(obj2)
#List of 2
 #$ x: num 2
 #$ y: int [1:100] 1 2 3 4 5 6 7 8 9 10 ...
 # - attr(*, "class")= chr "foo"
Justin Landis
  • 1,981
  • 7
  • 9
2

plot() is a generic function. The ape package has a method for the plot function, which is plot.phylo. When a package is loaded into an R session, any methods for each generic function are cached in your environment.

If you try methods(plot), you will see all the various plot() methods available in your environment. Here are two nifty lines for seeing information about each plot method in your environment.

m <- methods("plot")     
print(attr(m, "info"))  

So how does plot() know to use plot.phylo and not plot.default or one of the many other available plot methods? The package authors use their method on objects with a particular class attribute. In this case, the class attribute is "phylo". We can see the class attribute with str() or dplyr::glimpse():

> str(tree.owls)
List of 4
 $ edge       : int [1:6, 1:2] 5 6 7 7 6 5 6 7 1 2 ...
 $ edge.length: num [1:6] 6.3 3.1 4.2 4.2 7.3 13.5
 $ Nnode      : int 3
 $ tip.label  : chr [1:4] "Strix_aluco" "Asio_otus" "Athene_noctua" "Tyto_alba"
 - attr(*, "class")= chr "phylo"
 - attr(*, "order")= chr "cladewise"

If a given object does not have the class attribute required for the method, it will try other methods of the function, finally trying the default method, which is in this case is plot.default

SEAnalyst
  • 1,077
  • 8
  • 15