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"
加载中,请稍侯......
精彩评论