From aa7e809de7a24d4e8b975a47c2a5dc2fc9cfae28 Mon Sep 17 00:00:00 2001 From: Nick-Eagles Date: Mon, 14 Oct 2024 15:34:07 -0400 Subject: [PATCH] Merge help files for prep_fiji_* functions to simplify understanding of examples (and reduce computational time running examples) --- R/{prep_fiji_coords.R => prep_fiji.R} | 164 ++++++++++++++++++++--- R/prep_fiji_image.R | 160 ---------------------- man/{prep_fiji_image.Rd => prep_fiji.Rd} | 62 ++++++--- man/prep_fiji_coords.Rd | 74 ---------- 4 files changed, 192 insertions(+), 268 deletions(-) rename R/{prep_fiji_coords.R => prep_fiji.R} (56%) delete mode 100644 R/prep_fiji_image.R rename man/{prep_fiji_image.Rd => prep_fiji.Rd} (53%) delete mode 100644 man/prep_fiji_coords.Rd diff --git a/R/prep_fiji_coords.R b/R/prep_fiji.R similarity index 56% rename from R/prep_fiji_coords.R rename to R/prep_fiji.R index 34e1f96..cceb477 100644 --- a/R/prep_fiji_coords.R +++ b/R/prep_fiji.R @@ -1,29 +1,41 @@ -#' Apply transform info from Fiji XML output +#' Prepare Fiji outputs for building a SpatialExperiment #' +#' Together, `prep_fiji_image()` and `prep_fiji_coords()` process Fiji outputs +#' and generate one directory per group resembling Spaceranger's +#' [spatial outputs](https://www.10xgenomics.com/support/software/space-ranger/latest/analysis/outputs/spatial-outputs); +#' in particular, `tissue_positions.csv`, `tissue_lowres_image.png`, and +#' `scalefactors_json.json` files are created. These functions are necessary to +#' run in preparation for \code{build_SpatialExperiment()}. +#' #' Given a `data.frame()` of sample information (\code{sample_info}) with #' columns \code{capture_area}, \code{group}, and \code{fiji_xml_path}, -#' expected to have one unique path to Fiji XML output per group, read in -#' the pixel coordinates from each capture area's \code{tissue_positions.csv} +#' expected to have one unique path to Fiji XML output per group, `prep_fiji_coords` +#' reads in the pixel coordinates from each capture area's \code{tissue_positions.csv} #' file from SpaceRanger, and transform using the rotation matrix specified -#' by Fiji . -#' Write one new \code{tissue_positions.csv} file per group. +#' by Fiji . It writes one new \code{tissue_positions.csv} +#' file per group. +#' +#' After stitching all groups in \code{sample_info} with Fiji, images of +#' various resolutions (pixel dimensions) are left. `prep_fiji_image()` creates copies +#' of each image whose largest dimension is \code{lowres_max_size} pixels. It +#' also creates a corresponding \code{scalefactors_json.json} file much like +#' SpaceRanger's. #' +#' @name prep_fiji #' @param out_dir A \code{character(1)} vector giving a path to a directory to #' place the output pixel coordinates CSVs. It must exist in advance. +#' @param lowres_max_size An \code{integer(1)} vector: the resolution (number of +#' pixels) of the larger dimension of the output image(s), considered to be "low +#' resolution". The default value of `1200` assumes that you are stitching +#' together at most a 2 by 2 grid of Visium capture areas, where each has at +#' most 600 pixels on the longest dimension (as is the default in SpaceRanger). #' @inheritParams add_array_coords #' #' @return This function returns a `character()` with the file paths to the -#' `tissue_positions.csv` files it created. +#' files it created. For `prep_fiji_coords()`, these are the `tissue_positions.csv` +#' files; for `prep_fiji_image()`, these are the `tissue_lowres_image.png` and +#' `scalefactors_json.json` files. #' -#' @import xml2 -#' @importFrom stringr str_replace_all str_detect -#' @importFrom readr read_csv write_csv -#' @importFrom rjson fromJSON -#' @importFrom pkgcond suppress_warnings -#' -#' @family functions for parsing Fiji outputs -#' -#' @export #' @author Nicholas J. Eagles #' #' @examples @@ -60,11 +72,125 @@ #' } #' #' spe_input_dir <- tempdir() -#' out_file <- prep_fiji_coords(sample_info, out_dir = spe_input_dir) -#' out_file +#' out_paths_image <- prep_fiji_image( +#' sample_info, +#' out_dir = spe_input_dir, lowres_max_size = 1000 +#' ) +#' out_path_coords <- prep_fiji_coords(sample_info, out_dir = spe_input_dir) #' -#' # A file of spatial coordinates for the stitched Br2719 was produced -#' readr::read_csv(out_file) +#' # A "low resolution" stitched image was produced, which has 1000 +#' # pixels in its largest dimension +#' this_image <- imager::load.image( +#' file.path(spe_input_dir, "Br2719", "tissue_lowres_image.png") +#' ) +#' dim(this_image) +#' library("imager") +#' plot(this_image) +#' +#' # 'prep_fiji_image' produced an image and scalefactors +#' out_paths_image +#' +#' # 'prep_fiji_coords' produced a file of spatial coordinates for the +#' # stitched Br2719 +#' readr::read_csv(out_path_coords) +NULL + +#' @describeIn prep_fiji Create low-res images and scale factors from high-res +#' Fiji output images +#' @importFrom imager load.image resize save.image +#' @importFrom rjson fromJSON toJSON +#' +#' @export +prep_fiji_image <- function(sample_info, out_dir, lowres_max_size = 1200) { + ## For R CMD check + group <- NULL + + # State assumptions about columns expected to be in sample_info + expected_cols <- c( + "capture_area", "group", "fiji_image_path", "intra_group_scalar", + "group_hires_scalef", "spaceranger_dir" + ) + if (!all(expected_cols %in% colnames(sample_info))) { + stop( + sprintf( + 'Missing at least one of the following columns in "sample_info": "%s"', + paste(expected_cols, collapse = '", "') + ) + ) + } + + if (!all(file.exists(sample_info$fiji_image_path))) { + stop("All files in 'sample_info$fiji_image_path' must exist.") + } + + if (!dir.exists(out_dir)) { + stop("'out_dir' does not exist; please create it.") + } + + out_paths <- list() + for (this_group in unique(sample_info$group)) { + this_sample_info <- sample_info |> + dplyr::filter(group == this_group) + + if (length(unique(this_sample_info$fiji_image_path)) > 1) { + stop("Expected one unique path for 'fiji_image_path' per group in 'sample_info'.") + } + + this_image <- imager::load.image(this_sample_info$fiji_image_path[1]) + + # Combine info about the original scalefactors of the first capture + # area with group-related scalars to form a new scalefactors JSON + # for the whole stitched group + sr_json <- rjson::fromJSON( + file = file.path( + this_sample_info$spaceranger_dir[1], "scalefactors_json.json" + ) + ) + + low_over_hi <- lowres_max_size / max(dim(this_image)[seq(2)]) + sr_json <- list( + tissue_hires_scalef = this_sample_info$group_hires_scalef[[1]], + tissue_lowres_scalef = this_sample_info$group_hires_scalef[[1]] * + low_over_hi, + spot_diameter_fullres = sr_json$spot_diameter_fullres * + this_sample_info$intra_group_scalar[[1]] + ) + + this_image <- imager::resize( + this_image, + as.integer(low_over_hi * dim(this_image)[1]), + as.integer(low_over_hi * dim(this_image)[2]) + ) + + # Save the lowres image and scalefactors JSON in a subdirectory of + # 'out_dir' named with the current group + this_out_dir <- file.path(out_dir, this_group) + dir.create(this_out_dir, showWarnings = FALSE) + imager::save.image( + this_image, file.path(this_out_dir, "tissue_lowres_image.png") + ) + write( + rjson::toJSON(sr_json), + file.path(this_out_dir, "scalefactors_json.json") + ) + out_paths[[this_group]] <- c( + file.path(this_out_dir, "tissue_lowres_image.png"), + file.path(this_out_dir, "scalefactors_json.json") + ) + } + + return(unname(unlist(out_paths))) +} + +#' @describeIn prep_fiji Apply transform info from Fiji XML output +#' +#' @import xml2 +#' @importFrom stringr str_replace_all str_detect +#' @importFrom readr read_csv write_csv +#' @importFrom rjson fromJSON +#' @importFrom pkgcond suppress_warnings +#' +#' @export prep_fiji_coords <- function(sample_info, out_dir) { ## For R CMD check group <- barcode <- key <- pxl_col_in_fullres <- pxl_row_in_fullres <- NULL diff --git a/R/prep_fiji_image.R b/R/prep_fiji_image.R deleted file mode 100644 index 0fde3fe..0000000 --- a/R/prep_fiji_image.R +++ /dev/null @@ -1,160 +0,0 @@ -#' Create low-res images and scale factors from high-res Fiji output images -#' -#' After stitching all groups in \code{sample_info} with Fiji, images of -#' various resolutions (pixel dimensions) are left. This function creates copies -#' of each image whose largest dimension is \code{lowres_max_size} pixels. It -#' also creates a corresponding \code{scalefactors_json.json} file much like -#' SpaceRanger's. In conjunction with `prep_fiji_coords()`, this function -#' prepares for building the [SpatialExperiment-class][SpatialExperiment::SpatialExperiment-class] -#' with \code{build_SpatialExperiment()}. -#' -#' @param out_dir A \code{character(1)} vector giving a path to a directory to place -#' the output image(s) and scale factors. It must exist in advance. -#' @param lowres_max_size An \code{integer(1)} vector: the resolution (number of -#' pixels) of the larger dimension of the output image(s), considered to be "low -#' resolution". The default value of `1200` assumes that you are stitching -#' together at most a 2 by 2 grid of Visium capture areas, where each has at -#' most 600 pixels on the longest dimension (as is the default in SpaceRanger). -#' @inheritParams add_array_coords -#' -#' @return This function returns `character()` with the file paths to the -#' `tissue_lowres_image.png` and `scalefactors_json.json` files it created. -#' -#' @importFrom imager load.image resize save.image -#' @importFrom rjson fromJSON toJSON -#' -#' @family functions for parsing Fiji outputs -#' -#' @export -#' @author Nicholas J. Eagles -#' -#' @examples -#' if (file.exists("sample_info.rds")) { -#' sample_info <- readRDS("sample_info.rds") -#' } else { -#' sample_info <- dplyr::tibble( -#' group = "Br2719", -#' capture_area = c("V13B23-283_A1", "V13B23-283_C1", "V13B23-283_D1") -#' ) -#' # Add 'spaceranger_dir' column -#' sr_dir <- tempdir() -#' temp <- unzip( -#' spatialLIBD::fetch_data("visiumStitched_brain_spaceranger"), -#' exdir = sr_dir -#' ) -#' sample_info$spaceranger_dir <- file.path( -#' sr_dir, sample_info$capture_area, "outs", "spatial" -#' ) -#' -#' # Add Fiji-output-related columns -#' fiji_dir <- tempdir() -#' temp <- unzip( -#' spatialLIBD::fetch_data("visiumStitched_brain_Fiji_out"), -#' exdir = fiji_dir -#' ) -#' sample_info$fiji_xml_path <- temp[grep("xml$", temp)] -#' sample_info$fiji_image_path <- temp[grep("png$", temp)] -#' -#' ## Re-size images and add more information to the sample_info -#' sample_info <- rescale_fiji_inputs(sample_info, out_dir = tempdir()) -#' -#' saveRDS(sample_info, "sample_info.rds") -#' } -#' -#' spe_input_dir <- tempdir() -#' out_paths <- prep_fiji_image( -#' sample_info, -#' out_dir = spe_input_dir, lowres_max_size = 1000 -#' ) -#' -#' # A "low resolution" stitched image was produced, which has 1000 -#' # pixels in its largest dimension -#' this_image <- imager::load.image( -#' file.path(spe_input_dir, "Br2719", "tissue_lowres_image.png") -#' ) -#' dim(this_image) -#' library("imager") -#' plot(this_image) -#' -#' # In total, an image and scalefactors were written -#' out_paths -prep_fiji_image <- function(sample_info, out_dir, lowres_max_size = 1200) { - ## For R CMD check - group <- NULL - - # State assumptions about columns expected to be in sample_info - expected_cols <- c( - "capture_area", "group", "fiji_image_path", "intra_group_scalar", - "group_hires_scalef", "spaceranger_dir" - ) - if (!all(expected_cols %in% colnames(sample_info))) { - stop( - sprintf( - 'Missing at least one of the following columns in "sample_info": "%s"', - paste(expected_cols, collapse = '", "') - ) - ) - } - - if (!all(file.exists(sample_info$fiji_image_path))) { - stop("All files in 'sample_info$fiji_image_path' must exist.") - } - - if (!dir.exists(out_dir)) { - stop("'out_dir' does not exist; please create it.") - } - - out_paths <- list() - for (this_group in unique(sample_info$group)) { - this_sample_info <- sample_info |> - dplyr::filter(group == this_group) - - if (length(unique(this_sample_info$fiji_image_path)) > 1) { - stop("Expected one unique path for 'fiji_image_path' per group in 'sample_info'.") - } - - this_image <- imager::load.image(this_sample_info$fiji_image_path[1]) - - # Combine info about the original scalefactors of the first capture - # area with group-related scalars to form a new scalefactors JSON - # for the whole stitched group - sr_json <- rjson::fromJSON( - file = file.path( - this_sample_info$spaceranger_dir[1], "scalefactors_json.json" - ) - ) - - low_over_hi <- lowres_max_size / max(dim(this_image)[seq(2)]) - sr_json <- list( - tissue_hires_scalef = this_sample_info$group_hires_scalef[[1]], - tissue_lowres_scalef = this_sample_info$group_hires_scalef[[1]] * - low_over_hi, - spot_diameter_fullres = sr_json$spot_diameter_fullres * - this_sample_info$intra_group_scalar[[1]] - ) - - this_image <- imager::resize( - this_image, - as.integer(low_over_hi * dim(this_image)[1]), - as.integer(low_over_hi * dim(this_image)[2]) - ) - - # Save the lowres image and scalefactors JSON in a subdirectory of - # 'out_dir' named with the current group - this_out_dir <- file.path(out_dir, this_group) - dir.create(this_out_dir, showWarnings = FALSE) - imager::save.image( - this_image, file.path(this_out_dir, "tissue_lowres_image.png") - ) - write( - rjson::toJSON(sr_json), - file.path(this_out_dir, "scalefactors_json.json") - ) - out_paths[[this_group]] <- c( - file.path(this_out_dir, "tissue_lowres_image.png"), - file.path(this_out_dir, "scalefactors_json.json") - ) - } - - return(unname(unlist(out_paths))) -} diff --git a/man/prep_fiji_image.Rd b/man/prep_fiji.Rd similarity index 53% rename from man/prep_fiji_image.Rd rename to man/prep_fiji.Rd index fcd74db..c9b2b40 100644 --- a/man/prep_fiji_image.Rd +++ b/man/prep_fiji.Rd @@ -1,10 +1,14 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/prep_fiji_image.R -\name{prep_fiji_image} +% Please edit documentation in R/prep_fiji.R +\name{prep_fiji} +\alias{prep_fiji} \alias{prep_fiji_image} -\title{Create low-res images and scale factors from high-res Fiji output images} +\alias{prep_fiji_coords} +\title{Prepare Fiji outputs for building a SpatialExperiment} \usage{ prep_fiji_image(sample_info, out_dir, lowres_max_size = 1200) + +prep_fiji_coords(sample_info, out_dir) } \arguments{ \item{sample_info}{A \code{data.frame()} with columns \code{capture_area}, @@ -12,8 +16,8 @@ prep_fiji_image(sample_info, out_dir, lowres_max_size = 1200) \code{spaceranger_dir}, \code{intra_group_scalar}, and \code{group_hires_scalef}. The last two are made by \code{rescale_fiji_inputs()}.} -\item{out_dir}{A \code{character(1)} vector giving a path to a directory to place -the output image(s) and scale factors. It must exist in advance.} +\item{out_dir}{A \code{character(1)} vector giving a path to a directory to +place the output pixel coordinates CSVs. It must exist in advance.} \item{lowres_max_size}{An \code{integer(1)} vector: the resolution (number of pixels) of the larger dimension of the output image(s), considered to be "low @@ -22,18 +26,42 @@ together at most a 2 by 2 grid of Visium capture areas, where each has at most 600 pixels on the longest dimension (as is the default in SpaceRanger).} } \value{ -This function returns \code{character()} with the file paths to the -\code{tissue_lowres_image.png} and \code{scalefactors_json.json} files it created. +This function returns a \code{character()} with the file paths to the +files it created. For \code{prep_fiji_coords()}, these are the \code{tissue_positions.csv} +files; for \code{prep_fiji_image()}, these are the \code{tissue_lowres_image.png} and +\code{scalefactors_json.json} files. } \description{ +Together, \code{prep_fiji_image()} and \code{prep_fiji_coords()} process Fiji outputs +and generate one directory per group resembling Spaceranger's +\href{https://www.10xgenomics.com/support/software/space-ranger/latest/analysis/outputs/spatial-outputs}{spatial outputs}; +in particular, \code{tissue_positions.csv}, \code{tissue_lowres_image.png}, and +\code{scalefactors_json.json} files are created. These functions are necessary to +run in preparation for \code{build_SpatialExperiment()}. +} +\details{ +Given a \code{data.frame()} of sample information (\code{sample_info}) with +columns \code{capture_area}, \code{group}, and \code{fiji_xml_path}, +expected to have one unique path to Fiji XML output per group, \code{prep_fiji_coords} +reads in the pixel coordinates from each capture area's \code{tissue_positions.csv} +file from SpaceRanger, and transform using the rotation matrix specified +by Fiji \url{https://imagej.net/software/fiji/}. It writes one new \code{tissue_positions.csv} +file per group. + After stitching all groups in \code{sample_info} with Fiji, images of -various resolutions (pixel dimensions) are left. This function creates copies +various resolutions (pixel dimensions) are left. \code{prep_fiji_image()} creates copies of each image whose largest dimension is \code{lowres_max_size} pixels. It also creates a corresponding \code{scalefactors_json.json} file much like -SpaceRanger's. In conjunction with \code{prep_fiji_coords()}, this function -prepares for building the \link[SpatialExperiment:SpatialExperiment]{SpatialExperiment-class} -with \code{build_SpatialExperiment()}. +SpaceRanger's. } +\section{Functions}{ +\itemize{ +\item \code{prep_fiji_image()}: Create low-res images and scale factors from high-res +Fiji output images + +\item \code{prep_fiji_coords()}: Apply transform info from Fiji XML output + +}} \examples{ if (file.exists("sample_info.rds")) { sample_info <- readRDS("sample_info.rds") @@ -68,10 +96,11 @@ if (file.exists("sample_info.rds")) { } spe_input_dir <- tempdir() -out_paths <- prep_fiji_image( +out_paths_image <- prep_fiji_image( sample_info, out_dir = spe_input_dir, lowres_max_size = 1000 ) +out_path_coords <- prep_fiji_coords(sample_info, out_dir = spe_input_dir) # A "low resolution" stitched image was produced, which has 1000 # pixels in its largest dimension @@ -82,10 +111,13 @@ dim(this_image) library("imager") plot(this_image) -# In total, an image and scalefactors were written -out_paths +# 'prep_fiji_image' produced an image and scalefactors +out_paths_image + +# 'prep_fiji_coords' produced a file of spatial coordinates for the +# stitched Br2719 +readr::read_csv(out_path_coords) } \author{ Nicholas J. Eagles } -\concept{functions for parsing Fiji \url{https://imagej.net/software/fiji/} outputs} diff --git a/man/prep_fiji_coords.Rd b/man/prep_fiji_coords.Rd deleted file mode 100644 index 52a2cd3..0000000 --- a/man/prep_fiji_coords.Rd +++ /dev/null @@ -1,74 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/prep_fiji_coords.R -\name{prep_fiji_coords} -\alias{prep_fiji_coords} -\title{Apply transform info from Fiji XML output} -\usage{ -prep_fiji_coords(sample_info, out_dir) -} -\arguments{ -\item{sample_info}{A \code{data.frame()} with columns \code{capture_area}, -\code{group}, \code{fiji_xml_path}, \code{fiji_image_path}, -\code{spaceranger_dir}, \code{intra_group_scalar}, and -\code{group_hires_scalef}. The last two are made by \code{rescale_fiji_inputs()}.} - -\item{out_dir}{A \code{character(1)} vector giving a path to a directory to -place the output pixel coordinates CSVs. It must exist in advance.} -} -\value{ -This function returns a \code{character()} with the file paths to the -\code{tissue_positions.csv} files it created. -} -\description{ -Given a \code{data.frame()} of sample information (\code{sample_info}) with -columns \code{capture_area}, \code{group}, and \code{fiji_xml_path}, -expected to have one unique path to Fiji XML output per group, read in -the pixel coordinates from each capture area's \code{tissue_positions.csv} -file from SpaceRanger, and transform using the rotation matrix specified -by Fiji \url{https://imagej.net/software/fiji/}. -Write one new \code{tissue_positions.csv} file per group. -} -\examples{ -if (file.exists("sample_info.rds")) { - sample_info <- readRDS("sample_info.rds") -} else { - sample_info <- dplyr::tibble( - group = "Br2719", - capture_area = c("V13B23-283_A1", "V13B23-283_C1", "V13B23-283_D1") - ) - # Add 'spaceranger_dir' column - sr_dir <- tempdir() - temp <- unzip( - spatialLIBD::fetch_data("visiumStitched_brain_spaceranger"), - exdir = sr_dir - ) - sample_info$spaceranger_dir <- file.path( - sr_dir, sample_info$capture_area, "outs", "spatial" - ) - - # Add Fiji-output-related columns - fiji_dir <- tempdir() - temp <- unzip( - spatialLIBD::fetch_data("visiumStitched_brain_Fiji_out"), - exdir = fiji_dir - ) - sample_info$fiji_xml_path <- temp[grep("xml$", temp)] - sample_info$fiji_image_path <- temp[grep("png$", temp)] - - ## Re-size images and add more information to the sample_info - sample_info <- rescale_fiji_inputs(sample_info, out_dir = tempdir()) - - saveRDS(sample_info, "sample_info.rds") -} - -spe_input_dir <- tempdir() -out_file <- prep_fiji_coords(sample_info, out_dir = spe_input_dir) -out_file - -# A file of spatial coordinates for the stitched Br2719 was produced -readr::read_csv(out_file) -} -\author{ -Nicholas J. Eagles -} -\concept{functions for parsing Fiji outputs}