Pawliczek
Pawliczek

Reputation: 63

ggplot maps - unwanted horizontal lines when using coord_map

I've problem with projecting properly map of Europe when I use coord_map in ggplot package. The code below gives me a weird and unwanted horizontal lines in random places. Does anyone know how to overcome this problem?

I don't want to use coord_quickmap nor coord_cartesian because I want to preserve straight lines of countries.

library(ggplot2)

map.world <- map_data("world")

ggplot(map.world, aes(x = long, y = lat)) + 
  geom_polygon(mapping = aes(x = long, y = lat, group = group), fill =  "#B3B1B5", color = "#D9D8DA",size = 0.4) +
  theme_minimal() +
  theme(axis.text = element_blank(), text = element_blank(), panel.grid = element_blank()) +
  coord_map(xlim = c(-27,36), ylim = c(34,67))

enter image description here

Upvotes: 3

Views: 1115

Answers (1)

davidnortes
davidnortes

Reputation: 932

There are two ways to work around your problem:

The straightforward way

This way just needs a little tweaking of your code (note that I use magrittr's forward pipes):

library(maps)
library(magrittr)
library(maptools)
library(broom)
library(ggplot2)

europe <-  maps::map("world", fill=TRUE, plot=FALSE) %>%
                 maptools::pruneMap(xlim = c(-27,36), ylim = c(34,67))

ggplot(data= broom::tidy(europe)) + 
  geom_polygon(mapping = aes(x = long, y = lat, group = group), 
               fill =  "#B3B1B5", color = "#D9D8DA",size = 0.4) +
  theme_void() +
  coord_map()

The "owin/extent" approach

Another way to work around your problem can be done by using owin objects. This kind of objects will allow you to create a spatial window. Then you can represent only the intersection of such window over the world map.

Using this approach your code will be something as follows (also using magrittr's forward pipes and setting up a general CRS)

library(maps)
library(magrittr)
library(spatstat)
library(maptools)
library(raster)
library(broom)
library(ggplot2)

#Defining a general EPSG so there won't be any superposition problems
epsg <- "+proj=longlat +datum=WGS84 +no_defs"

#Using the original maps package, then converting map into SpatialPolygons object
map.world <- maps::map("world", fill=TRUE) %$% 
  maptools::map2SpatialPolygons(., IDs=names,proj4string=CRS(epsg))

#In order to keep the names of the countries we create the following data.frame
country.labs <- sapply(slot(map.world, "polygons"), function(x) slot(x, "ID")) %>% 
  data.frame( ID=1:length(map.world), name=., row.names = .) 

#We convert object map.world into a SpatialPolygonsDataFrame object
map.world.SPDF <- sp::SpatialPolygonsDataFrame(map.world, country.labs) 

#Creating owin object using your zooming coordinates
#This step always requires to load packages 'spatstat' and 'maptools'
zoom <- as(spatstat::as.owin(c(-27,36,34,67)), "SpatialPolygons") 
raster::projection(zoom)=epsg

#Storing intersection between 'zoom' and 'world.map'
europe <- raster::intersect(map.world.SPDF, zoom)

#*country names of object europe can be accessed via europe@data

#Representing object 'europe' using broom::tidy to create a data.frame object
ggplot() + 
  geom_polygon(data = broom::tidy(europe, region="name"), 
               mapping = aes(x = long, y = lat, group = group), 
               fill =  "#B3B1B5", color = "#D9D8DA",size = 0.4) +
  theme_void() +
  coord_map()

#*country names after tidying 'europe' this way are in a new column called 'id'

Depending on what you are doing, you may want to use

zoom <- as(raster::extent(c(-27,36,34,67)), "SpatialPolygons")

To create an extent object instead of an owin object (The result here is going to be the same)

The result obtained with any method is displayed below

enter image description here

In case you need to do different zooms you can easily wrap any of the alternatives up in a function.

I hope it helps

BONUS BALL: It might be interesting for you to check out the tmap package

Upvotes: 5

Related Questions