rmapshaper
rmapshaper copied to clipboard
An R wrapper for the mapshaper javascript library
rmapshaper
An R package providing access to the awesome mapshaper tool by Matthew Bloch, which has both a Node.js command-line tool as well as an interactive web tool.
I started this package so that I could use mapshaper’s Visvalingam simplification method in R. There is, as far as I know, no other R package that performs topologically-aware multi-polygon simplification. (This means that shared boundaries between adjacent polygons are always kept intact, with no gaps or overlaps, even at high levels of simplification).
But mapshaper does much more than simplification, so I am working on wrapping most of the core functionality of mapshaper into R functions.
So far, rmapshaper
provides the following functions:
-
ms_simplify
- simplify polygons or lines -
ms_clip
- clip an area out of a layer using a polygon layer or a bounding box. Works on polygons, lines, and points -
ms_erase
- erase an area from a layer using a polygon layer or a bounding box. Works on polygons, lines, and points -
ms_dissolve
- aggregate polygon features, optionally specifying a field to aggregate on. If no field is specified, will merge all polygons into one. -
ms_explode
- convert multipart shapes to single part. Works with polygons, lines, and points in geojson format, but currently only with polygons and lines in theSpatial
classes (notSpatialMultiPoints
andSpatialMultiPointsDataFrame
). -
ms_lines
- convert polygons to topological boundaries (lines) -
ms_innerlines
- convert polygons to shared inner boundaries (lines) -
ms_points
- create points from a polygon layer -
ms_filter_fields
- Remove fields from the attributes -
ms_filter_islands
- Remove small detached polygons
If you run into any bugs or have any feature requests, please file an issue
Installation
rmapshaper
is on CRAN. Install the current version with:
install.packages("rmapshaper")
You can install the development version from github with remotes
:
## install.packages("remotes")
library(remotes)
install_github("ateucher/rmapshaper")
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, and with sf
and scf
objects
from the sf
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)
library(sf)
#> Linking to GEOS 3.10.2, GDAL 3.4.2, PROJ 8.2.1; sf_use_s2() is TRUE
## First convert to json
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)
#> Warning in sp::proj4string(sp): CRS object has comment, which is lost in output; in tests, see
#> https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html
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)
#> Warning in sp::proj4string(sp): CRS object has comment, which is lost in output; in tests, see
#> https://cran.r-project.org/web/packages/sp/vignettes/CRS_warnings.html
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)
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. Operating on sf
objects is
faster than with Spatial
objects, but not as fast as with the
geo_json
or geo_list
. 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 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 with:
npm install -g mapshaper
Then you can use the sys
argument in any rmapshaper function:
states_simp_internal <- ms_simplify(states_sf)
states_simp_sys <- ms_simplify(states_sf, sys = TRUE, sys_mem=8) #sys_mem specifies the amout of memory to use in Gb. It defaults to 8 if omitted.
par(mfrow = c(1,2))
plot(st_geometry(states_simp_internal), main = "internal")
plot(st_geometry(states_simp_sys), main = "system")
Thanks
This package uses the V8
package to provide an environment in which to run mapshaper’s javascript
code in R. It relies heavily on all of the great spatial packages that
already exist (especially sp
and rgdal
), the geojsonio
package for
converting between geo_list
, geo_json
, and sf
and Spatial
objects, and the jsonlite
package for converting between json strings
and R objects.
Thanks to timelyportfolio for helping me wrangle the javascript to the point where it works in V8. He also wrote the mapshaper htmlwidget, which provides access to the mapshaper web interface, right in your R session. We have plans to combine the two in the future.
Code of Conduct
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
LICENSE
MIT