Plot a legend outside of the plotting area in base graphics?

前端 未结 10 736
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-22 14:48

As the title says: How can I plot a legend outside the plotting area when using base graphics?

I thought about fiddling around with layout

相关标签:
10条回答
  • 2020-11-22 15:18

    I like to do it like this:

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

    The only tweaking required is in setting the right margin to be wide enough to accommodate the legend.

    However, this can also be automated:

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

    0 讨论(0)
  • 2020-11-22 15:20

    Recently I found very easy and interesting function to print legend outside of the plot area where you want.

    Make the outer margin at the right side of the plot.

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

    Create a plot

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

    Add legend and just use locator(1) function as like below. Then you have to just click where you want after load following script.

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

    Try it

    0 讨论(0)
  • 2020-11-22 15:25

    Maybe what you need is par(xpd=TRUE) to enable things to be drawn outside the plot region. So if you do the main plot with bty='L' you'll have some space on the right for a legend. Normally this would get clipped to the plot region, but do par(xpd=TRUE) and with a bit of adjustment you can get a legend as far right as it can go:

     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))
    
    0 讨论(0)
  • 2020-11-22 15:25

    Adding another simple alternative that is quite elegant in my opinion.

    Your plot:

    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:

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

    Result:

    Here only the second line of the legend was added to your example. In turn:

    • inset=c(0,1) - moves the legend by fraction of plot region in (x,y) directions. In this case the legend is at "bottomright" position. It is moved by 0 plotting regions in x direction (so stays at "right") and by 1 plotting region in y direction (from bottom to top). And it so happens that it appears right above the plot.
    • xpd=TRUE - let's the legend appear outside of plotting region.
    • horiz=TRUE - instructs to produce a horizontal legend.
    • bty="n" - a style detail to get rid of legend bounding box.

    Same applies when adding legend to the side:

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

    Here we simply adjusted legend positions and added additional margin space to the right side of the plot. Result:

    0 讨论(0)
  • 2020-11-22 15:28

    No one has mentioned using negative inset values for legend. Here is an example, where the legend is to the right of the plot, aligned to the top (using keyword "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")
    

    The first value of inset=c(-0.2,0) might need adjusting based on the width of the legend.

    legend_right

    0 讨论(0)
  • 2020-11-22 15:32

    I can offer only an example of the layout solution already pointed out.

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

    an ugly picture :S

    0 讨论(0)
提交回复
热议问题