[R] Placement of legend in base plot()

Helmut Schütz he|mut@@chuetz @end|ng |rom beb@c@@t
Tue May 31 15:07:08 CEST 2022


Dear all,

I try to figure out where to automatically place the legend in a scatter 
plot.
If there is large variability, points may cover the legend. Hence, I 
assess in which section the fewest points are.
Example:

set.seed(27) # for reproducibility
n      <- 25
slope  <- +1
sd     <- 10
x      <- 1:n
mean.x <- mean(x)
y      <- slope * x + rnorm(n = n, mean = mean.x, sd = sd)
mean.y <- mean(y)
top    <- which(y >= mean.y)
bottom <- which(y < mean.y)
left   <- which(x <= mean.x)
right  <- which(x > mean.x)
n.pts  <- data.frame("topleft"     = sum(top %in% left),
                      "topright"    = sum(top %in% right),
                      "bottomleft"  = sum(bottom %in% left),
                      "bottomright" = sum(bottom %in% right))
loc    <- names(n.pts)[n.pts == min(n.pts)]
if (length(loc) > 1) loc <- loc[1] # arbitrary selection (better 
approaches?)
bg     <- "transparent"
lgd    <- paste("Pretty long legend line number #", 1:3)
plot(x, y, type ="n", pch = 19, xlab = "", ylab = "", axes = FALSE, 
frame.plot = TRUE)
abline(h = mean.y, v = mean.x)
mtext(text = paste0("top left: n = ", n.pts[1], ", right: n = ", n.pts[2]),
       side = 3, line = 1)
mtext(text = paste0("bottom left: n = ", n.pts[3], ", right: n = ", 
n.pts[4]),
       side = 1, line = 1)
mtext(text = paste0("bottom: n = ", sum(n.pts[3:4]),
                     ", top = ", sum(n.pts[1:2])), side = 2, line = 1)
points(x, y, pch = 19, col = "red", cex = 1.25)
print(n.pts); loc
if (loc == "topleft")     legend("topleft", legend = lgd, x.intersp = 0,
                                  title = paste("n =", n.pts[1]), bg = bg)
if (loc == "topright")    legend("topright", legend = lgd, x.intersp = 0,
                                  title = paste("n =", n.pts[2]), bg = bg)
if (loc == "bottomleft")  legend("bottomleft", legend = lgd, x.intersp = 0,
                                  title = paste("n =", n.pts[3]), bg = bg)
if (loc == "bottomright") legend("bottomright", legend = lgd, x.intersp = 0,
                                  title = paste("n =", n.pts[4]), bg = bg)

Unfortunately, one of the keywords in legend() instead of x, y cannot be 
a variable.
Hence, legend(loc, ...) throws an error...
Error in match.arg(x, c("bottomright", "bottom", "bottomleft", "left",  :
'arg' must be of length 1
... and I had to resort to conditionally specify all 4.
Given.

Problems:
1. If there are the same number of points in sections, I select the 
first though another might lead to fewer overlapping points. Is there a 
better approach?
2. I know how to get the width/height of the legend box with (..., plot 
= FALSE) but couldn't figure out how to squeeze it between points where 
enough space might exist.

Best,
Helmut
-- 
Ing. Helmut Schütz
BEBAC – Consultancy Services for
Bioequivalence and Bioavailability Studies
Neubaugasse 36/11
1070 Vienna, Austria
E helmut.schuetz using bebac.at <mailto:helmut.schuetz using bebac.at>
W https://bebac.at <https://bebac.at/>
F https://forum.bebac.at <https://forum.bebac.at/>



More information about the R-help mailing list