开发者

Automatically determine position of plot legend

You can position the key legend manually in most plotting programs. For example, in gnuplot it's done using set key top right. In ggplot2, it's done like this.

Is there 开发者_Go百科a plotting library, script, or simple algorithm that automatically positions the legend such that it overlaps the data in the plot minimally?

What I mean is: Suppose I plot the line y=x. A good place for the legend in that case would be top left or bottom right.


Try this,

require(Hmisc)
?largest.empty

there are other discussions and functions proposed in R-help archives


require(plotrix)

?emptyspace     # Find the largest empty space on a plot

This is the example from the help page:

x<-rnorm(100)
 y<-rnorm(100)
 plot(x,y,main="Find the empty space",xlab="X",ylab="Y")
 es<-plotrix::emptyspace(x,y)
 # use a transparent background so that any overplotted points are shown
 plotrix::boxed.labels(es,labels="Here is the\nempty space",bg="transparent")


A quick trick to get one of "topleft", "topright", "bottomleft" and "bottomright":

auto.legend.pos <- function(x,y,xlim=range(x),ylim=range(y)) {
  countIt <- function(a,zero.only=TRUE) {
    tl <- sum(x <= xlim[1]*(1-a)+xlim[2]*a & y >= ylim[1]*a+ylim[2]*(1-a))
    tr <- sum(x >= xlim[1]*a+xlim[2]*(1-a) & y >= ylim[1]*a+ylim[2]*(1-a))
    bl <- sum(x <= xlim[1]*(1-a)+xlim[2]*a & y <= ylim[1]*(1-a)+ylim[2]*a)
    br <- sum(x >= xlim[1]*a+xlim[2]*(1-a) & y <= ylim[1]*(1-a)+ylim[2]*a)
    c(topleft=tl,topright=tr,bottomleft=bl,bottomright=br)
  }
  for (k in seq(0.5,0.1,by=-0.05)) {
    a <- countIt(k)
    if (sum(a==0)>0) break
  }
  names(a)[which(a==0)][1]
}

Test:

plot(Sepal.Length~Petal.Length, data=iris)
auto.legend.pos(iris$Petal.Length, iris$Sepal.Length)
# [1] "topleft"

EDIT

par("usr") after plot returns the extremes of the user coordinates of the plotting regions: see ?par. So we can change the function to:

auto.legend.pos <- function(x,y,xlim=NULL,ylim=NULL) {
  if (dev.cur() > 1) {
    p <- par('usr')
    if (is.null(xlim)) xlim <- p[1:2]
    if (is.null(ylim)) ylim <- p[3:4]
  } else {
    if (is.null(xlim)) xlim <- range(x, na.rm = TRUE)
    if (is.null(ylim)) ylim <- range(y, na.rm = TRUE)
  }
  countIt <- function(a) {
    tl <- sum(x <= xlim[1]*(1-a)+xlim[2]*a & y >= ylim[1]*a+ylim[2]*(1-a))
    tr <- sum(x >= xlim[1]*a+xlim[2]*(1-a) & y >= ylim[1]*a+ylim[2]*(1-a))
    bl <- sum(x <= xlim[1]*(1-a)+xlim[2]*a & y <= ylim[1]*(1-a)+ylim[2]*a)
    br <- sum(x >= xlim[1]*a+xlim[2]*(1-a) & y <= ylim[1]*(1-a)+ylim[2]*a)
    c(topleft=tl,topright=tr,bottomleft=bl,bottomright=br)
  }
  for (k in seq(0.5,0.1,by=-0.05)) {
    a <- countIt(k)
    if (sum(a==0)>0) break
  }
  names(a)[which(a==0)][1]   # may delete "[1]"
}

plot(Sepal.Length~Petal.Length, data=iris, xlim=c(1,5), ylim=c(3.5,6))
auto.legend.pos(iris$Petal.Length, iris$Sepal.Length)
# [1] "bottomright"
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