Search code examples
rggplot2mapsgeospatial

Strange behavior with ggplot, sf package and orthographic projection


Cross posting with gis.stackexchange.com: the ggplot package throws errors for some versions of an orthographic projection. For example, this works fine

library(tmap)
library(sf)
library(tidyverse)

data("World") ## get built-in data from the tmap package
world.sf <- World
projection <- "+proj=ortho +lat_0=40"
# Fix polygons so they don't get cut in ortho projection
ortho_world.sf  <- st_cast(world.sf, 'MULTILINESTRING') %>%
  st_cast('LINESTRING', do_split=TRUE) %>%
  mutate(npts = npts(geometry, by_feature = TRUE)) %>%
  st_cast('POLYGON') %>% st_transform(crs=projection)
ggplot() + geom_sf(data=ortho_world.sf)

This projection works as well

projection <- "+proj=ortho +lat_0=70 +lon_0=-181" ## works fine

But all of these throw errors

projection <- "+proj=ortho +lat_0=40 +lon_0=-180" ## throws error
projection <- "+proj=ortho +lat_0=40 +lon_0=-149" ## throws error
projection <- "+proj=ortho +lat_0=20 +lon_0=-149" ## throws error

The error seems to be in sf, since I get similiar problems with plot in base R. What's going on?


Solution

  • The issue is that some of the polygons are degenerate after the transformation, with some features only containing a single point. Polygons in sf need at least 4 points. You need to count the points using npts after the transformation and filter out those with less than four points.

    For convenience, let's wrap the code in a function to which we need only pass the projection string:

    plot_proj <- function(proj) {
      st_cast(world.sf, 'MULTILINESTRING') %>%
      st_cast('LINESTRING', do_split = TRUE) %>%
      st_transform(crs = proj) %>%
      mutate(npts = npts(geometry, by_feature = TRUE)) %>%
      filter(npts > 3) %>%
      st_cast('POLYGON') %>%
      ggplot() + 
      geom_sf()
    }
    

    Now we can do:

    plot_proj("+proj=ortho +lat_0=40")
    

    enter image description here

    plot_proj("+proj=ortho +lat_0=40 +lon_0=-180")
    

    enter image description here

    plot_proj("+proj=ortho +lat_0=40 +lon_0=-149")
    

    enter image description here

    plot_proj("+proj=ortho +lat_0=20 +lon_0=-149")
    

    enter image description here