R inconsistency: why add=T sometimes works and sometimes not in the plot() function?

Why is R inconsistent with the add parameter in the plot() function? It sometimes works and sometimes doesn't! In this example, it takes the parameter add=TRUE with no problem:

plot(0:10, 0:10*3)
plot(identity, add=TRUE, xlim=c(0,10))
plot(function (x) { sin(x)*10 }, add=TRUE, xlim=c(0,10))

But when I issue

plot(c(2, 3, 4), c(20,10,15), add=TRUE, pch="A")

It doesn't work!! It says that "add" is not a graphical parameter.

Please do not write that I should use points() instead. I know I can use it. I want to understand the strange behaviour of R - why does it sometimes work and sometimes not?


Solution 1:

This is admittedly annoying and inconsistent, but it's explicable.

identity is an object of a class — function — that has a plot method (plot.function) with an add argument, while the default plot method does not have an add argument.

In general, when trying to plot object bar, you should try class(bar); if it is of class foo then try methods(class="foo") to see that it has a plot method, or methods("plot") to see that plot.foo exists. Try ?plot.foo (or help("plot.foo") to see help, or plot.foo to see the function itself. (If the method is a private function in the package mypkg you may need mypkg:::plot_foo or or getAnywhere(plot.foo) to find it.)

Solution 2:

This is because when you call plot(0:10, 0:10*3) or plot(c(2, 3, 4), c(20,10,15)), you are indirectly calling plot.default(), which in turn calls plot.xy(), whereas the other two calls you mention are running plot.function(). add is an argument for plot.function(), but not for plot.xy().

You can get around this inconsistency by setting par(new = TRUE), but then you need to make sure that you don't add fresh axis labels or redraw the axes. EDIT: As pointed out in the comment, you have to make sure that the range is the same as the previous plot. e.g.:

plot(0:10, 0:10*3)
plot(identity, add=T, xlim=c(0,10))
plot(function (x) { sin(x)*10 }, add=T, xlim=c(0,10))
par(new = TRUE)
plot(c(2, 3, 4), c(20,10,15), pch="A",
     axes = FALSE, ## don't redraw the axes 
     xlab = '', ylab = '', ## no fresh axis labels
     xlim = c(0,10), ylim = c(0,30)) ## keep the same limits as before

As Ben Bolker mentions, methods('plot') will show you what methods can be called when running plot() - the different methods have different arguments, which are listed when you call args(plot.foo) or in the help page ?plot.foo