在基本图形的绘图区域之外绘制图例?


185

如标题所述:使用基础图形时,如何在图例区域之外绘制图例?

我考虑过摆弄layout并生成一个仅包含图例的空白图,但是我对仅使用基础图形工具的一种方法感兴趣,例如,par(mar = )在图的右侧获得一些图例空间。


这里是一个例子:

plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o")
legend(1,-1,c("group A", "group B"), pch = c(1,2), lty = c(1,2))

产生:

替代文字

但是如前所述,我希望图例位于绘图区域之外(例如,在图形/绘图的右侧)。


...您还可以通过虚拟容器与标准容器相提并论,以方便,轻松地完成图例。这里有类似的问题。
hhh 2012年

2
@hhh链接不再起作用。您可以使用这种方法更新它或发布答案吗?
亨里克(Henrik)2012年

Answers:


111

也许您需要的是par(xpd=TRUE)使事物能够在绘图区域之外绘制。因此,如果使用主图进行绘制,则bty='L'图例的右侧将有一些空间。通常,这会被裁剪到绘图区域,但是这样做par(xpd=TRUE)并稍作调整,就可以得到一个尽可能远的图例:

 set.seed(1) # just to get the same random numbers
 par(xpd=FALSE) # this is usually the default

 plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2), bty='L')
 # this legend gets clipped:
 legend(2.8,0,c("group A", "group B"), pch = c(1,2), lty = c(1,2))

 # so turn off clipping:
 par(xpd=TRUE)
 legend(2.8,-1,c("group A", "group B"), pch = c(1,2), lty = c(1,2))

33
请注意,您可以将xpd直接传递给图例,因此您不必担心之后会重置参数。另请参见grconvertX&Y,以一种不依赖于所绘制数据限制的方式来指定图例的位置。
查尔斯

6
因为这个问题和答案仍然很受欢迎,par(xpd=NA)所以功能甚至更强大(例如,向更多地区绘制图)。
亨里克(Henrik)2015年

+1。我们应该提到,par在图例之前单独进行调用是有意义的。在我的情节中,我曾par(new=T)在其他几次场合中使用过,只是想xpd在同一调用中添加参数,这会带来麻烦。
马特·班纳特

146

没有人使用负提到的insetlegend。这是一个示例,其中图例位于图的右侧,并与顶部对齐(使用关键字"topright")。

# Random data to plot:
A <- data.frame(x=rnorm(100, 20, 2), y=rnorm(100, 20, 2))
B <- data.frame(x=rnorm(100, 21, 1), y=rnorm(100, 21, 1))

# Add extra space to right of plot area; change clipping to figure
par(mar=c(5.1, 4.1, 4.1, 8.1), xpd=TRUE)

# Plot both groups
plot(y ~ x, A, ylim=range(c(A$y, B$y)), xlim=range(c(A$x, B$x)), pch=1,
               main="Scatter plot of two groups")
points(y ~ x, B, pch=3)

# Add legend to top right, outside plot region
legend("topright", inset=c(-0.2,0), legend=c("A","B"), pch=c(1,3), title="Group")

的第一个值inset=c(-0.2,0)可能需要根据图例的宽度进行调整。

legend_right


14
@Henrik不,如果没有xpd = TRUE,它将无法正常工作。另请注意,最好将xpd = TRUE设置为legend()函数的参数。
斯特凡洛朗

