paleolimbot / ggspatial

Enhancing spatial visualization in ggplot2
https://paleolimbot.github.io/ggspatial
368 stars 35 forks source link

How to limit plot extent #62

Open lorenzwalthert opened 4 years ago

lorenzwalthert commented 4 years ago

Taking the README example, I tried to limit the extent of the map to exactly the boundary of the raster used (my non-simplified use case is a square raster area and I want it to match the map extend, otherwise I have some sort of frame around my plot):

I tried scale_y_continuous(expand = ggplot2::expand_scale()). Unfortunately, this did not work:

library(ggplot2)
library(ggspatial)
load_longlake_data()

ggplot() +
  # loads background map tiles from a tile source
  annotation_map_tile(zoomin = -1) +
  # raster layers train scales and get projected automatically
  layer_spatial(longlake_depth_raster, aes(colour = stat(band1))) +
  # make no data values transparent
  scale_fill_viridis_c(na.value = NA) +

  # layer_spatial trains the scales
  layer_spatial(longlake_depthdf, aes(fill = DEPTH_M)) + 
  scale_x_continuous(expand = ggplot2::expand_scale()) + 
  scale_y_continuous(expand = ggplot2::expand_scale())
#> Warning: Ignoring unknown aesthetics: colour
#> Zoom: 14
#> Fetching 6 missing tiles
#>   |                                                                              |                                                                      |   0%  |                                                                              |============                                                          |  17%  |                                                                              |=======================                                               |  33%  |                                                                              |===================================                                   |  50%  |                                                                              |===============================================                       |  67%  |                                                                              |==========================================================            |  83%  |                                                                              |======================================================================| 100%
#> ...complete!
#> Warning: Removed 9122 rows containing missing values (geom_raster).

Created on 2020-01-24 by the reprex package (v0.3.0)

I hope I don't miss the obvious.

Note that this is very similar to the initial problem described in #46, which lead to the implementation of shadow_spatial(). After giving it a second thought, I am not sure this implementation is as general as it could be. Because it's not only that you want to expand the limits of the map (as my initial idea was in #46), sometimes you want the opposite: limit them. I thin think shadow_spatial() does not support this (and the name would also not fit this functionality).

Reprex:

library(ggplot2)
library(ggspatial)
load_longlake_data()

ggplot() +
  shadow_spatial(sf::st_bbox(longlake_depthdf[1, ])) +
  layer_spatial(longlake_depthdf, aes(col = DEPTH_M))


ggplot() +
  shadow_spatial(sf::st_bbox(longlake_depthdf)) +
  layer_spatial(longlake_depthdf, aes(col = DEPTH_M))

Created on 2020-01-24 by the reprex package (v0.3.0)

The concept of a bounding box seems to me to be superior to the idea of shadowing in this context now... How would you approach this problem?

paleolimbot commented 4 years ago

True limiting requires a change in coord_sf(), which I think is coming in the next few months. In the meantime, I think you can use annotation_spatial() (in place of layer_sptial()) and shadow_spatial() to get the behaviour you're looking for!

lorenzwalthert commented 4 years ago

Indeed, thanks. For everyone after me:

library(ggplot2)
library(ggspatial)
load_longlake_data()

ggplot() +
  shadow_spatial(sf::st_bbox(longlake_depthdf[1, ])) +
  annotation_spatial(longlake_depthdf, aes(col = DEPTH_M)) # previously layer_spatial() here

Created on 2020-01-25 by the reprex package (v0.3.0)

I am a bit confused about when to use annotation_spatial(), layer_sptial() and shadow_spatial(). They are all documented in the same help file but the difference is not explained. Would a few words about the differences be helpful?

paleolimbot commented 4 years ago

That's a great idea... I'm going to release just after the new ggplot2 release and will def tackle this.

lorenzwalthert commented 4 years ago

Thanks. Leave closing this issue up to you, depending on whether you want to leave it open as a reminder for this documentation todo or not.

lorenzwalthert commented 4 years ago

Unfortunately, your proposed solution does not work for raster I believe. Taking the README example and changing layer_spatial() to annotation_spatial():

library(ggplot2)
library(ggspatial)
load_longlake_data()

ggplot() +
  # loads background map tiles from a tile source
  annotation_map_tile(zoomin = -1) +
  # raster layers train scales and get projected automatically
  # changed below from layer_spatial() to annotation_spatial()

  annotation_spatial(longlake_depth_raster, aes(colour = stat(band1))) +
  # make no data values transparent
  scale_fill_viridis_c(na.value = NA) +

  # layer_spatial trains the scales
  layer_spatial(longlake_depthdf, aes(fill = DEPTH_M))
#> Error in layer_spatial.Raster(data, mapping = mapping, interpolate = interpolate, : Non-RGBA rasters with is_annotation = TRUE is not implemented.

Created on 2020-01-28 by the reprex package (v0.3.0)

paleolimbot commented 4 years ago

Good call. I'm working on this for the next release anyway! Keeping this issue open as a reminder to do both!