![](/img/trans.png)
[英]ggplot - how to adjust spacing between legend items and edit legend symbols
[英]Adjust spacing between text in horizontal legend
我有一个带有水平图例的情节:
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
可以让您控制图例中每一列的宽度,但这并不简单。 基本上, text.width
是一个向量,它将乘以另一个与图例字符串向量一样长的向量。 第二个向量的元素是从0
到length(legend)-1
整数。 有关血腥的详细信息,请参阅legend()
的代码。 重要的是,您可以将text.width
和第二个向量的text.width
视为图例元素的近似 x 坐标。 然后如果你知道你想要哪个 x 坐标,你可以计算需要在text.width
参数中传递的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)
正如安德烈席尔瓦所提到的,您需要在xcoords
和textwidths
的值将取决于您的绘图的当前大小、为您的 x 轴指定的值范围等。
此外,如果每列有多个元素,上面的secondvector
看起来会有所不同。 例如,对于每列有两个图例元素的两列, secondvector == c(0,0,1,1)
。
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”和“信息技术”之间的距离,对于第三个和第四个参数,依此类推。
不幸的是,每次更改绘图大小时,我都需要重置text.width
的值。
在我的系统(平台:x86_64-w64-mingw32,R 版本:3.4.1 (2017-06-30))上,Andre Silva 和 pangja 迄今为止提供的解决方案并不令人满意。 这两种解决方案都需要用户输入并取决于设备尺寸。 由于我从不习惯text.width
命令并且总是不得不通过尝试和错误来调整值,因此我编写了函数 ( f.horlegend
)。 该函数具有与函数legend
类似的参数,并且基于此处发布的想法。
该函数创建一个水平(一行)图例,可以通过函数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( “BOTTOMLEFT”, “底”, “bottomright”, “左”, “中心”, “右”, “左上”, “顶”, “topright”))
legend
图例文本
xoff
调整 x 方向的位置。 注意:图例绘制在一个图上,limits = c(0,1)
yoff
与yoff
相同,但在 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
相对值增加文本和水平bbx.adj
之间的空间
bby.adj
与bby.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)
就我而言,水平方式有 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
函数发挥了神奇的作用
如果有人在 7 年后遇到同样的问题,我发现有帮助的一种技术是设置 text.width 并调用每个图例文本的字符串宽度 (strwidth)。 这会产生(在我看来)看起来“自然”的间距,并且可以通过向 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 的建议,但比按数字手动定义文本宽度参数更用户友好。
基于 pangia 的解决方案和
strwidth<\/code>的帮助,可以从图例文本中计算 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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.