rmapshaper Basics

Andy Teucher

2022-05-10

rmapshaper is a package which is an R wrapper around the awesome mapshaper tool by Matthew Bloch, which has both a Node.js command-line tool as well as an interactive web tool.

The main advantage of the package is the availability of the topologically-aware simplification algorithm in ms_simplify (provided by the simplify tool in mapshaper). This means that shared boundaries between adjacent polygons are always kept intact, with no gaps or overlaps, even at high levels of simplification. It uses the Visvalingam simplification method.

At this time, rmapshaper provides the following functions:

This short vignette focuses on simplifying polygons with the ms_simplify function.

Usage

rmapshaper works with geojson strings (character objects of class geo_json) and list geojson objects of class geo_list. These classes are defined in the geojsonio package. It also works with Spatial classes from the sp package.

We will use the states dataset from the geojsonio package and first turn it into a geo_json object:

library(geojsonio)
## Registered S3 method overwritten by 'geojsonsf':
##   method        from   
##   print.geojson geojson
## 
## Attaching package: 'geojsonio'
## The following object is masked from 'package:base':
## 
##     pretty
library(rmapshaper)
## Registered S3 method overwritten by 'geojsonlint':
##   method         from 
##   print.location dplyr
library(sp)

states_json <- geojson_json(states, geometry = "polygon", group = "group")
## Assuming 'long' and 'lat' are longitude and latitude, respectively

For ease of illustration via plotting, we will convert to a SpatialPolygonsDataFrame:

states_sp <- geojson_sp(states_json)

## Plot the original
plot(states_sp)

Now simplify using default parameters, then plot the simplified states

states_simp <- ms_simplify(states_sp)
plot(states_simp)

You can see that even at very high levels of simplification, the mapshaper simplification algorithm preserves the topology, including shared boundaries:

states_very_simp <- ms_simplify(states_sp, keep = 0.001)
plot(states_very_simp)

Compare this to the output using rgeos::gSimplify, where overlaps and gaps are evident:

library(rgeos)
## rgeos version: 0.5-9, (SVN revision 684)
##  GEOS runtime version: 3.10.2-CAPI-1.16.0 
##  Please note that rgeos will be retired by the end of 2023,
## plan transition to sf functions using GEOS at your earliest convenience.
##  GEOS using OverlayNG
##  Linking to sp version: 1.4-7 
##  Polygon checking: TRUE
states_gsimp <- gSimplify(states_sp, tol = 1, topologyPreserve = TRUE)
plot(states_gsimp)

The package also works with sf objects. This time we’ll demonstrate the ms_innerlines function:

library(sf)
## Linking to GEOS 3.10.2, GDAL 3.4.2, PROJ 8.2.1; sf_use_s2() is TRUE
states_sf <- st_as_sf(states_sp)
states_sf_innerlines <- ms_innerlines(states_sf)
plot(states_sf_innerlines)

All of the functions are quite fast with geo_json character objects and geo_list list objects. They are slower with the Spatial classes due to internal conversion to/from json. If you are going to do multiple operations on large Spatial objects, it’s recommended to first convert to json using geojson_list or geojson_json from the geojsonio package. All of the functions have the input object as the first argument, and return the same class of object as the input. As such, they can be chained together. For a totally contrived example, using states_sp as created above:

library(geojsonio)
library(rmapshaper)
library(sp)
library(magrittr)

## First convert 'states' dataframe from geojsonio pkg to json
states_json <- geojson_json(states, lat = "lat", lon = "long", group = "group", 
                            geometry = "polygon")

states_json %>% 
  ms_erase(bbox = c(-107, 36, -101, 42)) %>% # Cut a big hole in the middle
  ms_dissolve() %>% # Dissolve state borders
  ms_simplify(keep_shapes = TRUE, explode = TRUE) %>% # Simplify polygon
  geojson_sp() %>% # Convert to SpatialPolygonsDataFrame
  plot(col = "blue") # plot

Using the system mapshaper

Sometimes if you are dealing with a very large spatial object in R, rmapshaper functions will take a very long time or not work at all. As of version 0.4.0, you can make use of the system mapshaper library if you have it installed. This will allow you to work with very large spatial objects.

First make sure you have mapshaper installed:

check_sys_mapshaper()
## mapshaper version 0.5.88 is installed and on your PATH
##                  mapshaper-xl 
## "/usr/local/bin/mapshaper-xl"

If you get an error, you will need to install mapshaper. First install node (https://nodejs.org/en/) and then install mapshaper in a command prompt with:

$ npm install -g mapshaper

Then you can use the sys argument in any rmapshaper function:

states_simp_sys <- ms_simplify(states_sf, sys = TRUE)

plot(states_simp_sys[, "region"])