R语言 调整水平图例中文本之间的间距

k3fezbri  于 2023-03-05  发布在  其他
关注(0)|答案(7)|浏览(240)

我有一个带有水平图例的图:

legend("bottomleft", inset = c(0, -0.3), bty = "n",
        x.intersp=0, xjust=0,yjust=0,
        legend=c("AAPL", "Information Technology",
                 "Technology Hardware and Equipment", "S&P 500"),
        col=c("black", "red", "blue3", "olivedrab3"),
        lwd=2, cex = 0.5, xpd = TRUE, ncol = 4)

问题是,图例的第一项"AAPL"和第二项"信息技术"之间存在巨大的间隔。
我试着用txt.width()来调整间距,但是根本不起作用。或者我没有按照指示使用这个选项。下面是我在legend()中引入txt.width选项的方法:

txt.width = c(2,1,1)

我不知道是否有必要提及,但我的x轴是一个日期轴!
有没有一种简单的方法可以自定义图例中文本之间的空格?
谢谢!

2jcobegt

2jcobegt1#

text.width可以给予您控制图例中每列的宽度,但这并不简单。text.width是一个向量,它将乘以另一个向量,该向量的长度与图例字符串向量的长度相同。第二个向量的元素是从0length(legend)-1的整数。有关详细信息,请参阅code to legend()。重要的是,您可以将text.width与第二个向量的乘积近似地看作图例元素的x坐标,然后,如果您知道需要哪个x坐标,就可以计算需要在text.width参数中传递什么。

legtext <- c("AAPL", "Information Technology", 
             "Technology Hardware and Equipment", "S&P 500")
xcoords <- c(0, 10, 30, 60)
secondvector <- (1:length(legtext))-1
textwidths <- xcoords/secondvector # this works for all but the first element
textwidths[1] <- 0 # so replace element 1 with a finite number (any will do)

然后你的最终代码可能看起来像这样(除了我们不知道你的原始绘图数据或参数):

plot(x=as.Date(c("1/1/13","3/1/13","5/1/13"), "%m/%d/%y"), y=1:3, ylim=c(0,3))

legend(x="bottomleft", bty = "n", x.intersp=0, xjust=0, yjust=0,
   legend=legtext, 
   col=c("black", "red", "blue3", "olivedrab3"), 
   lwd=2, cex = 0.5, xpd = TRUE, ncol = 4,
   text.width=textwidths)

正如Andre Silva所提到的,xcoordstextwidths中所需的值取决于绘图的当前大小、为x轴指定的值的范围等。
此外,如果每列有多个元素,则上面的secondvector看起来会有所不同。例如,对于各有两个图例元素的两列,secondvector == c(0,0,1,1)

tf7tbtn2

tf7tbtn22#

plot(1,1,xlab="",ylab="",xlim=c(0,2),ylim=c(0,2))

legend("bottomleft", text.width=c(0,0.085,0.235,0.35),
       inset = c(0, -0.2), bty = "n", x.intersp=0.5,
       xjust=0, yjust=0,
       legend=c("AAPL", "Information Technology",
                "Technology Hardware and Equipment", "S&P 500"),
       col=c("black", "red", "blue3", "olivedrab3"),
       lwd=3, cex = 0.75, xpd = TRUE, horiz=TRUE)

我使用text.width和四个参数来设置图例中字符串之间的间距,第二个参数在text.width中设置了“AAPL”和“Information technology”之间的距离,第三和第四个参数也是如此。
不幸的是,每次更改绘图大小时,我都需要重置text.width内部的值。

jobtbby3

jobtbby33#

在我的系统(平台:x86_64-w 64-明w32,R版本:3.4.1(2017-06-30))Andre Silva和pangja目前提供的解决方案并不令人满意,这两种解决方案都需要用户输入,并且依赖于设备大小,由于我从来不习惯text.width命令,总是要通过试错来调整值,我编写了函数(f.horlegend)。该函数与函数legend具有相似的参数,并且基于here发布的思想。
该函数创建一个水平(一行)图例,可通过函数legend中已知的命令(例如"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)

}

参数

