Hi all,
As long as I've used R, add=TRUE hasn't worked in contexts like this:
f <- function(x) x^2
X <- seq(0, 1, by=1/4)
plot(f, col="blue")
plot(X, f(X), col="red", type="l", add=TRUE)
I attached a fix for version 2.6.2.
Cheers,
Andrew
-------------- next part --------------
diff --git a/src/library/graphics/R/plot.R b/src/library/graphics/R/plot.R
index 233b11e..ad3529e 100644
--- a/src/library/graphics/R/plot.R
+++ b/src/library/graphics/R/plot.R
@@ -46,16 +46,24 @@ plot.default <-
function(x, y = NULL, type = "p", xlim = NULL, ylim = NULL,
log = "", main = NULL, sub = NULL, xlab = NULL, ylab = NULL,
ann = par("ann"), axes = TRUE, frame.plot = axes,
- panel.first = NULL, panel.last = NULL, asp = NA, ...)
+ panel.first = NULL, panel.last = NULL, asp = NA, add=FALSE, ...)
{
+ xlabel <- if (!missing(x)) deparse(substitute(x))
+ ylabel <- if (!missing(y)) deparse(substitute(y))
+ if (add) {
+ log <- paste(ifelse(unlist(par("xlog", "ylog")), c("x", "y"), ""),
+ collapse="")
+ xy <- xy.coords(x, y, xlabel, ylabel, log=log)
+ plot.xy(xy, type, ...)
+ return(invisible())
+ }
+
## These col, bg, pch, cex can be vectors, so exclude them
## Also, axis and box accept some of these
localAxis <- function(..., col, bg, pch, cex, lty, lwd) Axis(...)
localBox <- function(..., col, bg, pch, cex, lty, lwd) box(...)
localWindow <- function(..., col, bg, pch, cex, lty, lwd) plot.window(...)
localTitle <- function(..., col, bg, pch, cex, lty, lwd) title(...)
- xlabel <- if (!missing(x)) deparse(substitute(x))
- ylabel <- if (!missing(y)) deparse(substitute(y))
xy <- xy.coords(x, y, xlabel, ylabel, log)
xlab <- if (is.null(xlab)) xy$xlab else xlab
ylab <- if (is.null(ylab)) xy$ylab else ylab
[patch] add=TRUE in plot.default()
15 messages · Andrew Clausen, Henrique Dallazuanna, Hadley Wickham +3 more
I think you can use par(new = T) here: f <- function(x) x^2 X <- seq(0, 1, by=1/4) plot(f, col="blue") par(new = T) plot(X, f(X), col="red", type="l", xlab="", ylab="")
On 09/03/2008, Andrew Clausen <clausen at econ.upenn.edu> wrote:
Hi all, As long as I've used R, add=TRUE hasn't worked in contexts like this: f <- function(x) x^2 X <- seq(0, 1, by=1/4) plot(f, col="blue") plot(X, f(X), col="red", type="l", add=TRUE) I attached a fix for version 2.6.2. Cheers, Andrew
Henrique Dallazuanna Curitiba-Paran?-Brasil 25? 25' 40" S 49? 16' 22" O
On 08/03/2008 10:11 PM, Andrew Clausen wrote:
Hi all, As long as I've used R, add=TRUE hasn't worked in contexts like this: f <- function(x) x^2 X <- seq(0, 1, by=1/4) plot(f, col="blue") plot(X, f(X), col="red", type="l", add=TRUE) I attached a fix for version 2.6.2.
It has never been claimed that it would work, and as far as I can see, it doesn't make anything easier: the last line could be replaced by lines(X, f(X), col="red") for more clarity from less typing. So why would you want add=TRUE in plot.default? Duncan Murdoch
Hi Henrique,
Sorry I wasn't very clear. I should have said that I think it's nice that
add=TRUE works for some things, like
plot(f)
plot(g, add=TRUE)
I think it's a convenient and simple way of adding things to a plot. But this
add=TRUE trick doesn't work for everything, and I think it would be convenient
if it did.
In the past, I've used
f <- function(x) x^2
X <- seq(0, 1, by=1/4)
plot(f, col="blue")
lines(X, f(X), col="red")
which I think is clumsy.
I didn't know about "new". Why is new back-to-front? If you specify
"new=TRUE", it does NOT create a new graph. Why does it require you
to specify empty xlab and ylab? Why doesn't this work:
f <- function(x) x^2
X <- seq(0, 1, by=1/4)
plot(f, col="blue")
plot(X, f(X), col="red", type="l", xlab="", ylab="", new=TRUE)
It seems like we can't solve the first problem with new=TRUE (that it's
back-to-front) without breaking backward compatibility. So I think add=TRUE
should be encouraged instead, as in my patch.
But, there is one extra thing to think about. Sometimes, it's useful to
have a for-loop for putting several functions on a graph. For example,
f <- function(a) function(x) a * x^2
plot.new()
for (a in c(1,2,3))
plot(f(a), add=TRUE, col=a)
This doesn't work well. For example, it doesn't draw the axes. Is there
a user-friendly way of doing this properly, short of
f <- function(a) function(x) a * x^2
plot(f(3), col=3)
for (a in 1:3)
plot(f(a), add=TRUE, col=a)
For instance, is there a command that can tell you if the axes have been
drawn? If there were, then you could do something like
f <- function(a) function(x) a * x^2
plot.new()
for (a in c(1,2,3))
plot(f(a), add=(TRUE & par("axes.already.drawn")), col=a)
Cheers,
Andrew
On Sun, Mar 09, 2008 at 12:08:59PM -0300, Henrique Dallazuanna wrote:
I think you can use par(new = T) here: f <- function(x) x^2 X <- seq(0, 1, by=1/4) plot(f, col="blue") par(new = T) plot(X, f(X), col="red", type="l", xlab="", ylab="") On 09/03/2008, Andrew Clausen <clausen at econ.upenn.edu> wrote:
Hi all, As long as I've used R, add=TRUE hasn't worked in contexts like this: f <- function(x) x^2 X <- seq(0, 1, by=1/4) plot(f, col="blue") plot(X, f(X), col="red", type="l", add=TRUE) I attached a fix for version 2.6.2. Cheers, Andrew
-- Henrique Dallazuanna Curitiba-Paran?-Brasil 25? 25' 40" S 49? 16' 22" O
Hi Duncan,
On Sun, Mar 09, 2008 at 12:11:45PM -0400, Duncan Murdoch wrote:
It has never been claimed that it would work, and as far as I can see, it doesn't make anything easier: the last line could be replaced by lines(X, f(X), col="red") for more clarity from less typing. So why would you want add=TRUE in plot.default?
I don't like lines() because it ONLY allows you to add to plots. I could send a patch for that too... But I also like how plot() is polymorphic. It's nice how you can do some computation -- a regression, a histogram or whatever, and then just call plot() on it, and you have a nice graphical representation of it. But why stop there... wouldn't it be nice if you could stack them on top of each other? It's often useful to compare things by putting them on top of each other. (Are 2 regression lines the same or similar? Are two utility functions the same? etc.) Cheers, Andrew
I agree with Andrew's viewpoint. These changes would make R easier to use.
On Sun, Mar 9, 2008 at 12:46 PM, Andrew Clausen <clausen at econ.upenn.edu> wrote:
Hi Duncan, On Sun, Mar 09, 2008 at 12:11:45PM -0400, Duncan Murdoch wrote:
It has never been claimed that it would work, and as far as I can see, it doesn't make anything easier: the last line could be replaced by lines(X, f(X), col="red") for more clarity from less typing. So why would you want add=TRUE in plot.default?
I don't like lines() because it ONLY allows you to add to plots. I could send a patch for that too... But I also like how plot() is polymorphic. It's nice how you can do some computation -- a regression, a histogram or whatever, and then just call plot() on it, and you have a nice graphical representation of it. But why stop there... wouldn't it be nice if you could stack them on top of each other? It's often useful to compare things by putting them on top of each other. (Are 2 regression lines the same or similar? Are two utility functions the same? etc.) Cheers, Andrew
______________________________________________ R-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
On 09/03/2008 12:46 PM, Andrew Clausen wrote:
Hi Duncan, On Sun, Mar 09, 2008 at 12:11:45PM -0400, Duncan Murdoch wrote:
It has never been claimed that it would work, and as far as I can see, it doesn't make anything easier: the last line could be replaced by lines(X, f(X), col="red") for more clarity from less typing. So why would you want add=TRUE in plot.default?
I don't like lines() because it ONLY allows you to add to plots. I could send a patch for that too... But I also like how plot() is polymorphic. It's nice how you can do some computation -- a regression, a histogram or whatever, and then just call plot() on it, and you have a nice graphical representation of it. But why stop there... wouldn't it be nice if you could stack them on top of each other? It's often useful to compare things by putting them on top of each other. (Are 2 regression lines the same or similar? Are two utility functions the same? etc.)
Part of the reason I didn't like your patch is that it was incomplete: it didn't patch the plot.default.Rd file. That function already has around 16 parameters; do we really want to add another one, that interacts with some of the ones that are there? What you really seem to want is to add it to the generic plot(), but it's way too late to go modifying that particular generic. Duncan Murdoch
On Sun, Mar 09, 2008 at 04:04:08PM -0400, Duncan Murdoch wrote:
Part of the reason I didn't like your patch is that it was incomplete: it didn't patch the plot.default.Rd file.
Fair enough -- I wasn't sure whether I was fixing a bug or not. ("..."
spreads the documentation around a bit.)
That function already has around 16 parameters; do we really want to add another one, that interacts with some of the ones that are there?
Yes. The ability to plot things on top of each other is important. The simplicity created by having a single interface for adding to plots outweighs the complexity of yet another parameter. The add parameter only interacts with other parameters superficially -- some parameters of "plot" (like log) are related to the shape of the axes, and should be inherited from what is on the plot already.
What you really seem to want is to add it to the generic plot(),
Agreed.
but it's way too late to go modifying that particular generic.
I agree. Adding an "add=FALSE" parameter to plot() would generate errors for methods that don't implement it, so they would all have to be changed simultaneously, including in private/unreleased code. So I'd like to settle for second best: adding add=FALSE parameters to many plot methods. Cheers, Andrew
Yes. The ability to plot things on top of each other is important. The simplicity created by having a single interface for adding to plots outweighs the complexity of yet another parameter. The add parameter only interacts with other parameters superficially -- some parameters of "plot" (like log) are related to the shape of the axes, and should be inherited from what is on the plot already.
But what about when the new data is outside the range of the current plot? Wouldn't you expect the axis ranges to expand automatically? Instead of trying to shoehorn plot modification on top of base graphics, you could try using ggplot2 (http://had.co.nz/ggplot2) which has been built from the ground up to facilitate this kind of manipulation. Hadley
On Sun, Mar 9, 2008 at 6:27 PM, hadley wickham <h.wickham at gmail.com> wrote:
Yes. The ability to plot things on top of each other is important. The simplicity created by having a single interface for adding to plots outweighs the complexity of yet another parameter. The add parameter only interacts with other parameters superficially -- some parameters of "plot" (like log) are related to the shape of the axes, and should be inherited from what is on the plot already.
But what about when the new data is outside the range of the current plot?
plot/lines/points already works that way so this is just an interface issue.
> But what about when the new data is outside the range of the current > plot?
plot/lines/points already works that way so this is just an interface issue.
That may be the way it is, but I don't see how you could argue that it's desirable behaviour. Hadley
Its not a matter of desirable or not -- its a matter that its a different point. The par(new= ) to get an old graph is completely confusing and its annoying that one has to suddenly switch to lines and points and cannot consistently use plot. That remains true whether or not there is auto expansion.
On Sun, Mar 9, 2008 at 7:51 PM, hadley wickham <h.wickham at gmail.com> wrote:
> But what about when the new data is outside the range of the current > plot?
plot/lines/points already works that way so this is just an interface issue.
That may be the way it is, but I don't see how you could argue that it's desirable behaviour. Hadley -- http://had.co.nz/
On 3/9/2008 5:58 PM, Andrew Clausen wrote:
On Sun, Mar 09, 2008 at 04:04:08PM -0400, Duncan Murdoch wrote:
Part of the reason I didn't like your patch is that it was incomplete: it didn't patch the plot.default.Rd file.
Fair enough -- I wasn't sure whether I was fixing a bug or not. ("..."
spreads the documentation around a bit.)
That function already has around 16 parameters; do we really want to add another one, that interacts with some of the ones that are there?
Yes. The ability to plot things on top of each other is important. The simplicity created by having a single interface for adding to plots outweighs the complexity of yet another parameter. The add parameter only interacts with other parameters superficially -- some parameters of "plot" (like log) are related to the shape of the axes, and should be inherited from what is on the plot already.
I'd say causing some parameters to be completely ignored without a warning is more than a superficial interaction. Really, add=TRUE is not a great design: it would be better to say "plot methods draw a new plot" (so they need args for all the decorations like axes, titles, etc.), and have other ways to add things to plots. Hadley was right on this, his ggplot2 has a better thought-out design than classic graphics. However, we have what we have.
What you really seem to want is to add it to the generic plot(),
Agreed.
but it's way too late to go modifying that particular generic.
I agree. Adding an "add=FALSE" parameter to plot() would generate errors for methods that don't implement it, so they would all have to be changed simultaneously, including in private/unreleased code. So I'd like to settle for second best: adding add=FALSE parameters to many plot methods.
I like that suggestion better than adding it here and there, one at a time. So, to advance the discussion: can you take a look at the plot methods that are in the base and recommended packages, and work out how many already have it, how many would be improved if it was added, and in how many cases it just wouldn't make sense? (You could also do this on all the CRAN and Bioconductor packages, but that would be about 100 times more work: about 50 times as many packages, and much less consistency in the programming and documentation standards. Maybe on a subset of popular ones, e.g. those that Rcmdr suggests?) Data like that could make a convincing argument that the effort of adding this to the base packages is worthwhile. (To get it added to non-base packages will require you to convince their maintainers that it's a good idea.) Another helpful part of the argument will be for you to volunteer to do the work of both code and documentation updates. Duncan Murdoch
5 days later
Hi Duncan,
On Mon, Mar 10, 2008 at 08:51:23AM -0400, Duncan Murdoch wrote:
The add parameter only interacts with other parameters superficially -- some parameters of "plot" (like log) are related to the shape of the axes, and should be inherited from what is on the plot already.
I'd say causing some parameters to be completely ignored without a warning is more than a superficial interaction.
Fair enough. I suppose you could inadvertantly put leave "add=TRUE" in some code, and wonder why axes aren't getting drawn.
Really, add=TRUE is not a great design: it would be better to say "plot methods draw a new plot" (so they need args for all the decorations like axes, titles, etc.), and have other ways to add things to plots.
I don't like the idea of having a separate way to add to plots. I like the look of this code: f <- function(x) x^2 g <- function(x) 1/x - 1 h <- function(x) x functions <- c(f, g, h) for (i in 1:length(functions)) plot(functions[[i]], add=i>1, col=i) Of course, I'd prefer something like plot.new() for (i in 1:length(functions)) plot(functions[[i]], add=TRUE, col=i) but that seems out of reach for compatibility reasons. How would you write this code in R today?
Hadley was right on this, his ggplot2 has a better thought-out design than classic graphics. However, we have what we have.
I'm sure ggplot2 is vastly better, although I couldn't find a quick intro. (Typing "ggplot2 examples" into Google didn't help me.) Since plot() isn't deprecated yet, it's worth making cheap useful improvements.
I agree. Adding an "add=FALSE" parameter to plot() would generate errors for methods that don't implement it, so they would all have to be changed simultaneously, including in private/unreleased code. So I'd like to settle for second best: adding add=FALSE parameters to many plot methods.
I like that suggestion better than adding it here and there, one at a time. So, to advance the discussion: can you take a look at the plot methods that are in the base and recommended packages, and work out how many already have it, how many would be improved if it was added, and in how many cases it just wouldn't make sense? (You could also do this on all the CRAN and Bioconductor packages, but that would be about 100 times more work: about 50 times as many packages, and much less consistency in the programming and documentation standards. Maybe on a subset of popular ones, e.g. those that Rcmdr suggests?)
I had a quick look at the base packages. (I did a crude search with find and grep on the R source tarball.) I attached the full list. There were 40 files containing plot methods. Of these, 9 already implemented add=TRUE explicitly and a further 9 inherited it from other plot methods that could or already do implement it. There were 2 methods for which it clearly makes no sense. For example, plot.lm makes no sense because it does several separate plots, one after the other. It looks reasonably straightforward to implement most of the remaining methods. I must confess I don't understand what all of these plots are doing from a statistics point of view, but I suppose this shouldn't matter. (Econometrics uses different language...)
Data like that could make a convincing argument that the effort of adding this to the base packages is worthwhile. (To get it added to non-base packages will require you to convince their maintainers that it's a good idea.) Another helpful part of the argument will be for you to volunteer to do the work of both code and documentation updates.
I'm not very excited about doing work outside of base. I can do the base code + documentation though. Any volunteers? Cheers, Andrew -------------- next part -------------- graphics/R/barplot.R already implemented graphics/R/spineplot.R graphics/R/boxplot.R already implemented graphics/R/mosaicplot.R graphics/R/sunflowerplot.R already implemented graphics/R/datetime.R graphics/R/coplot.R graphics/R/hist.R implemented for plot.histogram, but not hist graphics/R/plot.design.R graphics/R/matplot.R already implemented graphics/R/plot.R my patch :) graphics/R/fourfoldplot.R graphics/R/assocplot.R graphics/R/cdplot.R stats/R/ts.R has plot.type="multiple" stats/R/biplot.R stats/R/acf.R stats/R/ppr.R inherited stats/R/stl.R stats/R/plot.lm.R multiple plots -- no sense stats/R/qqplot.R inherited stats/R/stepfun.R already implemented stats/R/TukeyHSD.R stats/R/dendrogram.R stats/R/interaction.plot.R stats/R/lag.plot.R stats/R/monthplot.R already implemented stats/R/ecdf.R already implemented (inherited from stepfun) stats/R/spectrum.R already implemented stats/R/nls-profile.R stats/R/prcomp.R inherited stats/R/termplot.R multiple plots -- no sense stats/R/princomp-add.R stats/R/isoreg.R stats/R/hclust.R stats/R/kernel.R inherited stats/R/medpolish.R inherited stats/R/HoltWinters.R inherited stats/R/density.R inherited splines/R/splineClasses.R inherited
Andrew, Here's is a way how your example could be coded with the current implementation of plot. You can always start with an empty plot and then add lines or points (or both) using the corresponding functions.
x <- seq(-2, 2, 0.1) plot(x, x, type="n") mapply(function(f, i) lines(x, f(x), col=i), functions, 1:3)
The current approach saves specification of a couple of parameters that would otherwise had to be specified, since lines(...) would be equivalent to plot(..., type="l", add=TRUE), and I think that this adds to clarity. -Christos
-----Original Message----- From: r-devel-bounces at r-project.org [mailto:r-devel-bounces at r-project.org] On Behalf Of Andrew Clausen Sent: Sunday, March 16, 2008 12:05 AM To: Duncan Murdoch Cc: R-devel at r-project.org Subject: Re: [Rd] [patch] add=TRUE in plot.default() Hi Duncan, On Mon, Mar 10, 2008 at 08:51:23AM -0400, Duncan Murdoch wrote:
The add parameter only interacts with other parameters
superficially
-- some parameters of "plot" (like log) are related to the
shape of
the axes, and should be inherited from what is on the plot already.
I'd say causing some parameters to be completely ignored without a warning is more than a superficial interaction.
Fair enough. I suppose you could inadvertantly put leave "add=TRUE" in some code, and wonder why axes aren't getting drawn.
Really, add=TRUE is not a great design: it would be better to say "plot methods draw a new plot" (so they need args for all the decorations like axes, titles, etc.), and have other ways to add things to plots.
I don't like the idea of having a separate way to add to plots. I like the look of this code: f <- function(x) x^2 g <- function(x) 1/x - 1 h <- function(x) x functions <- c(f, g, h) for (i in 1:length(functions)) plot(functions[[i]], add=i>1, col=i) Of course, I'd prefer something like plot.new() for (i in 1:length(functions)) plot(functions[[i]], add=TRUE, col=i) but that seems out of reach for compatibility reasons. How would you write this code in R today?
Hadley was right on this, his ggplot2 has a better thought-out design than
classic graphics.
However, we have what we have.
I'm sure ggplot2 is vastly better, although I couldn't find a quick intro. (Typing "ggplot2 examples" into Google didn't help me.) Since plot() isn't deprecated yet, it's worth making cheap useful improvements.
I agree. Adding an "add=FALSE" parameter to plot() would generate errors for methods that don't implement it, so they would
all have to
be changed simultaneously, including in private/unreleased code. So I'd like to settle for second best: adding add=FALSE
parameters to
many plot methods.
I like that suggestion better than adding it here and
there, one at a
time. So, to advance the discussion: can you take a look
at the plot
methods that are in the base and recommended packages, and work out how many already have it, how many would be improved if it
was added,
and in how many cases it just wouldn't make sense? (You
could also do
this on all the CRAN and Bioconductor packages, but that would be about 100 times more work: about 50 times as many packages,
and much
less consistency in the programming and documentation standards. Maybe on a subset of popular ones, e.g. those that Rcmdr suggests?)
I had a quick look at the base packages. (I did a crude search with find and grep on the R source tarball.) I attached the full list. There were 40 files containing plot methods. Of these, 9 already implemented add=TRUE explicitly and a further 9 inherited it from other plot methods that could or already do implement it. There were 2 methods for which it clearly makes no sense. For example, plot.lm makes no sense because it does several separate plots, one after the other. It looks reasonably straightforward to implement most of the remaining methods. I must confess I don't understand what all of these plots are doing from a statistics point of view, but I suppose this shouldn't matter. (Econometrics uses different language...)
Data like that could make a convincing argument that the effort of adding this to the base packages is worthwhile. (To get it
added to
non-base packages will require you to convince their
maintainers that
it's a good idea.) Another helpful part of the argument
will be for
you to volunteer to do the work of both code and
documentation updates. I'm not very excited about doing work outside of base. I can do the base code + documentation though. Any volunteers? Cheers, Andrew