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