Adjust spacing between text in horizontal legend

前端 未结 4 1275
甜味超标
甜味超标 2020-12-24 08:46

I have a plot with a horizontal legend:

 legend(\"bottomleft\", inset = c(0, -0.3), bty = \"n\",
        x.intersp=0, xjust=0,yjust=0,
        legend=c(\"AAP         


        
4条回答
  •  爱一瞬间的悲伤
    2020-12-24 09:26

    On my system (platform: x86_64-w64-mingw32, R version: 3.4.1 (2017-06-30)) the solutions provided so far by Andre Silva and pangja are not satisfactory. Both solutions require user input and are dependent on the device size. Since I get never used to the text.width command and always had to adjust the values with try-and-error, I wrote the function (f.horlegend). The function has similar arguments as the function legend and is based on the idea posted here.

    The function creates a horizontal (one row) legend, which can be positioned by the commands known from the function legend, e.g. "bottomleft"

    f.horlegend <- function(pos, legend, xoff = 0, yoff = 0, 
      lty = 0, lwd = 1, ln.col = 1, seg.len = 0.04, 
      pch = NA, pt.col = 1, pt.bg = NA, pt.cex = par("cex"), pt.lwd = lwd, 
      text.cex = par("cex"), text.col = par("col"), text.font = NULL, text.vfont = NULL, 
      bty = "o", bbord = "black", bbg = par("bg"), blty = par("lty"), blwd = par("lwd"), bdens = NULL, bbx.adj = 0, bby.adj = 0.75 
    ) {
    
      ### get original par values and re-set them at end of function
      op <- par(no.readonly = TRUE)
      on.exit(par(op))
    
      ### new par with dimension [0,1]
      par(new=TRUE, xaxs="i", yaxs="i", xpd=TRUE)
      plot.new()
    
      ### spacing between legend elements
      d0 <- 0.01 * (1 + bbx.adj)
      d1 <- 0.01
      d2 <- 0.02
      pch.len <- 0.008
      ln.len <- seg.len/2
    
      n.lgd <- length(legend)
    
      txt.h <- strheight(legend[1], cex = text.cex, font = text.font, vfont = text.vfont) *(1 + bby.adj)
      i.pch <- seq(1, 2*n.lgd, 2)
      i.txt <- seq(2, 2*n.lgd, 2)
    
      ### determine x positions of legend elements
      X <- c(d0 + pch.len, pch.len + d1, rep(strwidth(legend[-n.lgd])+d2+pch.len, each=2))
      X[i.txt[-1]] <- pch.len+d1
    
      ### adjust symbol space if line is drawn
      if (any(lty != 0)) {
        lty <- rep(lty, n.lgd)[1:n.lgd]
        ln.sep <- rep(ln.len - pch.len, n.lgd)[lty]
        ln.sep[is.na(ln.sep)] <- 0
        X <- X + rep(ln.sep, each=2)
        lty[is.na(lty)] <- 0
      } 
    
      X <- cumsum(X)
    
      ### legend box coordinates
      bstart <- 0
      bend <- X[2*n.lgd]+strwidth(legend[n.lgd])+d0
    
      ### legend position
      if (pos == "top" | pos == "bottom" | pos == "center") x_corr <- 0.5 - bend/2 +xoff
      if (pos == "bottomright" | pos == "right" | pos == "topright") x_corr <- 1. - bend + xoff
      if (pos == "bottomleft" | pos == "left" | pos == "topleft") x_corr <- 0 + xoff
    
      if (pos == "bottomleft" | pos == "bottom" | pos == "bottomright") Y <- txt.h/2 + yoff
      if (pos == "left" | pos == "center" | pos =="right") Y <- 0.5 + yoff
      if (pos == "topleft" | pos == "top" | pos == "topright") Y <- 1  - txt.h/2 + yoff
    
      Y <- rep(Y, n.lgd)
      ### draw legend box
      if (bty != "n") rect(bstart+x_corr, Y-txt.h/2, x_corr+bend, Y+txt.h/2, border=bbord, col=bbg, lty=blty, lwd=blwd, density=bdens)
    
      ### draw legend symbols and text
      segments(X[i.pch]+x_corr-ln.len, Y, X[i.pch]+x_corr+ln.len, Y, col = ln.col, lty = lty, lwd = lwd)
      points(X[i.pch]+x_corr, Y, pch = pch, col = pt.col, bg = pt.bg, cex = pt.cex, lwd = pt.lwd)
      text(X[i.txt]+x_corr, Y, legend, pos=4, offset=0, cex = text.cex, col = text.col, font = text.font, vfont = text.vfont)
    
    }
    

    Arguments

    pos position of the legend (c("bottomleft", "bottom", "bottomright", "left", "center", "right", "topleft", "top", "topright"))

    legend legend text

    xoff adjustement of position in x-direction. NB: the legend is plotted on a plot with limits = c(0,1)

    yoff same as xoff but in y-directin

    lty The line type. Line types can only be specified as an integer (0=blank, 1=solid (default), 2=dashed, 3=dotted, 4=dotdash, 5=longdash, 6=twodash)

    lwd The line width, a positive number, defaulting to 1

    ln.col The line color

    seg.len The length of the line, deafult to 0.04

    pch An integer specifying the symbol.

    pt.col The symbol color.

    pt.bg The background color of the symbol.

    pt.cex expansion factor for the symbol

    pt.lwd line width of symbol

    text.cex expansion factor for the text

    text.col text color

    text.font text font

    text.vfont see vfont in text-help

    bty the type of box to be drawn around the legend. The allowed values are "o" (the default) and "n"

    bbord color of the legend box border

    bbg background color

    blty border style

    blwd border line width

    bdens density of lines, see segment-help

    bbx.adj relative value to increase space between text and horizontal box line

    bby.adj same as bbx.adj but for vertical boc line

    Unfortunately, I don't have time to create a package at the moment. But feel free to use the function. Any comments and ideas to improve the functions are welcome.

    Some examples

    plot(1:100, rnorm(100))
    lgd.text <- c("12", "12")
    sapply(c("bottomleft", "bottom", "bottomright", "left", "center", "right", "topleft", "top", "topright"), function(x) f.horlegend(x, lgd.text, pch=16, lty=c(NA, 1), bbg="orange"))
    
    
    plot(1:100, rnorm(100))
    lgd.text <- c("12", "132", "12345")
    f.horlegend("topleft", lgd.text, pch=NA)
    f.horlegend("top", lgd.text, pch=NA, bby.adj=1.5, bbord="red")
    f.horlegend("left", lgd.text, xoff=0.2, pch=1, bby.adj=0, bbord="red", bbg="lightgreen")
    f.horlegend("left", lgd.text, xoff=0.2, yoff=-0.05, pch=c(NA, 1, 6), lty=1, bbx.adj=2, bby.adj=0, bbord="red", bbg="lightgreen")
    
    f.horlegend("topright", lgd.text, yoff=0.1, pch=c(1,2,NA), lty=c(NA, NA, 2), bbord="red", blty=2, blwd=2)
    
    lgd.text <- c("12", "123456", "12345", "123")
    f.horlegend("bottom", lgd.text, yoff=0.1, pch=c(1,2,NA), lty=c(NA, 1, 2), text.font=2)
    f.horlegend("bottom", lgd.text, pch=c(1,2,NA), lty=c(NA, 1, 2), text.font=c(1,2,3))
    
    plot(seq(as.POSIXct("2017-08-30"), as.POSIXct("2017-09-30"), by="weeks"), rnorm(5), type="l")
    f.horlegend("topleft", "random values", lty=1)
    

提交回复
热议问题