[R] offset labeling boxplots

Paul Murrell p.murrell at auckland.ac.nz
Wed Jun 12 03:25:45 CEST 2002


> often I plot boxplots with different number of boxes (up to 200 boxes).
> I'd like to give every box a readable label on the x-axis. Therefore, I
> decrease the fontsize of the names and plot them vertical.
> But if you zoom into the plot (pdf) you will find an offset between the
> tickmark and the label - the label is shifted to the right.
> If you vary the box.count in the following example (without changing
> the fontsize) you will find every time this right shifted labels.
> (Finaly, for large box.counts the label will be shifted to the next right
> label!)
> Question 1: How can I avoid the right shift of the x-axis label?
> Question 2: Is it possible to scale the fontsize depending of the box.count
>          (So that I can read every single label)?

The problem here is with mtext().  A simpler demonstration of the
problem is as follows ...

	abline(v=1:10, col="grey")
	axis(3, at=1:10, las=3)
	axis(3, pos=9, at=1:10, las=3, cex.axis=.5) 
	axis(3, pos=8, at=1:10, las=3, cex.axis=2) 

... basically mtext() is using a hardcoded adjustment to position the
text in some cases.  It looks ok for the default text size, but gets it
wrong if the text size is modified.  (I will submit a bug report about
this problem).

The temporary hack solution requires using text() instead of mtext() to
draw the axis labels.  Here's one way to do it ...

	# Make sure that the text() output is not clipped
	# Create the boxplot information
	b <- boxplot(list(rnorm(10), rnorm(10), rnorm(10), rnorm(10), 	
	                  rnorm(10), rnorm(10), rnorm(10),
rnorm(10), rnorm(10)),
	# Draw the boxplot 
	# We control the y-axis scale so that we have some hope of
	# positioning the text() output later
	bp <- bxp(b, ylim=c(-4, 4), axes=FALSE)
	# Draw the x-axis ticks
	axis(1, at=bp, labels=FALSE)
	# Draw the x-axis tick labels using trial-and-error to
	# get the value -4.7
	text(bp, -4.7, letters[1:10], srt=90, adj=c(1, .5), cex=.5)

.. The disadvantage is that it requires trial-and-error to position the
labels.  This is maybe not too much pain for a one-off boxplot, but may
get tiresome if many boxplots are to be produced.  

Another approach which is not dependent on the y-axis scale is a bit
more complicated, but for the brave of heart here goes ...

	# First split the page into two figure regions
	# The lower region is .5cm high for the axis we will draw
	# plus .5in high for the axis labels -- change this second
	# amount to allow for longer labels
	layout(matrix(c(1, 2), ncol=1),
	       heights=c(1, lcm(.5 + 2.54/2)))
	# Prepare to draw the main boxplot
	# We make the bottom margin 0 so that the bottom of 
	# the boxplot is flush with the top of the axis we will draw
	# We make the left and right margins something that we can
	# reproduce when we come to drawing the axis
	par(mai=c(0, 1, 1, .5))
	# Create the boxplot information
	b <- boxplot(list(rnorm(10), rnorm(10), rnorm(10), rnorm(10), 	
	                  rnorm(10), rnorm(10), rnorm(10),
	                  rnorm(10), rnorm(10)),
	# Draw the boxplot, but not any axes
	bp <- bxp(b, axes=FALSE)
	# Draw the default y axis
	# Save the axis scales -- we want the x-axis scale for later
	savedusr <- par("usr")
	# Prepare to draw the axis
	# We make the top margin 0 so that the top of the axis
	# will be flush with the bottom of the boxplot
	# We replicate the left and right margins from the boxplot
	# The bottom margin is .5in -- the amount of room we allowed
	# for in the layout 
	# We set xpd=NA so that the text drawn for the axis tick
	# labels will not get clipped
	par(mai=c(.5, 1, 0, .5), xpd=NA)
	# Start a new plot -- the text() function draws in the
	# "data region" of a plot, so we will draw the axis as a
	# complete plot
	# Set up the scales on the new plot
	# We replicate the x-axis scale from the boxplot
	# The choice of y-axis scale is arbitrary
	plot.window(savedusr[1:2], c(1, 10), xaxs="i", yaxs="i")
	# Draw the axis ticks -- note that this axis is drawn at
	# the very top of the new plot (pos=10)
	axis(1, at=bp, pos=10, labels=FALSE)
	# Draw the axis tick labels
	text(bp, 1, letters[1:10], srt=90, adj=c(1, .5), cex=.5)

... anyway, that's a couple of ideas :)

Hope there's something useful in there somewhere.

r-help mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html
Send "info", "help", or "[un]subscribe"
(in the "body", not the subject !)  To: r-help-request at stat.math.ethz.ch

More information about the R-help mailing list