From marc_schwartz at comcast.net  Mon Oct 15 21:05:18 2007
From: marc_schwartz at comcast.net (marc_schwartz at comcast.net)
Date: Mon, 15 Oct 2007 21:05:18 +0200 (CEST)
Subject: [Rd] boxplot() confuses x- and y-axes (PR#10345)
Message-ID: <20071015190518.1DF4B283416A@mail.pubhealth.ku.dk>


--=-ZyOtZFb05MaZLi4/Ovwu
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

On Mon, 2007-10-15 at 18:25 +0200, maechler at stat.math.ethz.ch wrote: 
> >>>>> "JO" == Jari Oksanen <jarioksa at sun3.oulu.fi>
> >>>>>     on Mon, 15 Oct 2007 16:42:24 +0300 writes:
> 
>     JO> On Mon, 2007-10-15 at 15:25 +0200, maechler at stat.math.ethz.ch wrote:
>     >> >>>>> "ms" == marc schwartz <marc_schwartz at comcast.net>
>     >> >>>>>     on Mon, 15 Oct 2007 14:20:16 +0200 (CEST) writes:
>     >> 
>     ms> On Mon, 2007-10-15 at 10:30 +0200, bob.ohara at helsinki.fi wrote:
>     >> >> Full_Name: Bob O'Hara
>     >> >> Version: 2.6.0
>     >> >> OS: Windows XP
>     >> >> Submission from: (NULL) (88.112.20.250)
>     >> >> 
>     >> >> 
>     >> >> Using horizontal=TRUE with boxplot() confuses it as to what is an x- or y-axis. 
>     >> >> At least, xlim= and ylim= are the wrong way round, log="x" (or "y") and xaxt=
>     >> >> work as expected, I haven't looked at anything else.
>     >> >> 
>     >> >> Some code to see if you can reproduce the bug (or discover it's in my head...):
>     >> >> 
>     >> >> boxplot(count ~ spray, data = InsectSprays)
>     >> >> 
>     >> >> # Try to change x-axis:
>     >> >> boxplot(count ~ spray, data = InsectSprays, xlim=c(0,50))
>     >> >> 
>     >> >> # Plot horizontally:
>     >> >> boxplot(count ~ spray, data = InsectSprays, horizontal=TRUE)
>     >> >> 
>     >> >> # Now try to change x-axis:
>     >> >> boxplot(count ~ spray, data = InsectSprays, horizontal=TRUE, xlim=c(0,50))
>     >> >> # Changes y-axis!
>     >> >> 
>     >> >> # Now try to change y-axis:
>     >> >> boxplot(count ~ spray, data = InsectSprays, horizontal=TRUE, ylim=c(0,50))
>     >> >> # Changes x-axis!
>     >> >> 
>     >> >> # Plot x-axis on log scale:
>     >> >> boxplot(count+1 ~ spray, data = InsectSprays, horizontal=TRUE, log="x")
>     >> >> # Does indeed change x-axis
>     >> >> 
>     >> >> # Don't add ticks on x-axis:
>     >> >> boxplot(count ~ spray, data = InsectSprays, horizontal=TRUE, xaxt="n")
>     >> >> # Works as expected.
>     >> 
>     ms> Hi Bob,
>     >> 
>     ms> No, it's not in your head. This is documented in ?bxp, which is the
>     ms> function that actually does the plotting for boxplot(). See the
>     ms> description of 'pars' in ?bxp:
>     >> 
>     ms> "Currently, yaxs and ylim are used ???????????????along the boxplot????????????????, i.e.,
>     ms> vertically, when horizontal is false, and xlim horizontally."
>     >> 
>     ms> So essentially, the named 'x' and 'y' axes are rotated 90 degrees when
>     ms> you use 'horizontal = TRUE', rather than the vertical axis always being
>     ms> 'y' and the horizontal axis always being 'x'. This has been discussed on
>     ms> the lists previously.
>     >> 
>     >> Yes; thank you, Marc.
>     >> 
>     >> And the reason for this is very sensible I think:
>     >> 
>     >> If you have a longish  boxplot()  or  bxp() command,
>     >> and you just want to go from vertical to horizontal or vice
>     >> versa, it makes most sense just to have to change the
>     >> 'horizontal' flag and not having to see if there are other 'x*'
>     >> and or 'y*' arguments that all need to be changed as well.
>     >> 
>     JO> Except that you must change xaxt/yaxt and log="x"/log="y" which do not
>     JO> follow the "along the box" logic, and behave differently than
>     JO> xlim/ylim. 
> 
>     JO> Nothing of this is fatal, but this probably needs more than one
>     JO> iteration to find which way each of the x* and y* arguments works.
> 
> Oops!!    Thank you Jari, for the note.
> 
> What you describe is then very unfortunate, and I hadn't been
> aware of that.
> 
> ``of course'', making any change to consistency
> would break existing code that consciously works with the
> current mis-"designed" behavior.  
> 
> But now I understand why we have the word  "currently" 
> in the description mentioned above.
> 
> So given the help file, we should consider dropping the whole
> ``along the boxplot'' idea?
> 
> {{well, yes, we should drop "traditional graphics" and work with
>   grid-based graphical objects ("grob"s) that can be drawn
>   vertically or horizontally,
>   e.g., in lattice or (most probably) ggplot2
> }}
> 
> Martin

The key code in question, from boxplot.R, seems to be:

    if (!add) {
	plot.new()
	## shall we switch log for horizontal with
	## switch(log, x="y", y="x", log) ??
	if (horizontal)
	    plot.window(ylim = xlim, xlim = ylim, log = log, xaxs = pars$yaxs)
	else
	    plot.window(xlim = xlim, ylim = ylim, log = log, yaxs = pars$yaxs)
    }
    xlog <- (par("ylog") && horizontal) || (par("xlog") && !horizontal)


So it would appear that ylim/xlim and xaxs/yaxs are interchanged when
horizontal = TRUE.  All? other axis specific pars remain as per normal.

I have attached a proposed patch against bxp.Rd (against the current svn
copy) for consideration. Hopefully this makes ?bxp a bit more clear.

If any changes are to be made to current behavior, it would be good to
do this incrementally, with a note/warning added to 2.7.1 and then
changed in 2.8.0.  If that is too soon, then increment by one version.

Thanks all,

Marc


--=-ZyOtZFb05MaZLi4/Ovwu
Content-Disposition: attachment; filename=diff.patch
Content-Type: text/x-patch; name=diff.patch; charset=ISO-8859-15
Content-Transfer-Encoding: 7bit

--- bxp.Rd	2007-10-15 13:27:21.000000000 -0500
+++ bxp.Rd.patch	2007-10-15 13:55:42.000000000 -0500
@@ -43,8 +43,8 @@
   \item{frame.plot}{logical, indicating if a \sQuote{frame}
     (\code{\link{box}}) should be drawn; defaults to \code{TRUE}, unless
     \code{axes = FALSE} is specified.}
-  \item{horizontal}{logical indicating if the  boxplots should be
-    horizontal; default \code{FALSE} means vertical boxes.}
+  \item{horizontal}{logical indicating if the boxplots should be
+    horizontal; default \code{FALSE} means vertical boxes. See note.}
   \item{add}{logical, if true \emph{add} boxplot to current plot.}
   \item{at}{numeric vector giving the locations where the boxplots
     should be drawn, particularly when \code{add = TRUE}; defaults to
@@ -56,9 +56,6 @@
     normally(\code{\dots}), see the following.  (Those in \code{\dots}
     take precedence over those in \code{pars}.)
 
-    Currently, \code{yaxs} and \code{ylim} are used \sQuote{along the
-      boxplot}, i.e., vertically, when \code{horizontal} is
-    false, and \code{xlim} horizontally.
     \code{xaxt}, \code{yaxt}, \code{las}, \code{cex.axis}, and
     \code{col.axis} are passed to \code{\link{axis}}, and \code{main},
     \code{cex.main}, \code{col.main}, \code{sub}, \code{cex.sub},
@@ -101,10 +98,15 @@
   }%.../pars
 }
 \note{
-  if \code{add = FALSE}, the default is \code{xlim = c(0.5, n +0.5)}.
+  If \code{add = FALSE}, the default is \code{xlim = c(0.5, n +0.5)}.
   It will usually be a good idea to specify the latter if the "x" axis
   has a log scale or \code{at} is specified or \code{width} is far from
   uniform.
+
+  If \code{horizontal = TRUE}, the "y" axis is the horizontal axis and the "x"
+  axis is the vertical axis. Graphical pars \code{xlim/ylim} and 
+  \code{xaxs/yaxs} are reversed in this case. Other axis related pars treat
+  the vertical axis as "y" and the horizontal axis as "x".
 }
 \value{
   An invisible vector, actually identical to the \code{at} argument,

--=-ZyOtZFb05MaZLi4/Ovwu--



[Rd] boxplot() confuses x- and y-axes (PR#10345)
marc_schwartz at comcast.net