edzer / sp

Classes and methods for spatial data

Home Page:http://edzer.github.io/sp/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

setting par(mar) in plot.SpatialGridDataFrame necessary?

t-kalinowski opened this issue · comments

Hello,

I've been using the plot.SpatialGridDataFrame() function for the first time recently to make some custom layouts like this:

image
image

During my time working with the function, one of the annoyances was that it sets par(mar = c(1,1,1,1)) here and here

which makes doing custom layouts like the above cumbersome. I am wondering about the rationalle for setting par(mar), and to ask if it's really required here. So far, I've been working around the issue by setting up the plotting region first, then plotting the SpatialPixelsDataFrame with plot(...,add = T)

Two possible modifications would be nice.

  • add on.exit(par(oldpar), add = TRUE), right after setting par.
  • add a named argument mar to the plot.SpatialGridDataFrame function. The argument could accept either a length 4 numeric vector (defaulting to c(1,1,1,1), or a NULL value to not modify par).

I'd be happy to submit a pull request with these changes, but I wanted to start a discussion first as I'm not entirely sure behind the reasons for why the implementation is as it is currently, nor am I sure that these suggested edits are necessarily the best approach. The fact that both the color scale plotting code path and the main image plotting code path both set par(mar) complicates things, and makes me unsure about what the best solution is. However, having the plot function modify global settings (more than strictly necessary) seems like bad behavior.

Also, if you think that involved layouts like the above would better be done with either another class of object (raster?), I'd be interested in that feedback as well. I would rather not take another dependency if not needed however. The combination of sp + gstat + sf + ggplot + baseGrid + gridExtra seems Frankenstein enough.

Thank you very much

Great graphs. I haven't tried, but suspect your second approach will not work. I can see that the first one will, and is the more polite thing to do for power users. PR is welcome.

Thank you for the compliment!

I made the edit to the code locally, and noticed that it breaks the example under "Incrementally adding elements" in this blog post that introduces the addition of the plot method.

Adding

  oldpar <- par(no.readonly = TRUE)
  on.exit(par(oldpar), add = TRUE)

also resets any adjustments made by layout, thus breaking any code that depends on the existing graphics region being setup first by plot.SpatialGridDataFrame (like calls to points())

Seeing how this breaks existing code now makes me think that even adding a more limited

  oldmar <- par("mar")
  on.exit(par(mar = oldmar), add = TRUE)

might similarly break existing code somewhere that depends on the changes made by this plot method.

I'm no longer convinced there is an easy fix for this annoyance that doesn't break existing code. It seems like the primary goal for sp right now is to be stable, while all the exciting stuff is happening in sf. With that, I'm inclined to close this issue here.

(that said... the plot method in sf also frequently leaves the graphics device with residual (unwanted) par(mfrow) settings, perhaps sf is young enough that a on.exit(par(oldpar)) addition still makes sense?)

Completely agree; sf::plot is indeed still quite rough, but already has the on.exit, inspired by your ideas here. More good ideas very welcome!