Repository: sjewo/cartogram
Branch: master
Commit: 993422a45e81
Files: 29
Total size: 68.1 KB
Directory structure:
gitextract_6no1pgat/
├── .Rbuildignore
├── .github/
│ ├── .gitignore
│ └── workflows/
│ ├── R-CMD-check.yaml
│ ├── pkgdown.yaml
│ └── recheck.yaml
├── .gitignore
├── .lintr
├── DESCRIPTION
├── NAMESPACE
├── NEWS.md
├── R/
│ ├── cartogram_cont.R
│ ├── cartogram_dorling.R
│ ├── cartogram_ncont.R
│ └── utils.R
├── README.Rmd
├── README.md
├── _pkgdown.yml
├── cartogram.Rproj
├── man/
│ ├── cartogram.Rd
│ ├── cartogram_assert_package.Rd
│ ├── cartogram_cont.Rd
│ ├── cartogram_dorling.Rd
│ ├── cartogram_ncont.Rd
│ └── nc_cartogram.Rd
└── tests/
├── testthat/
│ ├── test-cartogram_cont.R
│ ├── test-cartogram_ncont.R
│ ├── test-markdown.R
│ └── test.Rmd
└── testthat.R
================================================
FILE CONTENTS
================================================
================================================
FILE: .Rbuildignore
================================================
^.*\.Rproj$
^\.Rproj\.user$
^\.travis\.yml$
^README\.Rmd$
^README-.*\.png$
^_pkgdown\.yml$
^docs$
^pkgdown$
^\.github$
^private$
^.cache$
^.config$
^.local$
^.vscode$
^.DS_Store$
^.lintr$
================================================
FILE: .github/.gitignore
================================================
*.html
================================================
FILE: .github/workflows/R-CMD-check.yaml
================================================
# 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: R-CMD-check
jobs:
R-CMD-check:
runs-on: ${{ matrix.config.os }}
name: ${{ matrix.config.os }} (${{ matrix.config.r }})
strategy:
fail-fast: false
matrix:
config:
- {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:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
R_KEEP_PKG_SOURCE: yes
steps:
- uses: actions/checkout@v3
- 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-r-dependencies@v2
with:
extra-packages: any::rcmdcheck
needs: check
- uses: r-lib/actions/check-r-package@v2
with:
upload-snapshots: true
================================================
FILE: .github/workflows/pkgdown.yaml
================================================
# 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]
release:
types: [published]
workflow_dispatch:
name: pkgdown
jobs:
pkgdown:
runs-on: ubuntu-latest
# Only restrict concurrency for non-PR jobs
concurrency:
group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }}
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
permissions:
contents: write
steps:
- uses: actions/checkout@v3
- uses: r-lib/actions/setup-pandoc@v2
- uses: r-lib/actions/setup-r@v2
with:
use-public-rspm: true
- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::pkgdown, local::.
needs: website
- name: Build site
run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE)
shell: Rscript {0}
- name: Deploy to GitHub pages 🚀
if: github.event_name != 'pull_request'
uses: JamesIves/github-pages-deploy-action@v4.4.1
with:
clean: false
branch: gh-pages
folder: docs
================================================
FILE: .github/workflows/recheck.yaml
================================================
on:
workflow_dispatch:
inputs:
which:
type: choice
description: Which dependents to check
options:
- strong
- most
name: Reverse dependency check
jobs:
revdep_check:
name: Reverse check ${{ inputs.which }} dependents
uses: r-devel/recheck/.github/workflows/recheck.yml@v1
with:
which: ${{ inputs.which }}
================================================
FILE: .gitignore
================================================
# History files
.Rhistory
.Rapp.history
# Session Data files
.RData
# Example code in package build process
*-Ex.R
# Output files from R CMD build
/*.tar.gz
# Output files from R CMD check
/*.Rcheck/
# RStudio files
.Rproj.user/
# produced vignettes
vignettes/*.html
vignettes/*.pdf
# OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3
.httr-oauth
# knitr and R markdown default cache directories
/*_cache/
/cache/
# Temporary files created by R markdown
*.utf8.md
*.knit.md
.Rproj.user
# VIM files
*.swp
# pkgdown
docs
# private folder for draft test scripts
private
.cache
.config
.local
.vscode
.DS_Store
================================================
FILE: .lintr
================================================
linters: linters_with_defaults(
return_linter = NULL,
line_length_linter = NULL,
commented_code_linter = NULL,
object_name_linter = NULL,
quotes_linter = NULL,
indentation_linter = NULL)
================================================
FILE: DESCRIPTION
================================================
Package: cartogram
Title: Create Cartograms with R
Version: 0.4.0
Authors@R: c(
person("Sebastian", "Jeworutzki", , "sebastian.jeworutzki@ruhr-uni-bochum.de", role = c("aut", "cre"),
comment = c(ORCID = "0000-0002-2671-5253")),
person("Timothee", "Giraud", role = "ctb"),
person("Nicolas", "Lambert", role = "ctb"),
person("Roger", "Bivand", , "Roger.Bivand@nhh.no", role = "cph"),
person("Edzer", "Pebesma", role = "cph"),
person("Jakub", "Nowosad", , "nowosad.jakub@gmail.com", role = "ctb",
comment = c(ORCID = "0000-0002-1057-3721")),
person("Egor", "Kotov", , "kotov.egor@gmail.com", role = "ctb",
comment = c(ORCID = "0000-0001-6690-5345"))
)
Description: Construct continuous and non-contiguous area cartograms.
License: GPL-3
URL: https://github.com/sjewo/cartogram,
https://sjewo.github.io/cartogram/
BugReports: https://github.com/sjewo/cartogram/issues
Imports:
methods,
packcircles,
rlang,
sf
Suggests:
future (>= 1.40.0),
future.apply,
parallelly,
progressr,
rmarkdown,
testthat (>= 3.0.0),
tmap
Config/testthat/edition: 3
Encoding: UTF-8
RoxygenNote: 7.3.2
Roxygen: list(markdown = TRUE)
================================================
FILE: NAMESPACE
================================================
# Generated by roxygen2: do not edit by hand
S3method(cartogram_cont,SpatialPolygonsDataFrame)
S3method(cartogram_cont,sf)
S3method(cartogram_dorling,SpatialPolygonsDataFrame)
S3method(cartogram_dorling,sf)
S3method(cartogram_ncont,SpatialPolygonsDataFrame)
S3method(cartogram_ncont,sf)
export(cartogram)
export(cartogram_cont)
export(cartogram_dorling)
export(cartogram_ncont)
export(nc_cartogram)
importFrom(methods,as)
importFrom(methods,is)
importFrom(methods,slot)
importFrom(packcircles,circleRepelLayout)
importFrom(sf,"st_crs<-")
importFrom(sf,"st_geometry<-")
importFrom(sf,st_area)
importFrom(sf,st_as_sf)
importFrom(sf,st_buffer)
importFrom(sf,st_cast)
importFrom(sf,st_centroid)
importFrom(sf,st_coordinates)
importFrom(sf,st_crs)
importFrom(sf,st_distance)
importFrom(sf,st_geometry)
importFrom(sf,st_geometry_type)
importFrom(sf,st_is_longlat)
importFrom(sf,st_point)
importFrom(sf,st_union)
importFrom(stats,quantile)
================================================
FILE: NEWS.md
================================================
# cartogram 0.4.0
* The new `n_cpu` option in `cartogram_cont()` and `cartogram_ncont()` enables distortion calculation across multiple CPU cores (thanks to [e-kotov](https://github.com/e-kotov)!)
* The default threshold value in `cartogram_cont()` will now automatically increase if the weighting variable contains a significant number of zeros.
* Additional tests have been implemented.
# cartogram 0.3.0
* Remove `sp`, `rgdal` and `maptools` from examples and suggestions.
* `cartogram_cont()` has a new parameter `verbose = FALSE` to hide print of size error on each iteration.
# cartogram 0.2.2
* Fix geometry replacement in `cartogram_ncont`
# cartogram 0.2.0
* Migrated all functions to sf, fixed problems with multipolygons.
* cartogram functions won't accept features with longitude/latitude coordinates anymore.
# cartogram 0.1.1
* Update sf code. Thanks to [@Nowosad](https://github.com/Nowosad) for speeding things up!
# cartogram 0.1.0
* Non-Overlapping Circles Cartogram (Dorling)
# cartogram 0.0.3
* sf support added
# cartogram 0.0.2
* Non-contiguous Area Cartogram
* Prepare data with missing or extreme values before cartogram calculation for faster convergence
# cartogram 0.0.1
* Initial Release
================================================
FILE: R/cartogram_cont.R
================================================
# Copyright (C) 2016 Sebastian Jeworutzki
# Copyright (C) of 'checkPolygonsGEOS' from package maptools Roger Bivand and Edzer Pebesma
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#' @title Calculate Contiguous Cartogram Boundaries
#' @description Construct a continuous area cartogram by a rubber sheet distortion algorithm (Dougenik et al. 1985)
#'
#' @name cartogram_cont
#' @param x a polygon or multiplogyon sf object
#' @param weight Name of the weighting variable in x
#' @param itermax Maximum iterations for the cartogram transformation, if maxSizeError ist not reached
#' @param maxSizeError Stop if meanSizeError is smaller than maxSizeError
#' @param prepare Weighting values are adjusted to reach convergence much earlier. Possible methods are:
#' * "adjust", adjust values to restrict the mass vector to the quantiles defined by threshold and 1-threshold (default),
#' * "remove", remove features with values lower than quantile at threshold,
#' * "none", don't adjust weighting values
#' @param threshold "auto" or a threshold value between 0 and 1. With “auto”, the value is 0.05 or, if the proportion of zeros in the weight is greater than 0.05, the value is adjusted accordingly.
#' @param verbose print meanSizeError on each iteration
#' @param n_cpu Number of cores to use. Defaults to "respect_future_plan". Available options are:
#' * "respect_future_plan" - By default, the function will run on a single core, unless the user specifies the number of cores using \code{\link[future]{plan}} (e.g. `future::plan(future::multisession, workers = 4)`) before running the `cartogram_cont` function.
#' * "auto" - Use all except available cores (identified with \code{\link[parallelly]{availableCores}}) except 1, to keep the system responsive.
#' * a `numeric` value - Use the specified number of cores. In this case `cartogram_cont` will use set the specified number of cores internally with `future::plan(future::multisession, workers = n_cpu)` and revert that back by switching the plan back to whichever plan might have been set before by the user. If only 1 core is set, the function will not require `future` and `future.apply` and will run on a single core.
#' @param show_progress A `logical` value. If TRUE, show progress bar. Defaults to TRUE.
#' @return An object of the same class as x
#' @export
#' @importFrom methods is slot
#' @importFrom stats quantile
#' @importFrom sf st_area st_as_sf st_centroid st_coordinates st_distance st_geometry st_geometry<- st_point st_crs st_crs<-
#' @examples
#'# ========= Basic example =========
#'library(sf)
#'library(cartogram)
#'
# Load North Carolina SIDS data
#'nc = st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
#'
#'# transform to NAD83 / UTM zone 16N
#'nc_utm <- st_transform(nc, 26916)
#'
#'# Create cartogram
#'nc_utm_carto <- cartogram_cont(nc_utm, weight = "BIR74", itermax = 5)
#'
#'# Plot
#'par(mfrow=c(2,1))
#'plot(nc[,"BIR74"], main="original", key.pos = NULL, reset = FALSE)
#'plot(nc_utm_carto[,"BIR74"], main="distorted", key.pos = NULL, reset = FALSE)
#'
#'
#'# ========= Advanced example 1 =========
#'# Faster cartogram using multiple CPU cores
#'# using n_cpu parameter
#'library(sf)
#'library(cartogram)
#'
# Load North Carolina SIDS data
#'nc = st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
#'
#'# transform to NAD83 / UTM zone 16N
#'nc_utm <- st_transform(nc, 26916)
#'
#'# Create cartogram using 2 CPU cores on local machine
#'nc_utm_carto <- cartogram_cont(nc_utm, weight = "BIR74", itermax = 5,
#' n_cpu = 2)
#'
#'# Plot
#'par(mfrow=c(2,1))
#'plot(nc[,"BIR74"], main="original", key.pos = NULL, reset = FALSE)
#'plot(nc_utm_carto[,"BIR74"], main="distorted", key.pos = NULL, reset = FALSE)
#'
#'
#'# ========= Advanced example 2 =========
#'# Faster cartogram using multiple CPU cores
#'# using future package plan
#'\donttest{
#'library(sf)
#'library(cartogram)
#'library(future)
#'
# Load North Carolina SIDS data
#'nc = st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
#'
#'# transform to NAD83 / UTM zone 16N
#'nc_utm <- st_transform(nc, 26916)
#'
#'# Set the future plan with 2 CPU local cores
#'# You can of course use any other plans, not just multisession
#'future::plan(future::multisession, workers = 2)
#'
#'# Create cartogram with multiple CPU cores
#'# The cartogram_cont() will respect the plan set above
#'nc_utm_carto <- cartogram_cont(nc_utm, weight = "BIR74", itermax = 5)
#'
#'# Shutdown the R processes that were created by the future plan
#'future::plan(future::sequential)
#'
#'# Plot
#'par(mfrow=c(2,1))
#'plot(nc[,"BIR74"], main="original", key.pos = NULL, reset = FALSE)
#'plot(nc_utm_carto[,"BIR74"], main="distorted", key.pos = NULL, reset = FALSE)
#'}
#'
#' @references Dougenik, J. A., Chrisman, N. R., & Niemeyer, D. R. (1985). An Algorithm To Construct Continuous Area Cartograms. In The Professional Geographer, 37(1), 75-81.
cartogram_cont <- function(x, weight, itermax = 15, maxSizeError = 1.0001,
prepare = "adjust", threshold = "auto", verbose = FALSE,
n_cpu = getOption("cartogram_n_cpu", "respect_future_plan"),
show_progress = getOption("cartogram.show_progress", TRUE)) {
UseMethod("cartogram_cont")
}
#' @title Calculate Contiguous Cartogram Boundaries
#' @description This function has been renamed: Please use cartogram_cont() instead of cartogram().
#'
#' @export
#' @param shp SpatialPolygonDataFrame or an sf object
#' @inheritDotParams cartogram_cont -x
#' @keywords internal
cartogram <- function(shp, ...) {
message("\nPlease use cartogram_cont() instead of cartogram().\n")
cartogram_cont(x = shp, ...)
}
#' @rdname cartogram_cont
#' @importFrom sf st_as_sf
#' @export
cartogram_cont.SpatialPolygonsDataFrame <- function(x, weight, itermax = 15, maxSizeError = 1.0001,
prepare = "adjust", threshold = "auto", verbose = FALSE,
n_cpu = getOption("cartogram_n_cpu", "respect_future_plan"),
show_progress = getOption("cartogram.show_progress", TRUE)) {
as(cartogram_cont.sf(sf::st_as_sf(x), weight, itermax = itermax, maxSizeError = maxSizeError,
prepare = prepare, threshold = threshold, verbose = verbose, n_cpu = n_cpu, show_progress = show_progress), 'Spatial')
}
#' @rdname cartogram_cont
#' @importFrom sf st_area st_geometry st_geometry_type st_centroid st_crs st_coordinates st_buffer st_is_longlat
#' @export
cartogram_cont.sf <- function(x, weight, itermax = 15, maxSizeError = 1.0001,
prepare = "adjust", threshold = "auto", verbose = FALSE,
n_cpu = getOption("cartogram_n_cpu", "respect_future_plan"),
show_progress = getOption("cartogram.show_progress", TRUE)) {
if (isTRUE(sf::st_is_longlat(x))) {
stop('Using an unprojected map. This function does not give correct centroids and distances for longitude/latitude data:\nUse "st_transform()" to transform coordinates to another projection.', call. = FALSE)
}
# Check n_cpu parameter and set up parallel processing
if (length(n_cpu) > 1) {
stop('Invalid value for `n_cpu`. Use "respect_future_plan", "auto", or a numeric value.', call. = FALSE)
}
# Check if weight variable exists
if (!(weight %in% names(x))) {
stop('There is no variable "', weight, '" in object "', deparse(substitute(x)), '".', call. = FALSE)
}
# Determine if we should use multithreading
if (is.numeric(n_cpu) && n_cpu == 1) {
multithreadded <- FALSE
} else if (is.numeric(n_cpu) && n_cpu > 1) {
cartogram_assert_package(c("future", "future.apply"))
with(future::plan(future::multisession, workers = n_cpu), local = TRUE)
multithreadded <- TRUE
} else if (n_cpu == "auto") {
cartogram_assert_package("parallelly")
n_cpu <- max(parallelly::availableCores() - 1, 1)
if (n_cpu == 1) {
multithreadded <- FALSE
} else if (n_cpu > 1) {
cartogram_assert_package(c("future", "future.apply"))
with(future::plan(future::multisession, workers = n_cpu), local = TRUE)
multithreadded <- TRUE
if (verbose) {
message("Using ", n_cpu, " cores for parallel processing.\n")
}
}
} else if (n_cpu == "respect_future_plan") {
if (rlang::is_installed("future")) {
if (is(future::plan(), "sequential")) {
multithreadded <- FALSE
} else {
multithreadded <- TRUE
}
} else {
multithreadded <- FALSE
}
} else {
stop('Invalid value for `n_cpu`. Use "respect_future_plan", "auto", or a numeric value.', call. = FALSE)
}
# prepare data
value <- x[[weight]]
# Adjust threshold on zero inflated data
# Set the threshold value to the proportion of zeros + number of cases corresponding to 1% of the observations, if larger than default value of 0.05
if (threshold == "auto") {
threshold <- round(max(0.05, (sum(value == 0, na.rm = TRUE) + ceiling(length(value) / 100)) / length(value)), 2)
if (verbose) {
message("\nSetting threshold parameter to ", threshold, ".\n")
}
}
switch(prepare,
# remove missing and values below threshold
"remove" = {
minValue <- quantile(value, probs = threshold, na.rm = TRUE)
x <- x[value > minValue | !is.na(value), ]
value <- value[value > minValue | !is.na(value)]
},
# Adjust ratio
"adjust" = {
if (any(is.na(value))) {
warning("NA not allowed in weight vector. Features will be removed from Shape.")
x <- x[!is.na(value), ]
value <- value[!is.na(value)]
}
# area for polygons and total area
area <- as.numeric(st_area(x))
areaTotal <- sum(area)
area[area < 0] <- 0
# sum up total value
valueTotal <- sum(value, na.rm = TRUE)
# prepare force field calculations
desired <- areaTotal * value / valueTotal
ratio <- desired / area
maxRatio <- quantile(ratio, probs = (1 - threshold))
minRatio <- quantile(ratio, probs = threshold)
# adjust values
value[ratio > maxRatio] <- (maxRatio * area[ratio > maxRatio] * valueTotal) / areaTotal
value[ratio < minRatio] <- (minRatio * area[ratio < minRatio] * valueTotal) / areaTotal
},
"none" = {
})
# sum up total value
valueTotal <- sum(value, na.rm = TRUE)
# set meanSizeError
meanSizeError <- 100
x.iter <- x
# setup for single-threaded progress bar
if (show_progress && !multithreadded) {
step <- 0
bar_width <- 40
}
# setup for multi-threaded progress bar
if (show_progress && multithreadded && interactive()) {
cartogram_assert_package("progressr")
old_handlers <- progressr::handlers("progress")
on.exit(progressr::handlers(old_handlers), add = TRUE)
global_handlers_status <- progressr::handlers(global = NA)
progressr::handlers(global = TRUE)
on.exit(progressr::handlers(global = global_handlers_status), add = FALSE)
p <- progressr::progressor(steps = itermax * nrow(x))
} else {
p <- function(...) NULL
}
# iterate until itermax is reached
for (z in 1:itermax) {
# break if mean Sizer Error is less than maxSizeError
if (meanSizeError < maxSizeError) break
# geometry
x.iter_geom <- sf::st_geometry(x.iter)
# polygon centroids (centroids for multipart polygons)
centroids_sf <- sf::st_centroid(x.iter_geom)
st_crs(centroids_sf) <- sf::st_crs(NULL)
centroids <- do.call(rbind, centroids_sf)
# area for polygons and total area
area <- as.numeric(sf::st_area(x.iter))
areaTotal <- as.numeric(sum(area))
area[area < 0] <- 0
# prepare force field calculations
desired <- areaTotal * value / valueTotal
desired[desired == 0] <- 0.01 # set minimum size to prevent inf values size Error
radius <- sqrt(area / pi)
mass <- sqrt(desired / pi) - sqrt(area / pi)
sizeError <- apply(cbind(area, desired), 1, max) / apply(cbind(area, desired), 1, min)
meanSizeError <- mean(sizeError, na.rm = TRUE)
forceReductionFactor <- 1 / (1 + meanSizeError)
if (verbose) {
message(paste0("Mean size error for iteration ", z, ": ", round(meanSizeError, 5)))
}
# Process polygons either in parallel or sequentially
if (multithreadded) {
x.iter_geom <- future.apply::future_lapply(
seq_len(nrow(x.iter)),
function(i) {
if (interactive() && show_progress) {
p(sprintf("[Iter.:%d/%d] Polygon %d", z, itermax, i))
}
process_polygon(x.iter_geom[[i]], centroids, mass, radius, forceReductionFactor)
},
future.seed = TRUE
)
# in case we used the local in-fuction plan instead of externally future plan set by user, shutdown the workers
if (n_cpu != "respect_future_plan") {
future::plan(future::sequential)
}
} else {
x.iter_geom <- lapply(
seq_len(nrow(x.iter)),
function(i) {
if (interactive() && show_progress && !multithreadded) {
step <<- step + 1
# calculate progress
progress <- step / (itermax * nrow(x))
filled <- floor(progress * bar_width)
empty <- bar_width - filled
bar <- paste0("[Iter.:", z, "/", itermax, "] ",
paste0(rep("=", filled), collapse = ""),
paste0(rep(".", empty), collapse = ""),
sprintf(" %3d%%", floor(progress * 100)))
cat("\r", bar)
utils::flush.console()
}
process_polygon(x.iter_geom[[i]], centroids, mass, radius, forceReductionFactor)
}
)
}
sf::st_geometry(x.iter) <- do.call(sf::st_sfc, x.iter_geom)
}
# Restore CRS
st_crs(x.iter) <- st_crs(x)
return(sf::st_buffer(x.iter, 0))
}
#' @keywords internal
process_polygon <- function(poly_geom, centroids, mass, radius, forceReductionFactor) {
pts <- sf::st_coordinates(poly_geom)
idx <- unique(pts[, colnames(pts) %in% c("L1", "L2", "L3")])
for (k in seq_len(nrow(idx))) {
newpts <- pts[pts[, "L1"] == idx[k, "L1"] & pts[, "L2"] == idx[k, "L2"], c("X", "Y")]
distances <- apply(centroids, 1, function(pt) {
ptm <- matrix(pt, nrow = nrow(newpts), ncol = 2, byrow = TRUE)
sqrt(rowSums((newpts - ptm)^2))
})
for (j in seq_len(nrow(centroids))) {
distance <- distances[, j]
# calculate force vector
Fij <- mass[j] * radius[j] / distance
Fbij <- mass[j] * (distance / radius[j]) ^ 2 * (4 - 3 * (distance / radius[j]))
Fij[distance <= radius[j]] <- Fbij[distance <= radius[j]]
Fij <- Fij * forceReductionFactor / distance
# calculate new border coordinates
newpts <- newpts + cbind(X1 = Fij, X2 = Fij) * (newpts - centroids[rep(j, nrow(newpts)), ])
}
# save final coordinates from this iteration
if (sf::st_geometry_type(poly_geom) == "POLYGON") {
poly_geom[[idx[k, "L1"]]] <- newpts
} else {
poly_geom[[idx[k, "L2"]]][[idx[k, "L1"]]] <- newpts
}
}
return(poly_geom)
}
================================================
FILE: R/cartogram_dorling.R
================================================
#' @title Calculate Non-Overlapping Circles Cartogram
#' @description Construct a cartogram which represents each geographic region
#' as non-overlapping circles (Dorling 1996).
#' @name cartogram_dorling
#' @param x a polygon or multiplogyon sf object
#' @param weight Name of the weighting variable in x
#' @param k Share of the bounding box of x filled by the larger circle
#' @param m_weight Circles' movements weights. An optional vector of numeric weights
#' (0 to 1 inclusive) to
#' apply to the distance each circle moves during pair-repulsion. A weight of 0
#' prevents any movement. A weight of 1 gives the default movement distance. A
#' single value can be supplied for uniform weights. A vector with length less
#' than the number of circles will be silently extended by repeating the final
#' value. Any values outside the range \[0, 1\] will be clamped to 0 or 1.
#' @param itermax Maximum iterations for the cartogram transformation.
#' @return Non overlaping proportional circles of the same class as x.
#' @export
#' @references Dorling, D. (1996). Area Cartograms: Their Use and Creation. In Concepts and Techniques in Modern Geography (CATMOG), 59.
#' @examples
#'library(sf)
#'library(cartogram)
#'
# Load North Carolina SIDS data
#'nc = st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
#'
#'# transform to NAD83 / UTM zone 16N
#'nc_utm <- st_transform(nc, 26916)
#'
#'# Create cartogram
#'nc_utm_carto <- cartogram_dorling(nc_utm, weight = "BIR74")
#'
#'# Plot
#'par(mfrow = c(2,1))
#'plot(nc[,"BIR74"], main="original", key.pos = NULL, reset = FALSE)
#'plot(nc_utm_carto[, "BIR74"], main="distorted", key.pos = NULL, reset = FALSE)
#'
cartogram_dorling <- function(x, weight, k = 5, m_weight = 1, itermax = 1000) {
UseMethod("cartogram_dorling")
}
#' @rdname cartogram_dorling
#' @importFrom sf st_is_longlat st_as_sf st_geometry st_coordinates st_geometry st_centroid st_crs
#' @importFrom packcircles circleRepelLayout
#' @export
cartogram_dorling.sf <- function(x, weight, k = 5, m_weight = 1, itermax = 1000) {
# proj or unproj
if (sf::st_is_longlat(x)) {
stop('Using an unprojected map. This function does not give correct centroids and distances for longitude/latitude data:\nUse "st_transform()" to transform coordinates to another projection.', call. = FALSE)
}
# no 0 values
x <- x[x[[weight]] > 0, ]
# data prep
dat.init <- data.frame(sf::st_coordinates(sf::st_centroid(sf::st_geometry(x))),
v = x[[weight]])
surf <- (max(dat.init[, 1]) - min(dat.init[, 1])) * (max(dat.init[, 2]) - min(dat.init[, 2]))
dat.init$v <- dat.init$v * (surf * k / 100) / max(dat.init$v)
# circles layout and radiuses
res <- packcircles::circleRepelLayout(x = dat.init, xysizecols = 1:3,
wrap = FALSE, sizetype = "area",
maxiter = itermax, weights = m_weight)
# sf object creation
. <- sf::st_buffer(sf::st_as_sf(res$layout,
coords = c('x', 'y'),
crs = sf::st_crs(x)),
dist = res$layout$radius)
sf::st_geometry(x) <- sf::st_geometry(.)
return(x)
}
#' @rdname cartogram_dorling
#' @export
cartogram_dorling.SpatialPolygonsDataFrame <- function(x, weight, k = 5, m_weight = 1, itermax = 1000) {
as(cartogram_dorling.sf(sf::st_as_sf(x), weight = weight, k = k, m_weight = m_weight, itermax = itermax), "Spatial")
}
================================================
FILE: R/cartogram_ncont.R
================================================
# Copyright (C) 2016 Sebastian Jeworutzki
# Copyright (C) of 'nc_cartogram' Timothee Giraud and Nicolas Lambert
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#' @title Calculate Non-Contiguous Cartogram Boundaries
#' @description Construct a non-contiguous area cartogram (Olson 1976).
#'
#' @name cartogram_ncont
#' @param x a polygon or multiplogyon sf object
#' @param weight Name of the weighting variable in x
#' @param k Factor expansion for the unit with the greater value
#' @param inplace If TRUE, each polygon is modified in its original place,
#' if FALSE multi-polygons are centered on their initial centroid
#' @param n_cpu Number of cores to use. Defaults to "respect_future_plan". Available options are:
#' * "respect_future_plan" - By default, the function will run on a single core, unless the user specifies the number of cores using \code{\link[future]{plan}} (e.g. `future::plan(future::multisession, workers = 4)`) before running the `cartogram_ncont` function.
#' * "auto" - Use all except available cores (identified with \code{\link[parallelly]{availableCores}}) except 1, to keep the system responsive.
#' * a `numeric` value - Use the specified number of cores. In this case `cartogram_ncont` will use set the specified number of cores internally with `future::plan(future::multisession, workers = n_cpu)` and revert that back by switching the plan back to whichever plan might have been set before by the user. If only 1 core is set, the function will not require `future` and `future.apply` and will run on a single core.
#' @param show_progress A `logical` value. If TRUE, show progress bar. Defaults to TRUE.
#' @return An object of the same class as x with resized polygon boundaries
#' @export
#' @importFrom methods is slot as
#' @examples
#'# ========= Basic example =========
#'library(sf)
#'library(cartogram)
#'
# Load North Carolina SIDS data
#'nc = st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
#'
#'# transform to NAD83 / UTM zone 16N
#'nc_utm <- st_transform(nc, 26916)
#'
#'# Create cartogram
#'nc_utm_carto <- cartogram_ncont(nc_utm, weight = "BIR74")
#'
#'# Plot
#'par(mfrow=c(2,1))
#'plot(nc[,"BIR74"], main="original", key.pos = NULL, reset = FALSE)
#'plot(st_geometry(nc_utm), main="distorted", reset = FALSE)
#'plot(nc_utm_carto[,"BIR74"], add =TRUE)
#'
#'
#'# ========= Advanced example 1 =========
#'# Faster cartogram using multiple CPU cores
#'# using n_cpu parameter
#'library(sf)
#'library(cartogram)
#'
# Load North Carolina SIDS data
#'nc = st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
#'
#'# transform to NAD83 / UTM zone 16N
#'nc_utm <- st_transform(nc, 26916)
#'
#'# Create cartogram using 2 CPU cores on local machine
#'nc_utm_carto <- cartogram_ncont(nc_utm, weight = "BIR74", n_cpu = 2)
#'
#'# Plot
#'par(mfrow=c(2,1))
#'plot(nc[,"BIR74"], main="original", key.pos = NULL, reset = FALSE)
#'plot(st_geometry(nc_utm), main="distorted", reset = FALSE)
#'plot(nc_utm_carto[,"BIR74"], add =TRUE)
#'
#'
#'# ========= Advanced example 2 =========
#'# Faster cartogram using multiple CPU cores
#'# using future package plan
#'library(sf)
#'library(cartogram)
#'library(future)
#'
# Load North Carolina SIDS data
#'nc = st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
#'
#'# transform to NAD83 / UTM zone 16N
#'nc_utm <- st_transform(nc, 26916)
#
#'# Set the future plan with 2 CPU local cores
#'# You can of course use any other plans, not just multisession
#'future::plan(future::multisession, workers = 2)
#'
#'# Create cartogram with multiple CPU cores
#'# The cartogram_cont() will respect the plan set above
#'nc_utm_carto <- cartogram_ncont(nc_utm, weight = "BIR74")
#'
#'# Shutdown the R processes that were created by the future plan
#'future::plan(future::sequential)
#'
#'# Plot
#'par(mfrow=c(2,1))
#'plot(nc[,"BIR74"], main = "original", key.pos = NULL, reset = FALSE)
#'plot(st_geometry(nc_utm), main = "distorted", reset = FALSE)
#'plot(nc_utm_carto[,"BIR74"], add = TRUE)
#'
#'
#' @references Olson, J. M. (1976). Noncontiguous Area Cartograms. In The Professional Geographer, 28(4), 371-380.
cartogram_ncont <- function(
x,
weight,
k = 1,
inplace = TRUE,
n_cpu = getOption("cartogram_n_cpu", "respect_future_plan"),
show_progress = getOption("cartogram.show_progress", TRUE)
) {
UseMethod("cartogram_ncont")
}
#' @title Calculate Non-Contiguous Cartogram Boundaries
#' @description This function has been renamed: Please use cartogram_ncont() instead of nc_cartogram().
#'
#' @export
#' @param shp SpatialPolygonDataFrame or an sf object
#' @inheritDotParams cartogram_ncont -x
#' @keywords internal
nc_cartogram <- function(shp, ...) {
message("\nPlease use cartogram_ncont() instead of nc_cartogram().\n", call. = FALSE)
cartogram_ncont(x = shp, ...)
}
#' @rdname cartogram_ncont
#' @importFrom sf st_as_sf
#' @export
cartogram_ncont.SpatialPolygonsDataFrame <- function(
x,
weight,
k = 1,
inplace = TRUE,
n_cpu = getOption("cartogram_n_cpu", "respect_future_plan"),
show_progress = getOption("cartogram.show_progress", TRUE)
) {
as(cartogram_ncont.sf(sf::st_as_sf(x), weight, k = k, inplace = inplace, n_cpu = n_cpu, show_progress = show_progress), 'Spatial')
}
#' @rdname cartogram_ncont
#' @importFrom sf st_geometry st_area st_buffer st_is_longlat
#' @export
cartogram_ncont.sf <- function(
x,
weight,
k = 1,
inplace = TRUE,
n_cpu = getOption("cartogram_n_cpu", "respect_future_plan"),
show_progress = getOption("cartogram.show_progress", TRUE)
) {
if (isTRUE(sf::st_is_longlat(x))) {
stop('Using an unprojected map. This function does not give correct centroids and distances for longitude/latitude data:\nUse "st_transform()" to transform coordinates to another projection.', call. = FALSE)
}
if (length(n_cpu) > 1) {
stop('Invalid value for `n_cpu`. Use "respect_future_plan", "auto", or a numeric value.', call. = FALSE)
}
if (is.numeric(n_cpu) && n_cpu == 1) {
multithreadded <- FALSE
} else if (is.numeric(n_cpu) && n_cpu > 1) {
cartogram_assert_package(c("future", "future.apply"))
with(future::plan(future::multisession, workers = n_cpu), local = TRUE)
multithreadded <- TRUE
} else if (n_cpu == "auto") {
cartogram_assert_package("parallelly")
n_cpu <- max(parallelly::availableCores() - 1, 1)
if (n_cpu == 1) {
multithreadded <- FALSE
} else if (n_cpu > 1) {
cartogram_assert_package(c("future", "future.apply"))
with(future::plan(future::multisession, workers = n_cpu), local = TRUE)
multithreadded <- TRUE
}
} else if (n_cpu == "respect_future_plan") {
if (rlang::is_installed("future")) {
if (is(future::plan(), "sequential")) {
multithreadded <- FALSE
} else {
multithreadded <- TRUE
}
} else {
# if future is not installed, there is definetly no multithreading plan active, so just fallback to single core code
multithreadded <- FALSE
}
} else if (n_cpu != "respect_future_plan") {
stop('Invalid value for `n_cpu`. Use "respect_future_plan", "auto", or a numeric value.', call. = FALSE)
}
var <- weight
spdf <- x[!is.na(x[, var, drop = TRUE]), ]
# size
surf <- as.numeric(sf::st_area(spdf, by_element = TRUE))
v <- spdf[, var, drop = TRUE]
mv <- max(v)
ms <- surf[v == mv]
wArea <- k * v * (ms / mv)
spdf$r <- as.numeric(sqrt(wArea / surf))
spdf$r[spdf$r == 0] <- 0.001 # don't shrink polygons to zero area
crs <- st_crs(spdf) # save crs
if (multithreadded == TRUE) {
cartogram_assert_package("future.apply")
# handle show_progress
if (show_progress && interactive()) {
cartogram_assert_package("progressr")
old_handlers <- progressr::handlers("progress")
on.exit(progressr::handlers(old_handlers), add = TRUE)
global_handlers_status <- progressr::handlers(global = NA)
progressr::handlers(global = TRUE)
on.exit(progressr::handlers(global = global_handlers_status), add = FALSE)
p <- progressr::progressor(along = seq_len(nrow(spdf)))
} else {
p <- function(...) NULL # don't show progress
}
spdf_geometry_list <- future.apply::future_lapply(
X = seq_len(nrow(spdf)),
FUN = function(i) {
if (interactive() && show_progress) {
p(sprintf("Processing polygon %d", i))
}
rescalePoly.sf(
spdf[i, ],
r = spdf$r[i],
inplace = inplace
)
},
future.seed = TRUE
)
} else if (multithreadded == FALSE) {
if (interactive() && show_progress) {
pb <- utils::txtProgressBar(min = 0, max = nrow(spdf), style = 3)
}
spdf_geometry_list <- lapply(
X = seq_len(nrow(spdf)),
FUN = function(i) {
if (interactive() && show_progress) {
utils::setTxtProgressBar(pb, i)
}
rescalePoly.sf(
spdf[i, ],
r = spdf$r[i],
inplace = inplace
)
}
)
if (interactive() && show_progress) {
close(pb)
}
}
spdf$geometry <- do.call(c, spdf_geometry_list)
st_crs(spdf) <- crs # restore crs
spdf$r <- NULL
sf::st_buffer(spdf, 0)
}
#' @importFrom sf st_geometry st_centroid st_cast st_union
#' @keywords internal
rescalePoly.sf <- function(p, r = 1, inplace = TRUE) {
co <- sf::st_geometry(p)
if (inplace) {
cntr <- sf::st_centroid(co)
ps <- (co - cntr) * r + cntr
} else {
cop <- sf::st_cast(co, "POLYGON")
cntrd <- sf::st_centroid(cop)
ps <- sf::st_union((cop - cntrd) * r + cntrd)
}
return(ps)
}
================================================
FILE: R/utils.R
================================================
# reworked is_installed2 from https://github.com/dataheld/elf/blob/main/R/dependencies.R
#' Checks if a package is installed and *informs* the user if not
#'
#' This is wrapper around [rlang::check_installed];
#' instead of erroring out if the check fails it returns `FALSE`.
#' However, unlike [rlang::is_installed], it emits a message to the user.
#'
#' @inheritParams rlang::check_installed
#' @inheritDotParams rlang::check_installed
#' @keywords internal
cartogram_assert_package <- function(...) {
if (rlang::is_installed(...)) {
return(TRUE)
}
withRestarts(
tryCatch(
rlang::check_installed(...),
error = function(cnd) {
if (inherits(cnd, "rlib_error_package_not_found")) {
message("The required package is not installed.")
stop(cnd) # Re-throw the error
}
}
),
abort = function(cnd) {
message("The required package is not installed.")
stop(cnd) # Re-throw the error
}
)
rlang::is_installed(...)
}
================================================
FILE: README.Rmd
================================================
---
title: "cartogram: Create Cartograms with R"
output:
github_document:
fig_width: 4
fig_height: 3.5
---
<!-- badges: start -->
[](https://cran.r-project.org/package=cartogram)
[](https://github.com/sjewo/cartogram/actions/workflows/R-CMD-check.yaml)
[](https://cran.r-project.org/package=cartogram)
<!-- badges: end -->
```{r, echo=F}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-"
)
```
`cartogram` is an R package that implements methods for generating continuous area cartograms (based on the rubber sheet distortion algorithm by Dougenik et al., 1985), non-contiguous area cartograms (Olson, 1976), and non-overlapping circles cartograms (Dorling et al., 1996).
## Installation
You can install the **cartogram** package from CRAN as follows:
```{r, eval=FALSE}
install.packages("cartogram")
```
To upgrade to the latest development version of `cartogram`, install the package `remotes` and run the following command:
```{r, eval=FALSE}
remotes::install_github("sjewo/cartogram")
```
## Examples
### Continuous Area Cartogram
```{r cont, fig.asp = 1.2}
library(cartogram)
library(sf)
library(tmap)
data("World")
# Keep only the African continent
afr <- World[World$continent == "Africa", ]
# Project the map
afr <- st_transform(afr, 3395)
# Construct continuous area cartogram
afr_cont <- cartogram_cont(afr, "pop_est", itermax = 5)
# Plot the cartogram
tm_shape(afr_cont) +
tm_polygons("pop_est",
fill.scale = tm_scale_intervals(style = "jenks")) +
tm_layout(frame = FALSE,
legend.position = c("left", "bottom"))
```
### Non-contiguous Area Cartogram
```{r ncont, fig.asp = 1.2}
library(cartogram)
library(sf)
library(tmap)
data("World")
# Keep only the African continent
afr <- World[World$continent == "Africa", ]
# Project the map
afr <- st_transform(afr, 3395)
# Plot the original map boundaries
tm_shape(afr) +
tm_borders() +
# Add the the cartogram
tm_shape(cartogram_ncont(afr, "pop_est")) +
tm_polygons("pop_est",
fill.scale = tm_scale_intervals(style = "jenks")) +
tm_layout(frame = FALSE,
legend.position = c("left", "bottom"))
```
### Non-Overlapping Circles Cartogram
```{r dorling, fig.asp = 1.2}
library(cartogram)
library(sf)
library(tmap)
data("World")
# Keep only the African continent
afr <- World[World$continent == "Africa", ]
# Project the map
afr <- st_transform(afr, 3395)
# Plot the original map boundaries
tm_shape(afr) +
tm_borders() +
# Add the the cartogram
tm_shape(cartogram_dorling(afr, "pop_est")) +
tm_polygons("pop_est",
fill.scale = tm_scale_intervals(style = "jenks")) +
tm_layout(frame = FALSE,
legend.position = c("left", "bottom"))
```
## Use multiple CPU cores
```{r parallel, fig.asp = 1.2}
library(cartogram)
library(sf)
library(tmap)
library(future)
library(future.apply)
library(parallelly)
library(progressr)
data("World")
# Keep only the African continent
afr <- World[World$continent == "Africa", ]
# Project the map
afr <- st_transform(afr, 3395)
# Create cartogram using 2 CPU cores on the local machine
# This can speed up computation for larger datasets.
# Set show_progress to TRUE for a progress indicator.
afr_cont <- cartogram_cont(afr, weight = "pop_est",
itermax = 5,
n_cpu = 2,
show_progress = FALSE)
# Plot the cartogram
tm_shape(afr_cont) +
tm_polygons("pop_est",
fill.scale = tm_scale_intervals(style = "jenks")) +
tm_layout(frame = FALSE,
legend.position = c("left", "bottom"))
```
## Acknowledgements
The non-contiguous area cartogram and non-overlapping circles cartogram functionalities include major code contributions from [@rCarto](https://github.com/rCarto) and [@neocarto](https://github.com/neocarto).
[@nowosad](https://github.com/nowosad) contributed to the package by transitioning it to use the `sf` package and by enhancing the documentation, a task further supported by documentation improvements from [@oliveroy](https://github.com/oliveroy).
The functionality to utilize multiple CPU cores was contributed by [@e-kotov](https://github.com/e-kotov).
## References
This package implements algorithms based on the following seminal works:
* Dorling, D. (1996). Area Cartograms: Their Use and Creation. In Concepts and Techniques in Modern Geography (CATMOG), 59.
* Dougenik, J. A., Chrisman, N. R., & Niemeyer, D. R. (1985). An Algorithm To Construct Continuous Area Cartograms. In The Professional Geographer, 37(1), 75-81.
* Olson, J. M. (1976), Noncontiguous Area Cartograms. The Professional Geographer, 28: 371–380. [doi:10.1111/j.0033-0124.1976.00371.x](https://doi.org/10.1111/j.0033-0124.1976.00371.x)
================================================
FILE: README.md
================================================
cartogram: Create Cartograms with R
================
<!-- badges: start -->
[](https://cran.r-project.org/package=cartogram)
[](https://github.com/sjewo/cartogram/actions/workflows/R-CMD-check.yaml)
[](https://cran.r-project.org/package=cartogram)
<!-- badges: end -->
`cartogram` is an R package that implements methods for generating
continuous area cartograms (based on the rubber sheet distortion
algorithm by Dougenik et al., 1985), non-contiguous area cartograms
(Olson, 1976), and non-overlapping circles cartograms (Dorling et al.,
1996).
## Installation
You can install the **cartogram** package from CRAN as follows:
``` r
install.packages("cartogram")
```
To upgrade to the latest development version of `cartogram`, install the
package `remotes` and run the following command:
``` r
remotes::install_github("sjewo/cartogram")
```
## Examples
### Continuous Area Cartogram
``` r
library(cartogram)
library(sf)
#> Linking to GEOS 3.13.0, GDAL 3.8.5, PROJ 9.5.1; sf_use_s2() is TRUE
library(tmap)
data("World")
# Keep only the African continent
afr <- World[World$continent == "Africa", ]
# Project the map
afr <- st_transform(afr, 3395)
# Construct continuous area cartogram
afr_cont <- cartogram_cont(afr, "pop_est", itermax = 5)
# Plot the cartogram
tm_shape(afr_cont) +
tm_polygons("pop_est",
fill.scale = tm_scale_intervals(style = "jenks")) +
tm_layout(frame = FALSE,
legend.position = c("left", "bottom"))
```
<!-- -->
### Non-contiguous Area Cartogram
``` r
library(cartogram)
library(sf)
library(tmap)
data("World")
# Keep only the African continent
afr <- World[World$continent == "Africa", ]
# Project the map
afr <- st_transform(afr, 3395)
# Plot the original map boundaries
tm_shape(afr) +
tm_borders() +
# Add the the cartogram
tm_shape(cartogram_ncont(afr, "pop_est")) +
tm_polygons("pop_est",
fill.scale = tm_scale_intervals(style = "jenks")) +
tm_layout(frame = FALSE,
legend.position = c("left", "bottom"))
```
<!-- -->
### Non-Overlapping Circles Cartogram
``` r
library(cartogram)
library(sf)
library(tmap)
data("World")
# Keep only the African continent
afr <- World[World$continent == "Africa", ]
# Project the map
afr <- st_transform(afr, 3395)
# Plot the original map boundaries
tm_shape(afr) +
tm_borders() +
# Add the the cartogram
tm_shape(cartogram_dorling(afr, "pop_est")) +
tm_polygons("pop_est",
fill.scale = tm_scale_intervals(style = "jenks")) +
tm_layout(frame = FALSE,
legend.position = c("left", "bottom"))
```
<!-- -->
## Use multiple CPU cores
``` r
library(cartogram)
library(sf)
library(tmap)
library(future)
library(future.apply)
library(parallelly)
library(progressr)
data("World")
# Keep only the African continent
afr <- World[World$continent == "Africa", ]
# Project the map
afr <- st_transform(afr, 3395)
# Create cartogram using 2 CPU cores on the local machine
# This can speed up computation for larger datasets.
# Set show_progress to TRUE for a progress indicator.
afr_cont <- cartogram_cont(afr, weight = "pop_est",
itermax = 5,
n_cpu = 2,
show_progress = FALSE)
# Plot the cartogram
tm_shape(afr_cont) +
tm_polygons("pop_est",
fill.scale = tm_scale_intervals(style = "jenks")) +
tm_layout(frame = FALSE,
legend.position = c("left", "bottom"))
```
<!-- -->
## Acknowledgements
The non-contiguous area cartogram and non-overlapping circles cartogram
functionalities include major code contributions from
[@rCarto](https://github.com/rCarto) and
[@neocarto](https://github.com/neocarto).
[@nowosad](https://github.com/nowosad) contributed to the package by
transitioning it to use the `sf` package and by enhancing the
documentation, a task further supported by documentation improvements
from [@oliveroy](https://github.com/oliveroy).
The functionality to utilize multiple CPU cores was contributed by
[@e-kotov](https://github.com/e-kotov).
## References
This package implements algorithms based on the following seminal works:
- Dorling, D. (1996). Area Cartograms: Their Use and Creation. In
Concepts and Techniques in Modern Geography (CATMOG), 59.
- Dougenik, J. A., Chrisman, N. R., & Niemeyer, D. R. (1985). An
Algorithm To Construct Continuous Area Cartograms. In The Professional
Geographer, 37(1), 75-81.
- Olson, J. M. (1976), Noncontiguous Area Cartograms. The Professional
Geographer, 28: 371–380.
[doi:10.1111/j.0033-0124.1976.00371.x](https://doi.org/10.1111/j.0033-0124.1976.00371.x)
================================================
FILE: _pkgdown.yml
================================================
url: ~
template:
bootstrap: 5
================================================
FILE: cartogram.Rproj
================================================
Version: 1.0
ProjectId: 8c1bcf45-2691-44bd-9d45-e57d19d3e1ce
RestoreWorkspace: Default
SaveWorkspace: Default
AlwaysSaveHistory: Default
EnableCodeIndexing: Yes
UseSpacesForTab: Yes
NumSpacesForTab: 2
Encoding: UTF-8
RnwWeave: knitr
LaTeX: pdfLaTeX
BuildType: Package
PackageUseDevtools: Yes
PackageInstallArgs: --no-multiarch --with-keep.source
PackageCheckArgs: --as-cran
PackageRoxygenize: rd,collate,namespace,vignette
================================================
FILE: man/cartogram.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/cartogram_cont.R
\name{cartogram}
\alias{cartogram}
\title{Calculate Contiguous Cartogram Boundaries}
\usage{
cartogram(shp, ...)
}
\arguments{
\item{shp}{SpatialPolygonDataFrame or an sf object}
\item{...}{
Arguments passed on to \code{\link[=cartogram_cont]{cartogram_cont}}
\describe{
\item{\code{weight}}{Name of the weighting variable in x}
\item{\code{itermax}}{Maximum iterations for the cartogram transformation, if maxSizeError ist not reached}
\item{\code{maxSizeError}}{Stop if meanSizeError is smaller than maxSizeError}
\item{\code{prepare}}{Weighting values are adjusted to reach convergence much earlier. Possible methods are:
\itemize{
\item "adjust", adjust values to restrict the mass vector to the quantiles defined by threshold and 1-threshold (default),
\item "remove", remove features with values lower than quantile at threshold,
\item "none", don't adjust weighting values
}}
\item{\code{threshold}}{"auto" or a threshold value between 0 and 1. With “auto”, the value is 0.05 or, if the proportion of zeros in the weight is greater than 0.05, the value is adjusted accordingly.}
\item{\code{verbose}}{print meanSizeError on each iteration}
\item{\code{n_cpu}}{Number of cores to use. Defaults to "respect_future_plan". Available options are:
\itemize{
\item "respect_future_plan" - By default, the function will run on a single core, unless the user specifies the number of cores using \code{\link[future]{plan}} (e.g. \code{future::plan(future::multisession, workers = 4)}) before running the \code{cartogram_cont} function.
\item "auto" - Use all except available cores (identified with \code{\link[parallelly]{availableCores}}) except 1, to keep the system responsive.
\item a \code{numeric} value - Use the specified number of cores. In this case \code{cartogram_cont} will use set the specified number of cores internally with \code{future::plan(future::multisession, workers = n_cpu)} and revert that back by switching the plan back to whichever plan might have been set before by the user. If only 1 core is set, the function will not require \code{future} and \code{future.apply} and will run on a single core.
}}
\item{\code{show_progress}}{A \code{logical} value. If TRUE, show progress bar. Defaults to TRUE.}
}}
}
\description{
This function has been renamed: Please use cartogram_cont() instead of cartogram().
}
\keyword{internal}
================================================
FILE: man/cartogram_assert_package.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/utils.R
\name{cartogram_assert_package}
\alias{cartogram_assert_package}
\title{Checks if a package is installed and \emph{informs} the user if not}
\usage{
cartogram_assert_package(...)
}
\arguments{
\item{...}{
Arguments passed on to \code{\link[rlang:is_installed]{rlang::check_installed}}
\describe{
\item{\code{pkg}}{The package names. Can include version requirements,
e.g. \code{"pkg (>= 1.0.0)"}.}
\item{\code{version}}{Minimum versions for \code{pkg}. If supplied, must be the
same length as \code{pkg}. \code{NA} elements stand for any versions.}
\item{\code{compare}}{A character vector of comparison operators to use
for \code{version}. If supplied, must be the same length as
\code{version}. If \code{NULL}, \code{>=} is used as default for all
elements. \code{NA} elements in \code{compare} are also set to \code{>=} by
default.}
\item{\code{reason}}{Optional string indicating why is \code{pkg} needed.
Appears in error messages (if non-interactive) and user prompts
(if interactive).}
\item{\code{action}}{An optional function taking \code{pkg} and \code{...}
arguments. It is called by \code{check_installed()} when the user
chooses to update outdated packages. The function is passed the
missing and outdated packages as a character vector of names.}
\item{\code{call}}{The execution environment of a currently
running function, e.g. \code{caller_env()}. The function will be
mentioned in error messages as the source of the error. See the
\code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.}
}}
}
\description{
This is wrapper around \link[rlang:is_installed]{rlang::check_installed};
instead of erroring out if the check fails it returns \code{FALSE}.
However, unlike \link[rlang:is_installed]{rlang::is_installed}, it emits a message to the user.
}
\keyword{internal}
================================================
FILE: man/cartogram_cont.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/cartogram_cont.R
\name{cartogram_cont}
\alias{cartogram_cont}
\alias{cartogram_cont.SpatialPolygonsDataFrame}
\alias{cartogram_cont.sf}
\title{Calculate Contiguous Cartogram Boundaries}
\usage{
cartogram_cont(
x,
weight,
itermax = 15,
maxSizeError = 1.0001,
prepare = "adjust",
threshold = "auto",
verbose = FALSE,
n_cpu = getOption("cartogram_n_cpu", "respect_future_plan"),
show_progress = getOption("cartogram.show_progress", TRUE)
)
\method{cartogram_cont}{SpatialPolygonsDataFrame}(
x,
weight,
itermax = 15,
maxSizeError = 1.0001,
prepare = "adjust",
threshold = "auto",
verbose = FALSE,
n_cpu = getOption("cartogram_n_cpu", "respect_future_plan"),
show_progress = getOption("cartogram.show_progress", TRUE)
)
\method{cartogram_cont}{sf}(
x,
weight,
itermax = 15,
maxSizeError = 1.0001,
prepare = "adjust",
threshold = "auto",
verbose = FALSE,
n_cpu = getOption("cartogram_n_cpu", "respect_future_plan"),
show_progress = getOption("cartogram.show_progress", TRUE)
)
}
\arguments{
\item{x}{a polygon or multiplogyon sf object}
\item{weight}{Name of the weighting variable in x}
\item{itermax}{Maximum iterations for the cartogram transformation, if maxSizeError ist not reached}
\item{maxSizeError}{Stop if meanSizeError is smaller than maxSizeError}
\item{prepare}{Weighting values are adjusted to reach convergence much earlier. Possible methods are:
\itemize{
\item "adjust", adjust values to restrict the mass vector to the quantiles defined by threshold and 1-threshold (default),
\item "remove", remove features with values lower than quantile at threshold,
\item "none", don't adjust weighting values
}}
\item{threshold}{"auto" or a threshold value between 0 and 1. With “auto”, the value is 0.05 or, if the proportion of zeros in the weight is greater than 0.05, the value is adjusted accordingly.}
\item{verbose}{print meanSizeError on each iteration}
\item{n_cpu}{Number of cores to use. Defaults to "respect_future_plan". Available options are:
\itemize{
\item "respect_future_plan" - By default, the function will run on a single core, unless the user specifies the number of cores using \code{\link[future]{plan}} (e.g. \code{future::plan(future::multisession, workers = 4)}) before running the \code{cartogram_cont} function.
\item "auto" - Use all except available cores (identified with \code{\link[parallelly]{availableCores}}) except 1, to keep the system responsive.
\item a \code{numeric} value - Use the specified number of cores. In this case \code{cartogram_cont} will use set the specified number of cores internally with \code{future::plan(future::multisession, workers = n_cpu)} and revert that back by switching the plan back to whichever plan might have been set before by the user. If only 1 core is set, the function will not require \code{future} and \code{future.apply} and will run on a single core.
}}
\item{show_progress}{A \code{logical} value. If TRUE, show progress bar. Defaults to TRUE.}
}
\value{
An object of the same class as x
}
\description{
Construct a continuous area cartogram by a rubber sheet distortion algorithm (Dougenik et al. 1985)
}
\examples{
# ========= Basic example =========
library(sf)
library(cartogram)
nc = st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
# transform to NAD83 / UTM zone 16N
nc_utm <- st_transform(nc, 26916)
# Create cartogram
nc_utm_carto <- cartogram_cont(nc_utm, weight = "BIR74", itermax = 5)
# Plot
par(mfrow=c(2,1))
plot(nc[,"BIR74"], main="original", key.pos = NULL, reset = FALSE)
plot(nc_utm_carto[,"BIR74"], main="distorted", key.pos = NULL, reset = FALSE)
# ========= Advanced example 1 =========
# Faster cartogram using multiple CPU cores
# using n_cpu parameter
library(sf)
library(cartogram)
nc = st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
# transform to NAD83 / UTM zone 16N
nc_utm <- st_transform(nc, 26916)
# Create cartogram using 2 CPU cores on local machine
nc_utm_carto <- cartogram_cont(nc_utm, weight = "BIR74", itermax = 5,
n_cpu = 2)
# Plot
par(mfrow=c(2,1))
plot(nc[,"BIR74"], main="original", key.pos = NULL, reset = FALSE)
plot(nc_utm_carto[,"BIR74"], main="distorted", key.pos = NULL, reset = FALSE)
# ========= Advanced example 2 =========
# Faster cartogram using multiple CPU cores
# using future package plan
\donttest{
library(sf)
library(cartogram)
library(future)
nc = st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
# transform to NAD83 / UTM zone 16N
nc_utm <- st_transform(nc, 26916)
# Set the future plan with 2 CPU local cores
# You can of course use any other plans, not just multisession
future::plan(future::multisession, workers = 2)
# Create cartogram with multiple CPU cores
# The cartogram_cont() will respect the plan set above
nc_utm_carto <- cartogram_cont(nc_utm, weight = "BIR74", itermax = 5)
# Shutdown the R processes that were created by the future plan
future::plan(future::sequential)
# Plot
par(mfrow=c(2,1))
plot(nc[,"BIR74"], main="original", key.pos = NULL, reset = FALSE)
plot(nc_utm_carto[,"BIR74"], main="distorted", key.pos = NULL, reset = FALSE)
}
}
\references{
Dougenik, J. A., Chrisman, N. R., & Niemeyer, D. R. (1985). An Algorithm To Construct Continuous Area Cartograms. In The Professional Geographer, 37(1), 75-81.
}
================================================
FILE: man/cartogram_dorling.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/cartogram_dorling.R
\name{cartogram_dorling}
\alias{cartogram_dorling}
\alias{cartogram_dorling.sf}
\alias{cartogram_dorling.SpatialPolygonsDataFrame}
\title{Calculate Non-Overlapping Circles Cartogram}
\usage{
cartogram_dorling(x, weight, k = 5, m_weight = 1, itermax = 1000)
\method{cartogram_dorling}{sf}(x, weight, k = 5, m_weight = 1, itermax = 1000)
\method{cartogram_dorling}{SpatialPolygonsDataFrame}(x, weight, k = 5, m_weight = 1, itermax = 1000)
}
\arguments{
\item{x}{a polygon or multiplogyon sf object}
\item{weight}{Name of the weighting variable in x}
\item{k}{Share of the bounding box of x filled by the larger circle}
\item{m_weight}{Circles' movements weights. An optional vector of numeric weights
(0 to 1 inclusive) to
apply to the distance each circle moves during pair-repulsion. A weight of 0
prevents any movement. A weight of 1 gives the default movement distance. A
single value can be supplied for uniform weights. A vector with length less
than the number of circles will be silently extended by repeating the final
value. Any values outside the range [0, 1] will be clamped to 0 or 1.}
\item{itermax}{Maximum iterations for the cartogram transformation.}
}
\value{
Non overlaping proportional circles of the same class as x.
}
\description{
Construct a cartogram which represents each geographic region
as non-overlapping circles (Dorling 1996).
}
\examples{
library(sf)
library(cartogram)
nc = st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
# transform to NAD83 / UTM zone 16N
nc_utm <- st_transform(nc, 26916)
# Create cartogram
nc_utm_carto <- cartogram_dorling(nc_utm, weight = "BIR74")
# Plot
par(mfrow = c(2,1))
plot(nc[,"BIR74"], main="original", key.pos = NULL, reset = FALSE)
plot(nc_utm_carto[, "BIR74"], main="distorted", key.pos = NULL, reset = FALSE)
}
\references{
Dorling, D. (1996). Area Cartograms: Their Use and Creation. In Concepts and Techniques in Modern Geography (CATMOG), 59.
}
================================================
FILE: man/cartogram_ncont.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/cartogram_ncont.R
\name{cartogram_ncont}
\alias{cartogram_ncont}
\alias{cartogram_ncont.SpatialPolygonsDataFrame}
\alias{cartogram_ncont.sf}
\title{Calculate Non-Contiguous Cartogram Boundaries}
\usage{
cartogram_ncont(
x,
weight,
k = 1,
inplace = TRUE,
n_cpu = getOption("cartogram_n_cpu", "respect_future_plan"),
show_progress = getOption("cartogram.show_progress", TRUE)
)
\method{cartogram_ncont}{SpatialPolygonsDataFrame}(
x,
weight,
k = 1,
inplace = TRUE,
n_cpu = getOption("cartogram_n_cpu", "respect_future_plan"),
show_progress = getOption("cartogram.show_progress", TRUE)
)
\method{cartogram_ncont}{sf}(
x,
weight,
k = 1,
inplace = TRUE,
n_cpu = getOption("cartogram_n_cpu", "respect_future_plan"),
show_progress = getOption("cartogram.show_progress", TRUE)
)
}
\arguments{
\item{x}{a polygon or multiplogyon sf object}
\item{weight}{Name of the weighting variable in x}
\item{k}{Factor expansion for the unit with the greater value}
\item{inplace}{If TRUE, each polygon is modified in its original place,
if FALSE multi-polygons are centered on their initial centroid}
\item{n_cpu}{Number of cores to use. Defaults to "respect_future_plan". Available options are:
\itemize{
\item "respect_future_plan" - By default, the function will run on a single core, unless the user specifies the number of cores using \code{\link[future]{plan}} (e.g. \code{future::plan(future::multisession, workers = 4)}) before running the \code{cartogram_ncont} function.
\item "auto" - Use all except available cores (identified with \code{\link[parallelly]{availableCores}}) except 1, to keep the system responsive.
\item a \code{numeric} value - Use the specified number of cores. In this case \code{cartogram_ncont} will use set the specified number of cores internally with \code{future::plan(future::multisession, workers = n_cpu)} and revert that back by switching the plan back to whichever plan might have been set before by the user. If only 1 core is set, the function will not require \code{future} and \code{future.apply} and will run on a single core.
}}
\item{show_progress}{A \code{logical} value. If TRUE, show progress bar. Defaults to TRUE.}
}
\value{
An object of the same class as x with resized polygon boundaries
}
\description{
Construct a non-contiguous area cartogram (Olson 1976).
}
\examples{
# ========= Basic example =========
library(sf)
library(cartogram)
nc = st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
# transform to NAD83 / UTM zone 16N
nc_utm <- st_transform(nc, 26916)
# Create cartogram
nc_utm_carto <- cartogram_ncont(nc_utm, weight = "BIR74")
# Plot
par(mfrow=c(2,1))
plot(nc[,"BIR74"], main="original", key.pos = NULL, reset = FALSE)
plot(st_geometry(nc_utm), main="distorted", reset = FALSE)
plot(nc_utm_carto[,"BIR74"], add =TRUE)
# ========= Advanced example 1 =========
# Faster cartogram using multiple CPU cores
# using n_cpu parameter
library(sf)
library(cartogram)
nc = st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
# transform to NAD83 / UTM zone 16N
nc_utm <- st_transform(nc, 26916)
# Create cartogram using 2 CPU cores on local machine
nc_utm_carto <- cartogram_ncont(nc_utm, weight = "BIR74", n_cpu = 2)
# Plot
par(mfrow=c(2,1))
plot(nc[,"BIR74"], main="original", key.pos = NULL, reset = FALSE)
plot(st_geometry(nc_utm), main="distorted", reset = FALSE)
plot(nc_utm_carto[,"BIR74"], add =TRUE)
# ========= Advanced example 2 =========
# Faster cartogram using multiple CPU cores
# using future package plan
library(sf)
library(cartogram)
library(future)
nc = st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE)
# transform to NAD83 / UTM zone 16N
nc_utm <- st_transform(nc, 26916)
# Set the future plan with 2 CPU local cores
# You can of course use any other plans, not just multisession
future::plan(future::multisession, workers = 2)
# Create cartogram with multiple CPU cores
# The cartogram_cont() will respect the plan set above
nc_utm_carto <- cartogram_ncont(nc_utm, weight = "BIR74")
# Shutdown the R processes that were created by the future plan
future::plan(future::sequential)
# Plot
par(mfrow=c(2,1))
plot(nc[,"BIR74"], main = "original", key.pos = NULL, reset = FALSE)
plot(st_geometry(nc_utm), main = "distorted", reset = FALSE)
plot(nc_utm_carto[,"BIR74"], add = TRUE)
}
\references{
Olson, J. M. (1976). Noncontiguous Area Cartograms. In The Professional Geographer, 28(4), 371-380.
}
================================================
FILE: man/nc_cartogram.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/cartogram_ncont.R
\name{nc_cartogram}
\alias{nc_cartogram}
\title{Calculate Non-Contiguous Cartogram Boundaries}
\usage{
nc_cartogram(shp, ...)
}
\arguments{
\item{shp}{SpatialPolygonDataFrame or an sf object}
\item{...}{
Arguments passed on to \code{\link[=cartogram_ncont]{cartogram_ncont}}
\describe{
\item{\code{weight}}{Name of the weighting variable in x}
\item{\code{k}}{Factor expansion for the unit with the greater value}
\item{\code{inplace}}{If TRUE, each polygon is modified in its original place,
if FALSE multi-polygons are centered on their initial centroid}
\item{\code{n_cpu}}{Number of cores to use. Defaults to "respect_future_plan". Available options are:
\itemize{
\item "respect_future_plan" - By default, the function will run on a single core, unless the user specifies the number of cores using \code{\link[future]{plan}} (e.g. \code{future::plan(future::multisession, workers = 4)}) before running the \code{cartogram_ncont} function.
\item "auto" - Use all except available cores (identified with \code{\link[parallelly]{availableCores}}) except 1, to keep the system responsive.
\item a \code{numeric} value - Use the specified number of cores. In this case \code{cartogram_ncont} will use set the specified number of cores internally with \code{future::plan(future::multisession, workers = n_cpu)} and revert that back by switching the plan back to whichever plan might have been set before by the user. If only 1 core is set, the function will not require \code{future} and \code{future.apply} and will run on a single core.
}}
\item{\code{show_progress}}{A \code{logical} value. If TRUE, show progress bar. Defaults to TRUE.}
}}
}
\description{
This function has been renamed: Please use cartogram_ncont() instead of nc_cartogram().
}
\keyword{internal}
================================================
FILE: tests/testthat/test-cartogram_cont.R
================================================
test_that("cartogram_cont matches expected area", {
# Load North Carolina SIDS data
nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
# transform to NAD83 / UTM zone 16N
nc_utm <- sf::st_transform(nc, 26916)
# Create cartogram
nc_utm_carto <- cartogram_cont(nc_utm, weight = "BIR74", itermax = 5)
cartogram_area <- as.integer((sum(nc_utm_carto |> st_area())) / 1000)
expect_equal(cartogram_area, 118877899, tolerance = 500)
})
test_that("cartogram_cont has crs", {
# Load North Carolina SIDS data
nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
# transform to NAD83 / UTM zone 16N
nc_utm <- sf::st_transform(nc, 26916)
# Create cartogram
nc_utm_carto <- cartogram_cont(nc_utm, weight = "BIR74", itermax = 5)
expect_false(is.na(sf::st_crs(nc_utm_carto)$wkt))
})
================================================
FILE: tests/testthat/test-cartogram_ncont.R
================================================
test_that("nc cartogram matches expected area", {
# Load North Carolina SIDS data
nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
# transform to NAD83 / UTM zone 16N
nc_utm <- sf::st_transform(nc, 26916)
# Create cartogram
nc_utm_carto <- cartogram_ncont(nc_utm, weight = "BIR74")
cartogram_area <- as.integer((sum(nc_utm_carto |> st_area())) / 1000)
expect_equal(cartogram_area, 22284872, tolerance = 500)
})
test_that("nc cartogram has crs", {
# Load North Carolina SIDS data
nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
# transform to NAD83 / UTM zone 16N
nc_utm <- sf::st_transform(nc, 26916)
# Create cartogram
nc_utm_carto <- cartogram_ncont(nc_utm, weight = "BIR74")
expect_false(is.na(sf::st_crs(nc_utm_carto)$wkt))
})
================================================
FILE: tests/testthat/test-markdown.R
================================================
test_that("R Markdown documents can be rendered", {
skip_on_cran()
skip_if_not_installed(c("rmarkdown", "tmap"))
rmarkdown::render("test.Rmd", quiet = TRUE)
expect_true(file.exists("test.html"))
unlink("test.html")
})
================================================
FILE: tests/testthat/test.Rmd
================================================
---
title: "test"
output: html_document
---
```{r parallel, fig.asp = 1.2}
library(cartogram)
library(sf)
library(tmap)
data("World")
# keep only the african continent
afr <- World[World$continent == "Africa", ]
# project the map
afr <- st_transform(afr, 3395)
# Create cartogram using 2 CPU cores on local machine
afr_cont <- cartogram_cont(afr, weight = "pop_est", itermax = 5)
# plot it
tm_shape(afr_cont) +
tm_polygons("pop_est",
fill.scale = tm_scale_intervals(style = "jenks")) +
tm_layout(frame = FALSE,
legend.position = c("left", "bottom"))
```
================================================
FILE: tests/testthat.R
================================================
# This file is part of the standard setup for testthat.
# It is recommended that you do not modify it.
#
# Where should you do additional test configuration?
# Learn more about the roles of various files in:
# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview
# * https://testthat.r-lib.org/articles/special-files.html
library(testthat)
library(cartogram)
test_check("cartogram")
gitextract_6no1pgat/
├── .Rbuildignore
├── .github/
│ ├── .gitignore
│ └── workflows/
│ ├── R-CMD-check.yaml
│ ├── pkgdown.yaml
│ └── recheck.yaml
├── .gitignore
├── .lintr
├── DESCRIPTION
├── NAMESPACE
├── NEWS.md
├── R/
│ ├── cartogram_cont.R
│ ├── cartogram_dorling.R
│ ├── cartogram_ncont.R
│ └── utils.R
├── README.Rmd
├── README.md
├── _pkgdown.yml
├── cartogram.Rproj
├── man/
│ ├── cartogram.Rd
│ ├── cartogram_assert_package.Rd
│ ├── cartogram_cont.Rd
│ ├── cartogram_dorling.Rd
│ ├── cartogram_ncont.Rd
│ └── nc_cartogram.Rd
└── tests/
├── testthat/
│ ├── test-cartogram_cont.R
│ ├── test-cartogram_ncont.R
│ ├── test-markdown.R
│ └── test.Rmd
└── testthat.R
Condensed preview — 29 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (74K chars).
[
{
"path": ".Rbuildignore",
"chars": 187,
"preview": "^.*\\.Rproj$\n^\\.Rproj\\.user$\n^\\.travis\\.yml$\n^README\\.Rmd$\n^README-.*\\.png$\n^_pkgdown\\.yml$\n^docs$\n^pkgdown$\n^\\.github$\n^"
},
{
"path": ".github/.gitignore",
"chars": 7,
"preview": "*.html\n"
},
{
"path": ".github/workflows/R-CMD-check.yaml",
"chars": 1326,
"preview": "# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples\n# Need help debugging build failures? Start at"
},
{
"path": ".github/workflows/pkgdown.yaml",
"chars": 1301,
"preview": "# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples\n# Need help debugging build failures? Start at"
},
{
"path": ".github/workflows/recheck.yaml",
"chars": 378,
"preview": "on:\n workflow_dispatch:\n inputs:\n which:\n type: choice\n description: Which dependents to check\n "
},
{
"path": ".gitignore",
"chars": 637,
"preview": "# History files\n.Rhistory\n.Rapp.history\n\n# Session Data files\n.RData\n\n# Example code in package build process\n*-Ex.R\n\n# "
},
{
"path": ".lintr",
"chars": 199,
"preview": "linters: linters_with_defaults(\n return_linter = NULL,\n line_length_linter = NULL,\n commented_code_linter = NULL,\n o"
},
{
"path": "DESCRIPTION",
"chars": 1216,
"preview": "Package: cartogram\nTitle: Create Cartograms with R\nVersion: 0.4.0\nAuthors@R: c(\n person(\"Sebastian\", \"Jeworutzki\", , "
},
{
"path": "NAMESPACE",
"chars": 934,
"preview": "# Generated by roxygen2: do not edit by hand\n\nS3method(cartogram_cont,SpatialPolygonsDataFrame)\nS3method(cartogram_cont,"
},
{
"path": "NEWS.md",
"chars": 1234,
"preview": "# cartogram 0.4.0\n\n* The new `n_cpu` option in `cartogram_cont()` and `cartogram_ncont()` enables distortion calculation"
},
{
"path": "R/cartogram_cont.R",
"chars": 15993,
"preview": "# Copyright (C) 2016 Sebastian Jeworutzki\n# Copyright (C) of 'checkPolygonsGEOS' from package maptools Roger Bivand and "
},
{
"path": "R/cartogram_dorling.R",
"chars": 3473,
"preview": "#' @title Calculate Non-Overlapping Circles Cartogram\n#' @description Construct a cartogram which represents each geogra"
},
{
"path": "R/cartogram_ncont.R",
"chars": 10162,
"preview": "# Copyright (C) 2016 Sebastian Jeworutzki\n# Copyright (C) of 'nc_cartogram' Timothee Giraud and Nicolas Lambert\n#\n# This"
},
{
"path": "R/utils.R",
"chars": 1005,
"preview": "# reworked is_installed2 from https://github.com/dataheld/elf/blob/main/R/dependencies.R\n#' Checks if a package is insta"
},
{
"path": "README.Rmd",
"chars": 5029,
"preview": "---\ntitle: \"cartogram: Create Cartograms with R\"\noutput:\n github_document:\n fig_width: 4\n fig_height: 3.5\n---\n\n<!"
},
{
"path": "README.md",
"chars": 4996,
"preview": "cartogram: Create Cartograms with R\n================\n\n<!-- badges: start -->\n\n[\n skip_if_not_installed(c(\"rmarkdown\", \"tmap\"))\n r"
},
{
"path": "tests/testthat/test.Rmd",
"chars": 589,
"preview": "---\ntitle: \"test\"\noutput: html_document\n---\n\n\n```{r parallel, fig.asp = 1.2}\nlibrary(cartogram)\nlibrary(sf)\nlibrary(tmap"
},
{
"path": "tests/testthat.R",
"chars": 399,
"preview": "# This file is part of the standard setup for testthat.\n# It is recommended that you do not modify it.\n#\n# Where should "
}
]
About this extraction
This page contains the full source code of the sjewo/cartogram GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 29 files (68.1 KB), approximately 20.1k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.