From a2c3de41e52a5be4c0785505cd1441097cf3b6d3 Mon Sep 17 00:00:00 2001 From: Jonathan Callahan Date: Tue, 12 Dec 2017 09:13:51 -0800 Subject: [PATCH] CRAN test modifications --- DESCRIPTION | 2 +- NEWS.md | 15 ++- R/esriMap_getMap.R | 116 ++++++++++------------ R/esriMap_plotOnStaticMap.R | 5 +- man/esriMap_getMap.Rd | 27 +++-- man/esriMap_plotOnStaticMap.Rd | 5 + {localVignettes => vignettes}/NowCast.Rmd | 10 +- 7 files changed, 102 insertions(+), 78 deletions(-) rename {localVignettes => vignettes}/NowCast.Rmd (99%) diff --git a/DESCRIPTION b/DESCRIPTION index 1896cbf2..757837c1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Type: Package Package: PWFSLSmoke -Version: 0.99.30 +Version: 0.99.33 Title: Utilities for Working with Air Quality Monitoring Data Authors@R: c( person("Jonathan", "Callahan", email="jonathan.s.callahan@gmail.com", role=c("aut","cre")), diff --git a/NEWS.md b/NEWS.md index 60ff7103..cdc63d6a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -9,12 +9,25 @@ from the US EPA, AirNow, AIRSIS, WRCC and others. ## Version 0.99 -- Regularized and Consistent (beta) +### PWFSLSmoke 0.99.33 + + * tweaked esriMap_~ examples for CRAN upload + +### PWFSLSmoke 0.99.32 + + * tweaked NowCast vignette for CRAN upload + +### PWFSLSmoke 0.99.31 + + * refactored `esriMap_getMap()` to use `httr` package + * added NowCast vignette + ### PWFSLSmoke 0.99.30 * new `airsis_availableUnits()` function * new `AIRSIS` object with available monitor types * fix to `esriMap_getMap()` to ensure that projected maps are the correct size - * `esriMap_getMap()` arguments changed to: `bboxString` and `mapType` + * `esriMap_getMap()` arguments changed to: `bboxString` ### PWFSLSmoke 0.99.29 diff --git a/R/esriMap_getMap.R b/R/esriMap_getMap.R index 4f7dc05c..02a70095 100644 --- a/R/esriMap_getMap.R +++ b/R/esriMap_getMap.R @@ -1,10 +1,9 @@ #' @keywords plotting #' @export -#' @title Create a RGB spatial raster from arcGIS REST +#' @title Download a Spatial Raster Object from ESRI #' @param centerLon map center longitude #' @param centerLat map center latitude -#' @param maptype map type. natGeo, worldStreetMap, worldTopoMap, satellite, or deLorme. Also accepts -#' map server identity, found at \url{http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Basemaps/02r3000001mt000000/} +#' @param maptype map type #' @param zoom map zoom level; corresponds to googleMaps zoom level #' @param bboxString comma separated string with bounding box (xmin, ymin, xmax, ymax). If not null, centerLon, centerLat, and zoom are ignored. #' @param bboxSR spatial reference of the bounding box @@ -12,21 +11,36 @@ #' @param height height of image, in pixels #' @param crs object of class CRS. The Coordinate Reference System (CRS) for the returned map. If the CRS of the downloaded #' map does not match, it will be projected to the specified CRS using \code{raster::projectRaster}. -#' @param additionalArgs additional arguments to be pasted into the image URL eg. \code{"&rotation=90"} +#' @param additionalArgs character string with additional arguments to be pasted into the image URL eg. \code{"&rotation=90"} +#' @description Downloads a PNG from ESRI and creates a \code{raster::rasterBrick} object with layers for red, green, and blue. +#' This can then passed as the \code{mapRaster} object to the \code{esriMap_plotOnStaticMap()} function for plotting. +#' +#' Available \code{maptypes} include: +#' \itemize{ +#' \item{natGeo} +#' \item{worldStreetMap} +#' \item{worldTopoMap} +#' \item{satellite} +#' \item{deLorme} +#' } +#' +#' Additional base maps are found at: +#' \url{http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Basemaps/02r3000001mt000000/} +#' #' @note The spatial reference of the image when it is downloaded is 3857. If the crs argument is different, projecting may cause #' the size and extent of the image to differ very slightly from the input, on a scale of 1-2 pixels or 10^-3 degrees. #' #' If bboxString is specified and the bbox aspect ratio does not match the width/height aspect ratio the extent is resized to prevent #' the map image from appearing stretched, so the map extent may not match the bbox argument exactly. -#' @return A rasterBrick object which can be plotted with \code{raster::plotRGB} and serve as a base plot. -#' @description Creates a rasterBrick using the \pkg{raster} package with layers for red, green, and blue color intensity. +#' @return A rasterBrick object which can be plotted with \code{esriMap_plotOnStaticMap()} or \code{raster::plotRGB()} and serve as a base plot. #' @references \url{http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Export_Map/02r3000000v7000000/} #' @examples #' \dontrun{ #' map <- esriMap_getMap(-122.3318, 47.668) #' esriMap_plotOnStaticMap(map) #' } - +#' @seealso \code{\link{esriMap_plotOnStaticMap}} +#' esriMap_getMap <- function(centerLon = NULL, centerLat = NULL, bboxString = NULL, @@ -39,7 +53,7 @@ esriMap_getMap <- function(centerLon = NULL, additionalArgs = NULL) { - # calculate degrees per pixel from zoom to determine bbox: + # Calculate degrees per pixel from zoom to determine bbox: # * google maps tiles are 256x256 pixels # * zoom level 0 includes 360 degrees-EW # * every time zoom level increases, scale halves. Thus, for degrees EW: @@ -47,15 +61,9 @@ esriMap_getMap <- function(centerLon = NULL, # degrees/pixel = 360degrees/(256pixels*2^zoomLevel) # degrees-NS/pixel = degreesPerPixelNS*cos(latitude) # Source: https://gis.stackexchange.com/questions/7430/what-ratio-scales-do-google-maps-zoom-levels-correspond-to - - # TODO: Improve logic - # TODO: if (lat AND lon) { ... } else if (bboxString) { ... } else { ERROR } - if ( is.null(centerLat) && is.null(centerLon) && is.null(bboxString) ) { - stop("centerLat, centerLon, or bboxString must be specified") - } - - # TODO: Merge this if block into the logic above - if ( is.null(bboxString) ) { + + # Create components of webservice URL + if ( !is.null(centerLon) && !is.null(centerLat) ) { degreesPerPixelEW <- 360/(256*2^zoom) degreesPerPixelNS <- degreesPerPixelEW*cos(pi/180*centerLat) # R does trigonometry in radians lonLo <- centerLon - degreesPerPixelEW*(width/2-.5) @@ -64,16 +72,20 @@ esriMap_getMap <- function(centerLon = NULL, latLo <- centerLat-degreesPerPixelNS*(height/2-.5) latHi <- centerLat+degreesPerPixelNS*(height/2-.5) bbox <- c(lonLo, latLo, lonHi, latHi) + bboxString <- paste0(bbox, collapse=",") bboxSR <- "4326" - } - bboxString <- paste0(bbox, collapse = ",") + } else if ( !is.null(bboxString) ) { + bboxSR <- "4326" + } else { + stop("centerLat + centerLon, or bboxString must be specified") + } - # url text for maptype http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Basemaps/02r3000001mt000000/ - # NatGeo_World_Map = natGeo - # World_Street_Map = worldStreetMap - # World_Topo_Map = worldTopoMap - # Specialty/DeLorme_World_Base_Map = deLorme - # World_Imagery = satellite + # NOTE: Url text for maptype http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Basemaps/02r3000001mt000000/ + # NOTE: * NatGeo_World_Map = natGeo + # NOTE: * World_Street_Map = worldStreetMap + # NOTE: * World_Topo_Map = worldTopoMap + # NOTE: * Specialty/DeLorme_World_Base_Map = deLorme + # NOTE: * World_Imagery = satellite if ( maptype == "natGeo" ) { maptypeText <- "NatGeo_World_map" @@ -89,46 +101,28 @@ esriMap_getMap <- function(centerLon = NULL, maptypeText <- maptype } - # Apply arguments to url - - # TODO: Naming consistency: url, baseUrl, pngUrl, jsonUrl + # Create URLs from components baseUrl <- paste0("http://server.arcgisonline.com/arcgis/rest/services/", maptypeText, "/MapServer/export") url <- paste0(baseUrl, "?bbox=", bboxString, "&bboxSR=", bboxSR, "&size=", width, ",", height, additionalArgs) pngUrl <- paste0(url, "&f=image") jsonUrl <- paste0(url, "&f=json") - - # TODO: Always use httr package to download stuff - # TODO: Much of the code below here can be replaced with: - # TODO: - # TODO: response <- httr::GET(jsonUrl) - # TODO: # check response$status_code and issue an intelligible error message if needed - # TODO: mapInfo <- jsonlite::fromJSON(httr::content(response)) - # TODO: response <- httr::GET(pngUrl) - # TODO: # check status_code - # TODO: array <- httr::content(response) - # TODO: mapRaster <- raster::rasterImamge(array, ...) - - # TODO: Test each web request by checking out - # Download and load PNG and metadata - - dirName <- paste("esriMap", centerLat, centerLon, sep = "_") - if ( dir.exists(dirName) ) { dirName <- paste0(dirName, "(temp)") } - dir.create(dirName) - - utils::download.file(pngUrl, paste0(dirName, "/image.png")) - utils::download.file(jsonUrl, paste0(dirName, "/info.json")) - - imageArray <- png::readPNG(paste0(dirName, "/image.png")) - mapInfoJSON <- readr::read_file(paste0(dirName, "/info.json")) - - unlink(dirName, recursive = TRUE) - - mapInfo <- jsonlite::fromJSON(mapInfoJSON) - - # Create raster with RBG layers and matching metadata + # Get ESRI JSON map metadata + response <- httr::GET(jsonUrl) + if ( httr::http_error(response) ) { + stop(paste0("ESRI JSON request failed with: ",httr::content(response))) + } + mapInfo <- jsonlite::fromJSON(httr::content(response)) - mapRaster <- raster::brick(ncol=mapInfo$width, + # Get ESRI map png + response <- httr::GET(pngUrl) + if ( httr::http_error(response) ) { + stop(paste0("ESRI PNG request failed with: ",httr::content(response))) + } + imageArray <- httr::content(response, type="image/png") + + # Convert PNG into a Raster object + mapRaster <- raster::brick(ncol=mapInfo$width, nrow=mapInfo$height, nl = 3) mapRaster <- raster::setValues(mapRaster, imageArray*255) @@ -139,14 +133,10 @@ esriMap_getMap <- function(centerLon = NULL, raster::extent(mapRaster) <- c(mapInfo$extent$xmin, mapInfo$extent$xmax, mapInfo$extent$ymin, mapInfo$extent$ymax) raster::crs(mapRaster) <- sp::CRS(paste0("+init=epsg:",mapInfo$extent$spatialReference$latestWkid)) - if ( rgdal::CRSargs(crs) != rgdal::CRSargs(sp::CRS(paste0("+init=epsg:", mapInfo$extent$spatialReference$latestWkid))) ) { mapRaster <- raster::projectRaster(mapRaster, crs = crs, method = "ngb") - # trim any extra NA on the edges generated by projectRaster - mapRaster <- raster::trim(mapRaster) - } return(mapRaster) diff --git a/R/esriMap_plotOnStaticMap.R b/R/esriMap_plotOnStaticMap.R index fffa7075..672e56c6 100644 --- a/R/esriMap_plotOnStaticMap.R +++ b/R/esriMap_plotOnStaticMap.R @@ -6,12 +6,15 @@ #' @param grayscale logical, if TRUE one layer is plotted with grayscale values. If FALSE, a color #' map is plotted from red, green, and blue colors. #' @param ... arguments passed on to \code{plot} (for grayscale = TRUE) or \code{plotRGB} (for grayscale = FALSE) -#' @return An plot of the map #' @description The map is plotted using \code{plotRGB} from \pkg{raster}. +#' @return An plot of the map #' @examples +#' \dontrun{ #' map <- esriMap_getMap(-122.3318, 47.668) #' esriMap_plotOnStaticMap(map) #' esriMap_plotOnStaticMap(map, grayscale = TRUE) +#' } +#' @seealso \code{\link{esriMap_getMap}} esriMap_plotOnStaticMap <- function(mapRaster, grayscale = FALSE, diff --git a/man/esriMap_getMap.Rd b/man/esriMap_getMap.Rd index 1a9d2d90..236d7a1a 100644 --- a/man/esriMap_getMap.Rd +++ b/man/esriMap_getMap.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/esriMap_getMap.R \name{esriMap_getMap} \alias{esriMap_getMap} -\title{Create a RGB spatial raster from arcGIS REST} +\title{Download a Spatial Raster Object from ESRI} \usage{ esriMap_getMap(centerLon = NULL, centerLat = NULL, bboxString = NULL, bboxSR = "4326", maptype = "worldStreetMap", zoom = 12, width = 640, @@ -17,8 +17,7 @@ esriMap_getMap(centerLon = NULL, centerLat = NULL, bboxString = NULL, \item{bboxSR}{spatial reference of the bounding box} -\item{maptype}{map type. natGeo, worldStreetMap, worldTopoMap, satellite, or deLorme. Also accepts -map server identity, found at \url{http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Basemaps/02r3000001mt000000/}} +\item{maptype}{map type} \item{zoom}{map zoom level; corresponds to googleMaps zoom level} @@ -29,13 +28,26 @@ map server identity, found at \url{http://resources.arcgis.com/en/help/arcgis-re \item{crs}{object of class CRS. The Coordinate Reference System (CRS) for the returned map. If the CRS of the downloaded map does not match, it will be projected to the specified CRS using \code{raster::projectRaster}.} -\item{additionalArgs}{additional arguments to be pasted into the image URL eg. \code{"&rotation=90"}} +\item{additionalArgs}{character string with additional arguments to be pasted into the image URL eg. \code{"&rotation=90"}} } \value{ -A rasterBrick object which can be plotted with \code{raster::plotRGB} and serve as a base plot. +A rasterBrick object which can be plotted with \code{esriMap_plotOnStaticMap()} or \code{raster::plotRGB()} and serve as a base plot. } \description{ -Creates a rasterBrick using the \pkg{raster} package with layers for red, green, and blue color intensity. +Downloads a PNG from ESRI and creates a \code{raster::rasterBrick} object with layers for red, green, and blue. +This can then passed as the \code{mapRaster} object to the \code{esriMap_plotOnStaticMap()} function for plotting. + +Available \code{maptypes} include: +\itemize{ +\item{natGeo} +\item{worldStreetMap} +\item{worldTopoMap} +\item{satellite} +\item{deLorme} +} + +Additional base maps are found at: +\url{http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Basemaps/02r3000001mt000000/} } \note{ The spatial reference of the image when it is downloaded is 3857. If the crs argument is different, projecting may cause @@ -53,4 +65,7 @@ esriMap_plotOnStaticMap(map) \references{ \url{http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Export_Map/02r3000000v7000000/} } +\seealso{ +\code{\link{esriMap_plotOnStaticMap}} +} \keyword{plotting} diff --git a/man/esriMap_plotOnStaticMap.Rd b/man/esriMap_plotOnStaticMap.Rd index 608730ba..fa05a6ff 100644 --- a/man/esriMap_plotOnStaticMap.Rd +++ b/man/esriMap_plotOnStaticMap.Rd @@ -22,8 +22,13 @@ An plot of the map The map is plotted using \code{plotRGB} from \pkg{raster}. } \examples{ +\dontrun{ map <- esriMap_getMap(-122.3318, 47.668) esriMap_plotOnStaticMap(map) esriMap_plotOnStaticMap(map, grayscale = TRUE) } +} +\seealso{ +\code{\link{esriMap_getMap}} +} \keyword{plotting} diff --git a/localVignettes/NowCast.Rmd b/vignettes/NowCast.Rmd similarity index 99% rename from localVignettes/NowCast.Rmd rename to vignettes/NowCast.Rmd index 034c1ca3..b1886d92 100644 --- a/localVignettes/NowCast.Rmd +++ b/vignettes/NowCast.Rmd @@ -237,8 +237,6 @@ We run the following code to get things set up to use our new funcitons. library(PWFSLSmoke) logger.setup() library(MazamaSpatialUtils) -setSpatialDataDir('~/Data/Spatial') -loadSpatialData('NaturalEarthAdm1') ``` For the following examples we will use the Northwest Megafires data from the PWFSLSmoke package. In particular, we will look at PM~2.5~ data from Omak, WA, which was heavily impacted by smoke from wildfires during the second half of August, 2015: @@ -541,10 +539,10 @@ plot(example5_df$datetime, example5_df$monitored) lines(example5_df$datetime, example5_df$aqi, col="blue") ``` -TODO: clean up and beef up this example + -## Test Dataset + -> Under "test datasets" I'd like to see a simple CSV file with two columns: pm25_input, expected_output + -TODO: add test datasets +