From ff4a8e0e05a4e6a19ec6c33f802506ea9b164f09 Mon Sep 17 00:00:00 2001 From: tim-salabim Date: Sun, 19 Jul 2020 20:37:25 +0200 Subject: [PATCH] export addGeoRaster & addGeotiff #25 --- NAMESPACE | 7 ++ R/addGeoRaster.R | 165 ++++++++++++++++++++++++++++++++++++++++++-- man/addGeoRaster.Rd | 85 +++++++++++++++++++++++ man/addGeotiff.Rd | 113 ++++++++++++++++++++++++++++++ man/colorOptions.Rd | 19 +++++ 5 files changed, 384 insertions(+), 5 deletions(-) create mode 100644 man/addGeoRaster.Rd create mode 100644 man/addGeotiff.Rd create mode 100644 man/colorOptions.Rd diff --git a/NAMESPACE b/NAMESPACE index 50c7467..83618db 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -4,6 +4,8 @@ export(addCopyExtent) export(addExtent) export(addFeatures) export(addFgb) +export(addGeoRaster) +export(addGeotiff) export(addHomeButton) export(addImageQuery) export(addLocalFile) @@ -15,6 +17,7 @@ export(addStarsRGB) export(addStaticLabels) export(addTileFolder) export(clip2sfc) +export(colorOptions) export(garnishMap) export(removeHomeButton) export(removeMouseCoordinates) @@ -40,5 +43,9 @@ importFrom(raster,projection) importFrom(raster,sampleRegular) importFrom(sf,st_as_sfc) importFrom(sf,st_bbox) +importFrom(sf,st_is_longlat) importFrom(sf,st_transform) +importFrom(stars,st_as_stars) +importFrom(stars,st_warp) +importFrom(stars,write_stars) importFrom(stats,quantile) diff --git a/R/addGeoRaster.R b/R/addGeoRaster.R index 2071e4d..e710975 100644 --- a/R/addGeoRaster.R +++ b/R/addGeoRaster.R @@ -1,3 +1,61 @@ +#' Add stars/raster image to a leaflet map using optimised rendering. +#' +#' @details +#' This uses the leaflet plugin 'georaster-layer-for-leaflet' to render raster data. +#' See \url{https://github.com/GeoTIFF/georaster-layer-for-leaflet} for details. +#' The clue is that rendering uses simple nearest neighbor interpolation on-the-fly +#' to ensure smooth rendering. This enables handling of larger rasters than with +#' the standard \code{\link[leaflet]{addRasterImage}}. +#' +#' @param map the map to add the raster data to. +#' @param x the stars/raster object to be rendered. +#' @param group he name of the group this raster image should belong to. +#' @param layerId the layerId. +#' @param resolution the target resolution for the simple nearest neighbor interpolation. +#' Larger values will result in more detailed rendering, but may impact performance. +#' Default is 96 (pixels). +#' @param opacity opacity of the rendered layer. +#' @param options options to be passed to the layer. +#' See \code{\link[leaflet]{tileOptions}} for details. +#' @param colorOptions list defining the palette, breaks and na.color to be used. +#' @param project whether to project the RasterLayer to conform with leaflets +#' expected crs. Defaults to \code{TRUE} and things are likely to go haywire +#' if set to \code{FALSE}. +#' @param pixelValuesToColorFn optional JS function to be passed to the browser. +#' Can be used to fine tune and manipulate the color mapping. +#' See \url{https://github.com/r-spatial/leafem/issues/25} for some examples. +#' @param ... currently not used. +#' +#' @return +#' A leaflet map object. +#' +#' @examples +#' if (interactive()) { +#' library(leaflet) +#' library(leafem) +#' library(stars) +#' +#' tif = system.file("tif/L7_ETMs.tif", package = "stars") +#' x1 = read_stars(tif) +#' x1 = x1[, , , 3] # band 3 +#' +#' leaflet() %>% +#' addTiles() %>% +#' leafem:::addGeoRaster( +#' x1 +#' , opacity = 1 +#' , colorOptions = colorOptions( +#' palette = hcl.colors(256, "inferno") +#' ) +#' ) +#' } +#' +#' @importFrom stars st_as_stars st_warp write_stars +#' @importFrom sf st_is_longlat +#' +#' @export addGeoRaster +#' @name addGeoRaster +#' @rdname addGeoRaster addGeoRaster = function(map, x, group = NULL, @@ -6,13 +64,15 @@ addGeoRaster = function(map, opacity = 0.8, options = leaflet::tileOptions(), colorOptions = colorOptions(), - pixelValuesToColorFn = NULL) { + project = TRUE, + pixelValuesToColorFn = NULL, + ...) { if (inherits(x, "Raster")) { x = stars::st_as_stars(x) } - if (!sf::st_is_longlat(x)) { + if (project && !sf::st_is_longlat(x)) { x = stars::st_warp(x, crs = 4326) } @@ -42,7 +102,92 @@ addGeoRaster = function(map, } - +#' Add a GeoTIFF file to a leaflet map using optimised rendering. +#' +#' @details +#' This uses the leaflet plugin 'georaster-layer-for-leaflet' to render GeoTIFF data. +#' See \url{https://github.com/GeoTIFF/georaster-layer-for-leaflet} for details. +#' The GeoTIFF file is read directly in the browser using geotiffjs +#' (\url{https://geotiffjs.github.io/}), so there's no need to read data into +#' the current R session. GeoTIFF files can be read from the file system or via url. +#' The clue is that rendering uses simple nearest neighbor interpolation on-the-fly +#' to ensure smooth rendering. This enables handling of larger rasters than with +#' the standard \code{\link[leaflet]{addRasterImage}}. +#' +#' @param map the map to add the raster data to. +#' @param file path to the GeoTIFF file to render. +#' @param url url to the GeoTIFF file to render. Ignored if \code{file} is provided. +#' @param group he name of the group this raster image should belong to. +#' @param layerId the layerId. +#' @param resolution the target resolution for the simple nearest neighbor interpolation. +#' Larger values will result in more detailed rendering, but may impact performance. +#' Default is 96 (pixels). +#' @param opacity opacity of the rendered layer. +#' @param options options to be passed to the layer. +#' See \code{\link[leaflet]{tileOptions}} for details. +#' @param colorOptions list defining the palette, breaks and na.color to be used. +#' @param pixelValuesToColorFn optional JS function to be passed to the browser. +#' Can be used to fine tune and manipulate the color mapping. +#' See examples & \url{https://github.com/r-spatial/leafem/issues/25} for some examples. +#' @param ... currently not used. +#' +#' @return +#' A leaflet map object. +#' +#' @examples +#' if (interactive()) { +#' library(leaflet) +#' library(leafem) +#' +#' chrpsfl_202004 = "https://data.chc.ucsb.edu/products/CHIRPS-2.0/africa_monthly/tifs/chirps-v2.0.2020.04.tif.gz" +#' dsn_202004 = file.path(tempdir(), basename(chrpsfl_202004)) +#' +#' download.file(chrpsfl_202004, dsn_202004) +#' +#' tiffl_202004 = gsub(".gz", "", dsn_202004) +#' R.utils::gunzip(dsn_202004, tiffl_202004) +#' +#' myCustomJSFunc = htmlwidgets::JS( +#' " +#' pixelValuesToColorFn = (raster, colorOptions) => { +#' const cols = colorOptions.palette; +#' var scale = chroma.scale(cols); +#' +#' if (colorOptions.breaks !== null) { +#' scale = scale.classes(colorOptions.breaks); +#' } +#' var pixelFunc = values => { +#' let clr = scale.domain([raster.mins, raster.maxs]); +#' if (isNaN(values)) return colorOptions.naColor; +#' if (values < 120) return colorOptions.naColor; +#' return clr(values).hex(); +#' }; +#' return pixelFunc; +#' }; +#' " +#' ) +#' +#' leaflet() %>% +#' addTiles() %>% +#' addGeotiff( +#' file = tiffl_202004 +#' , opacity = 0.9 +#' , colorOptions = colorOptions( +#' palette = hcl.colors(256, "viridis") +#' , breaks = seq(0, 1000, 10) +#' , na.color = "transparent" +#' ) +#' , pixelValuesToColorFn = myCustomJSFunc +#' ) +#' +#' } +#' +#' @importFrom stars st_as_stars st_warp write_stars +#' @importFrom sf st_is_longlat +#' +#' @export addGeotiff +#' @name addGeotiff +#' @rdname addGeotiff addGeotiff = function(map, file = NULL, url = NULL, @@ -51,8 +196,9 @@ addGeotiff = function(map, resolution = 96, opacity = 0.8, options = leaflet::tileOptions(), - colorOptions = colorOptions(), - pixelValuesToColorFn = NULL) { + colorOptions = NULL, #colorOptions(), + pixelValuesToColorFn = NULL, + ...) { if (inherits(map, "mapview")) map = mapview2leaflet(map) @@ -116,6 +262,15 @@ addGeotiff = function(map, } + +#' Color options for addGeoRaster and addGeotiff +#' +#' @param palette the color palette to use. Can be a set of colors or a +#' color generating function such as the result of \code{\link[grDevices]{colorRampPalette}}. +#' @param breaks the breaks at which color should change. +#' @param na.color color for NA values (will map to NaN in Javascript). +#' +#' @export colorOptions = function(palette = NULL, breaks = NULL, na.color = "#bebebe22") { diff --git a/man/addGeoRaster.Rd b/man/addGeoRaster.Rd new file mode 100644 index 0000000..8c79d5e --- /dev/null +++ b/man/addGeoRaster.Rd @@ -0,0 +1,85 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/addGeoRaster.R +\name{addGeoRaster} +\alias{addGeoRaster} +\title{Add stars/raster image to a leaflet map using optimised rendering.} +\usage{ +addGeoRaster( + map, + x, + group = NULL, + layerId = NULL, + resolution = 96, + opacity = 0.8, + options = leaflet::tileOptions(), + colorOptions = colorOptions(), + project = TRUE, + pixelValuesToColorFn = NULL, + ... +) +} +\arguments{ +\item{map}{the map to add the raster data to.} + +\item{x}{the stars/raster object to be rendered.} + +\item{group}{he name of the group this raster image should belong to.} + +\item{layerId}{the layerId.} + +\item{resolution}{the target resolution for the simple nearest neighbor interpolation. +Larger values will result in more detailed rendering, but may impact performance. +Default is 96 (pixels).} + +\item{opacity}{opacity of the rendered layer.} + +\item{options}{options to be passed to the layer. +See \code{\link[leaflet]{tileOptions}} for details.} + +\item{colorOptions}{list defining the palette, breaks and na.color to be used.} + +\item{project}{whether to project the RasterLayer to conform with leaflets +expected crs. Defaults to \code{TRUE} and things are likely to go haywire +if set to \code{FALSE}.} + +\item{pixelValuesToColorFn}{optional JS function to be passed to the browser. +Can be used to fine tune and manipulate the color mapping. +See \url{https://github.com/r-spatial/leafem/issues/25} for some examples.} + +\item{...}{currently not used.} +} +\value{ +A leaflet map object. +} +\description{ +Add stars/raster image to a leaflet map using optimised rendering. +} +\details{ +This uses the leaflet plugin 'georaster-layer-for-leaflet' to render raster data. +See \url{https://github.com/GeoTIFF/georaster-layer-for-leaflet} for details. +The clue is that rendering uses simple nearest neighbor interpolation on-the-fly +to ensure smooth rendering. This enables handling of larger rasters than with +the standard \code{\link[leaflet]{addRasterImage}}. +} +\examples{ +if (interactive()) { + library(leaflet) + library(leafem) + library(stars) + + tif = system.file("tif/L7_ETMs.tif", package = "stars") + x1 = read_stars(tif) + x1 = x1[, , , 3] # band 3 + + leaflet() \%>\% + addTiles() \%>\% + leafem:::addGeoRaster( + x1 + , opacity = 1 + , colorOptions = leafem:::colorOptions( + palette = hcl.colors(256, "inferno") + ) + ) +} + +} diff --git a/man/addGeotiff.Rd b/man/addGeotiff.Rd new file mode 100644 index 0000000..c45f8a9 --- /dev/null +++ b/man/addGeotiff.Rd @@ -0,0 +1,113 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/addGeoRaster.R +\name{addGeotiff} +\alias{addGeotiff} +\title{Add a GeoTIFF file to a leaflet map using optimised rendering.} +\usage{ +addGeotiff( + map, + file = NULL, + url = NULL, + group = NULL, + layerId = NULL, + resolution = 96, + opacity = 0.8, + options = leaflet::tileOptions(), + colorOptions = NULL, + pixelValuesToColorFn = NULL, + ... +) +} +\arguments{ +\item{map}{the map to add the raster data to.} + +\item{file}{path to the GeoTIFF file to render.} + +\item{url}{url to the GeoTIFF file to render. Ignored if \code{file} is provided.} + +\item{group}{he name of the group this raster image should belong to.} + +\item{layerId}{the layerId.} + +\item{resolution}{the target resolution for the simple nearest neighbor interpolation. +Larger values will result in more detailed rendering, but may impact performance. +Default is 96 (pixels).} + +\item{opacity}{opacity of the rendered layer.} + +\item{options}{options to be passed to the layer. +See \code{\link[leaflet]{tileOptions}} for details.} + +\item{colorOptions}{list defining the palette, breaks and na.color to be used.} + +\item{pixelValuesToColorFn}{optional JS function to be passed to the browser. +Can be used to fine tune and manipulate the color mapping. +See examples & \url{https://github.com/r-spatial/leafem/issues/25} for some examples.} + +\item{...}{currently not used.} +} +\value{ +A leaflet map object. +} +\description{ +Add a GeoTIFF file to a leaflet map using optimised rendering. +} +\details{ +This uses the leaflet plugin 'georaster-layer-for-leaflet' to render GeoTIFF data. +See \url{https://github.com/GeoTIFF/georaster-layer-for-leaflet} for details. +The GeoTIFF file is read directly in the browser using geotiffjs +(\url{https://geotiffjs.github.io/}), so there's no need to read data into +the current R session. GeoTIFF files can be read from the file system or via url. +The clue is that rendering uses simple nearest neighbor interpolation on-the-fly +to ensure smooth rendering. This enables handling of larger rasters than with +the standard \code{\link[leaflet]{addRasterImage}}. +} +\examples{ +if (interactive()) { + library(leaflet) + library(leafem) + + chrpsfl_202004 = "https://data.chc.ucsb.edu/products/CHIRPS-2.0/africa_monthly/tifs/chirps-v2.0.2020.04.tif.gz" + dsn_202004 = file.path(tempdir(), basename(chrpsfl_202004)) + + download.file(chrpsfl_202004, dsn_202004) + + tiffl_202004 = gsub(".gz", "", dsn_202004) + R.utils::gunzip(dsn_202004, tiffl_202004) + + myCustomJSFunc = htmlwidgets::JS( + " + pixelValuesToColorFn = (raster, colorOptions) => { + const cols = colorOptions.palette; + var scale = chroma.scale(cols); + + if (colorOptions.breaks !== null) { + scale = scale.classes(colorOptions.breaks); + } + var pixelFunc = values => { + let clr = scale.domain([raster.mins, raster.maxs]); + if (isNaN(values)) return colorOptions.naColor; + if (values < 120) return colorOptions.naColor; + return clr(values).hex(); + }; + return pixelFunc; + }; + " + ) + + leaflet() \%>\% + addTiles() \%>\% + addGeotiff( + file = tiffl_202004 + , opacity = 0.9 + , colorOptions = colorOptions( + palette = hcl.colors(256, "viridis") + , breaks = seq(0, 1000, 10) + , na.color = "transparent" + ) + , pixelValuesToColorFn = myCustomJSFunc + ) + +} + +} diff --git a/man/colorOptions.Rd b/man/colorOptions.Rd new file mode 100644 index 0000000..24c5a31 --- /dev/null +++ b/man/colorOptions.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/addGeoRaster.R +\name{colorOptions} +\alias{colorOptions} +\title{Color options for addGeoRaster and addGeotiff} +\usage{ +colorOptions(palette = NULL, breaks = NULL, na.color = "#bebebe22") +} +\arguments{ +\item{palette}{the color palette to use. Can be a set of colors or a +color generating function such as the result of \code{\link[grDevices]{colorRampPalette}}.} + +\item{breaks}{the breaks at which color should change.} + +\item{na.color}{color for NA values (will map to NaN in Javascript).} +} +\description{ +Color options for addGeoRaster and addGeotiff +}