Alex Brown
2005-Jul-04 10:19 UTC
[R] Rotate legends or other approaches to nice legend placement?
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
Marc Schwartz
2005-Jul-04 15:25 UTC
[R] Rotate legends or other approaches to nice legend placement?
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 BrownFor placing the legend outside the plot region, see this post from just a few days ago: https://stat.ethz.ch/pipermail/r-help/2005-July/073207.html 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) if(is.null(col)) 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. HTH, Marc Schwartz