diff --git a/.github/.gitignore b/.github/.gitignore
new file mode 100644
index 0000000..2d19fc7
--- /dev/null
+++ b/.github/.gitignore
@@ -0,0 +1 @@
+*.html
diff --git a/.github/workflows/R-CMD-check-docker.yaml b/.github/workflows/R-CMD-check-docker.yaml
deleted file mode 100644
index 064ba77..0000000
--- a/.github/workflows/R-CMD-check-docker.yaml
+++ /dev/null
@@ -1,29 +0,0 @@
-on: [push, pull_request]
-
-name: R-CMD-check-docker
-
-jobs:
- R-CMD-check-docker:
- runs-on: ubuntu-latest
- container: jakubnowosad/geocompr_proj6
- steps:
- - uses: actions/checkout@v1
-
- - name: Install dependencies
- run: |
- install.packages('remotes')
- install.packages('rcmdcheck')
- remotes::install_deps(dependencies = TRUE, repos = "https://cran.rstudio.com", upgrade = TRUE)
- shell: Rscript {0}
-
- - name: Check
- run: |
- rcmdcheck::rcmdcheck(args = '--no-manual', error_on = 'warning', check_dir = 'check')
- shell: Rscript {0}
-
- - name: Upload check results
- if: failure()
- uses: actions/upload-artifact@master
- with:
- name: ${{ runner.os }}-docker-geocompr-results
- path: check
diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml
index 2be71e6..dcc3f64 100644
--- a/.github/workflows/R-CMD-check.yaml
+++ b/.github/workflows/R-CMD-check.yaml
@@ -1,4 +1,14 @@
-on: [push, pull_request]
+# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
+# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
+#
+# NOTE: This workflow is overkill for most R packages and
+# check-standard.yaml is likely a better choice.
+# usethis::use_github_action("check-standard") will install it.
+on:
+ push:
+ branches: [main, master]
+ pull_request:
+ branches: [main, master]
name: R-CMD-check
@@ -6,118 +16,45 @@ jobs:
R-CMD-check:
runs-on: ${{ matrix.config.os }}
- name: ${{ matrix.config.os }} (${{ matrix.config.r }} ${{ matrix.config.v8 }})
+ name: ${{ matrix.config.os }} (${{ matrix.config.r }})
strategy:
fail-fast: false
matrix:
config:
- - { os: windows-latest, r: 'release', args: "--no-manual"}
- - { os: macOS-latest, r: 'release', args: "--no-manual"}
- - { os: macOS-latest, r: 'release', args: "--no-manual", no_node: true}
- - { os: ubuntu-18.04, r: 'oldrel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest", v8: "libnode-dev", args: "--no-manual"}
- - { os: ubuntu-18.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest", v8: "libnode-dev"}
- - { os: ubuntu-18.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest", v8: "libv8-dev"}
- - { os: ubuntu-18.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/bionic/latest", v8: "libnode-dev", args: "--no-manual"}
+ - {os: macos-latest, r: 'release'}
+ - {os: windows-latest, r: 'release'}
+ - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'}
+ - {os: ubuntu-latest, r: 'release'}
+ - {os: ubuntu-latest, r: 'oldrel-1'}
+
env:
- R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
- RSPM: ${{ matrix.config.rspm }}
- CRAN: ${{ matrix.config.cran }}
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
- cache-version: v3
+ R_KEEP_PKG_SOURCE: yes
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- - uses: actions/setup-node@v1
- if: matrix.config.no_node == false
+ - uses: actions/setup-node@v3
+ with:
+ node-version: '16'
- - name: install mapshaper node lib
- if: matrix.config.no_node == false
+ - name: Install mapshaper
run: npm install -g mapshaper
- - uses: r-lib/actions/setup-r@v1
+ - uses: r-lib/actions/setup-pandoc@v2
+
+ - uses: r-lib/actions/setup-r@v2
with:
r-version: ${{ matrix.config.r }}
+ http-user-agent: ${{ matrix.config.http-user-agent }}
+ use-public-rspm: true
- - uses: r-lib/actions/setup-pandoc@master
-
- - uses: r-lib/actions/setup-tinytex@master
- if: contains(matrix.config.args, 'no-manual') == false
-
- - name: Query dependencies
- run: |
- install.packages('remotes')
- saveRDS(remotes::dev_package_deps(dependencies = TRUE), "depends.Rds", version = 2)
- shell: Rscript {0}
-
- - name: Cache R packages
- uses: actions/cache@v2
+ - uses: r-lib/actions/setup-r-dependencies@v2
with:
- path: ${{ env.R_LIBS_USER }}
- key: ${{ env.cache-version }}-${{ runner.os }}-r-${{ matrix.config.r }}-${{ hashFiles('depends.Rds') }}
- restore-keys: ${{ env.cache-version }}-${{ runner.os }}-r-${{ matrix.config.r }}-
-
- - name: install macOS system dependencies
- if: runner.os == 'macOS'
- continue-on-error: true
- run: |
- brew install pkg-config gdal openssl udunits v8 protobuf
+ extra-packages: any::rcmdcheck
+ needs: check
- - name: add modern cran/v8 ppa
- # default libv8-dev on Xenial (16) and Bionic (18) is old libv8-3.14.5.
- # To test on new, add the cran/v8 ppa and install current libnode-dev,
- # To test on old, install libv8-dev from existing default ppa
- if: runner.os == 'Linux' && contains(matrix.config.v8, 'libnode-dev') == true
- run: |
- sudo add-apt-repository -y ppa:cran/v8
- sudo apt-get -y update
-
- - name: Install remotes package
- run: Rscript -e "install.packages('remotes')"
-
- - name: Install system dependencies
- if: runner.os == 'Linux'
- env:
- RHUB_PLATFORM: linux-x86_64-ubuntu-gcc
- run: |
- Rscript -e "remotes::install_github('r-hub/sysreqs')"
- sysreqs=$(Rscript -e "cat(sysreqs::sysreq_commands('DESCRIPTION'))")
- sudo add-apt-repository -y ppa:cran/v8
- sudo -s eval "$sysreqs"
- # install spatial dependencies
- sudo apt update
- sudo apt install \
- libudunits2-dev \
- libgdal-dev \
- libgeos-dev \
- libproj-dev \
- ${{ matrix.config.v8 }}
-
- - name: Install dependencies
- run: |
- remotes::install_deps(dependencies = TRUE)
- remotes::install_cran('rcmdcheck')
- shell: Rscript {0}
-
- - name: Check
- env:
- TMPDIR: ${{ runner.temp }}
- run: |
- rcmdcheck::rcmdcheck(args = "${{ matrix.config.args }}", error_on = 'warning', check_dir = 'check')
- shell: Rscript {0}
-
-
- - name: Upload check results
- if: failure()
- uses: actions/upload-artifact@master
+ - uses: r-lib/actions/check-r-package@v2
with:
- name: ${{ runner.os }}-r${{ matrix.config.r }}-results
- path: check
-
- - name: Test coverage
- if: matrix.config.os == 'macOS-latest' && matrix.config.r == 'release'
- continue-on-error: true
- run: |
- Rscript -e 'remotes::install_github("r-lib/covr@gh-actions")'
- Rscript -e 'covr::codecov(token = "${{secrets.CODECOV_TOKEN}}")'
+ upload-snapshots: true
diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml
new file mode 100644
index 0000000..2c5bb50
--- /dev/null
+++ b/.github/workflows/test-coverage.yaml
@@ -0,0 +1,50 @@
+# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
+# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
+on:
+ push:
+ branches: [main, master]
+ pull_request:
+ branches: [main, master]
+
+name: test-coverage
+
+jobs:
+ test-coverage:
+ runs-on: ubuntu-latest
+ env:
+ GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - uses: r-lib/actions/setup-r@v2
+ with:
+ use-public-rspm: true
+
+ - uses: r-lib/actions/setup-r-dependencies@v2
+ with:
+ extra-packages: any::covr
+ needs: coverage
+
+ - name: Test coverage
+ run: |
+ covr::codecov(
+ quiet = FALSE,
+ clean = FALSE,
+ install_path = file.path(Sys.getenv("RUNNER_TEMP"), "package")
+ )
+ shell: Rscript {0}
+
+ - name: Show testthat output
+ if: always()
+ run: |
+ ## --------------------------------------------------------------------
+ find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true
+ shell: bash
+
+ - name: Upload test results
+ if: failure()
+ uses: actions/upload-artifact@v3
+ with:
+ name: coverage-test-failures
+ path: ${{ runner.temp }}/package
diff --git a/DESCRIPTION b/DESCRIPTION
index 0bc244a..184c75a 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -21,33 +21,29 @@ Description: Edit and simplify 'geojson', 'Spatial', and 'sf'
by Matthew Bloch to perform
topologically-aware polygon simplification, as well as other
operations such as clipping, erasing, dissolving, and converting
- 'multi-part' to 'single-part' geometries. It relies on the
- 'geojsonio' package for working with 'geojson' objects, the 'sf'
- package for working with 'sf' objects, and the 'sp' and 'rgdal'
- packages for working with 'Spatial' objects.
+ 'multi-part' to 'single-part' geometries.
License: MIT + file LICENSE
URL: https://github.com/ateucher/rmapshaper
BugReports: https://github.com/ateucher/rmapshaper/issues
Imports:
- geojsonio (>= 0.9.4),
- geojsonlint (>= 0.4.0),
- jsonlite (>= 1.7.0),
methods,
- readr (>= 1.4.0),
- sf (>= 0.9-0),
+ geojsonsf (>= 2.0.2),
+ jsonify (>= 1.2.0),
+ readr (>= 2.1.0),
+ sf (>= 1.0.0),
sp (>= 1.4-0),
- V8 (>= 3.4.2)
+ V8 (>= 4.0.0)
Suggests:
+ geojsonio,
knitr,
magrittr,
- rgdal,
- rgeos,
rmarkdown,
testthat (>= 2.1.0),
+ jsonlite,
covr,
units
VignetteBuilder:
knitr
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
-RoxygenNote: 7.1.2
+RoxygenNote: 7.2.3
diff --git a/NAMESPACE b/NAMESPACE
index 314f786..514a36a 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -1,74 +1,63 @@
# Generated by roxygen2: do not edit by hand
S3method(drop_null_geometries,character)
-S3method(drop_null_geometries,geo_json)
-S3method(drop_null_geometries,geo_list)
+S3method(drop_null_geometries,json)
S3method(ms_clip,SpatialLines)
S3method(ms_clip,SpatialPoints)
S3method(ms_clip,SpatialPolygons)
S3method(ms_clip,character)
-S3method(ms_clip,geo_json)
-S3method(ms_clip,geo_list)
+S3method(ms_clip,json)
S3method(ms_clip,sf)
S3method(ms_clip,sfc)
S3method(ms_dissolve,SpatialPoints)
S3method(ms_dissolve,SpatialPolygons)
S3method(ms_dissolve,character)
-S3method(ms_dissolve,geo_json)
-S3method(ms_dissolve,geo_list)
+S3method(ms_dissolve,json)
S3method(ms_dissolve,sf)
S3method(ms_dissolve,sfc)
S3method(ms_erase,SpatialLines)
S3method(ms_erase,SpatialPoints)
S3method(ms_erase,SpatialPolygons)
S3method(ms_erase,character)
-S3method(ms_erase,geo_json)
-S3method(ms_erase,geo_list)
+S3method(ms_erase,json)
S3method(ms_erase,sf)
S3method(ms_erase,sfc)
S3method(ms_explode,SpatialLines)
S3method(ms_explode,SpatialPolygons)
S3method(ms_explode,character)
-S3method(ms_explode,geo_json)
-S3method(ms_explode,geo_list)
+S3method(ms_explode,json)
S3method(ms_explode,sf)
S3method(ms_explode,sfc)
S3method(ms_filter_fields,SpatialLinesDataFrame)
S3method(ms_filter_fields,SpatialPointsDataFrame)
S3method(ms_filter_fields,SpatialPolygonsDataFrame)
S3method(ms_filter_fields,character)
-S3method(ms_filter_fields,geo_json)
-S3method(ms_filter_fields,geo_list)
+S3method(ms_filter_fields,json)
S3method(ms_filter_fields,sf)
S3method(ms_filter_islands,SpatialPolygons)
S3method(ms_filter_islands,character)
-S3method(ms_filter_islands,geo_json)
-S3method(ms_filter_islands,geo_list)
+S3method(ms_filter_islands,json)
S3method(ms_filter_islands,sf)
S3method(ms_filter_islands,sfc)
S3method(ms_innerlines,SpatialPolygons)
S3method(ms_innerlines,character)
-S3method(ms_innerlines,geo_json)
-S3method(ms_innerlines,geo_list)
+S3method(ms_innerlines,json)
S3method(ms_innerlines,sf)
S3method(ms_innerlines,sfc)
S3method(ms_lines,SpatialPolygons)
S3method(ms_lines,character)
-S3method(ms_lines,geo_json)
-S3method(ms_lines,geo_list)
+S3method(ms_lines,json)
S3method(ms_lines,sf)
S3method(ms_lines,sfc)
S3method(ms_points,SpatialPolygons)
S3method(ms_points,character)
-S3method(ms_points,geo_json)
-S3method(ms_points,geo_list)
+S3method(ms_points,json)
S3method(ms_points,sf)
S3method(ms_points,sfc)
S3method(ms_simplify,SpatialLines)
S3method(ms_simplify,SpatialPolygons)
S3method(ms_simplify,character)
-S3method(ms_simplify,geo_json)
-S3method(ms_simplify,geo_list)
+S3method(ms_simplify,json)
S3method(ms_simplify,sf)
S3method(ms_simplify,sfc)
export(apply_mapshaper_commands)
@@ -85,7 +74,6 @@ export(ms_lines)
export(ms_points)
export(ms_simplify)
importFrom(V8,v8)
-importFrom(geojsonlint,geojson_validate)
importFrom(methods,.hasSlot)
importFrom(methods,as)
importFrom(methods,is)
diff --git a/NEWS.md b/NEWS.md
index 4424e9e..9de5762 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,5 +1,11 @@
# rmapshaper (development version)
+* Switched to using the `geojsonsf` package instead of `geojsonio` for object conversion (#118).
+* Dropped support for `geojson_list` objects. This was a rarely-used class from the `geojsonio` package (#118)
+* Arguments `force_FC`, `sys`, and `sys_mem` are now passed to `apply_mapshaper_commands` via `...` rather than explicitly, so they are now documented in the `...` section of each function. This may break some existing code if you were passing values to these arguments by position rather than by name, especially using `force_FC` in `ms_simplify` as it was not at the end of the argument list. It may also change the class of the return value for some input classes and functions (such as `ms_lines` and `ms_innerlines`) as `force_FC` will inherit the default `TRUE` for all functions.
+* Added `quiet` option to silence mapshaper console messages when using `sys = TRUE` (#125)
+* Added ability to globally set the system memory when using the system mapshaper via `options("mapshaper.sys_mem"=X)`, where `X` is the amount of memory in GB.
+
# rmapshaper 0.4.6
* Fixed a long-standing issue where `units` columns in `sf` objects would cause failures; all numeric columns of class `"units"` are now converted to numeric before running through mapshaper commands. (#116, thanks @Robinlovelace)
diff --git a/R/clip_erase.R b/R/clip_erase.R
index 1d715f5..9c5919d 100755
--- a/R/clip_erase.R
+++ b/R/clip_erase.R
@@ -5,29 +5,27 @@
#' @param target the target layer from which to remove portions. One of:
#' \itemize{
#' \item \code{geo_json} or \code{character} points, lines, or polygons;
-#' \item \code{geo_list} points, lines, or polygons;
#' \item \code{SpatialPolygons}, \code{SpatialLines}, \code{SpatialPoints};
#' \item \code{sf} or \code{sfc} points, lines, or polygons object
#' }
#' @param clip the clipping layer (polygon). One of:
#' \itemize{
#' \item \code{geo_json} or \code{character} polygons;
-#' \item \code{geo_list} polygons;
#' \item \code{SpatialPolygons*};
#' \item \code{sf} or \code{sfc} polygons object
#' }
#' @param bbox supply a bounding box instead of a clipping layer to extract from
#' the target layer. Supply as a numeric vector: \code{c(minX, minY, maxX, maxY)}.
#' @param remove_slivers Remove tiny sliver polygons created by clipping. (Default \code{FALSE})
-#' @inheritParams apply_mapshaper_commands
+#' @inheritDotParams apply_mapshaper_commands force_FC sys sys_mem quiet
#'
#' @return clipped target in the same class as the input target
#'
#' @examples
#'
#' if (rmapshaper:::check_v8_major_version() >= 6L) {
-#' library(geojsonio, quietly = TRUE)
-#' library(sp)
+#' library(geojsonsf, quietly = TRUE)
+#' library(sf)
#'
#' poly <- structure("{\"type\":\"FeatureCollection\",
#' \"features\":[{\"type\":\"Feature\",\"properties\":{},
@@ -39,8 +37,8 @@
#' [52.0329,-49.5677],[50.1747,-52.1814],[49.0098,-52.3641],
#' [52.7068,-45.7639],[43.2278,-47.1908],[48.4755,-45.1388],
#' [50.327,-43.5207],[48.0804,-41.2784],[49.6307,-40.6159],
-#' [52.8658,-44.7219]]]}}]}", class = c("json", "geo_json"))
-#' poly <- geojson_sp(poly)
+#' [52.8658,-44.7219]]]}}]}", class = c("geojson", "json"))
+#' poly <- geojson_sf(poly)
#' plot(poly)
#'
#' clip_poly <- structure('{
@@ -58,8 +56,8 @@
#' ]
#' ]
#' }
-#' }', class = c("json", "geo_json"))
-#' clip_poly <- geojson_sp(clip_poly)
+#' }', class = c("geojson", "json"))
+#' clip_poly <- geojson_sf(clip_poly)
#' plot(clip_poly)
#'
#' out <- ms_clip(poly, clip_poly)
@@ -67,70 +65,60 @@
#' }
#'
#' @export
-ms_clip <- function(target, clip = NULL, bbox = NULL, remove_slivers = FALSE,
- force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- if (!is.logical(force_FC)) stop("force_FC must be TRUE or FALSE")
+ms_clip <- function(target, clip = NULL, bbox = NULL, remove_slivers = FALSE, ...) {
stop_for_old_v8()
UseMethod("ms_clip")
}
#' @export
ms_clip.character <- function(target, clip = NULL, bbox = NULL,
- remove_slivers = FALSE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ remove_slivers = FALSE, ...) {
target <- check_character_input(target)
clip_erase_json(target = target, overlay_layer = clip, type = "clip",
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ remove_slivers = remove_slivers, bbox = bbox, ...)
}
#' @export
-ms_clip.geo_json <- function(target, clip = NULL, bbox = NULL, remove_slivers = FALSE,
- force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ms_clip.json <- function(target, clip = NULL, bbox = NULL, remove_slivers = FALSE, ...) {
clip_erase_json(target = target, overlay_layer = clip, type = "clip",
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
-}
-
-#' @export
-ms_clip.geo_list <- function(target, clip = NULL, bbox = NULL, remove_slivers = FALSE,
- force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- clip_erase_geo_list(target = target, overlay_layer = clip, type = "clip",
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ remove_slivers = remove_slivers, bbox = bbox, ...)
}
#' @export
ms_clip.SpatialPolygons <- function(target, clip = NULL, bbox = NULL,
- remove_slivers = FALSE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ remove_slivers = FALSE, ...) {
clip_erase_sp(target = target, overlay_layer = clip, type = "clip",
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ remove_slivers = remove_slivers, bbox = bbox, ...)
}
#' @export
ms_clip.SpatialLines <- function(target, clip = NULL, bbox = NULL,
- remove_slivers = FALSE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ remove_slivers = FALSE, ...) {
clip_erase_sp(target = target, overlay_layer = clip, type = "clip",
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ remove_slivers = remove_slivers, bbox = bbox, ...)
}
#' @export
ms_clip.SpatialPoints <- function(target, clip = NULL, bbox = NULL,
- remove_slivers = FALSE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ remove_slivers = FALSE, ...) {
clip_erase_sp(target = target, overlay_layer = clip, type = "clip",
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ remove_slivers = remove_slivers, bbox = bbox, ...)
}
#' @export
ms_clip.sf <- function(target, clip = NULL, bbox = NULL,
- remove_slivers = FALSE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ remove_slivers = FALSE, ...) {
clip_erase_sf(target = target, overlay_layer = clip, type = "clip",
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ remove_slivers = remove_slivers, bbox = bbox, ...)
}
#' @export
ms_clip.sfc <- function(target, clip = NULL, bbox = NULL,
- remove_slivers = FALSE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ remove_slivers = FALSE, ...) {
clip_erase_sf(target = target, overlay_layer = clip, type = "clip",
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ remove_slivers = remove_slivers, bbox = bbox, ...)
}
#' Remove features or portions of features that fall inside a specified area
@@ -140,25 +128,23 @@ ms_clip.sfc <- function(target, clip = NULL, bbox = NULL,
#' @param target the target layer from which to remove portions. One of:
#' \itemize{
#' \item \code{geo_json} or \code{character} points, lines, or polygons;
-#' \item \code{geo_list} points, lines, or polygons;
#' \item \code{SpatialPolygons}, \code{SpatialLines}, \code{SpatialPoints}
#' }
#' @param erase the erase layer (polygon). One of:
#' \itemize{
#' \item \code{geo_json} or \code{character} polygons;
-#' \item \code{geo_list} polygons;
#' \item \code{SpatialPolygons*}
#' }
#' @param bbox supply a bounding box instead of an erasing layer to remove from
#' the target layer. Supply as a numeric vector: \code{c(minX, minY, maxX, maxY)}.
#' @param remove_slivers Remove tiny sliver polygons created by erasing. (Default \code{FALSE})
-#' @inheritParams apply_mapshaper_commands
+#' @inheritDotParams apply_mapshaper_commands force_FC sys sys_mem quiet
#'
#' @return erased target in the same format as the input target
#' @examples
#' if (rmapshaper:::check_v8_major_version() >= 6L) {
-#' library(geojsonio, quietly = TRUE)
-#' library(sp)
+#' library(geojsonsf, quietly = TRUE)
+#' library(sf)
#'
#' points <- structure("{\"type\":\"FeatureCollection\",
#' \"features\":[{\"type\":\"Feature\",\"properties\":{},
@@ -175,8 +161,8 @@ ms_clip.sfc <- function(target, clip = NULL, bbox = NULL,
#' {\"type\":\"Point\",\"coordinates\":[61.0835,-40.7529]}},
#' {\"type\":\"Feature\",\"properties\":{},\"geometry\":
#' {\"type\":\"Point\",\"coordinates\":[58.0202,-43.634]}}]}",
-#' class = c("json", "geo_json"))
-#' points <- geojson_sp(points)
+#' class = c("geojson", "json"))
+#' points <- geojson_sf(points)
#' plot(points)
#'
#' erase_poly <- structure('{
@@ -194,8 +180,8 @@ ms_clip.sfc <- function(target, clip = NULL, bbox = NULL,
#' ]
#' ]
#' }
-#' }', class = c("json", "geo_json"))
-#' erase_poly <- geojson_sp(erase_poly)
+#' }', class = c("geojson", "json"))
+#' erase_poly <- geojson_sf(erase_poly)
#'
#' out <- ms_erase(points, erase_poly)
#' plot(out, add = TRUE)
@@ -203,73 +189,67 @@ ms_clip.sfc <- function(target, clip = NULL, bbox = NULL,
#'
#'@export
ms_erase <- function(target, erase = NULL, bbox = NULL,
- remove_slivers = FALSE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- if (!is.logical(force_FC)) stop("force_FC must be TRUE or FALSE")
+ remove_slivers = FALSE, ...) {
stop_for_old_v8()
UseMethod("ms_erase")
}
#' @export
ms_erase.character <- function(target, erase = NULL, bbox = NULL,
- remove_slivers = FALSE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ remove_slivers = FALSE, ...) {
target <- check_character_input(target)
clip_erase_json(target = target, overlay_layer = erase, type = "erase",
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ remove_slivers = remove_slivers, bbox = bbox, ...)
}
#' @export
-ms_erase.geo_json <- function(target, erase = NULL, bbox = NULL,
- remove_slivers = FALSE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ms_erase.json <- function(target, erase = NULL, bbox = NULL,
+ remove_slivers = FALSE, ...) {
clip_erase_json(target = target, overlay_layer = erase, type = "erase",
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
-}
-
-#' @export
-ms_erase.geo_list <- function(target, erase = NULL, bbox = NULL,
- remove_slivers = FALSE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- clip_erase_geo_list(target = target, overlay_layer = erase, type = "erase",
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ remove_slivers = remove_slivers, bbox = bbox, ...)
}
#' @export
ms_erase.SpatialPolygons <- function(target, erase = NULL, bbox = NULL,
- remove_slivers = FALSE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ remove_slivers = FALSE, ...) {
clip_erase_sp(target = target, overlay_layer = erase, type = "erase",
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ remove_slivers = remove_slivers, bbox = bbox, ...)
}
#' @export
ms_erase.SpatialLines <- function(target, erase = NULL, bbox = NULL,
- remove_slivers = FALSE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ remove_slivers = FALSE, ...) {
clip_erase_sp(target = target, overlay_layer = erase, type = "erase",
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ remove_slivers = remove_slivers, bbox = bbox, ...)
}
#' @export
ms_erase.SpatialPoints <- function(target, erase = NULL, bbox = NULL,
- remove_slivers = FALSE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ remove_slivers = FALSE, ...) {
clip_erase_sp(target = target, overlay_layer = erase, type = "erase",
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ remove_slivers = remove_slivers, bbox = bbox, ...)
}
#' @export
ms_erase.sf <- function(target, erase = NULL, bbox = NULL,
- remove_slivers = FALSE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ remove_slivers = FALSE, ...) {
clip_erase_sf(target = target, overlay_layer = erase, type = "erase",
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ remove_slivers = remove_slivers, bbox = bbox, ...)
}
#' @export
ms_erase.sfc <- function(target, erase = NULL, bbox = NULL,
- remove_slivers = FALSE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ remove_slivers = FALSE, ...) {
clip_erase_sf(target = target, overlay_layer = erase, type = "erase",
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ remove_slivers = remove_slivers, bbox = bbox, ...)
}
clip_erase_json <- function(target, overlay_layer, bbox, remove_slivers, type,
- force_FC, sys, sys_mem) {
+ force_FC = TRUE, sys = FALSE,
+ sys_mem = getOption("mapshaper.sys_mem", default = 8),
+ quiet = getOption("mapshaper.sys_quiet", default = FALSE)) {
check_overlay_bbox(overlay_layer = overlay_layer, bbox = bbox, type = type)
@@ -278,39 +258,23 @@ clip_erase_json <- function(target, overlay_layer, bbox, remove_slivers, type,
}
mapshaper_clip_erase(target_layer = target, overlay_layer = overlay_layer, type = type,
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
-}
-
-clip_erase_geo_list <- function(target, overlay_layer, bbox, type,
- remove_slivers, force_FC, sys, sys_mem) {
-
- check_overlay_bbox(overlay_layer = overlay_layer, bbox = bbox, type = type)
-
- if (is.null(bbox)) {
- if (!is(overlay_layer, "geo_list")) stop("both target and ", type, " must be class geo_list")
- overlay_layer <- geo_list_to_json(overlay_layer)
- }
- target <- geo_list_to_json(target)
- ret <- clip_erase_json(target = target, overlay_layer = overlay_layer, type = type,
- remove_slivers = remove_slivers, bbox = bbox, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
- geojsonio::geojson_list(ret)
+ remove_slivers = remove_slivers, bbox = bbox,
+ force_FC = force_FC, sys = sys, sys_mem = sys_mem, quiet = quiet)
}
-clip_erase_sp <- function(target, overlay_layer, bbox, type, remove_slivers, force_FC, sys, sys_mem) {
+clip_erase_sp <- function(target, overlay_layer, bbox, type, remove_slivers,
+ force_FC = TRUE, sys = FALSE,
+ sys_mem = getOption("mapshaper.sys_mem", default = 8),
+ quiet = getOption("mapshaper.sys_quiet", default = FALSE)) {
check_overlay_bbox(overlay_layer = overlay_layer, bbox = bbox, type = type)
- target_proj <- slot(target, "proj4string")
+ target_proj <- methods::slot(target, "proj4string")
if (is.null(bbox)) {
if (!is(overlay_layer, "SpatialPolygons")) stop(type, " must be of class SpatialPolygons or SpatialPolygonsDataFrame")
if (!sp::identicalCRS(target, overlay_layer)) {
- warning("target and ", type, " do not have identical CRS. Transforming ",
- type, " to target CRS")
- if (!requireNamespace("rgdal")) {
- stop("You need the rgdal package to use transform non-equivalent projections.")
- }
- overlay_layer <- sp::spTransform(overlay_layer, target_proj)
+ stop("target and ", type, " do not have identical CRS.", call. = FALSE)
}
overlay_geojson <- sp_to_GeoJSON(overlay_layer, file = sys)
}
@@ -332,7 +296,10 @@ clip_erase_sp <- function(target, overlay_layer, bbox, type, remove_slivers, for
ret
}
-clip_erase_sf <- function(target, overlay_layer, bbox, type, remove_slivers, force_FC, sys, sys_mem) {
+clip_erase_sf <- function(target, overlay_layer, bbox, type, remove_slivers,
+ force_FC = TRUE, sys = FALSE,
+ sys_mem = getOption("mapshaper.sys_mem", default = 8),
+ quiet = getOption("mapshaper.sys_quiet", default = FALSE)) {
check_overlay_bbox(overlay_layer = overlay_layer, bbox = bbox, type = type)
@@ -348,10 +315,8 @@ clip_erase_sf <- function(target, overlay_layer, bbox, type, remove_slivers, for
!all(sf::st_is(overlay_layer, c("POLYGON", "MULTIPOLYGON")))) {
stop(type, " must be an sf or sfc object with POLYGON or MULTIPLOYGON geometry")
}
- if (sf::st_crs(target) != sf::st_crs(overlay_layer)) {
- warning("target and ", type, " do not have identical CRS. Transforming ",
- type, " to target CRS")
- overlay_layer <- sf::st_transform(overlay_layer, target_proj)
+ if (target_proj != sf::st_crs(overlay_layer)) {
+ stop("target and ", type, " do not have identical CRS.", call. = FALSE)
}
overlay_geojson <- sf_to_GeoJSON(overlay_layer, file = sys)
}
@@ -394,7 +359,9 @@ check_overlay_bbox <- function(overlay_layer, bbox, type) {
}
mapshaper_clip_erase <- function(target_layer, overlay_layer, bbox, type,
- remove_slivers, force_FC, sys, sys_mem) {
+ remove_slivers, force_FC = TRUE, sys = FALSE,
+ sys_mem = getOption("mapshaper.sys_mem", default = 8),
+ quiet = getOption("mapshaper.sys_quiet", default = FALSE)) {
remove_slivers <- ifelse(remove_slivers, "remove-slivers", "")
@@ -402,13 +369,13 @@ mapshaper_clip_erase <- function(target_layer, overlay_layer, bbox, type,
if (!is.null(bbox)) {
cmd <- paste0("-", type, " bbox=",paste0(bbox, collapse = ","), " ",
remove_slivers)
- out <- apply_mapshaper_commands(target_layer, cmd, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ out <- apply_mapshaper_commands(target_layer, cmd, force_FC = force_FC, sys = sys, sys_mem = sys_mem, quiet = quiet)
} else if (!is.null(overlay_layer)) {
if (sys) {
on.exit(unlink(c(target_layer, overlay_layer)), add = TRUE)
cmd <- paste0("-", type)
- out <- sys_mapshaper(data = target_layer, data2 = overlay_layer, command = cmd, sys_mem = sys_mem)
+ out <- sys_mapshaper(data = target_layer, data2 = overlay_layer, command = cmd, sys_mem = sys_mem, quiet = quiet)
} else {
ms <- ms_make_ctx()
diff --git a/R/dissolve.R b/R/dissolve.R
index 3b5c34f..dd8d144 100644
--- a/R/dissolve.R
+++ b/R/dissolve.R
@@ -6,7 +6,6 @@
#' @param input spatial object to dissolve. One of:
#' \itemize{
#' \item \code{geo_json} or \code{character} points or polygons;
-#' \item \code{geo_list} points or polygons;
#' \item \code{SpatialPolygons}, or \code{SpatialPoints}
#' }
#' @param snap Snap together vertices within a small distance threshold to fix
@@ -16,13 +15,13 @@
#' @param copy_fields fields to copy. The first instance of each field will be
#' copied to the aggregated feature.
#' @param weight Name of an attribute field for generating weighted centroids (points only).
-#' @inheritParams apply_mapshaper_commands
+#' @inheritDotParams apply_mapshaper_commands force_FC sys sys_mem quiet
#'
#' @return the same class as the input
#'
#' @examples
-#' library(geojsonio)
-#' library(sp)
+#' library(geojsonsf)
+#' library(sf)
#'
#' poly <- structure('{"type":"FeatureCollection",
#' "features":[
@@ -35,100 +34,85 @@
#' "properties":{"a": 5, "b": 3},
#' "geometry":{"type":"Polygon","coordinates":[[
#' [100,0],[100,1],[101,1],[101,0],[100,0]
-#' ]]}}]}', class = c("json", "geo_json"))
-#' poly <- geojson_sp(poly)
+#' ]]}}]}', class = c("geojson", "json"))
+#' poly <- geojson_sf(poly)
#' plot(poly)
#' length(poly)
-#' poly@data
+#' poly
#'
#' # Dissolve the polygon
#' out <- ms_dissolve(poly)
#' plot(out)
#' length(out)
-#' out@data
+#' out
#'
#' # Dissolve and summing columns
#' out <- ms_dissolve(poly, sum_fields = c("a", "b"))
#' plot(out)
-#' out@data
+#' out
#'
#' @export
ms_dissolve <- function(input, field = NULL, sum_fields = NULL, copy_fields = NULL,
- weight = NULL, snap = TRUE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ weight = NULL, snap = TRUE, ...) {
UseMethod("ms_dissolve")
}
#' @export
ms_dissolve.character <- function(input, field = NULL, sum_fields = NULL, copy_fields = NULL,
- weight = NULL, snap = TRUE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ weight = NULL, snap = TRUE, ...) {
input <- check_character_input(input)
call <- make_dissolve_call(field = field, sum_fields = sum_fields, weight = weight,
copy_fields = copy_fields, snap = snap)
- apply_mapshaper_commands(data = input, command = call, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ apply_mapshaper_commands(data = input, command = call, ...)
}
#' @export
-ms_dissolve.geo_json <- function(input, field = NULL, sum_fields = NULL, copy_fields = NULL,
- weight = NULL, snap = TRUE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
-
- call <- make_dissolve_call(field = field, sum_fields = sum_fields, weight = weight,
- copy_fields = copy_fields, snap = snap)
-
- apply_mapshaper_commands(data = input, command = call, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
-}
-
-#' @export
-ms_dissolve.geo_list <- function(input, field = NULL, sum_fields = NULL, copy_fields = NULL,
- weight = NULL, snap = TRUE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
-
+ms_dissolve.json <- function(input, field = NULL, sum_fields = NULL, copy_fields = NULL,
+ weight = NULL, snap = TRUE, ...) {
call <- make_dissolve_call(field = field, sum_fields = sum_fields, weight = weight,
copy_fields = copy_fields, snap = snap)
- geojson <- geo_list_to_json(input)
-
- ret <- apply_mapshaper_commands(data = geojson, command = call, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
-
- geojsonio::geojson_list(ret)
+ apply_mapshaper_commands(data = input, command = call, ...)
}
#' @export
ms_dissolve.SpatialPolygons <- function(input, field = NULL, sum_fields = NULL, copy_fields = NULL,
- weight = NULL, snap = TRUE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ weight = NULL, snap = TRUE, ...) {
dissolve_sp(input = input, field = field, sum_fields = sum_fields, copy_fields = copy_fields,
- weight = weight, snap = snap, sys = sys, sys_mem = sys_mem)
+ weight = weight, snap = snap, ...)
}
#' @export
ms_dissolve.SpatialPoints <- function(input, field = NULL, sum_fields = NULL, copy_fields = NULL,
- weight = NULL, snap = TRUE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ weight = NULL, snap = TRUE, ...) {
dissolve_sp(input = input, field = field, sum_fields = sum_fields, copy_fields = copy_fields,
- weight = weight, snap = snap, sys = sys, sys_mem = sys_mem)
+ weight = weight, snap = snap, ...)
}
#' @export
ms_dissolve.sf <- function(input, field = NULL, sum_fields = NULL, copy_fields = NULL,
- weight = NULL, snap = TRUE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ weight = NULL, snap = TRUE, ...) {
if (!is.null(weight) && !(weight %in% names(input))) {
stop("specified 'weight' column not present in input data", call. = FALSE)
}
dissolve_sf(input = input, field = field, sum_fields = sum_fields, copy_fields = copy_fields,
- weight = weight, snap = snap, sys = sys, sys_mem = sys_mem)
+ weight = weight, snap = snap, ...)
}
#' @export
ms_dissolve.sfc <- function(input, field = NULL, sum_fields = NULL, copy_fields = NULL,
- weight = NULL, snap = TRUE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ weight = NULL, snap = TRUE, ...) {
if (!is.null(weight)) {
warning("'weight' cannot be used with sfc objects. Ignoring it and proceeding...")
}
dissolve_sf(input = input, field = field, sum_fields = sum_fields, copy_fields = copy_fields,
- weight = NULL, snap = snap, sys = sys, sys_mem = sys_mem)
+ weight = NULL, snap = snap, ...)
}
make_dissolve_call <- function(field, sum_fields, copy_fields, weight, snap) {
@@ -158,7 +142,7 @@ make_dissolve_call <- function(field, sum_fields, copy_fields, weight, snap) {
call
}
-dissolve_sp <- function(input, field, sum_fields, copy_fields, weight, snap, sys, sys_mem) {
+dissolve_sp <- function(input, field, sum_fields, copy_fields, weight, snap, ...) {
if (!inherits(input, "SpatialPointsDataFrame") && !is.null(weight)) {
stop("weight arguments only applies to points with attributes", call. = FALSE)
@@ -171,10 +155,10 @@ dissolve_sp <- function(input, field, sum_fields, copy_fields, weight, snap, sys
call <- make_dissolve_call(field = field, sum_fields = sum_fields, copy_fields = copy_fields,
weight = weight, snap = snap)
- ms_sp(input = input, call = call, sys = sys, sys_mem = sys_mem)
+ ms_sp(input = input, call = call, ...)
}
-dissolve_sf <- function(input, field, sum_fields, copy_fields, weight, snap, sys, sys_mem) {
+dissolve_sf <- function(input, field, sum_fields, copy_fields, weight, snap, ...) {
if (!all(sf::st_is(input, c("POINT", "MULTIPOINT", "POLYGON", "MULTIPOLYGON")))) {
stop("ms_dissolve only works with (MULTI)POINT or (MULTI)POLYGON", call. = FALSE)
@@ -187,5 +171,5 @@ dissolve_sf <- function(input, field, sum_fields, copy_fields, weight, snap, sys
call <- make_dissolve_call(field = field, sum_fields = sum_fields, copy_fields = copy_fields,
weight = weight, snap = snap)
- ms_sf(input = input, call = call, sys = sys, sys_mem = sys_mem)
+ ms_sf(input = input, call = call, ...)
}
diff --git a/R/drop_null_geometries.R b/R/drop_null_geometries.R
index bfb91de..a4f7680 100644
--- a/R/drop_null_geometries.R
+++ b/R/drop_null_geometries.R
@@ -1,8 +1,8 @@
-#' Drop features from a \code{geo_list} or \code{geo_json} FeatureCollection with null geometries
+#' Drop features from a \code{geo_json} FeatureCollection with null geometries
#'
-#' @param x a \code{geo_list} or \code{geo_json} FeatureCollection
+#' @param x a \code{geo_json} FeatureCollection
#'
-#' @return a \code{geo_list} or \code{geo_json} FeatureCollection with Features with null geometries
+#' @return a \code{geo_json} FeatureCollection with Features with null geometries
#' removed
#' @export
drop_null_geometries <- function(x) {
@@ -10,32 +10,9 @@ drop_null_geometries <- function(x) {
}
#' @export
-drop_null_geometries.geo_json <- function(x) {
+drop_null_geometries.json <- function(x) {
apply_mapshaper_commands(x, "-filter remove-empty", TRUE)
}
#' @export
-drop_null_geometries.character <- drop_null_geometries.geo_json
-
-#' @export
-drop_null_geometries.geo_list <- function(x) {
- # Using -filter mapshaper command
- geojson <- geo_list_to_json(x)
- ret <- drop_null_geometries.geo_json(geojson)
- geojsonio::geojson_list(ret)
-
- ## Use the list directly - it's faster
- # drop_null_geometries_list(x)
-}
-
-# drop_null_geometries_list <- function(x) {
-# if (x$type != "FeatureCollection") {
-# stop("type must be a FeatureCollection")
-# }
-#
-# features_to_keep <- vapply(x$features,
-# function(y) !is.null(y$geometry),
-# logical(1))
-# x$features <- x$features[features_to_keep]
-# x
-# }
+drop_null_geometries.character <- drop_null_geometries.json
diff --git a/R/explode.R b/R/explode.R
index 5f282a6..8684161 100644
--- a/R/explode.R
+++ b/R/explode.R
@@ -8,76 +8,63 @@
#' @param input One of:
#' \itemize{
#' \item \code{geo_json} or \code{character} multipart lines, or polygons;
-#' \item \code{geo_list} multipart lines, or polygons;
#' \item multipart \code{SpatialPolygons}, \code{SpatialLines};
#' \item \code{sf} or \code{sfc} multipart lines, or polygons object
#' }
-#' @inheritParams apply_mapshaper_commands
+#' @inheritDotParams apply_mapshaper_commands force_FC sys sys_mem quiet
#'
#' @return same class as input
#'
#' @examples
-#' library(geojsonio)
-#' library(sp)
+#' library(geojsonsf)
+#' library(sf)
#'
-#' poly <- structure("{\"type\":\"FeatureCollection\",\"crs\":
-#' {\"type\":\"name\",\"properties\":{\"name\":
-#' \"urn:ogc:def:crs:OGC:1.3:CRS84\"}},\"features\":
+#' poly <- "{\"type\":\"FeatureCollection\",\"features\":
#' [\n{\"type\":\"Feature\",\"geometry\":{\"type\":
#' \"MultiPolygon\",\"coordinates\":[[[[102,2],[102,3],
#' [103,3],[103,2],[102,2]]],[[[100,0],[100,1],[101,1],
-#' [101,0],[100,0]]]]},\"properties\":{\"rmapshaperid\":0}}\n]}",
-#' class = c("json", "geo_json"))
+#' [101,0],[100,0]]]]},\"properties\":{\"a\":0}}\n]}"
#'
-#' poly <- geojson_sp(poly)
+#' poly <- geojson_sf(poly)
#' plot(poly)
#' length(poly)
-#' poly@data
+#' poly
#'
#' # Explode the polygon
#' out <- ms_explode(poly)
#' plot(out)
#' length(out)
-#' out@data
+#' out
#'
#' @export
-ms_explode <- function(input, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ms_explode <- function(input, ...) {
UseMethod("ms_explode")
}
#' @export
-ms_explode.character <- function(input, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ms_explode.character <- function(input, ...) {
input <- check_character_input(input)
- apply_mapshaper_commands(data = input, command = "-explode", force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ apply_mapshaper_commands(data = input, command = "-explode", ...)
}
#' @export
-ms_explode.geo_json <- function(input, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- apply_mapshaper_commands(data = input, command = "-explode", force_FC = force_FC, sys = sys, sys_mem = sys_mem)
-}
-
-#' @export
-ms_explode.geo_list <- function(input, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- geojson <- geo_list_to_json(input)
-
- ret <- apply_mapshaper_commands(data = geojson, command = "-explode", force_FC = force_FC, sys = sys, sys_mem = sys_mem)
-
- geojsonio::geojson_list(ret)
+ms_explode.json <- function(input, ...) {
+ apply_mapshaper_commands(data = input, command = "-explode", ...)
}
## The method using mapshaper's explode works, but is waaaay slower than
## sp::disaggregate due to converstion to/from geojson
#' @export
-ms_explode.SpatialPolygons <- function(input, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- explode_sp(input, sys = sys, sys_mem = sys_mem)
+ms_explode.SpatialPolygons <- function(input, ...) {
+ explode_sp(input, ...)
}
#' @export
-ms_explode.SpatialLines <- function(input, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- explode_sp(input, sys = sys, sys_mem = sys_mem)
+ms_explode.SpatialLines <- function(input, ...) {
+ explode_sp(input, ...)
}
# #' @describeIn ms_explode Method for SpatialPoints
@@ -86,20 +73,20 @@ ms_explode.SpatialLines <- function(input, force_FC = TRUE, sys = FALSE, sys_mem
# explode_sp(input, force_FC)
# }
-explode_sp <- function(input, sys, sys_mem) {
- ms_sp(input = input, call = "-explode", sys = sys, sys_mem = sys_mem)
+explode_sp <- function(input, ...) {
+ ms_sp(input = input, call = "-explode", ...)
}
#' @export
-ms_explode.sf <- function(input, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- explode_sf(input = input, sys = sys, sys_mem = sys_mem)
+ms_explode.sf <- function(input, ...) {
+ explode_sf(input = input, ...)
}
#' @export
-ms_explode.sfc <- function(input, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- explode_sf(input = input, sys = sys, sys_mem = sys_mem)
+ms_explode.sfc <- function(input, ...) {
+ explode_sf(input = input, ...)
}
-explode_sf <- function(input, sys, sys_mem) {
- ms_sf(input = input, call = "-explode", sys = sys, sys_mem = sys_mem)
+explode_sf <- function(input, ...) {
+ ms_sf(input = input, call = "-explode", ...)
}
diff --git a/R/filter_fields.R b/R/filter_fields.R
index 3191f8e..e02f272 100644
--- a/R/filter_fields.R
+++ b/R/filter_fields.R
@@ -5,83 +5,71 @@
#' @param input spatial object to filter fields on. One of:
#' \itemize{
#' \item \code{geo_json} or \code{character} points, lines, or polygons;
-#' \item \code{geo_list} points, lines, or polygons;
#' \item \code{SpatialPolygonsDataFrame}, \code{SpatialLinesDataFrame}, \code{SpatialPointsDataFrame};
#' \item \code{sf} object
#' }
#' @param fields character vector of fields to retain.
-#' @inheritParams apply_mapshaper_commands
+#' @inheritDotParams apply_mapshaper_commands sys sys_mem quiet
#'
#' @return object with only specified attributes retained, in the same class as
#' the input
#'
#' @examples
-#' library(geojsonio)
-#' library(sp)
+#' library(geojsonsf)
+#' library(sf)
#'
#' poly <- structure("{\"type\":\"FeatureCollection\",
#' \"features\":[{\"type\":\"Feature\",
#' \"properties\":{\"a\": 1, \"b\":2, \"c\": 3},
#' \"geometry\":{\"type\":\"Polygon\",
#' \"coordinates\":[[[102,2],[102,4],[104,4],[104,2],[102,2]]]}}]}",
-#' class = c("json", "geo_json"))
-#' poly <- geojson_sp(poly)
-#' poly@data
+#' class = c("geojson", "json"))
+#' poly <- geojson_sf(poly)
+#' poly
#'
#' # Filter (keep) fields a and b, drop c
#' out <- ms_filter_fields(poly, c("a", "b"))
-#' out@data
+#' out
#'
#' @export
-ms_filter_fields <- function(input, fields, sys = FALSE, sys_mem = 8) {
+ms_filter_fields <- function(input, fields, ...) {
if (!is.character(fields)) stop("fields must be a character vector")
UseMethod("ms_filter_fields")
}
#' @export
-ms_filter_fields.character <- function(input, fields, sys = FALSE, sys_mem = 8) {
+ms_filter_fields.character <- function(input, fields, ...) {
input <- check_character_input(input)
cmd <- make_filterfields_call(fields)
- apply_mapshaper_commands(data = input, command = cmd, force_FC = FALSE, sys = sys, sys_mem = sys_mem)
+ apply_mapshaper_commands(data = input, command = cmd, force_FC = FALSE, ...)
}
#' @export
-ms_filter_fields.geo_json <- function(input, fields, sys = FALSE, sys_mem = 8) {
+ms_filter_fields.json <- function(input, fields, ...) {
cmd <- make_filterfields_call(fields)
- apply_mapshaper_commands(data = input, command = cmd, force_FC = FALSE, sys = sys, sys_mem = sys_mem)
+ apply_mapshaper_commands(data = input, command = cmd, force_FC = FALSE, ...)
}
#' @export
-ms_filter_fields.geo_list <- function(input, fields, sys = FALSE, sys_mem = 8) {
- geojson <- geo_list_to_json(input)
-
- cmd <- make_filterfields_call(fields)
-
- ret <- apply_mapshaper_commands(data = geojson, command = cmd, force_FC = FALSE, sys = sys, sys_mem = sys_mem)
-
- geojsonio::geojson_list(ret)
-}
-
-#' @export
-ms_filter_fields.SpatialPolygonsDataFrame <- function(input, fields, sys = FALSE, sys_mem = 8) {
- ms_filter_fields_sp(input, fields, sys = sys, sys_mem = sys_mem)
+ms_filter_fields.SpatialPolygonsDataFrame <- function(input, fields, ...) {
+ ms_filter_fields_sp(input, fields, ...)
}
#' @export
-ms_filter_fields.SpatialPointsDataFrame <- function(input, fields, sys = FALSE, sys_mem = 8) {
- ms_filter_fields_sp(input, fields, sys = sys, sys_mem = sys_mem)
+ms_filter_fields.SpatialPointsDataFrame <- function(input, fields, ...) {
+ ms_filter_fields_sp(input, fields, ...)
}
#' @export
-ms_filter_fields.SpatialLinesDataFrame <- function(input, fields, sys = FALSE, sys_mem = 8) {
- ms_filter_fields_sp(input, fields, sys = sys, sys_mem = sys_mem)
+ms_filter_fields.SpatialLinesDataFrame <- function(input, fields, ...) {
+ ms_filter_fields_sp(input, fields, ...)
}
#' @export
-ms_filter_fields.sf <- function(input, fields, sys = FALSE, sys_mem = 8) {
+ms_filter_fields.sf <- function(input, fields, ...) {
if (!all(fields %in% names(input))) {
stop("Not all fields are in input")
}
@@ -93,7 +81,7 @@ ms_filter_fields.sf <- function(input, fields, sys = FALSE, sys_mem = 8) {
input[, fields, drop = FALSE]
}
-ms_filter_fields_sp <- function(input, fields, sys, sys_mem) {
+ms_filter_fields_sp <- function(input, fields, ...) {
# cmd <- make_filterfields_call(fields)
#
diff --git a/R/filter_islands.R b/R/filter_islands.R
index 9e140b2..68e5022 100644
--- a/R/filter_islands.R
+++ b/R/filter_islands.R
@@ -6,7 +6,6 @@
#' @param input spatial object to filter. One of:
#' \itemize{
#' \item \code{geo_json} or \code{character} polygons;
-#' \item \code{geo_list} polygons;
#' \item \code{SpatialPolygons*};
#' \item \code{sf} or \code{sfc} polygons object
#' }
@@ -17,14 +16,14 @@
#' @param drop_null_geometries should features with empty geometries be dropped?
#' Default \code{TRUE}. Ignored for \code{SpatialPolyons*}, as it is always
#' \code{TRUE}.
-#' @inheritParams apply_mapshaper_commands
+#' @inheritDotParams apply_mapshaper_commands force_FC sys sys_mem quiet
#'
#' @return object with only specified features retained, in the same class as
#' the input
#'
#' @examples
-#' library(geojsonio)
-#' library(sp)
+#' library(geojsonsf)
+#' library(sf)
#'
#' poly <- structure("{\"type\":\"FeatureCollection\",
#' \"features\":[{\"type\":\"Feature\",\"properties\":{},
@@ -36,9 +35,9 @@
#' {\"type\":\"Feature\",\"properties\":{},
#' \"geometry\":{\"type\":\"Polygon\",
#' \"coordinates\":[[[100,0],[100,1],[101,1],[101,0],[100,0]]]}}]}",
-#' class = c("json", "geo_json"))
+#' class = c("geojson", "json"))
#'
-#' poly <- geojson_sp(poly)
+#' poly <- geojson_sf(poly)
#' plot(poly)
#'
#' out <- ms_filter_islands(poly, min_area = 12391399903)
@@ -46,69 +45,55 @@
#'
#' @export
ms_filter_islands <- function(input, min_area = NULL, min_vertices = NULL, drop_null_geometries = TRUE,
- force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ ...) {
if (!is.null(min_area) && !is.numeric(min_area)) stop("min_area must be numeric")
if (!is.null(min_vertices) && !is.numeric(min_vertices)) stop("min_vertices must be numeric")
if (!is.logical(drop_null_geometries)) stop("drop_null_geometries must be TRUE or FALSE")
- if (!is.logical(force_FC)) stop("force_FC must be TRUE or FALSE")
UseMethod("ms_filter_islands")
}
#' @export
ms_filter_islands.character <- function(input, min_area = NULL, min_vertices = NULL, drop_null_geometries = TRUE,
- force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ ...) {
input <- check_character_input(input)
cmd <- make_filterislands_call(min_area = min_area, min_vertices = min_vertices,
drop_null_geometries = drop_null_geometries)
- apply_mapshaper_commands(data = input, command = cmd, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ apply_mapshaper_commands(data = input, command = cmd, ...)
}
#' @export
-ms_filter_islands.geo_json <- function(input, min_area = NULL, min_vertices = NULL, drop_null_geometries = TRUE,
- force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ms_filter_islands.json <- function(input, min_area = NULL, min_vertices = NULL, drop_null_geometries = TRUE,
+ ...) {
cmd <- make_filterislands_call(min_area = min_area, min_vertices = min_vertices,
drop_null_geometries = drop_null_geometries)
- apply_mapshaper_commands(data = input, command = cmd, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
-}
-
-#' @export
-ms_filter_islands.geo_list <- function(input, min_area = NULL, min_vertices = NULL, drop_null_geometries = TRUE,
- force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- geojson <- geo_list_to_json(input)
-
- cmd <- make_filterislands_call(min_area = min_area, min_vertices = min_vertices,
- drop_null_geometries = drop_null_geometries)
-
- ret <- apply_mapshaper_commands(data = geojson, command = cmd, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
-
- geojsonio::geojson_list(ret)
+ apply_mapshaper_commands(data = input, command = cmd, ...)
}
#' @export
ms_filter_islands.SpatialPolygons <- function(input, min_area = NULL, min_vertices = NULL, drop_null_geometries = TRUE,
- force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- ms_filter_islands_sp(input, min_area = min_area, min_vertices = min_vertices, sys = sys, sys_mem = sys_mem)
+ ...) {
+ ms_filter_islands_sp(input, min_area = min_area, min_vertices = min_vertices, ...)
}
-ms_filter_islands_sp <- function(input, min_area = NULL, min_vertices = NULL, sys, sys_mem) {
+ms_filter_islands_sp <- function(input, min_area = NULL, min_vertices = NULL, ...) {
cmd <- make_filterislands_call(min_area = min_area, min_vertices = min_vertices,
drop_null_geometries = TRUE)
- ms_sp(input = input, call = cmd, sys = sys, sys_mem = sys_mem)
+ ms_sp(input = input, call = cmd, ...)
}
#' @export
ms_filter_islands.sf <- function(input, min_area = NULL, min_vertices = NULL,
- drop_null_geometries = TRUE, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ drop_null_geometries = TRUE, ...) {
cmd <- make_filterislands_call(min_area = min_area, min_vertices = min_vertices,
drop_null_geometries = TRUE)
- ms_sf(input = input, call = cmd, sys = sys, sys_mem = sys_mem)
+ ms_sf(input = input, call = cmd, ...)
}
#' @export
diff --git a/R/inner_lines.R b/R/inner_lines.R
index a6267e8..fe16ca9 100644
--- a/R/inner_lines.R
+++ b/R/inner_lines.R
@@ -3,17 +3,16 @@
#' @param input input polygons object to convert to inner lines. One of:
#' \itemize{
#' \item \code{geo_json} or \code{character} polygons;
-#' \item \code{geo_list} polygons;
#' \item \code{SpatialPolygons*};
#' \item \code{sf} or \code{sfc} polygons object
#' }
-#' @inheritParams apply_mapshaper_commands
+#' @inheritDotParams apply_mapshaper_commands force_FC sys sys_mem quiet
#'
#' @return lines in the same class as the input layer, but without attributes
#'
#' @examples
-#' library(geojsonio)
-#' library(sp)
+#' library(geojsonsf)
+#' library(sf)
#'
#' poly <- structure('{"type":"FeatureCollection",
#' "features":[
@@ -36,58 +35,45 @@
#' "properties":{"foo": "b"},
#' "geometry":{"type":"Polygon","coordinates":[[
#' [103,1],[103,2],[104,2],[104,1],[103,1]
-#' ]]}}]}', class = c("json", "geo_json"))
+#' ]]}}]}', class = c("geojson", "json"))
#'
-#' poly <- geojson_sp(poly)
+#' poly <- geojson_sf(poly)
#' plot(poly)
#'
#' out <- ms_innerlines(poly)
#' plot(out)
#'
#' @export
-ms_innerlines <- function(input, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- if (!is.logical(force_FC)) stop("force_FC must be TRUE or FALSE")
+ms_innerlines <- function(input, ...) {
UseMethod("ms_innerlines")
}
#' @export
-ms_innerlines.character <- function(input, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ms_innerlines.character <- function(input, ...) {
input <- check_character_input(input)
- apply_mapshaper_commands(data = input, command = "-innerlines",
- force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ apply_mapshaper_commands(data = input, command = "-innerlines", ...)
}
#' @export
-ms_innerlines.geo_json <- function(input, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- apply_mapshaper_commands(data = input, command = "-innerlines",
- force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ms_innerlines.json <- function(input, ...) {
+ apply_mapshaper_commands(data = input, command = "-innerlines", ...)
}
#' @export
-ms_innerlines.geo_list <- function(input, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- geojson <- geo_list_to_json(input)
-
- ret <- apply_mapshaper_commands(data = geojson, command = "-innerlines",
- force_FC = force_FC, sys = sys, sys_mem = sys_mem)
-
- geojsonio::geojson_list(ret)
-}
-
-#' @export
-ms_innerlines.SpatialPolygons <- function(input, force_FC, sys = FALSE, sys_mem = 8) {
- ms_sp(as(input, "SpatialPolygons"), "-innerlines", sys = sys, sys_mem = sys_mem)
+ms_innerlines.SpatialPolygons <- function(input, ...) {
+ ms_sp(as(input, "SpatialPolygons"), "-innerlines", ...)
}
#' @export
-ms_innerlines.sf <- function(input, force_FC, sys = FALSE, sys_mem = 8) {
- ms_sf(sf::st_geometry(input), "-innerlines", sys = sys, sys_mem = sys_mem)
+ms_innerlines.sf <- function(input, ...) {
+ ms_sf(sf::st_geometry(input), "-innerlines", ...)
}
#' @export
-ms_innerlines.sfc <- function(input, force_FC, sys = FALSE, sys_mem = 8) {
- ms_sf(input, "-innerlines", sys = sys, sys_mem = sys_mem)
+ms_innerlines.sfc <- function(input, ...) {
+ ms_sf(input, "-innerlines", ...)
}
diff --git a/R/lines.R b/R/lines.R
index b7622c3..a92f19d 100644
--- a/R/lines.R
+++ b/R/lines.R
@@ -4,7 +4,6 @@
#' @param input input polygons object to convert to inner lines. One of:
#' \itemize{
#' \item \code{geo_json} or \code{character} polygons;
-#' \item \code{geo_list} polygons;
#' \item \code{SpatialPolygons*};
#' \item \code{sf} or \code{sfc} polygons object
#' }
@@ -14,14 +13,14 @@
#' intermediate level of hierarchy at TYPE 1, with the lowest-level internal
#' boundaries set to TYPE 2. Supplying a character vector of field names adds
#' additional levels of hierarchy.
-#' @inheritParams apply_mapshaper_commands
+#' @inheritDotParams apply_mapshaper_commands force_FC sys sys_mem quiet
#'
#' @return topological boundaries as lines, in the same class as the input
#'
#' @examples
#'
-#' library(geojsonio)
-#' library(sp)
+#' library(geojsonsf)
+#' library(sf)
#'
#' poly <- structure('{"type":"FeatureCollection",
#' "features":[
@@ -39,9 +38,9 @@
#' "properties":{"foo": "b"},
#' "geometry":{"type":"Polygon","coordinates":[[
#' [102.5,1],[102.5,2],[103.5,2],[103.5,1],[102.5,1]
-#' ]]}}]}', class = c("json", "geo_json"))
+#' ]]}}]}', class = c("geojson", "json"))
#'
-#' poly <- geojson_sp(poly)
+#' poly <- geojson_sf(poly)
#' summary(poly)
#' plot(poly)
#'
@@ -50,45 +49,30 @@
#' plot(out)
#'
#' @export
-ms_lines <- function(input, fields = NULL, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ms_lines <- function(input, fields = NULL, ...) {
if (!is.null(fields) && !is.character(fields)) stop("fields must be a character vector of field names")
- if (!is.logical(force_FC)) stop("force_FC must be TRUE or FALSE")
UseMethod("ms_lines")
}
#' @export
-ms_lines.character <- function(input, fields = NULL, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ms_lines.character <- function(input, fields = NULL, ...) {
input <- check_character_input(input)
command <- make_lines_call(fields)
- apply_mapshaper_commands(data = input, command = command, force_FC = force_FC,
- sys = sys, sys_mem = sys_mem)
+ apply_mapshaper_commands(data = input, command = command, ...)
}
#' @export
-ms_lines.geo_json <- function(input, fields = NULL, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ms_lines.json <- function(input, fields = NULL, ...) {
command <- make_lines_call(fields)
- apply_mapshaper_commands(data = input, command = command, force_FC = force_FC,
- sys = sys, sys_mem = sys_mem)
+ apply_mapshaper_commands(data = input, command = command, ...)
}
#' @export
-ms_lines.geo_list <- function(input, fields = NULL, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- geojson <- geo_list_to_json(input)
-
- command <- make_lines_call(fields)
-
- ret <- apply_mapshaper_commands(data = geojson, command = command,
- force_FC = force_FC, sys = sys, sys_mem = sys_mem)
-
- geojsonio::geojson_list(ret)
-}
-
-#' @export
-ms_lines.SpatialPolygons <- function(input, fields = NULL, force_FC, sys = FALSE, sys_mem = 8) {
+ms_lines.SpatialPolygons <- function(input, fields = NULL, ...) {
if (.hasSlot(input, "data")) {
if (!all(fields %in% names(input@data))) {
@@ -98,37 +82,37 @@ ms_lines.SpatialPolygons <- function(input, fields = NULL, force_FC, sys = FALSE
command <- make_lines_call(fields)
- ms_sp(input, command, sys = sys, sys_mem = sys_mem)
+ ms_sp(input, command, ...)
}
#' @export
-ms_lines.sf <- function(input, fields = NULL, force_FC, sys = FALSE, sys_mem = 8) {
+ms_lines.sf <- function(input, fields = NULL, ...) {
if (!all(fields %in% names(input))) {
stop("not all fields specified exist in input data")
}
- lines_sf(input = input, fields = fields, sys = sys, sys_mem = sys_mem)
+ lines_sf(input = input, fields = fields, ...)
}
#' @export
-ms_lines.sfc <- function(input, fields = NULL, force_FC, sys = FALSE, sys_mem = 8) {
+ms_lines.sfc <- function(input, fields = NULL, ...) {
if (!is.null(fields)) {
stop("Do not specify fields for sfc classes", call. = FALSE)
}
- lines_sf(input = input, fields = fields, sys = sys, sys_mem = sys_mem)
+ lines_sf(input = input, fields = fields, ...)
}
-lines_sf <- function(input, fields, sys, sys_mem) {
+lines_sf <- function(input, fields, ...) {
if (!all(sf::st_is(input, c("POLYGON", "MULTIPOLYGON")))) {
stop("ms_lines only works with (MULTI)POLYGON")
}
command <- make_lines_call(fields)
- ms_sf(input, command, sys = sys, sys_mem = sys_mem)
+ ms_sf(input, command, ...)
}
make_lines_call <- function(fields) {
diff --git a/R/points.R b/R/points.R
index 6f44b50..2f7f96b 100644
--- a/R/points.R
+++ b/R/points.R
@@ -7,7 +7,6 @@
#' @param input input polygons object to convert to points. One of:
#' \itemize{
#' \item \code{geo_json} or \code{character} polygons;
-#' \item \code{geo_list} polygons;
#' \item \code{SpatialPolygons*};
#' \item \code{sf} or \code{sfc} polygons object
#' }
@@ -21,13 +20,13 @@
#' \code{location} is specified.
#' @param y name of field containing y coordinate values. Must be \code{NULL} if
#' \code{location} is specified.
-#' @inheritParams apply_mapshaper_commands
+#' @inheritDotParams apply_mapshaper_commands force_FC sys sys_mem quiet
#'
#' @return points in the same class as the input.
#'
#' @examples
-#' library(geojsonio)
-#' library(sp)
+#' library(geojsonsf)
+#' library(sf)
#'
#' poly <- structure("{\"type\":\"FeatureCollection\",
#' \"features\":[{\"type\":\"Feature\",\"properties\":
@@ -40,9 +39,9 @@
#' {\"type\":\"Feature\",\"properties\":{\"x_pos\": 5, \"y_pos\": 6},
#' \"geometry\":{\"type\":\"Polygon\",
#' \"coordinates\":[[[100,0],[100,1],[101,1],[101,0],[100,0]]]}}]}",
-#' class = c("json", "geo_json"))
+#' class = c("geojson", "json"))
#'
-#' poly <- geojson_sp(poly)
+#' poly <- geojson_sf(poly)
#' summary(poly)
#' plot(poly)
#'
@@ -57,53 +56,41 @@
#' plot(out)
#'
#' @export
-ms_points <- function(input, location = NULL, x = NULL, y = NULL, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- if (!is.logical(force_FC)) stop("force_FC must be TRUE or FALSE")
+ms_points <- function(input, location = NULL, x = NULL, y = NULL, ...) {
UseMethod("ms_points")
}
#' @export
-ms_points.character <- function(input, location = NULL, x = NULL, y = NULL, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ms_points.character <- function(input, location = NULL, x = NULL, y = NULL, ...) {
input <- check_character_input(input)
cmd <- make_points_call(location = location, x = x, y = y)
- apply_mapshaper_commands(data = input, command = cmd, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ apply_mapshaper_commands(data = input, command = cmd, ...)
}
#' @export
-ms_points.geo_json <- function(input, location = NULL, x = NULL, y = NULL, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+ms_points.json <- function(input, location = NULL, x = NULL, y = NULL, ...) {
cmd <- make_points_call(location = location, x = x, y = y)
- apply_mapshaper_commands(data = input, command = cmd, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ apply_mapshaper_commands(data = input, command = cmd, ...)
}
#' @export
-ms_points.geo_list <- function(input, location = NULL, x = NULL, y = NULL, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
- cmd <- make_points_call(location = location, x = x, y = y)
-
- geojson <- geo_list_to_json(input)
-
- ret <- apply_mapshaper_commands(data = geojson, command = cmd, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
-
- geojsonio::geojson_list(ret)
-}
-
-#' @export
-ms_points.SpatialPolygons <- function(input, location = NULL, x = NULL, y = NULL, force_FC, sys = FALSE, sys_mem = 8) {
+ms_points.SpatialPolygons <- function(input, location = NULL, x = NULL, y = NULL, ...) {
cmd <- make_points_call(location = location, x = x, y = y)
- ms_sp(input, cmd, sys = sys, sys_mem = sys_mem)
+ ms_sp(input, cmd, ...)
}
#' @export
-ms_points.sf <- function(input, location = NULL, x = NULL, y = NULL, force_FC, sys = FALSE, sys_mem = 8) {
+ms_points.sf <- function(input, location = NULL, x = NULL, y = NULL, ...) {
cmd <- make_points_call(location = location, x = x, y = y)
- ms_sf(input, cmd, sys = sys, sys_mem = sys_mem)
+ ms_sf(input, cmd, ...)
}
#' @export
diff --git a/R/rmapshaper.R b/R/rmapshaper.R
index 6114aed..8eedab1 100644
--- a/R/rmapshaper.R
+++ b/R/rmapshaper.R
@@ -5,9 +5,6 @@
#' \url{https://github.com/mbloch/mapshaper/} to perform topologically-aware
#' polygon simplification, as well as other operations such as clipping,
#' erasing, dissolving, and converting 'multi-part' to 'single-part' geometries.
-#' It relies on the 'geojsonio' package for working with 'geojson' objects, the 'sf'
-#' package for working with 'sf' objects, and the 'sp' and 'rgdal' packages for
-#' working with 'Spatial' objects.
#'
#' @section rmapshaper functions:
#'
diff --git a/R/simplify.R b/R/simplify.R
index cad1b2f..1a267ec 100644
--- a/R/simplify.R
+++ b/R/simplify.R
@@ -6,7 +6,6 @@
#' @param input spatial object to simplify. One of:
#' \itemize{
#' \item \code{geo_json} or \code{character} polygons or lines;
-#' \item \code{geo_list} polygons or lines;
#' \item \code{SpatialPolygons*} or \code{SpatialLines*};
#' \item \code{sf} or \code{sfc} polygons or lines object
#' }
@@ -34,7 +33,7 @@
#' Ignored for \code{Spatial*} objects, as it is always \code{TRUE}.
#' @param snap_interval Specify snapping distance in source units, must be a
#' numeric. Default \code{NULL}
-#' @inheritParams apply_mapshaper_commands
+#' @inheritDotParams apply_mapshaper_commands force_FC sys sys_mem quiet
#'
#' @return a simplified representation of the geometry in the same class as the
#' input
@@ -68,73 +67,56 @@
#' [-70.603637, -33.399918]
#' ]]
#' }
-#' }', class = c("json", "geo_json"))
+#' }', class = c("geojson", "json"))
#'
#' ms_simplify(poly, keep = 0.1)
#'
-#' # With a SpatialPolygonsDataFrame:
+#' # With an sf object
#'
-#' poly_sp <- geojsonio::geojson_sp(poly)
-#' ms_simplify(poly_sp, keep = 0.5)
+#' poly_sf <- geojsonsf::geojson_sf(poly)
+#' ms_simplify(poly_sf, keep = 0.5)
#'
#' @export
ms_simplify <- function(input, keep = 0.05, method = NULL, weighting = 0.7,
keep_shapes = FALSE, no_repair = FALSE, snap = TRUE,
- explode = FALSE, force_FC = TRUE, drop_null_geometries = TRUE,
- snap_interval = NULL, sys = FALSE, sys_mem = 8) {
+ explode = FALSE, drop_null_geometries = TRUE,
+ snap_interval = NULL, ...) {
UseMethod("ms_simplify")
}
#' @export
ms_simplify.character <- function(input, keep = 0.05, method = NULL, weighting = 0.7,
keep_shapes = FALSE, no_repair = FALSE,
- snap = TRUE, explode = FALSE, force_FC = TRUE,
- drop_null_geometries = TRUE, snap_interval = NULL, sys = FALSE, sys_mem = 8) {
+ snap = TRUE, explode = FALSE,
+ drop_null_geometries = TRUE, snap_interval = NULL, ...) {
input <- check_character_input(input)
ms_simplify_json(input = input, keep = keep, method = method,
weighting = weighting, keep_shapes = keep_shapes,
no_repair = no_repair, snap = snap, explode = explode,
- force_FC = force_FC, drop_null_geometries = drop_null_geometries,
- snap_interval = snap_interval, sys = sys, sys_mem = sys_mem)
+ drop_null_geometries = drop_null_geometries,
+ snap_interval = snap_interval, ...)
}
#' @export
-ms_simplify.geo_json <- function(input, keep = 0.05, method = NULL, weighting = 0.7,
+ms_simplify.json <- function(input, keep = 0.05, method = NULL, weighting = 0.7,
keep_shapes = FALSE, no_repair = FALSE,
- snap = TRUE, explode = FALSE, force_FC = TRUE,
- drop_null_geometries = TRUE, snap_interval = NULL, sys = FALSE, sys_mem = 8) {
+ snap = TRUE, explode = FALSE,
+ drop_null_geometries = TRUE, snap_interval = NULL, ...) {
ms_simplify_json(input = input, keep = keep, method = method,
weighting = weighting, keep_shapes = keep_shapes,
no_repair = no_repair, snap = snap, explode = explode,
- force_FC = force_FC, drop_null_geometries = drop_null_geometries,
- snap_interval = snap_interval, sys = sys, sys_mem = sys_mem)
-}
-
-#' @export
-ms_simplify.geo_list <- function(input, keep = 0.05, method = NULL,
- weighting = 0.7, keep_shapes = FALSE,
- no_repair = FALSE, snap = TRUE, explode = FALSE,
- force_FC = TRUE, drop_null_geometries = TRUE,
- snap_interval = NULL, sys = FALSE, sys_mem = 8) {
- geojson <- geo_list_to_json(input)
-
- ret <- ms_simplify_json(input = geojson, keep = keep, method = method,
- weighting = weighting, keep_shapes = keep_shapes,
- no_repair = no_repair, snap = snap, explode = explode,
- force_FC = force_FC, drop_null_geometries = drop_null_geometries,
- snap_interval = snap_interval, sys = sys, sys_mem = sys_mem)
-
- geojsonio::geojson_list(ret)
+ drop_null_geometries = drop_null_geometries,
+ snap_interval = snap_interval, ...)
}
#' @export
ms_simplify.SpatialPolygons <- function(input, keep = 0.05, method = NULL, weighting = 0.7,
keep_shapes = FALSE, no_repair = FALSE,
snap = TRUE, explode = FALSE,
- force_FC = TRUE, drop_null_geometries = TRUE,
- snap_interval = NULL, sys = FALSE, sys_mem = 8) {
+ drop_null_geometries = TRUE,
+ snap_interval = NULL, ...) {
if (!is(input, "Spatial")) stop("input must be a spatial object")
@@ -143,7 +125,7 @@ ms_simplify.SpatialPolygons <- function(input, keep = 0.05, method = NULL, weigh
snap = snap, explode = explode, drop_null_geometries = !keep_shapes,
snap_interval = snap_interval)
- ms_sp(input, call, sys = sys, sys_mem = sys_mem)
+ ms_sp(input, call, ...)
}
@@ -154,8 +136,8 @@ ms_simplify.SpatialLines <- ms_simplify.SpatialPolygons
ms_simplify.sf <- function(input, keep = 0.05, method = NULL, weighting = 0.7,
keep_shapes = FALSE, no_repair = FALSE,
snap = TRUE, explode = FALSE,
- force_FC = TRUE, drop_null_geometries = TRUE,
- snap_interval = NULL, sys = FALSE, sys_mem = 8) {
+ drop_null_geometries = TRUE,
+ snap_interval = NULL, ...) {
if (!all(sf::st_geometry_type(input) %in%
c("LINESTRING", "MULTILINESTRING", "POLYGON", "MULTIPOLYGON"))) {
@@ -169,21 +151,21 @@ ms_simplify.sf <- function(input, keep = 0.05, method = NULL, weighting = 0.7,
drop_null_geometries = !keep_shapes,
snap_interval = snap_interval)
- ms_sf(input, call, sys = sys, sys_mem = sys_mem)
+ ms_sf(input, call, ...)
}
#' @export
ms_simplify.sfc <- ms_simplify.sf
ms_simplify_json <- function(input, keep, method, weighting, keep_shapes, no_repair, snap,
- explode, force_FC, drop_null_geometries, snap_interval, sys, sys_mem) {
+ explode, drop_null_geometries, snap_interval, ...) {
call <- make_simplify_call(keep = keep, method = method, weighting = weighting,
keep_shapes = keep_shapes, no_repair = no_repair,
snap = snap, explode = explode, drop_null_geometries = drop_null_geometries,
snap_interval = snap_interval)
- ret <- apply_mapshaper_commands(data = input, command = call, force_FC = force_FC, sys = sys, sys_mem = sys_mem)
+ ret <- apply_mapshaper_commands(data = input, command = call, ...)
ret
}
diff --git a/R/utils.R b/R/utils.R
index a469b89..59ed420 100644
--- a/R/utils.R
+++ b/R/utils.R
@@ -1,24 +1,34 @@
#' Apply a mapshaper command string to a geojson object
#'
-#' @param data geojson object or path to geojson file. If a file path, \code{sys}
-#' must be true
+#' @param data character containing geojson or path to geojson file.
+#' If a file path, \code{sys} must be true.
#' @param command valid mapshaper command string
-#' @param force_FC should the output be forced to be a FeatureCollection (or
-#' Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}.
-#' FeatureCollections are more compatible with rgdal::readOGR and
-#' geojsonio::geojson_sp. If FALSE and there are no attributes associated with
-#' the geometries, a GeometryCollection (or Spatial object with no dataframe)
-#' will be output.
+#' @param force_FC should the output be forced to be a FeatureCollection (or sf object or
+#' Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}. If FALSE and
+#' there are no attributes associated with the geometries, a
+#' GeometryCollection (or Spatial object with no dataframe, or sfc) will be output.
#' @param sys Should the system mapshaper be used instead of the bundled mapshaper? Gives
#' better performance on large files. Requires the mapshaper node package to be installed
#' and on the PATH.
#' @param sys_mem How much memory (in GB) should be allocated if using the system
#' mapshaper (`sys = TRUE`)? Default 8. Ignored if `sys = FALSE`.
+#' This can also be set globally with the option `"mapshaper.sys_mem"`
+#' @param quiet If `sys = TRUE`, should the mapshaper messages be silenced? Default `FALSE`.
+#' This can also be set globally with the option `"mapshaper.sys_quiet"`
#'
#' @return geojson
#' @export
+#' @examples
#'
-apply_mapshaper_commands <- function(data, command, force_FC = TRUE, sys = FALSE, sys_mem = 8) {
+#' nc <- sf::read_sf(system.file("gpkg/nc.gpkg", package = "sf"))
+#' rmapshaper::apply_mapshaper_commands(geojsonsf::sf_geojson(nc), "-clean")
+#'
+apply_mapshaper_commands <- function(data, command, force_FC = TRUE, sys = FALSE,
+ sys_mem = getOption("mapshaper.sys_mem", default = 8),
+ quiet = getOption("mapshaper.sys_quiet", default = FALSE)) {
+ if (!is.logical(force_FC)) stop("force_FC must be TRUE or FALSE", call. = FALSE)
+ if (!is.logical(sys)) stop("sys must be TRUE or FALSE", call. = FALSE)
+ if (!is.numeric(sys_mem)) stop("sys_mem must be numeric", call. = FALSE)
data <- as.character(data)
@@ -43,7 +53,7 @@ apply_mapshaper_commands <- function(data, command, force_FC = TRUE, sys = FALSE
command <- paste(ms_compact(command), collapse = " ")
if (sys) {
- ret <- sys_mapshaper(data = data, command = command, sys_mem = sys_mem)
+ ret <- sys_mapshaper(data = data, command = command, sys_mem = sys_mem, quiet = quiet)
} else {
ms <- ms_make_ctx()
@@ -75,7 +85,9 @@ ms_make_ctx <- function() {
ctx
}
-sys_mapshaper <- function(data, data2 = NULL, command, sys_mem = 8) {
+sys_mapshaper <- function(data, data2 = NULL, command,
+ sys_mem = getOption("mapshaper.sys_mem", default = 8),
+ quiet = getOption("mapshaper.sys_quiet", default = FALSE)) {
# Get full path to sys mapshaper, use mapshaper-xl
ms_path <- paste0(check_sys_mapshaper("mapshaper-xl", verbose = FALSE))
@@ -83,6 +95,9 @@ sys_mapshaper <- function(data, data2 = NULL, command, sys_mem = 8) {
# by write_sf or writeOGR
read_write <- !file.exists(data)
+ in_data_file <- data
+ in_data_file2 <- data2
+
if (read_write) {
in_data_file <- temp_geojson()
readr::write_file(data, in_data_file)
@@ -93,18 +108,19 @@ sys_mapshaper <- function(data, data2 = NULL, command, sys_mem = 8) {
readr::write_file(data2, in_data_file2)
on.exit(unlink(in_data_file2), add = TRUE)
}
-
- } else {
- in_data_file <- data
- in_data_file2 <- data2
}
out_data_file <- temp_geojson()
- if (!is.null(data2)) {
- cmd_args <- c(sys_mem, shQuote(in_data_file), command, shQuote(in_data_file2), "-o", shQuote(out_data_file))
- } else {
- cmd_args <- c(sys_mem, shQuote(in_data_file), command, "-o", shQuote(out_data_file))
- }
+
+ cmd_args <- c(
+ sys_mem,
+ shQuote(in_data_file),
+ command,
+ shQuote(in_data_file2), # will be NULL if no data2/in_data_file2
+ "-o", shQuote(out_data_file),
+ if (quiet) "-quiet"
+ )
+
system2(ms_path, cmd_args)
if (read_write) {
@@ -131,7 +147,9 @@ return_data = data;
}"
}
-ms_sp <- function(input, call, sys = FALSE, sys_mem = 8) {
+ms_sp <- function(input, call, sys = FALSE,
+ sys_mem = getOption("mapshaper.sys_mem", default = 8),
+ quiet = getOption("mapshaper.sys_quiet", default = FALSE)) {
has_data <- .hasSlot(input, "data")
if (has_data) {
@@ -140,7 +158,7 @@ ms_sp <- function(input, call, sys = FALSE, sys_mem = 8) {
geojson <- sp_to_GeoJSON(input, file = sys)
- ret <- apply_mapshaper_commands(data = geojson, command = call, force_FC = TRUE, sys = sys, sys_mem = sys_mem)
+ ret <- apply_mapshaper_commands(data = geojson, command = call, force_FC = TRUE, sys = sys, sys_mem = sys_mem, quiet = quiet)
if (!sys & grepl('^\\{"type":"GeometryCollection"', ret)) {
stop("Cannot convert result to a Spatial* object.
@@ -148,7 +166,7 @@ ms_sp <- function(input, call, sys = FALSE, sys_mem = 8) {
were reduced to null.", call. = FALSE)
}
- ret <- GeoJSON_to_sp(ret, proj = attr(geojson, "proj"))
+ ret <- GeoJSON_to_sp(ret, crs = attr(geojson, "crs"))
# remove data slot if input didn't have one (default out_class is the class of the input)
if (!has_data) {
@@ -160,25 +178,29 @@ ms_sp <- function(input, call, sys = FALSE, sys_mem = 8) {
ret
}
-GeoJSON_to_sp <- function(geojson, proj = NULL) {
- x_sf <- GeoJSON_to_sf(geojson, proj)
+GeoJSON_to_sp <- function(geojson, crs = NULL) {
+ x_sf <- GeoJSON_to_sf(geojson, crs)
as(x_sf, "Spatial")
}
sp_to_GeoJSON <- function(sp, file = FALSE){
- proj <- slot(sp, "proj4string")
+
+ crs <- methods::slot(sp, "proj4string")
+
if (file) {
- js <- sf_sp_to_tempfile(sp)
+ js <- sp_to_tempfile(sp)
} else {
- js_tmp <- sf_sp_to_tempfile(sp)
+ js_tmp <- sp_to_tempfile(sp)
js <- readr::read_file(js_tmp, locale = readr::locale())
on.exit(unlink(js_tmp))
}
- structure(js, proj = proj)
+ structure(js, crs = crs)
}
## Utilties for sf
-ms_sf <- function(input, call, sys = FALSE, sys_mem = 8) {
+ms_sf <- function(input, call, sys = FALSE,
+ sys_mem = getOption("mapshaper.sys_mem", default = 8),
+ quiet = getOption("mapshaper.sys_quiet", default = FALSE)) {
has_data <- is(input, "sf")
if (has_data) {
@@ -191,7 +213,7 @@ ms_sf <- function(input, call, sys = FALSE, sys_mem = 8) {
geojson <- sf_to_GeoJSON(input, file = sys)
- ret <- apply_mapshaper_commands(data = geojson, command = call, force_FC = TRUE, sys = sys, sys_mem = sys_mem)
+ ret <- apply_mapshaper_commands(data = geojson, command = call, force_FC = TRUE, sys = sys, sys_mem = sys_mem, quiet = quiet)
if (!sys & grepl('^\\{"type":"GeometryCollection"', ret)) {
stop("Cannot convert result to an sf object.
@@ -199,7 +221,7 @@ ms_sf <- function(input, call, sys = FALSE, sys_mem = 8) {
were reduced to null.", call. = FALSE)
}
- ret <- GeoJSON_to_sf(ret, proj = attr(geojson, "proj"))
+ ret <- GeoJSON_to_sf(ret, crs = attr(geojson, "crs"))
## Only return sfc if that's all that was input
if (!has_data) {
@@ -216,41 +238,49 @@ ms_sf <- function(input, call, sys = FALSE, sys_mem = 8) {
ret
}
-GeoJSON_to_sf <- function(geojson, proj = NULL) {
- sf <- suppressWarnings(
- sf::st_read(unclass(geojson), quiet = TRUE, stringsAsFactors = FALSE)
- )
- if (!is.null(proj)) {
- suppressWarnings(sf::st_crs(sf) <- proj)
+GeoJSON_to_sf <- function(geojson, crs = NULL) {
+ sf <- geojsonsf::geojson_sf(geojson)
+ if (!is.null(crs)) {
+ suppressWarnings(sf::st_crs(sf) <- crs)
}
curly_brace_na(sf)
}
sf_to_GeoJSON <- function(sf, file = FALSE) {
- proj <- sf::st_crs(sf)
- if (file) {
- js <- sf_sp_to_tempfile(sf)
- } else {
- ## Use this instead of geojsonio::geojson_json to avoid
- ## the geo_json classing that goes on there
- js <- geo_list_to_json(sf)
- }
- structure(js, proj = proj)
+ crs <- sf::st_crs(sf)
+
+ js <- if (inherits(sf, "sf")) {
+ geojsonsf::sf_geojson(sf, simplify = FALSE)
+ } else {
+ json <- geojsonsf::sfc_geojson(sf)
+ paste0("{\"type\":\"GeometryCollection\",\"geometries\":[",
+ paste(json, collapse = ","),
+ "]}")
+ }
+
+ if (file) {
+ path <- tempfile(fileext = ".geojson")
+ writeLines(js, con = path)
+ js <- path
+ }
+ structure(js, crs = crs)
}
-geo_list_to_json <- function(x) {
- suppressMessages(
- jsonlite::toJSON(unclass(
- geojsonio::geojson_list(x, type = "auto")
- ), auto_unbox = TRUE, digits = 7, na = "null")
- )
+
+sp_to_tempfile <- function(obj) {
+ obj <- sf::st_as_sf(sp_to_spdf(obj))
+ path <- tempfile(fileext = ".geojson")
+ sf::st_write(obj, path, driver = "GeoJSON", quiet = TRUE, delete_dsn = TRUE)
+ normalizePath(path, winslash = "/", mustWork = TRUE)
}
-sf_sp_to_tempfile <- function(obj) {
- path <- suppressMessages(
- geojsonio::geojson_write(obj, file = temp_geojson())
- )
- normalizePath(path[["path"]], winslash = "/", mustWork = TRUE)
+sp_to_spdf <- function(obj) {
+ non_df_classes <- c("SpatialLines", "SpatialPolygons", "SpatialPoints")
+ cls <- inherits(obj, non_df_classes, which = TRUE)
+ if (!any(cls)) {
+ return(obj)
+ }
+ as(obj, paste0(non_df_classes[as.logical(cls)], "DataFrame"))
}
#' Check the system mapshaper
@@ -316,16 +346,15 @@ add_dummy_id_command <- function() {
}
class_geo_json <- function(x) {
- structure(x, class = c("json", "geo_json"))
+ structure(x, class = c("geojson", "json"))
}
-#' @importFrom geojsonlint geojson_validate
check_character_input <- function(x) {
## Collapse to character vector of length one if many lines (e.g., if used readLines)
if (length(x) > 1) {
x <- paste0(x, collapse = "")
}
- if (!geojsonlint::geojson_validate(x)) stop("Input is not valid geojson")
+ if (!jsonify::validate_json(x)) stop("Input is not valid geojson")
x
}
@@ -361,6 +390,9 @@ curly_brace_na.sf <- function(x) {
col_classes <- function(df) {
classes <- lapply(df, function(x) {
out <- list()
+ if (inherits(x, "POSIXlt")) {
+ stop("POSIXlt classes not supported. Please convert to POSIXct", call. = FALSE)
+ }
out$class <- class(x)
if (is.factor(x)) {
out$levels <- levels(x)
diff --git a/README.Rmd b/README.Rmd
index 424e022..fdc245e 100644
--- a/README.Rmd
+++ b/README.Rmd
@@ -1,7 +1,7 @@
---
output:
- md_document:
- variant: markdown_github
+ github_document:
+ html_preview: true
---
@@ -17,10 +17,10 @@ options(warnPartialMatchArgs = FALSE)
[![Codecov test coverage](https://codecov.io/gh/ateucher/rmapshaper/branch/master/graph/badge.svg)](https://app.codecov.io/gh/ateucher/rmapshaper?branch=master)
-[![R build status](https://github.com/ateucher/rmapshaper/workflows/R-CMD-check/badge.svg)](https://github.com/ateucher/rmapshaper)
[![CRAN\_Status\_Badge](http://www.r-pkg.org/badges/version/rmapshaper)](https://cran.r-project.org/package=rmapshaper)
[![CRAN Downloads per month](http://cranlogs.r-pkg.org/badges/rmapshaper)](https://cran.r-project.org/package=rmapshaper)
[![CRAN total downloads](http://cranlogs.r-pkg.org/badges/grand-total/rmapshaper?color=lightgrey)](https://cran.r-project.org/package=rmapshaper)
+[![R-CMD-check](https://github.com/ateucher/rmapshaper/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/ateucher/rmapshaper/actions/workflows/R-CMD-check.yaml)
# rmapshaper
@@ -64,84 +64,76 @@ 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.
+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 `states` dataset from the `geojsonio` package and first turn it
-into a `geo_json` object:
+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(geojsonio)
library(rmapshaper)
-library(sp)
library(sf)
-## First convert to json
-states_json <- geojson_json(states, geometry = "polygon", group = "group")
+file <- system.file("gpkg/nc.gpkg", package = "sf")
+nc_sf <- read_sf(file)
+```
-## For ease of illustration via plotting, we will convert to a `SpatialPolygonsDataFrame`:
-states_sp <- geojson_sp(states_json)
+Plot the original:
-## Plot the original
-plot(states_sp)
+```{r}
+plot(nc_sf["FIPS"])
+```
-## Now simplify using default parameters, then plot the simplified states
-states_simp <- ms_simplify(states_sp)
-plot(states_simp)
+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:
+simplification algorithm preserves the topology, including shared boundaries. The `keep`
+parameter specifies what proportion of vertices to keep:
```{r}
-states_very_simp <- ms_simplify(states_sp, keep = 0.001)
-plot(states_very_simp)
+nc_very_simp <- ms_simplify(nc_sf, keep = 0.001)
+plot(nc_very_simp["FIPS"])
```
-Compare this to the output using `rgeos::gSimplify`, where overlaps and gaps are evident:
+Compare this to the output using `sf::st_simplify`, where overlaps and gaps are evident:
```{r}
-library(rgeos)
-states_gsimp <- gSimplify(states_sp, tol = 1, topologyPreserve = TRUE)
-plot(states_gsimp)
+
+nc_stsimp <- st_simplify(nc_sf, preserveTopology = TRUE, dTolerance = 10000) # dTolerance specified in meters
+plot(nc_stsimp["FIPS"])
```
-The package also works with `sf` objects. This time we'll demonstrate the `ms_innerlines` function:
+This time we'll demonstrate the `ms_innerlines` function:
```{r}
-library(sf)
-
-states_sf <- st_as_sf(states_sp)
-states_sf_innerlines <- ms_innerlines(states_sf)
-plot(states_sf_innerlines)
-
+nc_sf_innerlines <- ms_innerlines(nc_sf)
+plot(nc_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,
+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 contrived example, using `states_sp` as created above:
+For a totally contrived example, using `nc_sf` as created above:
-```{r eval=rmapshaper:::check_v8_major_version() >= 6L}
-library(geojsonio)
+```{r eval=rmapshaper:::check_v8_major_version() >= 6}
+library(geojsonsf)
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
+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
```
@@ -149,7 +141,7 @@ states_json %>%
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.
+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:
@@ -159,27 +151,33 @@ 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 with:
+(https://nodejs.org/en/) and then install mapshaper in a command prompt with:
```
-npm install -g mapshaper
+$ npm install -g mapshaper
```
+
Then you can use the `sys` argument in any rmapshaper function:
```{r eval=nzchar(Sys.which("mapshaper"))}
-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.
+nc_simp_internal <- ms_simplify(nc_sf)
+nc_simp_sys <- ms_simplify(nc_sf, sys = TRUE, sys_mem=8) #sys_mem specifies the amount 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")
+plot(st_geometry(nc_simp_internal), main = "internal")
+plot(st_geometry(nc_simp_sys), main = "system")
```
### Thanks
-This package uses the [V8](https://cran.r-project.org/package=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.
+This package uses the [V8](https://cran.r-project.org/package=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 `sf`), and the `geojsonio` and the `geojsonsf` packages for
+converting between `geojson`, `sf` and `Spatial`
+object.
Thanks to [timelyportfolio](https://github.com/timelyportfolio) for helping me wrangle the javascript to the point where it works in V8. He also wrote the [mapshaper htmlwidget](https://github.com/timelyportfolio/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.
diff --git a/README.md b/README.md
index 291085b..0fa8a1f 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,15 @@
+
[![Codecov test
coverage](https://codecov.io/gh/ateucher/rmapshaper/branch/master/graph/badge.svg)](https://app.codecov.io/gh/ateucher/rmapshaper?branch=master)
-[![R build
-status](https://github.com/ateucher/rmapshaper/workflows/R-CMD-check/badge.svg)](https://github.com/ateucher/rmapshaper)
[![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/rmapshaper)](https://cran.r-project.org/package=rmapshaper)
[![CRAN Downloads per
month](http://cranlogs.r-pkg.org/badges/rmapshaper)](https://cran.r-project.org/package=rmapshaper)
[![CRAN total
downloads](http://cranlogs.r-pkg.org/badges/grand-total/rmapshaper?color=lightgrey)](https://cran.r-project.org/package=rmapshaper)
+[![R-CMD-check](https://github.com/ateucher/rmapshaper/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/ateucher/rmapshaper/actions/workflows/R-CMD-check.yaml)
# rmapshaper
@@ -32,24 +32,23 @@ 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 the `Spatial` classes (not
- `SpatialMultiPoints` and `SpatialMultiPointsDataFrame`).
-- `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
+- `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 the `Spatial` classes (not `SpatialMultiPoints`
+ and `SpatialMultiPointsDataFrame`).
+- `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](https://github.com/ateucher/rmapshaper/issues/)
@@ -72,131 +71,100 @@ 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.
+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 `states` dataset from the `geojsonio` package and first
-turn it into a `geo_json` object:
+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(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
+#> Linking to GEOS 3.11.0, GDAL 3.5.3, PROJ 9.1.0; 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
+file <- system.file("gpkg/nc.gpkg", package = "sf")
+nc_sf <- read_sf(file)
+```
-## For ease of illustration via plotting, we will convert to a `SpatialPolygonsDataFrame`:
-states_sp <- geojson_sp(states_json)
+Plot the original:
-## Plot the original
-plot(states_sp)
+``` r
+plot(nc_sf["FIPS"])
```
-![](tools/readme/unnamed-chunk-2-1.png)
+![](tools/readme/unnamed-chunk-3-1.png)
-``` r
+Now simplify using default parameters, then plot the simplified North
+Carolina counties:
-## 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)
+``` r
+nc_simp <- ms_simplify(nc_sf)
+plot(nc_simp["FIPS"])
```
-![](tools/readme/unnamed-chunk-2-2.png)
+![](tools/readme/unnamed-chunk-4-1.png)
You can see that even at very high levels of simplification, the
mapshaper simplification algorithm preserves the topology, including
-shared boundaries:
+shared boundaries. The `keep` parameter specifies what proportion of
+vertices to keep:
``` r
-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)
+nc_very_simp <- ms_simplify(nc_sf, keep = 0.001)
+plot(nc_very_simp["FIPS"])
```
-![](tools/readme/unnamed-chunk-3-1.png)
+![](tools/readme/unnamed-chunk-5-1.png)
-Compare this to the output using `rgeos::gSimplify`, where overlaps and
+Compare this to the output using `sf::st_simplify`, where overlaps and
gaps are evident:
``` r
-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)
+
+nc_stsimp <- st_simplify(nc_sf, preserveTopology = TRUE, dTolerance = 10000) # dTolerance specified in meters
+plot(nc_stsimp["FIPS"])
```
-![](tools/readme/unnamed-chunk-4-1.png)
+![](tools/readme/unnamed-chunk-6-1.png)
-The package also works with `sf` objects. This time we’ll demonstrate
-the `ms_innerlines` function:
+This time we’ll demonstrate the `ms_innerlines` function:
``` r
-library(sf)
-
-states_sf <- st_as_sf(states_sp)
-states_sf_innerlines <- ms_innerlines(states_sf)
-plot(states_sf_innerlines)
+nc_sf_innerlines <- ms_innerlines(nc_sf)
+plot(nc_sf_innerlines)
```
-![](tools/readme/unnamed-chunk-5-1.png)
+![](tools/readme/unnamed-chunk-7-1.png)
-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:
+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
-library(geojsonio)
+library(geojsonsf)
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
+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
```
-![](tools/readme/unnamed-chunk-6-1.png)
+![](tools/readme/unnamed-chunk-8-1.png)
### Using the system mapshaper
@@ -210,38 +178,37 @@ First make sure you have mapshaper installed:
``` r
check_sys_mapshaper()
-#> mapshaper version 0.5.88 is installed and on your PATH
-#> mapshaper-xl
-#> "/usr/local/bin/mapshaper-xl"
+#> mapshaper version 0.6.25 is installed and on your PATH
+#> mapshaper-xl
+#> "/opt/homebrew/bin/mapshaper-xl"
```
If you get an error, you will need to install mapshaper. First install
-node () and then install mapshaper with:
+node () and then install mapshaper in a command
+prompt with:
- npm install -g mapshaper
+ $ npm install -g mapshaper
Then you can use the `sys` argument in any rmapshaper function:
``` r
-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.
+nc_simp_internal <- ms_simplify(nc_sf)
+nc_simp_sys <- ms_simplify(nc_sf, sys = TRUE, sys_mem=8) #sys_mem specifies the amount 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")
+plot(st_geometry(nc_simp_internal), main = "internal")
+plot(st_geometry(nc_simp_sys), main = "system")
```
-![](tools/readme/unnamed-chunk-8-1.png)
+![](tools/readme/unnamed-chunk-10-1.png)
### Thanks
This package uses the [V8](https://cran.r-project.org/package=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.
+already exist (especially `sf`), and the `geojsonio` and the `geojsonsf`
+packages for converting between `geojson`, `sf` and `Spatial` object.
Thanks to [timelyportfolio](https://github.com/timelyportfolio) for
helping me wrangle the javascript to the point where it works in V8. He
diff --git a/codecov.yml b/codecov.yml
index 8f36b6c..04c5585 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -6,7 +6,9 @@ coverage:
default:
target: auto
threshold: 1%
+ informational: true
patch:
default:
target: auto
threshold: 1%
+ informational: true
diff --git a/man/apply_mapshaper_commands.Rd b/man/apply_mapshaper_commands.Rd
index d15c4e4..518482d 100644
--- a/man/apply_mapshaper_commands.Rd
+++ b/man/apply_mapshaper_commands.Rd
@@ -9,28 +9,31 @@ apply_mapshaper_commands(
command,
force_FC = TRUE,
sys = FALSE,
- sys_mem = 8
+ sys_mem = getOption("mapshaper.sys_mem", default = 8),
+ quiet = getOption("mapshaper.sys_quiet", default = FALSE)
)
}
\arguments{
-\item{data}{geojson object or path to geojson file. If a file path, \code{sys}
-must be true}
+\item{data}{character containing geojson or path to geojson file.
+If a file path, \code{sys} must be true.}
\item{command}{valid mapshaper command string}
-\item{force_FC}{should the output be forced to be a FeatureCollection (or
-Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}.
-FeatureCollections are more compatible with rgdal::readOGR and
-geojsonio::geojson_sp. If FALSE and there are no attributes associated with
-the geometries, a GeometryCollection (or Spatial object with no dataframe)
-will be output.}
+\item{force_FC}{should the output be forced to be a FeatureCollection (or sf object or
+Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}. If FALSE and
+there are no attributes associated with the geometries, a
+GeometryCollection (or Spatial object with no dataframe, or sfc) will be output.}
\item{sys}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
better performance on large files. Requires the mapshaper node package to be installed
and on the PATH.}
\item{sys_mem}{How much memory (in GB) should be allocated if using the system
-mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.}
+mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_mem"}}
+
+\item{quiet}{If \code{sys = TRUE}, should the mapshaper messages be silenced? Default \code{FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_quiet"}}
}
\value{
geojson
@@ -38,3 +41,9 @@ geojson
\description{
Apply a mapshaper command string to a geojson object
}
+\examples{
+
+nc <- sf::read_sf(system.file("gpkg/nc.gpkg", package = "sf"))
+rmapshaper::apply_mapshaper_commands(geojsonsf::sf_geojson(nc), "-clean")
+
+}
diff --git a/man/drop_null_geometries.Rd b/man/drop_null_geometries.Rd
index 2798c8c..2827b7e 100644
--- a/man/drop_null_geometries.Rd
+++ b/man/drop_null_geometries.Rd
@@ -2,17 +2,17 @@
% Please edit documentation in R/drop_null_geometries.R
\name{drop_null_geometries}
\alias{drop_null_geometries}
-\title{Drop features from a \code{geo_list} or \code{geo_json} FeatureCollection with null geometries}
+\title{Drop features from a \code{geo_json} FeatureCollection with null geometries}
\usage{
drop_null_geometries(x)
}
\arguments{
-\item{x}{a \code{geo_list} or \code{geo_json} FeatureCollection}
+\item{x}{a \code{geo_json} FeatureCollection}
}
\value{
-a \code{geo_list} or \code{geo_json} FeatureCollection with Features with null geometries
+a \code{geo_json} FeatureCollection with Features with null geometries
removed
}
\description{
-Drop features from a \code{geo_list} or \code{geo_json} FeatureCollection with null geometries
+Drop features from a \code{geo_json} FeatureCollection with null geometries
}
diff --git a/man/ms_clip.Rd b/man/ms_clip.Rd
index 16e2e32..cc75e11 100644
--- a/man/ms_clip.Rd
+++ b/man/ms_clip.Rd
@@ -4,21 +4,12 @@
\alias{ms_clip}
\title{Remove features or portions of features that fall outside a clipping area.}
\usage{
-ms_clip(
- target,
- clip = NULL,
- bbox = NULL,
- remove_slivers = FALSE,
- force_FC = TRUE,
- sys = FALSE,
- sys_mem = 8
-)
+ms_clip(target, clip = NULL, bbox = NULL, remove_slivers = FALSE, ...)
}
\arguments{
\item{target}{the target layer from which to remove portions. One of:
\itemize{
\item \code{geo_json} or \code{character} points, lines, or polygons;
-\item \code{geo_list} points, lines, or polygons;
\item \code{SpatialPolygons}, \code{SpatialLines}, \code{SpatialPoints};
\item \code{sf} or \code{sfc} points, lines, or polygons object
}}
@@ -26,7 +17,6 @@ ms_clip(
\item{clip}{the clipping layer (polygon). One of:
\itemize{
\item \code{geo_json} or \code{character} polygons;
-\item \code{geo_list} polygons;
\item \code{SpatialPolygons*};
\item \code{sf} or \code{sfc} polygons object
}}
@@ -36,19 +26,22 @@ the target layer. Supply as a numeric vector: \code{c(minX, minY, maxX, maxY)}.}
\item{remove_slivers}{Remove tiny sliver polygons created by clipping. (Default \code{FALSE})}
-\item{force_FC}{should the output be forced to be a FeatureCollection (or
-Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}.
-FeatureCollections are more compatible with rgdal::readOGR and
-geojsonio::geojson_sp. If FALSE and there are no attributes associated with
-the geometries, a GeometryCollection (or Spatial object with no dataframe)
-will be output.}
-
-\item{sys}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
+\item{...}{
+ Arguments passed on to \code{\link[=apply_mapshaper_commands]{apply_mapshaper_commands}}
+ \describe{
+ \item{\code{force_FC}}{should the output be forced to be a FeatureCollection (or sf object or
+Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}. If FALSE and
+there are no attributes associated with the geometries, a
+GeometryCollection (or Spatial object with no dataframe, or sfc) will be output.}
+ \item{\code{sys}}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
better performance on large files. Requires the mapshaper node package to be installed
and on the PATH.}
-
-\item{sys_mem}{How much memory (in GB) should be allocated if using the system
-mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.}
+ \item{\code{sys_mem}}{How much memory (in GB) should be allocated if using the system
+mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_mem"}}
+ \item{\code{quiet}}{If \code{sys = TRUE}, should the mapshaper messages be silenced? Default \code{FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_quiet"}}
+ }}
}
\value{
clipped target in the same class as the input target
@@ -59,8 +52,8 @@ Removes portions of the target layer that fall outside the clipping layer or bou
\examples{
if (rmapshaper:::check_v8_major_version() >= 6L) {
- library(geojsonio, quietly = TRUE)
- library(sp)
+ library(geojsonsf, quietly = TRUE)
+ library(sf)
poly <- structure("{\"type\":\"FeatureCollection\",
\"features\":[{\"type\":\"Feature\",\"properties\":{},
@@ -72,8 +65,8 @@ if (rmapshaper:::check_v8_major_version() >= 6L) {
[52.0329,-49.5677],[50.1747,-52.1814],[49.0098,-52.3641],
[52.7068,-45.7639],[43.2278,-47.1908],[48.4755,-45.1388],
[50.327,-43.5207],[48.0804,-41.2784],[49.6307,-40.6159],
- [52.8658,-44.7219]]]}}]}", class = c("json", "geo_json"))
- poly <- geojson_sp(poly)
+ [52.8658,-44.7219]]]}}]}", class = c("geojson", "json"))
+ poly <- geojson_sf(poly)
plot(poly)
clip_poly <- structure('{
@@ -91,8 +84,8 @@ if (rmapshaper:::check_v8_major_version() >= 6L) {
]
]
}
- }', class = c("json", "geo_json"))
- clip_poly <- geojson_sp(clip_poly)
+ }', class = c("geojson", "json"))
+ clip_poly <- geojson_sf(clip_poly)
plot(clip_poly)
out <- ms_clip(poly, clip_poly)
diff --git a/man/ms_dissolve.Rd b/man/ms_dissolve.Rd
index 7319104..973d72a 100644
--- a/man/ms_dissolve.Rd
+++ b/man/ms_dissolve.Rd
@@ -11,16 +11,13 @@ ms_dissolve(
copy_fields = NULL,
weight = NULL,
snap = TRUE,
- force_FC = TRUE,
- sys = FALSE,
- sys_mem = 8
+ ...
)
}
\arguments{
\item{input}{spatial object to dissolve. One of:
\itemize{
\item \code{geo_json} or \code{character} points or polygons;
-\item \code{geo_list} points or polygons;
\item \code{SpatialPolygons}, or \code{SpatialPoints}
}}
@@ -36,19 +33,22 @@ copied to the aggregated feature.}
\item{snap}{Snap together vertices within a small distance threshold to fix
small coordinate misalignment in adjacent polygons. Default \code{TRUE}.}
-\item{force_FC}{should the output be forced to be a FeatureCollection (or
-Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}.
-FeatureCollections are more compatible with rgdal::readOGR and
-geojsonio::geojson_sp. If FALSE and there are no attributes associated with
-the geometries, a GeometryCollection (or Spatial object with no dataframe)
-will be output.}
-
-\item{sys}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
+\item{...}{
+ Arguments passed on to \code{\link[=apply_mapshaper_commands]{apply_mapshaper_commands}}
+ \describe{
+ \item{\code{force_FC}}{should the output be forced to be a FeatureCollection (or sf object or
+Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}. If FALSE and
+there are no attributes associated with the geometries, a
+GeometryCollection (or Spatial object with no dataframe, or sfc) will be output.}
+ \item{\code{sys}}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
better performance on large files. Requires the mapshaper node package to be installed
and on the PATH.}
-
-\item{sys_mem}{How much memory (in GB) should be allocated if using the system
-mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.}
+ \item{\code{sys_mem}}{How much memory (in GB) should be allocated if using the system
+mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_mem"}}
+ \item{\code{quiet}}{If \code{sys = TRUE}, should the mapshaper messages be silenced? Default \code{FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_quiet"}}
+ }}
}
\value{
the same class as the input
@@ -58,8 +58,8 @@ Aggregates using specified field, or all shapes if no field is given. For point
replaces a group of points with their centroid.
}
\examples{
-library(geojsonio)
-library(sp)
+library(geojsonsf)
+library(sf)
poly <- structure('{"type":"FeatureCollection",
"features":[
@@ -72,21 +72,21 @@ poly <- structure('{"type":"FeatureCollection",
"properties":{"a": 5, "b": 3},
"geometry":{"type":"Polygon","coordinates":[[
[100,0],[100,1],[101,1],[101,0],[100,0]
- ]]}}]}', class = c("json", "geo_json"))
-poly <- geojson_sp(poly)
+ ]]}}]}', class = c("geojson", "json"))
+poly <- geojson_sf(poly)
plot(poly)
length(poly)
-poly@data
+poly
# Dissolve the polygon
out <- ms_dissolve(poly)
plot(out)
length(out)
-out@data
+out
# Dissolve and summing columns
out <- ms_dissolve(poly, sum_fields = c("a", "b"))
plot(out)
-out@data
+out
}
diff --git a/man/ms_erase.Rd b/man/ms_erase.Rd
index ec4fb1f..725c28f 100644
--- a/man/ms_erase.Rd
+++ b/man/ms_erase.Rd
@@ -4,28 +4,18 @@
\alias{ms_erase}
\title{Remove features or portions of features that fall inside a specified area}
\usage{
-ms_erase(
- target,
- erase = NULL,
- bbox = NULL,
- remove_slivers = FALSE,
- force_FC = TRUE,
- sys = FALSE,
- sys_mem = 8
-)
+ms_erase(target, erase = NULL, bbox = NULL, remove_slivers = FALSE, ...)
}
\arguments{
\item{target}{the target layer from which to remove portions. One of:
\itemize{
\item \code{geo_json} or \code{character} points, lines, or polygons;
-\item \code{geo_list} points, lines, or polygons;
\item \code{SpatialPolygons}, \code{SpatialLines}, \code{SpatialPoints}
}}
\item{erase}{the erase layer (polygon). One of:
\itemize{
\item \code{geo_json} or \code{character} polygons;
-\item \code{geo_list} polygons;
\item \code{SpatialPolygons*}
}}
@@ -34,19 +24,22 @@ the target layer. Supply as a numeric vector: \code{c(minX, minY, maxX, maxY)}.}
\item{remove_slivers}{Remove tiny sliver polygons created by erasing. (Default \code{FALSE})}
-\item{force_FC}{should the output be forced to be a FeatureCollection (or
-Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}.
-FeatureCollections are more compatible with rgdal::readOGR and
-geojsonio::geojson_sp. If FALSE and there are no attributes associated with
-the geometries, a GeometryCollection (or Spatial object with no dataframe)
-will be output.}
-
-\item{sys}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
+\item{...}{
+ Arguments passed on to \code{\link[=apply_mapshaper_commands]{apply_mapshaper_commands}}
+ \describe{
+ \item{\code{force_FC}}{should the output be forced to be a FeatureCollection (or sf object or
+Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}. If FALSE and
+there are no attributes associated with the geometries, a
+GeometryCollection (or Spatial object with no dataframe, or sfc) will be output.}
+ \item{\code{sys}}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
better performance on large files. Requires the mapshaper node package to be installed
and on the PATH.}
-
-\item{sys_mem}{How much memory (in GB) should be allocated if using the system
-mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.}
+ \item{\code{sys_mem}}{How much memory (in GB) should be allocated if using the system
+mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_mem"}}
+ \item{\code{quiet}}{If \code{sys = TRUE}, should the mapshaper messages be silenced? Default \code{FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_quiet"}}
+ }}
}
\value{
erased target in the same format as the input target
@@ -56,8 +49,8 @@ Removes portions of the target layer that fall inside the erasing layer or bound
}
\examples{
if (rmapshaper:::check_v8_major_version() >= 6L) {
- library(geojsonio, quietly = TRUE)
- library(sp)
+ library(geojsonsf, quietly = TRUE)
+ library(sf)
points <- structure("{\"type\":\"FeatureCollection\",
\"features\":[{\"type\":\"Feature\",\"properties\":{},
@@ -74,8 +67,8 @@ if (rmapshaper:::check_v8_major_version() >= 6L) {
{\"type\":\"Point\",\"coordinates\":[61.0835,-40.7529]}},
{\"type\":\"Feature\",\"properties\":{},\"geometry\":
{\"type\":\"Point\",\"coordinates\":[58.0202,-43.634]}}]}",
- class = c("json", "geo_json"))
- points <- geojson_sp(points)
+ class = c("geojson", "json"))
+ points <- geojson_sf(points)
plot(points)
erase_poly <- structure('{
@@ -93,8 +86,8 @@ if (rmapshaper:::check_v8_major_version() >= 6L) {
]
]
}
- }', class = c("json", "geo_json"))
- erase_poly <- geojson_sp(erase_poly)
+ }', class = c("geojson", "json"))
+ erase_poly <- geojson_sf(erase_poly)
out <- ms_erase(points, erase_poly)
plot(out, add = TRUE)
diff --git a/man/ms_explode.Rd b/man/ms_explode.Rd
index 912fcf1..784980c 100644
--- a/man/ms_explode.Rd
+++ b/man/ms_explode.Rd
@@ -4,30 +4,32 @@
\alias{ms_explode}
\title{Convert multipart lines or polygons to singlepart}
\usage{
-ms_explode(input, force_FC = TRUE, sys = FALSE, sys_mem = 8)
+ms_explode(input, ...)
}
\arguments{
\item{input}{One of:
\itemize{
\item \code{geo_json} or \code{character} multipart lines, or polygons;
-\item \code{geo_list} multipart lines, or polygons;
\item multipart \code{SpatialPolygons}, \code{SpatialLines};
\item \code{sf} or \code{sfc} multipart lines, or polygons object
}}
-\item{force_FC}{should the output be forced to be a FeatureCollection (or
-Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}.
-FeatureCollections are more compatible with rgdal::readOGR and
-geojsonio::geojson_sp. If FALSE and there are no attributes associated with
-the geometries, a GeometryCollection (or Spatial object with no dataframe)
-will be output.}
-
-\item{sys}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
+\item{...}{
+ Arguments passed on to \code{\link[=apply_mapshaper_commands]{apply_mapshaper_commands}}
+ \describe{
+ \item{\code{force_FC}}{should the output be forced to be a FeatureCollection (or sf object or
+Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}. If FALSE and
+there are no attributes associated with the geometries, a
+GeometryCollection (or Spatial object with no dataframe, or sfc) will be output.}
+ \item{\code{sys}}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
better performance on large files. Requires the mapshaper node package to be installed
and on the PATH.}
-
-\item{sys_mem}{How much memory (in GB) should be allocated if using the system
-mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.}
+ \item{\code{sys_mem}}{How much memory (in GB) should be allocated if using the system
+mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_mem"}}
+ \item{\code{quiet}}{If \code{sys = TRUE}, should the mapshaper messages be silenced? Default \code{FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_quiet"}}
+ }}
}
\value{
same class as input
@@ -40,27 +42,24 @@ you may find it faster to use \code{sp::disaggregate}.
There is currently no method for SpatialMultiPoints
}
\examples{
-library(geojsonio)
-library(sp)
+library(geojsonsf)
+library(sf)
-poly <- structure("{\"type\":\"FeatureCollection\",\"crs\":
- {\"type\":\"name\",\"properties\":{\"name\":
- \"urn:ogc:def:crs:OGC:1.3:CRS84\"}},\"features\":
+poly <- "{\"type\":\"FeatureCollection\",\"features\":
[\n{\"type\":\"Feature\",\"geometry\":{\"type\":
\"MultiPolygon\",\"coordinates\":[[[[102,2],[102,3],
[103,3],[103,2],[102,2]]],[[[100,0],[100,1],[101,1],
- [101,0],[100,0]]]]},\"properties\":{\"rmapshaperid\":0}}\n]}",
- class = c("json", "geo_json"))
+ [101,0],[100,0]]]]},\"properties\":{\"a\":0}}\n]}"
-poly <- geojson_sp(poly)
+poly <- geojson_sf(poly)
plot(poly)
length(poly)
-poly@data
+poly
# Explode the polygon
out <- ms_explode(poly)
plot(out)
length(out)
-out@data
+out
}
diff --git a/man/ms_filter_fields.Rd b/man/ms_filter_fields.Rd
index 5708cd3..112cf87 100644
--- a/man/ms_filter_fields.Rd
+++ b/man/ms_filter_fields.Rd
@@ -4,25 +4,30 @@
\alias{ms_filter_fields}
\title{Delete fields in the attribute table}
\usage{
-ms_filter_fields(input, fields, sys = FALSE, sys_mem = 8)
+ms_filter_fields(input, fields, ...)
}
\arguments{
\item{input}{spatial object to filter fields on. One of:
\itemize{
\item \code{geo_json} or \code{character} points, lines, or polygons;
-\item \code{geo_list} points, lines, or polygons;
\item \code{SpatialPolygonsDataFrame}, \code{SpatialLinesDataFrame}, \code{SpatialPointsDataFrame};
\item \code{sf} object
}}
\item{fields}{character vector of fields to retain.}
-\item{sys}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
+\item{...}{
+ Arguments passed on to \code{\link[=apply_mapshaper_commands]{apply_mapshaper_commands}}
+ \describe{
+ \item{\code{sys}}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
better performance on large files. Requires the mapshaper node package to be installed
and on the PATH.}
-
-\item{sys_mem}{How much memory (in GB) should be allocated if using the system
-mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.}
+ \item{\code{sys_mem}}{How much memory (in GB) should be allocated if using the system
+mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_mem"}}
+ \item{\code{quiet}}{If \code{sys = TRUE}, should the mapshaper messages be silenced? Default \code{FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_quiet"}}
+ }}
}
\value{
object with only specified attributes retained, in the same class as
@@ -32,20 +37,20 @@ the input
Removes all fields except those listed in the \code{fields} parameter
}
\examples{
-library(geojsonio)
-library(sp)
+library(geojsonsf)
+library(sf)
poly <- structure("{\"type\":\"FeatureCollection\",
\"features\":[{\"type\":\"Feature\",
\"properties\":{\"a\": 1, \"b\":2, \"c\": 3},
\"geometry\":{\"type\":\"Polygon\",
\"coordinates\":[[[102,2],[102,4],[104,4],[104,2],[102,2]]]}}]}",
- class = c("json", "geo_json"))
-poly <- geojson_sp(poly)
-poly@data
+ class = c("geojson", "json"))
+poly <- geojson_sf(poly)
+poly
# Filter (keep) fields a and b, drop c
out <- ms_filter_fields(poly, c("a", "b"))
-out@data
+out
}
diff --git a/man/ms_filter_islands.Rd b/man/ms_filter_islands.Rd
index ac2df1d..ba01ed8 100644
--- a/man/ms_filter_islands.Rd
+++ b/man/ms_filter_islands.Rd
@@ -9,16 +9,13 @@ ms_filter_islands(
min_area = NULL,
min_vertices = NULL,
drop_null_geometries = TRUE,
- force_FC = TRUE,
- sys = FALSE,
- sys_mem = 8
+ ...
)
}
\arguments{
\item{input}{spatial object to filter. One of:
\itemize{
\item \code{geo_json} or \code{character} polygons;
-\item \code{geo_list} polygons;
\item \code{SpatialPolygons*};
\item \code{sf} or \code{sfc} polygons object
}}
@@ -33,19 +30,22 @@ calculated using spherical geometry in units of square meters.}
Default \code{TRUE}. Ignored for \code{SpatialPolyons*}, as it is always
\code{TRUE}.}
-\item{force_FC}{should the output be forced to be a FeatureCollection (or
-Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}.
-FeatureCollections are more compatible with rgdal::readOGR and
-geojsonio::geojson_sp. If FALSE and there are no attributes associated with
-the geometries, a GeometryCollection (or Spatial object with no dataframe)
-will be output.}
-
-\item{sys}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
+\item{...}{
+ Arguments passed on to \code{\link[=apply_mapshaper_commands]{apply_mapshaper_commands}}
+ \describe{
+ \item{\code{force_FC}}{should the output be forced to be a FeatureCollection (or sf object or
+Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}. If FALSE and
+there are no attributes associated with the geometries, a
+GeometryCollection (or Spatial object with no dataframe, or sfc) will be output.}
+ \item{\code{sys}}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
better performance on large files. Requires the mapshaper node package to be installed
and on the PATH.}
-
-\item{sys_mem}{How much memory (in GB) should be allocated if using the system
-mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.}
+ \item{\code{sys_mem}}{How much memory (in GB) should be allocated if using the system
+mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_mem"}}
+ \item{\code{quiet}}{If \code{sys = TRUE}, should the mapshaper messages be silenced? Default \code{FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_quiet"}}
+ }}
}
\value{
object with only specified features retained, in the same class as
@@ -56,8 +56,8 @@ Remove small detached polygons, keeping those with a minimum area and/or a
minimum number of vertices. Optionally remove null geometries.
}
\examples{
-library(geojsonio)
-library(sp)
+library(geojsonsf)
+library(sf)
poly <- structure("{\"type\":\"FeatureCollection\",
\"features\":[{\"type\":\"Feature\",\"properties\":{},
@@ -69,9 +69,9 @@ poly <- structure("{\"type\":\"FeatureCollection\",
{\"type\":\"Feature\",\"properties\":{},
\"geometry\":{\"type\":\"Polygon\",
\"coordinates\":[[[100,0],[100,1],[101,1],[101,0],[100,0]]]}}]}",
- class = c("json", "geo_json"))
+ class = c("geojson", "json"))
-poly <- geojson_sp(poly)
+poly <- geojson_sf(poly)
plot(poly)
out <- ms_filter_islands(poly, min_area = 12391399903)
diff --git a/man/ms_innerlines.Rd b/man/ms_innerlines.Rd
index c218389..ac42726 100644
--- a/man/ms_innerlines.Rd
+++ b/man/ms_innerlines.Rd
@@ -4,30 +4,32 @@
\alias{ms_innerlines}
\title{Create a line layer consisting of shared boundaries with no attribute data}
\usage{
-ms_innerlines(input, force_FC = TRUE, sys = FALSE, sys_mem = 8)
+ms_innerlines(input, ...)
}
\arguments{
\item{input}{input polygons object to convert to inner lines. One of:
\itemize{
\item \code{geo_json} or \code{character} polygons;
-\item \code{geo_list} polygons;
\item \code{SpatialPolygons*};
\item \code{sf} or \code{sfc} polygons object
}}
-\item{force_FC}{should the output be forced to be a FeatureCollection (or
-Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}.
-FeatureCollections are more compatible with rgdal::readOGR and
-geojsonio::geojson_sp. If FALSE and there are no attributes associated with
-the geometries, a GeometryCollection (or Spatial object with no dataframe)
-will be output.}
-
-\item{sys}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
+\item{...}{
+ Arguments passed on to \code{\link[=apply_mapshaper_commands]{apply_mapshaper_commands}}
+ \describe{
+ \item{\code{force_FC}}{should the output be forced to be a FeatureCollection (or sf object or
+Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}. If FALSE and
+there are no attributes associated with the geometries, a
+GeometryCollection (or Spatial object with no dataframe, or sfc) will be output.}
+ \item{\code{sys}}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
better performance on large files. Requires the mapshaper node package to be installed
and on the PATH.}
-
-\item{sys_mem}{How much memory (in GB) should be allocated if using the system
-mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.}
+ \item{\code{sys_mem}}{How much memory (in GB) should be allocated if using the system
+mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_mem"}}
+ \item{\code{quiet}}{If \code{sys = TRUE}, should the mapshaper messages be silenced? Default \code{FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_quiet"}}
+ }}
}
\value{
lines in the same class as the input layer, but without attributes
@@ -36,8 +38,8 @@ lines in the same class as the input layer, but without attributes
Create a line layer consisting of shared boundaries with no attribute data
}
\examples{
-library(geojsonio)
-library(sp)
+library(geojsonsf)
+library(sf)
poly <- structure('{"type":"FeatureCollection",
"features":[
@@ -60,9 +62,9 @@ poly <- structure('{"type":"FeatureCollection",
"properties":{"foo": "b"},
"geometry":{"type":"Polygon","coordinates":[[
[103,1],[103,2],[104,2],[104,1],[103,1]
- ]]}}]}', class = c("json", "geo_json"))
+ ]]}}]}', class = c("geojson", "json"))
-poly <- geojson_sp(poly)
+poly <- geojson_sf(poly)
plot(poly)
out <- ms_innerlines(poly)
diff --git a/man/ms_lines.Rd b/man/ms_lines.Rd
index eb77127..3bf6dc1 100644
--- a/man/ms_lines.Rd
+++ b/man/ms_lines.Rd
@@ -4,13 +4,12 @@
\alias{ms_lines}
\title{Convert polygons to topological boundaries (lines)}
\usage{
-ms_lines(input, fields = NULL, force_FC = TRUE, sys = FALSE, sys_mem = 8)
+ms_lines(input, fields = NULL, ...)
}
\arguments{
\item{input}{input polygons object to convert to inner lines. One of:
\itemize{
\item \code{geo_json} or \code{character} polygons;
-\item \code{geo_list} polygons;
\item \code{SpatialPolygons*};
\item \code{sf} or \code{sfc} polygons object
}}
@@ -22,19 +21,22 @@ intermediate level of hierarchy at TYPE 1, with the lowest-level internal
boundaries set to TYPE 2. Supplying a character vector of field names adds
additional levels of hierarchy.}
-\item{force_FC}{should the output be forced to be a FeatureCollection (or
-Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}.
-FeatureCollections are more compatible with rgdal::readOGR and
-geojsonio::geojson_sp. If FALSE and there are no attributes associated with
-the geometries, a GeometryCollection (or Spatial object with no dataframe)
-will be output.}
-
-\item{sys}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
+\item{...}{
+ Arguments passed on to \code{\link[=apply_mapshaper_commands]{apply_mapshaper_commands}}
+ \describe{
+ \item{\code{force_FC}}{should the output be forced to be a FeatureCollection (or sf object or
+Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}. If FALSE and
+there are no attributes associated with the geometries, a
+GeometryCollection (or Spatial object with no dataframe, or sfc) will be output.}
+ \item{\code{sys}}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
better performance on large files. Requires the mapshaper node package to be installed
and on the PATH.}
-
-\item{sys_mem}{How much memory (in GB) should be allocated if using the system
-mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.}
+ \item{\code{sys_mem}}{How much memory (in GB) should be allocated if using the system
+mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_mem"}}
+ \item{\code{quiet}}{If \code{sys = TRUE}, should the mapshaper messages be silenced? Default \code{FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_quiet"}}
+ }}
}
\value{
topological boundaries as lines, in the same class as the input
@@ -44,8 +46,8 @@ Convert polygons to topological boundaries (lines)
}
\examples{
-library(geojsonio)
-library(sp)
+library(geojsonsf)
+library(sf)
poly <- structure('{"type":"FeatureCollection",
"features":[
@@ -63,9 +65,9 @@ poly <- structure('{"type":"FeatureCollection",
"properties":{"foo": "b"},
"geometry":{"type":"Polygon","coordinates":[[
[102.5,1],[102.5,2],[103.5,2],[103.5,1],[102.5,1]
- ]]}}]}', class = c("json", "geo_json"))
+ ]]}}]}', class = c("geojson", "json"))
-poly <- geojson_sp(poly)
+poly <- geojson_sf(poly)
summary(poly)
plot(poly)
diff --git a/man/ms_points.Rd b/man/ms_points.Rd
index 9e80e42..81838d6 100644
--- a/man/ms_points.Rd
+++ b/man/ms_points.Rd
@@ -4,21 +4,12 @@
\alias{ms_points}
\title{Create points from a polygon layer}
\usage{
-ms_points(
- input,
- location = NULL,
- x = NULL,
- y = NULL,
- force_FC = TRUE,
- sys = FALSE,
- sys_mem = 8
-)
+ms_points(input, location = NULL, x = NULL, y = NULL, ...)
}
\arguments{
\item{input}{input polygons object to convert to points. One of:
\itemize{
\item \code{geo_json} or \code{character} polygons;
-\item \code{geo_list} polygons;
\item \code{SpatialPolygons*};
\item \code{sf} or \code{sfc} polygons object
}}
@@ -36,19 +27,22 @@ specified. If left as \code{NULL} (default), will use centroids.}
\item{y}{name of field containing y coordinate values. Must be \code{NULL} if
\code{location} is specified.}
-\item{force_FC}{should the output be forced to be a FeatureCollection (or
-Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}.
-FeatureCollections are more compatible with rgdal::readOGR and
-geojsonio::geojson_sp. If FALSE and there are no attributes associated with
-the geometries, a GeometryCollection (or Spatial object with no dataframe)
-will be output.}
-
-\item{sys}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
+\item{...}{
+ Arguments passed on to \code{\link[=apply_mapshaper_commands]{apply_mapshaper_commands}}
+ \describe{
+ \item{\code{force_FC}}{should the output be forced to be a FeatureCollection (or sf object or
+Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}. If FALSE and
+there are no attributes associated with the geometries, a
+GeometryCollection (or Spatial object with no dataframe, or sfc) will be output.}
+ \item{\code{sys}}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
better performance on large files. Requires the mapshaper node package to be installed
and on the PATH.}
-
-\item{sys_mem}{How much memory (in GB) should be allocated if using the system
-mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.}
+ \item{\code{sys_mem}}{How much memory (in GB) should be allocated if using the system
+mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_mem"}}
+ \item{\code{quiet}}{If \code{sys = TRUE}, should the mapshaper messages be silenced? Default \code{FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_quiet"}}
+ }}
}
\value{
points in the same class as the input.
@@ -59,8 +53,8 @@ Can be generated from the polygons by specifying \code{location} to be
attributes of the layer containing \code{x} and \code{y} coordinates.
}
\examples{
-library(geojsonio)
-library(sp)
+library(geojsonsf)
+library(sf)
poly <- structure("{\"type\":\"FeatureCollection\",
\"features\":[{\"type\":\"Feature\",\"properties\":
@@ -73,9 +67,9 @@ poly <- structure("{\"type\":\"FeatureCollection\",
{\"type\":\"Feature\",\"properties\":{\"x_pos\": 5, \"y_pos\": 6},
\"geometry\":{\"type\":\"Polygon\",
\"coordinates\":[[[100,0],[100,1],[101,1],[101,0],[100,0]]]}}]}",
- class = c("json", "geo_json"))
+ class = c("geojson", "json"))
-poly <- geojson_sp(poly)
+poly <- geojson_sf(poly)
summary(poly)
plot(poly)
diff --git a/man/ms_simplify.Rd b/man/ms_simplify.Rd
index db7d3e2..16e39d4 100644
--- a/man/ms_simplify.Rd
+++ b/man/ms_simplify.Rd
@@ -13,18 +13,15 @@ ms_simplify(
no_repair = FALSE,
snap = TRUE,
explode = FALSE,
- force_FC = TRUE,
drop_null_geometries = TRUE,
snap_interval = NULL,
- sys = FALSE,
- sys_mem = 8
+ ...
)
}
\arguments{
\item{input}{spatial object to simplify. One of:
\itemize{
\item \code{geo_json} or \code{character} polygons or lines;
-\item \code{geo_list} polygons or lines;
\item \code{SpatialPolygons*} or \code{SpatialLines*};
\item \code{sf} or \code{sfc} polygons or lines object
}}
@@ -56,25 +53,28 @@ small coordinate misalignment in adjacent polygons. Default \code{TRUE}.}
This prevents small shapes from disappearing during simplification if
\code{keep_shapes = TRUE}. Default \code{FALSE}}
-\item{force_FC}{should the output be forced to be a FeatureCollection (or
-Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}.
-FeatureCollections are more compatible with rgdal::readOGR and
-geojsonio::geojson_sp. If FALSE and there are no attributes associated with
-the geometries, a GeometryCollection (or Spatial object with no dataframe)
-will be output.}
-
\item{drop_null_geometries}{should Features with null geometries be dropped?
Ignored for \code{Spatial*} objects, as it is always \code{TRUE}.}
\item{snap_interval}{Specify snapping distance in source units, must be a
numeric. Default \code{NULL}}
-\item{sys}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
+\item{...}{
+ Arguments passed on to \code{\link[=apply_mapshaper_commands]{apply_mapshaper_commands}}
+ \describe{
+ \item{\code{force_FC}}{should the output be forced to be a FeatureCollection (or sf object or
+Spatial*DataFrame) even if there are no attributes? Default \code{TRUE}. If FALSE and
+there are no attributes associated with the geometries, a
+GeometryCollection (or Spatial object with no dataframe, or sfc) will be output.}
+ \item{\code{sys}}{Should the system mapshaper be used instead of the bundled mapshaper? Gives
better performance on large files. Requires the mapshaper node package to be installed
and on the PATH.}
-
-\item{sys_mem}{How much memory (in GB) should be allocated if using the system
-mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.}
+ \item{\code{sys_mem}}{How much memory (in GB) should be allocated if using the system
+mapshaper (\code{sys = TRUE})? Default 8. Ignored if \code{sys = FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_mem"}}
+ \item{\code{quiet}}{If \code{sys = TRUE}, should the mapshaper messages be silenced? Default \code{FALSE}.
+This can also be set globally with the option \code{"mapshaper.sys_quiet"}}
+ }}
}
\value{
a simplified representation of the geometry in the same class as the
@@ -114,13 +114,13 @@ poly <- structure('{
[-70.603637, -33.399918]
]]
}
-}', class = c("json", "geo_json"))
+}', class = c("geojson", "json"))
ms_simplify(poly, keep = 0.1)
-# With a SpatialPolygonsDataFrame:
+# With an sf object
-poly_sp <- geojsonio::geojson_sp(poly)
-ms_simplify(poly_sp, keep = 0.5)
+poly_sf <- geojsonsf::geojson_sf(poly)
+ms_simplify(poly_sf, keep = 0.5)
}
diff --git a/man/rmapshaper.Rd b/man/rmapshaper.Rd
index af13740..6109596 100644
--- a/man/rmapshaper.Rd
+++ b/man/rmapshaper.Rd
@@ -10,9 +10,6 @@ This is wrapper around the 'mapshaper' 'javascript' library by Matthew Bloch
\url{https://github.com/mbloch/mapshaper/} to perform topologically-aware
polygon simplification, as well as other operations such as clipping,
erasing, dissolving, and converting 'multi-part' to 'single-part' geometries.
-It relies on the 'geojsonio' package for working with 'geojson' objects, the 'sf'
-package for working with 'sf' objects, and the 'sp' and 'rgdal' packages for
-working with 'Spatial' objects.
}
\section{rmapshaper functions}{
diff --git a/rmapshaper.Rproj b/rmapshaper.Rproj
index 7fa7884..9a2c6bf 100755
--- a/rmapshaper.Rproj
+++ b/rmapshaper.Rproj
@@ -16,7 +16,6 @@ StripTrailingWhitespace: Yes
BuildType: Package
PackageUseDevtools: Yes
-PackageCleanBeforeInstall: Yes
PackageInstallArgs: --no-multiarch --with-keep.source
PackageCheckArgs: --as-cran
PackageRoxygenize: rd,collate,namespace
diff --git a/scratch/fedora-test/Dockerfile b/scratch/docker/fedora-test/Dockerfile
similarity index 100%
rename from scratch/fedora-test/Dockerfile
rename to scratch/docker/fedora-test/Dockerfile
diff --git a/scratch/fedora-test/README.Rmd b/scratch/docker/fedora-test/README.Rmd
similarity index 100%
rename from scratch/fedora-test/README.Rmd
rename to scratch/docker/fedora-test/README.Rmd
diff --git a/scratch/fedora-test/README.md b/scratch/docker/fedora-test/README.md
similarity index 100%
rename from scratch/fedora-test/README.md
rename to scratch/docker/fedora-test/README.md
diff --git a/scratch/docker/fedora-test/poly.geojson b/scratch/docker/fedora-test/poly.geojson
new file mode 100644
index 0000000..55466c4
Binary files /dev/null and b/scratch/docker/fedora-test/poly.geojson differ
diff --git a/scratch/docker/fedora-test/poly_simp.geojson b/scratch/docker/fedora-test/poly_simp.geojson
new file mode 100644
index 0000000..2da66bf
--- /dev/null
+++ b/scratch/docker/fedora-test/poly_simp.geojson
@@ -0,0 +1,3 @@
+{"type":"FeatureCollection", "features": [
+{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[1745493.1964,6001802.1687],[1688395.3701,5989681.2008],[1611887.8264,6107105.9235],[1684932.9873,6121315.2794],[1745493.1964,6001802.1687]]]},"properties":{"foo":"bar"}}
+]}
\ No newline at end of file
diff --git a/scratch/docker/fedora-test/regional-council-2018-clipped-generalised.gpkg b/scratch/docker/fedora-test/regional-council-2018-clipped-generalised.gpkg
new file mode 100644
index 0000000..1aa6d2b
Binary files /dev/null and b/scratch/docker/fedora-test/regional-council-2018-clipped-generalised.gpkg differ
diff --git a/scratch/docker/fedora-test/statsnzregional-council-2018-clipped-generalised-GPKG.zip b/scratch/docker/fedora-test/statsnzregional-council-2018-clipped-generalised-GPKG.zip
new file mode 100644
index 0000000..c53be7b
Binary files /dev/null and b/scratch/docker/fedora-test/statsnzregional-council-2018-clipped-generalised-GPKG.zip differ
diff --git a/scratch/fedora-test/test.R b/scratch/docker/fedora-test/test.R
similarity index 100%
rename from scratch/fedora-test/test.R
rename to scratch/docker/fedora-test/test.R
diff --git a/scratch/docker/linux-check/Dockerfile b/scratch/docker/linux-check/Dockerfile
new file mode 100644
index 0000000..ea01389
--- /dev/null
+++ b/scratch/docker/linux-check/Dockerfile
@@ -0,0 +1,9 @@
+FROM jakubnowosad/rspatial_proj7:latest
+
+# RUN sudo apt-get update && apt-get install -y curl
+
+# RUN curl -sL https://deb.nodesource.com/setup_13.x | sudo -E bash - \
+# && sudo apt-get install -y libnode-dev libnode64 nodejs \
+# && npm install -g mapshaper
+
+RUN Rscript -e "install.packages(c('devtools', 'sf', 'V8', 'sp', 'geojsonsf', 'readr', 'geojsonlint', 'rgdal', 'geojsonio'))"
diff --git a/scratch/docker/linux-check/README.md b/scratch/docker/linux-check/README.md
new file mode 100644
index 0000000..27df2fc
--- /dev/null
+++ b/scratch/docker/linux-check/README.md
@@ -0,0 +1,12 @@
+```
+docker build --tag deb-test .
+docker run -d -p 8787:8787 -e PASSWORD=hello deb-test:latest
+```
+
+Go to localhost:8787 and log in with rstudio/hello. In terminal in Rstudio:
+
+```
+git clone https://github.com/ateucher/rmapshaper.git
+```
+
+Then open the `rmapshaper.Rproj` and run checks etc.
diff --git a/scratch/test_conversion_performance/test_conversion_performance.R b/scratch/test_conversion_performance/test_conversion_performance.R
new file mode 100644
index 0000000..ff43d6f
--- /dev/null
+++ b/scratch/test_conversion_performance/test_conversion_performance.R
@@ -0,0 +1,54 @@
+#' ---
+#' output: github_document
+#' ---
+
+library(sf)
+library(geojsonio)
+library(sp)
+library(rgdal)
+devtools::load_all()
+
+u = "https://borders.ukdataservice.ac.uk/ukborders/easy_download/prebuilt/shape/England_caswa_2001_clipped.zip"
+# download.file(u, destfile = "zipped_shapefile.zip")
+unzip("zipped_shapefile.zip")
+f = list.files(pattern = ".shp")
+
+# sf
+res = sf::st_read(f)
+
+res_simp <- ms_simplify(res, sys = TRUE)
+
+## Test converting sf to geojson object
+system.time(js_gjio <- geojson_json(res_simp))
+
+system.time(js_int <- sf_to_GeoJSON(res_simp))
+
+all.equal(as.character(js_gjio), as.character(js_int))
+
+## Test writing sf to geojson file
+system.time(st_write(res, tempfile(fileext = ".geojson")))
+
+system.time(sf_sp_to_tempfile(res))
+
+system.time(
+ jsonlite::write_json(unclass(geojson_list(res)), path = tempfile(fileext = ".geojson"),
+ auto_unbox = TRUE, digits = 7)
+)
+
+# sp
+res_sp <- as(res, "Spatial")
+res_sp_simp <- as(res_simp, "Spatial")
+
+## Test converting sf to geojson object
+system.time(js_gjio <- geojson_json(res_sp_simp))
+
+system.time(js_int <- sp_to_GeoJSON(res_sp_simp))
+
+## Test writing sp to geojson file
+f <- tempfile()
+system.time(
+ writeOGR(res_sp, paste0(f, ".geojson"), basename(f), driver = "GeoJSON",
+ check_exists = FALSE)
+)
+
+system.time(sf_sp_to_tempfile(res_sp))
diff --git a/scratch/test_conversion_performance/test_conversion_performance.html b/scratch/test_conversion_performance/test_conversion_performance.html
new file mode 100644
index 0000000..123c565
--- /dev/null
+++ b/scratch/test_conversion_performance/test_conversion_performance.html
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
test_conversion_performance.R
+
ateucher
+Mon Feb 5 15:02:19 2018
+
library(sf)
+
## Linking to GEOS 3.6.2, GDAL 2.2.3, proj.4 4.9.3
+
library(geojsonio)
+
##
+## Attaching package: 'geojsonio'
+
+## The following object is masked from 'package:devtools':
+##
+## lint
+
+## The following object is masked from 'package:base':
+##
+## pretty
+
library(sp)
+library(rgdal)
+
## rgdal: version: 1.2-16, (SVN revision 701)
+## Geospatial Data Abstraction Library extensions to R successfully loaded
+## Loaded GDAL runtime: GDAL 2.2.3, released 2017/11/20
+## Path to GDAL shared files: /usr/local/Cellar/gdal2/2.2.3/share/gdal
+## GDAL binary built with GEOS: TRUE
+## Loaded PROJ.4 runtime: Rel. 4.9.3, 15 August 2016, [PJ_VERSION: 493]
+## Path to PROJ.4 shared files: (autodetected)
+## Linking to sp version: 1.2-6
+
devtools::load_all()
+
## Loading rmapshaper
+
u = "https://borders.ukdataservice.ac.uk/ukborders/easy_download/prebuilt/shape/England_caswa_2001_clipped.zip"
+# download.file(u, destfile = "zipped_shapefile.zip")
+unzip("zipped_shapefile.zip")
+f =list.files(pattern =".shp")
+
+# sf
+res =sf::st_read(f)
+
## Reading layer `england_caswa_2001_clipped' from data source `/Users/ateucher/dev/rmapshaper/scratch/england_caswa_2001_clipped.shp' using driver `ESRI Shapefile'
+## Simple feature collection with 6930 features and 5 fields
+## geometry type: MULTIPOLYGON
+## dimension: XY
+## bbox: xmin: 85665 ymin: 7054 xmax: 655604 ymax: 657534.1
+## epsg (SRID): NA
+## proj4string: +proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +datum=OSGB36 +units=m +no_defs
+
res_simp <-ms_simplify(res, sys =TRUE)
+
+## Test converting sf to geojson object
+system.time(js_gjio <-geojson_json(res_simp))