GeoEki
GeoEki

Reputation: 437

Line break in R plot legend

I create many plots in R with data input from another script that are held in a separate variable each. I put the variables in a string and force a line break with \n. This works as intended, but the legend is not justified at all. xjust and yjust seem to not do anything. Also, when placing the legend e.g. in bottomright, it stretches beyond the margin of the plot. Any idea how I can properly place my legend justified at the corner of a plot?

Here a reproducible code snippet:

plot(c(0,3), c(0,3), type="n", xlab="x", ylab="y")

a <- 2.3456
b <- 3.4567
c <- 4.5678
d <- 5.6789

Corner_text <- function(text, location = "bottomright"){
  legend(location, legend = text, bty = "o", pch = NA, cex = 0.5, xjust = 0) 
}
Corner_text(sprintf("a = %3.2f m\n b = %3.2f N/m\UB2\n c = %3.2f deg\n d = %3.2f perc", a, b, c, d))

Upvotes: 3

Views: 6364

Answers (2)

Axeman
Axeman

Reputation: 35307

An example on how to do this using ggplot2, where legend creation is automatic when you map a variable in aes:

library(ggplot2)
units <- c('m', 'N/m\UB2', 'deg', 'perc')
p <- ggplot() + geom_hline(aes(yintercept = 1:4, color = letters[1:4])) +   #simple example
  scale_color_discrete(name = 'legend title',
                       breaks = letters[1:4],
                       labels = paste(letters[1:4], '=', c(a, b, c, d), units))

enter image description here

Or inside the plot:

p + theme(legend.position = c(1, 0), legend.justification = c(1, 0))

enter image description here

Or closer to your easthetic:

p + guides(col = guide_legend(keywidth = 0, override.aes = list(alpha = 0))) +
  theme_bw() + 
  theme(legend.position = c(1, 0), legend.justification = c(1, 0),
        legend.background = element_rect(colour = 'black'))

enter image description here

Upvotes: 3

Cath
Cath

Reputation: 24074

legend is usually used to explain what the points or lines (and the different colors) represent. Therefore, inside the legend box (bty) there is a space where the lines/points are supposed to be. This probably explains why you think your text is not left-justified (you also have a problem of space after your line-break (\n): if you put a space after a line-break, it will be your first character on the next line, hence the text does not appear justified).

In your example, you don't have lines or points to explain, hence, I would use text rather than legend.
To know where "bottomright" is on your axes, you can use the graphical parameters par("xaxp") and par("yaxp") (it gives you the values of first and last ticks and the number of ticks on your axis). On the x-axis, from the last tick, you need to shift left to have space for the widest line.

In R code, it gives:

# your plot
plot(c(0,3), c(0,3), type="n", xlab="x", ylab="y")

# your string (without the extra spaces)
text_to_put <- sprintf("a = %3.2f m\nb = %3.2f N/m\UB2\nc = %3.2f deg\nd = %3.2f perc", a, b, c, d)

# the width of widest line
max_str <- max(strwidth(strsplit(text_to_put, "\n")[[1]]))

# put the text
text(x=par("xaxp")[2]-max_str, y=par("yaxp")[1], labels=text_to_put, adj=c(0, 0))

# if really you need the box (here par("usr") is used to know the extreme values on both axes)
x_offset <- par("xaxp")[1]-par("usr")[1]
y_offset <- par("yaxp")[1]-par("usr")[3]
segments(rep(par("xaxp")[2]-max_str-x_offset, 2), c(par("usr")[3], par("yaxp")[1]+strheight(text_to_put)+y_offset), c(par("xaxp")[2]-max_str-x_offset, par("usr")[2]), rep(par("yaxp")[1]+strheight(text_to_put)+y_offset, 2))

enter image description here

Upvotes: 3

Related Questions