22

The problem

Suppose we have two shapefiles that should border seamlessly. Only, they don't. Is there a way to force them to stick to one another without gaps?

enter image description here


The specific case

I have two shapefiles: one for European regions -- REG, the other for the neighbouring countries -- NEI. Both shapefiles are taken from Eurostat repository and should fit together nicely; but there are small gaps. Also, I need to simplify the polygons, and then the gaps become really notable.


The best I can think of

I've tried several approaches but with no success. The only way to achieve the desired result that I see requires following steps:

  • create a line sf with just the border between my shapefiles;
  • from this line create a buffer polygon just big enough to cover all gaps;
  • join and dissolve this buffer to the shapefile for neighbours -- NEI;
  • clip off the expanded NEI with the REG shapefile.

Obviously, this is a rather clumsy workaround.

Is there a better way to go?


Reproducible example in this gist


A minimal example

# install dev version of ggplot2
devtools::dev_mode()
devtools::install_github("tidyverse/ggplot2")

library(tidyverse)
library(sf)
library(rmapshaper) 
library(ggthemes)


# load data
source(file = url("https://gist.githubusercontent.com/ikashnitsky/4b92f6b9f4bcbd8b2190fb0796fd1ec0/raw/1e281b7bb8ec74c9c9989fe50a87b6021ddbad03/minimal-data.R"))

# test how good they fit together
ggplot() + 
        geom_sf(data = REG, color = "black", size = .2, fill = NA) +
        geom_sf(data = NEI, color = "red", size = .2, fill = NA)+
        coord_sf(datum = NA)+
        theme_map()

ggsave("test-1.pdf", width = 12, height = 10)

# simplify
REGs <- REG %>% ms_simplify(keep = .5, keep_shapes = TRUE)
NEIs <- NEI %>% ms_simplify(keep = .5, keep_shapes = TRUE)


ggplot() + 
        geom_sf(data = REGs, color = "black", size = .2, fill = NA) +
        geom_sf(data = NEIs, color = "red", size = .2, fill = NA)+
        coord_sf(datum = NA)+
        theme_map()

ggsave("test-2.pdf", width = 12, height = 10)
ikashnitsky
  • 2,511
  • 20
  • 38
  • 1
    I suggest asking this question here: https://gis.stackexchange.com/ Also, I would see if `mapshaper::ms_simplify()` could help here. The function is designed to simplify polygons, and it has a `snap` argument that would avoid this from occurring when it's set to TRUE. Maybe that will do the trick? – Phil Jan 20 '18 at 22:27
  • @Phil Thanks for your suggestion. It does not seem to work. I guess, the problem is that I artificially merge the two spatial objects, thus there are no common vertex even where they should be – ikashnitsky Jan 22 '18 at 22:32
  • 2
    Can you try to reduce your example? It's a bit unwieldy - if you could reduce it to just one or two polygons from each dataset that illustrates the issue it will be easier for someone to work with. Also, please don't start your example with `rm(list = ls(all = TRUE))`. If someone runs that without looking carefully you could really mess them up. – andyteucher Jan 23 '18 at 04:41
  • @andyteucher Thanks for your comment! Done. – ikashnitsky Jan 23 '18 at 08:13
  • @ikashnitsky Can you provide the urls to the data your using from Eurostat? Your example data (NEI, REG) requires you merge a single geometry file, with a multi geometry file. – Technophobe01 Jan 28 '18 at 02:10
  • @andyteucher could you have a look at the solution provided by @Spacedman [here](https://gis.stackexchange.com/a/268911/49606) and decide whether [`pprepair`](https://github.com/tudelft3d/pprepair) has chances to be introduced in `rmapshaper` as a special function? (I feel like asking first before creating a github issue) – ikashnitsky Jan 30 '18 at 20:36
  • 1
    that’s a great solution, and pprepair looks like very good tool, but I think it’s out of scope for rmapshaper. rmapshaper simply wraps the [mapshaper](https://github.com/mbloch/mapshaper) node.js library and I’d like to keep that scope. pprepair could be a great standalone package though (as @spacedman said). – andyteucher Jan 30 '18 at 21:04
  • @andyteucher Now I get the point. I found `rmapshaper` is such nice tool that tought it can do **everything** =) thanks a lot! – ikashnitsky Jan 30 '18 at 21:20

1 Answers1

1

ms_simplify seems to work on your minimal example but you need first to group your 2 "shapefiles" into one "shapefile". If needed it would be easy to split them after the simplification of the boundaries.
(note : my version of rmapshaper returns an error when ms_simplify is used with an sf object. This is why I have transformed my tmp object in a sp object with as(tmp, "Spatial"))

NEI <- st_transform(NEI, st_crs(REG)$epsg)
tmp <- rbind(REG , NEI)
tmp <- ms_simplify(as(tmp, "Spatial"), keep = .1, keep_shapes = T)
ggplot() + geom_sf(data = st_as_sf(tmp)) + theme_bw()

enter image description here

Gilles
  • 3,668
  • 13
  • 27
  • 1
    This works, but only at *very* high levels of simplification. Already at "keep = 0.2" you start getting holes. – lbusett Jan 26 '18 at 18:32
  • 1
    I'm sorry to confirm that this is not a solution – ikashnitsky Jan 29 '18 at 08:52
  • 2
    I totally agree that this is at best a rough hack... This will probably be even worse on the real life example. But this solution might be useful in some circumstances. Maybe an option to explore is using Grass GIS from R and its v.clean command ? – Gilles Jan 29 '18 at 13:02