---
title: "rmapshaper Basics"
author: "Andy Teucher"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{rmapshaper Basics}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

rmapshaper is a package which is an R wrapper around the awesome [mapshaper](https://github.com/mbloch/mapshaper/) tool by Matthew Bloch, which has both a [Node.js command-line tool](https://github.com/mbloch/mapshaper/wiki/Introduction-to-the-Command-Line-Tool) as well as an [interactive web tool](https://mapshaper.org/).

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](https://bost.ocks.org/mike/simplify/) simplification method.

At this time, `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.
- `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

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

### Usage

rmapshaper works with `sf` objects as well as geojson strings (character objects of class `geo_json`). It also works with `Spatial` classes from the `sp` package, though this will likely be retired in the future; users are encouraged to use the more modern `sf` package.

We will use the `nc.gpkg` file (North Carolina county boundaries)
from the `sf` package and read it in as an `sf` object:

```{r}
library(rmapshaper)
library(sf)

file <- system.file("gpkg/nc.gpkg", package = "sf")
nc_sf <- read_sf(file)
```

Plot the original: 

```{r}
plot(nc_sf["FIPS"])
```

Now simplify using default parameters, then plot the simplified North Carolina counties:
```{r}
nc_simp <- ms_simplify(nc_sf)
plot(nc_simp["FIPS"])
```

You can see that even at very high levels of simplification, the mapshaper
simplification algorithm preserves the topology, including shared boundaries. The `keep` 
parameter specifies what proportion of vertices to keep:

```{r}
nc_very_simp <- ms_simplify(nc_sf, keep = 0.001)
plot(nc_very_simp["FIPS"])
```

Compare this to the output using `sf::st_simplify`, where overlaps and gaps are evident:

```{r}

nc_stsimp <- st_simplify(nc_sf, preserveTopology = TRUE, dTolerance = 10000) # dTolerance specified in meters
plot(nc_stsimp["FIPS"])
```

This time we'll demonstrate the `ms_innerlines` function:

```{r}
nc_sf_innerlines <- ms_innerlines(nc_sf)
plot(nc_sf_innerlines)
```

All of the functions are quite fast with `geojson` character objects. They are slower with the `sf` and 
`Spatial` classes due to internal conversion to/from json. If you are going to do multiple 
operations on large `sf` objects, 
it's recommended to first convert to json using `geojsonsf::sf_geojson()`, or `geojsonio::geojson_json()`. 
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 `nc_sf` as created above:

```{r eval=rmapshaper:::v8_version() >= '6'}
library(geojsonsf)
library(rmapshaper)
library(sf)

## First convert 'states' dataframe from geojsonsf pkg to json

nc_sf |> 
  sf_geojson() |> 
  ms_erase(bbox = c(-80, 35, -79, 35.5)) |>  # Cut a big hole in the middle
  ms_dissolve() |>  # Dissolve county borders
  ms_simplify(keep_shapes = TRUE, explode = TRUE) |> # Simplify polygon
  geojson_sf() |> # Convert to sf object
  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:

```{r eval=nzchar(Sys.which("mapshaper"))}
check_sys_mapshaper()
```

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:

```{r eval=nzchar(Sys.which("mapshaper"))}
nc_simp_sys <- ms_simplify(nc_sf, sys = TRUE)

plot(nc_simp_sys[, "FIPS"])
```
