Reputation: 71
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.)?
Upvotes: 3
Views: 717
Reputation: 1211
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
Upvotes: 2
Reputation: 2071
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"
Upvotes: 2