Search code examples
rggplot2r-sf

Preserve axis labels in geom_sf when changing projection


I'm trying to show axis labels on a world map using Robinson projection. I have no problem showing the labels in default projection:

library(tidyverse)
library(sf)
library(rnaturalearth)

world <- ne_countries(scale = "small", returnclass = "sf")

world %>%
  ggplot() +
  geom_sf() +
  coord_sf(label_axes = "E--N",
           expand = FALSE)

enter image description here

but when I try

world %>%
  ggplot() +
  geom_sf() +
  coord_sf(label_axes = "E--N",
           expand = FALSE,
           crs = "+proj=robin")

enter image description here

the y axis labels are messed up. Any suggestions how to fix/hack this? Ideally I get something like (but better formatted).

enter image description here


Solution

  • I think you'll need to do this manually:

    grid <- list(
           st_sf(geometry = st_sfc(
      st_multilinestring(x = lapply(c(-180, -120, -60, 0, 60, 120, 180), 
                    function(x) cbind(x, seq(-90, 90, 1)))), crs = 'WGS84')),
            st_sf(geometry = st_sfc(
      st_multilinestring(x = lapply(c(-90, -60, -30, 0, 30, 60, 90), function(x) {
        cbind(seq(-180, 180, 1), x)
      })), crs = 'WGS84'))) %>% bind_rows()
    
    ylabs <- lapply(c(-90, -60, -30, 0, 30, 60, 90), function(x) {
      st_sf(label = paste0(abs(x), '\u00b0', 
                           ifelse(x == 0, '', ifelse(x < 0, 'S', 'N'))),
            geometry = st_sfc(st_point(c(-180, x)), crs = 'WGS84'))
    }) %>% bind_rows()
    
    world %>%
      ggplot() +
      geom_sf(fill = 'white') +
      geom_sf(data = grid, linewidth = 0.1) +
      geom_sf_text(data = ylabs, aes(label = label), size = 3, color = 'gray30',
                   nudge_x = c(-2e6, -1.5e6, -1.3e6, -1e6, -1.3e6, -1.5e6, -2e6)) +
      coord_sf(label_axes = "E--N",
               expand = FALSE,
               crs = "+proj=robin",
               clip = "off") +
      theme_minimal() +
      theme(axis.text.y = element_blank(),
            panel.grid = element_blank(),
            axis.title = element_blank(),
            plot.margin = margin(10, 10, 10, 30))
    

    enter image description here