[R] Placement of legend in base plot()

John Fox j|ox @end|ng |rom mcm@@ter@c@
Tue May 31 15:35:50 CEST 2022


Dear Helmut,

I'm not sure why you're seeing an error, but replacing the last several 
commands in your code with

	legend(loc, legend = lgd, x.intersp = 0, title = paste("n =", 
n.pts[1]), bg = bg)

works perfectly fine for me. I suspect that the example you posted 
differs in some respect from the code that produces the error.

I hope this helps,
  John

On 2022-05-31 9:07 a.m., Helmut Schütz wrote:
> 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
-- 
John Fox, Professor Emeritus
McMaster University
Hamilton, Ontario, Canada
web: https://socialsciences.mcmaster.ca/jfox/



More information about the R-help mailing list