Search code examples
rplotclip

How to plot image outside plot area with par(xpd=T)?


In R, I'm trying to plot an image outside the plot area (as a legend). However, it seems that par(xpd=T) or par(xpd=NA) just don't work.

Here's a minimum reproducible example from the error, producing the following graph.

par(mar=c(4,4,4,4),xpd=F)
plot(1:2,1:2)
x <- c(2,2.1)
y <- seq(1.1,1.9,len=10)
m <- matrix(seq(0,1,len=10),ncol=10,nrow=2,byrow=T)
par(xpd=T)
image(x-.2,y,m,add=T)
image(x+.05,y,m,add=T)
par(xpd=NA)
image(x-.2,y,m,add=T)
image(x+.05,y,m,add=T)

R plot image bug

Both colored bars should have the same width, but of course the right-hand bar is being clipped, different from what the help from par says:

xpd

A logical value or NA. If FALSE, all plotting is clipped to the plot region, if TRUE, all plotting is clipped to the figure region, and if NA, all plotting is clipped to the device region. See also clip.

Is this a bug, or am I doing anything wrong?

I'm using R version 3.3.3 (2017-03-06) -- "Another Canoe", Platform: x86_64-pc-linux-gnu (64-bit), with RStudio Version 1.1.447, in Debian Stretch.


Solution

  • Frankly speaking, I have no direct answer to your question. I'm pretty sure it's related to image(), because xpd = TRUE works fine for other functions like text().

    Here are two more or less hacky solutions that worked for me with your MWE and hopefully help with your actual plot:

    x <- c(2, 2.1)
    y <- seq(1.1, 1.9, len = 10)
    m <- matrix(seq(0, 1, len = 10),
                ncol = 10, nrow = 2, byrow = TRUE)
    
    # Solution 1: useRaster = TRUE
    par(mar = c(4, 4, 4, 4), xpd = TRUE)
    plot(1:2, 1:2)
    image(x + .05, y, m, add = TRUE, useRaster = TRUE)
    # text(x + .05, y, "foo")
    
    # Solution 2: grid.clip() plus image() twice
    par(mar = c(4, 4, 4, 4), xpd = TRUE)
    plot(1:2, 1:2)
    image(x + .05, y, m, add = TRUE)
    grid::grid.clip()
    image(x + .05, y, m, add = TRUE)