1
有时xpd必须将其设置TRUE为负插图才能起作用。但有时不是。用命令args.legend=list(x="bottom", horiz=TRUE, inset=-0.2)barplot(...不seemd实际需要xpd=TRUE,但只有legend(x="bottom", horiz=TRUE, inset=-0.2)它似乎需要xpd=TRUE。有什么见解吗?我只是在通过辩论时感到困惑?
user3386170

28

除了已经提到的ondes(使用layoutpar(xpd=TRUE))外,另一种解决方案是在整个设备上用透明图覆盖您的图,然后在其中添加图例。

诀窍是在整个绘图区域上覆盖一个(空)图形,并在其中添加图例。我们可以使用该par(fig=...)选项。首先,我们指示R在整个绘图设备上创建一个新绘图:

par(fig=c(0, 1, 0, 1), oma=c(0, 0, 0, 0), mar=c(0, 0, 0, 0), new=TRUE)

需要设置omamar,因为我们想让绘图的内部覆盖整个设备。new=TRUE防止R启动新设备是必需的。然后我们可以添加空图:

plot(0, 0, type='n', bty='n', xaxt='n', yaxt='n')

现在我们准备添加图例:

legend("bottomright", ...)

将在设备的右下角添加图例。同样,我们可以将图例添加到顶部或右边距。我们唯一需要确保的是原始地块的边距足够大,可以容纳图例。

把所有这些都放到一个函数中;

add_legend <- function(...) {
  opar <- par(fig=c(0, 1, 0, 1), oma=c(0, 0, 0, 0), 
    mar=c(0, 0, 0, 0), new=TRUE)
  on.exit(par(opar))
  plot(0, 0, type='n', bty='n', xaxt='n', yaxt='n')
  legend(...)
}

还有一个例子。首先创建图,确保底部有足够的空间来添加图例:

par(mar = c(5, 4, 1.4, 0.2))
plot(rnorm(50), rnorm(50), col=c("steelblue", "indianred"), pch=20)

然后添加图例

add_legend("topright", legend=c("Foo", "Bar"), pch=20, 
   col=c("steelblue", "indianred"),
   horiz=TRUE, bty='n', cex=0.8)

导致:

示例图的上边显示图例


2
这里的清单很棒。在此处的图形中,有一个关于如何使它与多个图一起使用的解释。
shiri

Jan,有没有办法增加图例中的字体大小,而不会剪切某些文本?例如,我有一个图形4种不同类型的标签,但是它们之间有很多空白。
一位老人在海里。


16

对不起,我要复活旧线程,但是今天我遇到了同样的问题。我发现的最简单的方法如下:

# Expand right side of clipping rect to make room for the legend
par(xpd=T, mar=par()$mar+c(0,0,0,6))

# Plot graph normally
plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o")

# Plot legend where you want
legend(3.2,1,c("group A", "group B"), pch = c(1,2), lty = c(1,2))

# Restore default clipping rect
par(mar=c(5, 4, 4, 2) + 0.1)

在这里找到:http : //www.harding.edu/fmccown/R/


4
甚至更好的是oldpar <-par(xpd = T,mar = par()$ mar + c(0,0,0,6))... par(oldpar)(请参阅par的帮助)
rakensi

此解决方案更好,因为无论图例字符串的长度如何,图例的空间都是固定的
Sergio

15

我喜欢这样:

par(oma=c(0, 0, 0, 5))
plot(1:3, rnorm(3), pch=1, lty=1, type="o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch=2, lty=2, type="o")
legend(par('usr')[2], par('usr')[4], bty='n', xpd=NA,
       c("group A", "group B"), pch=c(1, 2), lty=c(1,2))

在此处输入图片说明

唯一需要进行的调整就是将正确的边距设置得足够宽以容纳图例。

但是,这也可以自动化:

dev.off() # to reset the graphics pars to defaults
par(mar=c(par('mar')[1:3], 0)) # optional, removes extraneous right inner margin space
plot.new()
l <- legend(0, 0, bty='n', c("group A", "group B"), 
            plot=FALSE, pch=c(1, 2), lty=c(1, 2))
# calculate right margin width in ndc
w <- grconvertX(l$rect$w, to='ndc') - grconvertX(0, to='ndc')
par(omd=c(0, 1-w, 0, 1))
plot(1:3, rnorm(3), pch=1, lty=1, type="o", ylim=c(-2, 2))
lines(1:3, rnorm(3), pch=2, lty=2, type="o")
legend(par('usr')[2], par('usr')[4], bty='n', xpd=NA,
       c("group A", "group B"), pch=c(1, 2), lty=c(1, 2))

在此处输入图片说明


使用xpd = T或xpd = NA并不能防止我的“ main”(标题)被拉伸以尝试使用带有右宽边距的区域时被裁剪。
Phil Goetz

@PhilGoetz您确定要在绘图区域内绘制主图吗?您可能没有足够的边距线来绘图吗?
jbaums

10

最近,我发现了一个非常简单有趣的功能,可以在想要的绘图区域之外打印图例。

在图的右侧绘制外边缘。

par(xpd=T, mar=par()$mar+c(0,0,0,5))

创建一个情节

plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o")

添加图例,只需使用locator(1)函数,如下所示。然后,您只需在加载以下脚本后单击所需的位置即可。

legend(locator(1),c("group A", "group B"), pch = c(1,2), lty = c(1,2))

试试吧


9

我只能提供已经指出的布局解决方案的示例。

layout(matrix(c(1,2), nrow = 1), widths = c(0.7, 0.3))
par(mar = c(5, 4, 4, 2) + 0.1)
plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o")
par(mar = c(5, 0, 4, 2) + 0.1)
plot(1:3, rnorm(3), pch = 1, lty = 1, ylim=c(-2,2), type = "n", axes = FALSE, ann = FALSE)
legend(1, 1, c("group A", "group B"), pch = c(1,2), lty = c(1,2))

一张丑陋的照片:S


9

在我看来,添加另一个非常优雅的简单替代方案。

您的情节:

plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o")

传说:

legend("bottomright", c("group A", "group B"), pch=c(1,2), lty=c(1,2),
       inset=c(0,1), xpd=TRUE, horiz=TRUE, bty="n"
       )

结果:

带有图例的图片

在这里,图例的第二行仅添加到您的示例中。反过来:

  • inset=c(0,1)-在图例区域的(x,y)方向上移动图例。在这种情况下,图例"bottomright"就位。它在x方向上移动0个绘图区域(因此保持在“右侧”),并在y方向上移动1个绘图区域(从底部到顶部)。碰巧它出现在情节上方。
  • xpd=TRUE -让图例出现在绘图区域之外。
  • horiz=TRUE -指示制作水平图例。
  • bty="n" -摆脱图例边界框的样式细节。

将图例添加到侧面时同样适用:

par(mar=c(5,4,2,6))
plot(1:3, rnorm(3), pch = 1, lty = 1, type = "o", ylim=c(-2,2))
lines(1:3, rnorm(3), pch = 2, lty = 2, type="o")

legend("topleft", c("group A", "group B"), pch=c(1,2), lty=c(1,2),
       inset=c(1,0), xpd=TRUE, bty="n"
       )

在这里,我们只是调整了图例位置,并在图的右侧添加了额外的边距空间。结果:

图例2


4

您可以使用Plotly R API(使用代码)或通过将GUI拖动到所需的图例来执行此操作。

这是一个例子。图形和代码也在这里

x = c(0,1,2,3,4,5,6,7,8) 
y = c(0,3,6,4,5,2,3,5,4) 
x2 = c(0,1,2,3,4,5,6,7,8) 
y2 = c(0,4,7,8,3,6,3,3,4)

通过将x和y值之一分配给100或-100,可以将图例放置在图形之外。

legendstyle = list("x"=100, "y"=1)
layoutstyle = list(legend=legendstyle)

以下是其他选项:

  • list("x" = 100, "y" = 0) 用于外侧右下
  • list("x" = 100, "y"= 1) 右上外侧
  • list("x" = 100, "y" = .5) 右外中间
  • list("x" = 0, "y" = -100) 左下
  • list("x" = 0.5, "y" = -100) 在中心之下
  • list("x" = 1, "y" = -100) 右下方

然后回应。

response = p$plotly(x,y,x2,y2, kwargs=list(layout=layoutstyle));

拨打电话时,使用图形绘制一个URL。您可以通过调用来更快地访问它,browseURL(response$url)这样它将为您打开浏览器中的图形。

url = response$url
filename = response$filename

这给了我们这张图。您也可以从GUI内移动图例,然后图形将相应缩放。全面披露:我在Plotly团队中。

图例上的图例


2

尝试layout()通过简单地在下面创建一个空图,适当地缩放到1/4左右,然后手动将图例部分放置在其中,来解决我过去使用的方法。

这里有一些较旧的问题,legend()这些问题应该使您入门。


正如问题中已经说过的,这也是我的想法。但是,如果有其他方法,那将是理想的。我以某种方式认为没有。
亨里克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.