Fons MA
Fons MA

Reputation: 1282

Insert geom_sf layer underneath existing geom_sf layers

I have a basic map of India with states and borders, some labels, and a number of other specifications stored as a gg object. I'd like to generate a number of maps with a district layer, which will bear data from different variables.

To prevent the district maps overwriting state and country borders, it must be before all the previous code, which I'd like to avoid repeating.

I thought I could do this by calling on $layers for the gg object as per this answer. However, it throws an error. Reprex is below:

library(ggplot2)
library(sf)
library(raster)

# Download district and state data (should be less than 10 Mb in total)

distSF <- st_as_sf(getData("GADM",country="IND",level=2))

stateSF <- st_as_sf(getData("GADM",country="IND",level=1))

# Add border

countryborder <- st_union(stateSF)

# Basic plot

basicIndia <- ggplot() +
  geom_sf(data = stateSF, color = "white", fill = NA) +
  geom_sf(data = countryborder, color = "blue", fill = NA) +
  theme_dark()

basicIndia

# Data-bearing plot

districts <- ggplot() +
  geom_sf(data = distSF, fill = "gold")

basicIndia$layers <- c(geom_sf(data = distSF, fill = "gold"), basicIndia$layers)

basicIndia
#> Error in y$layer_data(plot$data): attempt to apply non-function

Intended outcome

Any help would be much appreciated!

Upvotes: 4

Views: 5362

Answers (2)

camille
camille

Reputation: 16832

I'm still not sure if I'm missing a detail of what you're looking for, but ggplot2 draws layers in the order you provide them. So something like

ggplot(data) +
  geom_col() +
  geom_point(...) +
  geom_line(...)

will draw columns, then points on top of those, then lines on top of the previous layers.

Same goes for sf plots, which makes it easy to make a plot like this of multiple geographic levels.

(I'm using rmapshaper::ms_simplify on the sf objects just to simplify them and speed things up for plotting.)

library(dplyr)
library(ggplot2)
library(sf)
library(raster)

distSF <- st_as_sf(getData("GADM",country="IND",level=2)) %>% rmapshaper::ms_simplify()
...

Then you can plot by adding up the layers in the order you need them displayed. Keep in mind that if you needed to do other calculations with any of these sfs, you could do that in advance or inside your geom_sf.

ggplot() +
  geom_sf(data = distSF, fill = "gold", size = 0.1) +
  geom_sf(data = stateSF, color = "white", fill = NA) +
  geom_sf(data = countryborder, color = "blue", fill = NA)

Regarding trying to add one plot to another: ggplot2 works in layers, so you create a single base ggplot object, then add geometries on top of it. So you could make, for example, two valid plots:

state_plot <- ggplot(stateSF) + 
  geom_sf(color = "white", fill = NA)
country_plot <- ggplot(countryborder) + 
  geom_sf(color = "blue", fill = NA)

But you can't add them, because you would have 2 base ggplot objects. This should be the error you mentioned:

state_plot + 
  country_plot
#> Error: Don't know how to add country_plot to a plot

Instead, if you need to make a plot, then add something else on top of it, make the base ggplot, then add geometry layers, such as a geom_sf with a different set of data.

state_plot +
  geom_sf(data = countryborder, fill = NA, color = "blue")

Created on 2018-10-29 by the reprex package (v0.2.1)

Upvotes: 8

Chris
Chris

Reputation: 3986

If you look at geom_sf(data=distSF) you'll see that it is a list made up of two elements - you want the first one which contains the layer information, so geom_sf(data = distSF, fill = "gold")[[1]] should work.

districts <- ggplot() +
  geom_sf(data = distSF, fill = "gold")

basicIndia$layers <- c(geom_sf(data = distSF, fill = "gold")[[1]], basicIndia$layers)

Upvotes: 3

Related Questions