diff --git a/.gitignore b/.gitignore index 35865db..6d419f9 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,4 @@ xcuserdata .RData .Rproj.user inst/doc +test.png diff --git a/DESCRIPTION b/DESCRIPTION index 030aa2f..c5b7fc4 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -24,7 +24,7 @@ Imports: RColorBrewer (>= 1.1.2), sf (>= 0.6.1), units (>= 0.4-6) -RoxygenNote: 6.0.1 +RoxygenNote: 7.1.0 Suggests: knitr, rmarkdown, rgcam, diff --git a/NAMESPACE b/NAMESPACE index bd3a2fc..af73825 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,28 +1,56 @@ # Generated by roxygen2: do not edit by hand -export(EXTENT_AFRICA) -export(EXTENT_CHINA) -export(EXTENT_LA) -export(EXTENT_USA) -export(EXTENT_WORLD) -export(add_region_ID) -export(af_ortho) -export(basin235) -export(ch_aea) -export(chn) -export(eck3) -export(gcam14_colors) -export(gcam32_colors) +export(choropleth) +export(custom_map) +export(distributed_flow) +export(gridded_map) export(import_mapdata) -export(na_aea) -export(plot_GCAM) -export(plot_GCAM_grid) -export(rgn14) -export(rgn32) -export(robin) +export(load_shp) +export(process_data) +export(process_raster) +export(process_shape) +export(return_error) +export(save_plot) export(simplify_mapdata) -export(usa) -export(wgs84) -import(ggplot2) +export(verify_shape) +export(verify_simplify_mapdata) +import(RColorBrewer) +importFrom(classInt,classIntervals) +importFrom(dplyr,left_join) +importFrom(dplyr,mutate) +importFrom(ggplot2,aes_string) +importFrom(ggplot2,coord_sf) +importFrom(ggplot2,element_text) +importFrom(ggplot2,expand_scale) +importFrom(ggplot2,geom_raster) +importFrom(ggplot2,geom_sf) +importFrom(ggplot2,geom_sf_label) +importFrom(ggplot2,geom_sf_text) +importFrom(ggplot2,geom_text) +importFrom(ggplot2,ggplot) +importFrom(ggplot2,ggsave) +importFrom(ggplot2,guides) +importFrom(ggplot2,labs) +importFrom(ggplot2,rel) +importFrom(ggplot2,scale_fill_brewer) +importFrom(ggplot2,scale_fill_distiller) +importFrom(ggplot2,scale_x_continuous) +importFrom(ggplot2,scale_x_discrete) +importFrom(ggplot2,scale_y_continuous) +importFrom(ggplot2,scale_y_discrete) +importFrom(ggplot2,theme) +importFrom(ggplot2,theme_minimal) +importFrom(ggplot2,theme_update) +importFrom(ggspatial,df_spatial) +importFrom(ggspatial,layer_spatial) importFrom(magrittr,"%>%") -importFrom(utils,read.csv) +importFrom(raster,as.data.frame) +importFrom(raster,compareCRS) +importFrom(raster,crs) +importFrom(raster,maxValue) +importFrom(raster,minValue) +importFrom(raster,nlayers) +importFrom(raster,raster) +importFrom(rgis,import_raster) +importFrom(sf,st_crs) +importFrom(sf,st_transform) diff --git a/R/Map_Functions.R b/R/Map_Functions.R deleted file mode 100644 index f3699f6..0000000 --- a/R/Map_Functions.R +++ /dev/null @@ -1,535 +0,0 @@ -# map_functions.R -# -# The main file containing functions for producing maps of spatial GCAM data. - - -# Loading Data ------------------------------------------------------------ - -#' Import ESRI Shapefile or GeoJSON as sf object. -#' -#' Creates a Simple Feature (sf) object from full path string to ESRI Shapefile -#' or GeoJSON file. User defines which field is supposed to represent the ID for -#' the data. -#' -#' @param file_pth Full path to shapefile with extention (.shp). Shapefiles must -#' contain at least .shp, .shx, and .dbf file to function properly. -load_shp <- function(file_pth) { - return(sf::st_read(file_pth, quiet = TRUE)) -} - -#' Single import function for compatible data types. -#' -#' Imports available for sf objects, spatial data frames, ESRI Shapefiles, or -#' GeoJSON files. -#' -#' @param obj Input full path string or object. -#' @param fld Field name to use as identifier. -#' @param prj4s Proj4 string for projection (default WGS84). -#' @return An sf object representation of the map data. -#' @export -import_mapdata <- function(obj, fld = NULL, prj4s = wgs84) { - - # get object class - cls <- class(obj) - - # check for sf data frame object - if (cls[1] == "sf") { - return(obj) - } - - # check for file path - else if (is.character(obj)) { - - # get file extension - extn <- tolower(c(tools::file_ext(obj))) - - # if ESRI Shapefile or GeoJSON file - if (extn %in% list('shp', 'geojson')) { - - # load Shapefile - return(load_shp(file_pth = obj)) - } - # catch unknown - else { - return(NULL) - } - } - # check for spatial data frames - else if (cls %in% list("SpatialPolygonsDataFrame", "SpatialPointsDataFrame", - "SpatialLinesDataFrame")) { - - return(sf::st_as_sf(obj)) - } - else { - return(NULL) # catch_error: object type not understood. - } -} - - -# Map Data Transformations ------------------------------------------------ - -#' Get features topologically associated with extent bounds. -#' -#' Conducts a spatial join to retrieve spatial features that are topologically associated -#' (intersects, contains, within, etc.) with the provided bounds. -#' -#' @param mapdata The sf object containing the spatial data. -#' @param bbox Bounding box. -#' @param agr_type Inherited attribute-geometry-relationship type from plot_GCAM -#' function params. -#' @param topo SF topologic function to define how the join will be conducted. -#' Default is to join any feature that intersects the bounding box. -filter_spatial <- function(mapdata, bbox, agr_type='constant', topo=sf::st_intersects) { - # set attribute-geometry-relationship for input mapdata column and bounding - # box feature attribute - sf::st_agr(mapdata) <- agr_type - sf::st_agr(bbox) <- agr_type - - # Message for st_join and st_intersection suppressed: - # "although coordinates are longitude/latitude, it is assumed that they - # are planar." - # This comes from the input projection being a geographic coordinate system - # and not a projected one when conducting topological operations such as - # st_intersects used in the st_join. If 'longlat' appears in the proj string - # ("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs") then this message will - # present itself due to the operation being intersect according to the source - # code. There is no option to quiet this. We are getting the expected return - # from the operation due to harmonizing the map and bounding box projection - # pre-join. - mapdata <- suppressMessages({sf::st_intersection(mapdata, bbox)}) - return(suppressMessages({sf::st_join(mapdata, bbox, join = topo, left = FALSE)})) -} - -#' Join GCAM data with spatial data. -#' -#' Joins GCAM data from rgam query and inner joins it to spatial data provided by the user. -#' Note: due to conducting an inner join, only the keys that are present in both datasets -#' will be represented. -#' -#' @param mapdata The sf object containing the spatial data and a tuple identifier that -#' can be referenced in the gcam_df data frame. -#' @param mapdata_key Name of the field having a tuple identifier that can be referenced -#' in the gcam_df data frame. -#' @param gcam_df The GCAM data frame provided from the user. This is usually generated from -#' an \code{rgcam} query. -#' @param gcam_key Name of field having a tuple identifier that can be referenced in the -#' mapdata data frame. -join_gcam <- function(mapdata, mapdata_key, gcam_df, gcam_key) { - - if (is.null(gcam_df)) { - return(mapdata) - } - - # Make sure join keys are valid - if (is.null(mapdata_key) || !(mapdata_key %in% names(mapdata))) { - stop("You must provide a valid key for joining the spatial data") - } - if (is.null(gcam_key) || !(gcam_key %in% names(gcam_df))) { - stop("You must provide a valid key for joining the GCAM data") - } - - # add pkey fields for join - mapdata['pkey'] <- mapdata[[mapdata_key]] - gcam_df['pkey'] <- gcam_df[gcam_key] - - # Join the map data and gcam data using the keys provided - # Note that using dplyr::left_join() here can cause the result to no - # longer be an sf object as documented here: https://github.com/r-spatial/sf/issues/343 ; - # to remedy until dplyr creates an sf join function cast back to sf obj - mapdata <- dplyr::left_join(mapdata, gcam_df, by='pkey') %>% - dplyr::select(-pkey) %>% - sf::st_as_sf() - - return(mapdata) -} - - - -#' Reduce number of polygons and size of polygons for map Shapefiles -#' -#' Takes a sf object representation of a map and simplifys it by removing -#' polygons that are under a certain size. -#' -#' ** NOTE: This function adds two polygons to the edges of the map to prevent -#' the removal of polygons near the edges redefining the map bounds. -#' -#' @param mapdata sf object containing polygons or multipolygons to simplify. -#' @param min_area Minimum area of polygons to keep. -#' @param degree_tolerance Tolerance parameter for simplifying polygons. -#' @return The simplified sf object. -#' @export -simplify_mapdata <- function(mapdata, min_area = 2.5, degree_tolerance = 0.1) { - - . <- NULL # silence package notes for NSE. - - if ("MULTIPOLYGON" %in% sf::st_geometry_type(mapdata)) - mapdata <- sf::st_cast(mapdata, "POLYGON", warn = FALSE) - - # filter out all polygons in the data under the minimum area - areafilter <- sapply(sf::st_geometry(mapdata), sf::st_area) > min_area - filtermap <- mapdata[which(areafilter), ] - - filtermap <- suppressWarnings({sf::st_simplify(filtermap, preserveTopology=TRUE, dTolerance=degree_tolerance)}) - - # if nothing was filtered just return original map - if (utils::object.size(filtermap) == utils::object.size(mapdata)) - return(mapdata) - - # When removing polygons we might be shifting the bounds of the map, which - # would make it off-center when plotting. To account for this, we put tiny - # polygons on the edges. - xmin <- sf::st_bbox(mapdata)[1] %>% round - xmax <- sf::st_bbox(mapdata)[3] %>% round - height <- 0.0001 # small enough so it's not visible on plot - - left_edge <- matrix(c(xmin, 0, xmin, height, xmin - height, 0, xmin, 0), - byrow = TRUE, ncol = 2) %>% - list() %>% - sf::st_polygon() - - right_edge <- matrix(c(xmax, 0, xmax, height, xmax + height, 0, xmax, 0), - byrow = TRUE, ncol = 2) %>% - list() %>% - sf::st_polygon() - - # create geometry with the two edges - edges <- sf::st_sfc(left_edge, right_edge, crs = sf::st_crs(mapdata)) - - # data frame with same names as original map, so that the two can combine - borders <- data.frame(matrix(ncol = length(names(mapdata)), nrow = 2)) %>% - magrittr::set_names(names(mapdata)) - - # extra polygons should be GCAM region 0 - if ('region_id' %in% names(borders)) borders$region_id <- c(0, 0) - - # convert to sf object and add new border polygons - sf::st_geometry(borders) <- edges - - # add new polygons to filtered map and return - return(rbind(borders, filtermap)) -} - - -# Map Creation ------------------------------------------------------------ - -#' Primary GCAM mapping function. Can handle categorical or continuous data. -#' -#' This function produces a map visualization of a data set containing GCAM -#' output data. The required argument is a data frame of GCAM results by -#' region. The function \code{\link[rgcam]{getQuery}} produces suitable data -#' frames. -#' -#' We don't try to take the color mapping, legend title, etc. as arguments to -#' this function. The ggplot2 way of specifying this information is way more -#' flexible. To customize your color mapping, use one of \itemize{ \item -#' \code{\link[ggplot2]{scale_fill_manual}} : A list of colors to map to -#' categorical data. \item \code{\link[ggplot2]{scale_fill_gradient}} : A -#' gradient from one color to another. \item -#' \code{\link[ggplot2]{scale_fill_gradient2}} : A diverging gradient from one -#' color to another, passing through white in the middle. You can set the data -#' value that gets assigned to white with the \code{midpoint} argument. \item -#' \code{\link[ggplot2]{scale_fill_gradientn}} : A smooth gradient between an -#' arbitrary selection of colors. } If you choose to display a legend for the -#' color mapping, you will have to give it a title using the \code{title} -#' argument to any of the above gradient functions. You have to do this even if -#' you want a legend with no title at all. Use an empty string in that case. -#' -#' For specifying the projection you can use any Proj4 string. For convenience, -#' this package defines the following proj4 strings: \itemize{ \item -#' \code{\link{wgs84}} - WGS84 (EPSG:4326) \item \code{\link{eck3}} - Eckert III -#' \item \code{\link{robin}} - Robinson \item \code{\link{na_aea}} - Albers -#' equal area (North America) \item \code{\link{ch_aea}} - Albers equal area -#' (China) \item \code{\link{af_ortho}} - Orthographic projection over Africa } -#' -#' -#' The \code{extent} argument gives the bounding box of the area to be plotted. -#' Its format is \code{c(lon.min, lon.max, lat.min, lat.max)}. For convenience -#' we have defined the following frequently used map extents: \itemize{ \item -#' \code{\link{EXTENT_WORLD}} - Entire world \item \code{\link{EXTENT_USA}} - -#' Continental United States \item \code{\link{EXTENT_CHINA}} - China \item -#' \code{\link{EXTENT_AFRICA}} - Africa \item \code{\link{EXTENT_LA}} - Latin -#' America } -#' -#' @param mapdata The data frame containing both geometric data (simple features -#' collection and id) and regional metadata. This is the only mandatory -#' variable. If used alone, will produce the default map. -#' @param col If plotting categorical/continuous data, the name of the column to -#' plot. Will automatically determine type of style of plot based on type of -#' data (numeric or character). -#' @param proj Map projection to use in the display map. This should be a proj4 -#' string, except for a few special cases. There are also symbols defined for -#' some frequently used projections (e.g. \code{\link{robin}} or -#' \code{\link{na_aea}}). -#' @param proj_type Either esri, epsg, or sr-org as string. These correspond to -#' available reference types hosted by \url{http://spatialreference.org/}. -#' @param extent Numeric bounds [xmin, xmax, ymin, ymax] to zoom display to. -#' @param title Text to be displayed as the plot title. -#' @param legend Boolean flag: True = display map legend; False = do not display -#' legend. -#' @param gcam_df A data frame generated from the \code{rgcam} function -#' \code{\link[rgcam]{getQuery}}. Also accepts other data frames that contain -#' data that can be linked to the map geometry data using a unique identifier. -#' @param gcam_key The field name containing a join identifier in the gcam_df -#' data frame. -#' @param mapdata_key The field name containing a join identifier in the -#' mapdata. -#' @param zoom A distance to buffer the bounding box extent by for on-the-fly -#' adjustments needed when fitting area to maps. -#' @param graticules Where to position any graticules. One of 'top', 'bottom', -#' or '' (empty string). Note that 'bottom' places them under the map -#' background and will not be visible without a setting the -#' \code{background_color} parameter to NA or transparent. -#' @param agr_type Aggregate-geometry-relationship type. Either 'constant' -#' (default), 'aggregate', or 'identity' classified as follows: [constant] a -#' variable that has a constant value at every location over a spatial extent; -#' examples: soil type, climate zone, land use. [aggregate] values are summary -#' values (aggregates) over the geometry, e.g. population density, dominant -#' land use. [identity] values identify the geometry: they refer to (the -#' whole of) this and only this geometry. See the -#' \href{https://cran.r-project.org/web/packages/sf/vignettes/sf1.html#how-attributes-relate-to-geometries}{sf -#' vignette} for further explanation. -#' @param background_color Color for the areas with no regions (the oceans) -#' @param padding Boolean flag: Add space between map edge and plot edge? -#' @examples \dontrun{ -#' -#' ## Plot a map of GCAM regions; color it with the default theme palette. -#' plot_GCAM(map.rgn32.simple, col = 'region_name', proj = eck3) + -#' ggplot2::scale_fill_manual(values = gcam32_colors, na.value=gray(0.75)) -#' -#' ## Plot refined liquids production by region for the year 2050 -#' prj <- loadProject(system.file('sample-gcam-data', -#' 'gcam-longform-sample.dat', -#' package='gcammaptools')) -#' ref_liquids <- rgcam::getQuery(prj, 'Refined liquids production by region', 'Reference') -#' ref_liquids <- add_region_ID(ref_liquids, lookupfile=rgn32, drops=rgn32) -#' ref_liquids <- dplyr::filter(ref_liquids, year==2050) -#' plot_GCAM(map.rgn32.simple, col='value', proj=robin, title="Robinson World", -#' legend=T, gcam_df=co2, gcam_key='id', mapdata_key="region_id") + -#' ggplot2::scale_fill_gradientn(colors = c("white", "red"), -#' na.value = gray(0.75), -#' name="CO2 Emissions (MTC)") -#' } -#' @export -plot_GCAM <- function(mapdata, col = NULL, proj = robin, proj_type = NULL, - extent = EXTENT_WORLD, title = "", legend = F, - gcam_df = NULL, gcam_key = "id", mapdata_key = "region_id", - zoom = 0, graticules = "bottom", agr_type = 'constant', - background_color = MAP_BACKGROUND, - padding = all(extent == EXTENT_WORLD)) { - - # get proj4 string that corresponds to user selection - p4s <- assign_prj4s(proj_type, proj) - - # ensure that the map is an sf object - map <- import_mapdata(mapdata) - - # eliminate erroneous-filled polygons generated at the global extent - wborder <- spat_bb(EXTENT_WORLD, 0, sf::st_crs(map)) - sf::st_agr(wborder) <- agr_type - sf::st_agr(map) <- agr_type - map <- suppressMessages({sf::st_intersection(map, wborder)}) - - # create sf obj bounding box from extent; this box defines the final view of - # the map so it needs to be a rectangle (except for the global extent, where - # the map edge may be rounded). - bounds <- spat_bb(b_ext = extent, buff_dist = zoom, proj4s = p4s) - if (!all(extent == EXTENT_WORLD)) { - sf::st_geometry(bounds)[[1]] <- pgon_from_extent(sf::st_bbox(bounds)) - } - - # reproject map into user-specified crs, filter to extent, then join user data - map <- sf::st_transform(map, p4s) - map <- remove_invalid(map) - tryCatch( - map <- filter_spatial(map, bounds, agr_type), - error = function(e) stop("Reprojection produced invalid map.") - ) - map <- join_gcam(map, mapdata_key, gcam_df, gcam_key) - - # datum = wgs84 means that graticules are drawn based on first layer's crs - dtm <- if (graticules == "top" | graticules == "bottom") wgs84 else NA - - # Because graticules are drawn as ggplot gridlines, we cannot have them both - # on top of map and still have a solid panel background. We can get around - # this problem by making our own background. By default, coord_sf(expand = T) - # multiplies the panel's x and y ranges by 0.05, which we'll do here manually. - panel_background <- NULL - if (padding & graticules == "top") { - padding <- FALSE - panel <- sf::st_bbox(bounds) - panel[c(1,3,2,4)] <- c(scales::expand_range(c(panel[1], panel[3]), 0.05), - scales::expand_range(c(panel[2], panel[4]), 0.05)) - panel <- panel %>% sf::st_as_sfc() %>% sf::st_sf() - panel_background <- ggplot2::geom_sf(data = panel, fill = PANEL_FILL) - } - - # set different aesthetics depending on whether there is region-specific data - if (is.null(col)) - regions <- ggplot2::geom_sf(data = map, fill = FILL_COLOR, - color = BORDER_LIGHT) - else - regions <- ggplot2::geom_sf(data = map, aes_string(fill = col), alpha = 1, - color = BORDER_DARK) - - # generate plot object - mp <- ggplot() + - panel_background + - ggplot2::geom_sf(data = bounds, fill = background_color) + - regions + - ggplot2::coord_sf(expand = padding, datum = dtm) + - ggplot2::ggtitle(title) + - theme_GCAM(legend = legend, overlay_graticules = graticules == "top") - - return(mp) -} - -#' Plot a gridded dataset over a base map -#' -#' This function produces a map visualization of a gridded (i.e., values -#' specified by latitude and longitude) data set. The data will be plotted over -#' the base map supplied -#' -#' The plot data should be in the form of a table of latitude (lat), longitude -#' (lon), and data values. The name of the data column is given as an argument -#' to the function, so you can have, for example, latitude and longitude columns -#' followed by columns for time slices. Columns besides the coordinate and data -#' columns will be ignored. -#' -#' @param plotdata Data frame with the coordinates and values to be plotted. -#' Must contain 'lat' and 'lon' columns. -#' @param col Name of the column holding the data values to plot -#' @param map Base map data. Default is GCAM 32-region -#' @param alpha Transparency of the grid data layer. Given as a number between -#' 0 and 1, where 0 is completely transparent and 1 is completely opaque. -#' @param ... Other parameters passed on to \code{plot_GCAM}. -#' @inheritParams plot_GCAM -#' @export -plot_GCAM_grid <- function(plotdata, col, map = map.rgn32, proj = robin, - proj_type = NULL, extent = EXTENT_WORLD, zoom = 0, - alpha = 0.8, ...) { - - map.rgn32 <- gcammaptools::map.rgn32 # Silence package notes - - # make sure data has valid gridded data - if (!('lon' %in% names(plotdata) && 'lat' %in% names(plotdata))) - stop("gridded data must have a 'lon' column and a 'lat' column") - - # get plot bounds - p4s <- assign_prj4s(proj_type, proj) - bounds <- sf::st_bbox(spat_bb(extent, zoom, proj4s = p4s))[c(1,3,2,4)] - - # are we in a projected crs? - if (!sf::st_is_longlat(proj)) { - # get raster extent - e <- raster::extent(c(range(plotdata$lon), range(plotdata$lat))) - - # set the number of rows and columns in the raster equal to the number - # of unique latitudes and longitudes in the original data - nr <- plotdata['lat'] %>% unique() %>% nrow - nc <- plotdata['lon'] %>% unique() %>% nrow - - # build a raster that fits the data - plotraster <- raster::raster(nrows = nr, ncols = nc, ext = e, crs = wgs84) - - points <- plotdata[ , c('lon', 'lat')] - values <- plotdata[[col]] - - # 1. Add data values to raster cells - # 2. Reproject the raster into the user-defined crs - # 3. Crop out any cells not within the map extent - # 4. Turn the raster back into points in the new crs - # 5. Convert back to a data.frame with the correct names so that - # geom_raster can plot it - plotdata <- raster::rasterize(points, plotraster, field = values, fun = mean) %>% - raster::projectRaster(crs=p4s, over=TRUE) %>% - raster::crop(bounds) %>% - raster::rasterToPoints() %>% - data.frame() %>% - magrittr::set_names(c("lon", "lat", col)) - } - else { - plotdata <- dplyr::filter(plotdata, bounds[1] <= lon, lon <= bounds[2], - bounds[3] <= lat, lat <= bounds[4]) - } - - # get the base map using plot_GCAM - mp <- plot_GCAM(map, proj = proj, proj_type = proj_type, extent = extent, zoom = zoom, ...) - - # add the gridded data to the base map - grid <- geom_raster(data = plotdata, - mapping = aes_string(x='lon', y='lat', fill = col), - alpha = alpha) - - # remove x and y axis labels and give scale a title - lbls <- labs(x = XLAB, y = YLAB, fill=col) - return(mp + grid + lbls) -} - - -#' Default GCAM theme function -#' -#' An add-on function to any ggplot2 object. Derives from ggplot2 black and -#' white theme function (theme_bw). -#' -#' @param base_size Base font size -#' @param base_family Base font type -#' @param legend Boolean; whether to include a legend with default legend -#' formatting. -#' @param overlay_graticules Boolean; whether to place grid lines on top of plot -theme_GCAM <- function(base_size = 11, base_family = "", legend = FALSE, - overlay_graticules = FALSE) { - - tm <- theme_bw(base_size = base_size, base_family = base_family) %+replace% - theme(panel.border = element_rect(color = LINE_COLOR, fill = NA), - panel.background = element_rect(fill = PANEL_FILL), - panel.grid.major = PANEL_GRID, - axis.ticks = AXIS_TICKS, - axis.text = AXIS_TEXT, - legend.position = "none") - - if (legend) { - tm <- tm + - theme(legend.key.size = unit(0.75, "cm"), - legend.text = element_text(size = 12), - legend.title = element_text(size = 13, face = "bold"), - legend.position = LEGEND_POSITION, - legend.key = element_rect(color = "black")) - } - - if (overlay_graticules) { - tm <- tm + theme(panel.background = element_blank(), panel.ontop = T) - } - - return(tm) -} - - -#' Designator for the rgn14 map set -#' -#' This symbol will select the rgn14 map set -#' @export -rgn14 <- quote(rgn14) - -#' Designator for the rgn32 map set -#' -#' This symbol will select the rgn32 map set -#' @export -rgn32 <- quote(rgn32) - -#' Designator for the basin235 map set -#' -#' This symbol will select the basin235 map set -#' @export -basin235 <- quote(basin235) - -#' Designator for the chn map set -#' -#' This symbol will select the chn map set -#' @export -chn <- quote(chn) - -#' Designator for the usa map set -#' -#' This symbol will select the usa map set -#' @export -usa <- quote(usa) diff --git a/R/diag_header.R b/R/diag_header.R deleted file mode 100644 index b5eaaaa..0000000 --- a/R/diag_header.R +++ /dev/null @@ -1,211 +0,0 @@ -# LEGAL NOTICE -# This computer software was prepared by Battelle Memorial Institute, -# hereinafter the Contractor, under Contract No. DE-AC05-76RL0 1830 -# with the Department of Energy (DOE). NEITHER THE GOVERNMENT NOR THE -# CONTRACTOR MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY -# LIABILITY FOR THE USE OF THIS SOFTWARE. This notice including this -# sentence must appear on any copies of this computer software. -# -# EXPORT CONTROL -# User agrees that the Software will not be shipped, transferred or -# exported into any country or used in any manner prohibited by the -# United States Export Administration Act or any other applicable -# export laws, restrictions or regulations (collectively the "Export Laws"). -# Export of the Software may require some form of license or other -# authority from the U.S. Government, and failure to obtain such -# export control license may result in criminal liability under -# U.S. laws. In addition, if the Software is identified as export controlled -# items under the Export Laws, User represents and warrants that User -# is not a citizen, or otherwise located within, an embargoed nation -# (including without limitation Iran, Syria, Sudan, Cuba, and North Korea) -# and that User is not otherwise prohibited -# under the Export Laws from receiving the Software. -# -# Copyright 2011 Battelle Memorial Institute. All Rights Reserved. -# Distributed as open-source under the terms of the Educational Community -# License version 2.0 (ECL 2.0). http://www.opensource.org/licenses/ecl2.php -# -# For further details, see: http://www.globalchange.umd.edu/models/gcam/ -# - -# diag_header.R -# -# An automated graphing system to generate both standard and user-defined maps -# of GCAM data. -# -# Ben Bond-Lamberty, November 2012 -# Last Modified: February, 2018 - -# ----------------------------------------------------------------------------- -# Default Projections (as PROJ4 strings) - -### Predefined PROJ4 projection strings -#' Proj4 string for default WGS84 (EPSG:4326) coordinate reference system -#' -#' String for specifying the default WGS84 projection in mapping functions -#' Its value is \code{'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'} -#' @export -wgs84 <- "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs" -#' Proj4 string for the Eckert III World projection -#' -#' String for specifying the Eckert III projection in mapping functions. -#' Its value is \code{'+proj=eck3'} -#' @export -eck3 <- "+proj=eck3" -#' Proj4 string for the Robinson World projection -#' -#' String for specifying the Robinson projection in mapping functions. -#' Its value is \code{'+proj=robin'} -#' @export -robin <- "+proj=robin" -#' Proj4 string for the Albers equal area projection over North America. -#' -#' String for specifying the Albers equal area projection over North -#' America in mapping functions. This is a conic projection situatied -#' over the continental United States. Its value is \code{'+proj=aea -#' +lat_1=20 +lat_2=60 +lat_0=40 +lon_0=-96 +x_0=0 +y_0=0 +ellps=GRS80 -#' +datum=NAD83'} -#' @export -na_aea <- "+proj=aea +lat_1=20 +lat_2=60 +lat_0=40 +lon_0=-96 +x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83" -#' Proj4 string for the Albers equal area projection over China -#' -#' String for specifying the Albers equal area projection over China -#' in mapping functions. This is a conic projection situatied over -#' China. Its value is \code{'+proj=aea +lat_1=20 +lat_2=60 +lat_0=40 -#' +lon_0=-96 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84'} -#' @export -ch_aea <- "+proj=aea +lat_1=27 +lat_2=45 +x_0=0 +y_0=0 +lat_0=35 +lon_0=105 +ellps=WGS84 +datum=WGS84" -#' Proj4 string for orthographic projection over Africa -#' -#' String for specifying the orthographic projection over Africa. You can pass -#' this value to the \code{proj} argument of \code{\link{plot_GCAM}} to get the -#' best result. -#' @export -af_ortho <- "+proj=ortho +lat_0=10 +lon_0=19 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs" - - -# ----------------------------------------------------------------------------- -# EXTENT -# (lon0,lon1,lat0,lat1) - -#' Extent vector for the entire world -#' -#' This vector can be used as the \code{extent} argument to -#' \code{\link{plot_GCAM}}. -#' @export -EXTENT_WORLD <- c(-180,180,-90,90) -#' Extent vector for the continental United States -#' -#' This vector can be used as the \code{extent} argument to -#' \code{\link{plot_GCAM}}. -#' @export -EXTENT_USA <- c(-120,-71,20,55) -#' Extent vector for China -#' -#' This vector can be used as the \code{extent} argument to -#' \code{\link{plot_GCAM}}. -#' @export -EXTENT_CHINA <- c(77,130,15,53) -#' Extent vector for Africa -#' -#' This vector can be used as the \code{extent} argument to -#' \code{\link{plot_GCAM}}. -#' @export -EXTENT_AFRICA <- c(-20,60,-40,40) -#' Extent vector for Latin America -#' -#' This vector can be used as the \code{extent} argument to -#' \code{\link{plot_GCAM}}. -#' @export -EXTENT_LA <- c(-118,-33,-56,37) - - -# ----------------------------------------------------------------------------- -# AESTHETICS - -# Default Colors -LINE_COLOR <- "#444444" -FILL_COLOR <- "#222222" -BORDER_LIGHT <- alpha("#aaaaaa", 0.5) -BORDER_DARK <- alpha("#000000", 0.5) -MAP_BACKGROUND <- "#ddefff" - -# Background -PANEL_FILL <- "#eeeeee" -PANEL_GRID <- ggplot2::element_line(colour = "black") -AXIS_TICKS <- ggplot2::element_blank() -AXIS_TEXT <- ggplot2::element_blank() -XLAB <- "" -YLAB <- "" - - -# Legend -LEGEND_POSITION = "bottom" - -#' Color palette for 14-region GCAM -#' -#' This palette should be used for plots by region (whether maps, line plots, or -#' other types) to ensure consistency across plots and publications. XXX: -#' Perhaps this sort of thing should go in a separate GCAM style package, since -#' it isn't really specific to mapping? -#' @export -gcam14_colors<- c("Africa" = "navajowhite3", - "Australia_NZ" = "lightpink", - "India" = "lightslateblue", - "USA" = "sandybrown", - "Japan" = "rosybrown1", - "Korea" = "brown", - "Eastern Europe" = "orange" , - "Western Europe" = "greenyellow", - "Canada" = "saddlebrown", - "China" = "lightblue", - "Southeast Asia" = "gold", - "Latin America" = "seagreen2", - "Middle East" = "indianred", - "Former Soviet Union" = "plum2") - - -rgb255 <- function(r, g, b) {grDevices::rgb(r,g,b, maxColorValue=255)} -#' Color palette for 32-region GCAM -#' -#' This palette should be used for plots by region (whether maps, line plots, or -#' other types) to ensure consistency across plots and publications. -#' @export -gcam32_colors <- c( - 'Africa_Northern' = rgb255(139,69,19), - 'Africa_Eastern' = rgb255(139,115,88), - 'Africa_Southern' = rgb255(255,211,155), - 'Africa_Western' = rgb255(255,185,15), - 'South Africa' = rgb255(255,215,0), - - 'Canada' = rgb255(224,238,224), - 'USA' = rgb255(77,77,77), - - 'Argentina' = rgb255(0,100,0), - 'Brazil' = rgb255(154,205,50), - 'Central America and Caribbean' = rgb255(46,139,87), - 'Colombia' = rgb255(102,205,170), - 'Mexico' = rgb255(50,205,50), - 'South America_Southern' = rgb255(72,209,204), - 'South America_Northern' = rgb255(0,255,0), - - 'EU-12' = rgb255(25,25,112), - 'EU-15' = rgb255(131,111,255), - 'Europe_Eastern' = rgb255(173,216,230), - 'Europe_Non_EU' = rgb255(0,104,139), - 'European Free Trade Association' = rgb255(58,95,205), - - 'Russia' = rgb255(104,34,139), - 'China' = rgb255(255,0,0), - 'Middle East' = rgb255(188,143,143), - 'Australia_NZ' = rgb255(255,193,193), - 'Central Asia' = rgb255(139,0,0), - 'India' = rgb255(208,32,144), - 'Indonesia' = rgb255(139, 28, 98), - 'Japan' = hsv(0.01, 0.75, 0.65), - 'Pakistan' = rgb255(205, 181, 205), - 'South Asia' = rgb255(139, 123, 139), - 'South Korea' = rgb255(205, 92, 92), - 'Southeast Asia' = rgb255(240, 128, 128), - 'Taiwan' = rgb255(150, 150, 150) -) diff --git a/R/error_checking.R b/R/error_checking.R new file mode 100644 index 0000000..260faf5 --- /dev/null +++ b/R/error_checking.R @@ -0,0 +1,449 @@ +#' Error checking functions for maps package + + +#' Verify shape data +#' +#' This function runs a check on shape inputs and looks for errors +#' +#' @param shape_data (SF, SP, or Character) - Either the full path string to a shape file (with included necessary files) or an SF shape object +#' @param shape_key_field (Character) - Name of key field in shape object for merging with map_data object +#' @param shape_data_field (Character) - Optional field for utilizing a field within the shape data as the map data field. Negates the map_data variable +#' @param shape_label_field (Character) - Optional field for plotting data available from the shape attributes & fields (such as country name) +#' @param shape_label_size_field (Numeric) - Optional field used for computing shape label size dynamically (ie by area or amount etc.) +#' @param shape_xy_fields (c(Character, Character)) - Vector that specifies the x and y field names in the shape object (default c("LAT", "LON")) +#' @param shape_geom_field (Character) - Specifies field within shape object that contains needed geometry (default "geometry") +#' @param simplify (Boolean) - Option to reduce the number or complexity of the polygons in the shape file (default FALSE) +#' @return (Character) - Returns either "Success" or an error string if failed +#' @importFrom sf st_crs +#' @importFrom raster crs +#' @author Jason Evanoff, jason.evanoff@pnnl.gov +#' @export +verify_shape <- function(shape_data, simplify = FALSE, shape_label_field = NULL, shape_data_field = NULL, shape_key_field = NULL, + shape_label_size = 1, shape_xy_fields = c("LAT", "LON"), shape_geom_field = "geometry") +{ + result <- "Success" + default_projection <- "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0" + + # Shape loading - if given a path, use that, else expect an object passed in + if(is.null(shape_data)) + { + return("Error: Shape data is NULL") + } + else if(suppressWarnings({"sf" %in% class(shape_data)})) + { + # Verify shape projection and assign default if NA or NULL + if(is.na(crs(shape_data)) || is.null(crs(shape_data))) + { + sf::st_crs(shape_data) <- crs(default_projection) + print("Applying default projection to shape (shape projection was NA or NULL)") + } + } + else if("character" %in% class(shape_data)) + { + if (!file.exists(shape_data)) + { + return(paste0("Error: Cannot open shape file - `", shape_data, "`` - or shape file path does not exist ")) + } + } + else + { + return("Error: Unrecognized `shape_data` argument.") + } + + # Verify shape_data_field + if(!is.null(shape_data_field)) + { + # Verify class + if(!"character" %in% class(shape_data_field)) + { + return("Error: `shape_data_field` argument must be a character string ") + } + # look for shape data field + if(!shape_data_field %in% names(shape_data)) + { + return(paste0("Error: `shape_data_field` `", shape_data_field, "`` does not exist in shape object.")) + } + } + + # Verify shape_label_field + if(!is.null(shape_label_field)) + { + # Verify class + if(!"character" %in% class(shape_label_field)) + { + return("Error: `shape_label_field` argument must be a character string ") + } + # look for shape data field + if(!shape_label_field %in% names(shape_data)) + { + return(paste0("Error: `shape_label_field` - `", shape_label_field, "` - does not exist in shape object.")) + } + } + + # Verify shape_key_field + if(!is.null(shape_key_field)) + { + # Verify class + if(!"character" %in% class(shape_key_field)) + { + return("Error: `shape_key_field` argument must be a character string ") + } + # look for shape key field + if(!shape_key_field %in% names(shape_data)) + { + return(paste0("Error: `shape_key_field` - `", shape_key_field, "` - does not exist in shape object.")) + } + } + + # Verify shape_label_size + if(!is.null(shape_label_size)) + { + if(!"numeric" %in% class(shape_label_size)) + { + return("Error: `shape_label_size` argument must be numeric ") + } + if(shape_label_size <=0 || shape_label_size > 10) + { + return("Error: `shape_label_size` argument must be be > 0 amd < 10 ") + } + } + + if(!simplify %in% c(TRUE, FALSE)) + { + return("Error: Invalid value for `simplify` argument: Must be one of TRUE, FALSE") + } + + if(!shape_geom_field %in% names(shape_data)) + { + return(paste0("Error: `shape_geom_field` - `", shape_geom_field, "` - does not exist in shape object.")) + } + + return(result) + +} + + +#' Verify raster data +#' +#' This function runs a check on raster inputs and looks for errors, missing projection, or missing key fields +#' +#' @param raster_data (Raster or Character) - Either the full path string to raster file or a raster object +#' @param raster_col (Character) - Column name that contains the raster object's output variable +#' @param raster_band (Numeric) - Future variable for dealing with multi band or time series rasters etc (default 1) +#' @param bin_method (Character) - Method or function to use to split continuous data into discrete chunks (default "pretty") +#' @param bins (Numeric) - Number of bins in which to divide the raster (default 8) +#' @param convert_zero (Boolean) - Convert raster zero values to NA (default FALSE) +#' @return (Character) - Returns either "Success" or an error string if failed +#' @importFrom raster crs +#' @author Jason Evanoff, jason.evanoff@pnnl.gov +verify_raster <- function(raster_data = NULL, raster_col = NULL, raster_band = 1, bin_method = "pretty", bins = 8, convert_zero = FALSE) +{ + result <- "Success" + + # Raster loading - if given a path, use that, else expect an object passed in + if(is.null(raster_data)) + { + return("Error: Raster data is NULL") + } + else if("RasterLayer" %in% class(raster_data)) + { + raster_obj <- raster_data + } + else if("character" %in% class(raster_data)) + { + if (!file.exists(raster_data)) + { + return(paste0("Error: Cannot process raster file `", raster_data, "`\nRaster file does not exist or raster path is malformed.")) + } + } + else + { + return("Error: Unrecognized raster_data argument. Raster_data must be of type RasterLayer or a path to a raster file.") + } + + # Check raster_col argument to make sure it exists + if(is.null(raster_col)) + { + return("Error: No raster column defined") + } + + # Check raster CRS and assign default if NA + if(is.na(crs(raster_obj)) || is.null(crs(raster_obj))) + { + return("Error: Raster is missing projection. Please assign a projection to raster before mapping.") + } + + return(result) +} + + +#' Verify map data +#' +#' This function runs a check on map data inputs and looks for errors +#' +#' @param map_data (Data Frame or Character) - A data frame that contains the output data to map, or alternatively a full path to a CSV +#' @param data_key_field (Character) - Name of key field in data_obj for merging with shape_data +#' @param data_col (Character) - Column name that contains the data object's output variable +#' @param shape_obj (SF) - An SF object +#' @param shape_key_field (Character) - Name of key field in shape object for merging with map_data object +#' @param shape_data_field (Character) - Optional field for utilizing a field within the shape data as the map data field. Negates the map_data variable +#' @return (Character) - Returns either "Success" or an error string if failed +#' @author Jason Evanoff, jason.evanoff@pnnl.gov +verify_data <- function(map_data = NULL, data_key_field = NULL, data_col = NULL, shape_obj = NULL, shape_data_field = NULL, shape_key_field = NULL) +{ + result <- "Success" + + # Check column arguments are not duplicative + if(!is.null(shape_data_field)) + { + if(!is.null(data_col)) + { + return_error("Error: Both of the `shape_data_field` and `data_col` arguments cannot have a value (you may use only one)", "Duplicate arguments") + return("Error - see console for output") + } + if(!is.null(data_key_field)) + { + return_error("Error: Both of the `shape_data_field` and `data_key_field` arguments cannot have a value (you may use only one)", "Duplicate arguments") + return("Error - see console for output") + } + } + + # Check data arguments are not duplicative + if(is.null(map_data) && is.null(shape_data_field)) + { + return("Error: both `map_data` and `shape_data_field` cannot be NULL") + } + + # Map Data - if given a path to a csv, use that, else expect a data.frame object passed in + if(!class(map_data) %in% c("data.frame", "character") && is.null(shape_data_field)) + { + return("Error: `map_data` argument must be of type data.frame or a character path to a csv file") + } + + # Verify shape_data_field if not NULL + if(!is.null(shape_data_field)) + { + if(!"character" %in% class(shape_data_field)) + return(paste0("Error: `shape_data_field` argument must be of type character")) + if(!shape_data_field %in% colnames(shape_obj)) + return(paste0("Error: `shape_data_field` - `", shape_data_field, "` - was not found in the `shape_obj` argument")) + } + + # Verify data_key_field if not NULL + if(!is.null(data_key_field)) + { + if(!"character" %in% class(data_key_field)) + return(paste0("Error: `data_key_field` argument must be of type character")) + if(!data_key_field %in% colnames(map_data)) + return(paste0("Error: `data_key_field` - `", data_key_field, "` - was not found in the `map_data` data frame")) + } + + # Verify data_col + if(!is.null(data_col)) + { + if(!"character" %in% class(data_col)) + return("Error: `data_col` argument must be of type character") + if(!data_col %in% colnames(map_data)) + return(paste0("Error: `data_col` - `", data_col, "` - was not found in the `map_data` data frame")) + } + + return(result) +} + + +#' Verify map parameters +#' +#' Verify the set of arguments for choropleth and other map types +#' +#' @param bin_method (Character) - Method or function to use to split continuous data into discrete chunks (one of "quantile", "equal", "pretty", "kmeans") (default "pretty") +#' @param bins (Numeric) - Number of bins in which to divide the raster +#' @param dpi (Numeric) - Settable DPI for different print and screen formats (default 150) +#' @param expand_xy (c(Numeric, Numeric)) - Sets expansion amount for the X and Y scale of the map - Vector (expand x, expand y) (default c(0,0)) +#' @param map_xy_min_max (c(Numeric, ...)) - Vector that describes the desired extent of the map in the form of (xmin, xmax, ymin, ymax) (default: c(-180, 180, -90, 90)) +#' @param map_title (Character) - Title to be displayed on the output map +#' @param map_palette (Character) - Optional variable to manually set the colorscale to a specific palette from RColorbrewer +#' @param map_palette_reverse (Boolean) - Set palette to reverse direction - TRUE or FALSE +#' @param map_width_height_in (c(Numeric, Numeric)) - Vector that describes the desired file size of the output image in the form of (width, height) in inches (default c(15, 10)) +#' @param map_legend_title (Character) - Text for the legend header +#' @param map_x_label (Character) - Label for x axis (default Lon) +#' @param map_y_label (Character) - Label for y axis (default Lat) +#' @param map_font_adjust (Numeric) - A number between 0.2 and 2 that scales the map fonts either up or down (0.2 = 80% smaller, 2 = 200% bigger) +#' @return (Character) - Returns either "Success" or an error string if failed +#' @import RColorBrewer +#' @author Jason Evanoff, jason.evanoff@pnnl.gov +verify_map_params <- function(bin_method = "pretty", bins = 8, dpi = 150, expand_xy = c(0,0), map_xy_min_max = c(-180, 180, -90, 90), map_title = "", + map_palette = NULL, map_palette_reverse = FALSE, map_palette_type = "seq", map_width_height_in = c(15, 10), map_legend_title = "", + map_x_label = "Lon", map_y_label = "Lat", map_font_adjust = 1.0) +{ + output <- "Success" + + # Verify bin_method + if(is.null(bin_method) || !"character" %in% class(bin_method) || !bin_method %in% c("quantile", "pretty", "equal")) + { + return("Error: `bin_method` argument must be one of 'quantile', 'pretty', 'equal'") + } + + # Verify bins + if(is.null(bins) || class(bins) != "numeric") + { + return("Error: `bins` argument must be a positive integer and not NULL") + } + if(bins < 1 || bins > 100) + { + return("Error: `bins` argument must be a valid integer between 1-100") + } + + # verify dpi + if(!"numeric" %in% (class(dpi)) || dpi < 30 || dpi > 300) + { + return("Error: `dpi` argument must be a numeric value between 30 and 300") + } + + # Verify expand_xy + if(!"numeric" %in% (class(expand_xy)) || length(expand_xy) != 2) + { + return("Error: `expand_xy` argument must be a numeric vector of length 2") + } + + # Verify map_xy_min_max + if(!"numeric" %in% (class(map_xy_min_max)) || length(map_xy_min_max) != 4) + { + return("Error: `map_xy_min_max` argument must be a numeric vector of length 4") + } + + # Verify title + if(!"character" %in% class(map_title) && !is.null(map_title)) + { + return("Error: `map_title` must be of class character") + } + + # Verify map_palette + if(!is.null(map_palette) && (!"character" %in% class(map_palette) || !map_palette %in% row.names(brewer.pal.info)) ) + { + return("Error: `map_palette` must be of class character and a valid entry in the RColorBrewer palette (see brewer.pal.info") + } + + # Verify palette_reverse + if(!"logical" %in% class(map_palette_reverse)) + { + return("Error: `map_palette_reverse` must be of type logical (TRUE or FALSE)") + } + + # Verify map_width_height_in + if(!"numeric" %in% (class(map_width_height_in)) || length(map_width_height_in) != 2) + { + return("Error: `map_width_height_in` argument must be a numeric vector of length 2") + } + + # Verify map_legend_title + if(!"character" %in% class(map_legend_title) && !is.null(map_legend_title)) + { + return("Error: `map_legend_title` must be of class character or NULL") + } + + # Verify map_x_label + if(!"character" %in% class(map_x_label) && !is.null(map_x_label)) + { + return("Error: `map_x_label` must be of class character or NULL") + } + + # Verify map_y_label + if(!"character" %in% class(map_y_label) && !is.null(map_y_label)) + { + return("Error: `map_y_label` must be of class character or NULL") + } + + # Verify map_font_adjust + if(!"numeric" %in% class(map_font_adjust) && !is.null(map_font_adjust)) + { + return("Error: `map_font_adjust` must be of class numeric and not NULL") + } + if(map_font_adjust > 2 || map_font_adjust < 0.2) + { + return("Error: `map_font_adjust` must be between 0.2 and 2.0") + } + + return(output) +} + +#' Verify simplify +#' +#' This function does simple verification for the simplify_mapdata function +#' +#' @param mapdata (sf) object containing polygons or multipolygons to simplify. +#' @param min_area (Numeric) Minimum area of polygons to keep. +#' @param degree_tolerance (Numeric) Tolerance parameter for simplifying polygons. +#' @return (Character) - Returns a success token or an error string if failed +#' @export +verify_simplify_mapdata <- function(map_data = NULL, min_area = 2.5, degree_tolerance = 0.1) +{ + result <- "Success" + + # Verify map_data + if(is.null(map_data)) + { + return("Error: `map_data` argument must not be NULL") + } + if(suppressWarnings({!"sf" %in% class(map_data)})) + { + return("Error: `map_data` argument must be of type sf") + } + + # Verify min_area + if(is.null(min_area) || class(min_area) != "numeric") + { + return("Error: `min_area` argument must be a positive number and not NULL") + } + if(min_area <= 0) + { + return("Error: `min_area` argument must be a non-zero positive number") + } + + # verify degree_tolerance + if(is.null(degree_tolerance) || class(degree_tolerance) != "numeric") + { + return("Error: `degree_tolerance` argument must be a non NULL numeric value") + } + + return(result) + +} + + + +#' Verify csv data +#' +#' This function runs a check on csv data inputs and looks for errors +#' +#' @param mapdata sf object containing polygons or multipolygons to simplify. +#' @param min_area Minimum area of polygons to keep. +#' @param degree_tolerance Tolerance parameter for simplifying polygons. +#' @return (Character) - Returns a success token or an error string if failed +verify_csv <- function(map_data) +{ + + + result <- "Success" + + return(result) + +} + + + +#' Return and output errors +#' +#' This function prints out any caught errors to the console and returns the custom error string to the calling function +#' +#' @param error (Character) - Specific error string for output +#' @param location (Character) - Location the error was caught +#' @return (Character) - Prints the error to console and also returns it to caller +#' @author Jason Evanoff, jason.evanoff@pnnl.gov +#' @export +return_error <- function(error, location) +{ + print(paste0("There was an error at - `", location, "` - building your map:")) + print(error) + + return(error) +} diff --git a/R/gcam_data_processing.R b/R/gcam_data_processing.R deleted file mode 100644 index d33e4fe..0000000 --- a/R/gcam_data_processing.R +++ /dev/null @@ -1,155 +0,0 @@ -# gcam_data_processing.R -# -# Contains function for transforming GCAM data into a format for easy mapping. - -### TODO - modify to search for appropriate lookup, province, drop files in directory. -#' Match GCAM ID to region using data from a lookup table. -#' -#' We match by ID number to avoid problems with variant spellings and the like. -#' With the optional arguments you can also omit regions for which you don't -#' want to plot the data for some reason, and you can translate the -#' abbreviations used in subregion output. -#' -#' The \code{provincefile} and \code{drops} arguments are a little clunky. They -#' are optional, but if you are using one of the built-in map sets, then you -#' \emph{must not} specify them if they don't exist for the map set you are -#' using. Currently, \code{rgn14} and \code{basin235} have neither drops nor -#' province abbreviations. The \code{rgn32} set has drops, but not province -#' abbreviations. Only the \code{chn} set has both. -#' @param datatable A table of results produced by \code{\link[rgcam]{getQuery}} -#' @param lookupfile Name of one of the predefined map sets, OR, if you're using -#' a custom map set, the file containing the region lookup table -#' @param provincefile Name of one of the predefined map sets, OR, if you're -#' using a custom map set, file containing the province lookup table, if -#' applicable. -#' @param drops Name of one of the predefined map sets, OR, if you're using -#' a custom map set, the file containing a list of regions to drop, if -#' applicable. -#' @param disaggregate A column (or vector of columns) of \code{datatable} used -#' to disaggregate regions that are not specified in the original data. -#' @return Input table modified to include a GCAM ID for reach region. -#' @importFrom utils read.csv -#' @export -add_region_ID <- function(datatable, lookupfile = rgn32, provincefile = NULL, drops = NULL, disaggregate = NULL) { - - . <- NULL # silence package notes for NSE - naReg <- "#N/A" - - # Make sure there is a region column in the data. "Region" is okay, but will - # be replaced with "region". - names(datatable)[names(datatable) == "Region"] <- "region" - if (!"region" %in% names(datatable)) { - stop("Data must contain a 'region' column") - } - - if ("id" %in% names(datatable)) { - message("id column is already present and will not be modified") - return(datatable) - } - - if (!is.null(provincefile)) { - datatable <- translate_province(datatable, provincefile) - } - - if (!is.null(drops)) { - datatable <- drop_regions(datatable, drops) - } - - lookuptable <- if (is.symbol(lookupfile)) { - get.internal(lookupfile, "lut") - } else { - read.csv(lookupfile, strip.white = T, stringsAsFactors = F) - } - - # Add row to end of the lookup table to account for GCAM region 0 - if (!any(lookuptable$region == naReg)) { - lookuptable <- rbind(lookuptable, c(naReg, 0)) - } - - # If the user specifies columns to disaggregate, each unique combination of - # those columns needs to be disaggregated to contain every region. - # Grouping and then using dplyr's do() function joins the lookuptable to - # each group, with NA values in all columns except for region and region id - # (and the disaggregation columns filled in after). - if (!is.null(disaggregate)) { - finaltable <- datatable %>% - dplyr::group_by_at(dplyr::vars(disaggregate)) %>% - dplyr::do({ - grp <- dplyr::full_join(., lookuptable, by = "region") - grp[ , disaggregate] <- grp[1, disaggregate] - grp - }) - } else { - finaltable <- dplyr::full_join(datatable, lookuptable, by = "region") - if (any(duplicated(finaltable$region))) { - warning("Data contains multiple values for the same region") - } - } - - # Set column name and type for id column - names(finaltable)[ncol(finaltable)] <- "id" - finaltable$id <- as.numeric(finaltable$id) - - return(finaltable) -} - -#' Replace subregion abbreviations with full subregion names -#' -#' Subregions are given two-letter abbreviations in GCAM output. This function -#' uses a lookup table to restore the full names. -#' -#' @param datatable The table with the abbreviated names in it. -#' @param provincefile Name of a defined mapset OR name of a file containing the -#' lookup table. -#' @importFrom utils read.csv -translate_province <- function(datatable, provincefile) { - - if (is.symbol(provincefile)) { - provincetable <- get.internal(provincefile, "prov") - } - else { - provincetable <- read.csv(provincefile, strip.white = T, stringsAsFactors = T) - } - - datatable <- datatable %>% - dplyr::left_join(provincetable, by = c("region" = "province")) %>% - dplyr::mutate(region = dplyr::if_else(is.na(province.name), region, province.name)) %>% - dplyr::select(-province.name) - - return(datatable) -} - -#' Drop regions listed in drops file from data frame. -#' -#' @param datatable A data frame containing the output of a GCAM query. -#' @param drops String; path to file containing regions to be dropped -#' @return An updated data frame with regions dropped. -drop_regions <- function(datatable, drops) { - - if (is.symbol(drops)) { - dr <- get.internal(drops, "drop") - } - else { - dr <- read.csv(drops, strip.white = T, stringsAsFactors = F) - } - - datatable <- dplyr::filter(datatable, !region %in% dr[[1]]) - - return(datatable) -} - - -#' Get auxiliary data for a named mapset. -#' -#' We have several standard map sets. Each of them has several auxiliary tables -#' associated with it. This function retrieves the auxiliary table associated -#' with the requested. Right now this function understands \code{rgn14}, -#' \code{rgn32}, \code{basin235}, and \code{chn}. -#' -#' @param mapset The name of the mapset. Can be either a symbol or a string. -#' @param type The type of table. Right now this is either 'lut', 'drop', or -#' 'prov' -get.internal <- function(mapset, type) { - eval(as.symbol(paste(type, mapset, sep = "."))) -} - diff --git a/R/gcammaptools.R b/R/gcammaptools.R deleted file mode 100644 index 22ef6d4..0000000 --- a/R/gcammaptools.R +++ /dev/null @@ -1,120 +0,0 @@ -#' gcammaptools: A package for plotting GCAM data on maps -#' -#' The gcammaptools package provides functions for plotting GCAM data on world -#' or regional maps. This includes functions for making plots for regional or -#' gridded data, as well as default projection and theme settings that provide a -#' house style for GCAM plots. -#' -#' @section Preparing GCAM data: -#' -#' The recommended way to load your GCAM data is by using the \code{rgcam} -#' package create a project data file from a GCAM database, and then querying -#' that file for the data you want to plot. Alternatively, you can start with -#' any data frame that has a `region` column and one or more data columns. -#' -#' Once you have loaded the data, you must add the region identifiers used in -#' the map data to the data frame using the \code{add_region_ID} function. -#' -#' @section Mapping GCAM data: -#' -#' To map GCAM data, you will need a simple feature collection or geojson with -#' your region boundaries. The package provides the following commonly-used -#' base maps: -#' \itemize{ -#' \item \code{\link{map.rgn14}}: 14 region map used prior to GCAM 4.0. -#' \item \code{\link{map.rgn32}}: 32 region map used in GCAM 4.0 and later, -#' excluding Taiwan. -#' \item \code{\link{map.basin235}}: 235 water basins. -#' \item \code{\link{map.chn}}: 32 global regions plus China subregions -#' \item \code{\link{map.usa}}: 32 global regions plus US states. -#' } -#' Users can provide their own base maps. You will need a geometry file in -#' geojson format, where each region has a \code{region_id}. Land masses -#' that you want to draw, but which aren't part of any region should be included -#' and assigned a \code{region_id} of 0. The \code{examples} vignette shows how -#' to load such a file and convert it for use in this package. -#' -#' Once you have your map data and your GCAM data, can generate the maps by -#' passing both to the \code{\link{plot_GCAM}} function. -#' -#' @docType package -#' @name gcammaptools -#' @import ggplot2 -#' @importFrom magrittr %>% -NULL - -#' Base map for 14-region GCAM -#' -#' This is the region map used in versions of GCAM prior to GCAM 4.0. It is -#' largely obsolete, but there are still some data from those days floating -#' around in the wild -#' -#' @format Simple feature collection -"map.rgn14" - -#' Simplified base map for 14-region GCAM -#' -#' The same map as \code{map.rgn14} but with only Polygons that have an area -#' greater than 2.5 square degrees and simplified Polygon borders. -#' -#' @format Simple feature collection -"map.rgn14.simple" - -#' Base map for 32-region GCAM -#' -#' This is the region map used in GCAM 4.0 and subsequent. This version of the -#' map does not include the Taiwan region. -#' -#' @format Simple feature collection -"map.rgn32" - -#' Simplified base map for 32-region GCAM -#' -#' The same map as \code{map.rgn32} but with only Polygons that have an area -#' greater than 2.5 square degrees and simplified Polygon borders. -#' -#' @format Simple feature collection -"map.rgn32.simple" - -#' Base map for 235 global water basins -#' -#' This is the map of the 235 global water basins. For compatibility with the -#' other map data frames it refers to the basins as 'regions'. Thus, any GCAM -#' data with a 'basin' column will need to have a 'region' column added. There -#' is also some variability in how the basin names are represented, so this data -#' set will need some work. -#' -#' @format Simple feature collection -"map.basin235" - -#' Simplified base map for 235 global water basins -#' -#' The same map as \code{map.basin235} but with only Polygons that have an area -#' greater than 2.5 square degrees and simplified Polygon borders. -#' -#' @format Simple feature collection -"map.basin235.simple" - -#' Base map for 32-region GCAM with China subregions -#' -#' This map has the 32 GCAM regions, plus the subregions corresponding to -#' China's provinces, municipalities, autonomous regions, and SARs. -#' -#' @format Simple feature collection -"map.chn" - -#' Base map for 32-region GCAM with USA states -#' -#' This map has the 32 GCAM regions, plus the subregions corresponding to -#' US states including the District of Columbia. -#' -#' @format Simple feature collection -"map.usa" - -#' Base map for gridded data over national borders -#' -#' This map has the administrative borders of the world's countries. It is meant -#' for use with gridded data only, as no GCAM output matches country boundaries. -#' -#' @format Simple feature collection -"map.countries" diff --git a/R/maps.R b/R/maps.R new file mode 100644 index 0000000..4b8dded --- /dev/null +++ b/R/maps.R @@ -0,0 +1,580 @@ +# output.r +# +# This file produces dynamic maps from standardized functions + +#' Create a basic map object from input shape and-or raster. +#' +#' This function is designed to take both a shape and raster object or path and create a standardized output map. Option to save the output to file +#' +#' @param shape_data (SF, SP, or Character) - Either the full path string to a shape file (with all necessary files) or an SF shape object +#' @param raster_data (Raster or Character) - Either the full path string to a raster file or an object of type RasterLayer +#' @param raster_col (Character) - Raster field name that contains the desired output variable +#' @param shape_label_field (Character) - Optional field for plotting map labels from the shape attributes (such as country name) +#' @param shape_label_size_field (Character) - Optional field used for computing shape label size dynamically (ie by area or amount etc.) (Default "1") +#' @param simplify (Boolean) - Option to reduce the number or complexity of the polygons in the shape file (default FALSE) +#' @param raster_band (Numeric) - Variable for dealing with multi band or time series rasters that specifices which raster band to use (Default 1) +#' @param convert_zero (Boolean) - Convert values within the raster data from zero to NA (default FALSE) +#' @param dpi (Numeric) - Settable DPI for different print and screen formats (default 150) +#' @param output_file (Character) - Output file path and file name and type to save the resulting plot (e.g. "c:/temp/output.png") (Types accepted: "eps", "ps", "tex", "pdf", "jpeg", "tiff", "png", "bmp", "svg") +#' @param expand_xy (c(Numeric, Numeric)) - Sets expansion amount for the X and Y scales of the map - Vector (expand x, expand y) (default c(0,0)) +#' @param map_xy_min_max (c(Numeric, ...)) - Vector that describes the desired extent of the map in the form of (xmin, xmax, ymin, ymax) (default: c(-180, 180, -90, 90)) +#' @param map_title (Character) - Title to be displayed at the top of the output map +#' @param map_palette (Character) - Variable to hold the type of colorscale to be used from the RColorBrewer palette (default "RdYlBu") +#' @param map_palette_reverse (Boolean) - Set palette to reverse direction TRUE or FALSE +#' @param map_width_height_in (c(Numeric, Numeric)) - Vector that describes the desired file size of the output image in the form of (width, height) in inches (defalt c(15, 10)) +#' @param map_legend_title (Character) - Text variable to be used for the legend header +#' @param map_x_label (Character) - Label for x axis (default "Lon") +#' @param map_y_label (Character) - Label for y axis (default "Lat") +#' @return (ggplot2 or Character) - Returns a ggplot object of the resulting map or an error string if failed +#' @importFrom sf st_transform +#' @importFrom raster raster as.data.frame compareCRS minValue maxValue nlayers +#' @importFrom dplyr mutate +#' @importFrom ggplot2 scale_x_continuous scale_y_continuous scale_fill_distiller ggplot geom_raster geom_sf coord_sf labs theme geom_sf_label guides +#' @importFrom ggspatial layer_spatial df_spatial +#' @import RColorBrewer +#' @author Jason Evanoff, jason.evanoff@pnnl.gov +#' @export +custom_map <- function(shape_data = NULL, raster_data = NULL, raster_col = NULL, shape_label_field = NULL, shape_label_size = "1", + simplify = FALSE, raster_band = 1, convert_zero = FALSE, + dpi = 150, output_file = NULL, expand_xy = c(0, 0), + map_xy_min_max = c(-180, 180, -90, 90), map_title = NULL, map_palette = "RdYlBu", map_palette_reverse = FALSE, + map_width_height_in = c(15, 10), map_legend_title = NULL, map_x_label = "Longitude", map_y_label = "Latitude") +{ + error <- "" + output <- "Default error" + tryCatch( + { + result <- verify_shape(shape_data, simplify, shape_label_field) + + # If shape passes verification, load and process + if(result == "Success") + { + # Create shape object via local processing function + shape_obj <- process_shape(shape_data, simplify, shape_label_field) + } + else + { + # Verify shape failed, return result + return_error(result) + return("Error - see console for output") + } + + # Verify processed object is a shape object. If not, it's an error and return it + if(class(shape_obj) == "character") + { + return_error(paste0("Error: There was an error processing the shape object: ", shape_obj)) + return("Error - see console for output") + } + + # Create raster + raster_obj <- process_raster(raster_data , raster_col, raster_band, bin_method, bins, convert_zero) + + if(class(raster_obj) == "character") + { + return_error("Error: Raster argument is not of type RasterLayer") + return("Error - see console for output") + } + + + # Perform shape and raster comparisons or other operations + # Compare projections and equalize if necessary + if(!compareCRS(shape_obj, raster_obj)) + { + # Transform shape to match raster CRS + shape_obj <- st_transform(shape_obj, crs(raster_df)) + } + + # Raster operations + raster_df <- df_spatial(raster_obj) #raster_df <- as.data.frame(raster_obj, xy=TRUE) compare performance + raster_df <- mutate(raster_df, value = raster_df[[paste0("band", 1)]]) + + # Create mapping and output variables + # Raster stats and information + raster_min <- minValue(raster_obj) + raster_max <- maxValue(raster_obj) + raster_layers <- nlayers(raster_obj) + raster_active_band <- raster_band + + # Map output variables + x_min <- map_xy_min_max[1] + x_max <- map_xy_min_max[2] + y_min <- map_xy_min_max[3] + y_max <- map_xy_min_max[4] + map_width <- map_width_height_in[1] + map_height <- map_width_height_in[2] + expand_x <- expand_xy[1] + expand_y <- expand_xy[2] + + # Map colors and scales options + palette_direction <- 1 + + if(map_palette_reverse) + { + palette_direction <- -1 + } + + # Build map x and y scales using continuous scales + map_x_scale <- scale_x_continuous(limits=c(x_min, x_max), expand = expansion(add = expand_x), breaks=seq(x_min,x_max, abs(x_max - x_min)/12)) + map_y_scale <- scale_y_continuous(limits=c(y_min, y_max), expand = expansion(add = expand_y), breaks=seq(y_min,y_max, abs(y_max - y_min)/6)) + map_color_scale <- scale_fill_distiller(palette = map_palette, type = palette_type, direction = palette_direction, na.value = na_value, guide = map_guide) + map_shape_options <- NULL + map_size_guide_option <- NULL + + # Build geometry labels if enabled by user + if(!is.null(shape_label_field)) + { + map_shape_options <- geom_sf_label(data = shape_obj, aes_string(label = shape_label_field, fill=NULL, size = shape_label_size_field)) + if(!is.null(shape_label_size_field)) + { + map_size_guide_option <- guides(size = FALSE) + } + } + + # Build ggplot Map object + output <- ggplot() + geom_raster(data=raster_df, aes(x=x, y=y, fill=value), alpha = 1.0) + + geom_sf(data = shape_obj, na.rm = TRUE, fill=NA) + + map_color_scale + + coord_sf() + + labs(x=map_x_label, y=map_y_label, title = map_title, fill = map_legend_title) + + map_x_scale + + map_y_scale + + map_shape_options + + theme(plot.title = element_text(hjust = 0.5)) + + map_size_guide_option + + # Save File + if(!is.null(output_file)) + { + result <- gcammaptools::save_plot(output_file, dpi, map_width, map_height) + if(result != "Success") + { + return_error(result) + } + } + }, + error = function(err) + { + # error handler picks up error information + error <- err + return_error(error) + return("Error - see console for output") + }) + + return(output) +} + + +#' Dynamic choropleth map creation +#' +#' Create a choropleth map object from shape and data object and return, save (optional) the output +#' +#' @param shape_data (SF or Character) - Either the full path string to a shape file (with all necessary files) or an SF shape object +#' @param map_data (Data Frame or Character) - A data frame that contains the output data to map, or alternatively a full path to a CSV +#' @param data_col (Character) - Column name that contains the data object's output variable +#' @param data_key_field (Character) - Name of key field in data_obj for merging with shape_data +#' @param shape_key_field (Character) - Name of key field in shape object for merging with map_data object +#' @param shape_data_field (Character) - Optional field for utilizing a field within the shape data as the map data field. Negates the map_data variable +#' @param shape_geom_field (Character) - Specifies field within shape object that contains needed geometry (default "geometry") +#' @param output_file (Character) - Output file path and file name and type to save the resulting plot (e.g. "c:/temp/output.png") (Types accepted: "eps", "ps", "tex", "pdf", "jpeg", "tiff", "png", "bmp", "svg") +#' @param map_title (Character) - Title to be displayed at the top of the output map +#' @param simplify (Boolean) - Option to reduce the number and complexity of the polygons in the shape file (default FALSE) +#' @param bin_method (Character) - Method or function to use to split continuous data into discrete chunks (one of "quantile", "equal", "pretty", "kmeans") (default "pretty") +#' @param bins (Numeric) - Number of bins, or segments, in which to divide the raster (default 8) +#' @param map_legend_title (Character) - Text variable to be used for the legend header +#' @param map_palette_type (Character) - Variable to load default palette by type of data ("qual" for qualitative data, "seq" for sequential data, "div" for divergent data) (default "seq") +#' @param map_palette (Character) - Variable to hold the type of colorscale to be used from the RColorBrewer palette (default "RdYlBu") +#' @param map_palette_reverse (Boolean) - Set palette to reverse direction TRUE or FALSE +#' @param shape_label_field (Character) - Optional field for plotting map labels from the shape attributes (such as country name) +#' @param shape_label_size_field (Character) - Optional field used for computing shape label size dynamically (ie by area or amount etc.) (Default "1") +#' @param shape_xy_fields (c(Character, Character)) - Vector that specifies the x and y field names in the shape object (default c("LAT", "LON")) +#' @param map_width_height_in (c(Numeric, Numeric)) - Vector that describes the desired file size of the output image in the form of (width, height) in inches (defalt c(15, 10)) +#' @param dpi (Numeric) - Settable DPI for different print and screen formats (default 150) +#' @param expand_xy (c(Numeric, Numeric)) - Sets expansion or buffer amount for the X and Y scales of the map - Vector (expand x, expand y) (default c(0,0)) +#' @param map_xy_min_max (c(Numeric, ...)) - Vector that describes the desired extent of the map in the form of (xmin, xmax, ymin, ymax) (default: c(-180, 180, -90, 90)) +#' @param map_x_label (Character) - Label for x axis (default "Lon") +#' @param map_y_label (Character) - Label for y axis (default "Lat") +#' @param map_font_adjust (Numeric) - A number between 0.2 and 2 that scales the map fonts either up or down (0.2 = 80% smaller, 2 = 200% bigger) +#' @return (ggplot2 or Character) - Returns a ggplot object of the resulting map or an error string if failed +#' @importFrom sf st_transform st_crs +#' @importFrom dplyr mutate left_join +#' @importFrom ggplot2 scale_x_discrete scale_y_discrete scale_fill_distiller ggplot geom_raster geom_sf coord_sf labs theme geom_sf_label geom_sf_text theme_minimal expand_scale scale_fill_brewer aes_string element_text rel theme_update geom_text +#' @importFrom ggspatial layer_spatial df_spatial +#' @importFrom classInt classIntervals +#' @import RColorBrewer +#' @author Jason Evanoff, jason.evanoff@pnnl.gov +#' @export +choropleth <- function(shape_data = NULL, map_data = NULL, data_col = NULL, data_key_field = NULL, shape_key_field = NULL, output_file = NULL, + map_title = NULL, shape_data_field = NULL, shape_geom_field = "geometry", simplify = FALSE, + bin_method = "pretty", bins = 8, map_legend_title = "", map_palette_type = "seq", map_palette = NULL, + map_palette_reverse = FALSE, shape_label_field = NULL, shape_label_size = 3, + map_width_height_in = c(15, 10), shape_xy_fields = c("LON", "LAT"), dpi = 150, expand_xy = c(0, 0), + map_xy_min_max = c(-180, 180, -90, 90), map_x_label = "Lon", map_y_label = "Lat", map_font_adjust = 1.0) +{ + output <- "There was an unknown error while processing your map" + tryCatch( + { + + # ------- Shape processing + + # Create shape object via local processing function + shape_obj <- process_shape(shape_data, simplify, shape_label_field, shape_data_field, shape_key_field, shape_label_size, shape_xy_fields, shape_geom_field) + if(suppressWarnings({!"sf" %in% class(shape_obj)})) + { + # Verification failed, return result + return_error(paste0("Error: There was an error processing the shape object: `", shape_obj, "`"), "Process Shape") + return("Error - see console for output") + } + + # ------- End shape processing + + # ------- Data processing + + # Read and process map data object via local processing function + map_data_obj <- process_data(map_data, data_key_field, data_col, shape_obj, shape_data_field, shape_key_field) + + if("character" %in% class(map_data_obj)) + { + # Process_data must have caught an error + return_error(map_data_obj, "Process Data") + return("Error - see console for output") + } + + if(is.null(shape_data_field)) + { + # Merge map and data + suppressWarnings({combined_df <- left_join(x = shape_obj, y = map_data_obj, by = setNames(data_key_field, shape_key_field))}) + } + else + { + suppressWarnings({combined_df <- base::as.data.frame(map_data_obj)}) + data_col <- shape_data_field + } + + # ------- End data processing + + # ------- Map data and options processing + + result <- verify_map_params(bin_method, bins, dpi, expand_xy, map_xy_min_max , map_title, map_palette, map_palette_reverse, + map_palette_type, map_width_height_in, map_legend_title, map_x_label, map_y_label, map_font_adjust) + + if(result != "Success") + { + return_error(result, "Verify Map Parameters") + return("Error - see console for output") + } + + # Map output variables + x_min <- map_xy_min_max[1] + x_max <- map_xy_min_max[2] + y_min <- map_xy_min_max[3] + y_max <- map_xy_min_max[4] + map_width <- map_width_height_in[1] + map_height <- map_width_height_in[2] + expand_x <- expand_xy[1] + expand_y <- expand_xy[2] + + # Determine palette direction + if(map_palette_reverse) + { + palette_direction <- -1 + } + else + { + palette_direction <- 1 + } + + # Determine palette type + if(map_palette_type == "qual") + { + palette_type <- "qual" + palette_colors <- "Paired" + } + else if(map_palette_type == "div") + { + palette_type <- "div" + palette_colors <- "RdYlBu" + } + else + { + palette_type <- "seq" + palette_colors <- "Blues" + } + + # Override palette if explicitly set in map_palette argument + if(!is.null(map_palette)) + { + palette_colors <- map_palette + } + + # Set additional map options and create scales + na_value <- "Grey" + map_guide <- "colourbar" + map_x_scale <- scale_x_discrete(limits=c(x_min, x_max), expand = expand_scale(add = expand_x), breaks=seq(x_min,x_max, abs(x_max - x_min)/12)) + map_y_scale <- scale_y_discrete(limits=c(y_min, y_max), expand = expand_scale(add = expand_y), breaks=seq(y_min,y_max, abs(y_max - y_min)/6)) + map_color_scale <- scale_fill_brewer(palette = palette_colors, type = palette_type, direction = palette_direction, na.value = na_value) + map_shape_options <- NULL + map_size_guide_option <- NULL + shape_x <- shape_xy_fields[1] + shape_y <- shape_xy_fields[2] + shape_geom <- shape_geom_field + + # Build geometry labels if enabled by user + if(!is.null(shape_label_field)) + { + map_shape_options <- geom_sf_text(data = shape_obj, size = shape_label_size, aes_string(label = shape_label_field, fill=NULL)) + if(!is.null(shape_label_size)) + { + map_size_guide_option <- guides(size = FALSE) + } + } + + # Process bins + if(!is.null(bin_method) && !is.null(bins)) + { + suppressWarnings({data_breaks <- classIntervals(c(min(as.numeric(combined_df[[data_col]])),as.numeric(combined_df[[data_col]])), n = bins, style = bin_method)}) + suppressWarnings({combined_df <- mutate(combined_df, value = cut(as.numeric(combined_df[[data_col]]), data_breaks$brks))}) + } + + # ------- End map data and options processing + + # Build ggplot Map object + suppressWarnings({output <- ggplot(data = combined_df, aes_string(x=shape_x, y=shape_y, fill="value", geometry=shape_geom)) + + geom_sf(color="gray42") + + map_color_scale + + coord_sf(xlim = c(x_min, x_max), ylim = c(y_min, y_max), expand = FALSE) + + labs(x=map_x_label, y=map_y_label, title = map_title, fill = map_legend_title) + + map_x_scale + + map_y_scale + + map_shape_options + + theme_minimal() + + theme(axis.text = element_text(size=rel(map_font_adjust)), + axis.title = element_text(size=rel(map_font_adjust))) + + theme(legend.text = element_text(size=rel(map_font_adjust))) + + theme(legend.title = element_text(size=rel(map_font_adjust))) + + # theme(text = element_text(size=rel(map_font_adjust))) + + theme(plot.title = element_text(hjust = 0.5, size=21)) + + map_size_guide_option }) + + # Save File + if(!is.null(output_file)) + { + result <- suppressWarnings({gcammaptools::save_plot(output_file, dpi, map_width, map_height)}) + if(result != "Success") + { + return_error(result, "Output file") + return("Error - see console for output") + } + } + }, + error = function(err) + { + # error handler picks up error information + return_error(err, "General Error") + return("Error - see console for output") + }) + + return(output) +} + + +#' Create a gridded map object from input shape and raster. +#' +#' This function is designed to take both a shape and raster object or path and create a standardized output map. Option to save the output to file +#' +#' @param shape_data (SF, SP, or Character) - Either the full path string to a shape file (with all necessary files) or an SF shape object +#' @param raster_data (Raster or Character) - Either the full path string to a raster file or an object of type RasterLayer +#' @param raster_col (Character) - Raster field name that contains the desired output variable +#' @param shape_label_field (Character) - Optional field for plotting map labels from the shape attributes (such as country name) +#' @param shape_label_size_field (Character) - Optional field used for computing shape label size dynamically (ie by area or amount etc.) (Default "1") +#' @param simplify (Boolean) - Option to reduce the number or complexity of the polygons in the shape file (default FALSE) +#' @param raster_band (Numeric) - Variable for dealing with multi band or time series rasters that specifices which raster band to use (Default 1) +#' @param convert_zero (Boolean) - Convert values within the raster data from zero to NA (default FALSE) +#' @param dpi (Numeric) - Settable DPI for different print and screen formats (default 150) +#' @param output_file (Character) - Output file path and file name and type to save the resulting plot (e.g. "c:/temp/output.png") (Types accepted: "eps", "ps", "tex", "pdf", "jpeg", "tiff", "png", "bmp", "svg") +#' @param expand_xy (c(Numeric, Numeric)) - Sets expansion amount for the X and Y scales of the map - Vector (expand x, expand y) (default c(0,0)) +#' @param map_xy_min_max (c(Numeric, ...)) - Vector that describes the desired extent of the map in the form of (xmin, xmax, ymin, ymax) (default: c(-180, 180, -90, 90)) +#' @param map_title (Character) - Title to be displayed at the top of the output map +#' @param map_palette (Character) - Variable to hold the type of colorscale to be used from the RColorBrewer palette (default "RdYlBu") +#' @param map_palette_reverse (Boolean) - Set palette to reverse direction TRUE or FALSE +#' @param map_width_height_in (c(Numeric, Numeric)) - Vector that describes the desired file size of the output image in the form of (width, height) in inches (defalt c(15, 10)) +#' @param map_legend_title (Character) - Text variable to be used for the legend header +#' @param map_x_label (Character) - Label for x axis (default "Lon") +#' @param map_y_label (Character) - Label for y axis (default "Lat") +#' @return (ggplot2 or Character) - Returns a ggplot object of the resulting map or an error string if failed +#' @importFrom sf st_transform +#' @importFrom raster raster as.data.frame compareCRS minValue maxValue nlayers +#' @importFrom dplyr mutate +#' @importFrom ggplot2 scale_x_continuous scale_y_continuous scale_fill_distiller ggplot geom_raster geom_sf coord_sf labs theme geom_sf_label guides +#' @importFrom ggspatial layer_spatial df_spatial +#' @import RColorBrewer +#' @author Jason Evanoff, jason.evanoff@pnnl.gov +#' @export +gridded_map <- function(shape_data = NULL, raster_data = NULL, raster_col = NULL, convert_zero = FALSE, + map_xy_min_max = c(-180, 180, -90, 90), map_title = NULL, map_palette = "RdYlBu", + map_width_height_in = c(15, 10), map_legend_title = NULL,shape_geom_field = "geometry", + shape_xy_fields = c("LON", "LAT"), data_xy_fields = C("LON", "LAT")) +{ + error <- "" + output <- "Default error" + tryCatch( + { + + + # Perform shape and raster comparisons or other operations + # Compare projections and equalize if necessary + if(!compareCRS(shape_obj, raster_obj)) + { + # Transform shape to match raster CRS + shape_obj <- st_transform(shape_obj, crs(raster_df)) + } + + # Raster operations + raster_df <- df_spatial(raster_obj) #raster_df <- as.data.frame(raster_obj, xy=TRUE) compare performance + raster_df <- mutate(raster_df, value = raster_df[[paste0("band", 1)]]) + + # Create mapping and output variables + # Raster stats and information + raster_min <- minValue(raster_obj) + raster_max <- maxValue(raster_obj) + raster_layers <- nlayers(raster_obj) + raster_active_band <- raster_band + + # Map output variables + x_min <- map_xy_min_max[1] + x_max <- map_xy_min_max[2] + y_min <- map_xy_min_max[3] + y_max <- map_xy_min_max[4] + map_width <- map_width_height_in[1] + map_height <- map_width_height_in[2] + expand_x <- expand_xy[1] + expand_y <- expand_xy[2] + + # Map colors and scales options + palette_direction <- 1 + + if(map_palette_reverse) + { + palette_direction <- -1 + } + + # Build map x and y scales using continuous scales + map_x_scale <- scale_x_continuous(limits=c(x_min, x_max), expand = expansion(add = expand_x), breaks=seq(x_min,x_max, abs(x_max - x_min)/12)) + map_y_scale <- scale_y_continuous(limits=c(y_min, y_max), expand = expansion(add = expand_y), breaks=seq(y_min,y_max, abs(y_max - y_min)/6)) + map_color_scale <- scale_fill_distiller(palette = map_palette, type = palette_type, direction = palette_direction, na.value = na_value, guide = map_guide) + map_shape_options <- NULL + map_size_guide_option <- NULL + + # Build geometry labels if enabled by user + if(!is.null(shape_label_field)) + { + map_shape_options <- geom_sf_label(data = shape_obj, aes_string(label = shape_label_field, fill=NULL, size = shape_label_size_field)) + if(!is.null(shape_label_size_field)) + { + map_size_guide_option <- guides(size = FALSE) + } + } + + # coordinates <- pattern$coordinate_map + # incProgress(1/2, detail = paste("Loading pattern, downscaling")) + # # Construct coordinates based on -180 to 180 for longitude + # for(i in 1:length(coordinates$lon)) + # { + # if(coordinates$lon[i] > 180) + # coordinates$lon[i] <- coordinates$lon[i] - 360 + # } + + # ggplotMap <- ggplot2::ggplot() + + # mapWorld + + # ggplot2::geom_raster(data = combined_data, ggplot2::aes_string(x="Lon", y = "Lat", fill=mapVar),interpolate = TRUE ) + + # ggplot2::coord_fixed() + + # ggplot2::scale_fill_distiller(palette = mapPalette,type = "div", direction = mapDirection, na.value = "Gray") + #, limits = c(-1,1)*max(abs(combined_data[[mapVar]]))) + + # ggplot2::labs(x="\u00B0Longitude", y="\u00B0Latitude", title = paste0(input$mapCore, " - ", input$mapYear), fill = mapFill) + + # ggplot2::scale_y_continuous(limits=c(lat_min, lat_max), expand = c(0, 0), breaks=seq(-90,90,30))+ + # ggplot2::scale_x_continuous(limits=c(lon_min, lon_max), expand = c(0, 0), breaks=seq(-180,180,30)) + + # Build ggplot Map object + output <- ggplot() + geom_raster(data=raster_df, aes(x=x, y=y, fill=value), alpha = 1.0) + + geom_sf(data = shape_obj, na.rm = TRUE, fill=NA) + + map_color_scale + + coord_sf() + + labs(x=map_x_label, y=map_y_label, title = map_title, fill = map_legend_title) + + map_x_scale + + map_y_scale + + map_shape_options + + theme(plot.title = element_text(hjust = 0.5)) + + map_size_guide_option + + # Save File + if(!is.null(output_file)) + { + result <- gcammaptools::save_plot(output_file, dpi, map_width, map_height) + if(result != "Success") + { + return_error(result) + } + } + }, + error = function(err) + { + # error handler picks up error information + error <- err + return_error(error) + return("Error - see console for output") + }) + + return(output) +} + + +#' Distributed flow map +#' +#' Create a distributed flow map object from shape and data object and return, save (optional) the output +#' +#' @param shape_data (SF, SP, or Character) - Either the full path string to a shape file (with included necessary files) or an SF shape object +#' @param shape_key_field (Character) - Name of key field in shape object for merging with map_data object +#' @param shape_label_field (Character) - Optional field for plotting data available from the shape attributes or fields (such as country name) +#' @param shape_label_size_field (Character) - Optional field used for computing shape label size dynamically (ie by area or amount etc.) +#' @param shape_xy_fields (c(Character, Character)) - Vector that specifies the x and y field names in the shape object (default c("LAT", "LON")) +#' @param shape_geom_field (Character) - Specifies field within shape object that contains needed geometry (default "geometry") +#' @param simplify (Boolean) - Option to reduce the number and complexity of the polygons in the shape file (default FALSE) +#' @param map_data (Data Frame or Character) - A data frame that contains the output data to map, or alternatively a full path to a CSV +#' @param data_key_field (Character) - Name of key field in data_obj for merging with shape_data +#' @param data_col (Character) - Column name that contains the data object's output variable +#' @param bin_method (Character) - Method or function to use to split continuous data into discrete chunks (one of "quantile", "equal", "pretty", "kmeans") (default "pretty") +#' @param bins (Numeric) - Number of bins or segments in which to divide the raster +#' @param dpi (Numeric) - Settable DPI for different print and screen formats (default 150) +#' @param output_file (Character) - Output file path and file name and type to save the resulting plot (e.g. "c:/temp/output.png") (Types accepted: "pdf", "jpeg", "tiff", "png", "bmp", "svg", "eps", "ps", "tex") (default PNG) +#' @param expand_xy (c(Numeric, Numeric)) - Sets expansion amount for the X and Y scale of the map - Vector (expand x, expand y) (default c(0,0)) +#' @param map_xy_min_max (c(Numeric, ...)) - Vector that describes the desired extent of the map in the form of (xmin, xmax, ymin, ymax) (default: c(-180, 180, -90, 90)) +#' @param map_title (Character) - Title to be displayed on the output map +#' @param map_palette (Character) - Optional variable to manually set the colorscale to a specific palette from RColorbrewer +#' @param map_palette_type (Character) - Variable to load default palette by type of data ("qual" for qualitative data, "seq" for sequential data, "div" for divergent data) (default "seq") +#' @param map_palette_reverse (Boolean) - Set palette to reverse direction TRUE or FALSE +#' @param map_width_height_in (c(Numeric, Numeric)) - Vector that describes the desired file size of the output image in the form of (width, height) in inches (default c(15, 10)) +#' @param map_legend_title (Character) - Text for the legend header +#' @param map_x_label (Character) - Label for x axis (default Lon) +#' @param map_y_label (Character) - Label for y axis (default Lat) +#' @return (ggplot2 or Character) - Returns a ggplot object of the resulting map or an error string if failed +#' @importFrom sf st_transform st_crs +#' @importFrom dplyr mutate left_join +#' @importFrom ggplot2 scale_x_discrete scale_y_discrete scale_fill_distiller ggplot geom_raster geom_sf coord_sf labs theme geom_sf_label theme_minimal +#' @importFrom ggspatial layer_spatial df_spatial +#' @importFrom classInt classIntervals +#' @import RColorBrewer +#' @author Jason Evanoff, jason.evanoff@pnnl.gov +#' @export +distributed_flow <- function(shape_data = NULL, shape_key_field = NULL, shape_label_field = NULL, shape_label_size = "1", + shape_xy_fields = c("LON", "LAT"), shape_geom_field = "geometry", simplify = FALSE, + map_data = NULL, data_key_field = NULL, data_col = NULL, bin_method = "pretty", bins = NULL, + dpi = 150, output_file = NULL, expand_xy = c(0, 0), + map_xy_min_max = c(-180, 180, -90, 90), map_title = NULL, map_palette = NULL, + map_palette_reverse = FALSE, map_palette_type = "seq", map_width_height_in = c(15, 10), + map_legend_title = NULL, map_x_label = "Lon", map_y_label = "Lat") +{ + + + + + +} + diff --git a/R/output.R b/R/output.R new file mode 100644 index 0000000..6d95d52 --- /dev/null +++ b/R/output.R @@ -0,0 +1,49 @@ +# output.R +# +# Contains general output functions for the package + + +#' Saves a plot to disk +#' +#' Provides basic error handling and saving of the output map to file +#' +#' @param output_file (Character) - Output file path and file name and type to save the resulting plot (e.g. "c:/temp/output.png") Available file types ("eps", "ps", "tex", "pdf", "jpeg", "tiff", "png", "bmp", "svg") +#' @param dpi (Numeric) - Settable DPI for different print and screen formats (default 150) +#' @param map_width (Numeric) - Map width in inches (default 15) +#' @param map_height (Numeric) - Map height in inches (default 10) +#' @return (Character) - Returns a character string with success or an error string if failed +#' @importFrom ggplot2 ggsave +#' @author Jason Evanoff, jason.evanoff@pnnl.gov +#' @export +save_plot <- function(output_file = NULL, dpi = 150, map_width = 15, map_height = 10) +{ + output <- "Success" + tryCatch( + { + if(is.null(output_file) || !"character" %in% class(output_file)) + { + return("Error: `output_file` argument must be a valid character path") + } + + # Get file type dynamically and save to path + file_type <- substr(x = output_file, start = (nchar(output_file)-2), stop = nchar(output_file)) + + if(file_type %in% c("eps", "ps", "tex", "pdf", "jpeg", "tiff", "png", "bmp", "svg")) + { + ggsave(filename = output_file, device = file_type, dpi = dpi, limitsize = TRUE, + width = map_width, height = map_height) + } + else + { + return("Error: Unrecognized output file type (must be one of eps, ps, tex, pdf, jpeg, tiff, png, bmp, svg") + } + }, + error = function(err) + { + # error handler picks up error information + error <- err + return(error) + }) + + return(output) +} diff --git a/R/spatial_utils.R b/R/spatial_utils.R new file mode 100644 index 0000000..a6384ee --- /dev/null +++ b/R/spatial_utils.R @@ -0,0 +1,540 @@ +# utils.R +# +# Contains general helper functions for the package + + +#' Process shape +#' +#' This function processes the shape argument for dynamic mapping functions +#' +#' @param shape_data (SF, SP, or Character) - Either the full path string to a shape file (with included necessary files) or an SF shape object +#' @param shape_key_field (Character) - Name of key field in shape object for merging with map_data object +#' @param shape_data_field (Character) - Optional field for utilizing a field within the shape data as the map data field. Negates the map_data variable +#' @param shape_label_field (Character) - Optional field for plotting data available from the shape attributes or fields (such as country name) +#' @param shape_label_size_field (Numeric) - Optional field used for computing shape label size dynamically (ie by area or amount etc.) +#' @param shape_xy_fields (c(Character, Character)) - Vector that specifies the x and y field names in the shape object (default c("LAT", "LON")) +#' @param shape_geom_field (Character) - Specifies field within shape object that contains needed geometry (default "geometry") +#' @param simplify (Boolean) - Option to reduce the number and complexity of the polygons in the shape file (default FALSE) +#' @return (SF or Character) - Returns the resulting simplified SF object or an error string if failed +#' @importFrom sf st_crs +#' @importFrom raster crs +#' @author Jason Evanoff, jason.evanoff@pnnl.gov +#' @export +process_shape <- function(shape_data = NULL, simplify = FALSE, shape_label_field = NULL, shape_data_field = NULL, + shape_key_field = NULL, shape_label_size = 1, shape_xy_fields = c("LON", "LAT"), + shape_geom_field = "geometry") +{ + tryCatch( + { + # Initial processing of shape object so that a completed shape object can be sent to the error check function + if(is.null(shape_data)) + { + return("Error: `shape_data` is NULL") + } + else if("character" %in% class(shape_data)) + { + if (!file.exists(shape_data)) + { + return(paste0("Error: Cannot open shape file - `", shape_data, "` - or shape file path does not exist ")) + } + } + + # Import shape data + shape_obj <- gcammaptools::import_mapdata(shape_data) + + if(suppressWarnings({!"sf" %in% class(shape_obj)})) + { + return(paste0("Error: There was an unknown error processing the shape object: ", shape_obj)) + } + + # Verify shape + result <- verify_shape(shape_obj, simplify, shape_label_field, shape_data_field, shape_key_field, shape_label_size, shape_xy_fields, shape_geom_field) + + if(result != "Success") + { + return(result) + } + + # Verify raster CRS and assign default if NA + if(is.na(crs(shape_obj)) || is.null(crs(shape_obj))) + { + st_crs(shape_obj) <- crs(default_projection) + print("Applying default CRS to shape (shape CRS was NA or NULL)") + } + + # Optional argument to simplify polygons via the simplify_mapdata function + if(simplify) + { + shape_obj <- gcammaptools::simplify_mapdata(shape_obj) + } + # else + # { + # return(result) + # } + }, + error = function(err) + { + # error handler picks up error information + error <- err + return(error) + }) + + return(shape_obj) +} + + +#' Process raster +#' +#' This function handles the processing of raster data for use in dynamic mapping functions +#' +#' @param raster_data (Raster or Character) - Either the full path string to raster file or a raster object +#' @param raster_col (Character) - Column name that contains the raster object's output variable +#' @param raster_band (Numeric) - Future variable for dealing with multi band or time series rasters etc (default 1) +#' @param bin_method (Character) - Method or function to use to split continuous data into discrete chunks (default "pretty") +#' @param bins (Numeric) - Number of bins or segments in which to divide the raster (default 8) +#' @param convert_zero (Boolean) - Convert raster zero values to NA (default FALSE) +#' @importFrom rgis import_raster +#' @importFrom ggspatial layer_spatial df_spatial +#' @importFrom raster raster crs +#' @return (Raster or Character) - Returns the resulting raster object or an error string if failed +#' @author Jason Evanoff, jason.evanoff@pnnl.gov +#' @export +process_raster <- function(raster_data, raster_col, raster_band = 1, bin_method = "pretty", bins = 8, + convert_zero = FALSE) +{ + tryCatch( + { + # Verify raster + result <- verify_raster(raster_data , raster_col, raster_band, bin_method, bins, convert_zero) + + # If raster passes verification, load and process + if(result == "Success") + { + # Import raster data + raster_obj <- import_raster(raster_data) + } + else + { + return(result) + } + + # Set raster band + if(raster_band != 1) + { + raster_obj <- raster(raster_obj, band=raster_band) + } + + # Convert zeroes to NA if enabled + if(convert_zero == TRUE) + { + raster_obj[raster_obj==0] <- NA + } + }, + error = function(err) + { + # error handler picks up error information + error <- err + return(error) + }) + + return(raster_obj) +} + + +#' Process data +#' +#' This function handles the processing of source map data for use in dynamic mapping functions +#' +#' @param map_data (Data Frame or Character) - A data frame that contains the output data to map, or alternatively a full path to a CSV +#' @param data_key_field (Character) - Name of key field in data_obj for merging with shape_data +#' @param data_col (Character) - Column name that contains the data object's output variable +#' @param shape_obj (SF) - An SF object +#' @param shape_key_field (Character) - Name of key field in shape object for merging with map_data object +#' @param shape_data_field (Character) - Optional field for utilizing a field within the shape data as the map data field. Negates the map_data variable +#' @return (Data Frame or Character) - Returns the resulting simplified SF object or an error string if failed +#' @author Jason Evanoff, jason.evanoff@pnnl.gov +#' @export +process_data <- function(map_data = NULL, data_key_field = NULL, data_col = NULL, shape_obj = NULL, + shape_data_field = NULL, shape_key_field = NULL) +{ + tryCatch( + { + + if(!is.null(shape_data_field)) + { + # No shape_data_field, use map data + map_obj <- shape_obj + } + else + { + if("data.frame" %in% class(map_data) ) + { + map_obj <- map_data + } + else if("character" %in% class(map_data)) + { + if (file.exists(map_data)) + { + map_obj <- read.csv(map_data, stringsAsFactors = F) + } + else + { + return(paste0("Error: Cannot open data file - `", map_data)) + } + } + else + { + return("Error: Unrecognized `map_data` argument.") + } + } + + # Initial error checking + result <- verify_data(map_obj, data_key_field, data_col, shape_obj, shape_data_field, shape_key_field) + + # Return error if not Success + if(result != "Success") + { + return(result) + } + }, + error = function(err) + { + # error handler picks up error information + error <- err + return(error) + }) + + return(map_obj) +} + + +#' Import ESRI Shapefile or GeoJSON as sf object. +#' +#' Creates a Simple Feature (sf) object from full path string to ESRI Shapefile +#' or GeoJSON file. User defines which field is supposed to represent the ID for +#' the data. +#' +#' @param file_pth (Character) Full path to shapefile (.shp). Shapefiles must contain at least .shp, .shx, and .dbf file to function properly. +#' @return (sf or Character) - Returns the loaded SF object or an error string if failed +#' @export +load_shp <- function(file_pth = NULL) +{ + if(is.null(file_pth)) + { + return("Error: file_pth cannot be null") + } + result <- tryCatch( + { + file <- system.file(file_pth) + result <- (sf::st_read(file_pth, quiet = TRUE)) + }, + error = function(err) + { + # error handler picks up error information + error <- err + return(error) + }) + + if(!"sf" %in% class(result)) + { + return("Error: error loading shape, check your file path") + } + + return(result) +} + +#' Single import function for compatible data types. +#' +#' Imports available for sf objects, spatial data frames, ESRI Shapefiles, or +#' GeoJSON files. +#' +#' @param obj Input full path string or object. +#' @param fld Field name to use as identifier. +#' @param prj4s Proj4 string for projection (default WGS84). +#' @return An sf object representation of the map data. +#' @export +import_mapdata <- function(obj, fld = NULL, prj4s = wgs84) { + + # get object class + cls <- class(obj) + + # check for sf data frame object + if (cls[1] == "sf") { + return(obj) + } + + # check for file path + else if (is.character(obj)) { + + # get file extension + extn <- tolower(c(tools::file_ext(obj))) + + # if ESRI Shapefile or GeoJSON file + if (extn %in% list('shp', 'geojson')) { + + # load Shapefile + return(load_shp(file_pth = obj)) + } + # catch unknown + else { + return(NULL) + } + } + # check for spatial data frames + else if (cls %in% list("SpatialPolygonsDataFrame", "SpatialPointsDataFrame", + "SpatialLinesDataFrame")) { + + return(sf::st_as_sf(obj)) + } + else { + return(NULL) # catch_error: object type not understood. + } +} + + +#' Reduce number of polygons and size of polygons for map Shapefiles +#' +#' Takes a sf object representation of a map and simplifys it by removing +#' polygons that are under a certain size. +#' +#' ** NOTE: This function adds two polygons to the edges of the map to prevent +#' the removal of polygons near the edges redefining the map bounds. +#' +#' @param mapdata (sf) object containing polygons or multipolygons to simplify. +#' @param min_area (Numeric) Minimum area of polygons to keep. +#' @param degree_tolerance (Numeric) Tolerance parameter for simplifying polygons. +#' @return (sf or Character) The simplified sf object or error string if caught. +#' @importFrom magrittr %>% +#' @export +simplify_mapdata <- function(mapdata = NULL, min_area = 2.5, degree_tolerance = 0.1) +{ + # silence package notes for NSE. + . <- NULL + + result <- verify_simplify_mapdata(mapdata, min_area, degree_tolerance) + if(result != "Success") + { + return(result) + } + + if ("MULTIPOLYGON" %in% sf::st_geometry_type(mapdata)) + mapdata <- sf::st_cast(mapdata, "POLYGON", warn = FALSE) + + # filter out all polygons in the data under the minimum area + areafilter <- sapply(sf::st_geometry(mapdata), sf::st_area) > min_area + filtermap <- mapdata[which(areafilter), ] + + filtermap <- suppressWarnings({sf::st_simplify(filtermap, preserveTopology=TRUE, dTolerance=degree_tolerance)}) + + # if nothing was filtered just return original map + if (utils::object.size(filtermap) == utils::object.size(mapdata)) + return(mapdata) + + # When removing polygons we might be shifting the bounds of the map, which + # would make it off-center when plotting. To account for this, we put tiny + # polygons on the edges. + xmin <- sf::st_bbox(mapdata)[1] %>% round + xmax <- sf::st_bbox(mapdata)[3] %>% round + height <- 0.0001 # small enough so it's not visible on plot + + left_edge <- matrix(c(xmin, 0, xmin, height, xmin - height, 0, xmin, 0), + byrow = TRUE, ncol = 2) %>% + list() %>% + sf::st_polygon() + + right_edge <- matrix(c(xmax, 0, xmax, height, xmax + height, 0, xmax, 0), + byrow = TRUE, ncol = 2) %>% + list() %>% + sf::st_polygon() + + # create geometry with the two edges + edges <- sf::st_sfc(left_edge, right_edge, crs = sf::st_crs(mapdata)) + + # data frame with same names as original map, so that the two can combine + borders <- data.frame(matrix(ncol = length(names(mapdata)), nrow = 2)) %>% + magrittr::set_names(names(mapdata)) + + # extra polygons should be GCAM region 0 + if ('region_id' %in% names(borders)) borders$region_id <- c(0, 0) + + # convert to sf object and add new border polygons + sf::st_geometry(borders) <- edges + + # add new polygons to filtered map and return + return(rbind(borders, filtermap)) +} + + +#' Retrieve proj4 projection string. +#' +#' Provides a lookup list for default proj4 strings utilized. Users may also +#' specify their own lookup list. Options also include providing either the +#' EPSG, ESRI, or SR-ORG projection codes to retrieve the associated proj4 +#' string from a web query from http://spatialreference.org. Definitions for +#' proj4 string parmeters can be referenced here: +#' http://proj4.org/parameters.html#parameter-list +#' +#' @param obj Use object instead that has a predefined proj4 string. +#' @param prj_type The projection type is either 'esri', 'epsg', or 'sr-org' or 'prj4s_key'. +#' @param prj_code The projection code as an integer for EPSG, ESRI, or SR-ORG. +#' @param prj4s_key Lookup key string identifying the default projection. +get_prj4s <- function(obj = NULL, prj_type = NULL, prj_code = NULL, prj4s_key = NULL) { + + # default prj4 key: string lookup + lu <- list( + 'us' = "+proj=aea +lat_1=20 +lat_2=60 +lat_0=40 +lon_0=-96 +x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83", + 'africa' = "+proj=aea +lat_1=20 +lat_2=-23 +lat_0=0 +lon_0=25 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs +towgs84=0,0,0 ", + 'world' = "+proj=longlat +datum=WGS84 +no_defs", + 'ch_aea' = "+proj=aea +lat_1=27 +lat_2=45 +x_0=0 +y_0=0 +lat_0=35 +lon_0=105 +ellps=WGS84 +datum=WGS84", + 'eck3' = "+proj=eck3 +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs" + ) + + # use object if defined + if (!is.null(obj) && (obj %in% names(lu))) { + return(lu[[obj]]) + } + else if (!is.null(obj)) { + return(obj) + } + + # if a prj4 key is provided use it + if (prj_type == 'prj4s_key' && !is.null(prj4s_key)) { + return(lu[[prj4s_key]]) + } + # otherwise lookup proj4 string by url + else if (!is.null(prj_type) && !is.null(prj_code)) { + + # create url + url <- paste0('http://spatialreference.org/ref/', prj_type, '/', prj_code, '/proj4/') + prj4s <- tryCatch(readLines(url, warn = FALSE), error = function(e) NULL) + + # make sure url got a string + if (length(prj4s) == 0) { + warning(paste('Cannot find valid proj4 string for', prj_type, 'with projection code', prj_code)) + # Return wgs84 as default proj4 string + return(wgs84) + } + return(prj4s) + } + else { + return(wgs84) + } +} + + +#' Helper function for assigning a Proj4 string from several possible inputs. +#' +#' Uses user-input for projection type to identify what +#' type of URL fetch needs to be conducted to retrieve +#' a Proj4 string from http://spatialreference.org +#' +#' @param proj_type Either esri, epsg, or sr-org as string. These correspond to +#' available reference types hosted by http://spatialreference.org/ +#' @param proj The coordinate reference system number or object provided by the user +assign_prj4s <- function(proj_type, proj) { + + # change proj_type to lower case + if (is.null(proj_type)) { + pt <- NULL + } + else { + pt <- tolower(c(proj_type)) + } + + # get proj4 string that corresponds to user selection + if (is.null(pt)) { + return(get_prj4s(obj = proj)) + } + else if (pt == 'prj4s_key') { + return(get_prj4s(prj_type = pt, prj4s_key = proj)) + } else { + return(get_prj4s(prj_type = pt, prj_code = proj)) + } +} + +#' Create a rectangluar sf polygon from numeric extent or sf bbox. +#' +#' @param ext Numeric extent [xmin, xmax, ymin, ymax] or an object of class bbox +pgon_from_extent <- function(ext) { + # The position of xmax and ymin are switched with a bbox-defined extent + xmin <- ext[1] + xmax <- ext[(class(ext) == "bbox") + 2] + ymin <- ext[(class(ext) != "bbox") + 2] + ymax <- ext[4] + + # calling st_segmentize with a 1 degree resolution makes reprojections of + # the rectangle look smooth + return(sf::st_polygon(list(rbind(c(xmin, ymin), c(xmin, ymax), c(xmax, ymax), + c(xmax, ymin), c(xmin, ymin))))) +} + + +#' Create sf object from numeric extent. +#' +#' Creates a sf object from numeric extent vector and applies a default WGS84 +#' (EPSG:4326) coordinate reference system. +#' +#' @param b_ext Numeric extent [xmin, xmax, ymin, ymax] +#' @param buff_dist Distance in decimal degrees to expand the bounding box by in +#' all directions. +#' @param proj4s Either the proj4 string or EPSG number of the native projection +#' of the bounds +spat_bb <- function(b_ext, buff_dist = 0, proj4s = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs") { + + # create a rectangular polygon from bounding box, segmentize it to 1 degree + # resultion so that reprojections of it look smooth, then convert it to simple + # features polygon collection + geom <- pgon_from_extent(b_ext) %>% + sf::st_segmentize(1) %>% + sf::st_sfc() + + # make sf object, assign default WGS84 proj, and transform projection to that + # of the input mapdata + bb <- sf::st_sf(geometry = geom) %>% + sf::st_set_crs("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs") %>% + sf::st_transform(proj4s) + + # buffer if user desires + if (buff_dist) { + # each zoom level shrinks the map's bounding rectangle by 10% of its + # shortest side + x <- sf::st_bbox(bb)[3] - sf::st_bbox(bb)[1] + y <- sf::st_bbox(bb)[4] - sf::st_bbox(bb)[2] + zoom <- buff_dist * -0.1 * min(x, y) + if (sf::st_is_longlat(bb)) zoom <- units::set_units(zoom, degree) + + # Suppress Warning: + # "In st_buffer.sfc(st_geometry(x), dist, nQuadSegs) : st_buffer does + # not correctly buffer longitude-latitude data, dist needs to be in + # decimal degrees." + # This warning occurs from buffering a feature that is in a geographic + # coordinate system (lat-long) rather than a projection one. This makes the + # the buffer not be exact due to the distance being calculated in decimal + # degrees rather than meters or kilometers. This is fine with us since we + # are simply using buffer as a way of zooming to include or exclude portions + # of the bounding extent in this call. + return(suppressWarnings({ sf::st_buffer(bb, zoom, nQuadSegs = 5) })) + } + else { + return(bb) + } +} + + +#' Clean spatial data. +#' +#' Removes empty, corrupt, or invalid geometries from an sfc object. +#' +#' @param sfcobj Object of class \code{sf} or \code{sfc} +remove_invalid <- function(sfcobj) { + invalids <- sf::st_is_valid(sfcobj, reason = T) + intrscts <- grepl("Self-intersection", invalids) + + # See note in spat_bb about warning message + sfcobj[intrscts, ] <- suppressWarnings({ + suppressMessages({ sf::st_buffer(sfcobj[intrscts, ], 0) }) + }) + + sfcobj <- sfcobj[!is.na(invalids), ] + return(sfcobj) +} diff --git a/R/sysdata.rda b/R/sysdata.rda deleted file mode 100644 index 7f7dc3e..0000000 Binary files a/R/sysdata.rda and /dev/null differ diff --git a/R/utils.R b/R/utils.R deleted file mode 100644 index 106cc69..0000000 --- a/R/utils.R +++ /dev/null @@ -1,178 +0,0 @@ -# utils.R -# -# Contains general helper functions for the package - - -#' Retrieve proj4 projection string. -#' -#' Provides a lookup list for default proj4 strings utilized. Users may also -#' specify their own lookup list. Options also include providing either the -#' EPSG, ESRI, or SR-ORG projection codes to retrieve the associated proj4 -#' string from a web query from http://spatialreference.org. Definitions for -#' proj4 string parmeters can be referenced here: -#' http://proj4.org/parameters.html#parameter-list -#' -#' @param obj Use object instead that has a predefined proj4 string. -#' @param prj_type The projection type is either 'esri', 'epsg', or 'sr-org' or 'prj4s_key'. -#' @param prj_code The projection code as an integer for EPSG, ESRI, or SR-ORG. -#' @param prj4s_key Lookup key string identifying the default projection. -get_prj4s <- function(obj = NULL, prj_type = NULL, prj_code = NULL, prj4s_key = NULL) { - - # default prj4 key: string lookup - lu <- list( - 'us' = "+proj=aea +lat_1=20 +lat_2=60 +lat_0=40 +lon_0=-96 +x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83", - 'africa' = "+proj=aea +lat_1=20 +lat_2=-23 +lat_0=0 +lon_0=25 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs +towgs84=0,0,0 ", - 'world' = "+proj=longlat +datum=WGS84 +no_defs", - 'ch_aea' = "+proj=aea +lat_1=27 +lat_2=45 +x_0=0 +y_0=0 +lat_0=35 +lon_0=105 +ellps=WGS84 +datum=WGS84", - 'eck3' = "+proj=eck3 +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs" - ) - - # use object if defined - if (!is.null(obj) && (obj %in% names(lu))) { - return(lu[[obj]]) - } - else if (!is.null(obj)) { - return(obj) - } - - # if a prj4 key is provided use it - if (prj_type == 'prj4s_key' && !is.null(prj4s_key)) { - return(lu[[prj4s_key]]) - } - # otherwise lookup proj4 string by url - else if (!is.null(prj_type) && !is.null(prj_code)) { - - # create url - url <- paste0('http://spatialreference.org/ref/', prj_type, '/', prj_code, '/proj4/') - prj4s <- tryCatch(readLines(url, warn = FALSE), error = function(e) NULL) - - # make sure url got a string - if (length(prj4s) == 0) { - warning(paste('Cannot find valid proj4 string for', prj_type, 'with projection code', prj_code)) - # Return wgs84 as default proj4 string - return(wgs84) - } - return(prj4s) - } - else { - return(wgs84) - } -} - - -#' Helper function for assigning a Proj4 string from several possible inputs. -#' -#' Uses user-input for projection type to identify what -#' type of URL fetch needs to be conducted to retrieve -#' a Proj4 string from http://spatialreference.org -#' -#' @param proj_type Either esri, epsg, or sr-org as string. These correspond to -#' available reference types hosted by http://spatialreference.org/ -#' @param proj The coordinate reference system number or object provided by the user -assign_prj4s <- function(proj_type, proj) { - - # change proj_type to lower case - if (is.null(proj_type)) { - pt <- NULL - } - else { - pt <- tolower(c(proj_type)) - } - - # get proj4 string that corresponds to user selection - if (is.null(pt)) { - return(get_prj4s(obj = proj)) - } - else if (pt == 'prj4s_key') { - return(get_prj4s(prj_type = pt, prj4s_key = proj)) - } else { - return(get_prj4s(prj_type = pt, prj_code = proj)) - } -} - -#' Create a rectangluar sf polygon from numeric extent or sf bbox. -#' -#' @param ext Numeric extent [xmin, xmax, ymin, ymax] or an object of class bbox -pgon_from_extent <- function(ext) { - # The position of xmax and ymin are switched with a bbox-defined extent - xmin <- ext[1] - xmax <- ext[(class(ext) == "bbox") + 2] - ymin <- ext[(class(ext) != "bbox") + 2] - ymax <- ext[4] - - # calling st_segmentize with a 1 degree resolution makes reprojections of - # the rectangle look smooth - return(sf::st_polygon(list(rbind(c(xmin, ymin), c(xmin, ymax), c(xmax, ymax), - c(xmax, ymin), c(xmin, ymin))))) -} - - -#' Create sf object from numeric extent. -#' -#' Creates a sf object from numeric extent vector and applies a default WGS84 -#' (EPSG:4326) coordinate reference system. -#' -#' @param b_ext Numeric extent [xmin, xmax, ymin, ymax] -#' @param buff_dist Distance in decimal degrees to expand the bounding box by in -#' all directions. -#' @param proj4s Either the proj4 string or EPSG number of the native projection -#' of the bounds -spat_bb <- function(b_ext, buff_dist = 0, proj4s = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs") { - - # create a rectangular polygon from bounding box, segmentize it to 1 degree - # resultion so that reprojections of it look smooth, then convert it to simple - # features polygon collection - geom <- pgon_from_extent(b_ext) %>% - sf::st_segmentize(1) %>% - sf::st_sfc() - - # make sf object, assign default WGS84 proj, and transform projection to that - # of the input mapdata - bb <- sf::st_sf(geometry = geom) %>% - sf::st_set_crs("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs") %>% - sf::st_transform(proj4s) - - # buffer if user desires - if (buff_dist) { - # each zoom level shrinks the map's bounding rectangle by 10% of its - # shortest side - x <- sf::st_bbox(bb)[3] - sf::st_bbox(bb)[1] - y <- sf::st_bbox(bb)[4] - sf::st_bbox(bb)[2] - zoom <- buff_dist * -0.1 * min(x, y) - if (sf::st_is_longlat(bb)) zoom <- units::set_units(zoom, degree) - - # Suppress Warning: - # "In st_buffer.sfc(st_geometry(x), dist, nQuadSegs) : st_buffer does - # not correctly buffer longitude/latitude data, dist needs to be in - # decimal degrees." - # This warning occurs from buffering a feature that is in a geographic - # coordinate system (lat/long) rather than a projection one. This makes the - # the buffer not be exact due to the distance being calculated in decimal - # degrees rather than meters or kilometers. This is fine with us since we - # are simply using buffer as a way of zooming to include or exclude portions - # of the bounding extent in this call. - return(suppressWarnings({ sf::st_buffer(bb, zoom, nQuadSegs = 5) })) - } - else { - return(bb) - } -} - - -#' Clean spatial data. -#' -#' Removes empty, corrupt, or invalid geometries from an sfc object. -#' -#' @param sfcobj Object of class \code{sf} or \code{sfc} -remove_invalid <- function(sfcobj) { - invalids <- sf::st_is_valid(sfcobj, reason = T) - intrscts <- grepl("Self-intersection", invalids) - - # See note in spat_bb about warning/message - sfcobj[intrscts, ] <- suppressWarnings({ - suppressMessages({ sf::st_buffer(sfcobj[intrscts, ], 0) }) - }) - - sfcobj <- sfcobj[!is.na(invalids), ] - return(sfcobj) -} diff --git a/README.md b/README.md index 81884ae..9f9a4c7 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,52 @@ [![Build Status](https://travis-ci.org/JGCRI/gcammaptools.svg?branch=master)](https://travis-ci.org/JGCRI/gcammaptools) # gcammaptools +gcammaptools is an R package designed to deliver dynamically generated, highly customizable mapping products ## Overview -The gcammaptools package provides functions for plotting -[GCAM](http://jgcri.github.io/gcam-doc/) data on world or regional maps. This -includes functions for making plots for regional or gridded data, as well as -default projection and theme settings that provide a house style for GCAM plots. +The purpose of the `gcammaptools` package is to provide standardized functions that can handle a variety of different shape and data field arguments to dynamically generate world or regional based data driven maps. This includes functions for making plots based on regional (choropleth) or gridded (downscaled) data, as well as default projection and theme settings that provide a house style for plot aesthetic standardization. The package also provides the ability to plot data from our [GCAM](http://jgcri.github.io/gcam-doc/) system to GCAM based regions. -## Installation +## Getting Setup with the `gcammaptools` Package -This package must be installed from the github repository using -`install_github`. To do this, you will need to install `devtools` first if you -don't have it already. +### Installation +This package must be installed from the github repository located [here](https://github.com/JGCRI/gcammaptools) using the `install_github` command from the `devtools` package. To do this, you will need to install the `devtools` package first if you do not have it already. Additionaly, this package also depends on the following R packages: + +* RColorBrewer +* [rgis](https://github.com/JGCRI/rgis) +* classInt +* dplyr +* ggplot2 (currently supports 3.2 or lower) +* ggspatial +* magrittr +* raster +* sf + +### Step 1: Install package ```R install.packages('devtools') # if you don't have it already devtools::install_github('JGCRI/gcammaptools') ``` -Optionally, you can build the "examples" vignette, which shows how to -do several common mapping tasks. To build these examples, replace the -`install_github` command above with: +### Step 2: Build vignettes +Optionally, you can build the vignettes including a tutorial for how to use the package along with some examples, which shows how to do several common mapping tasks. To build these examples, replace the `install_github` command above with: ```R devtools::install_github('JGCRI/gcammaptools', dependencies=TRUE, build_vignettes=TRUE) ``` -You can display the vignette by running +You can display the choropleth vignette by running ```R -vignette('examples','gcammaptools') +vignette('choropleth','gcammaptools') ``` -Sometimes R can't find the CRAN repository without help. If during -the `install_github` steps you get errors about missing packages or -functions, rerun them with the `repos` option: +Sometimes R can't find the CRAN repository without help. If during the `install_github` steps you get errors about missing packages or functions, rerun them with the `repos` option: ```R cran <- 'http://cran.us.r-project.org' devtools::install_github('JGCRI/gcammaptools', build_vignettes=TRUE, dependencies=TRUE, repos=cran) ``` -This should allow R to fetch the packages it needs to complete the -installation from CRAN. +This should allow R to fetch the packages it needs to complete the installation from CRAN. ## Usage @@ -72,3 +77,185 @@ with the package. ```R plot_GCAM(map.rgn32, col='value', gcam_df=co2, title='CO2 Emissions', legend=TRUE) ``` + +[![DOI](https://zenodo.org/badge/254437500.svg)](https://zenodo.org/badge/latestdoi/254437500) + [![Build Status](https://travis-ci.org/IMMM-SFA/im3py.svg?branch=master)](https://travis-ci.org/IMMM-SFA/im3py) [![codecov](https://codecov.io/gh/IMMM-SFA/im3py/branch/master/graph/badge.svg)](https://codecov.io/gh/IMMM-SFA/im3py) + +# im3py +An IM3 template repository for Python projects that have time-steps + + +## Overview +The purpose of `im3py` is to help developers quickly establish a GitHub repository that conforms to IM3 software engineering standards. Our hope is to create a common user experience for all Python modeling software developed for use in IM3 experiments. We are mindfully developing software that exposes key variables per time-step so that they may be used in integrated and/or uncertainty characterization experiments while still maintaining the ability for autonomous use. This template package establishes the structure necessary to wrap existing Python code in our modeling interface and time-step processing generator. We also include: a sample test suite, `Zenodo`, `Travis-CI`, and `codecov` standard files and setup protocol, our expected `docstring` style, a `stdout` and file logger, and an example fake code file that represents a user's code contribution. + +## Getting Setup with the `im3py` Template Repository + +### Using the Template +Simply click `Use this template` on the main repository page (shows up to the left of `Clone or download`) and fill in your `Repository name`, the `Description`, select whether you want the repository to be `Public` or `Private`, and leave `Include all branches` unchecked. Repository names for Python packages should match the name of the actual package if at all possible. Python package name conventions should be all lower case and only separated by an underscore if necessary. We highly encourage `Public` development as well. + +### Setting up Travis-CI, Codecov, and Zenodo for your New Repository +We use Travis-CI for continuous integration testing to ensure we do not make changes to our code that cause our tests to fail. The sample `.travis.yml` file is currently setup to test on Windows, Mac, and Linux. You may need to tailor this script to install other libraries before your package is installed on a Travis-CI virtual environment (e.g., GDAL). Here is some Travis-CI info if you want to learn more: [Core Concepts for Beginners](https://docs.travis-ci.com/user/for-beginners/). + +We also use Codecov as a way to measure how well we are covering our code with tests. Codecov fits nicely within our Travis-CI setup. Please contact our software engineering team for a demo of how to get the most from the information this software provides. Here is some Codecov info if you wish to learn more: [About Code Coverage](https://docs.codecov.io/docs/about-code-coverage). + +As we develop our software, we want to make sure that we conduct relevant and timely releases that are linked to a permanent archive and have a resulting DOI. We do this in IM3 by linking Zenodo to our repositories. When we conduct a GitHub release, the resulting archive is automatically created in Zenodo. This can then be sited in a journal article or meta-repository. Here is some Zenodo info if you wish to learn more: [About Zeonodo](https://about.zenodo.org/). + +IM3 already has Zenodo, Travis-CI, and Codecov accounts setup, so when you create a repository from this template please notify our software engineering team and we will "flip the switch" to make our accounts recognize your new repository. + +You will also need to update the links in the badges at the top of this document to point to your model's information. + +## Understanding the `im3py` repository +The following table outlines each part of the repository and it's purpose: + +| Component | Description | +| ---- | ---- | +| `.gitignore` | Which files Git will ignore in your local when you push your changes to the remote | +| `.travis.yml`| Setup YAML file for Travis-CI; includes instantiation of Codecov +| `LICENSE` | The appropriate open-source license. Work with the software engineering team to ensure this is correct for your software | +| `MANIFEST.in` | A log of files to include in your source distribution that are not automatically included by default | +| `README.md` | A README file in Markdown that will display on the splash page of the repository | +| `requirements.txt` | A text file of required non-built-in Python packages to install | +| `setup.py` | A python file that is equipped with information to install the Python code as a package | +| `im3py` | The directory containing the Python package code | +| `im3py/__init__.py` | Allows Python to recognize a directory as a package. This one raises classes and functions to be accessible to the user from the package level | +| `im3py/model.py` | A model class that instantiates a logger and runs the model under user defined conditions | +| `im3py/process_step.py` | A class that the generator is built from which allows the user to place conditions on how the model will run per time-step | +| `im3py/read_config.py` | A class that reads the configuration file or from arguments passed into the model class | +| `im3py/install_supplement.py` | A class that downloads and unpacks an example data supplement from a remote source that matches the current installed distribution | +| `im3py/some_code.py` | Fake code to represent what a user may provide. This file should be removed. | +| `im3py/tests` | The module holding the test suite | +| `im3py/tests/test_model.py` | Tests for model.py | +| `im3py/tests/test_process_step.py` | Tests for process_step.py | +| `im3py/tests/test_read_config.py` | Tests for read_config.py | +| `im3py/tests/test_install_supplement.py` | Tests for install_supplement.py | +| `im3py/tests/test_some_code.py` | Tests for some_code.py | +| `im3py/tests/data` | Directory holding test data. Optional directories are `inputs` and `comp_data`. The `outputs` are not housed in the repository. | +| `im3py/tests/data/inputs` | Directory housing inputs that should be expected for a subset of a run | +| `im3py/tests/data/inputs/config.yml` | Sample configuration YAML file used in tests | +| `im3py/tests/data/comp_data` | Directory housing outputs that should be expected for a subset of a run. Test sets should be subsets and be able to run quickly where possible. | +| `im3py/tests/data/comp_data/output_year_2015.txt` | Expected output file for time-step 2015 | +| `im3py/tests/data/comp_data/output_year_2016.txt` | Expected output file for time-step 2016 | +| `im3py/tests/data/comp_data/test_no-header.csv` | Expected data from install supplement download | + + +## Getting Started Using the `im3py` Package +The `im3py` package uses only **Python 3.6** and up. + +### Step 1: +You can install `im3py` by running the following from your cloned directory (NOTE: ensure that you are using the desired `pip` instance that matches your Python3 distribution): + +`pip3 install git+https://github.com/IMMM-SFA/im3py.git --user` + +### Step 2: +Confirm that the module and its dependencies have been installed by running from your prompt: + +```python +from im3py import Model +``` + +If no error is returned then you are ready to go! + +## Setting up a run + +### Expected arguments +See examples below for how to pass into the `Model` class + +| Argument | Type | Description | +|----|----|----| +| `config_file` | str | Full path to configuration YAML file with file name and extension. If not provided by the user, the code will default to the expectation of alternate arguments. | +| `output_directory` | string | Full path with file name and extension to the output directory where outputs and the log file will be written. | +| `start_step` | int | Start time step value. | +| `through_step` | int | Through time step value. | +| `time_step` | int | Number of steps (e.g. number of years or minutes between projections) | +| `alpha_param` | float | Alpha parameter for model. Acceptable range: -2.0 to 2.0 | +| `beta_param` | float | Beta parameter for model. Acceptable range: -2.0 to 2.0 | +| `write_logfile` | bool | Optional, choose to write log as file. | + +### Variable arguments +Users can update variable argument values after model initialization; this includes updating values between time steps (see **Example 3**). The following are variable arguments: +- `alpha_param` +- `beta_param` + +### YAML configuration file option (e.g., config.yml) +Arguments can be passed into the `Model` class using a YAML configuration file as well (see **Example 1**): + +```yaml +# Example configuration file setup +output_directory: "" +start_step: 2015 +through_step: 2016 +time_step: 1 +alpha_param: 2.0 +beta_param: 1.42 +write_logfile: False +``` + +### Expected outputs +Each time-step processed will generate a TEXT file containing a solution message and have the file name formatted as `output_year_.txt`. These will be written to where the `output_directory` has been assigned. + +## Examples + +### Example 1: Run `im3py` for all years using a configuration file +```python +from im3py.model import Model + +run = Model(config_file="", + start_step=2015, + through_step=2016, + time_step=1, + alpha_param=2.0, + beta_param=1.42, + write_logfile=False) + +run.run_all_steps() +``` + +### Example 3: Run `im3py` by year by passing argument values; update value in between time step +```python +from im3py.model import Model + +run = Model(output_directory="", + start_step=2015, + through_step=2016, + time_step=1, + alpha_param=2.0, + beta_param=1.42, + write_logfile=False) + +# initialize model +run.initialize() + +# downscale year 0 +run.advance_step() + +# update the calibrated alpha parameter value +run.alpha_param = -0.1 + +# run next step with modified parameters +run.advance_step() + +# close out run +run.close() +``` + +### Example 4: Install supplemental data from a remote data source +```python +from im3py import InstallSupplement + +dirpath = '' + +# instantiate class +sup = InstallSupplement(dirpath) + +# fetch and unpack zipped data +sup.fetch_unpack_data() +``` diff --git a/data-raw/gen-maps.R b/data-raw/gen-maps.R deleted file mode 100644 index fe5c939..0000000 --- a/data-raw/gen-maps.R +++ /dev/null @@ -1,129 +0,0 @@ -### Run this script in an interactive session and call \code{devtools::use_data} -### on the resulting outputs. It assumes you are at the package top level -### directory. - -library('gcammaptools') -library('magrittr') -library('dplyr') - -# This function generates six map files, represented as sf objects (see -# https://cran.r-project.org/web/packages/sf/). The default maps supported by -# gcammaptools are: -# - rgn14: The outdated GCAM 14-region boundaries -# - rgn32: The current 32 GCAM regions -# - basin235: The 235 water basins, which are soon replacing AEZs -# - chn: The current 32 GCAM regions with China broken down into 30 -# provinces -# - usa: The current 32 GCAM regions with USA broken down into 51 -# regions (50 states and Washington DC) -# - countries: A standard world map containing country administrative borders -# Additionally, simplified versions of rgn14, rgn32, and basin235 are created. -gen.data <- function() { - - ## Both maps of the GCAM regions are built with the column 'region_name', - # which is not necessary for plotting but is used so that gcam32_colors can - # map to it. - map.rgn14 <- system.file("extdata", "rgn14/GCAM_region.geojson", package = "gcammaptools") %>% - import_mapdata() %>% - dplyr::left_join(lut.rgn14, by = "region_id") %>% - dplyr::rename(region_name = region) %>% sf::st_as_sf() - map.rgn32 <- system.file("extdata", "rgn32/reg32_spart.shp", package = "gcammaptools") %>% - import_mapdata() %>% - dplyr::left_join(lut.rgn32, by = "region_id") %>% - dplyr::rename(region_name = region) %>% sf::st_as_sf() - map.rgn14.simple <- simplify_mapdata(map.rgn14) - map.rgn32.simple <- simplify_mapdata(map.rgn32) - - ## The basin235 map is also provided in detailed and simplified forms. - path.basin235 <- "rgnbasin/Global235_CLM_05_dissolve.geojson" - map.basin235 <- system.file("extdata", path.basin235, package = "gcammaptools") %>% - import_mapdata() %>% - rbind(dplyr::rename(map.rgn14[1, ], basin_name = region_name)) # Add Antarctica - map.basin235.simple <- simplify_mapdata(map.basin235) - - ## The original geoJSON for China is 9.7MB, so it is not included. The - # smaller version was produced by simplifying both the Chinese provinces and - # the GCAM regions, but keeping more detail in the provinces: - # - # orig <- import_mapdata('path/to/original/file/GCAM_China.geojson') - # keeps <- c("China", "Central Asia", "Taiwan") - # simpler <- rbind(simplify_mapdata(orig[!orig$Region %in% keeps , ], 2.5, 0.1), - # simplify_mapdata(orig[orig$Region %in% keeps, ], 0, 0.01)) - # sf::st_write(simpler, "GCAM_China.geojson", layer = "simpler", - # driver = "GeoJSON") - # - # The geojson contains excess information, and only the region names and ids - # are kept for the final map. - map.chn <- system.file("extdata", "rgnchn/GCAM_China.geojson", package = "gcammaptools") %>% - import_mapdata() %>% - dplyr::select(region_name, region_id, geometry) - - ## GCAM USA uses the two letter state abbreviations as the state IDs, so the - # usa lookup table is actually of more use here in the building of the map. - # The USA map is placed on top of the 32-region map to produce a final GCAM - # USA compatable map. - # - # One problem with the defualt map data is that the US-Canada border lacks - # resolution. Because of this, many reprojections caused a gap between the - # the two countries. The problem is addressed below by segmentizing the - # polygon that represents mainland Canada such that it contains no segment - # longer than the resolution specified by 'min.seg'. More information about - # segmentization can be found here: - # http://www.georeference.org/doc/segmentization.htm - path.usa <- system.file("extdata", "rgnusa/us_states_50m.shp", package = "gcammaptools") - map.usa <- import_mapdata(path.usa)[ , c('name', 'geometry')] %>% - dplyr::mutate(name = levels(droplevels(name))) %>% - dplyr::left_join(lut.usa, by = c("name" = "region")) %>% - dplyr::rename(region_name = name) %>% - rbind(dplyr::filter(map.rgn32, region_id != 1)) %>% - sf::st_as_sf() - canada.main <- 273 # Index in map for polygon of Canada's mainland - min.seg <- 1 # Minimum segment length in degrees allowed for polygon - sf::st_geometry(map.usa)[[canada.main]] <- sf::st_segmentize(sf::st_geometry(map.usa)[[canada.main]],min.seg) - - ## The world map of countries is included for completeness' sake, and cannot - # be used with GCAM data as it currently is. - path.countries <- system.file("extdata", "rgnworld/ne_110m_admin_0_countries.shp", package = "gcammaptools") - map.countries <- import_mapdata(path.countries)[,c('admin', 'geometry')] - - devtools::use_data(map.rgn14, map.rgn14.simple, map.rgn32, map.rgn32.simple, - map.basin235, map.basin235.simple, map.chn, map.usa, - map.countries, overwrite=TRUE) -} - -gen.internal <- function() { - ## Read the various region lookup tables, drop region lists, and province - # lists 14-region has just a lookup - lut.rgn14 <- read.csv('inst/extdata/rgn14/lookup.txt', strip.white=TRUE, - stringsAsFactors=FALSE) - - ## 32-region has a lookup and a drop - lut.rgn32 <- read.csv('inst/extdata/rgn32/lookup.txt', strip.white=TRUE, - stringsAsFactors=FALSE) - drop.rgn32 <- read.csv('inst/extdata/rgn32/drop-regions.txt', strip.white=TRUE, - stringsAsFactors=FALSE, header=F) - - ## basins have just a lookup table - lut.basin235 <- read.csv('inst/extdata/rgnbasin/lookup.txt', strip.white=TRUE, - stringsAsFactors=FALSE) - - ## GCAM-china has all three - lut.chn <- read.csv('inst/extdata/rgnchn/lookup.txt', strip.white=TRUE, - stringsAsFactors=FALSE) - drop.chn <- read.csv('inst/extdata/rgnchn/drop-regions.txt', strip.white=TRUE, - stringsAsFactors=FALSE, header=F) - prov.chn <- read.csv('inst/extdata/rgnchn/rgn-name-translation.csv', strip.white=TRUE, - stringsAsFactors=FALSE) - - ## GCAM-USA has a lookup table - lut.usa <- read.csv('inst/extdata/rgnusa/lookup.txt', strip.white=TRUE, - stringsAsFactors=FALSE) - - devtools::use_data(lut.rgn14, lut.rgn32, drop.rgn32, lut.basin235, - lut.chn, drop.chn, prov.chn, lut.usa, - internal=TRUE, overwrite=TRUE) -} - - -gen.internal() -gen.data() diff --git a/data/map.basin235.rda b/data/map.basin235.rda deleted file mode 100644 index a6daff8..0000000 Binary files a/data/map.basin235.rda and /dev/null differ diff --git a/data/map.basin235.simple.rda b/data/map.basin235.simple.rda deleted file mode 100644 index 0603bc9..0000000 Binary files a/data/map.basin235.simple.rda and /dev/null differ diff --git a/data/map.chn.rda b/data/map.chn.rda deleted file mode 100644 index 64dd775..0000000 Binary files a/data/map.chn.rda and /dev/null differ diff --git a/data/map.countries.rda b/data/map.countries.rda deleted file mode 100644 index 8f328af..0000000 Binary files a/data/map.countries.rda and /dev/null differ diff --git a/data/map.rgn14.rda b/data/map.rgn14.rda deleted file mode 100644 index ef3a5a5..0000000 Binary files a/data/map.rgn14.rda and /dev/null differ diff --git a/data/map.rgn14.simple.rda b/data/map.rgn14.simple.rda deleted file mode 100644 index 2aa3304..0000000 Binary files a/data/map.rgn14.simple.rda and /dev/null differ diff --git a/data/map.rgn32.rda b/data/map.rgn32.rda deleted file mode 100644 index 4de5f19..0000000 Binary files a/data/map.rgn32.rda and /dev/null differ diff --git a/data/map.rgn32.simple.rda b/data/map.rgn32.simple.rda deleted file mode 100644 index a17fa10..0000000 Binary files a/data/map.rgn32.simple.rda and /dev/null differ diff --git a/data/map.usa.rda b/data/map.usa.rda deleted file mode 100644 index 6b4ee8b..0000000 Binary files a/data/map.usa.rda and /dev/null differ diff --git a/inst/data/TM_WORLD_BORDERS_SIMPL-0.3.dbf b/inst/data/TM_WORLD_BORDERS_SIMPL-0.3.dbf new file mode 100644 index 0000000..64ea895 Binary files /dev/null and b/inst/data/TM_WORLD_BORDERS_SIMPL-0.3.dbf differ diff --git a/inst/data/TM_WORLD_BORDERS_SIMPL-0.3.prj b/inst/data/TM_WORLD_BORDERS_SIMPL-0.3.prj new file mode 100644 index 0000000..f45cbad --- /dev/null +++ b/inst/data/TM_WORLD_BORDERS_SIMPL-0.3.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] \ No newline at end of file diff --git a/inst/data/TM_WORLD_BORDERS_SIMPL-0.3.shp b/inst/data/TM_WORLD_BORDERS_SIMPL-0.3.shp new file mode 100644 index 0000000..63e155c Binary files /dev/null and b/inst/data/TM_WORLD_BORDERS_SIMPL-0.3.shp differ diff --git a/inst/data/TM_WORLD_BORDERS_SIMPL-0.3.shx b/inst/data/TM_WORLD_BORDERS_SIMPL-0.3.shx new file mode 100644 index 0000000..18af94b Binary files /dev/null and b/inst/data/TM_WORLD_BORDERS_SIMPL-0.3.shx differ diff --git a/inst/data/data.csv b/inst/data/data.csv new file mode 100644 index 0000000..e00fd71 --- /dev/null +++ b/inst/data/data.csv @@ -0,0 +1,184 @@ +Country,2016,2015,2010,2005,2000 +Afghanistan,53,53.2,51.6,49.6,46.9 +Albania,68.1,67.8,66.4,65.4,64.9 +Algeria,65.5,65.3,64.5,62.8,60.7 +Angola,55.8,55.3,51.8,46.7,41.9 +Antigua and Barbuda,67,66.9,66.5,65.4,64.6 +Argentina,68.4,68.2,67.3,66.7,65.7 +Armenia,66.3,66,65.2,64.7,63.8 +Australia,73,72.7,72.2,71.4,70.3 +Austria,72.4,72.1,71.4,70.6,69.5 +Azerbaijan,64.9,64.6,63.4,61.5,59.6 +Bahamas,66.8,66.7,66.4,65.1,63.7 +Bahrain,68.1,67.7,66.3,64.5,63 +Bangladesh,63.3,62.8,60.7,58.6,56.5 +Barbados,67,66.8,66.2,65.8,65.1 +Belarus,65.5,65.2,62.3,60.8,60.8 +Belgium,71.6,71.4,70.8,69.9,68.9 +Belize,62.5,62.3,61.9,61.4,61 +Benin,53.5,53.1,51.7,49.7,48.4 +Bhutan,60.7,60.2,58.7,56.2,52.6 +Bolivia (Plurinational State of),63,62.7,61,58.5,56 +Bosnia and Herzegovina,67.2,66.9,66.7,65.6,65.5 +Botswana,57.5,56.8,52.9,45.3,42.7 +Brazil,66,65.8,64.5,63.3,61.5 +Brunei Darussalam,67.9,67.7,67.9,67.6,65.9 +Bulgaria,66.4,66.2,65.7,64.7,63.7 +Burkina Faso,52.9,52.4,49.7,45.9,43.1 +Burundi,52.6,52.2,50.3,47.1,44.6 +Cabo Verde,64.5,64.3,63.1,61.9,60.7 +Cambodia,60.8,60.4,58.5,54.5,50 +Cameroon,51.1,50.3,48.3,45.4,42.9 +Canada,73.2,73,72.2,71.3,70.4 +Central African Republic,44.9,44.6,42.7,39.7,39.2 +Chad,47.2,46.7,45.1,42.7,41.5 +Chile,69.7,69.6,68.9,68.6,67.8 +China,68.7,68.4,67.6,66.7,64.8 +Colombia,67.1,66.8,65.7,65.1,63.4 +Comoros,56.6,56.3,54.7,53,52.3 +Congo,56.7,56.1,54.2,49.2,46.4 +Costa Rica,70.9,70.7,69.7,70,69 +Côte d'Ivoire,48.3,47.7,46.2,44.1,43.1 +Croatia,69,68.4,67.9,66.6,65.9 +Cuba,69.9,69.6,69,68.3,67.7 +Cyprus,73.3,73.1,72.4,71.2,70.5 +Czechia,69.3,68.8,68.1,67,66.2 +Democratic People's Republic of Korea,64.6,64.4,62.3,61.5,58.3 +Democratic Republic of the Congo,52.5,52.1,49.9,47.1,44.4 +Denmark,71.8,71.5,70.4,69.6,68.6 +Djibouti,56.6,56.3,54.3,51.7,50.4 +Dominican Republic,65.2,64.9,63.8,62.4,61.8 +Ecuador,67.9,67.6,66.8,65.9,64.3 +Egypt,61.1,60.8,60,59.7,59.1 +El Salvador,65.5,65.2,64.2,62.6,61.3 +Equatorial Guinea,53.8,53.6,51.2,48.6,47 +Eritrea,57.4,57.1,55.3,52.9,39.6 +Estonia,68.2,68,66.7,64.4,62.6 +Eswatini,50.2,49.9,44.2,38.5,42.3 +Ethiopia,57.5,57,54,48.6,44.5 +Fiji,61.3,61.2,60.4,59.7,59.1 +Finland,71.7,71.6,70.4,69.6,68.5 +France,73.4,73.2,72.2,71.3,70.3 +Gabon,58.7,58.2,54.8,52.3,51.8 +Gambia,54.4,54.1,52.5,51,49.1 +Georgia,64.9,65.1,64.8,65.2,64 +Germany,71.6,71.3,70.9,70.2,69.2 +Ghana,56.4,56,54.1,51.9,50.6 +Greece,72,71.8,71.5,70.5,69.6 +Grenada,64.7,64.6,64,62.9,62.4 +Guatemala,64.2,63.9,62.1,60.4,59.1 +Guinea,52.2,51.1,50,47.1,45 +Guinea-Bissau,51.7,51.2,48.8,46.4,45 +Guyana,58.3,58.2,57.8,56.9,56.8 +Haiti,55.3,55.1,32.3,52.5,50.3 +Honduras,66.8,66.6,65.5,64.3,62.8 +Hungary,66.8,66.4,65.6,64.6,63.5 +Iceland,73,73,72.6,71.9,70.7 +India,59.3,58.9,57.4,55.3,53.5 +Indonesia,61.7,61.5,60.4,59.7,58.7 +Iran (Islamic Republic of),65.4,65.1,63.9,62,60.6 +Iraq,59,58.4,59.6,56.4,58.4 +Ireland,72.1,72,71.5,69.8,67.8 +Israel,72.9,72.7,72.4,70.8,69.7 +Italy,73.2,73,72.8,71.9,70.6 +Jamaica,66.9,66.7,66.1,64.6,64.1 +Japan,74.8,74.7,73.8,73.2,72.5 +Jordan,66.4,66.2,64.7,63.5,62.9 +Kazakhstan,63.4,62.8,60.2,57.7,57 +Kenya,58.9,58.3,55.5,48.9,47.1 +Kiribati,57.8,57.6,57.5,55,55.8 +Kuwait,66.3,66.1,64.6,63.8,63.7 +Kyrgyzstan,63.5,63.2,61.1,59.7,59.1 +Lao People's Democratic Republic,57.9,57.5,56,53.4,50.7 +Latvia,66.2,65.9,64.6,62.8,62.2 +Lebanon,66.1,65.6,65.2,64.6,63.1 +Lesotho,46.6,45.9,45.7,40,44.5 +Liberia,54.5,53.7,51.6,47.5,44.6 +Libya,62.3,62.3,62.9,62.1,61.3 +Lithuania,66.1,65.5,64.5,62.8,63.4 +Luxembourg,72.6,72.6,71.7,70.4,69.3 +Madagascar,58.3,57.9,55.8,53.6,51.2 +Malawi,56.2,55.5,50.4,43.5,40.2 +Malaysia,66.6,66.4,65.6,64.8,64.2 +Maldives,69.8,69.4,67.6,65.3,61.1 +Mali,50.7,50.2,48.4,45.3,41.4 +Malta,72.2,72.2,71.6,70.5,69.8 +Mauritania,56.4,56.1,54.5,53.1,52.4 +Mauritius,65.8,65.5,64.5,63.8,62.6 +Mexico,67.7,67.4,66.5,66.2,65.6 +Micronesia (Federated States of),61.1,60.8,60.3,59.4,58.7 +Mongolia,61.9,61.7,60.2,57.9,55.8 +Montenegro,68.1,67.9,67.1,65.6,64.9 +Morocco,65.3,65,63.5,61.4,58.8 +Mozambique,52.2,51.2,47.6,44.1,42 +Myanmar,58.4,58.1,56.3,54.9,53.4 +Namibia,55.9,55.6,53.4,47.2,49.1 +Nepal,61.3,60.2,59.2,56.7,54.2 +Netherlands,72.1,72,71.4,70.4,69.2 +New Zealand,72.8,72.6,72,71,69.8 +Nicaragua,66.9,66.6,65.5,63.8,61.9 +Niger,52.5,52,49.4,45.6,42.1 +Nigeria,48.9,48.5,46.2,43.6,41.5 +Norway,73,72.9,71.8,71.2,69.9 +Oman,65.6,65.5,65.5,64.4,63.1 +Pakistan,57.7,57.3,56.2,54.2,54.3 +Panama,69.4,69.3,68.3,67.8,67.4 +Papua New Guinea,58,57.8,56.9,55.5,54.6 +Paraguay,65.3,65.1,64.5,63.4,62.7 +Peru,67.5,67.2,66.3,65.1,63.3 +Philippines,61.7,61.6,60.6,59.6,59.2 +Poland,68.5,68.1,67.3,66.3,65.4 +Portugal,72,71.8,70.8,69.6,68.2 +Qatar,68.6,68.3,66.7,66.1,65.4 +Republic of Korea,73,72.7,71.4,69.9,68.1 +Republic of Moldova,63.6,62.9,61.3,60.4,60 +Romania,66.6,66.3,65.2,64,63.1 +Russia,63.5,63.1,61,58.1,58 +Rwanda,59.9,55.5 59.3,56.2,48.3,38.0 40.7 +Saint Lucia,66.4,66.3,65.7,64,63.6 +Saint Vincent and the Grenadines,63.4,63.6,63.4,62.6,62.3 +Samoa,66,65.7,64.4,63.1,61.8 +Sao Tome and Principe,60.7,60.5,59,57.1,55.3 +Saudi Arabia,65.7,65.4,64.4,63.5,62.7 +Senegal,58.8,58.4,56.1,52.7,49.9 +Serbia,67.4,67,66.2,65.2,64.3 +Seychelles,65.7,65.5,64.6,64.4,64.1 +Sierra Leone,47.6,46,43.9,39.4,35.6 +Singapore,76.2,75.9,74.8,73.3,71.3 +Slovakia,68.3,68,66.8,65.8,64.9 +Slovenia,70.5,70.2,69.2,67.7,66.6 +Solomon Islands,61.9,61.7,60.6,59.3,58 +Somalia,50,50.1,47.6,46.2,45.6 +South Africa,55.7,55.3,50.5,47.4,51.2 +South Sudan,50.6,50.2,48.4,45.1,42.6 +Spain,73.8,73.5,72.9,71.5,70.6 +Sri Lanka,66.8,66.6,66.1,65.7,63.4 +Sudan,55.7,55.4,54,52.5,50.3 +Suriname,63.2,62.9,61.8,60.4,59.5 +Sweden,72.4,72.3,71.9,71.2,70.4 +Switzerland,73.5,73.2,72.5,71.3,70.1 +Syrian Arab Republic,55.8,55.2,64.1,63.6,63.1 +Tajikistan,63.5,63.2,62.4,60.2,58.3 +Thailand,66.8,66.6,65.5,63.8,62.2 +Republic of North Macedonia,67.1,66.9,66.5,65.9,65 +Timor-Leste,59.2,58.6,57.3,55,51.5 +Togo,53.9,53.5,51.1,48.8,48.2 +Tonga,64.3,64.2,63.7,63.4,62.7 +Trinidad and Tobago,63.3,63.1,62.4,61.6,61.2 +Tunisia,66.3,66,65.1,64.4,63.2 +Turkey,66,65.6,64.4,62.6,60.6 +Turkmenistan,61.4,61,59.8,58,56.9 +Uganda,54.9,54.5,50.4,45.5,40 +Ukraine,64,63.7,62.2,59.6,60 +United Arab Emirates,66.7,66.5,66.4,65.8,64.9 +United Kingdom of Great Britain and Northern Ireland,71.9,71.7,71.3,69.9,69 +United Republic of Tanzania,56.5,56,52.3,47.8,44.6 +United States,68.5,68.6,68.7,67.9,67.4 +Uruguay,68.8,68.7,68,67.3,66.6 +Uzbekistan,64.5,64.2,63.2,61,59.8 +Vanuatu,62.7,62.5,62,61,60.1 +Venezuela,66.1,65.9,65.7,65.4,64.3 +Viet Nam,67.5,67.3,66.5,65.7,64.3 +Yemen,55.1,54.3,54.3,52.8,50.6 +Zambia,54.3,53.8,50.1,42.8,39.1 +Zimbabwe,54.4,53.8,46.7,40.3,40.5 diff --git a/man/EXTENT_AFRICA.Rd b/man/EXTENT_AFRICA.Rd deleted file mode 100644 index e4b6aaa..0000000 --- a/man/EXTENT_AFRICA.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/diag_header.R -\docType{data} -\name{EXTENT_AFRICA} -\alias{EXTENT_AFRICA} -\title{Extent vector for Africa} -\format{An object of class \code{numeric} of length 4.} -\usage{ -EXTENT_AFRICA -} -\description{ -This vector can be used as the \code{extent} argument to -\code{\link{plot_GCAM}}. -} -\keyword{datasets} diff --git a/man/EXTENT_CHINA.Rd b/man/EXTENT_CHINA.Rd deleted file mode 100644 index fcbe422..0000000 --- a/man/EXTENT_CHINA.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/diag_header.R -\docType{data} -\name{EXTENT_CHINA} -\alias{EXTENT_CHINA} -\title{Extent vector for China} -\format{An object of class \code{numeric} of length 4.} -\usage{ -EXTENT_CHINA -} -\description{ -This vector can be used as the \code{extent} argument to -\code{\link{plot_GCAM}}. -} -\keyword{datasets} diff --git a/man/EXTENT_LA.Rd b/man/EXTENT_LA.Rd deleted file mode 100644 index c4e854f..0000000 --- a/man/EXTENT_LA.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/diag_header.R -\docType{data} -\name{EXTENT_LA} -\alias{EXTENT_LA} -\title{Extent vector for Latin America} -\format{An object of class \code{numeric} of length 4.} -\usage{ -EXTENT_LA -} -\description{ -This vector can be used as the \code{extent} argument to -\code{\link{plot_GCAM}}. -} -\keyword{datasets} diff --git a/man/EXTENT_USA.Rd b/man/EXTENT_USA.Rd deleted file mode 100644 index 86d2d12..0000000 --- a/man/EXTENT_USA.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/diag_header.R -\docType{data} -\name{EXTENT_USA} -\alias{EXTENT_USA} -\title{Extent vector for the continental United States} -\format{An object of class \code{numeric} of length 4.} -\usage{ -EXTENT_USA -} -\description{ -This vector can be used as the \code{extent} argument to -\code{\link{plot_GCAM}}. -} -\keyword{datasets} diff --git a/man/EXTENT_WORLD.Rd b/man/EXTENT_WORLD.Rd deleted file mode 100644 index 2f7eb2c..0000000 --- a/man/EXTENT_WORLD.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/diag_header.R -\docType{data} -\name{EXTENT_WORLD} -\alias{EXTENT_WORLD} -\title{Extent vector for the entire world} -\format{An object of class \code{numeric} of length 4.} -\usage{ -EXTENT_WORLD -} -\description{ -This vector can be used as the \code{extent} argument to -\code{\link{plot_GCAM}}. -} -\keyword{datasets} diff --git a/man/add_region_ID.Rd b/man/add_region_ID.Rd deleted file mode 100644 index b433081..0000000 --- a/man/add_region_ID.Rd +++ /dev/null @@ -1,43 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gcam_data_processing.R -\name{add_region_ID} -\alias{add_region_ID} -\title{Match GCAM ID to region using data from a lookup table.} -\usage{ -add_region_ID(datatable, lookupfile = rgn32, provincefile = NULL, - drops = NULL, disaggregate = NULL) -} -\arguments{ -\item{datatable}{A table of results produced by \code{\link[rgcam]{getQuery}}} - -\item{lookupfile}{Name of one of the predefined map sets, OR, if you're using -a custom map set, the file containing the region lookup table} - -\item{provincefile}{Name of one of the predefined map sets, OR, if you're -using a custom map set, file containing the province lookup table, if -applicable.} - -\item{drops}{Name of one of the predefined map sets, OR, if you're using -a custom map set, the file containing a list of regions to drop, if -applicable.} - -\item{disaggregate}{A column (or vector of columns) of \code{datatable} used -to disaggregate regions that are not specified in the original data.} -} -\value{ -Input table modified to include a GCAM ID for reach region. -} -\description{ -We match by ID number to avoid problems with variant spellings and the like. -With the optional arguments you can also omit regions for which you don't -want to plot the data for some reason, and you can translate the -abbreviations used in subregion output. -} -\details{ -The \code{provincefile} and \code{drops} arguments are a little clunky. They -are optional, but if you are using one of the built-in map sets, then you -\emph{must not} specify them if they don't exist for the map set you are -using. Currently, \code{rgn14} and \code{basin235} have neither drops nor -province abbreviations. The \code{rgn32} set has drops, but not province -abbreviations. Only the \code{chn} set has both. -} diff --git a/man/af_ortho.Rd b/man/af_ortho.Rd deleted file mode 100644 index 6cf7e04..0000000 --- a/man/af_ortho.Rd +++ /dev/null @@ -1,16 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/diag_header.R -\docType{data} -\name{af_ortho} -\alias{af_ortho} -\title{Proj4 string for orthographic projection over Africa} -\format{An object of class \code{character} of length 1.} -\usage{ -af_ortho -} -\description{ -String for specifying the orthographic projection over Africa. You can pass -this value to the \code{proj} argument of \code{\link{plot_GCAM}} to get the -best result. -} -\keyword{datasets} diff --git a/man/assign_prj4s.Rd b/man/assign_prj4s.Rd index d9826e6..4b1377b 100644 --- a/man/assign_prj4s.Rd +++ b/man/assign_prj4s.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/utils.R +% Please edit documentation in R/spatial_utils.R \name{assign_prj4s} \alias{assign_prj4s} \title{Helper function for assigning a Proj4 string from several possible inputs.} diff --git a/man/basin235.Rd b/man/basin235.Rd deleted file mode 100644 index dc13bdd..0000000 --- a/man/basin235.Rd +++ /dev/null @@ -1,14 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Map_Functions.R -\docType{data} -\name{basin235} -\alias{basin235} -\title{Designator for the basin235 map set} -\format{An object of class \code{name} of length 1.} -\usage{ -basin235 -} -\description{ -This symbol will select the basin235 map set -} -\keyword{datasets} diff --git a/man/ch_aea.Rd b/man/ch_aea.Rd deleted file mode 100644 index 470318c..0000000 --- a/man/ch_aea.Rd +++ /dev/null @@ -1,17 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/diag_header.R -\docType{data} -\name{ch_aea} -\alias{ch_aea} -\title{Proj4 string for the Albers equal area projection over China} -\format{An object of class \code{character} of length 1.} -\usage{ -ch_aea -} -\description{ -String for specifying the Albers equal area projection over China -in mapping functions. This is a conic projection situatied over -China. Its value is \code{'+proj=aea +lat_1=20 +lat_2=60 +lat_0=40 -+lon_0=-96 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84'} -} -\keyword{datasets} diff --git a/man/chn.Rd b/man/chn.Rd deleted file mode 100644 index 467de4e..0000000 --- a/man/chn.Rd +++ /dev/null @@ -1,14 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Map_Functions.R -\docType{data} -\name{chn} -\alias{chn} -\title{Designator for the chn map set} -\format{An object of class \code{name} of length 1.} -\usage{ -chn -} -\description{ -This symbol will select the chn map set -} -\keyword{datasets} diff --git a/man/choropleth.Rd b/man/choropleth.Rd new file mode 100644 index 0000000..0eba195 --- /dev/null +++ b/man/choropleth.Rd @@ -0,0 +1,97 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/maps.R +\name{choropleth} +\alias{choropleth} +\title{Dynamic choropleth map creation} +\usage{ +choropleth( + shape_data = NULL, + map_data = NULL, + data_col = NULL, + data_key_field = NULL, + shape_key_field = NULL, + output_file = NULL, + map_title = NULL, + shape_data_field = NULL, + shape_geom_field = "geometry", + simplify = FALSE, + bin_method = "pretty", + bins = 8, + map_legend_title = "", + map_palette_type = "seq", + map_palette = NULL, + map_palette_reverse = FALSE, + shape_label_field = NULL, + shape_label_size = 3, + map_width_height_in = c(15, 10), + shape_xy_fields = c("LON", "LAT"), + dpi = 150, + expand_xy = c(0, 0), + map_xy_min_max = c(-180, 180, -90, 90), + map_x_label = "Lon", + map_y_label = "Lat", + map_font_adjust = 1 +) +} +\arguments{ +\item{shape_data}{(SF or Character) - Either the full path string to a shape file (with all necessary files) or an SF shape object} + +\item{map_data}{(Data Frame or Character) - A data frame that contains the output data to map, or alternatively a full path to a CSV} + +\item{data_col}{(Character) - Column name that contains the data object's output variable} + +\item{data_key_field}{(Character) - Name of key field in data_obj for merging with shape_data} + +\item{shape_key_field}{(Character) - Name of key field in shape object for merging with map_data object} + +\item{output_file}{(Character) - Output file path and file name and type to save the resulting plot (e.g. "c:/temp/output.png") (Types accepted: "eps", "ps", "tex", "pdf", "jpeg", "tiff", "png", "bmp", "svg")} + +\item{map_title}{(Character) - Title to be displayed at the top of the output map} + +\item{shape_data_field}{(Character) - Optional field for utilizing a field within the shape data as the map data field. Negates the map_data variable} + +\item{shape_geom_field}{(Character) - Specifies field within shape object that contains needed geometry (default "geometry")} + +\item{simplify}{(Boolean) - Option to reduce the number and complexity of the polygons in the shape file (default FALSE)} + +\item{bin_method}{(Character) - Method or function to use to split continuous data into discrete chunks (one of "quantile", "equal", "pretty", "kmeans") (default "pretty")} + +\item{bins}{(Numeric) - Number of bins, or segments, in which to divide the raster (default 8)} + +\item{map_legend_title}{(Character) - Text variable to be used for the legend header} + +\item{map_palette_type}{(Character) - Variable to load default palette by type of data ("qual" for qualitative data, "seq" for sequential data, "div" for divergent data) (default "seq")} + +\item{map_palette}{(Character) - Variable to hold the type of colorscale to be used from the RColorBrewer palette (default "RdYlBu")} + +\item{map_palette_reverse}{(Boolean) - Set palette to reverse direction TRUE or FALSE} + +\item{shape_label_field}{(Character) - Optional field for plotting map labels from the shape attributes (such as country name)} + +\item{map_width_height_in}{(c(Numeric, Numeric)) - Vector that describes the desired file size of the output image in the form of (width, height) in inches (defalt c(15, 10))} + +\item{shape_xy_fields}{(c(Character, Character)) - Vector that specifies the x and y field names in the shape object (default c("LAT", "LON"))} + +\item{dpi}{(Numeric) - Settable DPI for different print and screen formats (default 150)} + +\item{expand_xy}{(c(Numeric, Numeric)) - Sets expansion or buffer amount for the X and Y scales of the map - Vector (expand x, expand y) (default c(0,0))} + +\item{map_xy_min_max}{(c(Numeric, ...)) - Vector that describes the desired extent of the map in the form of (xmin, xmax, ymin, ymax) (default: c(-180, 180, -90, 90))} + +\item{map_x_label}{(Character) - Label for x axis (default "Lon")} + +\item{map_y_label}{(Character) - Label for y axis (default "Lat")} + +\item{map_font_adjust}{(Numeric) - A number between 0.2 and 2 that scales the map fonts either up or down (0.2 = 80% smaller, 2 = 200% bigger)} + +\item{shape_label_size_field}{(Character) - Optional field used for computing shape label size dynamically (ie by area or amount etc.) (Default "1")} +} +\value{ +(ggplot2 or Character) - Returns a ggplot object of the resulting map or an error string if failed +} +\description{ +Create a choropleth map object from shape and data object and return, save (optional) the output +} +\author{ +Jason Evanoff, jason.evanoff@pnnl.gov +} diff --git a/man/custom_map.Rd b/man/custom_map.Rd new file mode 100644 index 0000000..1396483 --- /dev/null +++ b/man/custom_map.Rd @@ -0,0 +1,76 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/maps.R +\name{custom_map} +\alias{custom_map} +\title{Create a basic map object from input shape and-or raster.} +\usage{ +custom_map( + shape_data = NULL, + raster_data = NULL, + raster_col = NULL, + shape_label_field = NULL, + shape_label_size = "1", + simplify = FALSE, + raster_band = 1, + convert_zero = FALSE, + dpi = 150, + output_file = NULL, + expand_xy = c(0, 0), + map_xy_min_max = c(-180, 180, -90, 90), + map_title = NULL, + map_palette = "RdYlBu", + map_palette_reverse = FALSE, + map_width_height_in = c(15, 10), + map_legend_title = NULL, + map_x_label = "Longitude", + map_y_label = "Latitude" +) +} +\arguments{ +\item{shape_data}{(SF, SP, or Character) - Either the full path string to a shape file (with all necessary files) or an SF shape object} + +\item{raster_data}{(Raster or Character) - Either the full path string to a raster file or an object of type RasterLayer} + +\item{raster_col}{(Character) - Raster field name that contains the desired output variable} + +\item{shape_label_field}{(Character) - Optional field for plotting map labels from the shape attributes (such as country name)} + +\item{simplify}{(Boolean) - Option to reduce the number or complexity of the polygons in the shape file (default FALSE)} + +\item{raster_band}{(Numeric) - Variable for dealing with multi band or time series rasters that specifices which raster band to use (Default 1)} + +\item{convert_zero}{(Boolean) - Convert values within the raster data from zero to NA (default FALSE)} + +\item{dpi}{(Numeric) - Settable DPI for different print and screen formats (default 150)} + +\item{output_file}{(Character) - Output file path and file name and type to save the resulting plot (e.g. "c:/temp/output.png") (Types accepted: "eps", "ps", "tex", "pdf", "jpeg", "tiff", "png", "bmp", "svg")} + +\item{expand_xy}{(c(Numeric, Numeric)) - Sets expansion amount for the X and Y scales of the map - Vector (expand x, expand y) (default c(0,0))} + +\item{map_xy_min_max}{(c(Numeric, ...)) - Vector that describes the desired extent of the map in the form of (xmin, xmax, ymin, ymax) (default: c(-180, 180, -90, 90))} + +\item{map_title}{(Character) - Title to be displayed at the top of the output map} + +\item{map_palette}{(Character) - Variable to hold the type of colorscale to be used from the RColorBrewer palette (default "RdYlBu")} + +\item{map_palette_reverse}{(Boolean) - Set palette to reverse direction TRUE or FALSE} + +\item{map_width_height_in}{(c(Numeric, Numeric)) - Vector that describes the desired file size of the output image in the form of (width, height) in inches (defalt c(15, 10))} + +\item{map_legend_title}{(Character) - Text variable to be used for the legend header} + +\item{map_x_label}{(Character) - Label for x axis (default "Lon")} + +\item{map_y_label}{(Character) - Label for y axis (default "Lat")} + +\item{shape_label_size_field}{(Character) - Optional field used for computing shape label size dynamically (ie by area or amount etc.) (Default "1")} +} +\value{ +(ggplot2 or Character) - Returns a ggplot object of the resulting map or an error string if failed +} +\description{ +This function is designed to take both a shape and raster object or path and create a standardized output map. Option to save the output to file +} +\author{ +Jason Evanoff, jason.evanoff@pnnl.gov +} diff --git a/man/distributed_flow.Rd b/man/distributed_flow.Rd new file mode 100644 index 0000000..3bf571a --- /dev/null +++ b/man/distributed_flow.Rd @@ -0,0 +1,91 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/maps.R +\name{distributed_flow} +\alias{distributed_flow} +\title{Distributed flow map} +\usage{ +distributed_flow( + shape_data = NULL, + shape_key_field = NULL, + shape_label_field = NULL, + shape_label_size = "1", + shape_xy_fields = c("LON", "LAT"), + shape_geom_field = "geometry", + simplify = FALSE, + map_data = NULL, + data_key_field = NULL, + data_col = NULL, + bin_method = "pretty", + bins = NULL, + dpi = 150, + output_file = NULL, + expand_xy = c(0, 0), + map_xy_min_max = c(-180, 180, -90, 90), + map_title = NULL, + map_palette = NULL, + map_palette_reverse = FALSE, + map_palette_type = "seq", + map_width_height_in = c(15, 10), + map_legend_title = NULL, + map_x_label = "Lon", + map_y_label = "Lat" +) +} +\arguments{ +\item{shape_data}{(SF, SP, or Character) - Either the full path string to a shape file (with included necessary files) or an SF shape object} + +\item{shape_key_field}{(Character) - Name of key field in shape object for merging with map_data object} + +\item{shape_label_field}{(Character) - Optional field for plotting data available from the shape attributes or fields (such as country name)} + +\item{shape_xy_fields}{(c(Character, Character)) - Vector that specifies the x and y field names in the shape object (default c("LAT", "LON"))} + +\item{shape_geom_field}{(Character) - Specifies field within shape object that contains needed geometry (default "geometry")} + +\item{simplify}{(Boolean) - Option to reduce the number and complexity of the polygons in the shape file (default FALSE)} + +\item{map_data}{(Data Frame or Character) - A data frame that contains the output data to map, or alternatively a full path to a CSV} + +\item{data_key_field}{(Character) - Name of key field in data_obj for merging with shape_data} + +\item{data_col}{(Character) - Column name that contains the data object's output variable} + +\item{bin_method}{(Character) - Method or function to use to split continuous data into discrete chunks (one of "quantile", "equal", "pretty", "kmeans") (default "pretty")} + +\item{bins}{(Numeric) - Number of bins or segments in which to divide the raster} + +\item{dpi}{(Numeric) - Settable DPI for different print and screen formats (default 150)} + +\item{output_file}{(Character) - Output file path and file name and type to save the resulting plot (e.g. "c:/temp/output.png") (Types accepted: "pdf", "jpeg", "tiff", "png", "bmp", "svg", "eps", "ps", "tex") (default PNG)} + +\item{expand_xy}{(c(Numeric, Numeric)) - Sets expansion amount for the X and Y scale of the map - Vector (expand x, expand y) (default c(0,0))} + +\item{map_xy_min_max}{(c(Numeric, ...)) - Vector that describes the desired extent of the map in the form of (xmin, xmax, ymin, ymax) (default: c(-180, 180, -90, 90))} + +\item{map_title}{(Character) - Title to be displayed on the output map} + +\item{map_palette}{(Character) - Optional variable to manually set the colorscale to a specific palette from RColorbrewer} + +\item{map_palette_reverse}{(Boolean) - Set palette to reverse direction TRUE or FALSE} + +\item{map_palette_type}{(Character) - Variable to load default palette by type of data ("qual" for qualitative data, "seq" for sequential data, "div" for divergent data) (default "seq")} + +\item{map_width_height_in}{(c(Numeric, Numeric)) - Vector that describes the desired file size of the output image in the form of (width, height) in inches (default c(15, 10))} + +\item{map_legend_title}{(Character) - Text for the legend header} + +\item{map_x_label}{(Character) - Label for x axis (default Lon)} + +\item{map_y_label}{(Character) - Label for y axis (default Lat)} + +\item{shape_label_size_field}{(Character) - Optional field used for computing shape label size dynamically (ie by area or amount etc.)} +} +\value{ +(ggplot2 or Character) - Returns a ggplot object of the resulting map or an error string if failed +} +\description{ +Create a distributed flow map object from shape and data object and return, save (optional) the output +} +\author{ +Jason Evanoff, jason.evanoff@pnnl.gov +} diff --git a/man/drop_regions.Rd b/man/drop_regions.Rd deleted file mode 100644 index 2c13b4b..0000000 --- a/man/drop_regions.Rd +++ /dev/null @@ -1,19 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gcam_data_processing.R -\name{drop_regions} -\alias{drop_regions} -\title{Drop regions listed in drops file from data frame.} -\usage{ -drop_regions(datatable, drops) -} -\arguments{ -\item{datatable}{A data frame containing the output of a GCAM query.} - -\item{drops}{String; path to file containing regions to be dropped} -} -\value{ -An updated data frame with regions dropped. -} -\description{ -Drop regions listed in drops file from data frame. -} diff --git a/man/eck3.Rd b/man/eck3.Rd deleted file mode 100644 index 5607e35..0000000 --- a/man/eck3.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/diag_header.R -\docType{data} -\name{eck3} -\alias{eck3} -\title{Proj4 string for the Eckert III World projection} -\format{An object of class \code{character} of length 1.} -\usage{ -eck3 -} -\description{ -String for specifying the Eckert III projection in mapping functions. -Its value is \code{'+proj=eck3'} -} -\keyword{datasets} diff --git a/man/filter_spatial.Rd b/man/filter_spatial.Rd deleted file mode 100644 index a0e31b0..0000000 --- a/man/filter_spatial.Rd +++ /dev/null @@ -1,24 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Map_Functions.R -\name{filter_spatial} -\alias{filter_spatial} -\title{Get features topologically associated with extent bounds.} -\usage{ -filter_spatial(mapdata, bbox, agr_type = "constant", - topo = sf::st_intersects) -} -\arguments{ -\item{mapdata}{The sf object containing the spatial data.} - -\item{bbox}{Bounding box.} - -\item{agr_type}{Inherited attribute-geometry-relationship type from plot_GCAM -function params.} - -\item{topo}{SF topologic function to define how the join will be conducted. -Default is to join any feature that intersects the bounding box.} -} -\description{ -Conducts a spatial join to retrieve spatial features that are topologically associated -(intersects, contains, within, etc.) with the provided bounds. -} diff --git a/man/gcam14_colors.Rd b/man/gcam14_colors.Rd deleted file mode 100644 index 692aa10..0000000 --- a/man/gcam14_colors.Rd +++ /dev/null @@ -1,17 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/diag_header.R -\docType{data} -\name{gcam14_colors} -\alias{gcam14_colors} -\title{Color palette for 14-region GCAM} -\format{An object of class \code{character} of length 14.} -\usage{ -gcam14_colors -} -\description{ -This palette should be used for plots by region (whether maps, line plots, or -other types) to ensure consistency across plots and publications. XXX: -Perhaps this sort of thing should go in a separate GCAM style package, since -it isn't really specific to mapping? -} -\keyword{datasets} diff --git a/man/gcam32_colors.Rd b/man/gcam32_colors.Rd deleted file mode 100644 index ca2f58f..0000000 --- a/man/gcam32_colors.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/diag_header.R -\docType{data} -\name{gcam32_colors} -\alias{gcam32_colors} -\title{Color palette for 32-region GCAM} -\format{An object of class \code{character} of length 32.} -\usage{ -gcam32_colors -} -\description{ -This palette should be used for plots by region (whether maps, line plots, or -other types) to ensure consistency across plots and publications. -} -\keyword{datasets} diff --git a/man/gcammaptools.Rd b/man/gcammaptools.Rd deleted file mode 100644 index d15dd12..0000000 --- a/man/gcammaptools.Rd +++ /dev/null @@ -1,49 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gcammaptools.R -\docType{package} -\name{gcammaptools} -\alias{gcammaptools} -\alias{gcammaptools-package} -\title{gcammaptools: A package for plotting GCAM data on maps} -\description{ -The gcammaptools package provides functions for plotting GCAM data on world -or regional maps. This includes functions for making plots for regional or -gridded data, as well as default projection and theme settings that provide a -house style for GCAM plots. -} -\section{Preparing GCAM data}{ - - -The recommended way to load your GCAM data is by using the \code{rgcam} -package create a project data file from a GCAM database, and then querying -that file for the data you want to plot. Alternatively, you can start with -any data frame that has a `region` column and one or more data columns. - -Once you have loaded the data, you must add the region identifiers used in -the map data to the data frame using the \code{add_region_ID} function. -} - -\section{Mapping GCAM data}{ - - -To map GCAM data, you will need a simple feature collection or geojson with -your region boundaries. The package provides the following commonly-used -base maps: -\itemize{ - \item \code{\link{map.rgn14}}: 14 region map used prior to GCAM 4.0. - \item \code{\link{map.rgn32}}: 32 region map used in GCAM 4.0 and later, -excluding Taiwan. - \item \code{\link{map.basin235}}: 235 water basins. - \item \code{\link{map.chn}}: 32 global regions plus China subregions - \item \code{\link{map.usa}}: 32 global regions plus US states. -} -Users can provide their own base maps. You will need a geometry file in -geojson format, where each region has a \code{region_id}. Land masses -that you want to draw, but which aren't part of any region should be included -and assigned a \code{region_id} of 0. The \code{examples} vignette shows how -to load such a file and convert it for use in this package. - -Once you have your map data and your GCAM data, can generate the maps by -passing both to the \code{\link{plot_GCAM}} function. -} - diff --git a/man/get.internal.Rd b/man/get.internal.Rd deleted file mode 100644 index 75f1ac6..0000000 --- a/man/get.internal.Rd +++ /dev/null @@ -1,20 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gcam_data_processing.R -\name{get.internal} -\alias{get.internal} -\title{Get auxiliary data for a named mapset.} -\usage{ -get.internal(mapset, type) -} -\arguments{ -\item{mapset}{The name of the mapset. Can be either a symbol or a string.} - -\item{type}{The type of table. Right now this is either 'lut', 'drop', or -'prov'} -} -\description{ -We have several standard map sets. Each of them has several auxiliary tables -associated with it. This function retrieves the auxiliary table associated -with the requested. Right now this function understands \code{rgn14}, -\code{rgn32}, \code{basin235}, and \code{chn}. -} diff --git a/man/get_prj4s.Rd b/man/get_prj4s.Rd index d9c7f38..93461bb 100644 --- a/man/get_prj4s.Rd +++ b/man/get_prj4s.Rd @@ -1,11 +1,10 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/utils.R +% Please edit documentation in R/spatial_utils.R \name{get_prj4s} \alias{get_prj4s} \title{Retrieve proj4 projection string.} \usage{ -get_prj4s(obj = NULL, prj_type = NULL, prj_code = NULL, - prj4s_key = NULL) +get_prj4s(obj = NULL, prj_type = NULL, prj_code = NULL, prj4s_key = NULL) } \arguments{ \item{obj}{Use object instead that has a predefined proj4 string.} diff --git a/man/gridded_map.Rd b/man/gridded_map.Rd new file mode 100644 index 0000000..ab14c63 --- /dev/null +++ b/man/gridded_map.Rd @@ -0,0 +1,69 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/maps.R +\name{gridded_map} +\alias{gridded_map} +\title{Create a gridded map object from input shape and raster.} +\usage{ +gridded_map( + shape_data = NULL, + raster_data = NULL, + raster_col = NULL, + convert_zero = FALSE, + map_xy_min_max = c(-180, 180, -90, 90), + map_title = NULL, + map_palette = "RdYlBu", + map_width_height_in = c(15, 10), + map_legend_title = NULL, + shape_geom_field = "geometry", + shape_xy_fields = c("LON", "LAT"), + data_xy_fields = C("LON", "LAT") +) +} +\arguments{ +\item{shape_data}{(SF, SP, or Character) - Either the full path string to a shape file (with all necessary files) or an SF shape object} + +\item{raster_data}{(Raster or Character) - Either the full path string to a raster file or an object of type RasterLayer} + +\item{raster_col}{(Character) - Raster field name that contains the desired output variable} + +\item{convert_zero}{(Boolean) - Convert values within the raster data from zero to NA (default FALSE)} + +\item{map_xy_min_max}{(c(Numeric, ...)) - Vector that describes the desired extent of the map in the form of (xmin, xmax, ymin, ymax) (default: c(-180, 180, -90, 90))} + +\item{map_title}{(Character) - Title to be displayed at the top of the output map} + +\item{map_palette}{(Character) - Variable to hold the type of colorscale to be used from the RColorBrewer palette (default "RdYlBu")} + +\item{map_width_height_in}{(c(Numeric, Numeric)) - Vector that describes the desired file size of the output image in the form of (width, height) in inches (defalt c(15, 10))} + +\item{map_legend_title}{(Character) - Text variable to be used for the legend header} + +\item{shape_label_field}{(Character) - Optional field for plotting map labels from the shape attributes (such as country name)} + +\item{shape_label_size_field}{(Character) - Optional field used for computing shape label size dynamically (ie by area or amount etc.) (Default "1")} + +\item{simplify}{(Boolean) - Option to reduce the number or complexity of the polygons in the shape file (default FALSE)} + +\item{raster_band}{(Numeric) - Variable for dealing with multi band or time series rasters that specifices which raster band to use (Default 1)} + +\item{dpi}{(Numeric) - Settable DPI for different print and screen formats (default 150)} + +\item{output_file}{(Character) - Output file path and file name and type to save the resulting plot (e.g. "c:/temp/output.png") (Types accepted: "eps", "ps", "tex", "pdf", "jpeg", "tiff", "png", "bmp", "svg")} + +\item{expand_xy}{(c(Numeric, Numeric)) - Sets expansion amount for the X and Y scales of the map - Vector (expand x, expand y) (default c(0,0))} + +\item{map_palette_reverse}{(Boolean) - Set palette to reverse direction TRUE or FALSE} + +\item{map_x_label}{(Character) - Label for x axis (default "Lon")} + +\item{map_y_label}{(Character) - Label for y axis (default "Lat")} +} +\value{ +(ggplot2 or Character) - Returns a ggplot object of the resulting map or an error string if failed +} +\description{ +This function is designed to take both a shape and raster object or path and create a standardized output map. Option to save the output to file +} +\author{ +Jason Evanoff, jason.evanoff@pnnl.gov +} diff --git a/man/import_mapdata.Rd b/man/import_mapdata.Rd index d99cf53..ec7e512 100644 --- a/man/import_mapdata.Rd +++ b/man/import_mapdata.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Map_Functions.R +% Please edit documentation in R/spatial_utils.R \name{import_mapdata} \alias{import_mapdata} \title{Single import function for compatible data types.} diff --git a/man/join_gcam.Rd b/man/join_gcam.Rd deleted file mode 100644 index a6db31b..0000000 --- a/man/join_gcam.Rd +++ /dev/null @@ -1,26 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Map_Functions.R -\name{join_gcam} -\alias{join_gcam} -\title{Join GCAM data with spatial data.} -\usage{ -join_gcam(mapdata, mapdata_key, gcam_df, gcam_key) -} -\arguments{ -\item{mapdata}{The sf object containing the spatial data and a tuple identifier that -can be referenced in the gcam_df data frame.} - -\item{mapdata_key}{Name of the field having a tuple identifier that can be referenced -in the gcam_df data frame.} - -\item{gcam_df}{The GCAM data frame provided from the user. This is usually generated from -an \code{rgcam} query.} - -\item{gcam_key}{Name of field having a tuple identifier that can be referenced in the -mapdata data frame.} -} -\description{ -Joins GCAM data from rgam query and inner joins it to spatial data provided by the user. -Note: due to conducting an inner join, only the keys that are present in both datasets -will be represented. -} diff --git a/man/load_shp.Rd b/man/load_shp.Rd index 978b088..0ac9580 100644 --- a/man/load_shp.Rd +++ b/man/load_shp.Rd @@ -1,14 +1,16 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Map_Functions.R +% Please edit documentation in R/spatial_utils.R \name{load_shp} \alias{load_shp} \title{Import ESRI Shapefile or GeoJSON as sf object.} \usage{ -load_shp(file_pth) +load_shp(file_pth = NULL) } \arguments{ -\item{file_pth}{Full path to shapefile with extention (.shp). Shapefiles must -contain at least .shp, .shx, and .dbf file to function properly.} +\item{file_pth}{(Character) Full path to shapefile (.shp). Shapefiles must contain at least .shp, .shx, and .dbf file to function properly.} +} +\value{ +(sf or Character) - Returns the loaded SF object or an error string if failed } \description{ Creates a Simple Feature (sf) object from full path string to ESRI Shapefile diff --git a/man/map.basin235.Rd b/man/map.basin235.Rd deleted file mode 100644 index 6f84fbc..0000000 --- a/man/map.basin235.Rd +++ /dev/null @@ -1,18 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gcammaptools.R -\docType{data} -\name{map.basin235} -\alias{map.basin235} -\title{Base map for 235 global water basins} -\format{Simple feature collection} -\usage{ -map.basin235 -} -\description{ -This is the map of the 235 global water basins. For compatibility with the -other map data frames it refers to the basins as 'regions'. Thus, any GCAM -data with a 'basin' column will need to have a 'region' column added. There -is also some variability in how the basin names are represented, so this data -set will need some work. -} -\keyword{datasets} diff --git a/man/map.basin235.simple.Rd b/man/map.basin235.simple.Rd deleted file mode 100644 index b77e7b8..0000000 --- a/man/map.basin235.simple.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gcammaptools.R -\docType{data} -\name{map.basin235.simple} -\alias{map.basin235.simple} -\title{Simplified base map for 235 global water basins} -\format{Simple feature collection} -\usage{ -map.basin235.simple -} -\description{ -The same map as \code{map.basin235} but with only Polygons that have an area -greater than 2.5 square degrees and simplified Polygon borders. -} -\keyword{datasets} diff --git a/man/map.chn.Rd b/man/map.chn.Rd deleted file mode 100644 index 0c3ef2d..0000000 --- a/man/map.chn.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gcammaptools.R -\docType{data} -\name{map.chn} -\alias{map.chn} -\title{Base map for 32-region GCAM with China subregions} -\format{Simple feature collection} -\usage{ -map.chn -} -\description{ -This map has the 32 GCAM regions, plus the subregions corresponding to -China's provinces, municipalities, autonomous regions, and SARs. -} -\keyword{datasets} diff --git a/man/map.countries.Rd b/man/map.countries.Rd deleted file mode 100644 index a955a97..0000000 --- a/man/map.countries.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gcammaptools.R -\docType{data} -\name{map.countries} -\alias{map.countries} -\title{Base map for gridded data over national borders} -\format{Simple feature collection} -\usage{ -map.countries -} -\description{ -This map has the administrative borders of the world's countries. It is meant -for use with gridded data only, as no GCAM output matches country boundaries. -} -\keyword{datasets} diff --git a/man/map.rgn14.Rd b/man/map.rgn14.Rd deleted file mode 100644 index e4d0c4c..0000000 --- a/man/map.rgn14.Rd +++ /dev/null @@ -1,16 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gcammaptools.R -\docType{data} -\name{map.rgn14} -\alias{map.rgn14} -\title{Base map for 14-region GCAM} -\format{Simple feature collection} -\usage{ -map.rgn14 -} -\description{ -This is the region map used in versions of GCAM prior to GCAM 4.0. It is -largely obsolete, but there are still some data from those days floating -around in the wild -} -\keyword{datasets} diff --git a/man/map.rgn14.simple.Rd b/man/map.rgn14.simple.Rd deleted file mode 100644 index 3d0e01e..0000000 --- a/man/map.rgn14.simple.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gcammaptools.R -\docType{data} -\name{map.rgn14.simple} -\alias{map.rgn14.simple} -\title{Simplified base map for 14-region GCAM} -\format{Simple feature collection} -\usage{ -map.rgn14.simple -} -\description{ -The same map as \code{map.rgn14} but with only Polygons that have an area -greater than 2.5 square degrees and simplified Polygon borders. -} -\keyword{datasets} diff --git a/man/map.rgn32.Rd b/man/map.rgn32.Rd deleted file mode 100644 index ab06563..0000000 --- a/man/map.rgn32.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gcammaptools.R -\docType{data} -\name{map.rgn32} -\alias{map.rgn32} -\title{Base map for 32-region GCAM} -\format{Simple feature collection} -\usage{ -map.rgn32 -} -\description{ -This is the region map used in GCAM 4.0 and subsequent. This version of the -map does not include the Taiwan region. -} -\keyword{datasets} diff --git a/man/map.rgn32.simple.Rd b/man/map.rgn32.simple.Rd deleted file mode 100644 index 3926475..0000000 --- a/man/map.rgn32.simple.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gcammaptools.R -\docType{data} -\name{map.rgn32.simple} -\alias{map.rgn32.simple} -\title{Simplified base map for 32-region GCAM} -\format{Simple feature collection} -\usage{ -map.rgn32.simple -} -\description{ -The same map as \code{map.rgn32} but with only Polygons that have an area -greater than 2.5 square degrees and simplified Polygon borders. -} -\keyword{datasets} diff --git a/man/map.usa.Rd b/man/map.usa.Rd deleted file mode 100644 index 4910650..0000000 --- a/man/map.usa.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gcammaptools.R -\docType{data} -\name{map.usa} -\alias{map.usa} -\title{Base map for 32-region GCAM with USA states} -\format{Simple feature collection} -\usage{ -map.usa -} -\description{ -This map has the 32 GCAM regions, plus the subregions corresponding to -US states including the District of Columbia. -} -\keyword{datasets} diff --git a/man/na_aea.Rd b/man/na_aea.Rd deleted file mode 100644 index cc89ae5..0000000 --- a/man/na_aea.Rd +++ /dev/null @@ -1,18 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/diag_header.R -\docType{data} -\name{na_aea} -\alias{na_aea} -\title{Proj4 string for the Albers equal area projection over North America.} -\format{An object of class \code{character} of length 1.} -\usage{ -na_aea -} -\description{ -String for specifying the Albers equal area projection over North -America in mapping functions. This is a conic projection situatied -over the continental United States. Its value is \code{'+proj=aea -+lat_1=20 +lat_2=60 +lat_0=40 +lon_0=-96 +x_0=0 +y_0=0 +ellps=GRS80 -+datum=NAD83'} -} -\keyword{datasets} diff --git a/man/pgon_from_extent.Rd b/man/pgon_from_extent.Rd index fd6fdf7..3d89701 100644 --- a/man/pgon_from_extent.Rd +++ b/man/pgon_from_extent.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/utils.R +% Please edit documentation in R/spatial_utils.R \name{pgon_from_extent} \alias{pgon_from_extent} \title{Create a rectangluar sf polygon from numeric extent or sf bbox.} diff --git a/man/plot_GCAM.Rd b/man/plot_GCAM.Rd deleted file mode 100644 index 668b843..0000000 --- a/man/plot_GCAM.Rd +++ /dev/null @@ -1,126 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Map_Functions.R -\name{plot_GCAM} -\alias{plot_GCAM} -\title{Primary GCAM mapping function. Can handle categorical or continuous data.} -\usage{ -plot_GCAM(mapdata, col = NULL, proj = robin, proj_type = NULL, - extent = EXTENT_WORLD, title = "", legend = F, gcam_df = NULL, - gcam_key = "id", mapdata_key = "region_id", zoom = 0, - graticules = "bottom", agr_type = "constant", - background_color = MAP_BACKGROUND, padding = all(extent == EXTENT_WORLD)) -} -\arguments{ -\item{mapdata}{The data frame containing both geometric data (simple features -collection and id) and regional metadata. This is the only mandatory -variable. If used alone, will produce the default map.} - -\item{col}{If plotting categorical/continuous data, the name of the column to -plot. Will automatically determine type of style of plot based on type of -data (numeric or character).} - -\item{proj}{Map projection to use in the display map. This should be a proj4 -string, except for a few special cases. There are also symbols defined for -some frequently used projections (e.g. \code{\link{robin}} or -\code{\link{na_aea}}).} - -\item{proj_type}{Either esri, epsg, or sr-org as string. These correspond to -available reference types hosted by \url{http://spatialreference.org/}.} - -\item{extent}{Numeric bounds [xmin, xmax, ymin, ymax] to zoom display to.} - -\item{title}{Text to be displayed as the plot title.} - -\item{legend}{Boolean flag: True = display map legend; False = do not display -legend.} - -\item{gcam_df}{A data frame generated from the \code{rgcam} function -\code{\link[rgcam]{getQuery}}. Also accepts other data frames that contain -data that can be linked to the map geometry data using a unique identifier.} - -\item{gcam_key}{The field name containing a join identifier in the gcam_df -data frame.} - -\item{mapdata_key}{The field name containing a join identifier in the -mapdata.} - -\item{zoom}{A distance to buffer the bounding box extent by for on-the-fly -adjustments needed when fitting area to maps.} - -\item{graticules}{Where to position any graticules. One of 'top', 'bottom', -or '' (empty string). Note that 'bottom' places them under the map -background and will not be visible without a setting the -\code{background_color} parameter to NA or transparent.} - -\item{agr_type}{Aggregate-geometry-relationship type. Either 'constant' -(default), 'aggregate', or 'identity' classified as follows: [constant] a -variable that has a constant value at every location over a spatial extent; -examples: soil type, climate zone, land use. [aggregate] values are summary -values (aggregates) over the geometry, e.g. population density, dominant -land use. [identity] values identify the geometry: they refer to (the -whole of) this and only this geometry. See the -\href{https://cran.r-project.org/web/packages/sf/vignettes/sf1.html#how-attributes-relate-to-geometries}{sf -vignette} for further explanation.} - -\item{background_color}{Color for the areas with no regions (the oceans)} - -\item{padding}{Boolean flag: Add space between map edge and plot edge?} -} -\description{ -This function produces a map visualization of a data set containing GCAM -output data. The required argument is a data frame of GCAM results by -region. The function \code{\link[rgcam]{getQuery}} produces suitable data -frames. -} -\details{ -We don't try to take the color mapping, legend title, etc. as arguments to -this function. The ggplot2 way of specifying this information is way more -flexible. To customize your color mapping, use one of \itemize{ \item -\code{\link[ggplot2]{scale_fill_manual}} : A list of colors to map to -categorical data. \item \code{\link[ggplot2]{scale_fill_gradient}} : A -gradient from one color to another. \item -\code{\link[ggplot2]{scale_fill_gradient2}} : A diverging gradient from one -color to another, passing through white in the middle. You can set the data -value that gets assigned to white with the \code{midpoint} argument. \item -\code{\link[ggplot2]{scale_fill_gradientn}} : A smooth gradient between an -arbitrary selection of colors. } If you choose to display a legend for the -color mapping, you will have to give it a title using the \code{title} -argument to any of the above gradient functions. You have to do this even if -you want a legend with no title at all. Use an empty string in that case. - -For specifying the projection you can use any Proj4 string. For convenience, -this package defines the following proj4 strings: \itemize{ \item -\code{\link{wgs84}} - WGS84 (EPSG:4326) \item \code{\link{eck3}} - Eckert III -\item \code{\link{robin}} - Robinson \item \code{\link{na_aea}} - Albers -equal area (North America) \item \code{\link{ch_aea}} - Albers equal area -(China) \item \code{\link{af_ortho}} - Orthographic projection over Africa } - -The \code{extent} argument gives the bounding box of the area to be plotted. -Its format is \code{c(lon.min, lon.max, lat.min, lat.max)}. For convenience -we have defined the following frequently used map extents: \itemize{ \item -\code{\link{EXTENT_WORLD}} - Entire world \item \code{\link{EXTENT_USA}} - -Continental United States \item \code{\link{EXTENT_CHINA}} - China \item -\code{\link{EXTENT_AFRICA}} - Africa \item \code{\link{EXTENT_LA}} - Latin -America } -} -\examples{ -\dontrun{ - -## Plot a map of GCAM regions; color it with the default theme palette. -plot_GCAM(map.rgn32.simple, col = 'region_name', proj = eck3) + - ggplot2::scale_fill_manual(values = gcam32_colors, na.value=gray(0.75)) - -## Plot refined liquids production by region for the year 2050 -prj <- loadProject(system.file('sample-gcam-data', - 'gcam-longform-sample.dat', - package='gcammaptools')) -ref_liquids <- rgcam::getQuery(prj, 'Refined liquids production by region', 'Reference') -ref_liquids <- add_region_ID(ref_liquids, lookupfile=rgn32, drops=rgn32) -ref_liquids <- dplyr::filter(ref_liquids, year==2050) -plot_GCAM(map.rgn32.simple, col='value', proj=robin, title="Robinson World", - legend=T, gcam_df=co2, gcam_key='id', mapdata_key="region_id") + - ggplot2::scale_fill_gradientn(colors = c("white", "red"), - na.value = gray(0.75), - name="CO2 Emissions (MTC)") -} -} diff --git a/man/plot_GCAM_grid.Rd b/man/plot_GCAM_grid.Rd deleted file mode 100644 index 7ff4d47..0000000 --- a/man/plot_GCAM_grid.Rd +++ /dev/null @@ -1,47 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Map_Functions.R -\name{plot_GCAM_grid} -\alias{plot_GCAM_grid} -\title{Plot a gridded dataset over a base map} -\usage{ -plot_GCAM_grid(plotdata, col, map = map.rgn32, proj = robin, - proj_type = NULL, extent = EXTENT_WORLD, zoom = 0, alpha = 0.8, ...) -} -\arguments{ -\item{plotdata}{Data frame with the coordinates and values to be plotted. -Must contain 'lat' and 'lon' columns.} - -\item{col}{Name of the column holding the data values to plot} - -\item{map}{Base map data. Default is GCAM 32-region} - -\item{proj}{Map projection to use in the display map. This should be a proj4 -string, except for a few special cases. There are also symbols defined for -some frequently used projections (e.g. \code{\link{robin}} or -\code{\link{na_aea}}).} - -\item{proj_type}{Either esri, epsg, or sr-org as string. These correspond to -available reference types hosted by \url{http://spatialreference.org/}.} - -\item{extent}{Numeric bounds [xmin, xmax, ymin, ymax] to zoom display to.} - -\item{zoom}{A distance to buffer the bounding box extent by for on-the-fly -adjustments needed when fitting area to maps.} - -\item{alpha}{Transparency of the grid data layer. Given as a number between -0 and 1, where 0 is completely transparent and 1 is completely opaque.} - -\item{...}{Other parameters passed on to \code{plot_GCAM}.} -} -\description{ -This function produces a map visualization of a gridded (i.e., values -specified by latitude and longitude) data set. The data will be plotted over -the base map supplied -} -\details{ -The plot data should be in the form of a table of latitude (lat), longitude -(lon), and data values. The name of the data column is given as an argument -to the function, so you can have, for example, latitude and longitude columns -followed by columns for time slices. Columns besides the coordinate and data -columns will be ignored. -} diff --git a/man/process_data.Rd b/man/process_data.Rd new file mode 100644 index 0000000..5e1c212 --- /dev/null +++ b/man/process_data.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/spatial_utils.R +\name{process_data} +\alias{process_data} +\title{Process data} +\usage{ +process_data( + map_data = NULL, + data_key_field = NULL, + data_col = NULL, + shape_obj = NULL, + shape_data_field = NULL, + shape_key_field = NULL +) +} +\arguments{ +\item{map_data}{(Data Frame or Character) - A data frame that contains the output data to map, or alternatively a full path to a CSV} + +\item{data_key_field}{(Character) - Name of key field in data_obj for merging with shape_data} + +\item{data_col}{(Character) - Column name that contains the data object's output variable} + +\item{shape_obj}{(SF) - An SF object} + +\item{shape_data_field}{(Character) - Optional field for utilizing a field within the shape data as the map data field. Negates the map_data variable} + +\item{shape_key_field}{(Character) - Name of key field in shape object for merging with map_data object} +} +\value{ +(Data Frame or Character) - Returns the resulting simplified SF object or an error string if failed +} +\description{ +This function handles the processing of source map data for use in dynamic mapping functions +} +\author{ +Jason Evanoff, jason.evanoff@pnnl.gov +} diff --git a/man/process_raster.Rd b/man/process_raster.Rd new file mode 100644 index 0000000..8ad4837 --- /dev/null +++ b/man/process_raster.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/spatial_utils.R +\name{process_raster} +\alias{process_raster} +\title{Process raster} +\usage{ +process_raster( + raster_data, + raster_col, + raster_band = 1, + bin_method = "pretty", + bins = 8, + convert_zero = FALSE +) +} +\arguments{ +\item{raster_data}{(Raster or Character) - Either the full path string to raster file or a raster object} + +\item{raster_col}{(Character) - Column name that contains the raster object's output variable} + +\item{raster_band}{(Numeric) - Future variable for dealing with multi band or time series rasters etc (default 1)} + +\item{bin_method}{(Character) - Method or function to use to split continuous data into discrete chunks (default "pretty")} + +\item{bins}{(Numeric) - Number of bins or segments in which to divide the raster (default 8)} + +\item{convert_zero}{(Boolean) - Convert raster zero values to NA (default FALSE)} +} +\value{ +(Raster or Character) - Returns the resulting raster object or an error string if failed +} +\description{ +This function handles the processing of raster data for use in dynamic mapping functions +} +\author{ +Jason Evanoff, jason.evanoff@pnnl.gov +} diff --git a/man/process_shape.Rd b/man/process_shape.Rd new file mode 100644 index 0000000..53cc6fb --- /dev/null +++ b/man/process_shape.Rd @@ -0,0 +1,43 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/spatial_utils.R +\name{process_shape} +\alias{process_shape} +\title{Process shape} +\usage{ +process_shape( + shape_data = NULL, + simplify = FALSE, + shape_label_field = NULL, + shape_data_field = NULL, + shape_key_field = NULL, + shape_label_size = 1, + shape_xy_fields = c("LON", "LAT"), + shape_geom_field = "geometry" +) +} +\arguments{ +\item{shape_data}{(SF, SP, or Character) - Either the full path string to a shape file (with included necessary files) or an SF shape object} + +\item{simplify}{(Boolean) - Option to reduce the number and complexity of the polygons in the shape file (default FALSE)} + +\item{shape_label_field}{(Character) - Optional field for plotting data available from the shape attributes or fields (such as country name)} + +\item{shape_data_field}{(Character) - Optional field for utilizing a field within the shape data as the map data field. Negates the map_data variable} + +\item{shape_key_field}{(Character) - Name of key field in shape object for merging with map_data object} + +\item{shape_xy_fields}{(c(Character, Character)) - Vector that specifies the x and y field names in the shape object (default c("LAT", "LON"))} + +\item{shape_geom_field}{(Character) - Specifies field within shape object that contains needed geometry (default "geometry")} + +\item{shape_label_size_field}{(Numeric) - Optional field used for computing shape label size dynamically (ie by area or amount etc.)} +} +\value{ +(SF or Character) - Returns the resulting simplified SF object or an error string if failed +} +\description{ +This function processes the shape argument for dynamic mapping functions +} +\author{ +Jason Evanoff, jason.evanoff@pnnl.gov +} diff --git a/man/remove_invalid.Rd b/man/remove_invalid.Rd index f9380e5..b8d2add 100644 --- a/man/remove_invalid.Rd +++ b/man/remove_invalid.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/utils.R +% Please edit documentation in R/spatial_utils.R \name{remove_invalid} \alias{remove_invalid} \title{Clean spatial data.} diff --git a/man/return_error.Rd b/man/return_error.Rd new file mode 100644 index 0000000..ec1dfe7 --- /dev/null +++ b/man/return_error.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/error_checking.R +\name{return_error} +\alias{return_error} +\title{Return and output errors} +\usage{ +return_error(error, location) +} +\arguments{ +\item{error}{(Character) - Specific error string for output} + +\item{location}{(Character) - Location the error was caught} +} +\value{ +(Character) - Prints the error to console and also returns it to caller +} +\description{ +This function prints out any caught errors to the console and returns the custom error string to the calling function +} +\author{ +Jason Evanoff, jason.evanoff@pnnl.gov +} diff --git a/man/rgn14.Rd b/man/rgn14.Rd deleted file mode 100644 index df43873..0000000 --- a/man/rgn14.Rd +++ /dev/null @@ -1,14 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Map_Functions.R -\docType{data} -\name{rgn14} -\alias{rgn14} -\title{Designator for the rgn14 map set} -\format{An object of class \code{name} of length 1.} -\usage{ -rgn14 -} -\description{ -This symbol will select the rgn14 map set -} -\keyword{datasets} diff --git a/man/rgn32.Rd b/man/rgn32.Rd deleted file mode 100644 index dfddbbc..0000000 --- a/man/rgn32.Rd +++ /dev/null @@ -1,14 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Map_Functions.R -\docType{data} -\name{rgn32} -\alias{rgn32} -\title{Designator for the rgn32 map set} -\format{An object of class \code{name} of length 1.} -\usage{ -rgn32 -} -\description{ -This symbol will select the rgn32 map set -} -\keyword{datasets} diff --git a/man/robin.Rd b/man/robin.Rd deleted file mode 100644 index 224fd3f..0000000 --- a/man/robin.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/diag_header.R -\docType{data} -\name{robin} -\alias{robin} -\title{Proj4 string for the Robinson World projection} -\format{An object of class \code{character} of length 1.} -\usage{ -robin -} -\description{ -String for specifying the Robinson projection in mapping functions. -Its value is \code{'+proj=robin'} -} -\keyword{datasets} diff --git a/man/save_plot.Rd b/man/save_plot.Rd new file mode 100644 index 0000000..7e944bb --- /dev/null +++ b/man/save_plot.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/output.R +\name{save_plot} +\alias{save_plot} +\title{Saves a plot to disk} +\usage{ +save_plot(output_file = NULL, dpi = 150, map_width = 15, map_height = 10) +} +\arguments{ +\item{output_file}{(Character) - Output file path and file name and type to save the resulting plot (e.g. "c:/temp/output.png") Available file types ("eps", "ps", "tex", "pdf", "jpeg", "tiff", "png", "bmp", "svg")} + +\item{dpi}{(Numeric) - Settable DPI for different print and screen formats (default 150)} + +\item{map_width}{(Numeric) - Map width in inches (default 15)} + +\item{map_height}{(Numeric) - Map height in inches (default 10)} +} +\value{ +(Character) - Returns a character string with success or an error string if failed +} +\description{ +Provides basic error handling and saving of the output map to file +} +\author{ +Jason Evanoff, jason.evanoff@pnnl.gov +} diff --git a/man/simplify_mapdata.Rd b/man/simplify_mapdata.Rd index 12675fa..596556a 100644 --- a/man/simplify_mapdata.Rd +++ b/man/simplify_mapdata.Rd @@ -1,20 +1,20 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Map_Functions.R +% Please edit documentation in R/spatial_utils.R \name{simplify_mapdata} \alias{simplify_mapdata} \title{Reduce number of polygons and size of polygons for map Shapefiles} \usage{ -simplify_mapdata(mapdata, min_area = 2.5, degree_tolerance = 0.1) +simplify_mapdata(mapdata = NULL, min_area = 2.5, degree_tolerance = 0.1) } \arguments{ -\item{mapdata}{sf object containing polygons or multipolygons to simplify.} +\item{mapdata}{(sf) object containing polygons or multipolygons to simplify.} -\item{min_area}{Minimum area of polygons to keep.} +\item{min_area}{(Numeric) Minimum area of polygons to keep.} -\item{degree_tolerance}{Tolerance parameter for simplifying polygons.} +\item{degree_tolerance}{(Numeric) Tolerance parameter for simplifying polygons.} } \value{ -The simplified sf object. +(sf or Character) The simplified sf object or error string if caught. } \description{ Takes a sf object representation of a map and simplifys it by removing diff --git a/man/spat_bb.Rd b/man/spat_bb.Rd index d3c9662..0874226 100644 --- a/man/spat_bb.Rd +++ b/man/spat_bb.Rd @@ -1,11 +1,14 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/utils.R +% Please edit documentation in R/spatial_utils.R \name{spat_bb} \alias{spat_bb} \title{Create sf object from numeric extent.} \usage{ -spat_bb(b_ext, buff_dist = 0, - proj4s = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs") +spat_bb( + b_ext, + buff_dist = 0, + proj4s = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs" +) } \arguments{ \item{b_ext}{Numeric extent [xmin, xmax, ymin, ymax]} diff --git a/man/theme_GCAM.Rd b/man/theme_GCAM.Rd deleted file mode 100644 index 3291532..0000000 --- a/man/theme_GCAM.Rd +++ /dev/null @@ -1,23 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Map_Functions.R -\name{theme_GCAM} -\alias{theme_GCAM} -\title{Default GCAM theme function} -\usage{ -theme_GCAM(base_size = 11, base_family = "", legend = FALSE, - overlay_graticules = FALSE) -} -\arguments{ -\item{base_size}{Base font size} - -\item{base_family}{Base font type} - -\item{legend}{Boolean; whether to include a legend with default legend -formatting.} - -\item{overlay_graticules}{Boolean; whether to place grid lines on top of plot} -} -\description{ -An add-on function to any ggplot2 object. Derives from ggplot2 black and -white theme function (theme_bw). -} diff --git a/man/translate_province.Rd b/man/translate_province.Rd deleted file mode 100644 index cd22952..0000000 --- a/man/translate_province.Rd +++ /dev/null @@ -1,18 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/gcam_data_processing.R -\name{translate_province} -\alias{translate_province} -\title{Replace subregion abbreviations with full subregion names} -\usage{ -translate_province(datatable, provincefile) -} -\arguments{ -\item{datatable}{The table with the abbreviated names in it.} - -\item{provincefile}{Name of a defined mapset OR name of a file containing the -lookup table.} -} -\description{ -Subregions are given two-letter abbreviations in GCAM output. This function -uses a lookup table to restore the full names. -} diff --git a/man/usa.Rd b/man/usa.Rd deleted file mode 100644 index 775e81a..0000000 --- a/man/usa.Rd +++ /dev/null @@ -1,14 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Map_Functions.R -\docType{data} -\name{usa} -\alias{usa} -\title{Designator for the usa map set} -\format{An object of class \code{name} of length 1.} -\usage{ -usa -} -\description{ -This symbol will select the usa map set -} -\keyword{datasets} diff --git a/man/verify_csv.Rd b/man/verify_csv.Rd new file mode 100644 index 0000000..f84f2fd --- /dev/null +++ b/man/verify_csv.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/error_checking.R +\name{verify_csv} +\alias{verify_csv} +\title{Verify csv data} +\usage{ +verify_csv(map_data) +} +\arguments{ +\item{mapdata}{sf object containing polygons or multipolygons to simplify.} + +\item{min_area}{Minimum area of polygons to keep.} + +\item{degree_tolerance}{Tolerance parameter for simplifying polygons.} +} +\value{ +(Character) - Returns a success token or an error string if failed +} +\description{ +This function runs a check on csv data inputs and looks for errors +} diff --git a/man/verify_data.Rd b/man/verify_data.Rd new file mode 100644 index 0000000..09c17c8 --- /dev/null +++ b/man/verify_data.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/error_checking.R +\name{verify_data} +\alias{verify_data} +\title{Verify map data} +\usage{ +verify_data( + map_data = NULL, + data_key_field = NULL, + data_col = NULL, + shape_obj = NULL, + shape_data_field = NULL, + shape_key_field = NULL +) +} +\arguments{ +\item{map_data}{(Data Frame or Character) - A data frame that contains the output data to map, or alternatively a full path to a CSV} + +\item{data_key_field}{(Character) - Name of key field in data_obj for merging with shape_data} + +\item{data_col}{(Character) - Column name that contains the data object's output variable} + +\item{shape_obj}{(SF) - An SF object} + +\item{shape_data_field}{(Character) - Optional field for utilizing a field within the shape data as the map data field. Negates the map_data variable} + +\item{shape_key_field}{(Character) - Name of key field in shape object for merging with map_data object} +} +\value{ +(Character) - Returns either "Success" or an error string if failed +} +\description{ +This function runs a check on map data inputs and looks for errors +} +\author{ +Jason Evanoff, jason.evanoff@pnnl.gov +} diff --git a/man/verify_map_params.Rd b/man/verify_map_params.Rd new file mode 100644 index 0000000..730928b --- /dev/null +++ b/man/verify_map_params.Rd @@ -0,0 +1,59 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/error_checking.R +\name{verify_map_params} +\alias{verify_map_params} +\title{Verify map parameters} +\usage{ +verify_map_params( + bin_method = "pretty", + bins = 8, + dpi = 150, + expand_xy = c(0, 0), + map_xy_min_max = c(-180, 180, -90, 90), + map_title = "", + map_palette = NULL, + map_palette_reverse = FALSE, + map_palette_type = "seq", + map_width_height_in = c(15, 10), + map_legend_title = "", + map_x_label = "Lon", + map_y_label = "Lat", + map_font_adjust = 1 +) +} +\arguments{ +\item{bin_method}{(Character) - Method or function to use to split continuous data into discrete chunks (one of "quantile", "equal", "pretty", "kmeans") (default "pretty")} + +\item{bins}{(Numeric) - Number of bins in which to divide the raster} + +\item{dpi}{(Numeric) - Settable DPI for different print and screen formats (default 150)} + +\item{expand_xy}{(c(Numeric, Numeric)) - Sets expansion amount for the X and Y scale of the map - Vector (expand x, expand y) (default c(0,0))} + +\item{map_xy_min_max}{(c(Numeric, ...)) - Vector that describes the desired extent of the map in the form of (xmin, xmax, ymin, ymax) (default: c(-180, 180, -90, 90))} + +\item{map_title}{(Character) - Title to be displayed on the output map} + +\item{map_palette}{(Character) - Optional variable to manually set the colorscale to a specific palette from RColorbrewer} + +\item{map_palette_reverse}{(Boolean) - Set palette to reverse direction - TRUE or FALSE} + +\item{map_width_height_in}{(c(Numeric, Numeric)) - Vector that describes the desired file size of the output image in the form of (width, height) in inches (default c(15, 10))} + +\item{map_legend_title}{(Character) - Text for the legend header} + +\item{map_x_label}{(Character) - Label for x axis (default Lon)} + +\item{map_y_label}{(Character) - Label for y axis (default Lat)} + +\item{map_font_adjust}{(Numeric) - A number between 0.2 and 2 that scales the map fonts either up or down (0.2 = 80% smaller, 2 = 200% bigger)} +} +\value{ +(Character) - Returns either "Success" or an error string if failed +} +\description{ +Verify the set of arguments for choropleth and other map types +} +\author{ +Jason Evanoff, jason.evanoff@pnnl.gov +} diff --git a/man/verify_raster.Rd b/man/verify_raster.Rd new file mode 100644 index 0000000..733816e --- /dev/null +++ b/man/verify_raster.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/error_checking.R +\name{verify_raster} +\alias{verify_raster} +\title{Verify raster data} +\usage{ +verify_raster( + raster_data = NULL, + raster_col = NULL, + raster_band = 1, + bin_method = "pretty", + bins = 8, + convert_zero = FALSE +) +} +\arguments{ +\item{raster_data}{(Raster or Character) - Either the full path string to raster file or a raster object} + +\item{raster_col}{(Character) - Column name that contains the raster object's output variable} + +\item{raster_band}{(Numeric) - Future variable for dealing with multi band or time series rasters etc (default 1)} + +\item{bin_method}{(Character) - Method or function to use to split continuous data into discrete chunks (default "pretty")} + +\item{bins}{(Numeric) - Number of bins in which to divide the raster (default 8)} + +\item{convert_zero}{(Boolean) - Convert raster zero values to NA (default FALSE)} +} +\value{ +(Character) - Returns either "Success" or an error string if failed +} +\description{ +This function runs a check on raster inputs and looks for errors, missing projection, or missing key fields +} +\author{ +Jason Evanoff, jason.evanoff@pnnl.gov +} diff --git a/man/verify_shape.Rd b/man/verify_shape.Rd new file mode 100644 index 0000000..087ed37 --- /dev/null +++ b/man/verify_shape.Rd @@ -0,0 +1,44 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/error_checking.R +\name{verify_shape} +\alias{verify_shape} +\title{Error checking functions for maps package +Verify shape data} +\usage{ +verify_shape( + shape_data, + simplify = FALSE, + shape_label_field = NULL, + shape_data_field = NULL, + shape_key_field = NULL, + shape_label_size = 1, + shape_xy_fields = c("LAT", "LON"), + shape_geom_field = "geometry" +) +} +\arguments{ +\item{shape_data}{(SF, SP, or Character) - Either the full path string to a shape file (with included necessary files) or an SF shape object} + +\item{simplify}{(Boolean) - Option to reduce the number or complexity of the polygons in the shape file (default FALSE)} + +\item{shape_label_field}{(Character) - Optional field for plotting data available from the shape attributes & fields (such as country name)} + +\item{shape_data_field}{(Character) - Optional field for utilizing a field within the shape data as the map data field. Negates the map_data variable} + +\item{shape_key_field}{(Character) - Name of key field in shape object for merging with map_data object} + +\item{shape_xy_fields}{(c(Character, Character)) - Vector that specifies the x and y field names in the shape object (default c("LAT", "LON"))} + +\item{shape_geom_field}{(Character) - Specifies field within shape object that contains needed geometry (default "geometry")} + +\item{shape_label_size_field}{(Numeric) - Optional field used for computing shape label size dynamically (ie by area or amount etc.)} +} +\value{ +(Character) - Returns either "Success" or an error string if failed +} +\description{ +This function runs a check on shape inputs and looks for errors +} +\author{ +Jason Evanoff, jason.evanoff@pnnl.gov +} diff --git a/man/verify_simplify_mapdata.Rd b/man/verify_simplify_mapdata.Rd new file mode 100644 index 0000000..a13d080 --- /dev/null +++ b/man/verify_simplify_mapdata.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/error_checking.R +\name{verify_simplify_mapdata} +\alias{verify_simplify_mapdata} +\title{Verify simplify} +\usage{ +verify_simplify_mapdata( + map_data = NULL, + min_area = 2.5, + degree_tolerance = 0.1 +) +} +\arguments{ +\item{min_area}{(Numeric) Minimum area of polygons to keep.} + +\item{degree_tolerance}{(Numeric) Tolerance parameter for simplifying polygons.} + +\item{mapdata}{(sf) object containing polygons or multipolygons to simplify.} +} +\value{ +(Character) - Returns a success token or an error string if failed +} +\description{ +This function does simple verification for the simplify_mapdata function +} diff --git a/man/wgs84.Rd b/man/wgs84.Rd deleted file mode 100644 index e11c8f7..0000000 --- a/man/wgs84.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/diag_header.R -\docType{data} -\name{wgs84} -\alias{wgs84} -\title{Proj4 string for default WGS84 (EPSG:4326) coordinate reference system} -\format{An object of class \code{character} of length 1.} -\usage{ -wgs84 -} -\description{ -String for specifying the default WGS84 projection in mapping functions -Its value is \code{'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'} -} -\keyword{datasets} diff --git a/tests/testthat/test_add_region_id.R b/tests/testthat/test_add_region_id.R deleted file mode 100644 index 0a7f1f8..0000000 --- a/tests/testthat/test_add_region_id.R +++ /dev/null @@ -1,46 +0,0 @@ -# Test add_region_id() - -library(gcammaptools) -context("Mapping user data to map data") - -test <- data.frame(region = c('USA'), stringsAsFactors = F) -test_that("32 regions get added even if only one provided", { - # taiwan id = 30 - test.id <- add_region_ID(test) - expect_equal(ncol(test.id), ncol(test) + 1) # Should only add 1 extra column - expect_equal(nrow(test.id), 32) # 32 regions + 1 NA region - 1 Taiwan - expect_equal(test.id[1, 'id'], 1) - expect_equal(test.id[nrow(test.id), 'id'], 0) # Last row has NA region -}) - -test_that("lookupfiles work", { - expect_equal(add_region_ID(test), - add_region_ID(test, system.file("extdata", "rgn32/lookup.txt", package = "gcammaptools"))) - expect_equal(nrow(add_region_ID(test, rgn14)), 15) # 14 regions + 1 NA - expect_equal(nrow(add_region_ID(test, basin235)), 237) # 235 basins + 1 NA + 1 USA - expect_equal(nrow(add_region_ID(test, chn)), 62) # 31 regions + 1 NA + 30 provinces - expect_equal(nrow(add_region_ID(test, usa)), 83) # 30 regions + 1 NA + 51 states + 1 USA - - # Hawaii is both a basin name and state name - test.hi <- data.frame(region = c('Hawaii'), stringsAsFactors = F) - expect_equal(nrow(add_region_ID(test.hi, basin235)), 236) # 235 basins + 1 NA - expect_equal(nrow(add_region_ID(test.hi, chn)), 63) # 31 regions + 1 NA + 30 provinces + 1 Hawaii - expect_equal(nrow(add_region_ID(test.hi, usa)), 82) # 30 regions + 1 NA + 51 states -}) - -test_that("provincefiles work", { - # Only China has a province file - test.chn <- read.csv(system.file('extdata', 'china_example.csv', package='gcammaptools'), - stringsAsFactors = F) - test.chn.id <- add_region_ID(test.chn) - expect_equal(sum(!is.na(test.chn.id$id)), 32) # Only GCAM-32 regions should match - expect_equal(nrow(add_region_ID(test.chn, chn)), nrow(test.chn.id) + 30) # Add 30 provinces - expect_equal(nrow(add_region_ID(test.chn, chn, chn)), nrow(test.chn.id)) # With provincefile, no extra rows -}) - -test_that("drops work", { - test.drops <- data.frame(region = c('Taiwan'), stringsAsFactors = F) - l1 <- nrow(add_region_ID(test.drops)) - l2 <- nrow(add_region_ID(test.drops, drops = rgn32)) - expect_equal(l1 - l2, 1) -}) diff --git a/tests/testthat/test_error_checking.R b/tests/testthat/test_error_checking.R new file mode 100644 index 0000000..616434b --- /dev/null +++ b/tests/testthat/test_error_checking.R @@ -0,0 +1,34 @@ +# Test Error Checking + +library(gcammaptools) +context("Testing error_checking functionality") + +# Load test shape and data objects +shape_path <- system.file("data/TM_WORLD_BORDERS_SIMPL-0.3.shp", package = "gcammaptools", mustWork = TRUE) +test_shape <- gcammaptools::import_mapdata(shape_path) +data_path <- system.file("data/data.csv", package = "gcammaptools", mustWork = TRUE) +test_data <- read.csv(data_path, stringsAsFactors = F) + +# Test process_shape +test_that("testing verify_shape", + { + # Test loading via path + result <- gcammaptools::process_shape(shape_path) + expect_equal(test_shape, result ) + + # Test loading via obj + result2 <- gcammaptools::process_shape(test_shape) + expect_equal(test_shape, result2 ) + + # Test no shape_data arg + result3 <- gcammaptools::process_shape() + expect_equal(substr(result3, start = 1, stop = 5), "Error") + + # Test file not found + result4 <- gcammaptools::process_shape("") + expect_equal(substr(result4, start = 1, stop = 5), "Error") + + # Test simplify + result5 <- gcammaptools::process_shape(test_shape, simplify = TRUE) + expect_equal(class(result5), c("sf", "data.frame")) + }) diff --git a/tests/testthat/test_gridded.R b/tests/testthat/test_gridded.R deleted file mode 100644 index 939f3f0..0000000 --- a/tests/testthat/test_gridded.R +++ /dev/null @@ -1,101 +0,0 @@ -# Test Gridded Data - -library(gcammaptools) -context("Plotting gridded data") - -# load a gridded dataset -prj <- rgcam::loadProject(system.file('sample-gcam-data','gcam-longform-sample.dat', package='gcammaptools')) -co2grid <- rgcam::getQuery(prj, 'Cooling Degree Days', 'Reference') -m <- map.rgn32.simple - -test_that("dataset has lat/lon values", { - expect_true("lon" %in% colnames(co2grid)) - expect_true("lat" %in% colnames(co2grid)) -}) - -test_that("plot_GCAM_grid plots with all defaults", { - plot_GCAM_grid(co2grid, 'value') -}) - -test_that("plot_GCAM_grid plots with provided basemaps", { - plot_GCAM_grid(co2grid, - col='value', - map=map.rgn14 - ) - plot_GCAM_grid(co2grid, - col='value', - map=simplify_mapdata(map.basin235, 5) - ) -}) - -test_that("plots default correctly to EXTENT_WORLD", { - expect_equal( - plot_GCAM_grid(co2grid, 'value'), - plot_GCAM_grid(co2grid, 'value', extent = EXTENT_WORLD) - ) -}) - -test_that("gridded data plots with EPSG projection type", { - plot_GCAM_grid(co2grid, - col='value', - map=m, - proj=4326, - proj_type='EPSG', - extent=EXTENT_USA) -}) - -test_that("gridded data plots with orthographic projection", { - # Expect a warning because raster::projectRaster attempts to transform into a - # projection where many of the points can't be plotted - expect_warning( - plot_GCAM_grid(co2grid, - col='value', - map=m, - proj=af_ortho, - extent=EXTENT_AFRICA) - ) -}) - -test_that("gridded data plots with SR-ORG projection type and zoom", { - plot_GCAM_grid(co2grid, - col='value', - map=m, - proj=7567, - proj_type='SR-ORG', - extent=EXTENT_LA) -}) - -test_that("gridded data plots with Robinson projection", { - plot_GCAM_grid(co2grid, - col='value', - map=m, - proj=robin) -}) - -test_that("gridded data plots with eck3 projection", { - plot_GCAM_grid(co2grid, - col='value', - map=m, - proj=eck3) -}) - - -test_that("plotting exits with incorrectly matched projections and extents", { - expect_error(plot_GCAM_grid(co2grid, - col="value", - proj=na_aea, - extent=EXTENT_WORLD) - ) -}) - - -test_that("grid plots and warns when projection is centered somewhere else", { - expect_warning(plot_GCAM_grid(co2grid, - col='value', - map=m, - proj=na_aea, - extent=EXTENT_USA) - ) -}) - - diff --git a/tests/testthat/test_importdata.R b/tests/testthat/test_importdata.R deleted file mode 100644 index cc8c23c..0000000 --- a/tests/testthat/test_importdata.R +++ /dev/null @@ -1,29 +0,0 @@ -library(gcammaptools) -context("Loading data") - -shp_path <- "shp/reg32_spart.shp" -json_path <- "json/reg32.geojson" - -test_that("shape file loads successfully from path name", { - shp <- import_mapdata(shp_path) - expect_equal(class(shp), c("sf", "data.frame")) - expect_equal(nrow(shp), 948) - expect_equal(names(import_mapdata(shp_path)), - c("region_id", "geometry")) -}) - -test_that("json file loads successfully from path name", { - json <- import_mapdata(json_path) - expect_equal(class(json), c("sf", "data.frame")) - expect_equal(nrow(json), 249) - expect_equal(names(import_mapdata(json_path)), - c("REGION_NAME","Area","GCAM_ID","geometry")) -}) - -test_that("loading an existing shape file returns same file", { - shp <- import_mapdata(shp_path) - expect_identical(shp, import_mapdata(shp)) -}) - -test_that("imported json loads successfully", { -}) diff --git a/tests/testthat/test_maps.R b/tests/testthat/test_maps.R new file mode 100644 index 0000000..e69de29 diff --git a/tests/testthat/test_output.R b/tests/testthat/test_output.R new file mode 100644 index 0000000..6e7fdc0 --- /dev/null +++ b/tests/testthat/test_output.R @@ -0,0 +1,28 @@ +# Test Output + +library(gcammaptools) +shape_path <- system.file("data/TM_WORLD_BORDERS_SIMPL-0.3.shp", package = "gcammaptools", mustWork = TRUE) +test_shape <- gcammaptools::import_mapdata(shape_path) +data_path <- system.file("data/data.csv", package = "gcammaptools", mustWork = TRUE) +test_data <- read.csv(data_path, stringsAsFactors = F) + + +test_that("testing save_plot", + { + # Test empty args + result <- gcammaptools::save_plot() + expect_equal(substr(result, start = 1, stop = 5), "Error") + + # Test no file type + result2 <- gcammaptools::save_plot("test") + expect_equal(substr(result2, start = 1, stop = 5), "Error") + + # Test invalid file type + result3 <- gcammaptools::save_plot("test.gov") + expect_equal(substr(result3, start = 1, stop = 5), "Error") + + # Test valid file and type + result4 <- gcammaptools::save_plot("test.png") + expect_equal(substr(result4, start = 1, stop = 7), "Success") + + }) diff --git a/tests/testthat/test_proj4_lookup.R b/tests/testthat/test_proj4_lookup.R deleted file mode 100644 index 59d4cf9..0000000 --- a/tests/testthat/test_proj4_lookup.R +++ /dev/null @@ -1,29 +0,0 @@ -library(gcammaptools) -context("Lookup proj4 string") - -test_that("looking up a proj4 string with a default key gives correct result", { - expect_equal(assign_prj4s("prj4s_key", "us"), "+proj=aea +lat_1=20 +lat_2=60 +lat_0=40 +lon_0=-96 +x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83") - expect_equal(assign_prj4s("prj4s_key", "africa"), "+proj=aea +lat_1=20 +lat_2=-23 +lat_0=0 +lon_0=25 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs +towgs84=0,0,0 ") - expect_equal(assign_prj4s("prj4s_key", "world"), "+proj=longlat +datum=WGS84 +no_defs") - expect_equal(assign_prj4s("prj4s_key", "ch_aea"), "+proj=aea +lat_1=27 +lat_2=45 +x_0=0 +y_0=0 +lat_0=35 +lon_0=105 +ellps=WGS84 +datum=WGS84") - expect_equal(assign_prj4s("prj4s_key", "eck3"), "+proj=eck3 +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs") -}) - -test_that("looking up an ESRI proj4 string from http://spatialreference.org works", { - expect_equal(assign_prj4s("ESRI", 37001), "+proj=longlat +ellps=WGS66 +no_defs ") -}) - -test_that("looking up an ESPG proj4 string from http://spatialreference.org works", { - expect_equal(assign_prj4s("EPSG", 2044), "+proj=tmerc +lat_0=0 +lon_0=105 +k=1 +x_0=18500000 +y_0=0 +ellps=krass +towgs84=-17.51,-108.32,-62.39,0,0,0,0 +units=m +no_defs ") -}) - -test_that("looking up an SG-ORG proj4 string from http://spatialreference.org works", { - expect_equal(assign_prj4s("SR-ORG", 6754), "+proj=lcc +lat_1=49 +lat_2=77 +lat_0=49 +lon_0=-95 +x_0=0 +y_0=0 +ellps=GRS80 +datum=NAD83 +units=m +no_defs ") -}) - -test_that("looking up an invalid proj4 string from http://spatialreference.org returns a warning", { - expect_warning(assign_prj4s("SR-ORG", 9004)) - expect_warning(x <- assign_prj4s("EPSG", "INVALID")) - # also test that looking up an invalid proj4 string returns a default value - expect_equal(x, wgs84) -}) diff --git a/tests/testthat/test_simplify.R b/tests/testthat/test_simplify.R deleted file mode 100644 index 7e90880..0000000 --- a/tests/testthat/test_simplify.R +++ /dev/null @@ -1,40 +0,0 @@ -# Test Gridded Data - -library(gcammaptools) -context("Simplifying map data for faster plotting") - -test_that("simplified map is smaller", { - expect_true(object.size(map.rgn32) > - object.size(simplify_mapdata(map.rgn32))) - - expect_true(object.size(map.basin235) > - object.size(simplify_mapdata(map.basin235))) -}) - -test_that("simplified map is same type and class as original map", { - expect_equal(class(map.rgn32), class(simplify_mapdata(map.rgn32))) - expect_equal(typeof(map.rgn32), typeof(simplify_mapdata(map.rgn32))) - - expect_equal(class(map.rgn14), class(simplify_mapdata(map.rgn14))) - expect_equal(typeof(map.rgn14), typeof(simplify_mapdata(map.rgn14))) - - expect_equal(class(map.basin235), class(simplify_mapdata(map.basin235))) - expect_equal(typeof(map.basin235), typeof(simplify_mapdata(map.basin235))) - - expect_equal(class(map.chn), class(simplify_mapdata(map.chn))) - expect_equal(typeof(map.chn), typeof(simplify_mapdata(map.chn))) -}) - -test_that("simplified map has fewer polygons", { - expect_true(length(sf::st_geometry(map.rgn32)) > - length(sf::st_geometry(simplify_mapdata(map.rgn32)))) - - # map.basin235 is built up of Multipolygons, which get split out into - # Polygons before simplifying, meaning there will be more of them - # unless doing high levels of simplification - expect_true(length(sf::st_geometry(map.basin235)) > - length(sf::st_geometry(simplify_mapdata(map.basin235, min_area = 10)))) - - expect_false(length(sf::st_geometry(map.basin235)) > - length(sf::st_geometry(simplify_mapdata(map.basin235)))) -}) diff --git a/tests/testthat/test_spatial_utils.R b/tests/testthat/test_spatial_utils.R new file mode 100644 index 0000000..e829cb3 --- /dev/null +++ b/tests/testthat/test_spatial_utils.R @@ -0,0 +1,134 @@ +# Test Spatial_Utils + +library(gcammaptools) +context("Testing spatial_utils functionality") + +# Load test shape and data objects +shape_path <- system.file("data/TM_WORLD_BORDERS_SIMPL-0.3.shp", package = "gcammaptools", mustWork = TRUE) +test_shape <- gcammaptools::import_mapdata(shape_path) +data_path <- system.file("data/data.csv", package = "gcammaptools", mustWork = TRUE) +test_data <- read.csv(data_path, stringsAsFactors = F) + +# Test process_shape +test_that("testing process_shape", + { + # Test loading via path + result <- gcammaptools::process_shape(shape_path) + expect_equal(test_shape, result ) + + # Test loading via obj + result2 <- gcammaptools::process_shape(test_shape) + expect_equal(test_shape, result2 ) + + # Test no shape_data arg + result3 <- gcammaptools::process_shape() + expect_equal(substr(result3, start = 1, stop = 5), "Error") + + # Test file not found + result4 <- gcammaptools::process_shape("") + expect_equal(substr(result4, start = 1, stop = 5), "Error") + + # Test simplify + result5 <- gcammaptools::process_shape(test_shape, simplify = TRUE) + expect_equal(class(result5), c("sf", "data.frame")) + }) + +# Test process_data +test_that("testing process_data", + { + # Test loading via path + result <- gcammaptools::process_data(data_path) + expect_equal(test_data, result ) + + # Test loading via obj + result2 <- gcammaptools::process_data(test_data) + expect_equal(test_data, result2 ) + + # Test no shape_data arg + result3 <- gcammaptools::process_data() + expect_equal(substr(result3, start = 1, stop = 5), "Error") + + # # Test file not found + result4 <- gcammaptools::process_data("") + expect_equal(substr(result4, start = 1, stop = 5), "Error") + + # # Test using shape data field + result5 <- gcammaptools::process_data(shape_obj = test_shape, shape_data_field = "POP2005") + expect_equal(class(result5), c("sf", "data.frame")) + + # Test both data args together (invalid) + result6 <- gcammaptools::process_data(test_data, shape_data_field = "POP2005") + expect_equal(substr(result4, start = 1, stop = 5), "Error") + }) + +# Test simplify_mapdata +test_that("testing simplify_mapdata", + { + # Test basic functionality + result <- gcammaptools::simplify_mapdata(test_shape, min_area = 2, degree_tolerance = 0.2) + expect_equal(class(result), c("sf", "data.frame")) + + # Test no args + result2 <- gcammaptools::simplify_mapdata() + expect_equal(substr(result2, start = 1, stop = 5), "Error") + + # Test wrong arg type for map_data + result3 <- gcammaptools::simplify_mapdata(test_data) + expect_equal(substr(result3, start = 1, stop = 5), "Error") + + # Test wrong args for min_area + result4 <- gcammaptools::simplify_mapdata(test_shape, min_area = 0) + expect_equal(substr(result4, start = 1, stop = 5), "Error") + + # Test wrong args for degree_tolerance + result5 <- gcammaptools::simplify_mapdata(test_shape, degree_tolerance = "0.1") + expect_equal(substr(result5, start = 1, stop = 5), "Error") + + }) + +# Test load_shp +test_that("testing load_shp", + { + # Test basic functionality + result <- gcammaptools::load_shp(shape_path) + expect_equal(class(result), c("sf", "data.frame")) + + # Test no args + result2 <- gcammaptools::load_shp() + expect_equal(substr(result2, start = 1, stop = 5), "Error") + + # Test bad path + result3 <- gcammaptools::load_shp("file.shp") + expect_equal(substr(result3, start = 1, stop = 5), "Error") + + }) + +# Test section for import_data function (using existing functionality for now) + +# Load shape and data test paths +shp_path <- "shp/reg32_spart.shp" +json_path <- "json/reg32.geojson" + +test_that("shape file loads successfully from path name", + { + shp <- import_mapdata(shp_path) + expect_equal(class(shp), c("sf", "data.frame")) + expect_equal(nrow(shp), 948) + expect_equal(names(import_mapdata(shp_path)), + c("region_id", "geometry")) +}) + +test_that("json file loads successfully from path name", + { + json <- import_mapdata(json_path) + expect_equal(class(json), c("sf", "data.frame")) + expect_equal(nrow(json), 249) + expect_equal(names(import_mapdata(json_path)), + c("REGION_NAME","Area","GCAM_ID","geometry")) +}) + +test_that("loading an existing shape file returns same file", + { + shp <- import_mapdata(shp_path) + expect_identical(shp, import_mapdata(shp)) +}) diff --git a/vignettes/choropleth.rmd b/vignettes/choropleth.rmd new file mode 100644 index 0000000..737e037 --- /dev/null +++ b/vignettes/choropleth.rmd @@ -0,0 +1,341 @@ +--- +title: "GCAMMaps Tutorial: Choropleth Map" +author: "Jason Evanoff" +date: "`r Sys.Date()`" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{GCAMMaps Tutorial: Choropleth Map} + %\VignetteEngine{knitr::rmarkdown} + \usepackage[utf8]{inputenc} +--- + +```{r setup, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + fig.width=9, fig.height=5, fig.align = "center" +) +``` + +```{r checknamespace, echo=FALSE} +if(!requireNamespace('rgcam', quietly=TRUE)) { + stop('The rgcam package is required to build this vignette') +} +if(!requireNamespace('rgis', quietly=TRUE)) { + stop('The rgis package is required to build this vignette') +} +``` + +## Introduction + +One of the most commonly produced map types in research is the choropleth map, which is a thematic map that shades geographic areas in proportion to a statistical variable such as population density or per-capita income. This vignette explains how to use this package to dynamically generate and customize a simple choropleth map by inputting a shape file and data file, and customizing the input arguments. This function has been designed to be both flexible regarding the scope and complexity of its arguments and simple to use with default values available for most arguments. This tutorial will outline all of these arguments in a step-by-step format. + +## Building Your First Map: Show World Health Organization (WHO) Healthy Life Expectancy (HALE) at Birth + +To get started building a choropleth map, there are 5 required fields that do not have defaults that must be passed to the function in order for it to generate a map: **`shape_data`**, **`map_data`** (or **`shape_data_field`** discussed later), **`data_col`**, **`shape_key_field`**, and **`data_key_field.`** + +* The **`shape_data`** argument must be either an SF object or point to a .shp file in a directory that includes all necessary accompanying files (.dbf, .prj, etc). +* The **`map_data`** argument must either be a data frame variable or point to a .csv file in comma delimited format. +* The **`data_col`** argument points to the 'value' field in the **`map_data`** object that will be the plot's output variable. +* The **`shape_key_field`** argument must point to the field in your shape object that will be used to join the shape and data objects together. +* The **`data_key_field`** argument must point to the field in your data object that will be used in the join operation. + +The **`shape_key_field`** and **`data_key_field`** fields must be compatible in a join operation. In the case of excess data, this function will left_join to preserve shape data (unjoinable **`map_data`** will be lost). + +**For the purposes of this example, the following arguments will be used:** + +* **`shape_data`** - *"data/tm_world_borders_simpl-0.3.shp"* - A simple world map with country borders +* **`map_data`** - *"data/data.csv"* - CSV file containing WHO HALE data from 2000-2016 +* **`data_col`** - *"X2016"* - Instructs the function to use the 2016 column from the csv +* **`shape_key_field`** - *"NAME"* - Tells the function to use the "NAME" field in the shape object for joining purposes +* **`data_key_field`** - *"Country"* - Tells the function to use the "Country" field in the csv/data object for joining purposes + +```{r load_data, warning=FALSE} +### Load the example scenario data. +data_file <- system.file("data", "data.csv", package="gcammaptools") +shape_file <- system.file("data", "tm_world_borders_simpl-0.3.shp", package="gcammaptools") +output <- gcammaptools::choropleth(shape_data = shape_file, + map_data = data_file, + data_col = "X2016", + shape_key_field = "NAME", + data_key_field = "Country") +plot(output) +``` +You should see a figure that shows WHO HALE data by country, using the default palette "blues". + +### Saving the Output + +Now that we have created a simple map, before we look at further customization let's take a look at how to save the output and what options are available. The relevant arguments here are **`output_file`** and **`dpi`**. The **`output_file`** argument should point to a fully qualified path such as "c:/temp/output.png" or other file path that R is able to process. The **`output_file`** argument should also include the file name appended at the end as well as the desired file type (Types accepted: "eps", "ps", "tex", "pdf", "jpeg", "tiff", "png", "bmp", "svg"). GCAMMaps will autodetect the file type based on the file extension passed in. **Note for this vignette we are using a temp file instead of a qualified path.** + +The **`dpi`** argument sets the dots per inch resolution and should be a number between 30 and 300 depending on your output and printing requirements. + +**The arguments added in this call:** + +* **`output_file`** - *"tempfile/.png"* - Tells the function to save as a temp file with PNG extension +* **`dpi`** - *150* - Sets the resolution to 150 dots per inch + +```{r save_output, warning=FALSE} +### Save the Map to File +file_out <- tempfile(pattern = "file", tmpdir = tempdir(), fileext = "png") +output <- gcammaptools::choropleth(shape_data = shape_file, + shape_key_field = "NAME", + data_col = "X2016", + map_data = data_file, + data_key_field = "Country", + output_file = file_out, + dpi = 150 ) +``` +You can verify that the file saved correctly by checking your local machine's temp file directly designated by R. + +## Customizing the Output: Text Labels +Now that we have started the framework for a simple choropleth map, let's learn how to fill in and customize some of the basic details like giving both the map and legend titles and customizing the axes labels. There are 4 label fields that control the output text: **`map_title`**, **`map_legend_title`**, **`map_x_label`**, and **`map_y_label`**. + +**The arguments added in this call:** + +* **`map_title`** - *"2016 Healthy Life Expectancy (HALE) at Birth"* - Sets the title text at the top of the map +* **`map_legend_title`** - *"HALE (years)"* - Sets the title text for the legend +* **`map_x_label`** - *"Longitude"* - Sets the label text for the X axis +* **`map_y_label`** - *"Latitude"* - Sets the label text for the Y axis + +```{r customize_data, warning=FALSE} +### Customize the map text labels +output <- gcammaptools::choropleth(shape_data = shape_file, + shape_key_field = "NAME", + data_col = "X2016", + map_data = data_file, + data_key_field = "Country", + map_title = "2016 Healthy Life Expectancy (HALE) at Birth", + map_legend_title = "HALE (years)", + map_x_label = "Longitude", + map_y_label = "Latitude" ) +plot(output) +``` +Note the addition of the title text, legend text, and axes labels. + + + +## Customizing the Output: Bins and Binning Options + +A choropleth map usually contains a range of values that need to be divided into categories, or "bins". The number of bins as well as the method of categorization are both customizable within this function. + +The arguments that control this functionality are **`bins`** (default 8) and **`bin_method`** (default "pretty"). The **`bins`** argument will vary based on your individual data, but should reflect the desired number of categories in which to appropriately subdivide the dataset. The **`bin_method`** argument must be one of "quantile", "equal", "pretty", or "kmeans". A description of these methods is available in the classIntervals description, or simply type ***help("classIntervals")*** in your R console. + +**Note that it is possible** for the system to override the number of bins depending on which **`bin_method`** is selected, the number of **`bins`** entered, and the particulars of your dataset. If this happens, and is a problem, reexamine your dataset and its relation to the **`bin_method`** and number of **`bins`** defined. + +**The arguments added in this call:** + +* **`bins`** - *4* - Tells the function to try to use 4 bins +* **`bin_method`** - *"equal"* - Sets the method for constructing bins to 'equal' + +```{r customize_bins, warning=FALSE} +### Customize bins and bin method +output <- gcammaptools::choropleth(shape_data = shape_file, + shape_key_field = "NAME", + data_col = "X2016", + map_data = data_file, + data_key_field = "Country", + map_title = "2016 Healthy Life Expectancy (HALE) at Birth", + map_legend_title = "HALE (years)", + map_x_label = "Longitude", + map_y_label = "Latitude", + output_file = file_out, + dpi = 150, + bins = 4, + bin_method = "equal" ) +plot(output) +``` + +Note that there are now 4 bins as specified, and each category is now 7.8 years in length from using the "equal" method. + + +## Customizing the Output: Color Palettes + +In addition to layout and formatting, the color scheme for the map can also be customized. This can be done in several ways. The **`map_palette_reverse`** argument can be set to TRUE, which inverts/reverses the current color scheme. The **`map_palette_type`** argument can be set to one of three presets: "seq" for sequential data, "div" for divergent data, and "qual" for qualitative data sets. By using this option, you will use the preselected JGCRI color defaults for that map type. Finally, the palette can be directly changed with the **`map_palette`** argument. + +The **`map_palette`** argument can be set to any palette type from the RColorBrewer package. To view the list of available palettes go to https://colorbrewer2.org/ or type display.brewer.all() in your R console (remember to load library). Note that using the **`map_palette`** option overrides the **`map_palette_type`** variable. + +**The arguments added in this call:** + +* **`map_palette_reverse`** - *FALSE* - Tells the function to not invert the color palette (unchanged, here for ref.) +* **`map_palette_type`** - *"seq"* - Sets the palette to the sequential data default palette (will be overriden by **`map_palette`**) +* **`map_palette`** - *"Spectral"* - Overrides the palette and sets it to the Spectral palette from RColorBrewer + +```{r customize_palette, warning=FALSE} +### Customize palette +output <- gcammaptools::choropleth(shape_data = shape_file, + shape_key_field = "NAME", + data_col = "X2016", + map_data = data_file, + data_key_field = "Country", + map_title = "2016 Healthy Life Expectancy (HALE) at Birth", + map_legend_title = "HALE (years)", + map_x_label = "Longitude", + map_y_label = "Latitude", + output_file = file_out, + dpi = 150, + bins = 8, + bin_method = "pretty", + map_palette_reverse = FALSE, + map_palette_type = "seq", + map_palette = "Spectral") +plot(output) +``` + +Note the output which reflects the change to the chosen color palette "Spectral". + +## Customizing the Shape Fields + +There are a number of shape specific options that can also be customized, if needed. The most important is the **`shape_geom_field`**, which designates which field within the shape object is used to plot the shape geometry. The standard field name is "geometry", which is the default. **However if your shape object is non-standard, then you must inspect it and determine which field to use.** +The other argument that controls how the shape object gets plotted is **`shape_xy_fields`**, which has a default of c("LON", "LAT"). This field designates how to generate the x and y axes using data from the shape object. Like the **`shape_geom_field`**, if your shape is different or non-standard, you must inspect and determine the correct value. + +Other shape related fields that control output are **`simplify`**, **`shape_label_field`**, and **`shape_label_size`**. The **`simplify`** argument can be set to TRUE, which runs an algorithm to reduce the complexity and amount of lines that are drawn, improving map aesthetics and/or rendering time in certain situations. The **`shape_label_field`** and **`shape_label_size`** work together to provide optional geographic labels such as country name. The **`shape_label_field`** designates which field contains the labels and **`shape_label_size`** controls how big those labels are. + +**The arguments added in this call:** + +* **`shape_geom_field`** - *"geometry"* - Designates the geographic data field in the shape object (unchanged, default) +* **`shape_xy_fields`** - *c("LON", "LAT")* - Designates the xy geographic axis data (unchanged, default) +* **`simplify`** - *TRUE* - Tells the system to run an algorithm reducing shape complexity and number of polygons +* **`shape_label_field`** - *"NAME"* - Turns labels on and sets the field from which to get label data +* **`shape_label_size`** - *1* - Tells the system to use size 1 (1mm) for shape label size + +```{r customize_shape, warning=FALSE} +### Customize shape options +output <- gcammaptools::choropleth(shape_data = shape_file, + shape_key_field = "NAME", + data_col = "X2016", + map_data = data_file, + data_key_field = "Country", + map_title = "2016 Healthy Life Expectancy (HALE) at Birth", + map_legend_title = "HALE (years)", + map_x_label = "Longitude", + map_y_label = "Latitude", + output_file = file_out, + dpi = 150, + bins = 8, + bin_method = "pretty", + map_palette_reverse = FALSE, + map_palette_type = "seq", + map_palette = "Spectral", + shape_geom_field = "geometry", + shape_xy_fields = c("LON", "LAT"), + simplify = TRUE, + shape_label_field = "NAME", + shape_label_size = 1) +plot(output) +``` +Note the shape labels displaying the country name and slightly reduced complexiy of the map from setting **`simplify`** = TRUE. + +## Customizing the Output: Map Adjustments + +A few additional fields remain which affect the layout and aesthetics of the output map. The **`map_font_adjust`** field allows you to customize the size of all of the map text (except the title). A value of 1.0 is the default and represents unadjusted size. The range of values are 0.5 (50%) - 2.0 (200%). + +The **`map_width_height`** parameter adjusts the actual output size of the map. Finally, the **`map_xy_min_max`** parameter adjusts the minimum and maximum values of the x and y scales and zooms in or out. + +**The arguments added in this call:** + +* **`map_font_adjust`** - *0.5* - Adjusts the text size of all text except the title +* **`map_width_height`** - *c(12,8) - tutorial overrides value* - Physical output size in inches +* **`expand_xy`** - *(unused)* - Expands x and y scales +* **`map_xy_min_max`** - *c(-90, 90, -45, 45)* - Sets the max and min for the xy scales which defines map zoom + +```{r customize_map_misc, warning=FALSE} +### Customize misc map options +output <- gcammaptools::choropleth(shape_data = shape_file, + shape_key_field = "NAME", + data_col = "X2016", + map_data = data_file, + data_key_field = "Country", + map_title = "2016 Healthy Life Expectancy (HALE) at Birth", + map_legend_title = "HALE (years)", + map_x_label = "Longitude", + map_y_label = "Latitude", + output_file = file_out, + dpi = 150, + bins = 8, + bin_method = "pretty", + map_palette_reverse = FALSE, + map_palette_type = "seq", + map_palette = "Spectral", + shape_geom_field = "geometry", + shape_xy_fields = c("LON", "LAT"), + simplify = TRUE, + shape_label_field = NULL, + shape_label_size = NULL, + map_font_adjust = 0.5, + map_width_height_in = c(12,8), + expand_xy = c(0.5,0.5), + map_xy_min_max = c(-90, 90, -45, 45) ) +plot(output) +``` +Note the reduced font size in the axes and legend as well as the extent of the map has been limited to 90/45 degrees. + +## Using Shape Data Fields(instead of **`map_data`**) + +The **`shape_data_field`** argument can be used to plot data that is contained in your shape object (instead of passing in a separate **`map_data`** argument.) Both the **`shape_data_field`** and **`map_data`** cannot be passed in to the same function call, the system can only use one. The plot output and bins would then be calculated based off of the data field in the shape. Not all shape objects have data fields however. + +**Note that when using this method you do not need to use the `map_data`, `data_col`, `data_key_field`, and `shape_key_field` arguments.** + +**The arguments added in this call:** + +* **`shape_data_field`** - *"POP2005" *- Uses a data field from the shape object that represents 2005 population as the plot output in place of data passed in through the map_data argument. + +```{r shape_data, warning=FALSE} +### Customize misc map options +output <- gcammaptools::choropleth(shape_data = shape_file, + shape_data_field = "POP2005", + map_title = "World Population 2005", + map_legend_title = "Population (millions)", + map_x_label = "Longitude", + map_y_label = "Latitude", + output_file = file_out, + dpi = 150, + bins = 7, + bin_method = "quantile", + map_palette_reverse = FALSE, + map_palette_type = "seq", + shape_geom_field = "geometry", + shape_xy_fields = c("LON", "LAT"), + simplify = TRUE, + shape_label_field = NULL, + shape_label_size = NULL, + ) +plot(output) +``` + +Note that the map now reflects 2005 world population from data embedded in the shape file. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vignettes/examples.Rmd b/vignettes/examples.Rmd deleted file mode 100644 index 3541899..0000000 --- a/vignettes/examples.Rmd +++ /dev/null @@ -1,170 +0,0 @@ ---- -title: "GCAM Mapping Tools Examples" -author: "Caleb Braun, Catherine Ledna, and Robert Link" -date: "13 February, 2018" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{GCAM Mapping Tools Examples} - %\VignetteEngine{knitr::rmarkdown} - \usepackage[utf8]{inputenc} ---- - -# GCAM Mapping Tools Examples - -## Introduction -This vignette explains how to use the GCAM Mapping Tools package to display GCAM data in map form. Using this package has a couple of advantages over rolling your own maps. First, it's easy. By the time you've worked through these examples, you will be able to make maps of GCAM data with just a few simple commands. Second, we have defined some default projections and extents for common use cases. This will ensure that the maps you make look professional and conform to the GCAM house style. - -```{r checknamespace, echo=FALSE} -if(!requireNamespace('rgcam', quietly=TRUE)) { - stop('The rgcam package is required to build this vignette') -} -``` - -## Setup -To get started with the GCAM map tools, attach the `gcammaptools` package. -```{r setup} -library('gcammaptools') -``` - -## Loading GCAM data -You will need to load your own GCAM data to work with. The best way to import GCAM results is to use the `rgcam` package, which will create a project file with your data in it. You can then load the project data with `rgcam::loadProject()` and retrieve tables for individual queries using `rgcam::getQuery()`. However, if you aren't using `rgcam`, you can start with any data frame that has a `region` column and one or more data columns. - -```{r load_data, warning=FALSE} -library('rgcam') -### Load the example scenario data. -prj <- loadProject(system.file('sample-gcam-data','gcam-longform-sample.dat', package='gcammaptools')) -listScenarios(prj) -listQueries(prj, 'Reference') -``` - -The sample data has one scenario with 19 queries. For demonstration purposes we will load the CO2 emissions table. After loading the query you want to display, you must add the region identifiers used in the map data to the data frame using the `add_region_ID()` function. - -```{r get_query} -co2 <- rgcam::getQuery(prj, 'CO2 emissions by region', 'Reference') -co2 <- dplyr::filter(co2, year==2050) -co2 <- add_region_ID(co2, lookupfile=rgn32, drops=rgn32) - -### Show the first observations -head(co2) -``` -The data is in long form, so using `dplyr::filter()` helps to get just the observations for the year you want to plot. At the end of this, `co2` is a data frame that has CO2 emissions by region for the year 2050. This structure can now be passed to `plot_GCAM()` to plot maps, as shown in the examples below. - -## Loading map data -When using `plot_GCAM()` for your GCAM data, you also need to provide the map data that it should be associated with. You should use one of the map datasets included in the package whenever possible, because they correspond to the geographical units reported by GCAM. The datasets available are `map.rgn32`, `map.rgn14`, `map.basin235`, `map.usa`, and `map.chn`. They correspond to the 32-region and 14-region GCAM region maps, the 235 global water basin map, and the 32-region map plus states/provinces for the USA and China. Additionally, the non-provincial datasets each have a simplified version such as `map.rgn32.simple`, which is helpful for faster plotting and less cluttered maps. -```{r plot.default, fig.width=3.48, fig.show='hold'} -plot_GCAM(map.rgn32, title="Full 32-Region map") -plot_GCAM(map.rgn32.simple, title="Simplified 32-Region map") -``` - -It is possible, however, for you to load your own map data as well. The map data can be loaded by `gcammaptools` given the file path. Your map data can be in any of the following formats: sf objects, spatial data frames, ESRI Shapefiles, or GeoJSON files. You can either pass the file path to `plot_GCAM()` or load the data yourself first. -```{r load.map, fig.width=4, fig.align='center'} -mapdata <- system.file("extdata/rgn32", "reg32_spart.shp", package = "gcammaptools") -mapdata -plot_GCAM(mapdata) -``` - -## Sample maps - -### Example 1: Eckert III World Projection, Colored by Region - -This example just plots the map data frame with the GCAM region name. Applying a scale with `gcam32_colors`, the default GCAM colors, you get each region colored according to a discrete color palette. For older data that uses 14-region GCAM, you can use the palette `gcam14_colors`. -```{r mp1, fig.width=6, fig.height=3, fig.align='center'} -plot_GCAM(map.rgn32.simple, col = 'region_name', proj = eck3) + - ggplot2::scale_fill_manual(values = gcam32_colors, na.value=gray(0.75)) -``` - -### Example 2: Robinson World Projection, Colored by Regional CO2 Emissions -In this example we plot the CO2 data frame that we created above. We select the column `value`, which is the name of the column that contains the data. It is also necessary to specify how to join the this data frame to the map data, which is why we created the column `id` with the function `add_region_id()` above. -```{r mp2, fig.width=6, fig.height=4, fig.align='center'} -plot_GCAM(map.rgn32.simple, col='value', proj=robin, title="Robinson World", legend=T, - gcam_df=co2) + - ggplot2::scale_fill_gradientn(colors = c("white", "red"), - na.value = gray(0.75), name="CO2 Emissions (MTC)") -``` - -### Example 3: U.S. Projection (Albers Equal Area) -This map is specialized to the continental USA. The `na_aea` and `EXTENT_USA` symbols are defined for convenience, but you can use any valid proj4 string (see `proj4::project` for how these strings are constructed) for the projection. The extent should be the bounding box of the plot area in the form `c(lon.min, lon.max, lat.min, lat.max)`. -```{r mp3, fig.width=4, fig.height=4, fig.align='center'} -plot_GCAM(map.rgn32, col='region_id', proj=na_aea, extent=EXTENT_USA, - title="USA Albers Equal-Area") -``` - -### Example 4: Africa Projection (Orthographic) -For superregions with a long north-south extent, the orthographic projection gives the best result. We have predefined one for Africa, but you can find others defined by proj4 strings from http://spatialreference.org as shown in the following example. Although the extent parameter is the best way to specify the view you want, you can fine-tune the final plot by adjusting the zoom. -```{r mp4, fig.width=4, fig.height=4, fig.align='center'} -plot_GCAM(map.rgn32, col='region_name', proj=af_ortho, extent=EXTENT_AFRICA, - title="Africa Orthographic") + - ggplot2::scale_fill_manual(values = gcam32_colors) -``` - -### Example 5: Latin America Projection (Orthographic) -Orthographic projection of the Latin America superregion. Notice that projection strings can also be defined by specifying an EPSG, ESRI, or SR-ORG projection code. -```{r mp5, fig.width=4, fig.height=4, fig.align='center'} -plot_GCAM(map.rgn32, col='region_name', proj=7567, proj_type='SR-ORG', - extent=EXTENT_LA, title="Latin America Orthographic") + - ggplot2::scale_fill_manual(values = gcam32_colors) -``` - -### Example 6: China Projection (Albers Equal Area) -A map of China. Although the projection is once again the Albers equal area projection, we have to have a different projection string because the string includes some information about the parallels the projection is based on. -```{r mp6, fig.width=4, fig.height=4, fig.align='center'} -plot_GCAM(map.rgn32, proj=ch_aea, extent=EXTENT_CHINA, title="China Albers Equal-Area") -``` - - -### Example 7: Global Water Basins -A map of the 235 global water basins. Because `col` is set to `basin_name`, each basin name is treated as a separate category, giving the colorful map below. -```{r mp7, fig.width=6, fig.height=3, fig.align='center'} -plot_GCAM(map.basin235, col='basin_name', proj=eck3) -``` - - -### Example 8: Gridded Data -The `plot_GCAM_grid()` function tiles gridded data over a base map. -```{r mp8, fig.width=4, fig.height=6, fig.align='center'} -co2grid <- rgcam::getQuery(prj, 'Cooling Degree Days', 'Reference') -plot_GCAM_grid(co2grid, col='value', proj=robin, extent=EXTENT_LA, legend=T) + - ggplot2::scale_fill_gradientn(colors=c("white", "red"), - guide=ggplot2::guide_colorbar(title="Cooling Degree Days", - title.position="top")) - -``` - -### Example 9: Faceting -Using `ggplot::facet_wrap()` is often a good way to compare the results from several different scenarios. To do this with `plot_GCAM()`, it is important to make sure that your dataset contains the facet variable for each region you want to plot. By default, `add_region_ID()` puts in `NA` values for missing regions. The `disaggregate` parameter allows you to specify that the missing regions with no data should be included in each facet. -```{r mp9, fig.width=7, fig.height=3, fig.align='center'} -waterdata <- read.csv(system.file('extdata','facet_example.csv', package='gcammaptools'), - stringsAsFactors = F) -waterdata <- add_region_ID(waterdata, disaggregate = 'scenario') - -plot_GCAM(map.rgn32.simple, col='value', legend=T, gcam_df=waterdata, - title="Water Scarcity in 2100") + - ggplot2::scale_fill_gradientn(colors=c("deepskyblue", "firebrick1"), - na.value=gray(0.9), - guide=ggplot2::guide_colorbar(title="km^3", - barwidth=12)) + - ggplot2::facet_wrap(~scenario) - -``` - -### Example 10: GCAM China -Data from GCAM China may contain extra regions that you want to drop as well as region name abbreviations that you want to translate into the full province name. -```{r mp10, fig.width=6, fig.height=4, fig.align='center'} -gcamchina <- read.csv(system.file('extdata', 'china_example.csv', package='gcammaptools'), - stringsAsFactors = F) -gcamchina <- add_region_ID(gcamchina, lookupfile = chn, provincefile = chn, drops = chn) - -# Highlight the provinces by filtering out values from other regions -gcamchina[!is.na(gcamchina$id) & gcamchina$id <= 32, 'value'] <- NA -plot_GCAM(map.chn, col='value', gcam_df=gcamchina, proj=ch_aea, - extent=EXTENT_CHINA) -``` - -### Example 11: GCAM USA -Support is also provided for GCAM USA data. The map expects states to be identified by their two letter abbreviations, which can be added on using `add_region_id()` with `lookupfile = usa`, as long as the state full names are present. -```{r mp11, fig.width=6, fig.height=4, fig.align='center'} -gcamusa <- read.csv(system.file('extdata', 'usa_example.csv', package='gcammaptools'), - stringsAsFactors = F) -plot_GCAM(map.usa, col='value', gcam_df=gcamusa, gcam_key='region', proj=na_aea, - extent=EXTENT_USA) -``` diff --git a/vignettes/rsconnect/documents/choropleth.rmd/rpubs.com/rpubs/Document.dcf b/vignettes/rsconnect/documents/choropleth.rmd/rpubs.com/rpubs/Document.dcf new file mode 100644 index 0000000..2c8d967 --- /dev/null +++ b/vignettes/rsconnect/documents/choropleth.rmd/rpubs.com/rpubs/Document.dcf @@ -0,0 +1,10 @@ +name: Document +title: +username: +account: rpubs +server: rpubs.com +hostUrl: rpubs.com +appId: https://api.rpubs.com/api/v1/document/623458/02a0f7fa45fb4240ab2ddcad724a0ae1 +bundleId: https://api.rpubs.com/api/v1/document/623458/02a0f7fa45fb4240ab2ddcad724a0ae1 +url: http://rpubs.com/publish/claim/623458/8135ebd0fe7a4ab5b794c7636e1a6b42 +when: 1591195605.16931 diff --git a/vignettes/rsconnect/documents/choropleth.rmd/rpubs.com/rpubs/Publish Document.dcf b/vignettes/rsconnect/documents/choropleth.rmd/rpubs.com/rpubs/Publish Document.dcf new file mode 100644 index 0000000..1a61e39 --- /dev/null +++ b/vignettes/rsconnect/documents/choropleth.rmd/rpubs.com/rpubs/Publish Document.dcf @@ -0,0 +1,10 @@ +name: Publish Document +title: +username: +account: rpubs +server: rpubs.com +hostUrl: rpubs.com +appId: https://api.rpubs.com/api/v1/document/623458/02a0f7fa45fb4240ab2ddcad724a0ae1 +bundleId: https://api.rpubs.com/api/v1/document/623458/02a0f7fa45fb4240ab2ddcad724a0ae1 +url: http://rpubs.com/jevanoff/623458 +when: 1592335899.69333