Loulou
Loulou

Reputation: 703

R map - poor representation of land borders

I map the southern part of the South hemisphere. My issue is Australia which has poorly drawn borders.

My data :

library("maptools")
library("ggplot2")
library("tidyverse")

ylim_map <- c(-90, -30)
xlim_map <- c(-180, 180)
world <- maps::map("world", fill=TRUE, plot=FALSE, ylim = ylim_map)

Convert data in correct format for ggplot :

IDs <- sapply(strsplit(world$names, ":"), function(x) x[1])
world <- map2SpatialPolygons(world, IDs = IDs, 
                             proj4string = CRS("+proj=longlat +datum=WGS84"))
world_map <- fortify(world)
world_map <- world_map[which(between(world_map$lat, ylim_map[1], ylim_map[2]) &
                               between(world_map$lon, xlim_map[1], xlim_map[2])),]

And my plot :

ggplot() +

  coord_map("orthographic", orientation = c(-90, 0, 0), 
            xlim = xlim_map, ylim = c(ylim_map[1], ylim_map[2] + 10)) +

  geom_map(data = world_map, map = world_map,
           aes(x = long, y = lat, map_id = id), fill = "black") +

  geom_text(aes(x = 180, y = ylim_map[2]+5, label = "180°E"), color = "black") +
  geom_text(aes(x = 90, y = ylim_map[2]+5, label = "90°E"), angle = -90, color = "black") +
  geom_text(aes(x = 0, y = ylim_map[2]+5, label = "0°"), color = "black") +
  geom_text(aes(x = -90, y = ylim_map[2]+5, label = "90°W"), angle = 90, color = "black") +

  labs(y = "", x = "") +

  # Theme
  theme(text = element_text(size = 20),
        panel.background = element_blank(),
        axis.title = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank(),
        axis.line = element_blank(),
        aspect.ratio = 1) 

enter image description here

Upvotes: 2

Views: 291

Answers (1)

Z.Lin
Z.Lin

Reputation: 29085

TLDR:

You need to close your polygons.

Explanation:

Let's trim away extraneous code & zoom in onto Australia. (Though actually the problem exists for Africa & South America as well; it's just not as obvious there...)

We can see that the top line is misbehaving. It's intersecting with the coastline further down south, rather than sticking to its correct latitude level:

ggplot() +
  coord_map("orthographic", orientation = c(-40, 130, 0)) +
  geom_map(data = world_map, map = world_map,
           aes(x = long, y = lat, map_id=id), 
           fill = "darkgrey") +
  theme_bw()

illustration 1

Now a geom_map layer is essentially plotting polygons, and ?geom_polygon states:

Polygons are very similar to paths (as drawn by geom_path()) except that the start and end points are connected and the inside is coloured by fill. The group aesthetic determines which cases are connected together into a polygon.

If we replace the geom_map layer with its geom_polygon / geom_path equivalents, the situation becomes much more obvious: the polygon corresponding to Australia has no top line. Instead, the path starts at the one corner and ends at the opposite corner. geom_polygon connects them with a straight line, which may intersect other lines when the coordinate system isn't linear (and coord_map isn't):

ggplot() +
  coord_map("orthographic", 
            orientation = c(-40, 130, 0)) +
  geom_polygon(data = world_map,
               aes(x = long, y = lat, group = group), 
               fill = "lightgrey") +
  geom_path(data = world_map,
            aes(x = long, y = lat, group = group)) +
  theme_bw()

illustration 2

Solution:

We can manually close each polygon by repeating its first point at the end. (For polygons that are already closed, this has no additional effect.)

library(dplyr)

world_map2 <- world_map %>%
  group_by(group) %>%              # each group corresponds to a unique polygon
  arrange(order) %>%               # sort points in the appropriate sequence
  slice(c(1:n(), 1)) %>%           # repeat first row after last row
  mutate(order = seq(1, n())) %>%  # define new order for n+1 rows
  ungroup()

Check that the polygons are now closed, & the top line for Australia now traces its latitude level nicely:

ggplot() +
  coord_map("orthographic", 
            orientation = c(-40, 130, 0)) +
  geom_polygon(data = world_map2,
               aes(x = long, y = lat, group = group), 
               fill = "lightgrey") +
  geom_path(data = world_map2,
            aes(x = long, y = lat, group = group)) +
  theme_bw()

illustration 3

Applying this to the original use case:

ggplot() +

  coord_map("orthographic", orientation = c(-90, 0, 0), 
            xlim = xlim_map, ylim = c(ylim_map[1], ylim_map[2] + 10)) +

  geom_map(data = world_map2, map = world_map2,
           aes(x = long, y = lat, map_id = id), fill = "black") +

  geom_text(aes(x = 180, y = ylim_map[2]+5, label = "180°E"), color = "black") +
  geom_text(aes(x = 90, y = ylim_map[2]+5, label = "90°E"), angle = -90, color = "black") +
  geom_text(aes(x = 0, y = ylim_map[2]+5, label = "0°"), color = "black") +
  geom_text(aes(x = -90, y = ylim_map[2]+5, label = "90°W"), angle = 90, color = "black") +

  labs(y = "", x = "") +

  # Theme
  theme(text = element_text(size = 20),
        panel.background = element_blank(),
        axis.title = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank(),
        axis.line = element_blank(),
        aspect.ratio = 1) 

result

Upvotes: 1

Related Questions