rggplot2axisrnaturalearth

Is there a way in R to specify the space between to make my X Axes fit my map?


I'm trying to display a planisphere using a map from rnaturalearth library, and I want to add some X and Y axes on each side of my planispher, I managed to set up correctly the Y axes, but I can't find a way to correctly set up the X axis. Here is the result I got for now :

MapIGot

As you can see the width of the X axes is equal to the width of the planisphere at 0° latitude, but I want it to have the same width as the planisphere at 80° latitude. I made the result that I want to obtain in the following image (sorry about my poors paint skills) :

MapIWant

I'm sorry that you can't see the meridans lines, I don't know why the screenshot didn't show the meridian lines.

Now let's talk about my code, here is the library that I use :

library(ggplot2) 
library(dplyr)
library(sf)
library(rnaturalearth)
library(rnaturalearthdata)
library(readxl)

And here is my code that generates everything :

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

longitudes <- longitudes <- c(-180, -140, -100, -60, -20, 0, 20, 60, 100, 140, 180)

# Créer les données pour les labels de longitude (axe X)
bottomXAxis <- lapply(longitudes, function(x) {
  st_sf(label = paste0(abs(x), '\u00b0'),
        geometry = st_sfc(st_point(c(x, 0)), crs = 'WGS84'))
}) %>% bind_rows()

topXAxis <- lapply(longitudes, function(x) {
  st_sf(label = paste0(abs(x), '\u00b0'),
        geometry = st_sfc(st_point(c(x, 0)), crs = 'WGS84'))
}) %>% bind_rows()

nudgeXValues <- rep(0, length(longitudes))


# Créer les données pour les labels de latitude (axe Y)
leftYAxis <- lapply(c(-80, -60, -40, -20, 0, 20, 40, 60, 80), function(y) {
  st_sf(label = paste0(abs(y), '\u00b0'),
        geometry = st_sfc(st_point(c(-180, y)), crs = 'WGS84'))
}) %>% bind_rows()

rightYAxis <- lapply(c(-80, -60, -40, -20, 0, 20, 40, 60, 80), function(y) {
  st_sf(label = paste0(abs(y), '\u00b0'),
        geometry = st_sfc(st_point(c(180, y)), crs = 'WGS84'))
}) %>% bind_rows()

nudge_left_y <- c(-1.6e6, -1.2e6, -0.8e6, -0.4e6, -0.2e6, -0.4e6, -0.8e6, -1.2e6, -1.6e6)
nudge_right_y <- c(1.6e6, 1.4e6, 1e6, 0.6e6, 0.4e6, 0.6e6, 1e6, 1.4e6, 1.6e6)

# Affichage de la carte avec les labels de longitude et latitude
world %>%
  ggplot() +
  geom_sf(color = "black", linewidth = 0.1) +
  geom_sf_text(data = topXAxis, aes(label = label), size = 3.5, color = 'black',
               nudge_y = rep(9e6, length(topXAxis$label)),
               nudge_x = nudgeXValues) +
  geom_sf_text(data = bottomXAxis, aes(label = label), size = 3.5, color = 'black',
               nudge_y = rep(-9e6, length(bottomXAxis$label)),
               nudge_x = nudgeXValues) +
  geom_sf_text(data = leftYAxis, aes(label = label), size = 3.5, color = 'black',
               nudge_x = nudge_left_y) +
  geom_sf_text(data = rightYAxis, aes(label = label), size = 3.5, color = 'black',
               nudge_x = nudge_right_y) +
  coord_sf(crs = "+proj=robin", expand = TRUE) +
  theme_minimal() +
  theme(axis.title = element_blank())

I tried several options as scale_x_continous with xlim, but it didn't work, I hope someone will have the solution. Also I'm still a beginner in R programming so don't hesitate if you have any other feedbacks about my code.

Thank you !


Solution

  • I think this gets close:

    plot of earth with appropriate x-axis labels

    Your code is not bad; it could be tightened up by using seq() to generate sequences and helper functions to avoid repetitive code.

    bottom_long <- -80
    top_long <- 80
    # Créer les données pour les labels de longitude (axe X)
    bottomXAxis <- lapply(longitudes, function(x) {
      st_sf(label = paste0(abs(x), '\u00b0'),
            geometry = st_sfc(st_point(c(x, bottom_long)), crs = "WGS84"))
    }) %>% bind_rows()
    
    topXAxis <- lapply(longitudes, function(x) {
      st_sf(label = paste0(abs(x), '\u00b0'),
            geometry = st_sfc(st_point(c(x, top_long)), crs = 'WGS84'))
    }) %>% bind_rows()
    
    nudgeXValues <- rep(0, length(longitudes))
    
    
    # Créer les données pour les labels de latitude (axe Y)
    leftYAxis <- lapply(c(-80, -60, -40, -20, 0, 20, 40, 60, 80), function(y) {
      st_sf(label = paste0(abs(y), '\u00b0'),
            geometry = st_sfc(st_point(c(-180, y)), crs = 'WGS84'))
    }) %>% bind_rows()
    
    rightYAxis <- lapply(c(-80, -60, -40, -20, 0, 20, 40, 60, 80), function(y) {
      st_sf(label = paste0(abs(y), '\u00b0'),
            geometry = st_sfc(st_point(c(180, y)), crs = 'WGS84'))
    }) %>% bind_rows()
    
    nudge_left_y <- c(-1.6e6, -1.2e6, -0.8e6, -0.4e6, -0.2e6, -0.4e6, -0.8e6, -1.2e6, -1.6e6)
    nudge_right_y <- c(1.6e6, 1.4e6, 1e6, 0.6e6, 0.4e6, 0.6e6, 1e6, 1.4e6, 1.6e6)
    
    # Affichage de la carte avec les labels de longitude et latitude
    plot0 <- world %>%
      ggplot() +
        geom_sf(color = "black", linewidth = 0.1) +
        coord_sf(crs = "+proj=robin", expand = TRUE) +
      theme_minimal() +
      theme(axis.title = element_blank())
    
    
    y_nudge <- 1e6
    plot0 +
        geom_sf_text(data = bottomXAxis, aes(label = label), size = 3.5, color = 'black',
                     nudge_y = rep(-y_nudge, length(bottomXAxis$label)),
                     nudge_x = nudgeXValues) +
      geom_sf_text(data = topXAxis, aes(label = label), size = 3.5, color = 'black',
                   nudge_y = rep(y_nudge, length(topXAxis$label)),
                   nudge_x = nudgeXValues) +
      geom_sf_text(data = leftYAxis, aes(label = label), size = 3.5, color = 'black',
                   nudge_x = nudge_left_y) +
      geom_sf_text(data = rightYAxis, aes(label = label), size = 3.5, color = 'black',
                   nudge_x = nudge_right_y)