[R] Rotate legends or other approaches to nice legend placement?

Marc Schwartz MSchwartz at mn.rr.com
Mon Jul 4 17:25:14 CEST 2005

On Mon, 2005-07-04 at 11:19 +0100, Alex Brown wrote:
> I'm sure this general sort of question has been asked many times before 
> - I would _like_ automatic and sensible legend placement in barplots so 
> data is not overwritten... but since there doesn't seem to be one, one 
> of the following would be useful:
> One approach for this would be to place the legend to the right of the 
> graph, and rotate it by 90 degrees.
> Is there a sensible way to do this?
> alternatively, is there a function to
> 1) estimate legend size
> 2) adjust nrows so that the full width of the drawing device is used, 
> minimising height
> 3) use layout() so that enough space is allocated beneath the graph for 
> the legend
> 4) draw legend
> 5) allow user to call plot, correctly drawing the plot in the remaining 
> frame?
> I have taken a look at this, but I am confused by the different units 
> used by par(mar), legend(plot=F), and layout.
> -Alex Brown

For placing the legend outside the plot region, see this post from just
a few days ago:


In terms of automating the process, that usually means making some
assumptions and then writing code to fit the assumptions, while
providing options to handle the cases that don't.

Briefly, one approach to automating legend placement within the plot
region might be something like this. Create a new function we'll call
barplotL() (not feeling overly creative this morning....). 

Basically, it figures out the maximum y value from the height argument
and multiplies that by 1.5 to provide extra room at the top of the plot
region for the legend. You can of course adjust this factor as required
(ie. less room is needed for a horizontal legend).

For the upper left hand corner (ULHC) of the legend, it takes the range
of the x and y axes and then places the UHLC at 5%/95% of the respective
ranges from the UHLC of the plot region. See ?par (specifically 'usr').

It provides options for coloring the legend boxes (in lieu of the
default grey) and for making the legend horizontal instead of vertical. 

You can add other options as well, but this should get you started.

BTW, this approach presumes that 'height' will be a matrix, since I am
not sure that a legend makes sense otherwise...

barplotL <- function(height, beside = FALSE, 
                     legend = NULL, col = NULL,
                     leg.horiz = FALSE)
  ylim <- ifelse(beside, 
                 max(height) * 1.5, 
                 max(colSums(height) * 1.5)) 

  barplot(height = height, ylim = c(0, ylim), 
          beside = beside, col = col)

  x.pos <- par("usr")[1] + ((par("usr")[2] - par("usr")[1]) * .05)
  y.pos <- par("usr")[4] - ((par("usr")[4] - par("usr")[3]) * .05)

    col <- grey.colors(nrow(height))

  if (is.null(legend))
    legend <- rownames(height) 

  legend(x.pos, y.pos, legend = legend, fill = col,
         horiz = leg.horiz)

So, let's try it:

barplotL(VADeaths, beside = FALSE)

barplotL(VADeaths, beside = FALSE, leg.horiz = TRUE)

barplotL(VADeaths, beside = TRUE, 
         col = c("red", "yellow", "orange"))

barplotL(VADeaths, beside = TRUE, leg.horiz = TRUE, 
         col = c("red", "yellow", "orange"))

You can also look at the smartlegend() function in the gplots package on
CRAN, but you still need to adjust the y axis ranges as above to make
room for the legend itself.


Marc Schwartz

More information about the R-help mailing list