From 750bc12e45a26587f8d993ab5004443771790a18 Mon Sep 17 00:00:00 2001 From: Christian Panse Date: Sat, 23 Sep 2023 16:54:54 +0200 Subject: [PATCH] Add roxygen2::roxygenize generated files --- .gitignore | 12 -- NAMESPACE | 44 +++++++ R/RcppExports.R | 147 ++++++++++++++++++++++ R/recmap.R | 4 +- README.md | 3 +- man/as.SpatialPolygonsDataFrame.recmap.Rd | 26 ++++ man/as.recmap.SpatialPolygonsDataFrame.Rd | 29 +++++ man/dot-get_7triangles.Rd | 36 ++++++ man/is.recmap.Rd | 14 +++ man/plot.recmap.Rd | 35 ++++++ man/recmap.Rd | 141 +++++++++++++++++++++ man/recmapGA.Rd | 123 ++++++++++++++++++ man/summary.recmap.Rd | 29 +++++ src/RcppExports.cpp | 67 ++++++++++ 14 files changed, 694 insertions(+), 16 deletions(-) create mode 100644 NAMESPACE create mode 100644 R/RcppExports.R create mode 100644 man/as.SpatialPolygonsDataFrame.recmap.Rd create mode 100644 man/as.recmap.SpatialPolygonsDataFrame.Rd create mode 100644 man/dot-get_7triangles.Rd create mode 100644 man/is.recmap.Rd create mode 100644 man/plot.recmap.Rd create mode 100644 man/recmap.Rd create mode 100644 man/recmapGA.Rd create mode 100644 man/summary.recmap.Rd create mode 100644 src/RcppExports.cpp diff --git a/.gitignore b/.gitignore index 6a4ce5b..56843bc 100644 --- a/.gitignore +++ b/.gitignore @@ -5,15 +5,3 @@ src/*.o src/*.so src/*.dll -NAMESPACE -man/as.SpatialPolygonsDataFrame.recmap.Rd -man/as.recmap.SpatialPolygonsDataFrame.Rd -man/dot-get_7triangles.Rd -man/is.recmap.Rd -man/plot.recmap.Rd -man/recmap.Rd -man/recmapGA.Rd -man/summary.recmap.Rd -recmap.Rproj -R/RcppExports.R -src/RcppExports.cpp diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..529f3ce --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,44 @@ +# Generated by roxygen2: do not edit by hand + +S3method(all.equal,recmap) +S3method(as.SpatialPolygonsDataFrame,recmap) +S3method(as.recmap,SpatialPolygonsDataFrame) +S3method(plot,recmap) +S3method(plot,recmapGA) +S3method(plot,recmapGRASP) +S3method(summary,recmap) +export(.get_7triangles) +export(all.equal.recmap) +export(as.SpatialPolygonsDataFrame) +export(as.recmap) +export(checkerboard) +export(is.recmap) +export(plot.recmap) +export(plot.recmapGA) +export(plot.recmapGRASP) +export(recmap) +export(recmapGA) +export(recmapGRASP) +export(summary.recmap) +export(summary.recmapGA) +import(Rcpp) +importFrom(GA,ga) +importFrom(GA,gaMonitor) +importFrom(GA,summary.ga) +importFrom(graphics,abline) +importFrom(graphics,axis) +importFrom(graphics,plot) +importFrom(graphics,polygon) +importFrom(graphics,rect) +importFrom(graphics,strwidth) +importFrom(graphics,text) +importFrom(sp,Polygon) +importFrom(sp,Polygons) +importFrom(sp,SpatialPolygons) +importFrom(sp,SpatialPolygonsDataFrame) +importFrom(sp,bbox) +importFrom(sp,spplot) +importFrom(utils,combn) +importFrom(utils,packageVersion) +importFrom(utils,read.table) +useDynLib(recmap, .registration=TRUE) diff --git a/R/RcppExports.R b/R/RcppExports.R new file mode 100644 index 0000000..371b6c5 --- /dev/null +++ b/R/RcppExports.R @@ -0,0 +1,147 @@ +# Generated by using Rcpp::compileAttributes() -> do not edit by hand +# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 + +#' @import Rcpp +get_angle <- function(x0, y0, x1, y1) { + .Call('_recmap_get_angle', PACKAGE = 'recmap', x0, y0, x1, y1) +} + +place_rectangle <- function(x0, y0, dx0, dy0, dx1, dy1, alpha) { + .Call('_recmap_place_rectangle', PACKAGE = 'recmap', x0, y0, dx0, dy0, dx1, dy1, alpha) +} + +#' Compute a Rectangular Statistical Cartogram +#' +#' @description +#' The input consists of a map represented by overlapping rectangles. +#' The algorithm requires as input for each map region: +#' \itemize{ +#' \item{a tuple of (x, y) values corresponding to the +#' (longitude, latitude) position,} +#' \item{a tuple of (dx, dy) of expansion along (longitude, latitude),} +#' \item{and a statistical value z.} +#' } +#' The (x, y) coordinates represent the center of the minimal bounding boxes +#' (MBB), The coordinates of the MBB are derived by adding or subtracting the +#' (dx, dy) / 2 tuple accordingly. The tuple (dx, dy) also defines the ratio of the +#' map region. The statistical values define the desired area of each map region. +#' +#' The output is a rectangular cartogram where the map regions are: +#' +#' \itemize{ +#' \item{Non-overlapping,} +#' \item{connected,} +#' \item{ratio and area of each rectangle correspond to the desired areas,} +#' \item{rectangles are placed parallel to the axes.} +#' } +#' +#' The construction heuristic places each rectangle in a way that important spatial +#' constraints, in particular +#' \itemize{ +#' \item{the topology of the pseudo dual graph,} +#' \item{the relative position of MBB centers.} +#' } +#' are tried to be preserved. +#' +#' The ratios are preserved and the area of each region corresponds to the as +#' input given statistical value z. +#' +#' @param V defines the input map regions formatted as \code{\link{data.frame}} +#' having the column names \code{c('x', 'y', 'dx', 'dy', 'z', 'name')} +#' as described above. V could also be considered as the nodes of the pseudo dual. +#' +#' @param E defines the edges of the map region's pseudo dual graph. +#' If \code{E} is not provided, this is the default; the pseudo dual graph is +#' composed of overlapping rectangles. If used, E must be a +#' \code{\link{data.frame}} containing two columns named \code{c('u', 'v')} +#' of type integer referencing the row number of \code{V}. +#' +#' @details The basic idea of the current recmap \emph{implementation}: +#' \enumerate{ +#' \item{Compute the pseudo dual out of the overlapping map regions.} +#' \item{Determine the \emph{core region} by \code{index <- int(n / 2)}.} +#' \item{Place region by region along DFS skeleton of pseudo dual starting +#' with the \emph{core region}.}} +#' +#' Note: if a rectangle can not be placed, accept a non-\emph{feasible solution} +#' (avoid solutions having a topology error higher than 100) +#' Solving this constellation can be intensive in the computation, and due to the +#' assumably low fitness value the candidate cartogram +#' will be likely rejected by the metaheuristic. +#' +#' \emph{Time Complexity:} +#' The time complexity is \eqn{O(n^2)}, where n is the number of regions. +#' DFS is visiting each map region only once and therefore has +#' time complexity \eqn{O(n)}. For each placement, a constant number of +#' MBB intersection are called (max 360). MBB check is implemented using +#' \code{std::set}, \code{insert}, \code{upper_bound}, \code{upper_bound} +#' costs are \eqn{O(\log(n))}{O(log(n))}. +#' However, the worst case for a range query is \eqn{O(n)}, if and only if dx or dy +#' cover the whole x or y range. Q.E.D. +#' +#' \emph{Performance:} +#' In praxis, computing on a 2.4 GHz Intel Core i7 machine (using only one core), using the +#' 50 state U.S. map example, recmap can compute approximately 100 cartograms in one second. +#' The number of MBB calls were +#' (Min., Median, Mean, Max) = (1448, 2534, 3174, 17740), using in each run +#' a different index order using the (\code{\link{sample}}) method. +#' +#' \emph{Geodetic datum:} the \code{recmap} algorithm is not transforming the +#' geodetic datum, e.g., WGS84 or Swissgrid. +#' +#' @return +#' Returns a \code{recmap} S3 object of the transformed map with new coordinates +#' (x, y, dx, dy) plus additional columns containing information for topology +#' error, relative position error, and the DFS number. +#' The error values are thought to be used for fitness function of the +#' metaheuristic. +#' +#' @aliases RecMap cartogram all.equal.recmap +#' +#' @author Christian Panse, 2016 +#' +#' @examples +#' map <- checkerboard(2) +#' cartogram <- recmap(map) +#' +#' map +#' cartogram +#' +#' op <- par(mfrow = c(1, 2)) +#' plot(map) +#' plot(cartogram) +#' +#' ## US example +#' usa <- data.frame(x = state.center$x, +#' y = state.center$y, +#' # make the rectangles overlapping by correcting +#' # lines of longitude distance. +#' dx = sqrt(state.area) / 2 +#' / (0.8 * 60 * cos(state.center$y * pi / 180)), +#' dy = sqrt(state.area) / 2 / (0.8 * 60), +#' z = sqrt(state.area), +#' name = state.name) +#' +#' usa$z <- state.x77[, 'Population'] +#' US.Map <- usa[match(usa$name, +#' c('Hawaii', 'Alaska'), nomatch = 0) == 0, ] +#' +#' plot.recmap(US.Map) +#' US.Map |> recmap() |> plot() +#' par(op) +#' +#' # define a fitness function +#' recmap.fitness <- function(idxOrder, Map, ...){ +#' Cartogram <- recmap(Map[idxOrder, ]) +#' # a map region could not be placed; +#' # accept only feasible solutions! +#' if (sum(Cartogram$topology.error == 100) > 0){return (0)} +#' 1 / sum(Cartogram$z / (sqrt(sum(Cartogram$z^2))) +#' * Cartogram$relpos.error) +#' } +#' +#' @export +recmap <- function(V, E = NULL) { + .Call('_recmap_recmap', PACKAGE = 'recmap', V, E) +} + diff --git a/R/recmap.R b/R/recmap.R index 0dc8d22..2b3b7cb 100644 --- a/R/recmap.R +++ b/R/recmap.R @@ -99,11 +99,11 @@ NULL #' construct polygon mesh displayed in Figure 4a in -#' \url{https://doi.org/10.1109/TVCG.2004.1260761} #' #' @param A defines the area of a region in the center #' #' @return a \link{SpatialPolygons} object +#' @references \doi{10.1109/TVCG.2004.1260761} #' @export #' #' @examples @@ -269,8 +269,6 @@ as.SpatialPolygonsDataFrame <- function (x, ...) { #' The method generates a SpatialPolygons object of a as input given #' \code{\link{recmap}} object. Both \code{data.frame}s are merged by the index order. #' -#' @import sp -#' #' @param x a \code{\link{recmap}} object. #' @param df a \code{data.frame} object. default is NULL. #' @param \dots \dots diff --git a/README.md b/README.md index 16401e7..41ff97e 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,8 @@ available through [jss.v086.c01](http://dx.doi.org/10.18637/jss.v086.c01). Run an interactive shiny application ```{r} -library(shiny) +library(recmap) +GA::gaControl("useRcpp" = FALSE) # apple M1 recmap_shiny <- system.file('shiny-examples', package = 'recmap') shiny::runApp(recmap_shiny, display.mode = 'normal') ``` diff --git a/man/as.SpatialPolygonsDataFrame.recmap.Rd b/man/as.SpatialPolygonsDataFrame.recmap.Rd new file mode 100644 index 0000000..f933b4a --- /dev/null +++ b/man/as.SpatialPolygonsDataFrame.recmap.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/recmap.R +\name{as.SpatialPolygonsDataFrame.recmap} +\alias{as.SpatialPolygonsDataFrame.recmap} +\alias{as.SpatialPolygonsDataFrame} +\title{Convert a recmap Object to SpatialPolygonsDataFrame Object.} +\usage{ +\method{as.SpatialPolygonsDataFrame}{recmap}(x, df = NULL, ...) +} +\arguments{ +\item{x}{a \code{\link{recmap}} object.} + +\item{df}{a \code{data.frame} object. default is NULL.} + +\item{\dots}{\dots} +} +\description{ +The method generates a SpatialPolygons object of a as input given +\code{\link{recmap}} object. Both \code{data.frame}s are merged by the index order. +} +\examples{ +SpDf <- as.SpatialPolygonsDataFrame(recmap(checkerboard(8))) +summary(SpDf) +spplot(SpDf) + +} diff --git a/man/as.recmap.SpatialPolygonsDataFrame.Rd b/man/as.recmap.SpatialPolygonsDataFrame.Rd new file mode 100644 index 0000000..d1835b0 --- /dev/null +++ b/man/as.recmap.SpatialPolygonsDataFrame.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/recmap.R +\name{as.recmap.SpatialPolygonsDataFrame} +\alias{as.recmap.SpatialPolygonsDataFrame} +\alias{as.recmap} +\title{Convert a SpatialPolygonsDataFrame Object to recmap Object} +\usage{ +\method{as.recmap}{SpatialPolygonsDataFrame}(X) +} +\arguments{ +\item{X}{\code{\link{SpatialPolygonsDataFrame}} object.} +} +\value{ +returns a \code{\link{recmap}} object. +} +\description{ +The method generates a recmap class out of a \code{\link{SpatialPolygonsDataFrame}} object. +} +\examples{ +SpDf <- as.SpatialPolygonsDataFrame(recmap(checkerboard(8))) +summary(SpDf) +spplot(SpDf) +summary(as.recmap(SpDf)) + +} +\references{ +Roger S. Bivand, Edzer Pebesma, Virgilio Gomez-Rubio, 2013. +Applied spatial data analysis with R, Second edition. Springer, NY. +} diff --git a/man/dot-get_7triangles.Rd b/man/dot-get_7triangles.Rd new file mode 100644 index 0000000..dfeb5e3 --- /dev/null +++ b/man/dot-get_7triangles.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/recmap.R +\name{.get_7triangles} +\alias{.get_7triangles} +\title{construct polygon mesh displayed in Figure 4a in} +\usage{ +.get_7triangles(A = 1) +} +\arguments{ +\item{A}{defines the area of a region in the center} +} +\value{ +a \link{SpatialPolygons} object +} +\description{ +construct polygon mesh displayed in Figure 4a in +} +\examples{ +triangle.map <- recmap:::.get_7triangles() +z <- c(rep(4, 4), rep(1, 3)) +cols <- c(rep('white', 4), rep('grey',3)) + +op <- par(mfrow=c(1,2), mar=c(0, 0, 0, 0)) +plot(triangle.map, col=cols) + +\dontrun{ + # requires libfft.so installed in linux +if (require(getcartr) & require(Rcartogram)){ + cartogram <- quick.carto(triangle.map, z, res=64) + plot(cartogram, col=cols) +} +} +} +\references{ +\doi{10.1109/TVCG.2004.1260761} +} diff --git a/man/is.recmap.Rd b/man/is.recmap.Rd new file mode 100644 index 0000000..bee2046 --- /dev/null +++ b/man/is.recmap.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/recmap.R +\name{is.recmap} +\alias{is.recmap} +\title{Is an Object from a Class recmap?} +\usage{ +is.recmap(object) +} +\arguments{ +\item{object}{any \R object.} +} +\description{ +Is an Object from a Class recmap? +} diff --git a/man/plot.recmap.Rd b/man/plot.recmap.Rd new file mode 100644 index 0000000..4a95ca3 --- /dev/null +++ b/man/plot.recmap.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/recmap.R +\name{plot.recmap} +\alias{plot.recmap} +\alias{plot.recmapGA} +\alias{plot.recmapGRASP} +\title{Plot a recmap object.} +\usage{ +\method{plot}{recmap}(x, col = "#00000011", col.text = "grey", border = "darkgreen", ...) +} +\arguments{ +\item{x}{\code{recmap} object - can be input or output of \code{recmap}.} + +\item{col}{a vector of colors.} + +\item{col.text}{a vector of colors.} + +\item{border}{This parameter is passed to the \code{\link{rect}} function. +color for rectangle border(s). The default means par("fg"). +Use border = NA to omit borders. If there are shading lines, border = TRUE +means use the same colour for the border as for the shading lines. +The default value is set to \code{'darkgreen'}.} + +\item{\ldots}{whatsoever} +} +\value{ +graphical output +} +\description{ +plots input and output of the \code{\link{recmap}} function. +The function requires column names (x, y, dx, dy). +} +\examples{ +checkerboard(2) |> recmap() |> plot() +} diff --git a/man/recmap.Rd b/man/recmap.Rd new file mode 100644 index 0000000..ba2d1b8 --- /dev/null +++ b/man/recmap.Rd @@ -0,0 +1,141 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/RcppExports.R +\name{recmap} +\alias{recmap} +\alias{RecMap} +\alias{cartogram} +\alias{all.equal.recmap} +\title{Compute a Rectangular Statistical Cartogram} +\usage{ +recmap(V, E = NULL) +} +\arguments{ +\item{V}{defines the input map regions formatted as \code{\link{data.frame}} +having the column names \code{c('x', 'y', 'dx', 'dy', 'z', 'name')} +as described above. V could also be considered as the nodes of the pseudo dual.} + +\item{E}{defines the edges of the map region's pseudo dual graph. +If \code{E} is not provided, this is the default; the pseudo dual graph is +composed of overlapping rectangles. If used, E must be a +\code{\link{data.frame}} containing two columns named \code{c('u', 'v')} +of type integer referencing the row number of \code{V}.} +} +\value{ +Returns a \code{recmap} S3 object of the transformed map with new coordinates +(x, y, dx, dy) plus additional columns containing information for topology +error, relative position error, and the DFS number. +The error values are thought to be used for fitness function of the +metaheuristic. +} +\description{ +The input consists of a map represented by overlapping rectangles. +The algorithm requires as input for each map region: +\itemize{ + \item{a tuple of (x, y) values corresponding to the + (longitude, latitude) position,} + \item{a tuple of (dx, dy) of expansion along (longitude, latitude),} + \item{and a statistical value z.} +} +The (x, y) coordinates represent the center of the minimal bounding boxes +(MBB), The coordinates of the MBB are derived by adding or subtracting the +(dx, dy) / 2 tuple accordingly. The tuple (dx, dy) also defines the ratio of the +map region. The statistical values define the desired area of each map region. + +The output is a rectangular cartogram where the map regions are: + +\itemize{ + \item{Non-overlapping,} + \item{connected,} + \item{ratio and area of each rectangle correspond to the desired areas,} + \item{rectangles are placed parallel to the axes.} +} + +The construction heuristic places each rectangle in a way that important spatial +constraints, in particular +\itemize{ + \item{the topology of the pseudo dual graph,} + \item{the relative position of MBB centers.} +} +are tried to be preserved. + +The ratios are preserved and the area of each region corresponds to the as +input given statistical value z. +} +\details{ +The basic idea of the current recmap \emph{implementation}: +\enumerate{ + \item{Compute the pseudo dual out of the overlapping map regions.} + \item{Determine the \emph{core region} by \code{index <- int(n / 2)}.} + \item{Place region by region along DFS skeleton of pseudo dual starting + with the \emph{core region}.}} + +Note: if a rectangle can not be placed, accept a non-\emph{feasible solution} +(avoid solutions having a topology error higher than 100) +Solving this constellation can be intensive in the computation, and due to the +assumably low fitness value the candidate cartogram +will be likely rejected by the metaheuristic. + +\emph{Time Complexity:} +The time complexity is \eqn{O(n^2)}, where n is the number of regions. +DFS is visiting each map region only once and therefore has +time complexity \eqn{O(n)}. For each placement, a constant number of +MBB intersection are called (max 360). MBB check is implemented using +\code{std::set}, \code{insert}, \code{upper_bound}, \code{upper_bound} +costs are \eqn{O(\log(n))}{O(log(n))}. +However, the worst case for a range query is \eqn{O(n)}, if and only if dx or dy +cover the whole x or y range. Q.E.D. + +\emph{Performance:} +In praxis, computing on a 2.4 GHz Intel Core i7 machine (using only one core), using the +50 state U.S. map example, recmap can compute approximately 100 cartograms in one second. +The number of MBB calls were +(Min., Median, Mean, Max) = (1448, 2534, 3174, 17740), using in each run +a different index order using the (\code{\link{sample}}) method. + +\emph{Geodetic datum:} the \code{recmap} algorithm is not transforming the +geodetic datum, e.g., WGS84 or Swissgrid. +} +\examples{ +map <- checkerboard(2) +cartogram <- recmap(map) + +map +cartogram + +op <- par(mfrow = c(1, 2)) +plot(map) +plot(cartogram) + +## US example +usa <- data.frame(x = state.center$x, + y = state.center$y, + # make the rectangles overlapping by correcting + # lines of longitude distance. + dx = sqrt(state.area) / 2 + / (0.8 * 60 * cos(state.center$y * pi / 180)), + dy = sqrt(state.area) / 2 / (0.8 * 60), + z = sqrt(state.area), + name = state.name) + +usa$z <- state.x77[, 'Population'] +US.Map <- usa[match(usa$name, + c('Hawaii', 'Alaska'), nomatch = 0) == 0, ] + +plot.recmap(US.Map) +US.Map |> recmap() |> plot() +par(op) + +# define a fitness function +recmap.fitness <- function(idxOrder, Map, ...){ + Cartogram <- recmap(Map[idxOrder, ]) + # a map region could not be placed; + # accept only feasible solutions! + if (sum(Cartogram$topology.error == 100) > 0){return (0)} + 1 / sum(Cartogram$z / (sqrt(sum(Cartogram$z^2))) + * Cartogram$relpos.error) +} + +} +\author{ +Christian Panse, 2016 +} diff --git a/man/recmapGA.Rd b/man/recmapGA.Rd new file mode 100644 index 0000000..68e9d5a --- /dev/null +++ b/man/recmapGA.Rd @@ -0,0 +1,123 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/recmap.R +\name{recmapGA} +\alias{recmapGA} +\title{Genetic Algorithm Wrapper Function for recmap} +\usage{ +recmapGA( + V, + fitness = .recmap.fitness, + pmutation = 0.25, + popSize = 10 * nrow(Map), + maxiter = 10, + run = maxiter, + monitor = if (interactive()) { + gaMonitor + } else FALSE, + parallel = FALSE, + ... +) +} +\arguments{ +\item{V}{defines the input map regions formatted as \code{\link{data.frame}} +having the column names \code{c('x', 'y', 'dx', 'dy', 'z', 'name')} +as described above. V could also be considered as the nodes of the pseudo dual.} + +\item{fitness}{the fitness function, any allowable R function which takes as input an individual \code{string} representing a potential solution, and returns a numerical value describing its ``fitness''.} + +\item{pmutation}{the probability of mutation in a parent chromosome. Usually mutation occurs with a small probability, and by default is set to 0.1.} + +\item{popSize}{the population size.} + +\item{maxiter}{the maximum number of iterations to run before the GA search is halted.} + +\item{run}{the number of consecutive generations without any improvement in the best fitness value before the GA is stopped.} + +\item{monitor}{a logical or an R function which takes as input the current state of the \code{ga-class} object and show the evolution of the search. By default, for interactive sessions the function \code{\link[GA]{gaMonitor}} prints the average and best fitness values at each iteration. If set to \code{plot} these information are plotted on a graphical device. Other functions can be written by the user and supplied as argument. In non interactive sessions, by default \code{monitor = FALSE} so any output is suppressed.} + +\item{parallel}{ +An optional argument which allows to specify if the Genetic Algorithm should be run sequentially or in parallel. + +For a single machine with multiple cores, possible values are: +\itemize{ + \item a logical value specifying if parallel computing should be used (\code{TRUE}) or not (\code{FALSE}, default) for evaluating the fitness function; + \item a numerical value which gives the number of cores to employ. By default, this is obtained from the function \code{\link[parallel]{detectCores}}; + \item a character string specifying the type of parallelisation to use. This depends on system OS: on Windows OS only \code{"snow"} type functionality is available, while on Unix/Linux/Mac OSX both \code{"snow"} and \code{"multicore"} (default) functionalities are available. +} +In all the cases described above, at the end of the search the cluster is automatically stopped by shutting down the workers. + +If a cluster of multiple machines is available, evaluation of the fitness function can be executed in parallel using all, or a subset of, the cores available to the machines belonging to the cluster. However, this option requires more work from the user, who needs to set up and register a parallel back end. +In this case the cluster must be explicitly stopped with \code{\link[parallel]{stopCluster}}. +} + +\item{...}{additional arguments to be passed to the fitness function. This allows to write fitness functions that keep some variables fixed during the search.} +} +\value{ +returns a list of the input \code{Map}, the solution of the \code{\link[GA]{ga}} +function, and a \code{\link{recmap}} object containing the cartogram. +} +\description{ +higher-level function for \code{\link{recmap}} using a Genetic Algorithm as +metaheuristic. +} +\examples{ +## The default fitnes function is currently defined as +function(idxOrder, Map, ...){ + + Cartogram <- recmap(Map[idxOrder, ]) + # a map region could not be placed; + # accept only feasible solutions! + + if (sum(Cartogram$topology.error == 100) > 0){return (0)} + + 1 / sum(Cartogram$relpos.error) +} + + +## use Genetic Algorithms (GA >=3.0.0) as metaheuristic +set.seed(1) + +## https://github.com/luca-scr/GA/issues/52 +if (Sys.info()['machine'] == "arm64") GA::gaControl(useRcpp = FALSE) +res <- recmapGA(V = checkerboard(4), pmutation = 0.25) + +op <- par(mfrow = c(1, 3)) +plot(res$Map, main = "Input Map") +plot(res$GA, main="Genetic Algorithm") +plot(res$Cartogram, main = "Output Cartogram") + + +## US example +getUS_map <- function(){ + usa <- data.frame(x = state.center$x, + y = state.center$y, + # make the rectangles overlapping by correcting + # lines of longitude distance. + dx = sqrt(state.area) / 2 + / (0.8 * 60 * cos(state.center$y * pi / 180)), + dy = sqrt(state.area) / 2 / (0.8 * 60), + z = sqrt(state.area), + name = state.name) + + usa$z <- state.x77[, 'Population'] + US.Map <- usa[match(usa$name, + c('Hawaii', 'Alaska'), nomatch = 0) == 0, ] + + class(US.Map) <- c('recmap', 'data.frame') + US.Map +} + +\dontrun{ +# takes 34.268 seconds on CRAN +res <- recmapGA(V = getUS_map(), maxiter = 5) +op <- par(ask = TRUE) +plot(res) +par(op) +summary(res) +} +} +\references{ +Luca Scrucca (2013). GA: A Package for Genetic Algorithms in R. +Journal of Statistical Software, 53(4), 1-37. +\doi{10.18637/jss.v053.i04}. +} diff --git a/man/summary.recmap.Rd b/man/summary.recmap.Rd new file mode 100644 index 0000000..34ac5ef --- /dev/null +++ b/man/summary.recmap.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/recmap.R +\name{summary.recmap} +\alias{summary.recmap} +\alias{summary.recmapGA} +\title{Summary for recmap object} +\usage{ +\method{summary}{recmap}(object, ...) +} +\arguments{ +\item{object}{an object for which a summary is desired.} + +\item{...}{additional arguments affecting the summary produced.} +} +\value{ +returns a \code{data.frame} containing summary information, e.g., +objective functions or number of map regions. +} +\description{ +Summary method for S3 class \code{\link{recmap}}. +The area error is computed as described in the CartoDraw paper. +} +\examples{ +summary(checkerboard(4)); +summary(recmap(checkerboard(4))) +} +\references{ +\doi{10.1109/TVCG.2004.1260761} +} diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp new file mode 100644 index 0000000..a9b01f0 --- /dev/null +++ b/src/RcppExports.cpp @@ -0,0 +1,67 @@ +// Generated by using Rcpp::compileAttributes() -> do not edit by hand +// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 + +#include + +using namespace Rcpp; + +#ifdef RCPP_USE_GLOBAL_ROSTREAM +Rcpp::Rostream& Rcpp::Rcout = Rcpp::Rcpp_cout_get(); +Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get(); +#endif + +// get_angle +double get_angle(double x0, double y0, double x1, double y1); +RcppExport SEXP _recmap_get_angle(SEXP x0SEXP, SEXP y0SEXP, SEXP x1SEXP, SEXP y1SEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< double >::type x0(x0SEXP); + Rcpp::traits::input_parameter< double >::type y0(y0SEXP); + Rcpp::traits::input_parameter< double >::type x1(x1SEXP); + Rcpp::traits::input_parameter< double >::type y1(y1SEXP); + rcpp_result_gen = Rcpp::wrap(get_angle(x0, y0, x1, y1)); + return rcpp_result_gen; +END_RCPP +} +// place_rectangle +DataFrame place_rectangle(double x0, double y0, double dx0, double dy0, double dx1, double dy1, double alpha); +RcppExport SEXP _recmap_place_rectangle(SEXP x0SEXP, SEXP y0SEXP, SEXP dx0SEXP, SEXP dy0SEXP, SEXP dx1SEXP, SEXP dy1SEXP, SEXP alphaSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< double >::type x0(x0SEXP); + Rcpp::traits::input_parameter< double >::type y0(y0SEXP); + Rcpp::traits::input_parameter< double >::type dx0(dx0SEXP); + Rcpp::traits::input_parameter< double >::type dy0(dy0SEXP); + Rcpp::traits::input_parameter< double >::type dx1(dx1SEXP); + Rcpp::traits::input_parameter< double >::type dy1(dy1SEXP); + Rcpp::traits::input_parameter< double >::type alpha(alphaSEXP); + rcpp_result_gen = Rcpp::wrap(place_rectangle(x0, y0, dx0, dy0, dx1, dy1, alpha)); + return rcpp_result_gen; +END_RCPP +} +// recmap +DataFrame recmap(DataFrame V, Rcpp::Nullable E); +RcppExport SEXP _recmap_recmap(SEXP VSEXP, SEXP ESEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< DataFrame >::type V(VSEXP); + Rcpp::traits::input_parameter< Rcpp::Nullable >::type E(ESEXP); + rcpp_result_gen = Rcpp::wrap(recmap(V, E)); + return rcpp_result_gen; +END_RCPP +} + +static const R_CallMethodDef CallEntries[] = { + {"_recmap_get_angle", (DL_FUNC) &_recmap_get_angle, 4}, + {"_recmap_place_rectangle", (DL_FUNC) &_recmap_place_rectangle, 7}, + {"_recmap_recmap", (DL_FUNC) &_recmap_recmap, 2}, + {NULL, NULL, 0} +}; + +RcppExport void R_init_recmap(DllInfo *dll) { + R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); + R_useDynamicSymbols(dll, FALSE); +}