diff --git a/.github/workflows/dev_check.yml b/.github/workflows/dev_check.yml index 0b18db3c..d33b0f6f 100644 --- a/.github/workflows/dev_check.yml +++ b/.github/workflows/dev_check.yml @@ -31,6 +31,9 @@ jobs: - name: Checkout repo for workflow access uses: actions/checkout@v3 + - name: Setup pandoc + uses: r-lib/actions/setup-pandoc@v2 + - name: Set up R environment uses: r-lib/actions/setup-r@v2 with: @@ -43,14 +46,7 @@ jobs: _R_CHECK_RD_XREFS: false with: dependencies: '"hard"' # do not use suggested dependencies - extra-packages: any::rcmdcheck, any::testthat, any::rlang, any::R.utils, any::remotes, any::sp, any::stars, any::raster, any::sf - - - name: Set up dependencies (GiottoData) - run: | - suppressWarnings({ - remotes::install_github('drieslab/GiottoData', build = FALSE) - }) - shell: Rscript {0} + extra-packages: any::rcmdcheck, any::testthat, any::rlang, any::R.utils, any::sp, any::stars, any::raster, any::sf, any::scattermore, any::exactextractr, github::drieslab/GiottoData - name: Run R CMD check uses: r-lib/actions/check-r-package@v2 diff --git a/DESCRIPTION b/DESCRIPTION index e651c7a3..fceba97f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: GiottoClass Title: Giotto Suite object definitions and framework -Version: 0.1.1 +Version: 0.1.2 Authors@R: c( person("Ruben", "Dries", email = "rubendries@gmail.com", role = c("aut", "cre")), @@ -34,7 +34,7 @@ Imports: data.table (>= 1.12.2), dbscan (>= 1.1-3), deldir (>= 1.0.6), - GiottoUtils (>= 0.1.0.1), + GiottoUtils (>= 0.1.2), igraph (>= 1.2.4.1), magick, Matrix (>= 1.6.2), @@ -54,11 +54,13 @@ Suggests: geometry, GiottoData, HDF5Array (>= 1.18.1), + knitr, R.utils, raster, remotes, rhdf5, rlang, + rmarkdown, RTriangle (>= 1.6-0.10), S4Vectors, ScaledMatrix, @@ -135,3 +137,4 @@ Collate: 'suite_reexports.R' 'zzz.R' URL: https://drieslab.github.io/GiottoClass/ +VignetteBuilder: knitr diff --git a/NAMESPACE b/NAMESPACE index 4cc82c67..5eba082c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,5 +1,10 @@ # Generated by roxygen2: do not edit by hand +S3method(.DollarNames,dimObj) +S3method(.DollarNames,metaData) +S3method(.DollarNames,spatEnrObj) +S3method(.DollarNames,spatLocsObj) +S3method(.DollarNames,terraVectData) S3method(as.data.table,SpatVector) S3method(as.data.table,giottoPoints) S3method(as.data.table,giottoPolygon) @@ -107,6 +112,7 @@ export(getExpression) export(getFeatureInfo) export(getFeatureMetadata) export(getGiottoImage) +export(getMonochromeColors) export(getMultiomics) export(getNearestNetwork) export(getPolygonInfo) @@ -368,6 +374,7 @@ importFrom(methods,show) importFrom(methods,slot) importFrom(methods,slotNames) importFrom(methods,validObject) +importFrom(utils,.DollarNames) importMethodsFrom(Matrix,t) importMethodsFrom(terra,"ext<-") importMethodsFrom(terra,as.data.frame) diff --git a/NEWS.md b/NEWS.md index cf9d4f8a..7d5a428a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,19 @@ -# Giotto Class 0.1.1 (2023/12/16) +# GiottoClass 0.1.2 (2024/01/02) + +## Added +- Added: `max_window` and `colors` slots to `giottoLargeImage`. Use `GiottoClass:::.update_giotto_image()` to update outdated objects. +- Added: `.bitdepth()` internal function to detect image bitdepth from sampled values +- Added: re-export `getMonochromeColors()` from *GiottoUtils* +- Added: `giottoPolygon`, `giottoLargeImage` method for `calculateOverlap()` +- Added: vignette for working with spatial classes +- Added: `output` param to `.spatraster_sample_values()`. Can now return as sampled `data.frame`, `array`, `magick`, `EBImage` + +## Changes +- Fixes: Updates to raster `calculateOverlap()` workflows + + +# GiottoClass 0.1.1 (2023/12/16) ## Breaking Changes - Removed: `getRainbowColors()` to *GiottoUtils* @@ -24,7 +38,9 @@ - Changed: `giottoPolygon` `plot()` now automatically switches to centroid plotting with more than 1e4 polys - Changed: Package internal functions now have `.` prefix -# Giotto Class 0.1.0 (23/11/29) + + +# GiottoClass 0.1.0 (2023/11/29) ## Breaking Changes diff --git a/R/aggregate.R b/R/aggregate.R index fce1fe13..0416bdc2 100644 --- a/R/aggregate.R +++ b/R/aggregate.R @@ -295,6 +295,31 @@ setMethod( ) +# * giottoPolygon giottoLargeImage #### +#' @rdname calculateOverlap +#' @export +setMethod( + "calculateOverlap", signature(x = "giottoPolygon", y = "giottoLargeImage"), + function( + x, y, + name_overlap = NULL, + poly_subset_ids = NULL, + return_gpolygon = TRUE, + verbose = TRUE, + ... + ) { + calculateOverlap( + x = x, + y = y@raster_object, + name_overlap = objName(y), + poly_subset_ids = poly_subset_ids, + verbose = verbose, + ... + ) + } +) + + # * giottoPolygon SpatRaster #### #' @rdname calculateOverlap #' @export @@ -307,6 +332,10 @@ setMethod( return_gpolygon = TRUE, verbose = TRUE, ...) { + if (is.null(name_overlap)) { + .gstop("calculateOverlap: name_overlap must be given") + } + res <- calculateOverlap( x = x[], y = y, @@ -1189,13 +1218,20 @@ setMethod( ) } - # pass to SpatVector method - overlapToMatrix( + argslist <- list( x = overlaps_data, count_info_column = count_info_column, output = output, ... ) + + # this arg not accepted by method + if (type == "intensity") { + argslist$count_info_column <- NULL + } + + # pass to SpatVector method + do.call(overlapToMatrix, args = argslist) } ) diff --git a/R/classes.R b/R/classes.R index fa4c1218..56896e07 100644 --- a/R/classes.R +++ b/R/classes.R @@ -428,6 +428,11 @@ updateGiottoObject <- function(gobject) { gobject@h5_file <- NULL } + # GiottoClass 0.1.2 adds max_window and colors slots to giottoLargeImage + if (!is.null(gobject@largeImages)) { + gobject@largeImages <- lapply(gobject@largeImages, .update_giotto_image) + } + # # 3.3.X release adds mirai slot # if (is.null(attr(gobject, "mirai"))) { # attr(gobject, "mirai") <- list() @@ -1464,8 +1469,10 @@ giottoImage <- setClass( #' @slot overall_extent terra extent object covering the original extent of image #' @slot scale_factor image scaling relative to spatial locations #' @slot resolution spatial location units covered per pixel -#' @slot max_intensity value to set as maximum intensity in color scaling -#' @slot min_intensity minimum value found +#' @slot max_intensity approximate maximum value +#' @slot min_intensity approximate minimum value +#' @slot max_window value to set as maximum intensity in color scaling +#' @slot colors color mappings in hex codes #' @slot is_int values are integers #' @slot file_path file path to the image if given #' @slot OS_platform Operating System to run Giotto analysis on @@ -1476,12 +1483,14 @@ giottoLargeImage <- setClass( slots = c( name = "ANY", raster_object = "ANY", - extent = "ANY", - overall_extent = "ANY", + extent = "ANY", # REMOVE? + overall_extent = "ANY", # REMOVE? New slot px_dims as replacement? scale_factor = "ANY", resolution = "ANY", - max_intensity = "ANY", - min_intensity = "ANY", + max_intensity = "numeric", + min_intensity = "numeric", + max_window = "numeric", # NEW + colors = 'character', # NEW is_int = "ANY", file_path = "ANY", OS_platform = "ANY" @@ -1493,10 +1502,55 @@ giottoLargeImage <- setClass( overall_extent = NULL, scale_factor = NULL, resolution = NULL, - max_intensity = NULL, - min_intensity = NULL, + max_intensity = NA_real_, + min_intensity = NA_real_, + max_window = NA_real_, + colors = grDevices::grey.colors(n = 256, start = 0, end = 1, gamma = 1), is_int = NULL, file_path = NULL, OS_platform = NULL ) ) + +# function for updating image objects if structure definitions have changed +.update_giotto_image = function(x) { + # 0.1.2 release adds colors & max_window slots + if (is.null(attr(x, "colors"))) { + attr(x, "colors") <- grDevices::grey.colors(n = 256, start = 0, end = 1, gamma = 1) + } + if (is.null(attr(x, "max_window"))) { + # get a max intensity value + if (!is.null(x@max_intensity)) { + x@max_intensity <- .spatraster_intensity_range(x@raster_object)[["max"]] + } + + attr(x, "max_window") <- .bitdepth(x@max_intensity, return_max = TRUE) + } + + # 0.1.x release adds giottoImageStack + # deprecate + + return(x) +} + + + +## giottoImageStack class #### + +## * definition #### +# giottoImageStack class + +# giottoImageStack <- setClass( +# Class = "giottoImageStack", +# +# slots = c( +# name = 'character', +# images = 'giottoLargeImage', +# weight = 'numeric' +# ) +# ) + + + + + diff --git a/R/create.R b/R/create.R index 45012be1..0492aae3 100644 --- a/R/create.R +++ b/R/create.R @@ -2840,7 +2840,10 @@ createGiottoLargeImage <- function(raster_object, ## 6. extent object g_imageL@extent <- g_imageL@overall_extent <- as.vector(terra::ext(raster_object)) - ## 7. return image object + ## 7. Assign discovered bitdepth max value as max window + g_imageL@max_window <- .bitdepth(g_imageL@max_intensity, return_max = TRUE) + + ## 8. return image object return(g_imageL) } diff --git a/R/images.R b/R/images.R index 2216d250..b81e22fe 100644 --- a/R/images.R +++ b/R/images.R @@ -755,25 +755,75 @@ plot_auto_largeImage_resample <- function(gobject, #' @title Sample values from SpatRaster #' @name .spatraster_sample_values -#' @param raster_object terra SpatRaster to sample from +#' @description +#' Sample numerical values from a `SpatRaster`. The output format depends on the +#' value of the `output` param. +#' @param raster_object terra `SpatRaster` to sample from #' @param size rough maximum of pixels allowed when resampling +#' @param output what output to return as. Defaults to "data.frame" #' @param verbose be verbose +#' @param \dots additional params to pass to `terra::spatSample` #' @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 - ) +.spatraster_sample_values <- function(raster_object, + size = 5000, + output = c('data.frame', 'array', 'magick', 'EBImage'), + verbose = NULL, + ...) { + + output <- match.arg( + arg = output, + choices = c('data.frame', 'array', 'magick', 'EBImage') + ) + + # account for possible giottoLargeImage input + if (inherits(raster_object, 'giottoLargeImage')) { + raster_object <- raster_object@raster_object + } + + # assemble argslist for terra::spatSample() + argslist <- list( + x = raster_object, + size = size, + as.df = TRUE, # default behavior + method = 'regular', + value = TRUE, + ... ) + if (output != 'data.frame') { + # if desired output is not data.frame, all other outputs require raster + argslist$as.raster <- TRUE + argslist$as.df <- FALSE + } + + res <- do.call(terra::spatSample, args = argslist) + + # convert and handle NA values + if (isTRUE(argslist$as.df)) { + res <- stats::na.omit(res) # data.frame remove NAs + } else { + # all others + res <- terra::as.array(res) + na_bool <- is.na(res) + res[na_bool] <- 0L # set NA values to 0 + } + + # throw error when there are no values discovered. if (nrow(res) == 0) { - if (isTRUE(verbose)) cat("No values discovered when sampling for image characteristics") + vmsg(.v = verbose, "No values discovered when sampling for image characteristics") + } + + # convert to specified image type if desired. + # Note that there is a conversion of image values to range of 0-1 + if (output %in% c('magick', 'EBImage')) { + res <- magick::image_read(res/max(res)) + } + if (output == 'EBImage') { + GiottoUtils::package_check("EBImage", repository = "Bioc") + res <- magick::as_EBImage(res) } - res + return(res) } @@ -1294,6 +1344,30 @@ convertGiottoLargeImageToMG <- function(gobject = NULL, } + +#' @name .bitdepth +#' @title Guess likely bitdepth from value(s) +#' @param x numeric vector. Values representative of the data to be assessed for +#' bitdepth. This is usually a sampled subset of values from the raster. +#' @param return_max logical. default is `FALSE`. Whether to return the maximum +#' possible value for the detected bitdepth instead of the bitdepth itself +#' @keywords internal +.bitdepth <- function(x, return_max = FALSE) { + res <- ceiling(log(max(x), base = 2L)) # power of 2 needed to represent value(s) + res <- 2^ceiling(log(res, base = 2L)) # actual bitdepth + + if (isTRUE(return_max)) { + res <- 2^res - 1 + } + + return(res) +} + + + + + + #' @title .terra_writeraster_datatype #' @name .terra_writeraster_datatype #' @description find likely compatible datatype for given image characteristics. @@ -1373,7 +1447,7 @@ convertGiottoLargeImageToMG <- function(gobject = NULL, } } else if (!is.null(quick_INTS_maxval)) { if (isTRUE(verbose)) cat("Selecting compatible datatype for given maximum value \n") - bitDepth <- ceiling(log(x = quick_INTS_maxval, base = 2)) + bitDepth <- .bitdepth(quick_INTS_maxval) } if (bitDepth > 32 && bitDepth <= 128) { diff --git a/R/methods-extract.R b/R/methods-extract.R index d30e4b7e..0a36c4ad 100644 --- a/R/methods-extract.R +++ b/R/methods-extract.R @@ -1,6 +1,10 @@ #' @include generics.R NULL + +# Documentations ------------------------------------------------------------ # + + #' @title Extract or replace parts of an object #' @name extract-methods #' @docType methods @@ -20,6 +24,9 @@ NULL #' NULL + +# --------------------------------------------------------------------------- # + # $ S4 access generic #### ## * coordDataDT #### @@ -48,6 +55,9 @@ setMethod( } ) + + +#' @export .DollarNames.spatLocsObj <- function(x, pattern) { names(x@coordinates) } @@ -78,6 +88,7 @@ setMethod( } ) +#' @export .DollarNames.spatEnrObj <- function(x, pattern) { names(x@enrichDT) } @@ -106,12 +117,14 @@ setMethod( } ) +#' @export .DollarNames.dimObj <- function(x, pattern) { names(x@misc) } ## * metaData #### +#' @export .DollarNames.metaData <- function(x, pattern) { colnames(x@metaDT) } @@ -163,6 +176,7 @@ setMethod( } ) +#' @export .DollarNames.terraVectData <- function(x, pattern) { names(x@spatVector) } diff --git a/R/methods-plot.R b/R/methods-plot.R index c11ecae1..c00004b3 100644 --- a/R/methods-plot.R +++ b/R/methods-plot.R @@ -23,8 +23,47 @@ NULL setMethod("plot", signature(x = "giottoImage", y = "missing"), function(x, y, ...) .plot_giottoimage_mg(giottoImage = x, ...)) #' @describeIn plot-generic Plot \emph{terra}-based giottoLargeImage object. ... param passes to \code{\link{.plot_giottolargeimage}} +#' @param col character. Colors. The default is grDevices::grey.colors(n = 256, start = 0, end = 1, gamma = 1) +#' @param max_intensity (optional) value to treat as maximum intensity in color scale +#' @param mar numeric vector of length 4 to set the margins of the plot (to make space for the legend). The default is (3, 5, 1.5, 1) +#' @param asRGB (optional) logical. Force RGB plotting if not automatically detected +#' @param legend logical or character. If not FALSE a legend is drawn. The character value can be used to indicate where the legend is to be drawn. For example "topright" or "bottomleft" +#' @param axes logical. Draw axes? +#' @param maxcell positive integer. Maximum number of cells to use for the plot +#' @param smooth logical. If TRUE the cell values are smoothed #' @export -setMethod("plot", signature(x = "giottoLargeImage", y = "missing"), function(x, y, ...) .plot_giottolargeimage(giottoLargeImage = x, ...)) +setMethod( + 'plot', + signature(x = 'giottoLargeImage', y = 'missing'), + function(x, y, col, max_intensity, mar, asRGB = FALSE, legend = FALSE, axes = TRUE, + maxcell = 5e5, smooth = TRUE, ...) + { + arglist = list(giottoLargeImage = x, + asRGB = asRGB, + legend = legend, + axes = axes, + maxcell = maxcell, + smooth = smooth, + ...) + + # check for pre-0.1.2 class + if (is.null(attr(x, "colors"))) { + .gstop("This image object is out of date + Please run `GiottoClass:::.update_giotto_image()` on this object.", + .n = 2) + } + + # If no 'col' param, pull from `colors` slot + if (missing("col")) arglist$col <- x@colors + else arglist$col <- col + # if no 'max_intensity' param, pull from `max_window` slot + if (missing("max_intensity")) arglist$max_intensity <- x@max_window + else arglist$max_intensity <- max_intensity + # if mar param provided, use it + if (!missing("mar")) arglist$mar <- mar + + do.call(.plot_giottolargeimage, args = arglist) + }) #' @describeIn plot-generic Plot \emph{terra}-based giottoPolygon object. ... param passes to \code{\link[terra]{plot}} #' @param point_size size of points when plotting giottoPolygon object centroids @@ -206,7 +245,7 @@ setMethod("plot", signature(x = "spatialNetworkObj", y = "missing"), function(x, #' @param crop_extent (optional) extent object to focus on specific region of image #' @param xmax_crop,xmin_crop,ymax_crop,ymin_crop (optional) crop min/max x and y bounds #' @param max_intensity (optional) value to treat as maximum intensity in color scale -#' @param asRGB (optional) boolean. Force RGB plotting if not automatically detected +#' @param asRGB (optional) logical. Force RGB plotting if not automatically detected #' @param stretch character. Option to stretch the values to increase contrast: "lin" #' linear or "hist" (histogram) #' @param axes boolean. Default = TRUE. Whether to draw axes diff --git a/R/methods-show.R b/R/methods-show.R index 296fae25..60b5869c 100644 --- a/R/methods-show.R +++ b/R/methods-show.R @@ -632,22 +632,27 @@ setMethod( f = "show", signature = "giottoLargeImage", definition = function(object) { - e <- ext(object) - img_dim <- dim(object)[c(2, 1, 3)] # x, y, layers - x_scalefactor <- diff(e[c(1, 2)]) / img_dim[1] - y_scalefactor <- diff(e[c(3, 4)]) / img_dim[2] - - show_class_and_name(object) - cat("Image extent :", show_ext(object)) - cat("Original image extent :", show_ext(object@overall_extent)) - cat("Scale factor :", paste(x_scalefactor, y_scalefactor, sep = ", "), "(x, y)\n") - cat("Resolution :", paste(1 / x_scalefactor, 1 / y_scalefactor, sep = ", "), "(x, y)\n") - cat("Layers :", img_dim[3], "\n") - cat("Estimated max intensity :", object@max_intensity, "\n") - cat("Estimated min intensity :", object@min_intensity, "\n") - if (object@is_int == TRUE) cat("Values : integers\n") - if (object@is_int == FALSE) cat("Values : floating point\n") - cat(paste0("File path : '", object@file_path, "'\n")) + if (is.null(object@raster_object)) { + cat('NULL giottoLargeImage') + } + else { + e <- ext(object) + img_dim <- dim(object)[c(2, 1, 3)] # x, y, layers + x_scalefactor <- diff(e[c(1, 2)]) / img_dim[1] + y_scalefactor <- diff(e[c(3, 4)]) / img_dim[2] + + show_class_and_name(object) + cat("Image extent :", show_ext(object)) + cat("Original image extent :", show_ext(object@overall_extent)) + cat("Scale factor :", paste(x_scalefactor, y_scalefactor, sep = ", "), "(x, y)\n") + cat("Resolution :", paste(1 / x_scalefactor, 1 / y_scalefactor, sep = ", "), "(x, y)\n") + cat("Layers :", img_dim[3], "\n") + cat("Estimated max intensity :", object@max_intensity, "\n") + cat("Estimated min intensity :", object@min_intensity, "\n") + if (object@is_int == TRUE) cat("Values : integers\n") + if (object@is_int == FALSE) cat("Values : floating point\n") + cat(paste0("File path : '", object@file_path, "'\n")) + } } ) diff --git a/R/package_imports.R b/R/package_imports.R index a1adc273..99653da7 100644 --- a/R/package_imports.R +++ b/R/package_imports.R @@ -30,4 +30,5 @@ #' @import GiottoUtils #' @import data.table #' @import utils +#' @importFrom utils .DollarNames NULL diff --git a/R/suite_reexports.R b/R/suite_reexports.R index 8c31a0b7..923859d0 100644 --- a/R/suite_reexports.R +++ b/R/suite_reexports.R @@ -2,3 +2,5 @@ GiottoUtils::getDistinctColors #' @export GiottoUtils::getRainbowColors +#' @export +GiottoUtils::getMonochromeColors diff --git a/_pkgdown.yml b/_pkgdown.yml index b6602677..58b2f11c 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -25,12 +25,18 @@ navbar: left: - intro - reference + - articles - news right: github components: reference: text: Documentation href: reference/index.html + articles: + text: Articles + menu: + - text: Spatial Geometry Objects + href: articles/spatial_geometries.html news: text: News href: news/index.html @@ -62,16 +68,21 @@ reference: - subtitle: Read desc: Read data in and create Giotto-native objects - contents: - - readDimReducData + - readCellMetadata + - readFeatMetadata + - readPolygonData + - readFeatData - readExprData - readExprMatrix - - readFeatData - - readNearestNetData - - readPolygonData - - readSpatEnrichData - readSpatLocsData - readSpatNetData - - .read_feature_metadata + - readSpatEnrichData + - readDimReducData + - readNearestNetData +- subtitle: evaluate + desc: Evaluate and format data for usage with Giotto +- contents: + - evaluate_input - subtitle: Create desc: Create Giotto-native objects - contents: @@ -218,22 +229,13 @@ reference: - subtitle: From desc: Convert from other frameworks to Giotto - contents: - - anndataToGiotto - - seuratToGiotto - - seuratToGiottoV4 - - seuratToGiottoV5 - - spatialExperimentToGiotto + - matches("ToGiotto") - giottoMasterToSuite - - gefToGiotto - subtitle: To desc: Convert Giotto Object to other frameworks - contents: - - giottoToAnnData + - starts_with("giottoTo") - createBentoAdata - - giottoToSeurat - - giottoToSeuratV4 - - giottoToSeuratV5 - - giottoToSpatialExperiment - title: Aggregate - subtitle: Polygon desc: Polygon and spatial unit aggregation and combination @@ -295,14 +297,14 @@ reference: - subtitle: Manipulation desc: Spatial manipulation and terra-based functions - contents: - - ext-generic - - flip-generic - - crop-generic + - ext + - flip + - crop - transpose-generic - - spin-generic + - spin - spatShift - - wrap-generic - - rescale-generic + - wrap + - rescale - rescalePolygons - subtitle: Querying desc: Spatial querying @@ -322,7 +324,7 @@ reference: - row-plus-colnames-generic - plot-generic - dims-generic - - copy-generic + - copy - subtitle: Hierarchical desc: Hierarchical tagging generics for Giotto exported classes - contents: @@ -343,6 +345,8 @@ reference: - title: As desc: As coercion functions - contents: + - as.points + - as.polygons - as.data.table - r_spatial_conversions - title: Python @@ -364,6 +368,7 @@ reference: - convertGiottoLargeImageToMG - estimateImageBg - distGiottoImage + - plot_auto_largeImage_resample - add_img_array_alpha - changeImageBg - writeGiottoLargeImage @@ -376,8 +381,6 @@ reference: - objHistory - update_giotto_params - showProcessingSteps - - get_args - - get_prev_fname - title: Utilities desc: Utility functions that are used in other code - contents: diff --git a/man/calculateOverlap.Rd b/man/calculateOverlap.Rd index bc7d6758..e28f4657 100644 --- a/man/calculateOverlap.Rd +++ b/man/calculateOverlap.Rd @@ -4,6 +4,7 @@ \alias{calculateOverlap} \alias{calculateOverlap,giotto,missing-method} \alias{calculateOverlap,giottoPolygon,giottoPoints-method} +\alias{calculateOverlap,giottoPolygon,giottoLargeImage-method} \alias{calculateOverlap,giottoPolygon,SpatRaster-method} \alias{calculateOverlap,SpatVector,SpatRaster-method} \alias{calculateOverlap,SpatVector,SpatVector-method} @@ -37,6 +38,16 @@ ... ) +\S4method{calculateOverlap}{giottoPolygon,giottoLargeImage}( + x, + y, + name_overlap = NULL, + poly_subset_ids = NULL, + return_gpolygon = TRUE, + verbose = TRUE, + ... +) + \S4method{calculateOverlap}{giottoPolygon,SpatRaster}( x, y, diff --git a/man/dot-bitdepth.Rd b/man/dot-bitdepth.Rd new file mode 100644 index 00000000..6c903367 --- /dev/null +++ b/man/dot-bitdepth.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/images.R +\name{.bitdepth} +\alias{.bitdepth} +\title{Guess likely bitdepth from value(s)} +\usage{ +.bitdepth(x, return_max = FALSE) +} +\arguments{ +\item{x}{numeric vector. Values representative of the data to be assessed for +bitdepth. This is usually a sampled subset of values from the raster.} + +\item{return_max}{logical. default is \code{FALSE}. Whether to return the maximum +possible value for the detected bitdepth instead of the bitdepth itself} +} +\description{ +Guess likely bitdepth from value(s) +} +\keyword{internal} diff --git a/man/dot-plot_giottolargeimage.Rd b/man/dot-plot_giottolargeimage.Rd index a9ab6a43..f2e3f486 100644 --- a/man/dot-plot_giottolargeimage.Rd +++ b/man/dot-plot_giottolargeimage.Rd @@ -39,7 +39,7 @@ \item{max_intensity}{(optional) value to treat as maximum intensity in color scale} -\item{asRGB}{(optional) boolean. Force RGB plotting if not automatically detected} +\item{asRGB}{(optional) logical. Force RGB plotting if not automatically detected} \item{stretch}{character. Option to stretch the values to increase contrast: "lin" linear or "hist" (histogram)} diff --git a/man/dot-spatraster_sample_values.Rd b/man/dot-spatraster_sample_values.Rd index 9dd23373..5711e5cf 100644 --- a/man/dot-spatraster_sample_values.Rd +++ b/man/dot-spatraster_sample_values.Rd @@ -4,16 +4,27 @@ \alias{.spatraster_sample_values} \title{Sample values from SpatRaster} \usage{ -.spatraster_sample_values(raster_object, size = 5000, verbose = TRUE) +.spatraster_sample_values( + raster_object, + size = 5000, + output = c("data.frame", "array", "magick", "EBImage"), + verbose = NULL, + ... +) } \arguments{ -\item{raster_object}{terra SpatRaster to sample from} +\item{raster_object}{terra \code{SpatRaster} to sample from} \item{size}{rough maximum of pixels allowed when resampling} +\item{output}{what output to return as. Defaults to "data.frame"} + \item{verbose}{be verbose} + +\item{\dots}{additional params to pass to \code{terra::spatSample}} } \description{ -Sample values from SpatRaster +Sample numerical values from a \code{SpatRaster}. The output format depends on the +value of the \code{output} param. } \keyword{internal} diff --git a/man/giottoLargeImage-class.Rd b/man/giottoLargeImage-class.Rd index df1a148e..1a94f474 100644 --- a/man/giottoLargeImage-class.Rd +++ b/man/giottoLargeImage-class.Rd @@ -23,9 +23,13 @@ class to handle images too large to load in normally through magick \item{\code{resolution}}{spatial location units covered per pixel} -\item{\code{max_intensity}}{value to set as maximum intensity in color scaling} +\item{\code{max_intensity}}{approximate maximum value} -\item{\code{min_intensity}}{minimum value found} +\item{\code{min_intensity}}{approximate minimum value} + +\item{\code{max_window}}{value to set as maximum intensity in color scaling} + +\item{\code{colors}}{color mappings in hex codes} \item{\code{is_int}}{values are integers} diff --git a/man/plot-generic.Rd b/man/plot-generic.Rd index 1f334478..8d7692dd 100644 --- a/man/plot-generic.Rd +++ b/man/plot-generic.Rd @@ -14,7 +14,19 @@ \usage{ \S4method{plot}{giottoImage,missing}(x, y, ...) -\S4method{plot}{giottoLargeImage,missing}(x, y, ...) +\S4method{plot}{giottoLargeImage,missing}( + x, + y, + col, + max_intensity, + mar, + asRGB = FALSE, + legend = FALSE, + axes = TRUE, + maxcell = 5e+05, + smooth = TRUE, + ... +) \S4method{plot}{giottoPolygon,missing}( x, @@ -39,6 +51,22 @@ \item{\dots}{additional parameters to pass} +\item{col}{character. Colors. The default is grDevices::grey.colors(n = 256, start = 0, end = 1, gamma = 1)} + +\item{max_intensity}{(optional) value to treat as maximum intensity in color scale} + +\item{mar}{numeric vector of length 4 to set the margins of the plot (to make space for the legend). The default is (3, 5, 1.5, 1)} + +\item{asRGB}{(optional) logical. Force RGB plotting if not automatically detected} + +\item{legend}{logical or character. If not FALSE a legend is drawn. The character value can be used to indicate where the legend is to be drawn. For example "topright" or "bottomleft"} + +\item{axes}{logical. Draw axes?} + +\item{maxcell}{positive integer. Maximum number of cells to use for the plot} + +\item{smooth}{logical. If TRUE the cell values are smoothed} + \item{point_size}{size of points when plotting giottoPoints} \item{type}{what to plot: either 'poly' (default) or polygon 'centroid'} diff --git a/man/reexports.Rd b/man/reexports.Rd index 911cea2d..e9f9771b 100644 --- a/man/reexports.Rd +++ b/man/reexports.Rd @@ -5,6 +5,7 @@ \alias{reexports} \alias{getDistinctColors} \alias{getRainbowColors} +\alias{getMonochromeColors} \title{Objects exported from other packages} \keyword{internal} \description{ @@ -12,6 +13,6 @@ These objects are imported from other packages. Follow the links below to see their documentation. \describe{ - \item{GiottoUtils}{\code{\link[GiottoUtils]{getDistinctColors}}, \code{\link[GiottoUtils]{getRainbowColors}}} + \item{GiottoUtils}{\code{\link[GiottoUtils]{getDistinctColors}}, \code{\link[GiottoUtils]{getMonochromeColors}}, \code{\link[GiottoUtils]{getRainbowColors}}} }} diff --git a/vignettes/spatial_geometries.Rmd b/vignettes/spatial_geometries.Rmd new file mode 100644 index 00000000..3e9a0682 --- /dev/null +++ b/vignettes/spatial_geometries.Rmd @@ -0,0 +1,195 @@ +--- +title: "Giotto spatial geometry classes" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Giotto spatial geometry classes} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +## 1. Overview + +*GiottoClass* represents spatial polygons and points respectively as S4 classes +`giottoPolygon` and `giottoPoints`. These objects are built on top of *terra* +`SpatVectors` in order to represent spatial biology. They also respond to many +of terra's generics, with some enhancements. Both objects have a +`spatVector` slot that contains the main information. This common slot is inherited +from the `VIRTUAL` `terraVectData` class, however this naming may be subject to +change as other data representations are added. + + +The structures of these classes are: + +``` +terraVectData +\- spatVector + +giottoPolygon +\- spatVector (spatial polygons SpatVector) +\- spatVectorCentroids (centroids points SpatVector) +\- overlaps (list of overlapped features info) +\- name (object name/spat_unit) +\- unique_ID_cache (cache of polygon IDs) + +giottoPoints +\- spatVector (spatial points SpatVector) +\- networks (feature network) +\- feat_type (object name/feat_type) +\- unique_ID_cache (cache of feature IDs) +``` +Of note are the `unique_ID_cache` slots which are used to get around the memory +usage incurred when frequently accessing the `SpatVectors` attributes. The caches +should be updated after modifications to the object. This is automatically +performed when using `[]` subsetting. + + +## 2.1 Polygon object creation + +`createGiottoPolygon()` accepts a number of inputs, including filepaths to spatial +files such as .wkt, .shp, or .GeoJSON or mask image files of common formats such +as .tif or .png. After reading in these files, they are passed to the respective +methods for `SpatVector` and `SpatRaster` (mask image). + +`data.frame-like` inputs are also allowed as long as they are formatted similarly +to *terra's* `matrix` representation of polygon geometries, with at least the +following columns. + +- `geom`: integer identifier for each polygon +- `part`: integer identifier for each part of the polygon, in the case of a multi polygon +- `x`: numeric x coordinate of a polygon vertex +- `y`: numeric y coordinate of a polygon vertex +- `hole`: integer identifier for each hole within a polygon +- `poly_ID`: standard Giotto identifier for the polygon. Akin to cell_ID + +Additional columns can be included as other attributes, but a set of `poly_ID`s +are required. + +*For de-novo generation of simple polygon arrays, see the documentation for +`polyStamp()` and `tessellate()`* + +## 2.2 Points object creation + +There are relatively fewer input methods for `giottoPoints` since they currently +tend to be provided as flat files as opposed to spatial-specific formats. +`createGiottoPoints()` works with +with `data.frame-like` inputs with at least columns for x-coordinate, y-coordinate, +and ID information. The first two detected numeric columns are expected to be +x and y respectively. The first character column is assumed to be the feat_IDs. +*terra* `SpatVector` inputs are also accepted. + +A helpful parameter is `split_keyword` which accepts a list of regex keywords +to pull matched features into separate `giottoPoints` objects. This is useful +in situations where multiple feature modalities and/or QC targets are provided +together and would interfere with each other if analyzed together. (see examples +in `createGiottoPoints()` documentation) + + +## 3. Subsetting + +`giottoPoints` and `giottoPolygons` can be subset either by logical vectors +or by ID. +```{r} +library(GiottoClass) +gpoly <- GiottoData::loadSubObjectMini("giottoPolygon") +gpoints <- GiottoData::loadSubObjectMini("giottoPoints") + +# full objects +print(gpoly) +print(gpoints) + +# subsets +plot(gpoly) +plot(gpoly[c("100210519278873141813371229408401071444", "101161259912191124732236989250178928032", "101488859781016188084173008420811094152")]) +print(gpoly[c("100210519278873141813371229408401071444", "101161259912191124732236989250178928032", "101488859781016188084173008420811094152")]) +plot(gpoly[c(T,F)]) + +plot(gpoints) +plot(gpoints[c("Fn1")]) +print(gpoints[c("Fn1")]) +``` + +`$` extraction can be used to pull attributes of these objects as vectors +```{r} +head(gpoly$poly_ID) +``` + +## 4. Conversion to data.table +*GiottoClass* has a set of functions for converting `giottoPoints` and `giottoPolygon` +objects between spatial classes using `as.sf()`, `as.sp()`, `as.stars()`, and +`as.terra()`. +*terra*-based `giottoPoints` and `giottoPolygon` objects can also +be converted into `data.table` for geometry manipulation. This method largely +piggybacks off *terra*'s `as.data.frame()` and adds support for `geom = "XY"` +for polygon geometry. + +```{r} +gpoly_dt <- data.table::as.data.table(gpoly, geom = "XY") +gpoints_dt <- data.table::as.data.table(gpoints, geom = "XY") + +print(gpoly_dt) +print(gpoints_dt) +``` + +These tables can then be either re-ingested using `createGiottoPolygon()` and +`createGiottoPoints()` or converted to `SpatVector` using `as.polygons()` or +`as.points()` +```{r} +print(as.polygons(gpoly_dt)) + +# gpoints currently still requires addition of geom, part, and hole cols +gpoints_dt[, geom := 1:.N] +gpoints_dt[, part := 1] +gpoints_dt[, hole := 0] +print(as.points(gpoints_dt)) +``` + +## 5. Centroids +Centroids information are carried by `giottoPolygon` objects in the `spatVectorCentroids` +slot. The `centroids()` generic from *terra* pulls from this slot if the +information already exists. Otherwise, it calculates and returns a set of +centroids for the polygons as `SpatVector` points. The `append_gpolygon` param +makes it so that the `giottoPolygon` with the centroids info appended is returned +instead. + + +## 6.1 Overlaps +Overlaps are sets of features overlapped by the polygons. `calculateOverlaps()` +is a generic function that performs this overlapping between polygons and points +and polygons and raster (intensity) data. +```{r} +gpoly@overlaps <- NULL # reset overlaps info +gpoly <- calculateOverlap(gpoly, gpoints, verbose = FALSE) + +gimg <- GiottoData::loadSubObjectMini("giottoLargeImage") +gpoly <- calculateOverlap(gpoly, gimg, verbose = FALSE, progress = FALSE) +``` + + +Overlaps are stored as a `list` under the `giottoPolygon` `overlaps` slot, +separated by modalities. This list can be retrieved using `overlaps()`. +In the case of overlapped points geometries, the list items are points `SpatVector` +objects. The `poly_ID` column tracks which + +For overlaps intensities, the results are `data.tables` in a nested +list called `intensities` +```{r} +print(gpoly@overlaps$rna) +print(gpoly@overlaps$intensity) +``` + +## 6.2 Overlaps to matrix +Overlap results can be converted into expression matrices using `overlapToMatrix()` +```{r} +# points, rna modality (default) +rna_mat <- overlapToMatrix(gpoly) +print(rna_mat[1:3,1:3]) + +# intensity, dapi_z0 +intens_mat <- overlapToMatrix(gpoly, type = "intensity", feat_info = "dapi_z0") +print(intens_mat[1, 1:3, drop = FALSE]) +``` + +```{r} +sessionInfo() +``` +