[R] Ticks and labels on plots

Martin Maechler maechler at stat.math.ethz.ch
Thu Mar 22 10:03:52 CET 2007


>>>>> "Marc" == Marc Schwartz <marc_schwartz at comcast.net>
>>>>>     on Wed, 21 Mar 2007 14:23:12 -0500 writes:

    Marc> On Wed, 2007-03-21 at 14:40 -0400, Mike Prager wrote:
    >> Marc Schwartz <marc_schwartz at comcast.net> wrote:
    >> 
    >> > On Tue, 2007-03-20 at 18:04 -0400, Michael H. Prager wrote:
    >> > > I am generating stacked barplots of age-composition of fish populations 
    >> > > (Y) over time (X).  As there are many years, not every bars is labeled.  
    >> > > When looking at the plot, it becomes difficult to associate labels with 
    >> > > their bars.
    >> > > 
    >> > > We have improved this a bit by using axis() to add a tickmark below each 
    >> > > bar.  Can anyone suggest a way to draw ticks ONLY at bars where a tick 
    >> > > label is drawn?  Or to make such ticks longer than those where there is 
    >> > > no label?
    >> > > 
    >> > > This is going into a function, so I'm hoping for a method that doesn't 
    >> > > require looking at the plot first.
    >> > >
    >> > > # sample code (simplified) #
    >> > > mp <- barplot(t(N.age), xlab = "Year", axisnames = FALSE)
    >> > > axis(side = 1, at = mp, labels = rownames(N.age), tcl = -0.75)
    >> > > 
    >> > > Thanks!
    >> > > 
    >> > > Mike Prager
    >> > > NOAA, Beaufort, NC
    >> > 
    >> > Mike,
    >> > 
    >> > How about something like this:
    >> > 
    >> >   mp <- barplot(1:50, axisnames = FALSE)
    >> > 
    >> >   # Create short tick marks at each bar
    >> >   axis(1, at = mp, labels = rep("", 50), tcl = -0.25)
    >> > 
    >> >   # Create longer tick marks every 5 years with labels
    >> >   axis(1, at = mp[seq(1, 50, 5)], 
    >> >        labels = 1900 + seq(0, 45, 5), tcl = -0.75, las = 2, 
    >> >        cex.axis = 0.75)
    >> > 
    >> > 
    >> > Just pick which labels you want to be shown (eg. every 5 years) and
    >> > synchronize the values of those with the 'at' argument in axis().
    >> > 
    >> > HTH,
    >> > 
    >> > Marc Schwartz
    >> > 
    >> 
    >> Thanks, Marc, for this solution and thanks equally to Jim Lemon
    >> for a similar idea.  This seems promising.  Since this is to go
    >> into a function (and should work without intervention), I'll
    >> need to devise an algorithm to decide at what interval the
    >> labels should be plotted.  Clearly "axis()" has such an
    >> algorithm.  Unfortunately, it reports its result only by placing
    >> the labels.
    >> 
    >> Mike

    Marc> Mike,

    Marc> To get a feel for how axis() creates the default tick positions when
    Marc> 'at' is the default NULL, see ?axTicks, which provides functionality
    Marc> similar to the internal C routine.

yes, partly not only similar but "the same" when it works (by
default) with par("axp")

    Marc> You could also look at ?pretty

Yes.  *However* there's one important thing which I think hasn't
been mentioned yet.

We have now been talking how and where axis() {i.e. its internal
code} chooses to place tick marks.
The clue is that it draws labels at all tick marks by default or
explicitly with axis(*, at= ., labels = .)
BUT the labels are not shown on your plot as soon as they
would get too much crammed together.

You can see this nicely, interactively, by the following:
Use
     graphics.off()
     plot(1:11)

This will show ticks *and* labels  at  2 , 4 , 6 , 8, 10
and now use your mouse, drag to make the graphics window
narrower (e.g. keeping height constant), in small steps,
releasing the mouse again to let R redraw the graphic.
For quite a while, the labels remain until there's not enough
room, the 5 ticks remain, but only the
 labels  2 , 4, 6, 8  are drawn
 then    2 , 6 , 10 
 then    2 , 6
 then    2 , 8  ( a little surprise to me)
 then    2

you always see all ticks but labels are only drawn when they
don't get in each other's way.

Of course, things like

 plot(1:11, xaxt="n")
 axis(1, at=1:11, labels = paste("Lab", 1:11))

show even more when the window is widened or narrowed,
and yes, it depends on the device and on the fonts and its
sizes, see e.g.,

 plot(1:11, xaxt="n")
 axis(1, at=1:11, labels = paste("Lab", 1:11), cex.axis = 0.5)

----- -----

If you don't like this --- almost always very desirable ---
builtin smartness, you need to descend slightly lower level and use
mtext(), e.g., the analogue of the above is

  plot(1:11, xaxt="n")
  mtext(side=1, at=1:11, text = paste("Lab", 1:11), cex = 0.5)

or rather leave traditional graphics which really gets messy in
such cases {par() .. etc} and upgrade to using the "grid"
package,  or also packages built on grid, "lattice" or "ggplot".
But infact, someone else needs to tell you how to play similar
goes with these.

Martin Maechler, ETH Zurich



More information about the R-help mailing list