pos图例的位置(c(“左下”、“下”、“右下”、“左”、“中”、“右”、“上”、“上”))
legend图例文本
xoff在x方向上的位置调整。注:图例绘制在极限= c(0,1)的图上
yoff与xoff相同,但在y方向
lty线型。线型只能指定为整数(0=空白,1=实线(默认值),2=虚线,3=点线,4=点划线,5=长划线,6=双划线)
lwd线宽,正数,默认为1
ln.col线条颜色
seg.len线的长度,默认为0.04
pch指定符号的整数。
pt.col符号颜色。
pt.bg符号的背景颜色。
pt.cex符号的扩展因子
pt.lwd符号的线宽
text.cex文本的扩展因子
text.col文本颜色
text.font文本字体
text.vfont参见文本帮助中的vfont
bty在图例周围绘制的框的类型。允许的值为“o”(默认值)和“n”
bbord图例框边框的颜色
bbg背景色
blty边框样式
blwd边框线宽度
bdens线密度,参见线段帮助
bbx.adj增加文本和水平框线之间间距的相对值
bby.adj与bbx.adj相同,但用于垂直boc线
很遗憾,我现在没有时间创建一个软件包。但是请随意使用这个功能。欢迎任何改进功能的意见和想法。

部分示例

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)
rmbxnbpk

rmbxnbpk4#

对于我的情况,有5个图例在水平的方式。我必须自定义每个图例之间的间距。以下是为此目的的代码片段。

legend("topright",horiz = T, legend = df2, fill = col_box,
       inset = c(-0.2,-0.1), xpd = TRUE, bty = 'n', density = density_value, angle = angle_value, x.intersp=0.3,
       text.width=c(3.5,3.4,3.7,4.3,7))

正是text.width函数发挥了神奇的作用

8tntrjer

8tntrjer5#

如果7年后有人遇到同样的问题,我发现一个有用的技巧是通过调用每段图例文本的字符串宽度(strwidth)来设置text.width。这会产生(在我看来)看起来“自然”的间距,并且可以通过向strwidth参数添加空格来修改。对于提出的问题,它看起来如下所示:

legend("bottomleft", inset = c(0, -0.3), bty = "n", x.intersp=0, xjust=0,yjust=0,
    legend=c("AAPL", "Information Technology",
             "Technology Hardware and Equipment", "S&P 500"),
    col=c("black", "red", "blue3", "olivedrab3"),
    lwd=2, cex = 0.5, xpd = TRUE, ncol = 4, text.width =
        c(strwidth("AAPL"), strwidth("Information Technology"), strwidth("Technology Hardware and Equipment"), strwidth("S&P 500"))
    )

这基本上就是Andre所建议的,但是比手动通过数字定义文本宽度参数更加用户友好。

kqqjbcuj

kqqjbcuj6#

基于pangia的解和strwidth的帮助,可以从图例文本计算x坐标:

### plot needs to be called first, so that strwidth can work
plot(x=as.Date(c("1/1/13","3/1/13","5/1/13"), "%m/%d/%y"), y=1:3, ylim=c(0,3))

legtext <- c("AAPL", "Information Technology", 
    "Technology Hardware and Equipment", "S&P 500")

### the following lines calculate the xcoords
### note that the cex argument in strwidth should be
### the same as in the legend call
xcoords <- c(0, cumsum( strwidth(legtext, cex = 0.5))[-length(legtext)])
secondvector <- (1:length(legtext))-1
textwidths <- xcoords/secondvector 
textwidths[1] <- 0 

legend(x="bottomleft", bty = "n", x.intersp=0.5, xjust=0, yjust=0,
    legend=legtext, 
    col=c("black", "red", "blue3", "olivedrab3"), 
    lwd=2, cex = 0.5, xpd = TRUE, ncol = 4,
    text.width=textwidths)
4ioopgfo

4ioopgfo7#

legend()中设置textwidth = NA将生成
strwidth的适当的列方向最大值(图例))。
(引用自R手册中的legend()。)

plot(1, 1, xlab = "", ylab = "", xlim = c(0, 2), ylim = c(0, 2))

legend(
  "bottomleft",
  text.width = NA,
  inset = c(0, -0.2), bty = "n", x.intersp = 0.5,
  xjust = 0, yjust = 0,
  legend = c(
    "AAPL", "Information Technology",
    "Technology Hardware and Equipment", "S&P 500"
  ),
  col = c("black", "red", "blue3", "olivedrab3"),
  lwd = 3, cex = 0.75, xpd = TRUE, horiz = TRUE
)

在处理类似情况时帮了我的忙。

相关问题