From 53c5c7ab56abbc75c70890cb8d7aa85958bbbfda Mon Sep 17 00:00:00 2001 From: jiajic <72078254+jiajic@users.noreply.github.com> Date: Tue, 19 Sep 2023 15:28:03 -0400 Subject: [PATCH] `crop()` method for `giottoLargeImage` - refactor portion of `createGiottoLargeImage()` for usage with `crop()` workflow - add `crop()` import and method - run document --- DESCRIPTION | 1 + NAMESPACE | 2 + R/create.R | 41 +++++++++----------- R/images.R | 67 +++++++++++++++++++++++++++++++++ R/methods_crop.R | 23 +++++++++++ R/package_imports.R | 1 + man/crop-generic.Rd | 24 ++++++++++++ man/ext-generic.Rd | 6 +++ man/spatraster_sample_values.Rd | 19 ++++++++++ 9 files changed, 161 insertions(+), 23 deletions(-) create mode 100644 R/methods_crop.R create mode 100644 man/crop-generic.Rd create mode 100644 man/spatraster_sample_values.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 188b5d98..65dd9ba5 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -109,6 +109,7 @@ Collate: 'methods-spin.R' 'methods-transpose.R' 'methods-wrap.R' + 'methods_crop.R' 'provenance.R' 'python_environment.R' 'save_load.R' diff --git a/NAMESPACE b/NAMESPACE index dec2e2aa..4ef13b81 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -305,6 +305,7 @@ exportMethods(as.sf) exportMethods(centroids) exportMethods(colnames) exportMethods(copy) +exportMethods(crop) exportMethods(dim) exportMethods(ext) exportMethods(featIDs) @@ -351,6 +352,7 @@ importMethodsFrom(Matrix,t) importMethodsFrom(terra,"ext<-") importMethodsFrom(terra,as.data.frame) importMethodsFrom(terra,centroids) +importMethodsFrom(terra,crop) importMethodsFrom(terra,ext) importMethodsFrom(terra,flip) importMethodsFrom(terra,ncol) diff --git a/R/create.R b/R/create.R index 7269b43b..19dec304 100644 --- a/R/create.R +++ b/R/create.R @@ -200,14 +200,14 @@ createGiottoObject = function(expression, ## evaluate if h5_file exists if(!is.null(h5_file)) { if(file.exists(h5_file)) { - wrap_msg("'", h5_file, "'", + wrap_msg("'", h5_file, "'", " file already exists and will be replaced", sep = "") file.remove(h5_file) } else { wrap_msg("Initializing file ", "'", h5_file, "'", sep = "") } } - + ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### gobject = setExpression(gobject = gobject, x = expression_data, @@ -2526,31 +2526,22 @@ createGiottoLargeImage = function(raster_object, ## 5. Get image characteristics by sampling - sampleValues = stats::na.omit(terra::spatSample(raster_object, - size = 5000, # Defines the rough maximum of pixels allowed when resampling - method = 'regular', - value = TRUE)) - if(nrow(sampleValues) == 0) { + sample_values = spatraster_sample_values(raster_object, size = 5000, verbose = verbose) + + if(nrow(sample_values) == 0) { if(verbose == TRUE) cat('No values discovered when sampling for image characteristics') } else { - # get intensity range - srMinmax = suppressWarnings(terra::minmax(raster_object)) - if(sum(is.infinite(srMinmax)) == 0) { # pull minmax values from terra spatRaster obj if img was small enough for them to be calculated - g_imageL@max_intensity = srMinmax[2] - g_imageL@min_intensity = srMinmax[1] - } else { # pull minmax values from sampled subset if img was too large - intensityRange = range(sampleValues) - g_imageL@max_intensity = intensityRange[2] - g_imageL@min_intensity = intensityRange[1] - } + + # find estimated intensity range + intensity_range = spatraster_intensity_range(raster_object = raster_object, + sample_values = sample_values) + g_imageL@min_intensity = intensity_range[['min']] + g_imageL@max_intensity = intensity_range[['max']] # find out if image is int or floating point - is_int = identical(sampleValues, round(sampleValues)) - if(is_int == TRUE) { - g_imageL@is_int = TRUE - } else { - g_imageL@is_int = FALSE - } + is_int = spatraster_is_int(raster_object = raster_object, + sample_values = sample_values) + g_imageL@is_int = is_int } @@ -2563,6 +2554,10 @@ createGiottoLargeImage = function(raster_object, } + + + + #' @title createGiottoLargeImageList #' @name createGiottoLargeImageList #' @description Creates a list of large giotto images that can be added to a Giotto object. Generates deep copy of SpatRaster diff --git a/R/images.R b/R/images.R index f2066fed..6ebeddde 100644 --- a/R/images.R +++ b/R/images.R @@ -730,6 +730,73 @@ plot_auto_largeImage_resample = function(gobject, +#' @title Sample values from SpatRaster +#' @name spatraster_sample_values +#' @param raster_object terra SpatRaster to sample from +#' @param size rough maximum of pixels allowed when resampling +#' @param verbose be verbose +#' @keywords internal +spatraster_sample_values = function(raster_object, size = 5000, verbose = TRUE) { + res = stats::na.omit( + terra::spatSample( + raster_object, + size = size, + method = 'regular', + value = TRUE) + ) + + if(nrow(res) == 0) { + if(isTRUE(verbose)) cat('No values discovered when sampling for image characteristics') + } + + res +} + + + + +#' @title Find SpatRaster intensity range +#' @name spatraster_intensity_range +#' @keywords internal +#' @noRd +#' @return named numeric vector of min then max detected values +spatraster_intensity_range = function( + raster_object, + sample_values = spatraster_sample_values(raster_object) +) { + # get intensity range + srMinmax = suppressWarnings(terra::minmax(raster_object)) + if(sum(is.infinite(srMinmax)) == 0) { # pull minmax values from terra spatRaster obj if img was small enough for them to be calculated + res = c(srMinmax[1], srMinmax[2]) + } else { # pull minmax values from sampled subset if img was too large + intensityRange = range(sample_values) + res = c(intensityRange[1],intensityRange[2]) + } + + names(res) = c('min', 'max') + return(res) +} + + + + +#' @title Find SpatRaster int or floating point +#' @name spatraster_is_int +#' @keywords internal +#' @noRd +#' @return logical +spatraster_is_int = function( + raster_object, + sample_values = spatraster_sample_values(raster_object) +) { + # find out if image is int or floating point + identical(sample_values, round(sample_values)) +} + + + + + #' @title Plot smoothed curve of giotto largeImage intensity values #' @name density_giottoLargeImage diff --git a/R/methods_crop.R b/R/methods_crop.R new file mode 100644 index 00000000..714c9060 --- /dev/null +++ b/R/methods_crop.R @@ -0,0 +1,23 @@ + + +#' @name crop-generic +#' @title Crop to a spatial subset +#' @description see [terra::crop]. Object x will be cropped using object y. +#' @param x object +#' @param y any object that has a SpatExtent or returns a SpatExtent +#' @param ... additional params to pass to terra::crop +NULL + + + +#' @describeIn crop-generic Crop a giottoLargeImage +#' @export +setMethod('crop', signature('giottoLargeImage'), function(x, y, ...) { + x@raster_object = terra::crop(x@raster_object, y) + x@extent = ext(x@raster_object) + intensity_range = spatraster_intensity_range(x@raster_object) + x@min_intensity = intensity_range[['min']] + x@max_intensity = intensity_range[['max']] + + x +}) diff --git a/R/package_imports.R b/R/package_imports.R index 46d33032..ce16a5e0 100644 --- a/R/package_imports.R +++ b/R/package_imports.R @@ -21,6 +21,7 @@ #' @importMethodsFrom terra plot #' @importMethodsFrom terra wrap #' @importMethodsFrom terra vect +#' @importMethodsFrom terra crop #' @importMethodsFrom terra as.data.frame #' @importMethodsFrom terra nrow ncol #' @importClassesFrom terra SpatExtent diff --git a/man/crop-generic.Rd b/man/crop-generic.Rd new file mode 100644 index 00000000..dd3c35ba --- /dev/null +++ b/man/crop-generic.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/methods_crop.R +\name{crop-generic} +\alias{crop-generic} +\alias{crop,giottoLargeImage-method} +\title{Crop to a spatial subset} +\usage{ +\S4method{crop}{giottoLargeImage}(x, y, ...) +} +\arguments{ +\item{x}{object} + +\item{y}{any object that has a SpatExtent or returns a SpatExtent} + +\item{...}{additional params to pass to terra::crop} +} +\description{ +see \link[terra:crop]{terra::crop}. Object x will be cropped using object y. +} +\section{Functions}{ +\itemize{ +\item \code{crop(giottoLargeImage)}: Crop a giottoLargeImage + +}} diff --git a/man/ext-generic.Rd b/man/ext-generic.Rd index 6ce556cf..27282aa5 100644 --- a/man/ext-generic.Rd +++ b/man/ext-generic.Rd @@ -7,6 +7,8 @@ \alias{ext,giottoPoints-method} \alias{ext,spatialNetworkObj-method} \alias{ext,giottoLargeImage-method} +\alias{ext<-,giottoPoints,SpatExtent-method} +\alias{ext<-,giottoPolygon,SpatExtent-method} \alias{ext<-,giottoLargeImage,SpatExtent-method} \alias{ext<-,ANY,ANY-method} \title{Get a SpatExtent} @@ -21,6 +23,10 @@ \S4method{ext}{giottoLargeImage}(x, ...) +\S4method{ext}{giottoPoints,SpatExtent}(x) <- value + +\S4method{ext}{giottoPolygon,SpatExtent}(x) <- value + \S4method{ext}{giottoLargeImage,SpatExtent}(x) <- value \S4method{ext}{ANY,ANY}(x) <- value diff --git a/man/spatraster_sample_values.Rd b/man/spatraster_sample_values.Rd new file mode 100644 index 00000000..c38b6fda --- /dev/null +++ b/man/spatraster_sample_values.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/images.R +\name{spatraster_sample_values} +\alias{spatraster_sample_values} +\title{Sample values from SpatRaster} +\usage{ +spatraster_sample_values(raster_object, size = 5000, verbose = TRUE) +} +\arguments{ +\item{raster_object}{terra SpatRaster to sample from} + +\item{size}{rough maximum of pixels allowed when resampling} + +\item{verbose}{be verbose} +} +\description{ +Sample values from SpatRaster +} +\keyword{internal}