From 86ed5fb50d5a74e3a6743ab27d9084bcee363b87 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 30 May 2024 14:24:44 -0400 Subject: [PATCH 001/160] enh: py rework --- NEWS.md | 6 + R/python_environment.R | 867 +++++++++--------- man/checkGiottoEnvironment.Rd | 35 +- man/dot-check_giotto_python_modules.Rd | 3 +- man/dot-giotto_environment_path.Rd | 15 - man/dot-giotto_environment_path_executable.Rd | 15 - man/dot-install_giotto_environment.Rd | 5 +- ...dot-install_giotto_environment_specific.Rd | 21 - man/installGiottoEnvironment.Rd | 66 +- man/removeGiottoEnvironment.Rd | 20 +- man/set_giotto_python_path.Rd | 2 +- 11 files changed, 549 insertions(+), 506 deletions(-) delete mode 100644 man/dot-giotto_environment_path.Rd delete mode 100644 man/dot-giotto_environment_path_executable.Rd delete mode 100644 man/dot-install_giotto_environment_specific.Rd diff --git a/NEWS.md b/NEWS.md index a773b291..55fb48f0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,8 +1,14 @@ # GiottoClass 0.3.2 +## breaking changes +- python environment installation and how it relates to default settings such as .condarc may have changed. + ## enhancements - `verbose` param for `createNearestNetwork()` +- `checkGiottoEnvironment()` in addition to full filepaths, also now supports name of environment or installation directory +- `installGiottoEnvironment()`, `removeGiottoEnvironment()` now have `conda` param for setting path to conda executable and `envname` param for specifying environment by name +- `installGiottoEnvironment()` now has `confirm` param for skipping path input checks # GiottoClass 0.3.1 (2024/05/21) diff --git a/R/python_environment.R b/R/python_environment.R index 5f2fac80..2ddb3f81 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -1,118 +1,77 @@ + + + +# check #### + #' @title checkGiottoEnvironment #' @name checkGiottoEnvironment -#' @param mini_install_path (optional) path to miniconda or conda directory -#' within which the giotto environment lives -#' If not provided, automatically determined by reticulate::miniconda_path() -#' Note the required input format: -#' Correct format --> mini_install_path = "C:/my/conda/lives/here" -#' OR "C:\\my\\conda\\lives\\here" -#' INCORRECT formats --> mini_install_path = "C:/my/conda/lives/here/" -#' AND "C:\\my\\conda\\lives\\here\\" +#' @description +#' Based on `envname`, detect if there is a conda or miniconda installation. +#' This is done by detecting if there is a python executable in the +#' expected location. +#' @param envname character. (optional) The name of or path to a miniconda or +#' conda environment directory or python executable. Default is +#' `reticulate::miniconda_path()`. +#' @param mini_install_path deprecated #' @param verbose be verbose #' @details Checks if a miniconda giotto environment can be found. #' Can be installed with \code{\link{installGiottoEnvironment}}. #' @returns logical #' @examples +#' # check default location #' checkGiottoEnvironment() +#' +#' # use environment name +#' checkGiottoEnvironment("giotto_env") +#' +#' # full path +#' # (use this if a different install location specified with .condarc) +#' if (FALSE) { +#' checkGiottoEnvironment( +#' "/Users/example/Library/r-miniconda-arm64/envs/giotto_env/bin/pythonw" +#' ) +#' } #' @export -checkGiottoEnvironment <- function(mini_install_path = NULL, verbose = TRUE) { - ## get operating system - os_specific_system <- get_os() - - ## check if giotto environment is already installed - if (is.null(mini_install_path)) { - conda_path <- reticulate::miniconda_path() - } else if (!dir.exists(mini_install_path)) { - if (verbose) { - GiottoUtils::wrap_msg( - " Unable to find miniconda directory", mini_install_path, - "\nPlease ensure the directory exists and is provided as - a string." - ) - } - return(FALSE) - } else { - conda_path <- mini_install_path - } - - if (os_specific_system == "osx") { - full_path <- paste0(conda_path, "/envs/giotto_env/bin/pythonw") - } else if (os_specific_system == "windows") { - full_path <- paste0(conda_path, "\\envs\\giotto_env\\python.exe") - } else if (os_specific_system == "linux") { - full_path <- paste0(conda_path, "/envs/giotto_env/bin/python") - } - - if (file.exists(full_path)) { - if (verbose) { - message( - "\n giotto environment found at \n", - full_path, "\n" - ) - } - return(TRUE) - } else { - if (verbose) GiottoUtils::wrap_msg("\n giotto environment was expected, - but NOT found at \n", full_path, "\n") - return(FALSE) - } -} - -#' @title .giotto_environment_path -#' @description returns the path to the detected giotto environment -#' @returns string path -#' @keywords internal -.giotto_environment_path <- function() { - ## get operating system - os_specific_system <- get_os() - - ## check if giotto environment is already installed - conda_path <- reticulate::miniconda_path() - if (os_specific_system == "osx") { - full_path <- paste0(conda_path, "/envs/giotto_env") - } else if (os_specific_system == "windows") { - full_path <- paste0(conda_path, "\\envs\\giotto_env") - } else if (os_specific_system == "linux") { - full_path <- paste0(conda_path, "/envs/giotto_env") - } - - if (file.exists(full_path)) { - return(full_path) - } else { - return(NA) +checkGiottoEnvironment <- function( + envname = "giotto_env", + mini_install_path = deprecated(), + verbose = NULL +) { + + if (is_present(mini_install_path)) { + deprecate_warn( + when = "0.3.2", + what = "checkGiottoEnvironment(mini_install_path)", + with = "checkGiottoEnvironment(envname)" + ) } + + py_path <- .full_miniconda_path(path = envname) + + if (is.null(py_path)) { + vmsg( + .v = verbose, + " Unable to find conda directory", envname, + "\nPlease ensure the directory exists and is provided as", + "character. \nIf only the name of the environment was provided, + ensure it is a subdirectory of reticulate::miniconda_path()" + ) + return(FALSE) + } + + vmsg(.v = verbose, "giotto environment found at\n", py_path) + return(TRUE) } -#' @title .giotto_environment_path_executable -#' @description returns the path to the detected giotto environment executable -#' @returns string path -#' @keywords internal -.giotto_environment_path_executable <- function() { - ## get operating system - os_specific_system <- get_os() - - ## check if giotto environment is already installed - conda_path <- reticulate::miniconda_path() - if (os_specific_system == "osx") { - full_path <- paste0(conda_path, "/envs/giotto_env/bin/pythonw") - } else if (os_specific_system == "windows") { - full_path <- paste0(conda_path, "\\envs\\giotto_env\\python.exe") - } else if (os_specific_system == "linux") { - full_path <- paste0(conda_path, "/envs/giotto_env/bin/python") - } - - if (file.exists(full_path)) { - return(full_path) - } else { - return(NA) - } -} #' @name .check_giotto_python_modules #' @title Check if Giotto python modules are in python environment +#' @description +#' Check for some core python packages that Giotto uses. This is an internal +#' currently only called by the `giotto` `initialize()` method #' @param my_python_path path to python environment #' @returns character or NULL #' @keywords internal @@ -130,7 +89,7 @@ checkGiottoEnvironment <- function(mini_install_path = NULL, verbose = TRUE) { python_modules <- c( "pandas", "igraph", "leidenalg", "community", - "networkx", "sklearn" + "networkx", "scikit-learn" ) missing_modules <- vector(mode = "character") @@ -155,13 +114,22 @@ checkGiottoEnvironment <- function(mini_install_path = NULL, verbose = TRUE) { - +# install #### #' @title .install_giotto_environment_specific #' @description installation of giotto environment +#' @param packages_to_install python packages to install with giotto env +#' @param python_version python version to install +#' @param mini_install_path directory to install the environment to. +#' @param create_dir whether to create the directory specified by +#' `mini_install_path` if it does not already exist. (default = FALSE) +#' @param conda path to conda executable. See ?reticulate::`conda-tools` +#' **finding conda** section. (Default = "auto") +#' @param verbose be verbose #' @keywords internal +#' @noRd #' @returns character or NULL .install_giotto_environment_specific <- function(packages_to_install = c( "pandas", "networkx", "python-igraph", @@ -170,112 +138,111 @@ checkGiottoEnvironment <- function(mini_install_path = NULL, verbose = TRUE) { ), python_version = "3.10.2", mini_install_path = NULL, - verbose = TRUE) { - ## install Giotto environment - if (verbose) message("\n |---- install giotto environment ----| \n") - conda_path <- mini_install_path + confirm = TRUE, + envname = "giotto_env", + conda = "auto", + verbose = NULL) { + + vmsg(.v = verbose, "\n |---- install giotto environment ----| \n") + + ## paths ## + ## ----- ## + # conda (let reticulate handle it when possible) + conda <- conda %null% "auto" + conda_path <- reticulate::conda_binary(conda) + + # environment + if (is.null(mini_install_path)) { + # default giotto environment path + mini_install_path <- reticulate::miniconda_path() + } + if (!is.character(mini_install_path)) { + stop(wrap_txt("`mini_install_path` input must be character")) + } + if (file.exists(mini_install_path)) { + stop(wrap_txt( + "`mini_install_path` should be a path to a directory; + not an executable." + )) + } + + # complete path + mini_install_path <- file.path(mini_install_path, "envs", envname) + + # confirm location + vmsg(.v = verbose, sprintf( + "Installing env to directory:\n\"%s\"", mini_install_path + )) + if (isTRUE(confirm)) { + # if not confirmed, return early + input <- readline("Is this the right location? [y/n] ") + if (!input %in% c("y", "Y", "n", "N")) { + stop("Invalid input. Please try again.") + } + if (!input %in% c("y", "Y")) stop("aborting") + } + + # create directory if not existing + if (!dir.exists(mini_install_path)) { + dir.create(mini_install_path, recursive = TRUE) + } - ## 3. identify operating system and adjust the necessary packages + ## identify operating system and adjust the necessary packages ## + ## ----------------------------------------------------------- ## os_specific_system <- get_os() - - if (os_specific_system != "osx") { + if (os_specific_system != "osx") { # only osx needs python.app packages_to_install <- packages_to_install[!grepl( pattern = "python.app", x = packages_to_install )] } - py_lou <- packages_to_install[grepl( - pattern = "python-louvain", - x = packages_to_install - )] - - pip_packages <- c("smfishhmrf", "session-info", py_lou) - # python-louvain must be installed with pip, not with conda-forge - packages_to_install <- packages_to_install[!grepl( - pattern = "python-louvain", x = packages_to_install - )] - - ## for unix-like systems ## - if (.Platform[["OS.type"]] == "unix") { - conda_full_path <- paste0(conda_path, "/", "bin/conda") - # If this does not exist, check for alternative conda config - # i.e. an env created through .condarc config - if (!file.exists(conda_full_path)) { - conda_full_path <- paste0( - conda_path, "/conda.exe" - ) - } - reticulate::conda_create( - envname = "giotto_env", - conda = conda_full_path, - python_version = python_version - ) - - full_envname <- paste0(conda_path, "/envs/giotto_env") - - if (os_specific_system == "osx") { - python_full_path <- paste0( - conda_path, - "/envs/giotto_env/bin/pythonw" - ) - } else if (os_specific_system == "linux") { - python_full_path <- paste0( - conda_path, - "/envs/giotto_env/bin/python" - ) - } - - - reticulate::py_install( - packages = packages_to_install, - envname = "giotto_env", - method = "conda", - conda = conda_full_path, - python_version = python_version, - channel = c("conda-forge", "vtraag") - ) - - reticulate::py_install( - packages = pip_packages, - envname = full_envname, - method = "conda", - conda = conda_full_path, - pip = TRUE, - python_version = python_version - ) - - - ## for windows systems ## - } else if (.Platform[["OS.type"]] == "windows") { - conda_full_path <- paste0(conda_path, "/", "condabin/conda.bat") - reticulate::conda_create( - envname = "giotto_env", - conda = conda_full_path, - python_version = python_version - ) - - - full_envname <- paste0(conda_path, "/envs/giotto_env") - python_full_path <- paste0(conda_path, "/envs/giotto_env/python.exe") - - reticulate::py_install( - packages = packages_to_install, - envname = "giotto_env", - method = "conda", - conda = conda_full_path, - python_version = python_version, - channel = c("conda-forge", "vtraag") + # `pip_packages` will be installed with pip + # `forge_packages` will be installed with conda-forge + forge_packages <- packages_to_install + py_lou <-"python-louvain" + pip_packages <- c("smfishhmrf", "session-info") + if (py_lou %in% packages_to_install) { + pip_packages <- c(pip_packages, py_lou) + forge_packages <- forge_packages[ + forge_packages != py_lou + ] + } + + ## create conda env ## + ## ---------------- ## + + a <- list( + python_version = python_version, + envname = mini_install_path, + conda = conda_path + ) + + do.call(reticulate::conda_create, args = a) + + ## install python packges ## + ## ---------------------- ## + + if (length(forge_packages) > 0L) { + do.call( + reticulate::py_install, + args = c(a, list( + packages = forge_packages, + method = "conda", + channel = c("conda-forge", "vtraag") + )) ) + } - reticulate::py_install( - packages = pip_packages, - envname = full_envname, - method = "conda", - conda = conda_full_path, - pip = TRUE, - python_version = python_version + if (length(pip_packages) > 0L) { + do.call( + reticulate::py_install, + args = c(a, list( + packages = pip_packages, + method = "conda", + pip = TRUE + )) ) } } @@ -285,97 +252,98 @@ checkGiottoEnvironment <- function(mini_install_path = NULL, verbose = TRUE) { #' @description installation options of giotto environment #' @returns character or NULL #' @keywords internal -.install_giotto_environment <- function(force_environment = FALSE, - packages_to_install = c( - "pandas", "networkx", "python-igraph", - "leidenalg", "python-louvain", "python.app", - "scikit-learn" - ), - python_version = "3.10.2", - mini_install_path = NULL, - verbose = TRUE) { - # first see if Giotto is already installed +.install_giotto_environment <- function( + force_environment = FALSE, + packages_to_install = c( + "pandas", "networkx", "python-igraph", + "leidenalg", "python-louvain", "python.app", + "scikit-learn" + ), + python_version = "3.10.2", + mini_install_path = NULL, + confirm = TRUE, + envname = "giotto_env", + conda = "auto", + verbose = NULL +) { + + # first see if Giotto environment is already installed giotto_installed <- checkGiottoEnvironment( mini_install_path = mini_install_path, verbose = verbose ) - - if (giotto_installed == TRUE & force_environment == FALSE) { - # do nothing if already installed and no force required - - if (verbose) { - GiottoUtils::wrap_msg("Giotto environment is already installed, - set force_environment = TRUE to reinstall \n") - } - } else if (giotto_installed == TRUE & force_environment == TRUE) { - # reinstall giotto if force required - if (.Platform[["OS.type"]] == "unix") { - conda_full_path <- paste0(mini_install_path, "/", "bin/conda") - # If this does not exist, check for alternative conda config - # i.e. an env created through .condarc config - if (!file.exists(conda_full_path)) { - conda_full_path <- paste0(mini_install_path, "/conda.exe") - } - } else if (.Platform[["OS.type"]] == "windows") { - conda_full_path <- paste0( - mini_install_path, - "/", "condabin/conda.bat" - ) - } + # already installed and no force: do nothing & return + if (isTRUE(giotto_installed) && !isTRUE(force_environment)) { + vmsg(.v = verbose, + "Giotto environment is already installed, + set force_environment = TRUE to reinstall" + ) + return(invisible()) # return early + } + + # find conda binary (let reticulate handle it when possible) + conda <- conda %null% "auto" + conda_path <- reticulate::conda_binary(conda) + + # already installed and force: remove original env + if (isTRUE(giotto_installed) && isTRUE(force_environment)) { # first remove giotto environment, then install reticulate::conda_remove( - envname = "giotto_env", - conda = conda_full_path - ) - - .install_giotto_environment_specific( - packages_to_install = packages_to_install, - python_version = python_version, - mini_install_path = mini_install_path, - verbose = verbose - ) - } else { - # install giotto if nothing is found - .install_giotto_environment_specific( - packages_to_install = packages_to_install, - python_version = python_version, - mini_install_path = mini_install_path, - verbose = verbose + envname = envname, + conda = conda_path ) } + + # install giotto environment + .install_giotto_environment_specific( + packages_to_install = packages_to_install, + python_version = python_version, + mini_install_path = mini_install_path, + confirm = confirm, + envname = envname, + conda = conda_path, + verbose = verbose + ) } #' @title installGiottoEnvironment -#' @description Installs a giotto environment -#' @param packages_to_install all python modules (packages) that should be -#' installed for Giotto to work +#' @description Installs a giotto python environment. This includes a +#' miniconda installation and also a set of python packages that Giotto may +#' often use. See details for further information on setting up an +#' environment with a .yml +#' @param packages_to_install python modules (packages) to install for Giotto. #' @param python_version python version to use within the giotto conda -#' environment -#' @param mini_install_path (optional) desired location miniconda installation. -#' If not provided, it is chosen by reticulate::install_miniconda() -#' Note the required input format: -#' Correct format --> mini_install_path = "C:/my/conda/lives/here" -#' OR "C:\\my\\conda\\lives\\here" -#' INCORRECT formats --> mini_install_path = "C:/my/conda/lives/here/" -#' AND "C:\\my\\conda\\lives\\here\\" +#' environment. Default is v3.10.2 +#' @param mini_install_path (optional) desired miniconda installation location. +#' Default is chosen by `reticulate::install_miniconda()` +#' @param confirm whether to pause for confirmation of conda environment +#' install location (default = TRUE) +#' @param envname name to assign environment. Default = "giotto_env" +#' @param conda either "auto" (default) to allow reticulate to handle it, or +#' the full filepath to the conda executable. You can also set the option +#' "reticulate.conda_binary" or `Sys.setenv()` "RETICULATE_CONDA" to tell +#' reticulate where to look. #' @param force_miniconda force reinstallation of miniconda #' @param force_environment force reinstallation of the giotto environment #' @param verbose be verbose #' @returns installs a giotto environment using the reticulate miniconda system #' @details This function will install a local giotto environment using -#' the miniconda system as implemented by reticulate. Once this giotto +#' the miniconda system as implemented by \pkg{reticulate}. Once this giotto #' environment is installed it will be automatically detected when you run the -#' Giotto toolbox. If you want to use -#' your own python path then you can set the python_path in -#' the \code{\link{createGiottoInstructions}} +#' Giotto toolbox. \cr +#' +#' # custom python paths +#' If you want to use your own python path then you can set the python_path in +#' the `"giotto.py_path"` option or \code{\link{createGiottoInstructions}} #' and provide the instructions to the \code{\link{createGiottoObject}} #' function. #' +#' # python versions #' By default, Python v3.10.2 will be used with the following python modules #' for Giotto Suite implementations: #' \preformatted{ @@ -404,8 +372,27 @@ checkGiottoEnvironment <- function(mini_install_path = NULL, verbose = TRUE) { #' - python.app==2 # macOS only #' - scikit-learn==0.24.2 #' } +#' +#' # .yml installs +#' Please note that multiple .yml files are provided in the +#' repository for advanced installation and convenience. To install the most +#' up-to-date Giotto environment using a .yml file, open a shell compatible +#' with conda/miniconda and navigate to the directory specified by +#' `system.file(package = "Giotto", "python/configuration")`. Once in this +#' directory, run the following to create your environment in one step: +#' +#' `conda env create -n giotto_env -f ./genv.yml` +#' #' @examples +#' if (FALSE) { +#' # default install #' installGiottoEnvironment() +#' +#' # install to alternate location +#' temp_env <- tempdir() +#' installGiottoEnvironment(mini_install_path = temp_env) +#' } +#' #' @export installGiottoEnvironment <- function(packages_to_install = c( "pandas==1.5.1", @@ -418,168 +405,99 @@ installGiottoEnvironment <- function(packages_to_install = c( ), python_version = "3.10.2", mini_install_path = NULL, + confirm = TRUE, + envname = "giotto_env", + conda = "auto", force_miniconda = FALSE, force_environment = FALSE, - verbose = TRUE) { + verbose = NULL) { + ## 1. check and install miniconda locally if necessary - conda_path <- NULL - if (is.null(mini_install_path)) { - conda_path <- reticulate::miniconda_path() - } else if (!dir.exists(mini_install_path)) { - stop(GiottoUtils::wrap_msg(paste0( - " Unable to install miniconda in ", - mini_install_path, - "\nPlease ensure the directory has been created and provided as - a string." - ))) - } else { - conda_path <- mini_install_path - - GiottoUtils::wrap_msg( - "NOTICE: Attempting to install the Giotto Environment at a - custom path.\n", - "Please note that multiple .yml files are provided in the - repository for advanced installation and convenience.", - "To install the most up-to-date Giotto environment using a .yml - file, open a shell", - " compatible with conda/miniconda and navigate to the directory - containing Giotto.", - "If you are unsure where Giotto lives on your machine, run the R - function", - " `.libPaths()`, which will return the path(s) at which R packages - install on your machine.", - "Once in the directory containing Giotto, run the following to - create your environment in one step:\n\n", - "conda env create -n giotto_env -f ./python/configuration/genv.yml - \n\n", - "Alternatively, Giotto environment configurations are stored in", - " the directory Giotto/inst/python/configuration/ on the github - repository." - ) - - manual_install <- as.character( - readline("Would you prefer to install manually? [y/n] ") - ) - - if (!manual_install %in% c("y", "Y", "n", "N")) { - stop("Invalid input. Please try again.") - } - - if (manual_install %in% c("y", "Y")) { - stop(GiottoUtils::wrap_txt("There is no error; this just stops - function execution. Please follow the - instructions above for manual installation. - Thank you!")) - } else { - GiottoUtils::wrap_msg("Continuing with automatic installation...\n") - } + conda_path <- reticulate::conda_binary(conda = conda) - - if (.Platform[["OS.type"]] == "unix") { - conda_full_path <- paste0(conda_path, "/", "bin/conda") - # If this does not exist, check for alternative conda config - # i.e. an env created through .condarc config - if (!file.exists(conda_full_path)) { - conda_full_path <- paste0( - conda_path, "/conda.exe" - ) - } - } else if (.Platform[["OS.type"]] == "windows") { - conda_full_path <- paste0(conda_path, "/", "condabin/conda.bat") - } - if (!file.exists(conda_full_path)) force_miniconda <- TRUE - } - - if (!file.exists(conda_path) | isTRUE(force_miniconda)) { - if (verbose) message("\n |---- install local miniconda ----| \n") + # install miniconda if needed + if (!file.exists(conda_path) || isTRUE(force_miniconda)) { + vmsg(.v = verbose, .initial = " ", + "|---- install local miniconda ----|") + reticulate::install_miniconda( path = conda_path, force = force_miniconda ) } - ## 2. install giotto environment + if (is.null(mini_install_path)) { + confirm <- FALSE # following defaults, no confirm needed + } + .install_giotto_environment( force_environment = force_environment, packages_to_install = packages_to_install, python_version = python_version, - mini_install_path = conda_path, + mini_install_path = mini_install_path, + confirm = confirm, + envname = envname, + conda = conda, verbose = verbose ) } +# remove #### + #' @title removeGiottoEnvironment #' @name removeGiottoEnvironment -#' @param mini_path path to anaconda/miniconda. -#' Default: reticulate::miniconda_path() -#' i.e. "C:/my/conda/lives/here" OR "C:\\my\\conda\\lives\\here" +#' @description +#' Remove a Giotto environment +#' @param envname name of environment to remove (e.g. "giotto_env") +#' @param mini_path deprecated +#' @param conda either "auto" (default) to allow reticulate to handle it, or +#' the full filepath to the conda executable. You can also set the option +#' "reticulate.conda_binary" or `Sys.setenv()` "RETICULATE_CONDA" to tell +#' reticulate where to look. #' @param verbose be verbose #' @returns character or NULL #' @details Removes a previously installed giotto environment. #' See \code{\link{installGiottoEnvironment}}. #' @export -removeGiottoEnvironment <- function(mini_path = NULL, verbose = TRUE) { - if (is.null(mini_path)) { - conda_path <- reticulate::miniconda_path() - } else if (!dir.exists(mini_path)) { - stop(GiottoUtils::wrap_msg(paste0( - "Directory", mini_path, - "could not be found. Please ensure it was - entered properly and as a string." - ))) - } else { - conda_path <- mini_path - } - - if (.Platform[["OS.type"]] == "unix") { - conda_full_path <- paste0(conda_path, "/", "bin/conda") - } else if (.Platform[["OS.type"]] == "windows") { - conda_full_path <- paste0(conda_path, "/", "condabin/conda.bat") +removeGiottoEnvironment <- function( + mini_path = deprecated(), + envname = "giotto_env", + conda = "auto", + verbose = TRUE +) { + + if (is_present(mini_path)) { + deprecate_warn( + when = "0.3.2", + what = "removeGiottoEnvironment(mini_path)", + details = "See new params `envname` and `conda` instead" + ) } # first see if Giotto is already installed - giotto_installed <- checkGiottoEnvironment(verbose = verbose) + giotto_installed <- checkGiottoEnvironment( + envname = envname, verbose = verbose + ) - if (giotto_installed == FALSE) { - GiottoUtils::wrap_msg("Giotto environment is not found and probably - never installed") + if (!isTRUE(giotto_installed)) { + wrap_msg( + "Giotto environment is not found and probably never installed" + ) } - # first remove giotto environment, then install reticulate::conda_remove( - envname = "giotto_env", - conda = conda_full_path + envname = envname, + conda = conda ) } -.os_py_path <- function(path, os = get_os()) { - checkmate::assert_directory_exists(path) - switch(os, - "osx" = paste0(path, "/envs/giotto_env/bin/pythonw"), - "windows" = paste0(path, "\\envs\\giotto_env\\python.exe"), - "linux" = paste0(path, "/envs/giotto_env/bin/python") - ) -} -.try_set_provided_py <- function(path, verbose = TRUE) { - res <- NULL - if (checkmate::test_file_exists(path)) { - res <- path - } - if (dir.exists(path)) { - res <- .os_py_path(path) - } - - if (is.null(res)) return(invisible()) - - vmsg(.v = verbose, " external python path provided and will be used") - reticulate::use_python(required = TRUE, python = res) - return(res) -} + +# detect and activate #### #' @title set_giotto_python_path #' @name set_giotto_python_path @@ -595,18 +513,22 @@ removeGiottoEnvironment <- function(mini_path = NULL, verbose = TRUE) { #' set_giotto_python_path() #' @export set_giotto_python_path <- function( - python_path = getOption("giotto.py_path"), - verbose = TRUE + python_path = getOption("giotto.py_path"), # default is NULL + verbose = NULL ) { if (isFALSE(getOption("giotto.use_conda", TRUE))) { return(invisible(NULL)) # exit early } - # If a path is provided by the user and it exists, + # If a path is provided or found by option and it exists, # direct reticulate to said executable and exit immediately if (!is.null(python_path)) { - res <- .try_set_provided_py(path = python_path, verbose = verbose) - if (is.null(res)) { + res <- .full_miniconda_path(path = python_path) + + if (!is.null(res)) { # found + vmsg(.v = verbose, " external python path provided and will be used") + reticulate::use_python(required = TRUE, python = res) + } else { # not found vmsg(.v = verbose, sprintf( "provided 'python_path': \n\"%s\" is not a filepath to executable or miniconda env directory. @@ -614,74 +536,70 @@ set_giotto_python_path <- function( python_path )) } + return(python_path) } # Otherwise, check the OS and if a Giotto Environment exists # use that executable - conda_path <- reticulate::miniconda_path() - python_path <- .os_py_path(path = conda_path) + python_path <- .os_py_path() # check if giotto environment exists giotto_environment_installed <- checkGiottoEnvironment( - mini_install_path = conda_path, + envname = python_path, verbose = FALSE ) if (isTRUE(giotto_environment_installed)) { - if (verbose) { - GiottoUtils::wrap_msg("\n no external python path was provided, - but a giotto python environment was found and - will be used \n") - } - # python_path = .giotto_environment_path_executable() + vmsg( + .v = verbose, + "no external python path was provided, + but a giotto python environment was found and will be used" + ) + # activate environment reticulate::use_python(required = TRUE, python = python_path) } else { - if (verbose) { - GiottoUtils::wrap_msg("\n no external python path or giotto - environment was specified, will check if a - default python path is available \n") - } - - python_path <- try( - { - switch(.Platform[["OS.type"]], - "unix" = system("which python3", intern = TRUE), - "windows" = system("where python3", intern = TRUE) - ) - }, - silent = TRUE + vmsg(.v = verbose, + "no external python path or giotto environment was specified, + will check if a default python path is available" ) + # system calls to check py location + python_path <- .sys_detect_py() if (inherits(python_path, "try-error")) { - GiottoUtils::wrap_msg("\nno default python path found + vmsg("no default python path found. For full functionality, install python and/or use strategy 1 or 2:") python_path <- NULL } else { python_path <- python_path + # activate environment reticulate::use_python(required = TRUE, python = python_path) - if (verbose) { - GiottoUtils::wrap_msg( - "\n A default python path was found: ", - python_path, " and will be used - If this is not the correct python path, either" - ) - } + vmsg(.v = verbose, + sprintf( + "a default python path was found: \n\"%s\" + If this is not the correct python path, either", + python_path)) } - GiottoUtils::wrap_msg("\n 1. use installGiottoEnvironment() to install + vmsg("\n 1. use installGiottoEnvironment() to install a local miniconda python environment along with required modules") - GiottoUtils::wrap_msg("\n 2. provide an existing python path to + vmsg("\n 2. provide an existing python path to python_path to use your own python path which has all modules installed") - GiottoUtils::wrap_msg('Set options(\"giotto.use_conda\" = FALSE) if - python functionalities are not needed') + vmsg('Set options(\"giotto.use_conda\" = FALSE) if + python functionalities are not needed') } return(python_path) } + + + + +# py package installs #### + #' @title Prompt User for Python Install #' @name .py_install_prompt #' @param package python package/github url @@ -959,3 +877,110 @@ checkPythonPackage <- function(package_name = NULL, return(inst_result) } } + + + + + + + +# common internals #### + +# construct path to miniconda executable when the python directory is given +# python directory should be provided in the same way as +# `reticulate::miniconda_path()` where it is one level above the `envs` +# subdirectory. +# NULL is returned if the executable is not found if `must_exist` is TRUE +# when `must_exist` is FALSE, the built path is always returned +.os_py_path <- function( + path = reticulate::miniconda_path(), + envname = "giotto_env", + os = get_os(), + must_exist = TRUE +) { + checkmate::assert_directory_exists(path) + env_level <- file.path(path, "envs", envname) + full_path <- switch(os, + "osx" = file.path(env_level, "bin/pythonw"), + "windows" = file.path(env_level, "python.exe"), + "linux" = file.path(env_level, "bin/python") + ) + # if not must exist or the file exists, return + if (!must_exist || file.exists(full_path)) { + return(full_path) + } + # call again with python instead of pythonw for mac + if (os == "osx") { + full_path <- gsub("pythonw", "python", full_path) + if (file.exists(full_path)) { + return(full_path) + } + } + # not found, return NULL + return(NULL) +} + +# run `os_py_path()` with defaults to get the default install location of +# the `giotto_env`, based on OS. +.giotto_environment_path_executable <- function() { + .os_py_path() +} + +# # build path to expected conda file location +# .os_conda_path <- function( +# path = reticulate::miniconda_path(), +# must_exist = TRUE +# ) { +# checkmate::assert_directory_exists(path) +# full_path <- switch(.Platform$OS.type, +# "windows" = file.path(path, "condabin", "conda.bat"), +# "unix" = file.path(path, "bin", "conda") +# ) +# +# if (!must_exist || file.exists(full_path)) { +# return(full_path) +# } +# # not found, return NULL +# return(NULL) +# } + +# get full path to miniconda executable +# if a full path to the executable is provided, it will be used +# if a directory is provided, it will be completed with `.os_py_path` +# if an envname is given, it will be completed with `.os_py_path` based on +# `reticulate::miniconda_path()` as the base. +# If no file is detected, NULL is returned. +.full_miniconda_path <- function(path = NULL) { + + # default giotto_env install location + if (is.null(path)) { + return(.os_py_path()) + } + + if (checkmate::test_file_exists(path)) { + # fullpath + res <- path + } else if (dir.exists(path)) { + # specific install location (.condarc) + giotto_env default name + res <- .os_py_path(path) + } else { + # specific envname under reticulate::miniconda_path() directory + res <- .os_py_path(envname = path) + } + + return(res) +} + +# system call to detect python location +.sys_detect_py <- function() { + res <- try( + { + switch(.Platform[["OS.type"]], + "unix" = system("which python3", intern = TRUE), + "windows" = system("where python3", intern = TRUE) + ) + }, + silent = TRUE + ) + return(res) +} diff --git a/man/checkGiottoEnvironment.Rd b/man/checkGiottoEnvironment.Rd index 91bba5e5..265690a7 100644 --- a/man/checkGiottoEnvironment.Rd +++ b/man/checkGiottoEnvironment.Rd @@ -4,17 +4,18 @@ \alias{checkGiottoEnvironment} \title{checkGiottoEnvironment} \usage{ -checkGiottoEnvironment(mini_install_path = NULL, verbose = TRUE) +checkGiottoEnvironment( + envname = "giotto_env", + mini_install_path = deprecated(), + verbose = NULL +) } \arguments{ -\item{mini_install_path}{(optional) path to miniconda or conda directory -within which the giotto environment lives -If not provided, automatically determined by reticulate::miniconda_path() -Note the required input format: -Correct format --> mini_install_path = "C:/my/conda/lives/here" -OR "C:\\my\\conda\\lives\\here" -INCORRECT formats --> mini_install_path = "C:/my/conda/lives/here/" -AND "C:\\my\\conda\\lives\\here\\"} +\item{envname}{character. (optional) The name of or path to a miniconda or +conda environment directory or python executable. Default is +\code{reticulate::miniconda_path()}.} + +\item{mini_install_path}{deprecated} \item{verbose}{be verbose} } @@ -22,12 +23,26 @@ AND "C:\\my\\conda\\lives\\here\\"} logical } \description{ -checkGiottoEnvironment +Based on \code{envname}, detect if there is a conda or miniconda installation. +This is done by detecting if there is a python executable in the +expected location. } \details{ Checks if a miniconda giotto environment can be found. Can be installed with \code{\link{installGiottoEnvironment}}. } \examples{ +# check default location checkGiottoEnvironment() + +# use environment name +checkGiottoEnvironment("giotto_env") + +# full path +# (use this if a different install location specified with .condarc) +if (FALSE) { +checkGiottoEnvironment( + "/Users/example/Library/r-miniconda-arm64/envs/giotto_env/bin/pythonw" +) +} } diff --git a/man/dot-check_giotto_python_modules.Rd b/man/dot-check_giotto_python_modules.Rd index c4966a26..f437a06f 100644 --- a/man/dot-check_giotto_python_modules.Rd +++ b/man/dot-check_giotto_python_modules.Rd @@ -13,6 +13,7 @@ character or NULL } \description{ -Check if Giotto python modules are in python environment +Check for some core python packages that Giotto uses. This is an internal +currently only called by the \code{giotto} \code{initialize()} method } \keyword{internal} diff --git a/man/dot-giotto_environment_path.Rd b/man/dot-giotto_environment_path.Rd deleted file mode 100644 index ef1d911e..00000000 --- a/man/dot-giotto_environment_path.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/python_environment.R -\name{.giotto_environment_path} -\alias{.giotto_environment_path} -\title{.giotto_environment_path} -\usage{ -.giotto_environment_path() -} -\value{ -string path -} -\description{ -returns the path to the detected giotto environment -} -\keyword{internal} diff --git a/man/dot-giotto_environment_path_executable.Rd b/man/dot-giotto_environment_path_executable.Rd deleted file mode 100644 index b7e984d3..00000000 --- a/man/dot-giotto_environment_path_executable.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/python_environment.R -\name{.giotto_environment_path_executable} -\alias{.giotto_environment_path_executable} -\title{.giotto_environment_path_executable} -\usage{ -.giotto_environment_path_executable() -} -\value{ -string path -} -\description{ -returns the path to the detected giotto environment executable -} -\keyword{internal} diff --git a/man/dot-install_giotto_environment.Rd b/man/dot-install_giotto_environment.Rd index c1718c6b..bb39be5e 100644 --- a/man/dot-install_giotto_environment.Rd +++ b/man/dot-install_giotto_environment.Rd @@ -10,7 +10,10 @@ "python-louvain", "python.app", "scikit-learn"), python_version = "3.10.2", mini_install_path = NULL, - verbose = TRUE + confirm = TRUE, + envname = "giotto_env", + conda = "auto", + verbose = NULL ) } \value{ diff --git a/man/dot-install_giotto_environment_specific.Rd b/man/dot-install_giotto_environment_specific.Rd deleted file mode 100644 index cf1d8ee5..00000000 --- a/man/dot-install_giotto_environment_specific.Rd +++ /dev/null @@ -1,21 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/python_environment.R -\name{.install_giotto_environment_specific} -\alias{.install_giotto_environment_specific} -\title{.install_giotto_environment_specific} -\usage{ -.install_giotto_environment_specific( - packages_to_install = c("pandas", "networkx", "python-igraph", "leidenalg", - "python-louvain", "python.app", "scikit-learn"), - python_version = "3.10.2", - mini_install_path = NULL, - verbose = TRUE -) -} -\value{ -character or NULL -} -\description{ -installation of giotto environment -} -\keyword{internal} diff --git a/man/installGiottoEnvironment.Rd b/man/installGiottoEnvironment.Rd index f8a095b8..50a1b293 100644 --- a/man/installGiottoEnvironment.Rd +++ b/man/installGiottoEnvironment.Rd @@ -9,25 +9,32 @@ installGiottoEnvironment( "leidenalg==0.9.0", "python-louvain==0.16", "python.app==1.4", "scikit-learn==1.1.3"), python_version = "3.10.2", mini_install_path = NULL, + confirm = TRUE, + envname = "giotto_env", + conda = "auto", force_miniconda = FALSE, force_environment = FALSE, - verbose = TRUE + verbose = NULL ) } \arguments{ -\item{packages_to_install}{all python modules (packages) that should be -installed for Giotto to work} +\item{packages_to_install}{python modules (packages) to install for Giotto.} \item{python_version}{python version to use within the giotto conda -environment} +environment. Default is v3.10.2} -\item{mini_install_path}{(optional) desired location miniconda installation. -If not provided, it is chosen by reticulate::install_miniconda() -Note the required input format: -Correct format --> mini_install_path = "C:/my/conda/lives/here" -OR "C:\\my\\conda\\lives\\here" -INCORRECT formats --> mini_install_path = "C:/my/conda/lives/here/" -AND "C:\\my\\conda\\lives\\here\\"} +\item{mini_install_path}{(optional) desired miniconda installation location. +Default is chosen by \code{reticulate::install_miniconda()}} + +\item{confirm}{whether to pause for confirmation of conda environment +install location (default = TRUE)} + +\item{envname}{name to assign environment. Default = "giotto_env"} + +\item{conda}{either "auto" (default) to allow reticulate to handle it, or +the full filepath to the conda executable. You can also set the option +"reticulate.conda_binary" or \code{Sys.setenv()} "RETICULATE_CONDA" to tell +reticulate where to look.} \item{force_miniconda}{force reinstallation of miniconda} @@ -39,18 +46,25 @@ AND "C:\\my\\conda\\lives\\here\\"} installs a giotto environment using the reticulate miniconda system } \description{ -Installs a giotto environment +Installs a giotto python environment. This includes a +miniconda installation and also a set of python packages that Giotto may +often use. See details for further information on setting up an +environment with a .yml } \details{ This function will install a local giotto environment using -the miniconda system as implemented by reticulate. Once this giotto +the miniconda system as implemented by \pkg{reticulate}. Once this giotto environment is installed it will be automatically detected when you run the -Giotto toolbox. If you want to use -your own python path then you can set the python_path in -the \code{\link{createGiottoInstructions}} +Giotto toolbox. \cr +} +\section{custom python paths}{ +If you want to use your own python path then you can set the python_path in +the \code{"giotto.py_path"} option or \code{\link{createGiottoInstructions}} and provide the instructions to the \code{\link{createGiottoObject}} function. +} +\section{python versions}{ By default, Python v3.10.2 will be used with the following python modules for Giotto Suite implementations: \preformatted{ @@ -80,6 +94,26 @@ Python v3.6 - scikit-learn==0.24.2 } } + +\section{.yml installs}{ +Please note that multiple .yml files are provided in the +repository for advanced installation and convenience. To install the most +up-to-date Giotto environment using a .yml file, open a shell compatible +with conda/miniconda and navigate to the directory specified by +\code{system.file(package = "Giotto", "python/configuration")}. Once in this +directory, run the following to create your environment in one step: + +\verb{conda env create -n giotto_env -f ./genv.yml} +} + \examples{ +if (FALSE) { +# default install installGiottoEnvironment() + +# install to alternate location +temp_env <- tempdir() +installGiottoEnvironment(mini_install_path = temp_env) +} + } diff --git a/man/removeGiottoEnvironment.Rd b/man/removeGiottoEnvironment.Rd index 6bf989d4..eeeae148 100644 --- a/man/removeGiottoEnvironment.Rd +++ b/man/removeGiottoEnvironment.Rd @@ -4,12 +4,22 @@ \alias{removeGiottoEnvironment} \title{removeGiottoEnvironment} \usage{ -removeGiottoEnvironment(mini_path = NULL, verbose = TRUE) +removeGiottoEnvironment( + mini_path = deprecated(), + envname = "giotto_env", + conda = "auto", + verbose = TRUE +) } \arguments{ -\item{mini_path}{path to anaconda/miniconda. -Default: reticulate::miniconda_path() -i.e. "C:/my/conda/lives/here" OR "C:\\my\\conda\\lives\\here"} +\item{mini_path}{deprecated} + +\item{envname}{name of environment to remove (e.g. "giotto_env")} + +\item{conda}{either "auto" (default) to allow reticulate to handle it, or +the full filepath to the conda executable. You can also set the option +"reticulate.conda_binary" or \code{Sys.setenv()} "RETICULATE_CONDA" to tell +reticulate where to look.} \item{verbose}{be verbose} } @@ -17,7 +27,7 @@ i.e. "C:/my/conda/lives/here" OR "C:\\my\\conda\\lives\\here"} character or NULL } \description{ -removeGiottoEnvironment +Remove a Giotto environment } \details{ Removes a previously installed giotto environment. diff --git a/man/set_giotto_python_path.Rd b/man/set_giotto_python_path.Rd index c9329b6b..db554a5a 100644 --- a/man/set_giotto_python_path.Rd +++ b/man/set_giotto_python_path.Rd @@ -6,7 +6,7 @@ \usage{ set_giotto_python_path( python_path = getOption("giotto.py_path"), - verbose = TRUE + verbose = NULL ) } \arguments{ From f9ca8bf7405a948f4ccd6a0fbda3d0198e95ea84 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 30 May 2024 14:32:14 -0400 Subject: [PATCH 002/160] fix: typo --- R/create.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/create.R b/R/create.R index 0058f156..97354d8c 100644 --- a/R/create.R +++ b/R/create.R @@ -817,7 +817,7 @@ createGiottoObjectSubcellular <- function( # generate named list of giottoPoints objects points_res <- .extract_points_list(pointslist = gpoints) gobject <- setGiotto( - gobject, points_res, verbose = FALSE, initalize = FALSE + gobject, points_res, verbose = FALSE, initialize = FALSE ) vmsg(.v = verbose, From 07c2aa99d0825a1fd9159344bfc71a0c701827e7 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 30 May 2024 15:25:03 -0400 Subject: [PATCH 003/160] fix: update deprecated param usage --- R/python_environment.R | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 2ddb3f81..904e5255 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -44,6 +44,7 @@ checkGiottoEnvironment <- function( what = "checkGiottoEnvironment(mini_install_path)", with = "checkGiottoEnvironment(envname)" ) + envname <- mini_install_path } py_path <- .full_miniconda_path(path = envname) @@ -269,7 +270,7 @@ checkGiottoEnvironment <- function( # first see if Giotto environment is already installed giotto_installed <- checkGiottoEnvironment( - mini_install_path = mini_install_path, + envname = mini_install_path, verbose = verbose ) @@ -463,8 +464,8 @@ installGiottoEnvironment <- function(packages_to_install = c( #' See \code{\link{installGiottoEnvironment}}. #' @export removeGiottoEnvironment <- function( - mini_path = deprecated(), envname = "giotto_env", + mini_path = deprecated(), conda = "auto", verbose = TRUE ) { From a8a22bac1747f9a51f1141d0f5f8f6a8cfe4d299 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 30 May 2024 15:28:55 -0400 Subject: [PATCH 004/160] fix: silence a check --- R/python_environment.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/python_environment.R b/R/python_environment.R index 904e5255..07e8d7b9 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -271,7 +271,7 @@ checkGiottoEnvironment <- function( # first see if Giotto environment is already installed giotto_installed <- checkGiottoEnvironment( envname = mini_install_path, - verbose = verbose + verbose = FALSE ) # already installed and no force: do nothing & return From f987590728c04c15060883ae67077aba1283d943 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 30 May 2024 15:32:22 -0400 Subject: [PATCH 005/160] fix: filecheck --- R/python_environment.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/python_environment.R b/R/python_environment.R index 07e8d7b9..2a4f05f5 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -160,7 +160,7 @@ checkGiottoEnvironment <- function( if (!is.character(mini_install_path)) { stop(wrap_txt("`mini_install_path` input must be character")) } - if (file.exists(mini_install_path)) { + if (checkmate::test_file_exists(mini_install_path)) { stop(wrap_txt( "`mini_install_path` should be a path to a directory; not an executable." From 9e03b270499d5f3593d8d37069a091fb550dbf3c Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 30 May 2024 15:49:47 -0400 Subject: [PATCH 006/160] fix: py install location defaults --- R/python_environment.R | 66 +++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 2a4f05f5..9fd06082 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -154,40 +154,48 @@ checkGiottoEnvironment <- function( # environment if (is.null(mini_install_path)) { - # default giotto environment path - mini_install_path <- reticulate::miniconda_path() - } - if (!is.character(mini_install_path)) { - stop(wrap_txt("`mini_install_path` input must be character")) - } - if (checkmate::test_file_exists(mini_install_path)) { - stop(wrap_txt( - "`mini_install_path` should be a path to a directory; + # giotto environment path defaults + if (!is.null(envname)) { + mini_install_path <- envname + } else { + mini_install_path <- reticulate::miniconda_path() + } + # only the envname or default path should be used. + } else { + # checks if not following defaults + if (!is.character(mini_install_path)) { + stop(wrap_txt("`mini_install_path` input must be character")) + } + if (checkmate::test_file_exists(mini_install_path)) { + stop(wrap_txt( + "`mini_install_path` should be a path to a directory; not an executable." + )) + } + # complete path + mini_install_path <- file.path(mini_install_path, "envs", envname) + + # confirm location + vmsg(.v = verbose, sprintf( + "Installing env to directory:\n\"%s\"", mini_install_path )) - } - - # complete path - mini_install_path <- file.path(mini_install_path, "envs", envname) - - # confirm location - vmsg(.v = verbose, sprintf( - "Installing env to directory:\n\"%s\"", mini_install_path - )) - if (isTRUE(confirm)) { - # if not confirmed, return early - input <- readline("Is this the right location? [y/n] ") - if (!input %in% c("y", "Y", "n", "N")) { - stop("Invalid input. Please try again.") + if (isTRUE(confirm)) { + # if not confirmed, return early + input <- readline("Is this the right location? [y/n] ") + if (!input %in% c("y", "Y", "n", "N")) { + stop("Invalid input. Please try again.") + } + if (!input %in% c("y", "Y")) stop("aborting") } - if (!input %in% c("y", "Y")) stop("aborting") - } - - # create directory if not existing - if (!dir.exists(mini_install_path)) { - dir.create(mini_install_path, recursive = TRUE) + + # create directory if not existing + if (!dir.exists(mini_install_path)) { + dir.create(mini_install_path, recursive = TRUE) + } + # user defined path will be used } + ## identify operating system and adjust the necessary packages ## ## ----------------------------------------------------------- ## os_specific_system <- get_os() From e960d2575ce7a4e5fe5b76383663f6dbe5a5a02b Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 30 May 2024 15:57:39 -0400 Subject: [PATCH 007/160] Revert "fix: py install location defaults" This reverts commit 9e03b270499d5f3593d8d37069a091fb550dbf3c. --- R/python_environment.R | 66 +++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 9fd06082..2a4f05f5 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -154,48 +154,40 @@ checkGiottoEnvironment <- function( # environment if (is.null(mini_install_path)) { - # giotto environment path defaults - if (!is.null(envname)) { - mini_install_path <- envname - } else { - mini_install_path <- reticulate::miniconda_path() - } - # only the envname or default path should be used. - } else { - # checks if not following defaults - if (!is.character(mini_install_path)) { - stop(wrap_txt("`mini_install_path` input must be character")) - } - if (checkmate::test_file_exists(mini_install_path)) { - stop(wrap_txt( - "`mini_install_path` should be a path to a directory; + # default giotto environment path + mini_install_path <- reticulate::miniconda_path() + } + if (!is.character(mini_install_path)) { + stop(wrap_txt("`mini_install_path` input must be character")) + } + if (checkmate::test_file_exists(mini_install_path)) { + stop(wrap_txt( + "`mini_install_path` should be a path to a directory; not an executable." - )) - } - # complete path - mini_install_path <- file.path(mini_install_path, "envs", envname) - - # confirm location - vmsg(.v = verbose, sprintf( - "Installing env to directory:\n\"%s\"", mini_install_path )) - if (isTRUE(confirm)) { - # if not confirmed, return early - input <- readline("Is this the right location? [y/n] ") - if (!input %in% c("y", "Y", "n", "N")) { - stop("Invalid input. Please try again.") - } - if (!input %in% c("y", "Y")) stop("aborting") - } - - # create directory if not existing - if (!dir.exists(mini_install_path)) { - dir.create(mini_install_path, recursive = TRUE) + } + + # complete path + mini_install_path <- file.path(mini_install_path, "envs", envname) + + # confirm location + vmsg(.v = verbose, sprintf( + "Installing env to directory:\n\"%s\"", mini_install_path + )) + if (isTRUE(confirm)) { + # if not confirmed, return early + input <- readline("Is this the right location? [y/n] ") + if (!input %in% c("y", "Y", "n", "N")) { + stop("Invalid input. Please try again.") } - # user defined path will be used + if (!input %in% c("y", "Y")) stop("aborting") } - + # create directory if not existing + if (!dir.exists(mini_install_path)) { + dir.create(mini_install_path, recursive = TRUE) + } + ## identify operating system and adjust the necessary packages ## ## ----------------------------------------------------------- ## os_specific_system <- get_os() From 58e9519e8ebf8c0291fbd0c30b86f7cb72e7955b Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 30 May 2024 15:59:37 -0400 Subject: [PATCH 008/160] Update python_environment.R --- R/python_environment.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/python_environment.R b/R/python_environment.R index 2a4f05f5..6d76f9b5 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -168,6 +168,7 @@ checkGiottoEnvironment <- function( } # complete path + checkmate::assert_character(envname) mini_install_path <- file.path(mini_install_path, "envs", envname) # confirm location From b43684bf927e5de3b62d34c7e5166dba702e1208 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 30 May 2024 16:02:33 -0400 Subject: [PATCH 009/160] Revert "Update python_environment.R" This reverts commit 58e9519e8ebf8c0291fbd0c30b86f7cb72e7955b. --- R/python_environment.R | 1 - 1 file changed, 1 deletion(-) diff --git a/R/python_environment.R b/R/python_environment.R index 6d76f9b5..2a4f05f5 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -168,7 +168,6 @@ checkGiottoEnvironment <- function( } # complete path - checkmate::assert_character(envname) mini_install_path <- file.path(mini_install_path, "envs", envname) # confirm location From af561fae0c6e8e1bd191fe85bdeb4918abba293e Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 30 May 2024 16:02:46 -0400 Subject: [PATCH 010/160] Reapply "fix: py install location defaults" This reverts commit e960d2575ce7a4e5fe5b76383663f6dbe5a5a02b. --- R/python_environment.R | 66 +++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 2a4f05f5..9fd06082 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -154,40 +154,48 @@ checkGiottoEnvironment <- function( # environment if (is.null(mini_install_path)) { - # default giotto environment path - mini_install_path <- reticulate::miniconda_path() - } - if (!is.character(mini_install_path)) { - stop(wrap_txt("`mini_install_path` input must be character")) - } - if (checkmate::test_file_exists(mini_install_path)) { - stop(wrap_txt( - "`mini_install_path` should be a path to a directory; + # giotto environment path defaults + if (!is.null(envname)) { + mini_install_path <- envname + } else { + mini_install_path <- reticulate::miniconda_path() + } + # only the envname or default path should be used. + } else { + # checks if not following defaults + if (!is.character(mini_install_path)) { + stop(wrap_txt("`mini_install_path` input must be character")) + } + if (checkmate::test_file_exists(mini_install_path)) { + stop(wrap_txt( + "`mini_install_path` should be a path to a directory; not an executable." + )) + } + # complete path + mini_install_path <- file.path(mini_install_path, "envs", envname) + + # confirm location + vmsg(.v = verbose, sprintf( + "Installing env to directory:\n\"%s\"", mini_install_path )) - } - - # complete path - mini_install_path <- file.path(mini_install_path, "envs", envname) - - # confirm location - vmsg(.v = verbose, sprintf( - "Installing env to directory:\n\"%s\"", mini_install_path - )) - if (isTRUE(confirm)) { - # if not confirmed, return early - input <- readline("Is this the right location? [y/n] ") - if (!input %in% c("y", "Y", "n", "N")) { - stop("Invalid input. Please try again.") + if (isTRUE(confirm)) { + # if not confirmed, return early + input <- readline("Is this the right location? [y/n] ") + if (!input %in% c("y", "Y", "n", "N")) { + stop("Invalid input. Please try again.") + } + if (!input %in% c("y", "Y")) stop("aborting") } - if (!input %in% c("y", "Y")) stop("aborting") - } - - # create directory if not existing - if (!dir.exists(mini_install_path)) { - dir.create(mini_install_path, recursive = TRUE) + + # create directory if not existing + if (!dir.exists(mini_install_path)) { + dir.create(mini_install_path, recursive = TRUE) + } + # user defined path will be used } + ## identify operating system and adjust the necessary packages ## ## ----------------------------------------------------------- ## os_specific_system <- get_os() From e498f38c206b2a65969646e5ecc934953492783e Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 31 May 2024 00:07:58 -0400 Subject: [PATCH 011/160] fix: update py env checking --- R/python_environment.R | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/R/python_environment.R b/R/python_environment.R index 9fd06082..74bbb248 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -47,6 +47,13 @@ checkGiottoEnvironment <- function( envname <- mini_install_path } + # check for envnames, if found, get the path + envs <- reticulate::conda_list() + enames <- envs$name + epaths <- envs$python + if (envname %in% enames) envname <- epaths[enames == envname] + + # complete any directory inputs py_path <- .full_miniconda_path(path = envname) if (is.null(py_path)) { From 634a24f8d504a98045a69036287bd213d7b33a21 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 31 May 2024 00:26:06 -0400 Subject: [PATCH 012/160] enh: only check py list when a envname is given --- R/python_environment.R | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 74bbb248..80e17a2e 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -48,10 +48,12 @@ checkGiottoEnvironment <- function( } # check for envnames, if found, get the path - envs <- reticulate::conda_list() - enames <- envs$name - epaths <- envs$python - if (envname %in% enames) envname <- epaths[enames == envname] + if (!grepl("\\\\||/", envname)) { + envs <- reticulate::conda_list() + enames <- envs$name + epaths <- envs$python + if (envname %in% enames) envname <- epaths[enames == envname] + } # complete any directory inputs py_path <- .full_miniconda_path(path = envname) From 60c5e4cf730d9f0eba1b6124e6ed89a00ba90e32 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 31 May 2024 09:32:07 -0400 Subject: [PATCH 013/160] fix: removeGiottoEnvironment() - also refactor some code --- R/python_environment.R | 60 +++++++++++++++++----------------- man/removeGiottoEnvironment.Rd | 6 ++-- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 80e17a2e..3cc10c68 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -49,10 +49,7 @@ checkGiottoEnvironment <- function( # check for envnames, if found, get the path if (!grepl("\\\\||/", envname)) { - envs <- reticulate::conda_list() - enames <- envs$name - epaths <- envs$python - if (envname %in% enames) envname <- epaths[enames == envname] + envname <- .envname_to_pypath(envname) } # complete any directory inputs @@ -63,8 +60,7 @@ checkGiottoEnvironment <- function( .v = verbose, " Unable to find conda directory", envname, "\nPlease ensure the directory exists and is provided as", - "character. \nIf only the name of the environment was provided, - ensure it is a subdirectory of reticulate::miniconda_path()" + "character." ) return(FALSE) } @@ -505,6 +501,13 @@ removeGiottoEnvironment <- function( "Giotto environment is not found and probably never installed" ) } + + # if envname was provided, get pypath from conda_list, + # then convert to envpath + if (!grepl("\\\\||/", envname)) { + envname <- .envname_to_pypath(envname) %>% + .pypath_to_envpath() + } reticulate::conda_remove( envname = envname, @@ -919,9 +922,9 @@ checkPythonPackage <- function(package_name = NULL, checkmate::assert_directory_exists(path) env_level <- file.path(path, "envs", envname) full_path <- switch(os, - "osx" = file.path(env_level, "bin/pythonw"), - "windows" = file.path(env_level, "python.exe"), - "linux" = file.path(env_level, "bin/python") + "osx" = file.path(env_level, "bin/pythonw"), + "windows" = file.path(env_level, "python.exe"), + "linux" = file.path(env_level, "bin/python") ) # if not must exist or the file exists, return if (!must_exist || file.exists(full_path)) { @@ -938,29 +941,26 @@ checkPythonPackage <- function(package_name = NULL, return(NULL) } -# run `os_py_path()` with defaults to get the default install location of -# the `giotto_env`, based on OS. -.giotto_environment_path_executable <- function() { - .os_py_path() +# convert a full python executable path to the miniconda install directory +.pypath_to_envpath <- function(python_path) { + os <- get_os() + remove <- switch(os, + "osx" = "bin/pythonw$|bin/python$", + "windows" = "python.exe", + "linux" = "bin/python" + ) + gsub(remove, "", python_path) } -# # build path to expected conda file location -# .os_conda_path <- function( -# path = reticulate::miniconda_path(), -# must_exist = TRUE -# ) { -# checkmate::assert_directory_exists(path) -# full_path <- switch(.Platform$OS.type, -# "windows" = file.path(path, "condabin", "conda.bat"), -# "unix" = file.path(path, "bin", "conda") -# ) -# -# if (!must_exist || file.exists(full_path)) { -# return(full_path) -# } -# # not found, return NULL -# return(NULL) -# } +.envname_to_pypath <- function(envname) { + envs <- reticulate::conda_list() + enames <- envs$name + epaths <- envs$python + if (envname %in% enames) envname <- epaths[enames == envname] + else stop(sprintf("envname '%s' not found in reticulate::conda_list()", + envname), call. = FALSE) + return(envname) +} # get full path to miniconda executable # if a full path to the executable is provided, it will be used diff --git a/man/removeGiottoEnvironment.Rd b/man/removeGiottoEnvironment.Rd index eeeae148..b117f695 100644 --- a/man/removeGiottoEnvironment.Rd +++ b/man/removeGiottoEnvironment.Rd @@ -5,17 +5,17 @@ \title{removeGiottoEnvironment} \usage{ removeGiottoEnvironment( - mini_path = deprecated(), envname = "giotto_env", + mini_path = deprecated(), conda = "auto", verbose = TRUE ) } \arguments{ -\item{mini_path}{deprecated} - \item{envname}{name of environment to remove (e.g. "giotto_env")} +\item{mini_path}{deprecated} + \item{conda}{either "auto" (default) to allow reticulate to handle it, or the full filepath to the conda executable. You can also set the option "reticulate.conda_binary" or \code{Sys.setenv()} "RETICULATE_CONDA" to tell From f0aded0102a5af07bbd80b7ceb94969e49a9fac7 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 31 May 2024 09:49:16 -0400 Subject: [PATCH 014/160] fix: detect if path --- R/python_environment.R | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 3cc10c68..543fab61 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -48,7 +48,7 @@ checkGiottoEnvironment <- function( } # check for envnames, if found, get the path - if (!grepl("\\\\||/", envname)) { + if (!.is_path(envname)) { envname <- .envname_to_pypath(envname) } @@ -504,7 +504,7 @@ removeGiottoEnvironment <- function( # if envname was provided, get pypath from conda_list, # then convert to envpath - if (!grepl("\\\\||/", envname)) { + if (!.is_path(envname)) { envname <- .envname_to_pypath(envname) %>% .pypath_to_envpath() } @@ -1002,3 +1002,9 @@ checkPythonPackage <- function(package_name = NULL, ) return(res) } + +# detect if something is likely a path based on slashes (forward and back) +# also if a file exists (also covers directories) +.is_path <- function(x) { + grepl("\\\\|/", x) || file.exists(x) +} From 57198b4c3ca7dd7fd398426da8f3a35950b24f4d Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 31 May 2024 09:59:34 -0400 Subject: [PATCH 015/160] Update python_environment.R --- R/python_environment.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/python_environment.R b/R/python_environment.R index 543fab61..669b285c 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -46,6 +46,7 @@ checkGiottoEnvironment <- function( ) envname <- mini_install_path } + envname <- envname %null% "giotto_env" # check for envnames, if found, get the path if (!.is_path(envname)) { From 9758670ecb99b1a369aef5eba00cdb231fd0d697 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 31 May 2024 10:09:26 -0400 Subject: [PATCH 016/160] Update python_environment.R --- R/python_environment.R | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 669b285c..b878e75e 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -50,10 +50,13 @@ checkGiottoEnvironment <- function( # check for envnames, if found, get the path if (!.is_path(envname)) { - envname <- .envname_to_pypath(envname) + # if a condaenv matches envname, return fullpath + # otherwise return envname without modification + envname <- .envname_to_pypath(envname, must_exist = FALSE) } # complete any directory inputs + # if path does not exist, return NULL py_path <- .full_miniconda_path(path = envname) if (is.null(py_path)) { @@ -506,8 +509,10 @@ removeGiottoEnvironment <- function( # if envname was provided, get pypath from conda_list, # then convert to envpath if (!.is_path(envname)) { - envname <- .envname_to_pypath(envname) %>% - .pypath_to_envpath() + # if a condaenv matches envname, return fullpath + # otherwise throw error + envname <- .envname_to_pypath(envname, must_exist = TRUE) %>% + .pypath_to_envpath() # fullpath to envpath } reticulate::conda_remove( @@ -953,13 +958,17 @@ checkPythonPackage <- function(package_name = NULL, gsub(remove, "", python_path) } -.envname_to_pypath <- function(envname) { +# if found, return the fullpath +# if not, return without modification +.envname_to_pypath <- function(envname, must_exist = TRUE) { envs <- reticulate::conda_list() enames <- envs$name epaths <- envs$python if (envname %in% enames) envname <- epaths[enames == envname] - else stop(sprintf("envname '%s' not found in reticulate::conda_list()", - envname), call. = FALSE) + else if (isTRUE(must_exist)) { + stop(sprintf("envname '%s' not found in reticulate::conda_list()", + envname), call. = FALSE) + } return(envname) } From dc89912f483e9be48a450187699a4dceee1bcc86 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 31 May 2024 12:26:49 -0400 Subject: [PATCH 017/160] enh: rework `set_giotto_python_path()` --- R/python_environment.R | 150 +++++++++++++++++----------------- man/set_giotto_python_path.Rd | 26 ++++-- 2 files changed, 93 insertions(+), 83 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index b878e75e..643090da 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -528,11 +528,21 @@ removeGiottoEnvironment <- function( #' @title set_giotto_python_path #' @name set_giotto_python_path -#' @description Detect and set the python path when `python_path` is NULL -#' (default). A default path to check can be set using the "giotto.py_path" -#' option. Exits without doing anything if option "giotto.use_conda" is FALSE. -#' @param python_path character. Full path to python executable. Checks option -#' `"giotto.py_path"` +#' @description Detect and activate a python path. The `python_path` param +#' accepts both full filepaths to the python executable and envnames. The +#' final path to use is determined as follows in decreasing priority: +#' +#' 1. User provided (when `python_path` is not `NULL`) +#' 2. Any provided path or envname in option `"giotto.py_path"` +#' 3. Default expected giotto environment location based on +#' `reticulate::miniconda_path()` +#' 4. Envname "giotto_env" +#' 5. System default python environment +#' +#' This function exits without doing anything if option +#' `"giotto.use_conda"` is `FALSE`. +#' @param python_path character. Name of environment or full path to python +#' executable. #' @param verbose be verbose #' @returns path to python executable #' @keywords internal @@ -540,85 +550,75 @@ removeGiottoEnvironment <- function( #' set_giotto_python_path() #' @export set_giotto_python_path <- function( - python_path = getOption("giotto.py_path"), # default is NULL + python_path = NULL, verbose = NULL ) { if (isFALSE(getOption("giotto.use_conda", TRUE))) { return(invisible(NULL)) # exit early } - - # If a path is provided or found by option and it exists, - # direct reticulate to said executable and exit immediately + + # get path in order of DECREASING priority # + # ---------------------------------------- # + + # (1.) from user (when `python_path` != NULL) if (!is.null(python_path)) { - res <- .full_miniconda_path(path = python_path) - - if (!is.null(res)) { # found - vmsg(.v = verbose, " external python path provided and will be used") - reticulate::use_python(required = TRUE, python = res) - } else { # not found - vmsg(.v = verbose, sprintf( - "provided 'python_path': \n\"%s\" - is not a filepath to executable or miniconda env directory. - Continuing with default detection.", - python_path - )) - } - - return(python_path) + vmsg(.v = verbose, "a python path has been provided") } - # Otherwise, check the OS and if a Giotto Environment exists - # use that executable - python_path <- .os_py_path() - - # check if giotto environment exists - giotto_environment_installed <- checkGiottoEnvironment( - envname = python_path, - verbose = FALSE - ) - - if (isTRUE(giotto_environment_installed)) { - vmsg( - .v = verbose, - "no external python path was provided, - but a giotto python environment was found and will be used" - ) - # activate environment - reticulate::use_python(required = TRUE, python = python_path) - } else { - vmsg(.v = verbose, - "no external python path or giotto environment was specified, - will check if a default python path is available" - ) - # system calls to check py location - python_path <- .sys_detect_py() - - if (inherits(python_path, "try-error")) { - vmsg("no default python path found. - For full functionality, install python and/or use - strategy 1 or 2:") - python_path <- NULL - } else { - python_path <- python_path - # activate environment - reticulate::use_python(required = TRUE, python = python_path) - vmsg(.v = verbose, - sprintf( - "a default python path was found: \n\"%s\" - If this is not the correct python path, either", - python_path)) - } - - vmsg("\n 1. use installGiottoEnvironment() to install - a local miniconda python environment along with required modules") - vmsg("\n 2. provide an existing python path to - python_path to use your own python path which has all modules - installed") - vmsg('Set options(\"giotto.use_conda\" = FALSE) if - python functionalities are not needed') + # (2.) check option (default is null) + python_path <- python_path %null% getOption("giotto.py_path") + if (!is.null(python_path)) { + vmsg(.v = verbose, "found python path from option 'giotto.py_path'") + } + + # (3.) check default install path; if not existing, returns NULL + # will return NULL for .condarc alternate location "giotto_env" installs + python_path <- python_path %null% .os_py_path(must_exist = TRUE) + if (!is.null(python_path)) { + vmsg(.v = verbose, "a giotto python environment was found") + } + + # (4.) check default envname, relying on reticulate::conda_list() + # catches .condarc alternate location "giotto_env" + if (is.null(python_path)) { + python_path <- "giotto_env" + vmsg(.v = verbose, "checking default envname \'giotto_env\'") + } + + # if an envname was provided, convert to a full python path to test + # if no existing python path found, return the envname without changes + if (!.is_path(python_path)) { + python_path <- .envname_to_pypath(python_path, must_exist = FALSE) + } + # if python_path thus far is not completable to an existing path + # return NULL, otherwise return existing path + python_path <- .full_miniconda_path(path = python_path) + + # (5.) detect from system call; return NULL if not found + python_path <- python_path %null% .sys_detect_py() + if (!is.null(python_path)) { + vmsg(.v = verbose, "a system default python environment was found") } - return(python_path) + # if any working python path found; activate the environment and return # + # --------------------------------------------------------------------- # + if (!is.null(python_path)) { + vmsg(.v = verbose, sprintf("Using python path:\n\"%s\"", res)) + reticulate::use_python(required = TRUE, python = res) + return(python_path) + } + + # otherwise, not found -- helpful prints + vmsg("no default python path found. + For full functionality, install python and/or use + strategy 1 or 2:") + vmsg("1. use installGiottoEnvironment() to install + a local miniconda python environment along with required modules") + vmsg("2. provide an existing python path to + python_path to use your own python path which has all modules + installed") + vmsg('Set options(\"giotto.use_conda\" = FALSE) if + python functionalities are not needed') } @@ -1000,6 +1000,7 @@ checkPythonPackage <- function(package_name = NULL, } # system call to detect python location +# if found, returns path, if not returns NULL .sys_detect_py <- function() { res <- try( { @@ -1010,6 +1011,7 @@ checkPythonPackage <- function(package_name = NULL, }, silent = TRUE ) + if (inherits(res, "try-error")) res <- NULL return(res) } diff --git a/man/set_giotto_python_path.Rd b/man/set_giotto_python_path.Rd index db554a5a..d5d61a02 100644 --- a/man/set_giotto_python_path.Rd +++ b/man/set_giotto_python_path.Rd @@ -4,14 +4,11 @@ \alias{set_giotto_python_path} \title{set_giotto_python_path} \usage{ -set_giotto_python_path( - python_path = getOption("giotto.py_path"), - verbose = NULL -) +set_giotto_python_path(python_path = NULL, verbose = NULL) } \arguments{ -\item{python_path}{character. Full path to python executable. Checks option -\code{"giotto.py_path"}} +\item{python_path}{character. Name of environment or full path to python +executable.} \item{verbose}{be verbose} } @@ -19,9 +16,20 @@ set_giotto_python_path( path to python executable } \description{ -Detect and set the python path when \code{python_path} is NULL -(default). A default path to check can be set using the "giotto.py_path" -option. Exits without doing anything if option "giotto.use_conda" is FALSE. +Detect and activate a python path. The \code{python_path} param +accepts both full filepaths to the python executable and envnames. The +final path to use is determined as follows in decreasing priority: +\enumerate{ +\item User provided (when \code{python_path} is not \code{NULL}) +\item Any provided path or envname in option \code{"giotto.py_path"} +\item Default expected giotto environment location based on +\code{reticulate::miniconda_path()} +\item Envname "giotto_env" +\item System default python environment +} + +This function exits without doing anything if option +\code{"giotto.use_conda"} is \code{FALSE}. } \examples{ set_giotto_python_path() From 39ce687270f47b30d166a09bb152e64bb679bb1a Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 31 May 2024 12:33:05 -0400 Subject: [PATCH 018/160] Update python_environment.R --- R/python_environment.R | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 643090da..0708d0b4 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -8,7 +8,8 @@ #' @description #' Based on `envname`, detect if there is a conda or miniconda installation. #' This is done by detecting if there is a python executable in the -#' expected location. +#' expected location. The default behavior is to only check for giotto's +#' default environment called "giotto_env" #' @param envname character. (optional) The name of or path to a miniconda or #' conda environment directory or python executable. Default is #' `reticulate::miniconda_path()`. @@ -603,8 +604,8 @@ set_giotto_python_path <- function( # if any working python path found; activate the environment and return # # --------------------------------------------------------------------- # if (!is.null(python_path)) { - vmsg(.v = verbose, sprintf("Using python path:\n\"%s\"", res)) - reticulate::use_python(required = TRUE, python = res) + vmsg(.v = verbose, sprintf("Using python path:\n\"%s\"", python_path)) + reticulate::use_python(required = TRUE, python = python_path) return(python_path) } From c7536f5d775264ea352f9962007f94d38bb20306 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 31 May 2024 12:52:13 -0400 Subject: [PATCH 019/160] fix: found msgs --- R/python_environment.R | 29 ++++++++++++++++++----------- man/checkGiottoEnvironment.Rd | 3 ++- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 0708d0b4..fe809a3e 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -560,24 +560,26 @@ set_giotto_python_path <- function( # get path in order of DECREASING priority # # ---------------------------------------- # + found <- vector(mode = "numeric") + found_msg <- c( + "a python path has been provided", + "found python path from option 'giotto.py_path'", + "a giotto python environment was found", + "", # skip 4 since it's always printed + "a system default python environment was found" + ) # (1.) from user (when `python_path` != NULL) - if (!is.null(python_path)) { - vmsg(.v = verbose, "a python path has been provided") - } + if (!is.null(python_path)) found <- c(found, 1) # (2.) check option (default is null) python_path <- python_path %null% getOption("giotto.py_path") - if (!is.null(python_path)) { - vmsg(.v = verbose, "found python path from option 'giotto.py_path'") - } + if (!is.null(python_path)) found <- c(found, 2) # (3.) check default install path; if not existing, returns NULL # will return NULL for .condarc alternate location "giotto_env" installs python_path <- python_path %null% .os_py_path(must_exist = TRUE) - if (!is.null(python_path)) { - vmsg(.v = verbose, "a giotto python environment was found") - } + if (!is.null(python_path)) found <- c(found, 3) # (4.) check default envname, relying on reticulate::conda_list() # catches .condarc alternate location "giotto_env" @@ -597,8 +599,13 @@ set_giotto_python_path <- function( # (5.) detect from system call; return NULL if not found python_path <- python_path %null% .sys_detect_py() - if (!is.null(python_path)) { - vmsg(.v = verbose, "a system default python environment was found") + if (!is.null(python_path)) found <- c(found, 5) + + # print any found messages # + # ------------------------ # + if (length(found) > 0) { + found_at <- min(found) + vmsg(.v = verbose, found_msg[found_at]) } # if any working python path found; activate the environment and return # diff --git a/man/checkGiottoEnvironment.Rd b/man/checkGiottoEnvironment.Rd index 265690a7..36f7f849 100644 --- a/man/checkGiottoEnvironment.Rd +++ b/man/checkGiottoEnvironment.Rd @@ -25,7 +25,8 @@ logical \description{ Based on \code{envname}, detect if there is a conda or miniconda installation. This is done by detecting if there is a python executable in the -expected location. +expected location. The default behavior is to only check for giotto's +default environment called "giotto_env" } \details{ Checks if a miniconda giotto environment can be found. From cb4d4833f2f27efc9c612d413c927774f2b8567e Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 31 May 2024 13:52:33 -0400 Subject: [PATCH 020/160] chore: R req to 4.4 & remove remotes --- DESCRIPTION | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index fdc44d47..595eca38 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -26,9 +26,9 @@ Encoding: UTF-8 Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.1 Depends: - base (>= 4.0.1), - utils (>= 4.0.1), - R (>= 4.0.1), + base (>= 4.4.0), + utils (>= 4.4.0), + R (>= 4.4.0), Imports: checkmate, data.table (>= 1.12.2), @@ -80,7 +80,6 @@ Suggests: testthat (>= 3.0.0), qs, XML -Remotes: drieslab/GiottoUtils Config/testthat/edition: 3 Collate: 'package_imports.R' From 121d975bcb8351801590f755b28c1306493c834a Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 31 May 2024 14:04:22 -0400 Subject: [PATCH 021/160] fix: pymodule detection scikit-learn -> sklearn --- R/python_environment.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/python_environment.R b/R/python_environment.R index fe809a3e..d8e12418 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -100,7 +100,7 @@ checkGiottoEnvironment <- function( python_modules <- c( "pandas", "igraph", "leidenalg", "community", - "networkx", "scikit-learn" + "networkx", "sklearn" ) missing_modules <- vector(mode = "character") From 7d6cac7769422b73a74536ab2b96575a3d373fa1 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 31 May 2024 14:06:10 -0400 Subject: [PATCH 022/160] chore: document --- man/giottoToSpatialData.Rd | 7 ++----- man/spatialdataToGiotto.Rd | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/man/giottoToSpatialData.Rd b/man/giottoToSpatialData.Rd index 25d1b268..2317e7a3 100644 --- a/man/giottoToSpatialData.Rd +++ b/man/giottoToSpatialData.Rd @@ -30,14 +30,11 @@ giottoToSpatialData( \item{save_directory}{directory in which the SpatialData object will be saved} } \value{ -SpatialData object in the form of +SpatialData object saved on disk. } \description{ Converts a Giotto object to SpatialData object } \details{ -Function in beta. Converts a .h5ad file into a Giotto object. -The returned Giotto Object will take default insructions with the -exception of the python path, which may be customized. -See \code{\link{changeGiottoInstructions}} to modify instructions after creation. +Function in beta. Converts and saves a Giotto object in SpatialData format on disk. } diff --git a/man/spatialdataToGiotto.Rd b/man/spatialdataToGiotto.Rd index 7bbdba3a..5e0f238e 100644 --- a/man/spatialdataToGiotto.Rd +++ b/man/spatialdataToGiotto.Rd @@ -51,7 +51,7 @@ Giotto object Converts a saved SpatialData object into a Giotto object } \details{ -Function in beta. Converts a .h5ad file into a Giotto object. +Function in beta. Converts a structured SpatialData file into a Giotto object. The returned Giotto Object will take default insructions with the exception of the python path, which may be customized. See \code{\link{changeGiottoInstructions}} to modify instructions after creation. From f381733dc2997c1be5fb6b9ce9da2d3cf9ca8969 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 4 Jun 2024 12:17:12 -0400 Subject: [PATCH 023/160] feat: affine vector transforms --- DESCRIPTION | 1 + NAMESPACE | 1 + R/generics.R | 1 + R/methods-affine.R | 167 ++++++++++++++++++++++++++++++++++++++++++++ R/methods-show.R | 53 +++++++------- man/affine.Rd | 61 ++++++++++++++++ man/parse_affine.Rd | 33 +++++++++ 7 files changed, 288 insertions(+), 29 deletions(-) create mode 100644 R/methods-affine.R create mode 100644 man/affine.Rd create mode 100644 man/parse_affine.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 595eca38..b2bc28d4 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -106,6 +106,7 @@ Collate: 'interoperability.R' 'join.R' 'methods-IDs.R' + 'methods-affine.R' 'methods-centroids.R' 'methods-coerce.R' 'methods-copy.R' diff --git a/NAMESPACE b/NAMESPACE index ef56593c..9b298134 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -322,6 +322,7 @@ exportMethods("prov<-") exportMethods("spatUnit<-") exportMethods(activeFeatType) exportMethods(activeSpatUnit) +exportMethods(affine) exportMethods(as.matrix) exportMethods(as.points) exportMethods(as.polygons) diff --git a/R/generics.R b/R/generics.R index f77cc655..12b60689 100644 --- a/R/generics.R +++ b/R/generics.R @@ -35,6 +35,7 @@ setGeneric( # Methods and documentations found in methods-spatShift.R setGeneric("spatShift", function(x, ...) standardGeneric("spatShift")) +setGeneric("affine", function(x, ...) standardGeneric("affine")) # Methods and documentations found in methods-overlaps.R setGeneric("overlaps", function(x, ...) standardGeneric("overlaps")) diff --git a/R/methods-affine.R b/R/methods-affine.R new file mode 100644 index 00000000..d3d5585e --- /dev/null +++ b/R/methods-affine.R @@ -0,0 +1,167 @@ +#' @include generics.R +#' @include classes.R + +# docs ----------------------------------------------------------- # +#' @title Apply an affine tranform +#' @name affine +#' @description Apply an affine transformation matrix to a spatial object. +#' Currently only works for 2D transforms. +#' @param x object +#' @param m `matrix` or coercible to `matrix`. Should be a matrix with either +#' 2 or 3 columns (linear or affine). +#' @param ... additional args to pass (none implemented) +#' @returns affine transformed object +#' @examples +#' m <- diag(rep(1, 3)) +#' trans_m <- matrix(c(1, 0, 0, 0, 1, 0, 200, 300, 1), nrow = 3) +#' scale_m <- matrix(c(2, 0, 0, 0, 3, 0, 0, 0, 1), nrow = 3) +#' aff_m <- matrix(c(2, 3, 0.43, 0.2, 3, 0, 100, 29, 1), nrow = 3) +#' +#' gpoints <- GiottoData::loadSubObjectMini("giottoPoints") +#' gpoly <- GiottoData::loadSubObjectMini("giottoPolygon") +#' sl <- GiottoData::loadSubObjectMini("spatLocsObj") +#' +#' # giottoPoints ############################################## +#' plot(affine(gpoints, m)) +#' plot(affine(gpoints, trans_m)) +#' plot(affine(gpoints, scale_m)) +#' plot(affine(gpoints, aff_m)) +#' +#' # giottoPolygon ############################################# +#' plot(affine(gpoly, m)) +#' plot(affine(gpoly, trans_m)) +#' plot(affine(gpoly, scale_m)) +#' plot(affine(gpoly, aff_m)) +#' +#' # spatLocsObj ############################################### +#' plot(affine(sl, m)) +#' plot(affine(sl, trans_m)) +#' plot(affine(sl, scale_m)) +#' plot(affine(sl, aff_m)) +NULL +# ---------------------------------------------------------------- # + +#' @rdname affine +#' @export +setMethod("affine", signature("SpatVector"), function(x, m, ...) { + .affine_sv(x, m, ...) +}) + +#' @rdname affine +#' @export +setMethod( + "affine", signature("giottoPoints"), + function(x, m, ...) { + x[] <- .affine_sv(x = x[], m = m, ...) + return(x) + } +) + +#' @rdname affine +#' @export +setMethod( + "affine", signature("giottoPolygon"), + function(x, m, ...) { + .do_gpoly(x, what = .affine_sv, args = list(m = m, ...)) + } +) + +#' @rdname affine +#' @export +setMethod( + "affine", signature("spatLocsObj"), + function(x, m, ...) { + x[] <- .affine_dt(x = x[], m = m, xcol = "sdimx", ycol = "sdimy", ...) + return(x) + } +) + + + + +# internals #### + +# 2D only +.affine_sv <- function(x, m, ...) { + m <- as.matrix(m) + gtype <- terra::geomtype(x) + xdt <- data.table::as.data.table(x, geom = "XY") + + xdt <- .affine_dt( + x = xdt, m = m, xcol = "x", ycol = "y", ... + ) + + res <- switch(gtype, + "points" = terra::vect(xdt, geom = c("x", "y")), + "polygons" = terra::as.polygons(xdt) + ) + + return(res) +} + +.affine_dt <- function(x, m, xcol = "sdimx", ycol = "sdimy", ...) { + x <- data.table::as.data.table(x) + m <- as.matrix(m) + xm <- as.matrix(x[, c(xcol, ycol), with = FALSE]) + + # linear transforms + aff_m <- m[seq(2), seq(2)] + xm <- xm %*% aff_m + + # translations (if any) + if (ncol(m) > 2) { + translation <- m[seq(2), 3] # class: numeric + xm <- t(t(xm) + translation) + } + + x[, (xcol) := xm[, 1L]] + x[, (ycol) := xm[, 2L]] + + return(x) +} + + + +#' @name parse_affine +#' @title Read affine matrix for linear transforms +#' @description Affine transforms are linear transformations that cover scaling, +#' rotation, shearing, and translations. They can be represented as matrices of +#' 2x3 or 3x3 values. This function reads the matrix and extracts the values +#' needed to perform them. +#' @param x object coercible to matrix with a 2x3 or 3x3 affine matrix +#' @returns a list of transforms information. +#' @keywords internal +#' @examples +#' m <- diag(rep(1, 3)) +#' trans_m <- matrix(c(1, 0, 0, 0, 1, 0, 200, 300, 1), nrow = 3) +#' scale_m <- matrix(c(2, 0, 0, 0, 3, 0, 0, 0, 1), nrow = 3) +#' +#' aff_m <- matrix(c(2, 3, 0.43, 0.2, 3, 0, 100, 29, 1), nrow = 3) +#' +#' parse_affine(m) +#' parse_affine(trans_m) +#' parse_affine(scale_m) +#' parse_affine(aff_m) +parse_affine <- function(x) { + # should be matrix or coercible to matrix + x <- as.matrix(x) + + scale_x <- x[[1, 1]] + shear_x <- x[[1, 2]] + translate_x <- x[[1, 3]] + scale_y <- x[[2, 2]] + shear_y <- x[[2, 1]] + translate_y <- x[[2, 3]] + + structure( + .Data = list( + scale = c(x = scale_x, y = scale_y), + rotate = atan(shear_x / scale_x) + atan(shear_y / scale_y), + shear = c(x = shear_x, y = shear_y), + translate = c(x = translate_x, y = translate_y), + matrix = x + ), + class = "affine" + ) +} + diff --git a/R/methods-show.R b/R/methods-show.R index 6ea1279f..9280faab 100644 --- a/R/methods-show.R +++ b/R/methods-show.R @@ -347,36 +347,31 @@ setMethod( #' @aliases show,spatLocsObj-method #' @docType methods #' @rdname show-methods -setMethod( - f = "show", signature("spatLocsObj"), function(object) { - sdimx <- sdimy <- NULL - - show_class_and_name(object) - show_spat(object) - show_prov(object) - - cat(" ------------------------\n\npreview:\n") - if (!is.null(slot(object, "coordinates"))) { - show(head(slot(object, "coordinates"), 3L)) - } - - cat("\nranges:\n") - - col_names <- colnames(object) - coord_cols <- col_names[col_names %in% c("sdimx", "sdimy", "sdimz")] - - try( - expr = print(vapply( - slot(object, "coordinates")[, c(coord_cols), with = FALSE], - range, - FUN.VALUE = numeric(2L) - )), - silent = TRUE - ) - - cat("\n") +setMethod("show", signature("spatLocsObj"), function(object) { + show_class_and_name(object) + show_spat(object) + show_prov(object) + + cat(" ------------------------\n\npreview:\n") + if (!is.null(slot(object, "coordinates"))) { + show(head(slot(object, "coordinates"), 3L)) } -) + + # print ranges if possible + cat("\nranges:\n") + col_names <- colnames(slot(object, "coordinates")) + coord_cols <- col_names[col_names %in% c("sdimx", "sdimy", "sdimz")] + + try( + expr = print(vapply( + slot(object, "coordinates")[, c(coord_cols), with = FALSE], + range, + FUN.VALUE = numeric(2L) + )), + silent = TRUE + ) + cat("\n") +}) diff --git a/man/affine.Rd b/man/affine.Rd new file mode 100644 index 00000000..e0bdef0a --- /dev/null +++ b/man/affine.Rd @@ -0,0 +1,61 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/methods-affine.R +\name{affine} +\alias{affine} +\alias{affine,SpatVector-method} +\alias{affine,giottoPoints-method} +\alias{affine,giottoPolygon-method} +\alias{affine,spatLocsObj-method} +\title{Apply an affine tranform} +\usage{ +\S4method{affine}{SpatVector}(x, m, ...) + +\S4method{affine}{giottoPoints}(x, m, ...) + +\S4method{affine}{giottoPolygon}(x, m, ...) + +\S4method{affine}{spatLocsObj}(x, m, ...) +} +\arguments{ +\item{x}{object} + +\item{m}{\code{matrix} or coercible to \code{matrix}. Should be a matrix with either +2 or 3 columns (linear or affine).} + +\item{...}{additional args to pass (none implemented)} +} +\value{ +affine transformed object +} +\description{ +Apply an affine transformation matrix to a spatial object. +Currently only works for 2D transforms. +} +\examples{ +m <- diag(rep(1, 3)) +trans_m <- matrix(c(1, 0, 0, 0, 1, 0, 200, 300, 1), nrow = 3) +scale_m <- matrix(c(2, 0, 0, 0, 3, 0, 0, 0, 1), nrow = 3) +aff_m <- matrix(c(2, 3, 0.43, 0.2, 3, 0, 100, 29, 1), nrow = 3) + +gpoints <- GiottoData::loadSubObjectMini("giottoPoints") +gpoly <- GiottoData::loadSubObjectMini("giottoPolygon") +sl <- GiottoData::loadSubObjectMini("spatLocsObj") + +# giottoPoints ############################################## +plot(affine(gpoints, m)) +plot(affine(gpoints, trans_m)) +plot(affine(gpoints, scale_m)) +plot(affine(gpoints, aff_m)) + +# giottoPolygon ############################################# +plot(affine(gpoly, m)) +plot(affine(gpoly, trans_m)) +plot(affine(gpoly, scale_m)) +plot(affine(gpoly, aff_m)) + +# spatLocsObj ############################################### +plot(affine(sl, m)) +plot(affine(sl, trans_m)) +plot(affine(sl, scale_m)) +plot(affine(sl, aff_m)) +} diff --git a/man/parse_affine.Rd b/man/parse_affine.Rd new file mode 100644 index 00000000..de1d1b45 --- /dev/null +++ b/man/parse_affine.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/methods-affine.R +\name{parse_affine} +\alias{parse_affine} +\title{Read affine matrix for linear transforms} +\usage{ +parse_affine(x) +} +\arguments{ +\item{x}{object coercible to matrix with a 2x3 or 3x3 affine matrix} +} +\value{ +a list of transforms information. +} +\description{ +Affine transforms are linear transformations that cover scaling, +rotation, shearing, and translations. They can be represented as matrices of +2x3 or 3x3 values. This function reads the matrix and extracts the values +needed to perform them. +} +\examples{ +m <- diag(rep(1, 3)) +trans_m <- matrix(c(1, 0, 0, 0, 1, 0, 200, 300, 1), nrow = 3) +scale_m <- matrix(c(2, 0, 0, 0, 3, 0, 0, 0, 1), nrow = 3) + +aff_m <- matrix(c(2, 3, 0.43, 0.2, 3, 0, 100, 29, 1), nrow = 3) + +parse_affine(m) +parse_affine(trans_m) +parse_affine(scale_m) +parse_affine(aff_m) +} +\keyword{internal} From fb718f6350b42a19175c281d8e834748937003fe Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 4 Jun 2024 12:20:35 -0400 Subject: [PATCH 024/160] chore: update news --- NEWS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS.md b/NEWS.md index 55fb48f0..d453b52b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,6 +10,9 @@ - `installGiottoEnvironment()`, `removeGiottoEnvironment()` now have `conda` param for setting path to conda executable and `envname` param for specifying environment by name - `installGiottoEnvironment()` now has `confirm` param for skipping path input checks +## new +- `affine()` for `giottoPolygon`, `giottoPoints`, `spatLocsObj` + # GiottoClass 0.3.1 (2024/05/21) From 4c00c9fe2999786b7268795f146cdfb3f0ffb5ff Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 4 Jun 2024 14:31:12 -0400 Subject: [PATCH 025/160] feat: add inverting of affine transforms --- R/methods-affine.R | 66 +++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/R/methods-affine.R b/R/methods-affine.R index d3d5585e..6d12a647 100644 --- a/R/methods-affine.R +++ b/R/methods-affine.R @@ -9,13 +9,15 @@ #' @param x object #' @param m `matrix` or coercible to `matrix`. Should be a matrix with either #' 2 or 3 columns (linear or affine). +#' @param inv logical. Whether the inverse of the affine transform should +#' be applied. #' @param ... additional args to pass (none implemented) #' @returns affine transformed object #' @examples #' m <- diag(rep(1, 3)) #' trans_m <- matrix(c(1, 0, 0, 0, 1, 0, 200, 300, 1), nrow = 3) #' scale_m <- matrix(c(2, 0, 0, 0, 3, 0, 0, 0, 1), nrow = 3) -#' aff_m <- matrix(c(2, 3, 0.43, 0.2, 3, 0, 100, 29, 1), nrow = 3) +#' aff_m <- matrix(c(2, 3, 0, 0.2, 3, 0, 100, 29, 1), nrow = 3) #' #' gpoints <- GiottoData::loadSubObjectMini("giottoPoints") #' gpoly <- GiottoData::loadSubObjectMini("giottoPolygon") @@ -25,34 +27,40 @@ #' plot(affine(gpoints, m)) #' plot(affine(gpoints, trans_m)) #' plot(affine(gpoints, scale_m)) -#' plot(affine(gpoints, aff_m)) +#' aff_gpoints <- affine(gpoints, aff_m) +#' plot(aff_gpoints) +#' plot(affine(aff_gpoints, aff_m, inv = TRUE)) #' #' # giottoPolygon ############################################# #' plot(affine(gpoly, m)) #' plot(affine(gpoly, trans_m)) #' plot(affine(gpoly, scale_m)) -#' plot(affine(gpoly, aff_m)) +#' aff_gpoly <- affine(gpoly, aff_m) +#' plot(aff_gpoly) +#' plot(affine(aff_gpoly, aff_m, inv = TRUE)) #' #' # spatLocsObj ############################################### #' plot(affine(sl, m)) #' plot(affine(sl, trans_m)) #' plot(affine(sl, scale_m)) -#' plot(affine(sl, aff_m)) +#' aff_sl <- affine(sl, aff_m) +#' plot(aff_sl) +#' plot(affine(aff_sl, aff_m, inv = TRUE)) NULL # ---------------------------------------------------------------- # #' @rdname affine #' @export -setMethod("affine", signature("SpatVector"), function(x, m, ...) { - .affine_sv(x, m, ...) +setMethod("affine", signature("SpatVector"), function(x, m, inv = FALSE, ...) { + .affine_sv(x, m, inv, ...) }) #' @rdname affine #' @export setMethod( "affine", signature("giottoPoints"), - function(x, m, ...) { - x[] <- .affine_sv(x = x[], m = m, ...) + function(x, m, inv = FALSE, ...) { + x[] <- .affine_sv(x = x[], m = m, inv = inv, ...) return(x) } ) @@ -61,8 +69,8 @@ setMethod( #' @export setMethod( "affine", signature("giottoPolygon"), - function(x, m, ...) { - .do_gpoly(x, what = .affine_sv, args = list(m = m, ...)) + function(x, m, inv = FALSE, ...) { + .do_gpoly(x, what = .affine_sv, args = list(m = m, inv = inv, ...)) } ) @@ -70,8 +78,10 @@ setMethod( #' @export setMethod( "affine", signature("spatLocsObj"), - function(x, m, ...) { - x[] <- .affine_dt(x = x[], m = m, xcol = "sdimx", ycol = "sdimy", ...) + function(x, m, inv = FALSE, ...) { + x[] <- .affine_dt( + x = x[], m = m, xcol = "sdimx", ycol = "sdimy", inv = inv, ... + ) return(x) } ) @@ -82,38 +92,52 @@ setMethod( # internals #### # 2D only -.affine_sv <- function(x, m, ...) { +.affine_sv <- function(x, m, inv = FALSE, ...) { m <- as.matrix(m) gtype <- terra::geomtype(x) xdt <- data.table::as.data.table(x, geom = "XY") xdt <- .affine_dt( - x = xdt, m = m, xcol = "x", ycol = "y", ... + x = xdt, m = m, xcol = "x", ycol = "y", inv = inv, ... ) res <- switch(gtype, - "points" = terra::vect(xdt, geom = c("x", "y")), - "polygons" = terra::as.polygons(xdt) + "points" = terra::vect(xdt, geom = c("x", "y")), + "polygons" = terra::as.polygons(xdt) ) return(res) } -.affine_dt <- function(x, m, xcol = "sdimx", ycol = "sdimy", ...) { +.affine_dt <- function( + x, m, xcol = "sdimx", ycol = "sdimy", inv = FALSE, ... +) { x <- data.table::as.data.table(x) m <- as.matrix(m) xm <- as.matrix(x[, c(xcol, ycol), with = FALSE]) - # linear transforms - aff_m <- m[seq(2), seq(2)] - xm <- xm %*% aff_m - # translations (if any) + trans <- NULL if (ncol(m) > 2) { translation <- m[seq(2), 3] # class: numeric + if (isTRUE(inv)) translation <- -translation + } + + # inv translation + if (!is.null(trans) && isTRUE(inv)) { xm <- t(t(xm) + translation) } + # linear transforms + aff_m <- m[seq(2), seq(2)] + if (isTRUE(inv)) aff_m <- solve(aff_m) + xm <- xm %*% aff_m + + # normal translation + if (!is.null(trans) && !isTRUE(inv)) { + xm <- t(t(xm) + translation) + } + x[, (xcol) := xm[, 1L]] x[, (ycol) := xm[, 2L]] From fbc2b94f55ad2e2ceac47f249e1596440b5c0b53 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 6 Jun 2024 17:49:31 -0400 Subject: [PATCH 026/160] feat: decomp_affine() --- NAMESPACE | 2 + NEWS.md | 1 + R/methods-affine.R | 74 ++++++++++++++++------- man/affine.Rd | 25 +++++--- man/{parse_affine.Rd => decomp_affine.Rd} | 25 +++++--- man/print.affine.Rd | 17 ++++++ 6 files changed, 105 insertions(+), 39 deletions(-) rename man/{parse_affine.Rd => decomp_affine.Rd} (58%) create mode 100644 man/print.affine.Rd diff --git a/NAMESPACE b/NAMESPACE index 9b298134..2715970a 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -8,6 +8,7 @@ S3method(.DollarNames,terraVectData) S3method(as.data.table,SpatVector) S3method(as.data.table,giottoPoints) S3method(as.data.table,giottoPolygon) +S3method(print,affine) S3method(t,spatLocsObj) S3method(t,spatialNetworkObj) export(addCellMetadata) @@ -100,6 +101,7 @@ export(create_spat_grid_obj) export(create_spat_locs_obj) export(create_spat_net_obj) export(cropGiottoLargeImage) +export(decomp_affine) export(distGiottoImage) export(edge_distances) export(estimateImageBg) diff --git a/NEWS.md b/NEWS.md index d453b52b..5f68dbdf 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,6 +12,7 @@ ## new - `affine()` for `giottoPolygon`, `giottoPoints`, `spatLocsObj` +- `decomp_affine()` for decomposing affine matrix to simple transforms # GiottoClass 0.3.1 (2024/05/21) diff --git a/R/methods-affine.R b/R/methods-affine.R index 6d12a647..e979a2d3 100644 --- a/R/methods-affine.R +++ b/R/methods-affine.R @@ -146,12 +146,14 @@ setMethod( -#' @name parse_affine -#' @title Read affine matrix for linear transforms + +#' @name decomp_affine +#' @title Decompose affine matrix into scale, rotation, and shear operations #' @description Affine transforms are linear transformations that cover scaling, #' rotation, shearing, and translations. They can be represented as matrices of #' 2x3 or 3x3 values. This function reads the matrix and extracts the values -#' needed to perform them. +#' needed to perform them as a list of class `affine`. Works only for 2D +#' transforms. Logic from \url{https://math.stackexchange.com/a/3521141} #' @param x object coercible to matrix with a 2x3 or 3x3 affine matrix #' @returns a list of transforms information. #' @keywords internal @@ -160,32 +162,62 @@ setMethod( #' trans_m <- matrix(c(1, 0, 0, 0, 1, 0, 200, 300, 1), nrow = 3) #' scale_m <- matrix(c(2, 0, 0, 0, 3, 0, 0, 0, 1), nrow = 3) #' -#' aff_m <- matrix(c(2, 3, 0.43, 0.2, 3, 0, 100, 29, 1), nrow = 3) +#' aff_m <- matrix(c( +#' 2, 0.5, 1000, +#' -0.3, 3, 20, +#' 100, 29, 1 +#' ), nrow = 3, byrow = TRUE) #' -#' parse_affine(m) -#' parse_affine(trans_m) -#' parse_affine(scale_m) -#' parse_affine(aff_m) -parse_affine <- function(x) { +#' decomp_affine(m) +#' decomp_affine(trans_m) +#' decomp_affine(scale_m) +#' decomp_affine(aff_m) +#' @export +decomp_affine <- function(x) { # should be matrix or coercible to matrix x <- as.matrix(x) - scale_x <- x[[1, 1]] - shear_x <- x[[1, 2]] - translate_x <- x[[1, 3]] - scale_y <- x[[2, 2]] - shear_y <- x[[2, 1]] - translate_y <- x[[2, 3]] + a11 <- x[[1, 1]] + a21 <- x[[2, 1]] + a12 <- x[[1, 2]] + a22 <- x[[2, 2]] + + sx <- sqrt(a11^2 + a21^2) # scale x + r <- atan(a21 / a11) # rotation + msy <- a12 * cos(r) + a22 * sin(r) + if (sin(r) != 0) { # scale y + sy <- (msy * cos(r) - a12) / sin(r) + } else { + sy <- (a22 - msy * sin(r)) / cos(r) + } + m <- msy / sy # shear + + # translations + if (ncol(x) > 2) { + tx <- x[[1, 3]] + ty <- x[[2, 3]] + } else { + tx <- ty <- 0 + } structure( - .Data = list( - scale = c(x = scale_x, y = scale_y), - rotate = atan(shear_x / scale_x) + atan(shear_y / scale_y), - shear = c(x = shear_x, y = shear_y), - translate = c(x = translate_x, y = translate_y), - matrix = x + .Data = list( + scale = c(x = sx, y = sy), + rotate = r, + shear = m, + translate = c(x = tx, y = ty) ), class = "affine" ) } +#' @name print.affine +#' @title affine print method +#' @param x object to print +#' @param \dots additional params to pass (none implemented) +#' @keywords internal +#' @export +print.affine <- function(x, ...) { + cat("\n") + print_list(x) +} diff --git a/man/affine.Rd b/man/affine.Rd index e0bdef0a..c2734ee4 100644 --- a/man/affine.Rd +++ b/man/affine.Rd @@ -8,13 +8,13 @@ \alias{affine,spatLocsObj-method} \title{Apply an affine tranform} \usage{ -\S4method{affine}{SpatVector}(x, m, ...) +\S4method{affine}{SpatVector}(x, m, inv = FALSE, ...) -\S4method{affine}{giottoPoints}(x, m, ...) +\S4method{affine}{giottoPoints}(x, m, inv = FALSE, ...) -\S4method{affine}{giottoPolygon}(x, m, ...) +\S4method{affine}{giottoPolygon}(x, m, inv = FALSE, ...) -\S4method{affine}{spatLocsObj}(x, m, ...) +\S4method{affine}{spatLocsObj}(x, m, inv = FALSE, ...) } \arguments{ \item{x}{object} @@ -22,6 +22,9 @@ \item{m}{\code{matrix} or coercible to \code{matrix}. Should be a matrix with either 2 or 3 columns (linear or affine).} +\item{inv}{logical. Whether the inverse of the affine transform should +be applied.} + \item{...}{additional args to pass (none implemented)} } \value{ @@ -35,7 +38,7 @@ Currently only works for 2D transforms. m <- diag(rep(1, 3)) trans_m <- matrix(c(1, 0, 0, 0, 1, 0, 200, 300, 1), nrow = 3) scale_m <- matrix(c(2, 0, 0, 0, 3, 0, 0, 0, 1), nrow = 3) -aff_m <- matrix(c(2, 3, 0.43, 0.2, 3, 0, 100, 29, 1), nrow = 3) +aff_m <- matrix(c(2, 3, 0, 0.2, 3, 0, 100, 29, 1), nrow = 3) gpoints <- GiottoData::loadSubObjectMini("giottoPoints") gpoly <- GiottoData::loadSubObjectMini("giottoPolygon") @@ -45,17 +48,23 @@ sl <- GiottoData::loadSubObjectMini("spatLocsObj") plot(affine(gpoints, m)) plot(affine(gpoints, trans_m)) plot(affine(gpoints, scale_m)) -plot(affine(gpoints, aff_m)) +aff_gpoints <- affine(gpoints, aff_m) +plot(aff_gpoints) +plot(affine(aff_gpoints, aff_m, inv = TRUE)) # giottoPolygon ############################################# plot(affine(gpoly, m)) plot(affine(gpoly, trans_m)) plot(affine(gpoly, scale_m)) -plot(affine(gpoly, aff_m)) +aff_gpoly <- affine(gpoly, aff_m) +plot(aff_gpoly) +plot(affine(aff_gpoly, aff_m, inv = TRUE)) # spatLocsObj ############################################### plot(affine(sl, m)) plot(affine(sl, trans_m)) plot(affine(sl, scale_m)) -plot(affine(sl, aff_m)) +aff_sl <- affine(sl, aff_m) +plot(aff_sl) +plot(affine(aff_sl, aff_m, inv = TRUE)) } diff --git a/man/parse_affine.Rd b/man/decomp_affine.Rd similarity index 58% rename from man/parse_affine.Rd rename to man/decomp_affine.Rd index de1d1b45..0225e95f 100644 --- a/man/parse_affine.Rd +++ b/man/decomp_affine.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/methods-affine.R -\name{parse_affine} -\alias{parse_affine} -\title{Read affine matrix for linear transforms} +\name{decomp_affine} +\alias{decomp_affine} +\title{Decompose affine matrix into scale, rotation, and shear operations} \usage{ -parse_affine(x) +decomp_affine(x) } \arguments{ \item{x}{object coercible to matrix with a 2x3 or 3x3 affine matrix} @@ -16,18 +16,23 @@ a list of transforms information. Affine transforms are linear transformations that cover scaling, rotation, shearing, and translations. They can be represented as matrices of 2x3 or 3x3 values. This function reads the matrix and extracts the values -needed to perform them. +needed to perform them as a list of class \code{affine}. Works only for 2D +transforms. Logic from \url{https://math.stackexchange.com/a/3521141} } \examples{ m <- diag(rep(1, 3)) trans_m <- matrix(c(1, 0, 0, 0, 1, 0, 200, 300, 1), nrow = 3) scale_m <- matrix(c(2, 0, 0, 0, 3, 0, 0, 0, 1), nrow = 3) -aff_m <- matrix(c(2, 3, 0.43, 0.2, 3, 0, 100, 29, 1), nrow = 3) +aff_m <- matrix(c( + 2, 0.5, 1000, + -0.3, 3, 20, + 100, 29, 1 +), nrow = 3, byrow = TRUE) -parse_affine(m) -parse_affine(trans_m) -parse_affine(scale_m) -parse_affine(aff_m) +decomp_affine(m) +decomp_affine(trans_m) +decomp_affine(scale_m) +decomp_affine(aff_m) } \keyword{internal} diff --git a/man/print.affine.Rd b/man/print.affine.Rd new file mode 100644 index 00000000..0d0b03e4 --- /dev/null +++ b/man/print.affine.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/methods-affine.R +\name{print.affine} +\alias{print.affine} +\title{affine print method} +\usage{ +\method{print}{affine}(x, ...) +} +\arguments{ +\item{x}{object to print} + +\item{\dots}{additional params to pass (none implemented)} +} +\description{ +affine print method +} +\keyword{internal} From a0bae74eb67a01d0560befaef7aa55fe6055e616 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 10 Jun 2024 12:24:32 -0400 Subject: [PATCH 027/160] feat: affine decomp and shear --- DESCRIPTION | 1 + NAMESPACE | 3 +- NEWS.md | 2 + R/generics.R | 1 + R/methods-affine.R | 199 ++++++++++++++---- R/methods-shear.R | 62 ++++++ man/affine.Rd | 13 +- man/decomp_affine.Rd | 39 +++- ...print.affine.Rd => print.affine_decomp.Rd} | 10 +- man/shear.Rd | 38 ++++ man/solve.affine_decomp.Rd | 42 ++++ 11 files changed, 352 insertions(+), 58 deletions(-) create mode 100644 R/methods-shear.R rename man/{print.affine.Rd => print.affine_decomp.Rd} (60%) create mode 100644 man/shear.Rd create mode 100644 man/solve.affine_decomp.Rd diff --git a/DESCRIPTION b/DESCRIPTION index b2bc28d4..6827402b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -125,6 +125,7 @@ Collate: 'methods-reconnect.R' 'methods-rescale.R' 'methods-setGiotto.R' + 'methods-shear.R' 'methods-show.R' 'methods-spatShift.R' 'methods-spin.R' diff --git a/NAMESPACE b/NAMESPACE index 2715970a..c60553ac 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -8,7 +8,8 @@ S3method(.DollarNames,terraVectData) S3method(as.data.table,SpatVector) S3method(as.data.table,giottoPoints) S3method(as.data.table,giottoPolygon) -S3method(print,affine) +S3method(print,affine_decomp) +S3method(solve,affine_decomp) S3method(t,spatLocsObj) S3method(t,spatialNetworkObj) export(addCellMetadata) diff --git a/NEWS.md b/NEWS.md index 5f68dbdf..0c7cf235 100644 --- a/NEWS.md +++ b/NEWS.md @@ -13,6 +13,8 @@ ## new - `affine()` for `giottoPolygon`, `giottoPoints`, `spatLocsObj` - `decomp_affine()` for decomposing affine matrix to simple transforms +- `shear()` for `spatLocsObj` +- `solve()` method for `affine_decomp` # GiottoClass 0.3.1 (2024/05/21) diff --git a/R/generics.R b/R/generics.R index 12b60689..414ca7e0 100644 --- a/R/generics.R +++ b/R/generics.R @@ -36,6 +36,7 @@ setGeneric( # Methods and documentations found in methods-spatShift.R setGeneric("spatShift", function(x, ...) standardGeneric("spatShift")) setGeneric("affine", function(x, ...) standardGeneric("affine")) +setGeneric("shear", function(x, ...) standardGeneric("shear")) # Methods and documentations found in methods-overlaps.R setGeneric("overlaps", function(x, ...) standardGeneric("overlaps")) diff --git a/R/methods-affine.R b/R/methods-affine.R index e979a2d3..16bd72f8 100644 --- a/R/methods-affine.R +++ b/R/methods-affine.R @@ -24,25 +24,18 @@ #' sl <- GiottoData::loadSubObjectMini("spatLocsObj") #' #' # giottoPoints ############################################## -#' plot(affine(gpoints, m)) +#' plot(gpoints) #' plot(affine(gpoints, trans_m)) -#' plot(affine(gpoints, scale_m)) -#' aff_gpoints <- affine(gpoints, aff_m) -#' plot(aff_gpoints) -#' plot(affine(aff_gpoints, aff_m, inv = TRUE)) #' #' # giottoPolygon ############################################# -#' plot(affine(gpoly, m)) -#' plot(affine(gpoly, trans_m)) +#' plot(gpoly) #' plot(affine(gpoly, scale_m)) -#' aff_gpoly <- affine(gpoly, aff_m) -#' plot(aff_gpoly) -#' plot(affine(aff_gpoly, aff_m, inv = TRUE)) #' #' # spatLocsObj ############################################### #' plot(affine(sl, m)) #' plot(affine(sl, trans_m)) #' plot(affine(sl, scale_m)) +#' # this transformation can be inverted #' aff_sl <- affine(sl, aff_m) #' plot(aff_sl) #' plot(affine(aff_sl, aff_m, inv = TRUE)) @@ -117,14 +110,15 @@ setMethod( xm <- as.matrix(x[, c(xcol, ycol), with = FALSE]) # translations (if any) - trans <- NULL + translation <- NULL if (ncol(m) > 2) { translation <- m[seq(2), 3] # class: numeric if (isTRUE(inv)) translation <- -translation + if (all(translation == c(0, 0))) translation <- NULL } # inv translation - if (!is.null(trans) && isTRUE(inv)) { + if (!is.null(translation) && isTRUE(inv)) { xm <- t(t(xm) + translation) } @@ -134,7 +128,7 @@ setMethod( xm <- xm %*% aff_m # normal translation - if (!is.null(trans) && !isTRUE(inv)) { + if (!is.null(translation) && !isTRUE(inv)) { xm <- t(t(xm) + translation) } @@ -147,6 +141,7 @@ setMethod( + #' @name decomp_affine #' @title Decompose affine matrix into scale, rotation, and shear operations #' @description Affine transforms are linear transformations that cover scaling, @@ -158,30 +153,94 @@ setMethod( #' @returns a list of transforms information. #' @keywords internal #' @examples +#' # affine transform matrices #' m <- diag(rep(1, 3)) -#' trans_m <- matrix(c(1, 0, 0, 0, 1, 0, 200, 300, 1), nrow = 3) -#' scale_m <- matrix(c(2, 0, 0, 0, 3, 0, 0, 0, 1), nrow = 3) -#' +#' shear_m <- trans_m <- m +#' trans_m[seq(2), 3] <- c(200, 300) +#' scale_m <- diag(c(2, 3, 1)) +#' shear_m[2, 1] <- 2 #' aff_m <- matrix(c( #' 2, 0.5, 1000, -#' -0.3, 3, 20, +#' -0.3, 3, 20, #' 100, 29, 1 #' ), nrow = 3, byrow = TRUE) #' +#' # show decomps +#' # values are shown in order of operations #' decomp_affine(m) #' decomp_affine(trans_m) #' decomp_affine(scale_m) -#' decomp_affine(aff_m) +#' s <- decomp_affine(shear_m) +#' a <- decomp_affine(aff_m) +#' force(a) +#' +#' # perform piecewise transforms with decomp +#' +#' sl_shear_piecewise <- sl %>% +#' spin(GiottoUtils::degrees(s$rotate), x0 = 0, y0 = 0) %>% +#' shear(fx = s$shear[["x"]], fy = s$shear[["y"]], x0 = 0, y0 = 0) %>% +#' rescale(fx = s$scale[["x"]], fy = s$scale[["y"]], x0 = 0, y0 = 0) %>% +#' spatShift(dx = s$translate[["x"]], dy = s$translate[["y"]]) +#' +#' sl_aff_piecewise <- sl %>% +#' spin(GiottoUtils::degrees(a$rotate), x0 = 0, y0 = 0) %>% +#' shear(fx = a$shear[["x"]], fy = a$shear[["y"]], x0 = 0, y0 = 0) %>% +#' rescale(fx = a$scale[["x"]], fy = a$scale[["y"]], x0 = 0, y0 = 0) %>% +#' spatShift(dx = a$translate[["x"]], dy = a$translate[["y"]]) +#' +#' plot(affine(sl, shear_m)) +#' plot(sl_shear_piecewise) +#' plot(affine(sl, aff_m)) +#' plot(sl_aff_piecewise) +#' #' @export +#' @seealso [solve.affine_decomp()] decomp_affine <- function(x) { # should be matrix or coercible to matrix x <- as.matrix(x) - + a11 <- x[[1, 1]] a21 <- x[[2, 1]] a12 <- x[[1, 2]] a22 <- x[[2, 2]] + res_x <- .decomp_affine_xshear(a11, a21, a12, a22) + res_y <- .decomp_affine_yshear(a11, a21, a12, a22) + + res_x_s <- .decomp_affine_simplicity(res_x) + res_y_s <- .decomp_affine_simplicity(res_y) + + if (res_y_s > res_x_s) { + res <- res_y + } else { + res <- res_x + } + + # apply xy translations + if (ncol(x) == 3) { + res$translate = res$translate + x[seq(2), 3] + } + + res <- structure( + .Data = c(res, list(matrix = x)), class = "affine_decomp" + ) + + return(res) +} + +# score decomp solutions based on how simple they are +.decomp_affine_simplicity <- function(affine_res) { + a <- affine_res + + score <- 0 + score <- score + sum(a$scale == c(1, 1)) + score <- score + sum(a$shear == c(0, 0)) + score <- score + sum(a$rotate == 0) + + return(score) +} + +.decomp_affine_yshear <- function(a11, a21, a12, a22) { sx <- sqrt(a11^2 + a21^2) # scale x r <- atan(a21 / a11) # rotation msy <- a12 * cos(r) + a22 * sin(r) @@ -190,34 +249,100 @@ decomp_affine <- function(x) { } else { sy <- (a22 - msy * sin(r)) / cos(r) } - m <- msy / sy # shear + m <- msy / sy # y shear (no x shear) - # translations - if (ncol(x) > 2) { - tx <- x[[1, 3]] - ty <- x[[2, 3]] + list( + scale = c(x = sx, y = sy), + rotate = r, + shear = c(x = 0, y = m), + translate = c(x = 0, y = 0), + order = c("rotate", "shear", "scale", "translate") + ) +} + +.decomp_affine_xshear <- function(a11, a21, a12, a22) { + sy <- sqrt(a12^2 + a22^2) # scale y + r <- atan(-(a12 / a22)) # rotation + msx <- a21 * cos(r) - a11 * sin(r) + if (sin(r) != 0) { # scale y + sx <- (a21 - msx * cos(r)) / sin(r) } else { - tx <- ty <- 0 + sx <- (a11 + msx * sin(r)) / cos(r) } + m <- msx / sx # y shear (no x shear) - structure( - .Data = list( - scale = c(x = sx, y = sy), - rotate = r, - shear = m, - translate = c(x = tx, y = ty) - ), - class = "affine" + list( + scale = c(x = sx, y = sy), + rotate = r, + shear = c(x = m, y = 0), + translate = c(x = 0, y = 0), + order = c("rotate", "shear", "scale", "translate") ) } -#' @name print.affine -#' @title affine print method + + +#' @name print.affine_decomp +#' @title affine_decomp print method #' @param x object to print #' @param \dots additional params to pass (none implemented) #' @keywords internal #' @export -print.affine <- function(x, ...) { - cat("\n") +print.affine_decomp <- function(x, ...) { + cat("\n") + # reorder in order of piecewise transforms + x <- x[x$order] print_list(x) } + +#' @name solve.affine_decomp +#' @title Solve for inverted 2D affine decomp +#' @param a `affine_decomp` object +#' @param b not used +#' @param \dots additional params to pass (none implemented) +#' @examples +#' sl <- GiottoData::loadSubObjectMini("spatLocsObj") +#' +#' m <- matrix(c( +#' 2, 0.5, 1000, +#' -0.3, 3, 20, +#' 100, 29, 1 +#' ), nrow = 3, byrow = TRUE) +#' +#' a <- decomp_affine(m) +#' i <- solve(decomp) # inverted +#' +#' aff_sl <- affine(sl, aff_m) +#' inv_sl <- aff_sl %>% +#' spatShift(dx = i$translate[["x"]], dy = i$translate[["y"]]) %>% +#' spin(GiottoUtils::degrees(i$rotate), x0 = 0, y0 = 0) %>% +#' shear(fx = i$shear[["x"]], fy = i$shear[["y"]], x0 = 0, y0 = 0) %>% +#' rescale(fx = i$scale[["x"]], fy = i$scale[["y"]], x0 = 0, y0 = 0) +#' +#' plot(aff_sl) +#' plot(sl) +#' plot(inv_sl) # same as original +#' +#' @export +solve.affine_decomp <- function(a, b, ...) { + m <- a$matrix[seq(2), seq(2)] + m <- solve(m) + # translations <- NULL + translation <- -a$translate + + inv_m <- rbind(m, c(0,0)) %>% + cbind(c(translation, 1)) + + res <- decomp_affine(inv_m) + res$order <- c("translate", "rotate", "shear", "scale") + class(res) <- "affine_decomp" + return(res) +} + + + + + + + + diff --git a/R/methods-shear.R b/R/methods-shear.R new file mode 100644 index 00000000..3ed6566b --- /dev/null +++ b/R/methods-shear.R @@ -0,0 +1,62 @@ +#' @include generics.R +#' @include classes.R + +# docs ----------------------------------------------------------- # +#' @title Apply a shear tranform +#' @name shear +#' @description Apply shear transformation to a spatial object. +#' Currently only works for 2D transforms. This implementation +#' applies a shear along one axis by adding the value of the other +#' axis after a multiplicative factor `fx` or `fy` is applied. +#' @param x object +#' @param fx numeric. x shear +#' @param fy numeric. y shear +#' @param x0 numeric. x-origin of shear +#' @param y0 numeric. y-origin of shear +#' @param ... additional args to pass (none implemented) +#' @returns shear transformed object +#' @examples +#' sl <- GiottoData::loadSubObjectMini("spatLocsObj") +#' +#' plot(shear(sl, fx = 2)) +#' +#' # equivalent affine transform +#' shear_m <- diag(rep(1, 3)) +#' shear_m[2, 1] <- 2 +#' plot(affine(sl, shear_m)) +#' plot(shear(sl, fx = 2, x0 = 0, y0 = 0)) +NULL +# ---------------------------------------------------------------- # + +setMethod("shear", signature("spatLocsObj"), function( + x, fx = 0, fy = 0, x0, y0, ... +) { + x <- data.table::copy(x) + sdimx <- sdimy <- NULL + + # find center + if (missing(x0)) x0 <- x[][, mean(range(sdimx))] + if (missing(y0)) y0 <- x[][, mean(range(sdimy))] + scenter <- c(x0, y0) + + if (!all(scenter == c(0, 0))) { + # center values + x <- spatShift(x, dx = -x0, dy = -y0) + } + + # perform shears + if (fx != 0) { + x[][, sdimx := sdimy * fx + sdimx] + } + if (fy != 0) { + x[][, sdimy := sdimx * fy + sdimy] + } + + if (!all(scenter == c(0, 0))) { + # return values to original positions + x <- spatShift(x, dx = x0, dy = y0) + } + + return(x) +}) + diff --git a/man/affine.Rd b/man/affine.Rd index c2734ee4..d45d3a5f 100644 --- a/man/affine.Rd +++ b/man/affine.Rd @@ -45,25 +45,18 @@ gpoly <- GiottoData::loadSubObjectMini("giottoPolygon") sl <- GiottoData::loadSubObjectMini("spatLocsObj") # giottoPoints ############################################## -plot(affine(gpoints, m)) +plot(gpoints) plot(affine(gpoints, trans_m)) -plot(affine(gpoints, scale_m)) -aff_gpoints <- affine(gpoints, aff_m) -plot(aff_gpoints) -plot(affine(aff_gpoints, aff_m, inv = TRUE)) # giottoPolygon ############################################# -plot(affine(gpoly, m)) -plot(affine(gpoly, trans_m)) +plot(gpoly) plot(affine(gpoly, scale_m)) -aff_gpoly <- affine(gpoly, aff_m) -plot(aff_gpoly) -plot(affine(aff_gpoly, aff_m, inv = TRUE)) # spatLocsObj ############################################### plot(affine(sl, m)) plot(affine(sl, trans_m)) plot(affine(sl, scale_m)) +# this transformation can be inverted aff_sl <- affine(sl, aff_m) plot(aff_sl) plot(affine(aff_sl, aff_m, inv = TRUE)) diff --git a/man/decomp_affine.Rd b/man/decomp_affine.Rd index 0225e95f..a8ab4f82 100644 --- a/man/decomp_affine.Rd +++ b/man/decomp_affine.Rd @@ -20,19 +20,48 @@ needed to perform them as a list of class \code{affine}. Works only for 2D transforms. Logic from \url{https://math.stackexchange.com/a/3521141} } \examples{ +# affine transform matrices m <- diag(rep(1, 3)) -trans_m <- matrix(c(1, 0, 0, 0, 1, 0, 200, 300, 1), nrow = 3) -scale_m <- matrix(c(2, 0, 0, 0, 3, 0, 0, 0, 1), nrow = 3) - +shear_m <- trans_m <- m +trans_m[seq(2), 3] <- c(200, 300) +scale_m <- diag(c(2, 3, 1)) +shear_m[2, 1] <- 2 aff_m <- matrix(c( 2, 0.5, 1000, - -0.3, 3, 20, + -0.3, 3, 20, 100, 29, 1 ), nrow = 3, byrow = TRUE) +# show decomps +# values are shown in order of operations decomp_affine(m) decomp_affine(trans_m) decomp_affine(scale_m) -decomp_affine(aff_m) +s <- decomp_affine(shear_m) +a <- decomp_affine(aff_m) +force(a) + +# perform piecewise transforms with decomp + +sl_shear_piecewise <- sl \%>\% + spin(GiottoUtils::degrees(s$rotate), x0 = 0, y0 = 0) \%>\% + shear(fx = s$shear[["x"]], fy = s$shear[["y"]], x0 = 0, y0 = 0) \%>\% + rescale(fx = s$scale[["x"]], fy = s$scale[["y"]], x0 = 0, y0 = 0) \%>\% + spatShift(dx = s$translate[["x"]], dy = s$translate[["y"]]) + +sl_aff_piecewise <- sl \%>\% + spin(GiottoUtils::degrees(a$rotate), x0 = 0, y0 = 0) \%>\% + shear(fx = a$shear[["x"]], fy = a$shear[["y"]], x0 = 0, y0 = 0) \%>\% + rescale(fx = a$scale[["x"]], fy = a$scale[["y"]], x0 = 0, y0 = 0) \%>\% + spatShift(dx = a$translate[["x"]], dy = a$translate[["y"]]) + +plot(affine(sl, shear_m)) +plot(sl_shear_piecewise) +plot(affine(sl, aff_m)) +plot(sl_aff_piecewise) + +} +\seealso{ +\code{\link[=solve.affine_decomp]{solve.affine_decomp()}} } \keyword{internal} diff --git a/man/print.affine.Rd b/man/print.affine_decomp.Rd similarity index 60% rename from man/print.affine.Rd rename to man/print.affine_decomp.Rd index 0d0b03e4..ba6f76b0 100644 --- a/man/print.affine.Rd +++ b/man/print.affine_decomp.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/methods-affine.R -\name{print.affine} -\alias{print.affine} -\title{affine print method} +\name{print.affine_decomp} +\alias{print.affine_decomp} +\title{affine_decomp print method} \usage{ -\method{print}{affine}(x, ...) +\method{print}{affine_decomp}(x, ...) } \arguments{ \item{x}{object to print} @@ -12,6 +12,6 @@ \item{\dots}{additional params to pass (none implemented)} } \description{ -affine print method +affine_decomp print method } \keyword{internal} diff --git a/man/shear.Rd b/man/shear.Rd new file mode 100644 index 00000000..a5bcd455 --- /dev/null +++ b/man/shear.Rd @@ -0,0 +1,38 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/methods-shear.R +\name{shear} +\alias{shear} +\title{Apply a shear tranform} +\arguments{ +\item{x}{object} + +\item{fx}{numeric. x shear} + +\item{fy}{numeric. y shear} + +\item{x0}{numeric. x-origin of shear} + +\item{y0}{numeric. y-origin of shear} + +\item{...}{additional args to pass (none implemented)} +} +\value{ +shear transformed object +} +\description{ +Apply shear transformation to a spatial object. +Currently only works for 2D transforms. This implementation +applies a shear along one axis by adding the value of the other +axis after a multiplicative factor \code{fx} or \code{fy} is applied. +} +\examples{ +sl <- GiottoData::loadSubObjectMini("spatLocsObj") + +plot(shear(sl, fx = 2)) + +# equivalent affine transform +shear_m <- diag(rep(1, 3)) +shear_m[2, 1] <- 2 +plot(affine(sl, shear_m)) +plot(shear(sl, fx = 2, x0 = 0, y0 = 0)) +} diff --git a/man/solve.affine_decomp.Rd b/man/solve.affine_decomp.Rd new file mode 100644 index 00000000..1d463d2f --- /dev/null +++ b/man/solve.affine_decomp.Rd @@ -0,0 +1,42 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/methods-affine.R +\name{solve.affine_decomp} +\alias{solve.affine_decomp} +\title{Solve for inverted 2D affine decomp} +\usage{ +\method{solve}{affine_decomp}(a, b, ...) +} +\arguments{ +\item{a}{\code{affine_decomp} object} + +\item{b}{not used} + +\item{\dots}{additional params to pass (none implemented)} +} +\description{ +Solve for inverted 2D affine decomp +} +\examples{ +sl <- GiottoData::loadSubObjectMini("spatLocsObj") + +m <- matrix(c( + 2, 0.5, 1000, + -0.3, 3, 20, + 100, 29, 1 +), nrow = 3, byrow = TRUE) + +a <- decomp_affine(m) +i <- solve(decomp) # inverted + +aff_sl <- affine(sl, aff_m) +inv_sl <- aff_sl \%>\% + spatShift(dx = i$translate[["x"]], dy = i$translate[["y"]]) \%>\% + spin(GiottoUtils::degrees(i$rotate), x0 = 0, y0 = 0) \%>\% + shear(fx = i$shear[["x"]], fy = i$shear[["y"]], x0 = 0, y0 = 0) \%>\% + rescale(fx = i$scale[["x"]], fy = i$scale[["y"]], x0 = 0, y0 = 0) + +plot(aff_sl) +plot(sl) +plot(inv_sl) # same as original + +} From cc02e8bbf75014abe7a1066faca00596b1a44afe Mon Sep 17 00:00:00 2001 From: Iqra Amin <90134115+iqraAmin@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:17:07 +0500 Subject: [PATCH 028/160] Update DESCRIPTION --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 6827402b..de86156d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -28,7 +28,7 @@ RoxygenNote: 7.3.1 Depends: base (>= 4.4.0), utils (>= 4.4.0), - R (>= 4.4.0), + R (>= 4.3.1), Imports: checkmate, data.table (>= 1.12.2), From d7628bdd3c28865f90807fb20c2ff2faf0d13c7c Mon Sep 17 00:00:00 2001 From: Iqra Amin <90134115+iqraAmin@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:37:30 +0500 Subject: [PATCH 029/160] Update DESCRIPTION --- DESCRIPTION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index de86156d..cd6d091f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -26,8 +26,8 @@ Encoding: UTF-8 Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.1 Depends: - base (>= 4.4.0), - utils (>= 4.4.0), + base (>= 4.3.1), + utils (>= 4.3.1), R (>= 4.3.1), Imports: checkmate, From b316ae1ace355e540cb8a66e0a351cbb3995ab8e Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 18 Jun 2024 12:04:00 -0400 Subject: [PATCH 030/160] feat: affine feat: `affine2d` class feat: `affine2d` initialize - converts inputs to anchor slot to extent numeric vectors (xmin, xmax, ymin, ymax) - regenerates rotate, shear, scale, translate values for the affine after every call feat: helpful internals for objects with `ext()` - `.get_centroid_xy()` internal for getting numeric centroid xy values of any object that responds to `ext()` - `.bound_poly()` internal for generating a dummy polygon from the extent of any object that responds to `ext()` feat: define `affine()` generic feat: `shear()` feat: `affine()` - change `decomp_affine()` to an internal that runs when `affine()` is called on a `matrix` - `.aff_shift_2d()`, `.aff_shift_2d<-()`, `.aff_linear_2d`, `.aff_linear_2d()` internals for accessing and manipulating affine matrices feat: extract methods for `affine2d` feat: `plot()` for `affine2d` - plots the affine transform described by an `affine2d` class. blue is start, red is end feat: `rescale()` for `affine2d` feat: `show()` for `affine2d` feat: `spatShift()` for `affine2d` chore: update news chore: document --- NAMESPACE | 5 +- NEWS.md | 10 ++- R/classes.R | 28 +++++++ R/generics.R | 2 +- R/giotto_structures.R | 14 +++- R/methods-affine.R | 151 +++++++++++++++++-------------------- R/methods-extract.R | 46 +++++++++++ R/methods-initialize.R | 18 ++++- R/methods-plot.R | 13 +++- R/methods-rescale.R | 33 ++++++++ R/methods-shear.R | 120 ++++++++++++++++++++++++++--- R/methods-show.R | 31 ++++++++ R/methods-spatShift.R | 43 +++++++---- R/methods-spin.R | 38 ++++++++++ man/affine.Rd | 30 +++++--- man/decomp_affine.Rd | 18 ++--- man/extract-methods.Rd | 17 +++++ man/plot-generic.Rd | 5 ++ man/print.affine_decomp.Rd | 17 ----- man/rescale.Rd | 3 + man/shear.Rd | 13 ++++ man/show-methods.Rd | 3 + man/solve.affine_decomp.Rd | 42 ----------- man/spatShift.Rd | 3 + man/spin.Rd | 3 + 25 files changed, 505 insertions(+), 201 deletions(-) delete mode 100644 man/print.affine_decomp.Rd delete mode 100644 man/solve.affine_decomp.Rd diff --git a/NAMESPACE b/NAMESPACE index c60553ac..d0579a65 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,5 +1,6 @@ # Generated by roxygen2: do not edit by hand +S3method(.DollarNames,affine2d) S3method(.DollarNames,dimObj) S3method(.DollarNames,metaData) S3method(.DollarNames,spatEnrObj) @@ -8,8 +9,6 @@ S3method(.DollarNames,terraVectData) S3method(as.data.table,SpatVector) S3method(as.data.table,giottoPoints) S3method(as.data.table,giottoPolygon) -S3method(print,affine_decomp) -S3method(solve,affine_decomp) S3method(t,spatLocsObj) S3method(t,spatialNetworkObj) export(addCellMetadata) @@ -102,7 +101,6 @@ export(create_spat_grid_obj) export(create_spat_locs_obj) export(create_spat_net_obj) export(cropGiottoLargeImage) -export(decomp_affine) export(distGiottoImage) export(edge_distances) export(estimateImageBg) @@ -361,6 +359,7 @@ exportMethods(reconnect) exportMethods(rescale) exportMethods(rownames) exportMethods(setGiotto) +exportMethods(shear) exportMethods(spatIDs) exportMethods(spatShift) exportMethods(spatUnit) diff --git a/NEWS.md b/NEWS.md index 0c7cf235..0cc27f4c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,9 +12,13 @@ ## new - `affine()` for `giottoPolygon`, `giottoPoints`, `spatLocsObj` -- `decomp_affine()` for decomposing affine matrix to simple transforms -- `shear()` for `spatLocsObj` -- `solve()` method for `affine_decomp` +- `shear()` for `giottoPoints`, `giottoPolygon`, `spatLocsObj`, `affine2d` +- `affine2d` class for accumulating linear transforms to be used with `affine()` +- `spin()`, `rescale`, `spatShift()` methods for `affine2d` +- `initialize()`, `[`, `$`, `show()`, `plot()` methods for `affine2d` +- `.get_centroid_xy()` internal for getting numeric centroid xy values of any object that responds to `ext()` +- `.bound_poly()` internal for generating a dummy polygon from the extent of any object that responds to `ext()` +- `.aff_shift_2d()`, `.aff_shift_2d<-()`, `.aff_linear_2d`, `.aff_linear_2d()` internals for accessing and manipulating affine matrices # GiottoClass 0.3.1 (2024/05/21) diff --git a/R/classes.R b/R/classes.R index a0e81389..a27071d2 100644 --- a/R/classes.R +++ b/R/classes.R @@ -1630,6 +1630,34 @@ giottoLargeImage <- setClass( ) ) + + + +setClass( + Class = "affine2d", + slots = list( + anchor = "ANY", + affine = "matrix", + order = "character", + rotate = "numeric", + shear = "numeric", + scale = "numeric", + translate = "numeric" + ), + prototype = list( + anchor = c(-180, 180, -90, 90), + affine = diag(rep(1, 2L)), + order = c("rotate", "shear", "scale", "translate"), + rotate = 0, + shear = c(0, 0), + scale = c(1, 1), + translate = c(0, 0) + ) +) + + + + # function for updating image objects if structure definitions have changed .update_giotto_image <- function(x) { if (inherits(x, "giottoLargeImage")) { diff --git a/R/generics.R b/R/generics.R index 414ca7e0..6b76b940 100644 --- a/R/generics.R +++ b/R/generics.R @@ -35,7 +35,7 @@ setGeneric( # Methods and documentations found in methods-spatShift.R setGeneric("spatShift", function(x, ...) standardGeneric("spatShift")) -setGeneric("affine", function(x, ...) standardGeneric("affine")) +setGeneric("affine", function(x, y, ...) standardGeneric("affine")) setGeneric("shear", function(x, ...) standardGeneric("shear")) # Methods and documentations found in methods-overlaps.R diff --git a/R/giotto_structures.R b/R/giotto_structures.R index 649cc911..ebadbbdf 100644 --- a/R/giotto_structures.R +++ b/R/giotto_structures.R @@ -166,9 +166,19 @@ } +# from a spatvector, get the centroid xy values as a numeric vector +.get_centroid_xy <- function(x) { + res <- centroids(x) %>% ext() %>% .ext_to_num_vec() + res[c(1L, 3L)] +} - - +# create a polygon of the extent. +# useful for plotting and figuring out how the full data will behave spatially +.bound_poly <- function(x) { + res <- ext(x) %>% as.polygons() + res$id <- "bound" + return(res) +} diff --git a/R/methods-affine.R b/R/methods-affine.R index 16bd72f8..45e326ab 100644 --- a/R/methods-affine.R +++ b/R/methods-affine.R @@ -2,7 +2,7 @@ #' @include classes.R # docs ----------------------------------------------------------- # -#' @title Apply an affine tranform +#' @title Affine transformations #' @name affine #' @description Apply an affine transformation matrix to a spatial object. #' Currently only works for 2D transforms. @@ -44,16 +44,35 @@ NULL #' @rdname affine #' @export -setMethod("affine", signature("SpatVector"), function(x, m, inv = FALSE, ...) { - .affine_sv(x, m, inv, ...) +setMethod("affine", signature(x = "ANY", y = "missing"), function(x) { + x <- as.matrix(x) + if (ncol(x) <= 3) { + res <- new("affine2d", affine = x) + } + return(res) +}) + +#' @rdname affine +#' @export +setMethod("affine", signature(x = "ANY", y = "affine2d"), function(x, y, ...) { + a <- get_args_list(...) + a$y <- y@affine + do.call(affine, args = a) +}) + +#' @rdname affine +#' @export +setMethod("affine", signature(x = "SpatVector", y = "matrix"), + function(x, y, inv = FALSE, ...) { + .affine_sv(x, m = y, inv, ...) }) #' @rdname affine #' @export setMethod( - "affine", signature("giottoPoints"), - function(x, m, inv = FALSE, ...) { - x[] <- .affine_sv(x = x[], m = m, inv = inv, ...) + "affine", signature(x = "giottoPoints", y = "matrix"), + function(x, y, inv = FALSE, ...) { + x[] <- .affine_sv(x = x[], m = y, inv = inv, ...) return(x) } ) @@ -61,19 +80,19 @@ setMethod( #' @rdname affine #' @export setMethod( - "affine", signature("giottoPolygon"), - function(x, m, inv = FALSE, ...) { - .do_gpoly(x, what = .affine_sv, args = list(m = m, inv = inv, ...)) + "affine", signature(x = "giottoPolygon", y = "matrix"), + function(x, y, inv = FALSE, ...) { + .do_gpoly(x, what = .affine_sv, args = list(m = y, inv = inv, ...)) } ) #' @rdname affine #' @export setMethod( - "affine", signature("spatLocsObj"), - function(x, m, inv = FALSE, ...) { + "affine", signature("spatLocsObj", y = "matrix"), + function(x, y, inv = FALSE, ...) { x[] <- .affine_dt( - x = x[], m = m, xcol = "sdimx", ycol = "sdimy", inv = inv, ... + x = x[], m = y, xcol = "sdimx", ycol = "sdimy", inv = inv, ... ) return(x) } @@ -89,7 +108,6 @@ setMethod( m <- as.matrix(m) gtype <- terra::geomtype(x) xdt <- data.table::as.data.table(x, geom = "XY") - xdt <- .affine_dt( x = xdt, m = m, xcol = "x", ycol = "y", inv = inv, ... ) @@ -165,13 +183,13 @@ setMethod( #' 100, 29, 1 #' ), nrow = 3, byrow = TRUE) #' -#' # show decomps +#' # create affine objects #' # values are shown in order of operations -#' decomp_affine(m) -#' decomp_affine(trans_m) -#' decomp_affine(scale_m) -#' s <- decomp_affine(shear_m) -#' a <- decomp_affine(aff_m) +#' affine(m) +#' affine(trans_m) +#' affine(scale_m) +#' s <- affine(shear_m) +#' a <- affine(aff_m) #' force(a) #' #' # perform piecewise transforms with decomp @@ -193,9 +211,7 @@ setMethod( #' plot(affine(sl, aff_m)) #' plot(sl_aff_piecewise) #' -#' @export -#' @seealso [solve.affine_decomp()] -decomp_affine <- function(x) { +.decomp_affine <- function(x) { # should be matrix or coercible to matrix x <- as.matrix(x) @@ -219,12 +235,13 @@ decomp_affine <- function(x) { # apply xy translations if (ncol(x) == 3) { res$translate = res$translate + x[seq(2), 3] + } else { + # append translations + x <- cbind(x, rep(0, 2L)) %>% + rbind(c(0, 0, 1)) } - res <- structure( - .Data = c(res, list(matrix = x)), class = "affine_decomp" - ) - + res$affine <- x return(res) } @@ -280,68 +297,38 @@ decomp_affine <- function(x) { ) } - - -#' @name print.affine_decomp -#' @title affine_decomp print method -#' @param x object to print -#' @param \dots additional params to pass (none implemented) -#' @keywords internal -#' @export -print.affine_decomp <- function(x, ...) { - cat("\n") - # reorder in order of piecewise transforms - x <- x[x$order] - print_list(x) +.aff_linear_2d <- function(x) { + if (inherits(x, "affine2d")) x <- x[] + x[][seq(2), seq(2)] } -#' @name solve.affine_decomp -#' @title Solve for inverted 2D affine decomp -#' @param a `affine_decomp` object -#' @param b not used -#' @param \dots additional params to pass (none implemented) -#' @examples -#' sl <- GiottoData::loadSubObjectMini("spatLocsObj") -#' -#' m <- matrix(c( -#' 2, 0.5, 1000, -#' -0.3, 3, 20, -#' 100, 29, 1 -#' ), nrow = 3, byrow = TRUE) -#' -#' a <- decomp_affine(m) -#' i <- solve(decomp) # inverted -#' -#' aff_sl <- affine(sl, aff_m) -#' inv_sl <- aff_sl %>% -#' spatShift(dx = i$translate[["x"]], dy = i$translate[["y"]]) %>% -#' spin(GiottoUtils::degrees(i$rotate), x0 = 0, y0 = 0) %>% -#' shear(fx = i$shear[["x"]], fy = i$shear[["y"]], x0 = 0, y0 = 0) %>% -#' rescale(fx = i$scale[["x"]], fy = i$scale[["y"]], x0 = 0, y0 = 0) -#' -#' plot(aff_sl) -#' plot(sl) -#' plot(inv_sl) # same as original -#' -#' @export -solve.affine_decomp <- function(a, b, ...) { - m <- a$matrix[seq(2), seq(2)] - m <- solve(m) - # translations <- NULL - translation <- -a$translate - - inv_m <- rbind(m, c(0,0)) %>% - cbind(c(translation, 1)) +`.aff_linear_2d<-` <- function(x, value) { + checkmate::assert_matrix(value, nrows = 2L, ncols = 2L) + if (inherits(x, "affine2d")) { + x[][seq(2), seq(2)] <- value + x <- initialize(x) + } + else x[seq(2), seq(2)] <- value - res <- decomp_affine(inv_m) - res$order <- c("translate", "rotate", "shear", "scale") - class(res) <- "affine_decomp" - return(res) + return(x) } +.aff_shift_2d <- function(x) { + if (inherits(x, "affine2d")) x <- x[] + x[seq(2), 3] +} - - +`.aff_shift_2d<-` <- function(x, value) { + checkmate::assert_numeric(value, len = 2L) + if (inherits(x, "affine2d")) { + x[][seq(2), 3] <- value + x <- initialize(x) + } else { + x[seq(2), 3] <- value + } + + return(x) +} diff --git a/R/methods-extract.R b/R/methods-extract.R index 8b5890f7..e68f4f89 100644 --- a/R/methods-extract.R +++ b/R/methods-extract.R @@ -186,6 +186,24 @@ setMethod( names(x@spatVector) } +#' @rdname extract-methods +#' @section \code{`$`} methods: +#' Select piecewise transform values from `affine2d` +#' @export +setMethod("$", signature("affine2d"), function(x, name) { + accessible <- c("affine", "order", "rotate", "shear", "scale", "translate") + if (name %in% accessible) { + return(slot(x, name)) + } else { + return(NULL) + } +}) + +#' @export +.DollarNames.affine2d <- function(x, pattern) { + c("affine", "order", "rotate", "shear", "scale", "translate") +} + # [ S4 access generic #### @@ -955,3 +973,31 @@ setMethod( x } ) + +#' @rdname extract-methods +#' @export +setMethod( + "[", + signature( + x = "affine2d", i = "missing", j = "missing", drop = "missing" + ), + function(x) { + x@affine + } +) + +#' @rdname extract-methods +#' @aliases [<-,affine2d,missing,missing, +#' ANY-method [<-,affine2d,missing,missing-method +#' @docType methods +#' @section \code{`[<-`} methods: +#' Assign to \code{affine} slot in affine2d +#' @export +setMethod( + "[<-", + signature(x = "affine2d", i = "missing", j = "missing", value = "ANY"), + function(x, value) { + x@affine <- value + return(initialize(x)) + } +) diff --git a/R/methods-initialize.R b/R/methods-initialize.R index edfa578c..c97b73f0 100644 --- a/R/methods-initialize.R +++ b/R/methods-initialize.R @@ -566,8 +566,22 @@ setMethod( ) - - +## transform_plan_2d +setMethod("initialize", "affine2d", function(.Object, ...) { + .Object <- methods::callNextMethod() + .Object@anchor <- ext(.Object@anchor) %>% + .ext_to_num_vec() + + res <- .decomp_affine(.Object@affine) + + .Object@affine <- res$affine + .Object@rotate <- res$rotate + .Object@shear <- res$shear + .Object@scale <- res$scale + .Object@translate <- res$translate + + return(.Object) +}) diff --git a/R/methods-plot.R b/R/methods-plot.R index fe7a9eac..54a93a13 100644 --- a/R/methods-plot.R +++ b/R/methods-plot.R @@ -291,9 +291,16 @@ setMethod("plot", signature(x = "spatialNetworkObj", y = "missing"), function(x, }) - - - +#' @describeIn plot-generic Plot a affine2d. blue is start, red is end +#' @export +setMethod("plot", signature(x = "affine2d", y = "missing"), function(x, ...) { + a <- as.polygons(ext(x@anchor)) + a$id <- "start" + b <- affine(a, x) + b$id <- "end" + res <- rbind(a, b) + terra::plot(res, border = c("blue", "red"), alpha = 0.5) +}) # internals #### diff --git a/R/methods-rescale.R b/R/methods-rescale.R index 5dd50b4c..648d37d4 100644 --- a/R/methods-rescale.R +++ b/R/methods-rescale.R @@ -230,6 +230,39 @@ setMethod("rescale", signature("giottoLargeImage"), function(x, fx = 1, fy = fx, return(x) }) +#' @rdname rescale +#' @export +setMethod("rescale", signature("affine2d"), function(x, fx = 1, fy = fx, x0, y0) { + a <- get_args_list() + + # update linear + scale_m <- diag(c(fx, fy)) + old_aff <- new_aff <- x@affine + .aff_linear_2d(new_aff) <- .aff_linear_2d(new_aff) %*% scale_m + + ## calc shifts ## + # create dummy + d <- .bound_poly(x@anchor) + # perform transforms so far + a$x <- affine(d, old_aff) + # perform new transform + post <- do.call(rescale, args = a) + + # perform affine & transform without shifts + b <- a + b$x0 <- b$y0 <- 0 + b$x <- affine(d, .aff_linear_2d(old_aff)) + pre <- do.call(rescale, args = b) + + # find xyshift by comparing tfs so far vs new tf + xyshift <- .get_centroid_xy(post) - .get_centroid_xy(pre) + + # update translate + .aff_shift_2d(new_aff) <- xyshift + + x@affine <- new_aff + return(initialize(x)) +}) # TODO more methods for other objects diff --git a/R/methods-shear.R b/R/methods-shear.R index 3ed6566b..1e080019 100644 --- a/R/methods-shear.R +++ b/R/methods-shear.R @@ -28,35 +28,137 @@ NULL # ---------------------------------------------------------------- # +#' @rdname shear +#' @export setMethod("shear", signature("spatLocsObj"), function( x, fx = 0, fy = 0, x0, y0, ... ) { - x <- data.table::copy(x) - sdimx <- sdimy <- NULL + a <- get_args_list(...) + a$x <- x[] + x[] <- do.call(.shear_dt, args = a) + return(x) +}) + +#' @rdname shear +#' @export +setMethod("shear", signature("SpatVector"), function( + x, fx = 0, fy = 0, x0, y0, ... +) { + a <- get_args_list(...) + do.call(.shear_sv, args = a) +}) + +#' @rdname shear +#' @export +setMethod("shear", signature("giottoPoints"), function( + x, fx = 0, fy = 0, x0, y0, ... +) { + a <- get_args_list(...) + a$x <- x[] + res <- do.call(.shear_sv, args = a) + x[] <- res + return(x) +}) + +#' @rdname shear +#' @export +setMethod("shear", signature("giottoPolygon"), function( + x, fx = 0, fy = 0, x0, y0, ... +) { + a <- get_args_list(...) + a$x <- NULL + .do_gpoly(x, what = .shear_sv, args = a) +}) + + + +setMethod("shear", signature("affine2d"), function( + x, fx = 0, fy = 0, x0, y0, ... + ) { + a <- get_args_list(...) + + # update linear + shear_x <- matrix(c(1, fx, 0, 1), ncol = 2) + shear_y <- matrix(c(1, 0, fy, 1), ncol = 2) + old_aff <- new_aff <- x@affine + .aff_linear_2d(new_aff) <- .aff_linear_2d(new_aff) %*% shear_x %*% shear_y + + ## calc shifts ## + # create dummy + d <- .bound_poly(x@anchor) + # perform transforms so far + a$x <- affine(d, old_aff) + # perform new transform + post <- do.call(shear, args = a) + + # perform affine & transform without shifts + b <- a + b$x0 <- b$y0 <- 0 + b$x <- affine(d, .aff_linear_2d(old_aff)) + pre <- do.call(shear, args = b) + + # find xyshift by comparing tfs so far vs new tf + xyshift <- .get_centroid_xy(post) - .get_centroid_xy(pre) + + # update translate + .aff_shift_2d(new_aff) <- xyshift + x@affine <- new_aff + return(initialize(x)) +}) + + + +# internals #### + +.shear_dt <- function( + x, fx = 0, fy = 0, x0, y0, geom = c("sdimx", "sdimy", "sdimz"), ... +) { + x <- data.table::copy(x) + xyz <- tail(letters, 3L) + if (is.null(names(geom))) names(geom) <- xyz + if (!all(names(geom) %in% xyz)) stop("geom value names not recognized") + geom_col <- geom # avoid name collisions with terra "geom" ID column + # find center - if (missing(x0)) x0 <- x[][, mean(range(sdimx))] - if (missing(y0)) y0 <- x[][, mean(range(sdimy))] + if (missing(x0)) x0 <- x[, mean(range(get(geom_col[["x"]])))] + if (missing(y0)) y0 <- x[, mean(range(get(geom_col[["y"]])))] scenter <- c(x0, y0) if (!all(scenter == c(0, 0))) { # center values - x <- spatShift(x, dx = -x0, dy = -y0) + x <- spatShift(x, dx = -x0, dy = -y0, geom = geom) } # perform shears if (fx != 0) { - x[][, sdimx := sdimy * fx + sdimx] + x[, (geom[["x"]]) := get(geom_col[["y"]]) * fx + get(geom_col[["x"]])] } if (fy != 0) { - x[][, sdimy := sdimx * fy + sdimy] + x[, (geom[["y"]]) := get(geom_col[["x"]]) * fy + get(geom_col[["y"]])] } if (!all(scenter == c(0, 0))) { # return values to original positions - x <- spatShift(x, dx = x0, dy = y0) + x <- spatShift(x, dx = x0, dy = y0, geom = geom) } return(x) -}) +} + +.shear_sv <- function( + x, fx = 0, fy = 0, x0, y0, geom = tail(letters, 3L), ... +) { + a <- get_args_list(...) + gtype <- terra::geomtype(x) + a$x <- data.table::as.data.table(x, geom = "XY") + res <- do.call(.shear_dt, args = a) + + res <- switch(gtype, + "points" = terra::vect(res, geom = c("x", "y")), + "polygons" = terra::as.polygons(res) + ) + + return(res) +} diff --git a/R/methods-show.R b/R/methods-show.R index 9280faab..5e2d5f1f 100644 --- a/R/methods-show.R +++ b/R/methods-show.R @@ -778,6 +778,37 @@ setMethod( } ) + + + +#' @rdname show-methods +setMethod("show", signature("affine2d"), function(object) { + cat("\n") + .anchor_print <- function() { + paste(object@anchor, collapse = ", ") %>% + paste(" (xmin, xmax, ymin, ymax)") + } + .rad_val_show <- function() { + paste(object@rotate, " (rad)") + } + .xy_val_show <- function(x) { + paste(x, collapse = ", ") %>% + paste(" (x, y)") + } + + showlist <- list() + showlist$anchor <- .anchor_print() + for (tf in object@order) { + if (tf == "rotate") { + showlist$rotate <- .rad_val_show() + next + } + showlist[[tf]] <- .xy_val_show(slot(object, tf)) + } + GiottoUtils::print_list(showlist) +}) + + # internal setMethod("as.character", signature("giottoLargeImage"), function(x, ...) { sprintf("<%s> %s", class(x), objName(x)) diff --git a/R/methods-spatShift.R b/R/methods-spatShift.R index 2d219206..9a7c0884 100644 --- a/R/methods-spatShift.R +++ b/R/methods-spatShift.R @@ -140,6 +140,7 @@ setMethod( function(x, dx = 0, dy = 0, dz = 0, copy_obj = TRUE, ...) { argslist <- get_args_list() argslist$x <- x[] + argslist$geom = c("sdimx", "sdimy", "sdimz") # pass to data.frame method x[] <- do.call(spatShift, argslist) @@ -162,7 +163,7 @@ setMethod( spatlocs = x, dx = dx, dy = dy, dz = dz, copy_obj = copy_obj, - geom = geom, ... + geom = geom ) return(x) @@ -232,7 +233,17 @@ setMethod( } ) - +#' @rdname spatShift +#' @export +setMethod( + "spatShift", signature("affine2d"), + function(x, dx = 0, dy = 0, ...) { + aff <- x@affine + aff[seq(2), 3] <- aff[seq(2), 3] + c(dx, dy) + x@affine <- aff + return(initialize(x)) + } +) @@ -267,21 +278,22 @@ setMethod( if (is.null(names(geom))) names(geom) <- xyz if (!all(names(geom) %in% xyz)) stop("geom value names not recognized") + geom_col <- geom # avoid name collisions with terra "geom" ID column - spatlocs[, (geom[["x"]]) := get(geom[["x"]]) + dx] - spatlocs[, (geom[["y"]]) := get(geom[["y"]]) + dy] + spatlocs[, (geom_col[["x"]]) := get(geom_col[["x"]]) + dx] + spatlocs[, (geom_col[["y"]]) := get(geom_col[["y"]]) + dy] if (dz == 0) return(spatlocs) # return early if no z shift - if (geom[["z"]] %in% colnames(spatlocs)) { + if (geom_col[["z"]] %in% colnames(spatlocs)) { # existing z info - spatlocs[, (geom[["z"]]) := get(geom[["z"]]) + dz] + spatlocs[, (geom_col[["z"]]) := get(geom_col[["z"]]) + dz] } else { # initialize z info - spatlocs[, (geom[["z"]]) := dz] + spatlocs[, (geom_col[["z"]]) := dz] } # fix col ordering - data.table::setcolorder(spatlocs, c(geom, "cell_ID")) + data.table::setcolorder(spatlocs, c(geom_col, "cell_ID")) return(spatlocs) } @@ -428,13 +440,14 @@ setMethod( if (copy_obj) gpoly@spatVector <- terra::deepcopy(gpoly@spatVector) if (!all(dx == 0, dy == 0)) { - gpoly <- .do_gpoly(gpoly, - what = terra::shift, - args = list( - dx = dx, - dy = dy, - ... - ) + gpoly <- .do_gpoly( + gpoly, + what = terra::shift, + args = list( + dx = dx, + dy = dy, + ... + ) ) } gpoly diff --git a/R/methods-spin.R b/R/methods-spin.R index 0b555ab6..9f49efb4 100644 --- a/R/methods-spin.R +++ b/R/methods-spin.R @@ -206,6 +206,44 @@ setMethod( } ) +#' @rdname spin +#' @export +setMethod("spin", signature("affine2d"), function( + x, angle = NULL, x0 = NULL, y0 = NULL +) { + a <- get_args_list() + # remove from args list if not provided + if (is.null(x0)) a$x0 <- NULL + if (is.null(y0)) a$y0 <- NULL + # update linear + r <- radians(angle) + rotate_m <- matrix(c(cos(r), sin(r), -sin(r), cos(r)), nrow = 2L) + old_aff <- new_aff <- x@affine + .aff_linear_2d(new_aff) <- .aff_linear_2d(new_aff) %*% rotate_m + + ## calc shifts ## + # create dummy + d <- .bound_poly(x@anchor) + # perform transforms so far + a$x <- affine(d, old_aff) + # perform new transform + post <- do.call(spin, args = a) + + # perform affine & transform without shifts + b <- a + b$x0 <- b$y0 <- 0 + b$x <- affine(d, .aff_linear_2d(old_aff)) + pre <- do.call(spin, args = b) + + # find xyshift by comparing tfs so far vs new tf + xyshift <- .get_centroid_xy(post) - .get_centroid_xy(pre) + + # update translate + .aff_shift_2d(new_aff) <- xyshift + + x@affine <- new_aff + return(initialize(x)) +}) # internals #### diff --git a/man/affine.Rd b/man/affine.Rd index d45d3a5f..d0436f67 100644 --- a/man/affine.Rd +++ b/man/affine.Rd @@ -2,30 +2,36 @@ % Please edit documentation in R/methods-affine.R \name{affine} \alias{affine} -\alias{affine,SpatVector-method} -\alias{affine,giottoPoints-method} -\alias{affine,giottoPolygon-method} -\alias{affine,spatLocsObj-method} -\title{Apply an affine tranform} +\alias{affine,ANY,missing-method} +\alias{affine,ANY,affine2d-method} +\alias{affine,SpatVector,matrix-method} +\alias{affine,giottoPoints,matrix-method} +\alias{affine,giottoPolygon,matrix-method} +\alias{affine,spatLocsObj,matrix-method} +\title{Affine transformations} \usage{ -\S4method{affine}{SpatVector}(x, m, inv = FALSE, ...) +\S4method{affine}{ANY,missing}(x) -\S4method{affine}{giottoPoints}(x, m, inv = FALSE, ...) +\S4method{affine}{ANY,affine2d}(x, y, ...) -\S4method{affine}{giottoPolygon}(x, m, inv = FALSE, ...) +\S4method{affine}{SpatVector,matrix}(x, y, inv = FALSE, ...) -\S4method{affine}{spatLocsObj}(x, m, inv = FALSE, ...) +\S4method{affine}{giottoPoints,matrix}(x, y, inv = FALSE, ...) + +\S4method{affine}{giottoPolygon,matrix}(x, y, inv = FALSE, ...) + +\S4method{affine}{spatLocsObj,matrix}(x, y, inv = FALSE, ...) } \arguments{ \item{x}{object} -\item{m}{\code{matrix} or coercible to \code{matrix}. Should be a matrix with either -2 or 3 columns (linear or affine).} +\item{...}{additional args to pass (none implemented)} \item{inv}{logical. Whether the inverse of the affine transform should be applied.} -\item{...}{additional args to pass (none implemented)} +\item{m}{\code{matrix} or coercible to \code{matrix}. Should be a matrix with either +2 or 3 columns (linear or affine).} } \value{ affine transformed object diff --git a/man/decomp_affine.Rd b/man/decomp_affine.Rd index a8ab4f82..b50d0792 100644 --- a/man/decomp_affine.Rd +++ b/man/decomp_affine.Rd @@ -2,9 +2,10 @@ % Please edit documentation in R/methods-affine.R \name{decomp_affine} \alias{decomp_affine} +\alias{.decomp_affine} \title{Decompose affine matrix into scale, rotation, and shear operations} \usage{ -decomp_affine(x) +.decomp_affine(x) } \arguments{ \item{x}{object coercible to matrix with a 2x3 or 3x3 affine matrix} @@ -32,13 +33,13 @@ aff_m <- matrix(c( 100, 29, 1 ), nrow = 3, byrow = TRUE) -# show decomps +# create affine objects # values are shown in order of operations -decomp_affine(m) -decomp_affine(trans_m) -decomp_affine(scale_m) -s <- decomp_affine(shear_m) -a <- decomp_affine(aff_m) +affine(m) +affine(trans_m) +affine(scale_m) +s <- affine(shear_m) +a <- affine(aff_m) force(a) # perform piecewise transforms with decomp @@ -60,8 +61,5 @@ plot(sl_shear_piecewise) plot(affine(sl, aff_m)) plot(sl_aff_piecewise) -} -\seealso{ -\code{\link[=solve.affine_decomp]{solve.affine_decomp()}} } \keyword{internal} diff --git a/man/extract-methods.Rd b/man/extract-methods.Rd index dbe59b70..50c938c3 100644 --- a/man/extract-methods.Rd +++ b/man/extract-methods.Rd @@ -17,6 +17,7 @@ \alias{$<-,metaData-method} \alias{$,terraVectData-method} \alias{$<-,terraVectData-method} +\alias{$,affine2d-method} \alias{[,gdtData,gIndex,gIndex,missing-method} \alias{[,gdtData,logical,missing,missing-method} \alias{[,gdtData,character,missing,missing-method} @@ -84,6 +85,10 @@ \alias{[<-,giottoPolygon,missing,missing,ANY-method} \alias{[<-,giottoPolygon,missing,missing,} \alias{[<-,giottoPolygon,missing,missing-method} +\alias{[,affine2d,missing,missing,missing-method} +\alias{[<-,affine2d,missing,missing,ANY-method} +\alias{[<-,affine2d,missing,missing,} +\alias{[<-,affine2d,missing,missing-method} \title{Extract or replace parts of an object} \usage{ \S4method{$}{coordDataDT}(x, name) @@ -106,6 +111,8 @@ \S4method{$}{terraVectData}(x, name) <- value +\S4method{$}{affine2d}(x, name) + \S4method{[}{gdtData,gIndex,gIndex,missing}(x, i, j) \S4method{[}{gdtData,logical,missing,missing}(x, i, j) @@ -199,6 +206,10 @@ \S4method{[}{terraVectData,gIndex,gIndex,missing}(x, i, j) \S4method{[}{giottoPolygon,missing,missing,ANY}(x, i, j) <- value + +\S4method{[}{affine2d,missing,missing,missing}(x) + +\S4method{[}{affine2d,missing,missing,ANY}(x) <- value } \arguments{ \item{x}{Giotto S4 object to extract columns from} @@ -242,6 +253,9 @@ Select by colname from giotto S4 data.table metaDT slot. Select by colname from giotto S4 spatVector slot. + + +Select piecewise transform values from \code{affine2d} } \section{\code{`$<-`} methods}{ @@ -331,6 +345,9 @@ Assign to \code{spatVector} slot in giotto S4 Assign to \code{spatVector} slot in giottoPolygon + + +Assign to \code{affine} slot in affine2d } \examples{ diff --git a/man/plot-generic.Rd b/man/plot-generic.Rd index 5ee65fd0..4fd11dd5 100644 --- a/man/plot-generic.Rd +++ b/man/plot-generic.Rd @@ -10,6 +10,7 @@ \alias{plot,spatLocsObj,missing-method} \alias{plot,dimObj,missing-method} \alias{plot,spatialNetworkObj,missing-method} +\alias{plot,affine2d,missing-method} \title{Preview a Giotto spatial object} \usage{ \S4method{plot}{giottoImage,missing}(x, y, ...) @@ -43,6 +44,8 @@ \S4method{plot}{dimObj,missing}(x, dims = c(1, 2), ...) \S4method{plot}{spatialNetworkObj,missing}(x, y, ...) + +\S4method{plot}{affine2d,missing}(x, y, ...) } \arguments{ \item{x}{giotto image, giottoPolygon, or giottoPoints object} @@ -133,6 +136,8 @@ through \code{...} \item \code{plot(x = spatialNetworkObj, y = missing)}: Plot a spatialNetworkObj +\item \code{plot(x = affine2d, y = missing)}: Plot a affine2d. blue is start, red is end + }} \examples{ ######### giottoLargeImage plotting ######### diff --git a/man/print.affine_decomp.Rd b/man/print.affine_decomp.Rd deleted file mode 100644 index ba6f76b0..00000000 --- a/man/print.affine_decomp.Rd +++ /dev/null @@ -1,17 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/methods-affine.R -\name{print.affine_decomp} -\alias{print.affine_decomp} -\title{affine_decomp print method} -\usage{ -\method{print}{affine_decomp}(x, ...) -} -\arguments{ -\item{x}{object to print} - -\item{\dots}{additional params to pass (none implemented)} -} -\description{ -affine_decomp print method -} -\keyword{internal} diff --git a/man/rescale.Rd b/man/rescale.Rd index 0551e714..7f2f05cb 100644 --- a/man/rescale.Rd +++ b/man/rescale.Rd @@ -8,6 +8,7 @@ \alias{rescale,giottoPolygon-method} \alias{rescale,giottoPoints-method} \alias{rescale,giottoLargeImage-method} +\alias{rescale,affine2d-method} \title{Rescale an object} \usage{ \S4method{rescale}{giotto}( @@ -39,6 +40,8 @@ \S4method{rescale}{giottoPoints}(x, fx = 1, fy = fx, x0, y0) \S4method{rescale}{giottoLargeImage}(x, fx = 1, fy = fx, x0, y0) + +\S4method{rescale}{affine2d}(x, fx = 1, fy = fx, x0, y0) } \arguments{ \item{x}{object} diff --git a/man/shear.Rd b/man/shear.Rd index a5bcd455..2a3b4e55 100644 --- a/man/shear.Rd +++ b/man/shear.Rd @@ -2,7 +2,20 @@ % Please edit documentation in R/methods-shear.R \name{shear} \alias{shear} +\alias{shear,spatLocsObj-method} +\alias{shear,SpatVector-method} +\alias{shear,giottoPoints-method} +\alias{shear,giottoPolygon-method} \title{Apply a shear tranform} +\usage{ +\S4method{shear}{spatLocsObj}(x, fx = 0, fy = 0, x0, y0, ...) + +\S4method{shear}{SpatVector}(x, fx = 0, fy = 0, x0, y0, ...) + +\S4method{shear}{giottoPoints}(x, fx = 0, fy = 0, x0, y0, ...) + +\S4method{shear}{giottoPolygon}(x, fx = 0, fy = 0, x0, y0, ...) +} \arguments{ \item{x}{object} diff --git a/man/show-methods.Rd b/man/show-methods.Rd index 9e357790..22d76430 100644 --- a/man/show-methods.Rd +++ b/man/show-methods.Rd @@ -12,6 +12,7 @@ \alias{show,spatEnrObj-method} \alias{show,giottoImage-method} \alias{show,giottoLargeImage-method} +\alias{show,affine2d-method} \title{show method for giotto class} \usage{ \S4method{show}{giotto}(object) @@ -33,6 +34,8 @@ \S4method{show}{giottoImage}(object) \S4method{show}{giottoLargeImage}(object) + +\S4method{show}{affine2d}(object) } \arguments{ \item{object}{giottoLargeImage object} diff --git a/man/solve.affine_decomp.Rd b/man/solve.affine_decomp.Rd deleted file mode 100644 index 1d463d2f..00000000 --- a/man/solve.affine_decomp.Rd +++ /dev/null @@ -1,42 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/methods-affine.R -\name{solve.affine_decomp} -\alias{solve.affine_decomp} -\title{Solve for inverted 2D affine decomp} -\usage{ -\method{solve}{affine_decomp}(a, b, ...) -} -\arguments{ -\item{a}{\code{affine_decomp} object} - -\item{b}{not used} - -\item{\dots}{additional params to pass (none implemented)} -} -\description{ -Solve for inverted 2D affine decomp -} -\examples{ -sl <- GiottoData::loadSubObjectMini("spatLocsObj") - -m <- matrix(c( - 2, 0.5, 1000, - -0.3, 3, 20, - 100, 29, 1 -), nrow = 3, byrow = TRUE) - -a <- decomp_affine(m) -i <- solve(decomp) # inverted - -aff_sl <- affine(sl, aff_m) -inv_sl <- aff_sl \%>\% - spatShift(dx = i$translate[["x"]], dy = i$translate[["y"]]) \%>\% - spin(GiottoUtils::degrees(i$rotate), x0 = 0, y0 = 0) \%>\% - shear(fx = i$shear[["x"]], fy = i$shear[["y"]], x0 = 0, y0 = 0) \%>\% - rescale(fx = i$scale[["x"]], fy = i$scale[["y"]], x0 = 0, y0 = 0) - -plot(aff_sl) -plot(sl) -plot(inv_sl) # same as original - -} diff --git a/man/spatShift.Rd b/man/spatShift.Rd index 33222896..7014ea0d 100644 --- a/man/spatShift.Rd +++ b/man/spatShift.Rd @@ -11,6 +11,7 @@ \alias{spatShift,giottoPoints-method} \alias{spatShift,giottoLargeImage-method} \alias{spatShift,giottoImage-method} +\alias{spatShift,affine2d-method} \title{Spatially shift an object} \usage{ \S4method{spatShift}{giotto}( @@ -45,6 +46,8 @@ \S4method{spatShift}{giottoLargeImage}(x, dx = 0, dy = 0, copy_obj = FALSE, ...) \S4method{spatShift}{giottoImage}(x, dx = 0, dy = 0, ...) + +\S4method{spatShift}{affine2d}(x, dx = 0, dy = 0, ...) } \arguments{ \item{x}{object} diff --git a/man/spin.Rd b/man/spin.Rd index db7ff1c1..748fea53 100644 --- a/man/spin.Rd +++ b/man/spin.Rd @@ -7,6 +7,7 @@ \alias{spin,giottoPoints-method} \alias{spin,spatLocsObj-method} \alias{spin,data.frame-method} +\alias{spin,affine2d-method} \title{Spin an object} \usage{ \S4method{spin}{giotto}(x, angle, x0 = NULL, y0 = NULL, spat_unit = ":all:", feat_type = ":all:") @@ -37,6 +38,8 @@ xz_angle = NULL, geom = c("sdimx", "sdimy", "sdimz") ) + +\S4method{spin}{affine2d}(x, angle = NULL, x0 = NULL, y0 = NULL) } \arguments{ \item{x}{object} From 5159eb474485e4b6ecf5486d1b87520f4fe4c282 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 18 Jun 2024 12:22:19 -0400 Subject: [PATCH 031/160] chore: typo --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 0cc27f4c..72d30444 100644 --- a/NEWS.md +++ b/NEWS.md @@ -18,7 +18,7 @@ - `initialize()`, `[`, `$`, `show()`, `plot()` methods for `affine2d` - `.get_centroid_xy()` internal for getting numeric centroid xy values of any object that responds to `ext()` - `.bound_poly()` internal for generating a dummy polygon from the extent of any object that responds to `ext()` -- `.aff_shift_2d()`, `.aff_shift_2d<-()`, `.aff_linear_2d`, `.aff_linear_2d()` internals for accessing and manipulating affine matrices +- `.aff_shift_2d()`, `.aff_shift_2d<-()`, `.aff_linear_2d`, `.aff_linear_2d()<-` internals for accessing and manipulating affine matrices # GiottoClass 0.3.1 (2024/05/21) From dca1d4cdb4f9bc4de3c5fdee548439fd26153635 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 18 Jun 2024 12:28:32 -0400 Subject: [PATCH 032/160] chore: typo --- R/create.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/create.R b/R/create.R index 97354d8c..c71f0689 100644 --- a/R/create.R +++ b/R/create.R @@ -3198,7 +3198,7 @@ createGiottoLargeImage <- function(raster_object, image_path = raster_object ) } else { - stop("raster_object needs to be a'SpatRaster' object from the + stop("raster_object needs to be a 'SpatRaster' object from the terra package or \n an existing path that can be read by terra::rast()") } From 2ca1dafb52c4356cdd8c9b51e39db441f151a127 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:41:24 -0400 Subject: [PATCH 033/160] chore: change internal function naming --- R/methods-show.R | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/R/methods-show.R b/R/methods-show.R index 5e2d5f1f..59433ac3 100644 --- a/R/methods-show.R +++ b/R/methods-show.R @@ -164,7 +164,7 @@ setMethod( #' @rdname show-methods setMethod( f = "show", signature("exprObj"), function(object) { - show_class_and_name(object) + .show_class_and_name(object) # print spat/feat and provenance info show_spat_and_feat(object) @@ -261,7 +261,7 @@ setMethod("show", signature("featMetaObj"), function(object) { #' @rdname show-methods setMethod( f = "show", signature("dimObj"), function(object) { - show_class_and_name(object) + .show_class_and_name(object) if (!is.null(object@reduction_method)) { cat( "--| Contains dimension reduction generated with:", @@ -305,7 +305,7 @@ setMethod( #' @rdname show-methods setMethod( f = "show", signature("nnNetObj"), function(object) { - show_class_and_name(object) + .show_class_and_name(object) if (!is.null(object@nn_type)) { cat( "--| Contains nearest neighbor network generated with:", @@ -348,7 +348,7 @@ setMethod( #' @docType methods #' @rdname show-methods setMethod("show", signature("spatLocsObj"), function(object) { - show_class_and_name(object) + .show_class_and_name(object) show_spat(object) show_prov(object) @@ -391,7 +391,7 @@ setMethod("show", signature("spatLocsObj"), function(object) { #' @rdname show-methods setMethod( f = "show", signature("spatialNetworkObj"), function(object) { - show_class_and_name(object) + .show_class_and_name(object) if (!is.na(object@method)) { cat("Contains spatial network generated with:", object@method, "\n") } @@ -434,7 +434,7 @@ setMethod( # define for data.table x_start <- x_end <- y_start <- y_end <- z_start <- z_end <- NULL - show_class_and_name(object) + .show_class_and_name(object) cat('Contains annotations for spatial unit: "', slot(object, "spat_unit"), '"', sep = "" @@ -521,7 +521,7 @@ setMethod( #' @rdname show-methods setMethod( f = "show", signature("spatEnrObj"), function(object) { - show_class_and_name(object) + .show_class_and_name(object) show_spat_and_feat(object) show_prov(object) @@ -752,7 +752,7 @@ setMethod( 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) + .show_class_and_name(object) cat("Image extent :", show_ext(object)) cat("Original image extent :", show_ext(object@overall_extent)) cat( @@ -822,7 +822,7 @@ setMethod("as.character", signature("giottoLargeImage"), function(x, ...) { # show helpers #### #' @noRd -show_class_and_name <- function(object) { +.show_class_and_name <- function(object) { cat("An object of class ", class(object), ' : \"', objName(object), '\"\n', sep = "" From d5fa0a7f827fbe21492c5dedac85bee92d2c6034 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:43:34 -0400 Subject: [PATCH 034/160] chore: change internal fn naming --- R/methods-show.R | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/R/methods-show.R b/R/methods-show.R index 59433ac3..397827b2 100644 --- a/R/methods-show.R +++ b/R/methods-show.R @@ -167,8 +167,8 @@ setMethod( .show_class_and_name(object) # print spat/feat and provenance info - show_spat_and_feat(object) - show_prov(object) + .show_spat_and_feat(object) + .show_prov(object) cat("\ncontains:\n") # preview matrix @@ -224,8 +224,8 @@ setMethod( ## cellMetaObj #### setMethod("show", signature("cellMetaObj"), function(object) { cat("An object of class", class(object), "\n") - show_spat_and_feat(object) - show_prov(object) + .show_spat_and_feat(object) + .show_prov(object) cat("\n") if (!is.null(object[])) print(head(object[], 3L)) }) @@ -236,8 +236,8 @@ setMethod("show", signature("cellMetaObj"), function(object) { ## featMetaObj #### setMethod("show", signature("featMetaObj"), function(object) { cat("An object of class", class(object), "\n") - show_spat_and_feat(object) - show_prov(object) + .show_spat_and_feat(object) + .show_prov(object) cat("\n") if (!is.null(object[])) print(head(object[], 3L)) }) @@ -349,8 +349,8 @@ setMethod( #' @rdname show-methods setMethod("show", signature("spatLocsObj"), function(object) { .show_class_and_name(object) - show_spat(object) - show_prov(object) + .show_spat(object) + .show_prov(object) cat(" ------------------------\n\npreview:\n") if (!is.null(slot(object, "coordinates"))) { @@ -395,8 +395,8 @@ setMethod( if (!is.na(object@method)) { cat("Contains spatial network generated with:", object@method, "\n") } - show_spat(object) - show_prov(object) + .show_spat(object) + .show_prov(object) if (!is.null(object@networkDT)) { cat(" ", nrow(object@networkDT), "connections (filtered)\n") @@ -522,8 +522,8 @@ setMethod( setMethod( f = "show", signature("spatEnrObj"), function(object) { .show_class_and_name(object) - show_spat_and_feat(object) - show_prov(object) + .show_spat_and_feat(object) + .show_prov(object) cat(" ------------------------\n\npreview:\n") if (!is.null(slot(object, "enrichDT"))) { @@ -567,7 +567,7 @@ setMethod( ## giottoPolygon #### setMethod("show", signature = "giottoPolygon", function(object) { cat("An object of class giottoPolygon\n") - show_spat(object) + .show_spat(object) cat("Spatial Information:\n") print(object@spatVector) @@ -619,7 +619,7 @@ setMethod( ## giottoPoints #### setMethod("show", signature = "giottoPoints", function(object) { cat("An object of class giottoPoints\n") - show_feat(object) + .show_feat(object) cat("Feature Information:\n") print(object@spatVector) @@ -753,8 +753,8 @@ setMethod( 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("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" @@ -830,32 +830,32 @@ setMethod("as.character", signature("giottoLargeImage"), function(x, ...) { } #' @noRd -show_spat_and_feat <- function(object) { - show_spat(object) - show_feat(object) +.show_spat_and_feat <- function(object) { + .show_spat(object) + .show_feat(object) # cat(paste0('for spatial unit: "', spatUnit(object), # '" and feature type: "', featType(object),'" \n')) } #' @noRd -show_spat <- function(object) { +.show_spat <- function(object) { cat(paste0('spat_unit : "', spatUnit(object), '\"\n')) } #' @noRd -show_feat <- function(object) { +.show_feat <- function(object) { cat(paste0('feat_type : "', featType(object), '\"\n')) } #' @noRd -show_prov <- function(object) { +.show_prov <- function(object) { if (!is.null(object@provenance)) { cat("provenance:", object@provenance, "\n") } } #' @noRd -show_ext <- function(object) { +.show_ext <- function(object) { paste0( paste0(ext(object)[], collapse = (", ")), " (xmin, xmax, ymin, ymax)\n" From 1fc640fdb8818e7421ec82c60319cfbf2d78f91a Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:44:21 -0400 Subject: [PATCH 035/160] chore: move some code around --- R/classes.R | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/R/classes.R b/R/classes.R index a27071d2..4a0ef381 100644 --- a/R/classes.R +++ b/R/classes.R @@ -307,6 +307,30 @@ terraVectData <- setClass( +# UTILITY #### + +setClass( + Class = "affine2d", + slots = list( + anchor = "ANY", + affine = "matrix", + order = "character", + rotate = "numeric", + shear = "numeric", + scale = "numeric", + translate = "numeric" + ), + prototype = list( + anchor = c(-180, 180, -90, 90), + affine = diag(rep(1, 2L)), + order = c("rotate", "shear", "scale", "translate"), + rotate = 0, + shear = c(0, 0), + scale = c(1, 1), + translate = c(0, 0) + ) +) + # SUBCLASSES #### From 064bae51f733c3cd2fe6cc6e587c1edd659b3717 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:41:24 -0400 Subject: [PATCH 036/160] chore: move some code around chore: change internal function naming chore: change internal fn naming --- R/classes.R | 24 ++++++++++++++++++ R/methods-show.R | 64 ++++++++++++++++++++++++------------------------ 2 files changed, 56 insertions(+), 32 deletions(-) diff --git a/R/classes.R b/R/classes.R index a27071d2..4a0ef381 100644 --- a/R/classes.R +++ b/R/classes.R @@ -307,6 +307,30 @@ terraVectData <- setClass( +# UTILITY #### + +setClass( + Class = "affine2d", + slots = list( + anchor = "ANY", + affine = "matrix", + order = "character", + rotate = "numeric", + shear = "numeric", + scale = "numeric", + translate = "numeric" + ), + prototype = list( + anchor = c(-180, 180, -90, 90), + affine = diag(rep(1, 2L)), + order = c("rotate", "shear", "scale", "translate"), + rotate = 0, + shear = c(0, 0), + scale = c(1, 1), + translate = c(0, 0) + ) +) + # SUBCLASSES #### diff --git a/R/methods-show.R b/R/methods-show.R index 5e2d5f1f..397827b2 100644 --- a/R/methods-show.R +++ b/R/methods-show.R @@ -164,11 +164,11 @@ setMethod( #' @rdname show-methods setMethod( f = "show", signature("exprObj"), function(object) { - show_class_and_name(object) + .show_class_and_name(object) # print spat/feat and provenance info - show_spat_and_feat(object) - show_prov(object) + .show_spat_and_feat(object) + .show_prov(object) cat("\ncontains:\n") # preview matrix @@ -224,8 +224,8 @@ setMethod( ## cellMetaObj #### setMethod("show", signature("cellMetaObj"), function(object) { cat("An object of class", class(object), "\n") - show_spat_and_feat(object) - show_prov(object) + .show_spat_and_feat(object) + .show_prov(object) cat("\n") if (!is.null(object[])) print(head(object[], 3L)) }) @@ -236,8 +236,8 @@ setMethod("show", signature("cellMetaObj"), function(object) { ## featMetaObj #### setMethod("show", signature("featMetaObj"), function(object) { cat("An object of class", class(object), "\n") - show_spat_and_feat(object) - show_prov(object) + .show_spat_and_feat(object) + .show_prov(object) cat("\n") if (!is.null(object[])) print(head(object[], 3L)) }) @@ -261,7 +261,7 @@ setMethod("show", signature("featMetaObj"), function(object) { #' @rdname show-methods setMethod( f = "show", signature("dimObj"), function(object) { - show_class_and_name(object) + .show_class_and_name(object) if (!is.null(object@reduction_method)) { cat( "--| Contains dimension reduction generated with:", @@ -305,7 +305,7 @@ setMethod( #' @rdname show-methods setMethod( f = "show", signature("nnNetObj"), function(object) { - show_class_and_name(object) + .show_class_and_name(object) if (!is.null(object@nn_type)) { cat( "--| Contains nearest neighbor network generated with:", @@ -348,9 +348,9 @@ setMethod( #' @docType methods #' @rdname show-methods setMethod("show", signature("spatLocsObj"), function(object) { - show_class_and_name(object) - show_spat(object) - show_prov(object) + .show_class_and_name(object) + .show_spat(object) + .show_prov(object) cat(" ------------------------\n\npreview:\n") if (!is.null(slot(object, "coordinates"))) { @@ -391,12 +391,12 @@ setMethod("show", signature("spatLocsObj"), function(object) { #' @rdname show-methods setMethod( f = "show", signature("spatialNetworkObj"), function(object) { - show_class_and_name(object) + .show_class_and_name(object) if (!is.na(object@method)) { cat("Contains spatial network generated with:", object@method, "\n") } - show_spat(object) - show_prov(object) + .show_spat(object) + .show_prov(object) if (!is.null(object@networkDT)) { cat(" ", nrow(object@networkDT), "connections (filtered)\n") @@ -434,7 +434,7 @@ setMethod( # define for data.table x_start <- x_end <- y_start <- y_end <- z_start <- z_end <- NULL - show_class_and_name(object) + .show_class_and_name(object) cat('Contains annotations for spatial unit: "', slot(object, "spat_unit"), '"', sep = "" @@ -521,9 +521,9 @@ setMethod( #' @rdname show-methods setMethod( f = "show", signature("spatEnrObj"), function(object) { - show_class_and_name(object) - show_spat_and_feat(object) - show_prov(object) + .show_class_and_name(object) + .show_spat_and_feat(object) + .show_prov(object) cat(" ------------------------\n\npreview:\n") if (!is.null(slot(object, "enrichDT"))) { @@ -567,7 +567,7 @@ setMethod( ## giottoPolygon #### setMethod("show", signature = "giottoPolygon", function(object) { cat("An object of class giottoPolygon\n") - show_spat(object) + .show_spat(object) cat("Spatial Information:\n") print(object@spatVector) @@ -619,7 +619,7 @@ setMethod( ## giottoPoints #### setMethod("show", signature = "giottoPoints", function(object) { cat("An object of class giottoPoints\n") - show_feat(object) + .show_feat(object) cat("Feature Information:\n") print(object@spatVector) @@ -752,9 +752,9 @@ setMethod( 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)) + .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" @@ -822,7 +822,7 @@ setMethod("as.character", signature("giottoLargeImage"), function(x, ...) { # show helpers #### #' @noRd -show_class_and_name <- function(object) { +.show_class_and_name <- function(object) { cat("An object of class ", class(object), ' : \"', objName(object), '\"\n', sep = "" @@ -830,32 +830,32 @@ show_class_and_name <- function(object) { } #' @noRd -show_spat_and_feat <- function(object) { - show_spat(object) - show_feat(object) +.show_spat_and_feat <- function(object) { + .show_spat(object) + .show_feat(object) # cat(paste0('for spatial unit: "', spatUnit(object), # '" and feature type: "', featType(object),'" \n')) } #' @noRd -show_spat <- function(object) { +.show_spat <- function(object) { cat(paste0('spat_unit : "', spatUnit(object), '\"\n')) } #' @noRd -show_feat <- function(object) { +.show_feat <- function(object) { cat(paste0('feat_type : "', featType(object), '\"\n')) } #' @noRd -show_prov <- function(object) { +.show_prov <- function(object) { if (!is.null(object@provenance)) { cat("provenance:", object@provenance, "\n") } } #' @noRd -show_ext <- function(object) { +.show_ext <- function(object) { paste0( paste0(ext(object)[], collapse = (", ")), " (xmin, xmax, ymin, ymax)\n" From 2499c09ee3a3171a1282595f6c43e685e88effb1 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:44:38 -0400 Subject: [PATCH 037/160] feat: `giottoAffineImage` class --- R/classes.R | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/R/classes.R b/R/classes.R index 4a0ef381..4ba6f619 100644 --- a/R/classes.R +++ b/R/classes.R @@ -1654,34 +1654,18 @@ giottoLargeImage <- setClass( ) ) - - - setClass( - Class = "affine2d", - slots = list( - anchor = "ANY", - affine = "matrix", - order = "character", - rotate = "numeric", - shear = "numeric", - scale = "numeric", - translate = "numeric" - ), - prototype = list( - anchor = c(-180, 180, -90, 90), - affine = diag(rep(1, 2L)), - order = c("rotate", "shear", "scale", "translate"), - rotate = 0, - shear = c(0, 0), - scale = c(1, 1), - translate = c(0, 0) + "giottoAffineImage", + contains = c("giottoLargeImage"), + slots = c( + affine = "affine2d" ) ) + # function for updating image objects if structure definitions have changed .update_giotto_image <- function(x) { if (inherits(x, "giottoLargeImage")) { From 080a29e68af498fb54cdb7f9701c4e8bb2306361 Mon Sep 17 00:00:00 2001 From: iqraAmin Date: Tue, 25 Jun 2024 16:59:20 -0400 Subject: [PATCH 038/160] Updates in Seurat Interoperability Functions --- R/interoperability.R | 252 +++++++++++++++++++++++++++++-------------- 1 file changed, 172 insertions(+), 80 deletions(-) diff --git a/R/interoperability.R b/R/interoperability.R index 74466136..5fe5bbed 100644 --- a/R/interoperability.R +++ b/R/interoperability.R @@ -22,7 +22,10 @@ #' @returns giotto object #' @export -gefToGiotto <- function(gef_file, bin_size = "bin100", verbose = FALSE, +gefToGiotto <- function( + gef_file, + bin_size = "bin100", + verbose = FALSE, h5_file = NULL) { # data.table vars genes <- gene_idx <- x <- y <- sdimx <- sdimy <- cell_ID <- bin_ID <- @@ -165,7 +168,7 @@ check_py_for_scanpy <- function() { #' neighbors(). If multiple spatial networks are in the anndata object, a list #' of key_added terms may be provided. If converting an anndata object from #' giottoToAnnData, a .txt file may be provided, which was generated in that -#' function, i.e. {spat_unit}_{feat_type}_nn_network_keys_added.txt. Cannot +#' function, i.e. \{spat_unit\}_\{feat_type\}_nn_network_keys_added.txt. Cannot #' be "spatial". This becomes the name of the nearest network in the gobject. #' @param spatial_n_key_added equivalent of "key_added" argument from #' squidpy.gr.spatial_neighbors. If multiple spatial networks are in the @@ -175,9 +178,9 @@ check_py_for_scanpy <- function() { #' i.e. {spat_unit}_{feat_type}_spatial_network_keys_added.txt #' Cannot be the same as n_key_added. #' @param delaunay_spat_net binary parameter for spatial network. If TRUE, the -#' spatial network is a delaunay network. -#' @param spat_unit desired spatial unit for conversion, default NULL -#' @param feat_type desired feature type for conversion, default NULL +#' spatial network is a deluanay network. +#' @param spat_unit desired spatial unit to use for conversion, default NULL +#' @param feat_type desired feature type to use for conversion, default NULL #' @param h5_file name to create and on-disk HDF5 file #' @param python_path path to python executable within a conda/miniconda #' environment @@ -1456,6 +1459,7 @@ giottoToSeuratV4 <- function( #' The default values are 'cell' and 'rna' respectively. #' @param gobject Giotto object #' @param spat_unit spatial unit (e.g. 'cell') +#' @param res_type type of 10x image output resolution #' @param ... additional params to pass to \code{\link{get_spatial_locations}} #' @returns Seurat object #' @keywords seurat interoperability @@ -1463,10 +1467,13 @@ giottoToSeuratV4 <- function( giottoToSeuratV5 <- function( gobject, spat_unit = NULL, + res_type = c("hires", "lowres", "fullres"), ...) { # data.table vars feat_type <- name <- dim_type <- nn_type <- NULL + res_type <- match.arg(res_type, choices = c("hires", "lowres", "fullres")) + # set default spat_unit and feat_type to be extracted as a Seurat assay spat_unit <- set_default_spat_unit( gobject = gobject, @@ -1686,15 +1693,20 @@ giottoToSeuratV5 <- function( } # spatial coordinates - loc_use <- data.table::setDF( - get_spatial_locations( + loc_use <- getSpatialLocations( gobject = gobject, spat_unit = spat_unit, + output = "spatLocsObj", output = "data.table", copy_obj = TRUE, ... # allow setting of spat_loc_name through additional params ) - ) + + # flip y vals + + loc_use <- flip(loc_use)[] %>% + data.table::setDF() + rownames(loc_use) <- loc_use$cell_ID sobj <- Seurat::AddMetaData(sobj, metadata = loc_use) # add spatial coordinates as new dim reduct object @@ -1740,26 +1752,37 @@ giottoToSeuratV5 <- function( all_x <- NULL all_y <- NULL - if (length(gobject@largeImages) > 0) { - for (i in seq_along(gobject@largeImages)) { - # spatVec <- terra::as.points( - # gobject@largeImages[[i]]@raster_object) - # geomSpatVec <- terra::geom(spatVec) - # x <- geomSpatVec[,"x"] - # y <- geomSpatVec[,"y"] - imagerow <- gobject@spatial_locs$cell$raw$sdimy - imagecol <- gobject@spatial_locs$cell$raw$sdimx - img <- terra::as.array(gobject@largeImages[[i]]@raster_object) - img[, , seq_len(3)] <- img[, , seq_len(3)] / 255 - coord <- data.frame(imagerow = imagerow, imagecol = imagecol) - + gimgs <- getGiottoImage(gobject, name = ":all:") + if (length(gimgs) > 0) { + for (i in seq_along(gimgs)) { + gimg <- gimgs[[i]] + key <- objName(gimg) + imagerow <- loc_use$sdimy + imagecol <- loc_use$sdimx + img_array <- as(gimg, "array") + img_array <- img_array / 255 + coord <- data.frame( + imagerow = imagerow, imagecol = imagecol, + row.names = loc_use$cell_ID + ) + scalef <- .estimate_scalefactors( + gimg, + res_type = res_type, + spatlocs = loc_use + ) + # There does not seem to be a way to tell seurat which image type + # you are using. The lowres scalefactor seems to be the important + # one in mapping the image scalefactors <- Seurat::scalefactors( - spot = gobject@largeImages[[i]]@scale_factor, - fiducial = gobject@largeImages[[i]]@resolution, - hires = max(img), - lowres = min(img) - ) - + spot = scalef$spot, + fiducial = scalef$fiducial, + hires = scalef$hires, + lowres = scalef[res_type] # this looks like the main one + # so instead of strictly supplying lowres scalef, we use + # the scalef belonging to whichever image was used in Giotto + # since we allow use non-lowres images + ) + # see https://github.com/satijalab/seurat/issues/3595 newV1 <- new( Class = "VisiumV1", image = img, @@ -1776,7 +1799,73 @@ giottoToSeuratV5 <- function( return(sobj) } - +#' @param x image object +#' @param res_type type of 10x image output resolution +#' @param spatlocs a data.frame of spatial locations coordinates +#' @noRd + +.estimate_scalefactors <- function( + x, + res_type = c("hires", "lowres", "fullres"), + spatlocs + ){ + res_type <- match.arg(res_type, + choices = c("hires", "lowres", "fullres")) + pxdims <- dim(x)[1:2] + edims <- range(ext(x)) + scalef <- mean(pxdims / edims) +# assume that lowres and hires follow a general ratio +# may not be that important since the scalefactor should theoretically +# only matter for the image res that we are using +# this ratio is roughly 3.333334 based on Visium BreastCancerA1 dataset + res_ratio <- 3.333334 + # fullres should have a scalef of roughly 1. + # No way to guess hires or lowres scalefs so use arbitrary values. + hres_scalef <- switch(res_type, + "hires" = scalef, + "lowres" = scalef * res_ratio, + "fullres" = 0.08250825 # arbitrary + + ) + lres_scalef <- switch(res_type, + "hires" = scalef / res_ratio, + "lowres" = scalef, + "fullres" = 0.02475247 # arbitrary + ) +# spot diameter and fid diameter are variable based on how spatial info was +# mapped to the image. Estimate this by getting the center to center + # px distance vs fullsize px dims ratio. + # ! fullsize px dims is the same as edims ! + coords <- data.table::as.data.table(spatlocs) + # create a delaunay + dnet <- createNetwork( + as.matrix(coords[, c("sdimx", "sdimy")]), + type = "delaunay", + method = "geometry", + include_distance = TRUE, + as.igraph = FALSE, + include_weight = TRUE, + verbose = FALSE + ) + + # expect center to center be most common edge distance + # this gives CC dist as fullres px distance + distances <- sort(unique(dnet$distance)) + cc_px <- distances[which.max(table(dnet$distance))] + # assume constant ratios between diameters and cc_px + fid_cc_ratio <- 1.045909 +fid_diam <- cc_px * fid_cc_ratio +spot_cc_ratio <- 0.6474675 +spot_diam <- cc_px * spot_cc_ratio +scalef_list <- list( + spot = spot_diam, + fiducial = fid_diam, + hires = hres_scalef, + lowres = lres_scalef + ) +return(scalef_list) + + } #' @title Deprecated @@ -1857,9 +1946,10 @@ seuratToGiottoV4 <- function( # Cell Metadata cell_metadata <- sobject@meta.data # Dimension Reduction - if (sum(sapply( + if (sum(vapply( dim_reduction, - function(x) length(sobject@reductions[[x]]) + function(x) length(sobject@reductions[[x]], + FUN.VALUE = integer(1L)) )) == 0) { dimReduc_list <- NULL } else { @@ -2096,7 +2186,10 @@ seuratToGiottoV5 <- function( nn_network = NULL, verbose = TRUE) { package_check("Seurat") - + + # NSE vars + sdimy <- NULL + if (is.null(Seurat::GetAssayData( object = sobject, slot = "counts", assay = spatial_assay @@ -2134,13 +2227,20 @@ seuratToGiottoV5 <- function( # Cell Metadata cell_metadata <- sobject@meta.data + cell_metadata <- data.table::as.data.table( + cell_metadata, keep.rownames = TRUE) + # Feat Metadata feat_metadata <- sobject[[]] - + feat_metadata <- data.table::as.data.table( + feat_metadata, keep.rownames = TRUE) + + # Dimension Reduction - if (sum(sapply( + if (sum(vapply( dim_reduction, - function(x) length(sobject@reductions[[x]]) + function(x) length(sobject@reductions[[x]], + FUN.VALUE = integer(1L)) )) == 0) { dimReduc_list <- NULL } else { @@ -2188,35 +2288,34 @@ seuratToGiottoV5 <- function( object = sobject, assay = spatial_assay ))) { - spat_coord <- Seurat::GetTissueCoordinates(sobject) + spat_coord <- Seurat::GetTissueCoordinates(sobject, + scale = NULL, + cols = c( + "imagerow", + "imagecol")) # spat_coord = cbind(rownames(spat_coord), # data.frame(spat_coord, row.names=NULL)) if (!("cell" %in% spat_coord)) { spat_coord$cell_ID <- rownames(spat_coord) - colnames(spat_coord) <- c("sdimx", "sdimy", "cell_ID") + colnames(spat_coord) <- c("sdimy", "sdimx", "cell_ID") } else { - colnames(spat_coord) <- c("sdimx", "sdimy", "cell_ID") + colnames(spat_coord) <- c("sdimy", "sdimx", "cell_ID") } - spat_loc <- spat_coord + spat_loc <- data.table::as.data.table(spat_coord) length_assay <- length(colnames(sobject)) - - spat_datatable <- data.table( - cell_ID = character(length_assay), - sdimx = rep(NA_real_, length_assay), - sdimy = rep(NA_real_, length_assay) - ) - - spat_datatable$cell_ID <- colnames(sobject) - match_cell_ID <- match(spat_loc$cell_ID, spat_datatable$cell_ID) - matching_indices <- match_cell_ID - matching_indices <- matching_indices[!is.na(matching_indices)] - spat_datatable[ - matching_indices, - c("sdimx", "sdimy") := list(spat_loc$sdimx, spat_loc$sdimy) - ] - spat_loc <- spat_datatable +# seurat has coords following imaging conventions + # flip them for Giotto + spat_loc[, sdimy := -sdimy] + data.table::setcolorder( + spat_loc, + neworder = c("sdimx", + "sdimy", + "cell_ID" + ) + ) + } else { message("Images for RNA assay not found in the data. Skipping image processing.") @@ -2295,30 +2394,19 @@ seuratToGiottoV5 <- function( } } - # Find SueratImages, extract them, and pass to create seuratobj + # Find SueratImages, extract them, and pass to create image for (i in names(sobject@images)) { + simg <- sobject[[i]] # check if image slot has image in it - if ("image" %in% slotNames(sobject@images[[i]])) { - if (!is.null(sobject@images[[i]]@image)) { - # Extract the red (r), green (g), and blue (b) channels - r <- as.matrix(sobject@images[[i]]@image[, , 1]) - g <- as.matrix(sobject@images[[i]]@image[, , 2]) - b <- as.matrix(sobject@images[[i]]@image[, , 3]) - - r <- round(r * 255) - g <- round(g * 255) - b <- round(b * 255) - - # Convert channels to rasters - r <- terra::rast(r) - g <- terra::rast(g) - b <- terra::rast(b) - - # Create Giotto LargeImage + if ("image" %in% slotNames(simg)) { + img_array <- slot(simg, "image") + if (!is.null(img_array)) { + scalef <- Seurat::ScaleFactors(simg) gImg <- createGiottoLargeImage( - raster_object = terra::rast(list(r, g, b)), - name = names(sobject@images) + raster_object = terra::rast(img_array) * 255, + name = i, + scale_factor = 1 / scalef$lowres ) } } @@ -2436,25 +2524,29 @@ seuratToGiottoV5 <- function( ) } } - gobject <- addCellMetadata(gobject = gobject, new_metadata = cell_metadata) - gobject <- addFeatMetadata(gobject = gobject, new_metadata = feat_metadata) - + gobject <- addCellMetadata( + gobject = gobject, new_metadata = cell_metadata, + by_column = TRUE, column_cell_ID = "rn") + + gobject <- addFeatMetadata( + gobject = gobject, new_metadata = feat_metadata, + by_column = TRUE, column_feat_ID = "rn") - if (exists("gpoints") == TRUE) { + if (exists("gpoints")) { gobject <- addGiottoPoints( gobject = gobject, gpoints = list(gpoints) ) } - if (exists("gpolygon") == TRUE) { + if (exists("gpolygon")) { gobject <- addGiottoPolygons( gobject = gobject, gpolygons = polygon_list ) } - if (exists("gImg") == TRUE) { + if (exists("gImg")) { gobject <- addGiottoLargeImage( gobject = gobject, largeImages = list(gImg) From ff473251ee863efb8e5a7cfe3bec51fca66bb450 Mon Sep 17 00:00:00 2001 From: iqraAmin Date: Tue, 25 Jun 2024 16:59:20 -0400 Subject: [PATCH 039/160] Updates in Seurat Interoperability Functions --- R/interoperability.R | 273 +++++++++++++++++++++++++++++-------------- 1 file changed, 186 insertions(+), 87 deletions(-) diff --git a/R/interoperability.R b/R/interoperability.R index 74466136..60f4f7e6 100644 --- a/R/interoperability.R +++ b/R/interoperability.R @@ -22,7 +22,10 @@ #' @returns giotto object #' @export -gefToGiotto <- function(gef_file, bin_size = "bin100", verbose = FALSE, +gefToGiotto <- function( + gef_file, + bin_size = "bin100", + verbose = FALSE, h5_file = NULL) { # data.table vars genes <- gene_idx <- x <- y <- sdimx <- sdimy <- cell_ID <- bin_ID <- @@ -165,7 +168,7 @@ check_py_for_scanpy <- function() { #' neighbors(). If multiple spatial networks are in the anndata object, a list #' of key_added terms may be provided. If converting an anndata object from #' giottoToAnnData, a .txt file may be provided, which was generated in that -#' function, i.e. {spat_unit}_{feat_type}_nn_network_keys_added.txt. Cannot +#' function, i.e. \{spat_unit\}_\{feat_type\}_nn_network_keys_added.txt. Cannot #' be "spatial". This becomes the name of the nearest network in the gobject. #' @param spatial_n_key_added equivalent of "key_added" argument from #' squidpy.gr.spatial_neighbors. If multiple spatial networks are in the @@ -175,9 +178,9 @@ check_py_for_scanpy <- function() { #' i.e. {spat_unit}_{feat_type}_spatial_network_keys_added.txt #' Cannot be the same as n_key_added. #' @param delaunay_spat_net binary parameter for spatial network. If TRUE, the -#' spatial network is a delaunay network. -#' @param spat_unit desired spatial unit for conversion, default NULL -#' @param feat_type desired feature type for conversion, default NULL +#' spatial network is a deluanay network. +#' @param spat_unit desired spatial unit to use for conversion, default NULL +#' @param feat_type desired feature type to use for conversion, default NULL #' @param h5_file name to create and on-disk HDF5 file #' @param python_path path to python executable within a conda/miniconda #' environment @@ -1456,6 +1459,7 @@ giottoToSeuratV4 <- function( #' The default values are 'cell' and 'rna' respectively. #' @param gobject Giotto object #' @param spat_unit spatial unit (e.g. 'cell') +#' @param res_type type of 10x image output resolution #' @param ... additional params to pass to \code{\link{get_spatial_locations}} #' @returns Seurat object #' @keywords seurat interoperability @@ -1463,10 +1467,13 @@ giottoToSeuratV4 <- function( giottoToSeuratV5 <- function( gobject, spat_unit = NULL, + res_type = c("hires", "lowres", "fullres"), ...) { # data.table vars feat_type <- name <- dim_type <- nn_type <- NULL + res_type <- match.arg(res_type, choices = c("hires", "lowres", "fullres")) + # set default spat_unit and feat_type to be extracted as a Seurat assay spat_unit <- set_default_spat_unit( gobject = gobject, @@ -1686,15 +1693,20 @@ giottoToSeuratV5 <- function( } # spatial coordinates - loc_use <- data.table::setDF( - get_spatial_locations( + loc_use <- getSpatialLocations( gobject = gobject, spat_unit = spat_unit, + output = "spatLocsObj", output = "data.table", copy_obj = TRUE, ... # allow setting of spat_loc_name through additional params ) - ) + + # flip y vals + + loc_use <- flip(loc_use)[] %>% + data.table::setDF() + rownames(loc_use) <- loc_use$cell_ID sobj <- Seurat::AddMetaData(sobj, metadata = loc_use) # add spatial coordinates as new dim reduct object @@ -1740,34 +1752,48 @@ giottoToSeuratV5 <- function( all_x <- NULL all_y <- NULL - if (length(gobject@largeImages) > 0) { - for (i in seq_along(gobject@largeImages)) { - # spatVec <- terra::as.points( - # gobject@largeImages[[i]]@raster_object) - # geomSpatVec <- terra::geom(spatVec) - # x <- geomSpatVec[,"x"] - # y <- geomSpatVec[,"y"] - imagerow <- gobject@spatial_locs$cell$raw$sdimy - imagecol <- gobject@spatial_locs$cell$raw$sdimx - img <- terra::as.array(gobject@largeImages[[i]]@raster_object) - img[, , seq_len(3)] <- img[, , seq_len(3)] / 255 - coord <- data.frame(imagerow = imagerow, imagecol = imagecol) - + gimgs <- getGiottoImage(gobject, name = ":all:") + if (length(gimgs) > 0) { + for (i in seq_along(gimgs)) { + gimg <- gimgs[[i]] + key <- objName(gimg) + imagerow <- loc_use$sdimy + imagecol <- loc_use$sdimx + img_array <- as(gimg, "array") + img_array <- img_array / 255 + coord <- data.frame( + imagerow = imagerow, imagecol = imagecol, + row.names = loc_use$cell_ID + ) + scalef <- .estimate_scalefactors( + gimg, + res_type = res_type, + spatlocs = loc_use + ) + # There does not seem to be a way to tell seurat which image type + # you are using. The lowres scalefactor seems to be the important + # one in mapping the image scalefactors <- Seurat::scalefactors( - spot = gobject@largeImages[[i]]@scale_factor, - fiducial = gobject@largeImages[[i]]@resolution, - hires = max(img), - lowres = min(img) - ) - + spot = scalef$spot, + fiducial = scalef$fiducial, + hires = scalef$hires, + lowres = scalef[res_type] # this looks like the main one + # so instead of strictly supplying lowres scalef, we use + # the scalef belonging to whichever image was used in Giotto + # since we allow use non-lowres images + ) + # see https://github.com/satijalab/seurat/issues/3595 newV1 <- new( Class = "VisiumV1", - image = img, + image = img_array, scale.factors = scalefactors, - coordinates = coord + coordinates = coord, + spot.radius = + scalef$fiducial * scalef$lowres / max(dim(img_array)), + key = paste0(key, "_") ) - sobj@images[[gobject@largeImages[[i]]@name]] <- newV1 + sobj@images[[key]] <- newV1 } } @@ -1776,7 +1802,73 @@ giottoToSeuratV5 <- function( return(sobj) } - +#' @param x image object +#' @param res_type type of 10x image output resolution +#' @param spatlocs a data.frame of spatial locations coordinates +#' @noRd + +.estimate_scalefactors <- function( + x, + res_type = c("hires", "lowres", "fullres"), + spatlocs + ){ + res_type <- match.arg(res_type, + choices = c("hires", "lowres", "fullres")) + pxdims <- dim(x)[1:2] + edims <- range(ext(x)) + scalef <- mean(pxdims / edims) +# assume that lowres and hires follow a general ratio +# may not be that important since the scalefactor should theoretically +# only matter for the image res that we are using +# this ratio is roughly 3.333334 based on Visium BreastCancerA1 dataset + res_ratio <- 3.333334 + # fullres should have a scalef of roughly 1. + # No way to guess hires or lowres scalefs so use arbitrary values. + hres_scalef <- switch(res_type, + "hires" = scalef, + "lowres" = scalef * res_ratio, + "fullres" = 0.08250825 # arbitrary + + ) + lres_scalef <- switch(res_type, + "hires" = scalef / res_ratio, + "lowres" = scalef, + "fullres" = 0.02475247 # arbitrary + ) +# spot diameter and fid diameter are variable based on how spatial info was +# mapped to the image. Estimate this by getting the center to center + # px distance vs fullsize px dims ratio. + # ! fullsize px dims is the same as edims ! + coords <- data.table::as.data.table(spatlocs) + # create a delaunay + dnet <- createNetwork( + as.matrix(coords[, c("sdimx", "sdimy")]), + type = "delaunay", + method = "geometry", + include_distance = TRUE, + as.igraph = FALSE, + include_weight = TRUE, + verbose = FALSE + ) + + # expect center to center be most common edge distance + # this gives CC dist as fullres px distance + distances <- sort(unique(dnet$distance)) + cc_px <- distances[which.max(table(dnet$distance))] + # assume constant ratios between diameters and cc_px + fid_cc_ratio <- 1.045909 +fid_diam <- cc_px * fid_cc_ratio +spot_cc_ratio <- 0.6474675 +spot_diam <- cc_px * spot_cc_ratio +scalef_list <- list( + spot = spot_diam, + fiducial = fid_diam, + hires = hres_scalef, + lowres = lres_scalef + ) +return(scalef_list) + + } #' @title Deprecated @@ -1821,6 +1913,11 @@ seuratToGiotto <- function( #' @returns A Giotto object converted from Seurat object with all computations #' stored in it. #' @keywords seurat interoperability +#' @examples +#' m_expression <- Matrix::Matrix(rnorm(100), nrow = 10, sparse = TRUE) +#' s <- Seurat::CreateSeuratObject(counts = m_expression) +#' +#' seuratToGiottoV5(s, spatial_assay = "RNA") #' @export seuratToGiottoV4 <- function( sobject, @@ -1857,9 +1954,10 @@ seuratToGiottoV4 <- function( # Cell Metadata cell_metadata <- sobject@meta.data # Dimension Reduction - if (sum(sapply( + if (sum(vapply( dim_reduction, - function(x) length(sobject@reductions[[x]]) + function(x) length(sobject@reductions[[x]]), + FUN.VALUE = integer(1L) )) == 0) { dimReduc_list <- NULL } else { @@ -2096,7 +2194,10 @@ seuratToGiottoV5 <- function( nn_network = NULL, verbose = TRUE) { package_check("Seurat") - + + # NSE vars + sdimy <- NULL + if (is.null(Seurat::GetAssayData( object = sobject, slot = "counts", assay = spatial_assay @@ -2134,13 +2235,20 @@ seuratToGiottoV5 <- function( # Cell Metadata cell_metadata <- sobject@meta.data + cell_metadata <- data.table::as.data.table( + cell_metadata, keep.rownames = TRUE) + # Feat Metadata feat_metadata <- sobject[[]] - + feat_metadata <- data.table::as.data.table( + feat_metadata, keep.rownames = TRUE) + + # rownames of both kept as `rn` # Dimension Reduction - if (sum(sapply( + if (sum(vapply( dim_reduction, - function(x) length(sobject@reductions[[x]]) + function(x) length(sobject@reductions[[x]]), + FUN.VALUE = integer(1L) )) == 0) { dimReduc_list <- NULL } else { @@ -2188,35 +2296,33 @@ seuratToGiottoV5 <- function( object = sobject, assay = spatial_assay ))) { - spat_coord <- Seurat::GetTissueCoordinates(sobject) - # spat_coord = cbind(rownames(spat_coord), - # data.frame(spat_coord, row.names=NULL)) + spat_coord <- Seurat::GetTissueCoordinates( + sobject, + scale = NULL, + cols = c( + "imagerow", + "imagecol")) if (!("cell" %in% spat_coord)) { spat_coord$cell_ID <- rownames(spat_coord) - colnames(spat_coord) <- c("sdimx", "sdimy", "cell_ID") + colnames(spat_coord) <- c("sdimy", "sdimx", "cell_ID") } else { - colnames(spat_coord) <- c("sdimx", "sdimy", "cell_ID") + colnames(spat_coord) <- c("sdimy", "sdimx", "cell_ID") } - spat_loc <- spat_coord - length_assay <- length(colnames(sobject)) - - spat_datatable <- data.table( - cell_ID = character(length_assay), - sdimx = rep(NA_real_, length_assay), - sdimy = rep(NA_real_, length_assay) - ) - - spat_datatable$cell_ID <- colnames(sobject) - match_cell_ID <- match(spat_loc$cell_ID, spat_datatable$cell_ID) - matching_indices <- match_cell_ID - matching_indices <- matching_indices[!is.na(matching_indices)] - spat_datatable[ - matching_indices, - c("sdimx", "sdimy") := list(spat_loc$sdimx, spat_loc$sdimy) - ] - spat_loc <- spat_datatable + spat_loc <- data.table::as.data.table(spat_coord) + + # seurat has coords following imaging conventions + # flip them for Giotto + spat_loc[, sdimy := -sdimy] + data.table::setcolorder( + spat_loc, + neworder = c("sdimx", + "sdimy", + "cell_ID" + ) + ) + } else { message("Images for RNA assay not found in the data. Skipping image processing.") @@ -2295,30 +2401,19 @@ seuratToGiottoV5 <- function( } } - # Find SueratImages, extract them, and pass to create seuratobj + # Find SueratImages, extract them, and pass to create image for (i in names(sobject@images)) { + simg <- sobject[[i]] # check if image slot has image in it - if ("image" %in% slotNames(sobject@images[[i]])) { - if (!is.null(sobject@images[[i]]@image)) { - # Extract the red (r), green (g), and blue (b) channels - r <- as.matrix(sobject@images[[i]]@image[, , 1]) - g <- as.matrix(sobject@images[[i]]@image[, , 2]) - b <- as.matrix(sobject@images[[i]]@image[, , 3]) - - r <- round(r * 255) - g <- round(g * 255) - b <- round(b * 255) - - # Convert channels to rasters - r <- terra::rast(r) - g <- terra::rast(g) - b <- terra::rast(b) - - # Create Giotto LargeImage + if ("image" %in% slotNames(simg)) { + img_array <- slot(simg, "image") + if (!is.null(img_array)) { + scalef <- Seurat::ScaleFactors(simg) gImg <- createGiottoLargeImage( - raster_object = terra::rast(list(r, g, b)), - name = names(sobject@images) + raster_object = terra::rast(img_array) * 255, + name = i, + scale_factor = 1 / scalef$lowres ) } } @@ -2436,25 +2531,29 @@ seuratToGiottoV5 <- function( ) } } - gobject <- addCellMetadata(gobject = gobject, new_metadata = cell_metadata) - gobject <- addFeatMetadata(gobject = gobject, new_metadata = feat_metadata) - + gobject <- addCellMetadata( + gobject = gobject, new_metadata = cell_metadata, + by_column = TRUE, column_cell_ID = "rn") + + gobject <- addFeatMetadata( + gobject = gobject, new_metadata = feat_metadata, + by_column = TRUE, column_feat_ID = "rn") - if (exists("gpoints") == TRUE) { + if (exists("gpoints")) { gobject <- addGiottoPoints( gobject = gobject, gpoints = list(gpoints) ) } - if (exists("gpolygon") == TRUE) { + if (exists("gpolygon")) { gobject <- addGiottoPolygons( gobject = gobject, gpolygons = polygon_list ) } - if (exists("gImg") == TRUE) { + if (exists("gImg")) { gobject <- addGiottoLargeImage( gobject = gobject, largeImages = list(gImg) @@ -2618,7 +2717,7 @@ giottoToSpatialExperiment <- function(giottoObj, verbose = TRUE) { ) } SpatialExperiment::spatialCoords(spe) <- data.matrix( - spatialLocs[, seq_len(2)] + spatialLocs[, seq_len(2)] ) } else { if (verbose) { From 256f1a6b23dc5cbaa597472ba96fa0c5e31a386d Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:09:11 -0400 Subject: [PATCH 040/160] !feat: `giottoImage` class definition change --- NEWS.md | 1 + R/classes.R | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 72d30444..f7177d4d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,7 @@ ## breaking changes - python environment installation and how it relates to default settings such as .condarc may have changed. +- `giottoImage` `name` slot now requires `character` and will not accept `NULL` ## enhancements - `verbose` param for `createNearestNetwork()` diff --git a/R/classes.R b/R/classes.R index 4ba6f619..e92bde59 100644 --- a/R/classes.R +++ b/R/classes.R @@ -1563,7 +1563,7 @@ featureNetwork <- setClass( giottoImage <- setClass( Class = "giottoImage", slots = c( - name = "ANY", + name = "character", mg_object = "ANY", minmax = "ANY", boundaries = "ANY", @@ -1573,7 +1573,7 @@ giottoImage <- setClass( OS_platform = "ANY" ), prototype = list( - name = NULL, + name = "test", mg_object = NULL, minmax = NULL, boundaries = NULL, From e73b47884bf74be20c02df16ee8f0ea49da05306 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:10:22 -0400 Subject: [PATCH 041/160] chore: `giottoLargeImage` docs --- R/classes.R | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/R/classes.R b/R/classes.R index e92bde59..2654a799 100644 --- a/R/classes.R +++ b/R/classes.R @@ -1596,11 +1596,15 @@ giottoImage <- setClass( # giottoLargeImage class #' @title S4 giottoLargeImage Class -#' @description class to handle images too large to load in normally through -#' magick +#' @description Image class for Giotto that uses \pkg{terra} `SpatRaster` as +#' a backend. If images are loaded from a file on disk then they are worked +#' with lazily, where only the values needed at any moment are loaded/sampled +#' into memory. Since `SpatRaster` objects are C pointers, `giottoLargeImage` +#' and inheriting classes need to run `reconnect()` after loading from a +#' saved object. #' @concept giotto object image #' @slot name name of large Giotto image -#' @slot raster_object terra raster object +#' @slot raster_object terra `SpatRaster` object #' @slot extent tracks the extent of the raster object. Note that most #' processes should rely on the extent of the raster object instead of this. #' @slot overall_extent terra extent object covering the original extent of From 1d554179e6daea2b40d28a47db9a9b9756f81c2d Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:11:35 -0400 Subject: [PATCH 042/160] feat: `giottoAffineImage` class Class extending `giottoLargeImage` that allows for delayed affine transforms. * This class hierarchy or at least the naming of `giottoLargeImage` is still intended to be changed in the future --- R/classes.R | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/R/classes.R b/R/classes.R index 2654a799..9cbe4612 100644 --- a/R/classes.R +++ b/R/classes.R @@ -1658,11 +1658,22 @@ giottoLargeImage <- setClass( ) ) +#' @title S4 giottoAffineImage Class +#' @description +#' Class extending `giottoLargeImage`. When `shear()` or `spin()` operations +#' are performed on +#' +#' +#' @slot affine contains `affine2d` object allowing lazily performed spatial +#' transforms +#' @slot funs list of functions associated with the object. Primarily to +#' perform the delayed/lazy operations setClass( "giottoAffineImage", contains = c("giottoLargeImage"), slots = c( - affine = "affine2d" + affine = "affine2d", + funs = "list" ) ) From 1013cd75dac3d70c45008b0df9dcf454085df389 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:16:30 -0400 Subject: [PATCH 043/160] change: refactor `createGiottoLargeImage` and add `initialize()` method for this image class Create `initialize()` method for `giottoLargeImage` and offload some things that are done in `createGiottoLargeImage()` into it. --- NEWS.md | 1 + R/create.R | 64 ++---------------------------------------- R/methods-initialize.R | 46 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 61 deletions(-) diff --git a/NEWS.md b/NEWS.md index f7177d4d..eaad125e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -16,6 +16,7 @@ - `shear()` for `giottoPoints`, `giottoPolygon`, `spatLocsObj`, `affine2d` - `affine2d` class for accumulating linear transforms to be used with `affine()` - `spin()`, `rescale`, `spatShift()` methods for `affine2d` +- `initialize()`, method for `giottoLargeImage` - `initialize()`, `[`, `$`, `show()`, `plot()` methods for `affine2d` - `.get_centroid_xy()` internal for getting numeric centroid xy values of any object that responds to `ext()` - `.bound_poly()` internal for generating a dummy polygon from the extent of any object that responds to `ext()` diff --git a/R/create.R b/R/create.R index c71f0689..f82ac3fd 100644 --- a/R/create.R +++ b/R/create.R @@ -3179,15 +3179,7 @@ createGiottoLargeImage <- function(raster_object, scale_factor = 1, verbose = TRUE) { # create minimum giotto - g_imageL <- new("giottoLargeImage", - name = name, - raster_object = NULL, - overall_extent = NULL, - scale_factor = NULL, - resolution = NULL, - file_path = NULL, - OS_platform = .Platform[["OS.type"]] - ) + g_imageL <- new("giottoLargeImage", name = name) ## 1. check raster object and load as SpatRaster if necessary @@ -3288,61 +3280,11 @@ createGiottoLargeImage <- function(raster_object, raster_object <- terra::flip(raster_object, direction = "horizontal") } - - ## 3. Assign raster_object to giottoLargeImage g_imageL@raster_object <- raster_object - ## 4. scale factor and resolution values - g_imageL@resolution <- terra::res(g_imageL@raster_object) # (x,y) - names(g_imageL@resolution) <- c("x", "y") - g_imageL@scale_factor <- (1 / g_imageL@resolution) - - - - - - - ## 5. Get image characteristics by sampling - sample_values <- .spatraster_sample_values(raster_object, - size = 5000, - verbose = verbose - ) - - if (nrow(sample_values) == 0) { - if (verbose == TRUE) { - wrap_msg("No values discovered when sampling for image - characteristics") - } - } else { - # 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 <- .spatraster_is_int( - raster_object = raster_object, - sample_values = sample_values - ) - g_imageL@is_int <- is_int - } - - - - ## 6. extent object - g_imageL@extent <- g_imageL@overall_extent <- as.vector( - terra::ext(raster_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) + ## 4. return image object + return(initialize(g_imageL)) } diff --git a/R/methods-initialize.R b/R/methods-initialize.R index c97b73f0..324580fe 100644 --- a/R/methods-initialize.R +++ b/R/methods-initialize.R @@ -583,6 +583,52 @@ setMethod("initialize", "affine2d", function(.Object, ...) { return(.Object) }) +## giottoLargeImage #### +setMethod("initialize", signature("giottoLargeImage"), function(.Object, ...) { + .Object <- methods::callNextMethod() + + # defaults + .Object@OS_platform <- .Object@OS_platform %null% .Platform[["OS.type"]] + objName(.Object) <- objName(.Object) %null% "image" + + r <- .Object@raster_object + if (is.null(r)) return(.Object) # return early if NULL + + # scale factor and res + .Object@resolution <- terra::res(r) + names(.Object@resolution) <- c("x", "y") + .Object@scale_factor <- 1 / .Object@resolution + + # sample for image characteristics + svals <- .spatraster_sample_values(r, size = 5000, verbose = FALSE) + + if (nrow(svals) != 0) { + intensity_range <- .spatraster_intensity_range( + raster_object = r, + sample_values = svals + ) + } + .Object@min_intensity <- intensity_range[["min"]] + .Object@max_intensity <- intensity_range[["max"]] + + # find out if image is int or floating pt + is_int <- .spatraster_is_int( + raster_object = r, + sample_values = svals + ) + .Object@is_int <- is_int + + # extent + .Object@extent <- as.vector(terra::ext(r)) + .Object@overall_extent <- .Object@overall_extent %null% + as.vector(terra::ext(r)) + + # max window + .Object@max_window <- .Object@max_window %na% + .bitdepth(.Object@max_intensity, return_max = TRUE) + + return(.Object) +}) From 381fe4384febebdc99a86fc52d4e0d29de116d22 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:17:45 -0400 Subject: [PATCH 044/160] feat: `.magick_image_corners()` internal - create a spatLocsObj of 3 corner pixel locations from a magick object input. - used to help with calculation of control coordinates for affine distorts --- R/giotto_structures.R | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/R/giotto_structures.R b/R/giotto_structures.R index ebadbbdf..8867f2b9 100644 --- a/R/giotto_structures.R +++ b/R/giotto_structures.R @@ -180,7 +180,20 @@ return(res) } - +# create a spatLocsObj of 3 corner pixel locations from a magick object input. +# used to help with calculation of control coordinates for affine distorts +.magick_image_corners <- function(x) { + checkmate::assert_class(x, "magick-image") + im_info <- magick::image_info(x) + spatLocsObj( + name = "mg_ctrl_coords", + coordinates = data.table::data.table( + cell_ID = letters[seq_len(3)], + sdimx = c(0.5, 0.5, im_info$width - 0.5), + sdimy = c(0.5, im_info$height - 0.5, 0.5) + ) + ) +} From fa15d341d27d66b464d972d923a8ba4e25b3196f Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:18:48 -0400 Subject: [PATCH 045/160] feat: `.magick_preview()` internal - save a magick image to disk and return the filepath - can be loaded in with terra or used with `getOption("viewer")()` downstream - based on `magick:::image_preview()` - accepts a single `magick-image` object --- R/images.R | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/R/images.R b/R/images.R index af9a8a46..36c0637a 100644 --- a/R/images.R +++ b/R/images.R @@ -276,7 +276,19 @@ get_adj_rescale_img <- function(img_minmax, )) } - +# save a magick image to disk and return the filepath +# can be loaded in with terra or used with getOption("viewer")() downstream +# based on magick:::image_preview() +# accepts a single `magick-image` object +.magick_preview <- function(x, tempname = "preview") { + stopifnot(inherits(x, "magick-image")) + stopifnot(length(x) == 1L) + format <- tolower(magick::image_info(x[1])$format) + tmp <- file.path(tempdir(), paste0(tempname, format, collapse = ".")) + vmsg(.is_debug = TRUE, "`.magick_preview()` saving as", format) + image_write(x, path = tmp, format = format) + return(tmp) +} #' @title addGiottoImageMG #' @name addGiottoImageMG From f4f4b9c92895ea75fc573a6b81fcbf9792ad9f5b Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:19:31 -0400 Subject: [PATCH 046/160] feat: coerce `giottoLargeImage` to `giottoAffineImage`` --- R/methods-coerce.R | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/R/methods-coerce.R b/R/methods-coerce.R index 2e5e652e..28e3223c 100644 --- a/R/methods-coerce.R +++ b/R/methods-coerce.R @@ -174,6 +174,14 @@ methods::setAs("giottoLargeImage", "giottoImage", function(from) { return(mImg) }) +methods::setAs("giottoLargeImage", "giottoAffineImage", function(from) { + attr(from, "affine") <- new("affine2d") + attr(from, "funs") <- list() + attr(from, "class") <- "giottoAffineImage" + + initialize(from) +}) + # TODO redo this as `as.array`. # Careful: There are already usages of this `as()` method in the code methods::setAs("giottoLargeImage", "array", function(from) { From 4b4cb462c02f5d91e86815aee5b7d92a1a5053d2 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:21:41 -0400 Subject: [PATCH 047/160] chore: update NEWS --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index eaad125e..57b5d7a4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -16,6 +16,8 @@ - `shear()` for `giottoPoints`, `giottoPolygon`, `spatLocsObj`, `affine2d` - `affine2d` class for accumulating linear transforms to be used with `affine()` - `spin()`, `rescale`, `spatShift()` methods for `affine2d` +- `giottoAffineImage` class for just-in-time affine transformed images +- `as()` conversion from `giottoLargeImage` to `giottoAffineImage` - `initialize()`, method for `giottoLargeImage` - `initialize()`, `[`, `$`, `show()`, `plot()` methods for `affine2d` - `.get_centroid_xy()` internal for getting numeric centroid xy values of any object that responds to `ext()` From 4e271dc3d6071a3caa006263b48f6abb10fc1086 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:22:49 -0400 Subject: [PATCH 048/160] feat: `ext()` for `giottoAffineImage` --- R/methods-ext.R | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/R/methods-ext.R b/R/methods-ext.R index 90b35b5d..db06044d 100644 --- a/R/methods-ext.R +++ b/R/methods-ext.R @@ -227,7 +227,11 @@ setMethod("ext", signature("giotto"), function(x, return(e) }) - +#' @rdname ext +#' @export +setMethod("ext", signature("giottoAffineImage"), function(x, ...) { + ext(x@extent) +}) From 6e49a79f10237779600473080ad869b6c529fd58 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:23:49 -0400 Subject: [PATCH 049/160] enh: make `show()` for `giottoLargeImage` more flexible for inheriting classes --- R/methods-show.R | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/R/methods-show.R b/R/methods-show.R index 397827b2..0c479779 100644 --- a/R/methods-show.R +++ b/R/methods-show.R @@ -745,7 +745,7 @@ setMethod( signature = "giottoLargeImage", definition = function(object) { if (is.null(object@raster_object)) { - cat("NULL giottoLargeImage") + cat("NULL", class(object)) } else { e <- ext(object) img_dim <- dim(object)[c(2, 1, 3)] # x, y, layers @@ -780,7 +780,6 @@ setMethod( - #' @rdname show-methods setMethod("show", signature("affine2d"), function(object) { cat("\n") From cdd9dcf7dd6967a4f4ab3a07fa804cddc84dad96 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:24:48 -0400 Subject: [PATCH 050/160] chore: formatting --- R/methods-initialize.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/methods-initialize.R b/R/methods-initialize.R index 324580fe..4f9a7d34 100644 --- a/R/methods-initialize.R +++ b/R/methods-initialize.R @@ -566,7 +566,7 @@ setMethod( ) -## transform_plan_2d +## affine2d #### setMethod("initialize", "affine2d", function(.Object, ...) { .Object <- methods::callNextMethod() .Object@anchor <- ext(.Object@anchor) %>% From dbeb4a2ec42741771a7cd3b70fc6c9cd69c6957a Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:25:41 -0400 Subject: [PATCH 051/160] feat: `initialize()` for `giottoAffineImage` --- R/methods-initialize.R | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/R/methods-initialize.R b/R/methods-initialize.R index 4f9a7d34..cd4e1f3d 100644 --- a/R/methods-initialize.R +++ b/R/methods-initialize.R @@ -630,9 +630,44 @@ setMethod("initialize", signature("giottoLargeImage"), function(.Object, ...) { return(.Object) }) - - - +## giottoAffineImage #### +setMethod("initialize", signature("giottoAffineImage"), function(.Object, ...) { + .Object <- methods::callNextMethod() + + # default name + if (is.null(objName(.Object))) { + objName(.Object) <- "test" + } + + # append associated functions + + + r <- .Object@raster_object + if (!is.null(r)) { + # apply the image extent as anchor for affine object plotting + .Object@affine@anchor <- ext(r) + .Object@affine <- initialize(.Object@affine) + + # compute & set extent slot as a numeric vector + d <- .bound_poly(r) %>% + affine(.Object@affine) + .Object@extent <- .ext_to_num_vec(ext(d)) + } + + .Object@funs$realize_magick <- function(tempname = "preview", size = 5e5) { + mg <- .gaffine_realize_magick(.Object, size = size) + gimg <- .magick_preview(mg@mg_object, tempname = tempname) %>% + createGiottoLargeImage() + ext(gimg) <- ext(.Object) + return(gimg) + # TODO things to be implemented for this pipeline: + # col (the trip the magick-image flattened the image without applying col) + # max_intensity same as above + # the above options are also stripped when the fresh largeImage is created + } + + return(.Object) +}) From 270c1d78225a5c2ba83428b4e85213b3462462b7 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:26:35 -0400 Subject: [PATCH 052/160] chore: formatting --- R/methods-affine.R | 2 ++ 1 file changed, 2 insertions(+) diff --git a/R/methods-affine.R b/R/methods-affine.R index 45e326ab..d86ec737 100644 --- a/R/methods-affine.R +++ b/R/methods-affine.R @@ -297,6 +297,8 @@ setMethod( ) } +## affine matrix manipulation #### +# internal accessors for the relevant parts of 2D affine matrices .aff_linear_2d <- function(x) { if (inherits(x, "affine2d")) x <- x[] x[][seq(2), seq(2)] From d133a2947f47303489bfc7c73386694437f50696 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:29:06 -0400 Subject: [PATCH 053/160] feat: `spin()` methods for gaImage --- R/methods-spin.R | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/R/methods-spin.R b/R/methods-spin.R index 9f49efb4..8c227a15 100644 --- a/R/methods-spin.R +++ b/R/methods-spin.R @@ -206,6 +206,31 @@ setMethod( } ) + +#' @rdname spin +#' @export +setMethod("spin", signature("giottoLargeImage"), function( + x, angle = NULL, x0 = NULL, y0 = NULL, ... +) { + a <- get_args_list(...) + a$x <- as(x, "giottoAffineImage") # convert to giottoAffineImage + res <- do.call(spin, args = a) + return(res) +}) + +#' @rdname spin +#' @export +setMethod("spin", signature("giottoAffineImage"), function( + x, angle = NULL, x0 = NULL, y0 = NULL, ... +) { + a <- get_args_list(...) + a$x <- x@affine + # update affine + x@affine <- do.call(spin, args = a) + + return(initialize(x)) +}) + #' @rdname spin #' @export setMethod("spin", signature("affine2d"), function( From 7b2b7bff62526601684856507d745b1ef4d0cffe Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:29:25 -0400 Subject: [PATCH 054/160] feat: spatShift() for gaImage --- R/methods-spatShift.R | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/R/methods-spatShift.R b/R/methods-spatShift.R index 9a7c0884..25a0ca77 100644 --- a/R/methods-spatShift.R +++ b/R/methods-spatShift.R @@ -233,6 +233,14 @@ setMethod( } ) +#' @rdname spatShift +#' @export +setMethod("spatShift", signature("giottoAffineImage"), + function(x, dx = 0, dy = 0, ...) { + x@affine <- spatShift(x@affine, dx = dx, dy = dy, ...) + return(initialize(x)) + }) + #' @rdname spatShift #' @export setMethod( From 36bd3379a97a7e7bb6c262014a304a802a4d319b Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:29:51 -0400 Subject: [PATCH 055/160] feat: `shear()` for gaImage --- R/methods-shear.R | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/R/methods-shear.R b/R/methods-shear.R index 1e080019..05dfa671 100644 --- a/R/methods-shear.R +++ b/R/methods-shear.R @@ -70,7 +70,29 @@ setMethod("shear", signature("giottoPolygon"), function( .do_gpoly(x, what = .shear_sv, args = a) }) +#' @rdname shear +#' @export +setMethod("shear", signature("giottoLargeImage"), function( + x, fx = 0, fy = 0, x0, y0, ... +) { + a <- get_args_list(...) + a$x <- as(x, "giottoAffineImage") # convert to giottoAffineImage + res <- do.call(shear, args = a) + return(res) +}) +#' @rdname shear +#' @export +setMethod("shear", signature("giottoAffineImage"), function( + x, fx = 0, fy = 0, x0, y0, ... +) { + a <- get_args_list(...) + a$x <- x@affine + # update affine + x@affine <- do.call(shear, args = a) + + return(initialize(x)) +}) setMethod("shear", signature("affine2d"), function( x, fx = 0, fy = 0, x0, y0, ... From e9f57e78ae3c090512b12c183adbfdf0134f09f0 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:30:50 -0400 Subject: [PATCH 056/160] feat: `rescale()` for `giottoImage` --- R/methods-rescale.R | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/R/methods-rescale.R b/R/methods-rescale.R index 648d37d4..587d36e8 100644 --- a/R/methods-rescale.R +++ b/R/methods-rescale.R @@ -219,6 +219,17 @@ setMethod( } ) +#' @rdname rescale +#' @export +setMethod("rescale", signature("giottoImage"), function(x, fx = 1, fy = fx, x0, y0) { + a <- get_args_list() + d <- .bound_poly(x) + a$x <- d + d <- do.call(rescale, args = a) + ext(x) <- ext(d) + return(x) +}) + #' @rdname rescale #' @export setMethod("rescale", signature("giottoLargeImage"), function(x, fx = 1, fy = fx, x0, y0) { From dfcbd15929dbc23b6c023cb4d7f34778b1c1c0f0 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:03:32 -0400 Subject: [PATCH 057/160] feat: `affine()` for `affine2d` --- R/methods-affine.R | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/R/methods-affine.R b/R/methods-affine.R index d86ec737..ebd30915 100644 --- a/R/methods-affine.R +++ b/R/methods-affine.R @@ -99,6 +99,41 @@ setMethod( ) +#' @rdname affine +#' @export +setMethod("affine", signature(x = "affine2d", y = "matrix"), function( + x, y, inv = FALSE, ... +) { + a <- get_args_list() + # update linear + m <- .aff_linear_2d(y) + if (isTRUE(inv)) m <- solve(m) + old_aff <- new_aff <- x@affine + .aff_linear_2d(new_aff) <- .aff_linear_2d(new_aff) %*% m + + ## calc shifts ## + # create dummy + d <- .bound_poly(x@anchor) + # perform transforms so far + a$x <- affine(d, old_aff) + # perform new transform + post <- do.call(affine, args = a) + + # perform affine & transform without shifts + b <- a + b$y <- .aff_linear_2d(y) + b$x <- affine(d, .aff_linear_2d(old_aff)) + pre <- do.call(affine, args = b) + + # find xyshift by comparing tfs so far vs new tf + xyshift <- .get_centroid_xy(post) - .get_centroid_xy(pre) + + # update translate + .aff_shift_2d(new_aff) <- xyshift + + x@affine <- new_aff + return(initialize(x)) +}) # internals #### From a0b1489071bdda581d65d39ba76dbada66cfd162 Mon Sep 17 00:00:00 2001 From: Ruben Dries Date: Wed, 3 Jul 2024 10:32:07 -0400 Subject: [PATCH 058/160] update expression and dim_reduction getters --- R/slot_accessors.R | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/R/slot_accessors.R b/R/slot_accessors.R index ea6012ae..fe6d1555 100644 --- a/R/slot_accessors.R +++ b/R/slot_accessors.R @@ -1438,12 +1438,12 @@ getExpression <- function( feat_type = NULL, output = c("exprObj", "matrix"), set_defaults = TRUE) { - # 0. Check input + + + # 0. Check input assert_giotto(gobject) output <- match.arg(output, choices = c("exprObj", "matrix")) - - # 1. Set feat_type and spat_unit if (isTRUE(set_defaults)) { spat_unit <- set_default_spat_unit( @@ -1503,13 +1503,19 @@ get_expression_values <- function( gobject, spat_unit = NULL, feat_type = NULL, - values = NULL, + values = c('raw', 'normalized', 'scaled'), output = c("exprObj", "matrix"), set_defaults = TRUE) { deprecate_soft("3.3.0", "get_expression_values()", "getExpression()") assert_giotto(gobject) + ## check parameters + values <- match.arg( + arg = values, + choices = unique(c("raw", "normalized", "scaled", values)) + ) + output <- match.arg(output, choices = c("exprObj", "matrix")) # 1. Set feat_type and spat_unit @@ -1525,6 +1531,7 @@ get_expression_values <- function( ) } + # 2. Find object potential_values <- list_expression_names( gobject = gobject, From 7fa8de0f2b1d23991f91fae7041152a45f3dcd19 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:43:23 -0400 Subject: [PATCH 059/160] feat: `rescale()` for `giottoAffineImage` --- R/methods-rescale.R | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/R/methods-rescale.R b/R/methods-rescale.R index 587d36e8..553a5dbb 100644 --- a/R/methods-rescale.R +++ b/R/methods-rescale.R @@ -241,6 +241,18 @@ setMethod("rescale", signature("giottoLargeImage"), function(x, fx = 1, fy = fx, return(x) }) +#' @rdname rescale +#' @export +setMethod("rescale", signature("giottoAffineImage"), + function(x, fx = 1, fy = fx, x0, y0) { + a <- get_args_list() + a$x <- x@affine + # update affine + x@affine <- do.call(rescale, args = a) + + return(initialize(x)) +}) + #' @rdname rescale #' @export setMethod("rescale", signature("affine2d"), function(x, fx = 1, fy = fx, x0, y0) { From 9432ea2e1be7472c6bdd10ad8a62a09289ae4b61 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:44:10 -0400 Subject: [PATCH 060/160] feat: `crop()` for `giottoAffineImage` --- R/methods-crop.R | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/R/methods-crop.R b/R/methods-crop.R index e584d825..c00a445c 100644 --- a/R/methods-crop.R +++ b/R/methods-crop.R @@ -46,6 +46,19 @@ setMethod("crop", signature("giottoLargeImage"), function(x, y, ...) { x }) +# * giottoAffineImage #### +#' @rdname crop +#' @export +setMethod("crop", signature("giottoAffineImage"), function(x, y, ...) { + crop_ext <- ext(y) + d <- .bound_poly(crop_ext) + aff <- x@affine + img_crop_ext <- ext(affine(d, aff, inv = TRUE)) # find extent in img space + x@raster_object <- terra::crop(x@raster_object, img_crop_ext) + + return(initialize(x)) +}) + # * spatLocsObj #### #' @rdname crop #' @export From 8be4cd42259cb6f707756e03d9e23b52a8c8e665 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:44:57 -0400 Subject: [PATCH 061/160] feat: `affine()` for `giottoAffineImage` and `giottoLargeImage` --- R/methods-affine.R | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/R/methods-affine.R b/R/methods-affine.R index ebd30915..f333a85c 100644 --- a/R/methods-affine.R +++ b/R/methods-affine.R @@ -98,6 +98,29 @@ setMethod( } ) +#' @rdname affine +#' @export +setMethod("affine", signature(x = "giottoLargeImage", y = "matrix"), function( + x, y, inv = FALSE, ... +) { + a <- get_args_list(...) + a$x <- as(x, "giottoAffineImage") # convert to giottoAffineImage + res <- do.call(affine, args = a) + return(res) +}) + +#' @rdname affine +#' @export +setMethod("affine", signature(x = "giottoAffineImage", y = "matrix"), function( + x, y, inv = FALSE, ... +) { + a <- get_args_list(...) + aff <- x@affine + a$x <- aff + # update affine + x@affine <- do.call(affine, args = a) + return(x) +}) #' @rdname affine #' @export From 3a7c135936aa524823a434f82acdc0607cf96cc4 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:45:37 -0400 Subject: [PATCH 062/160] feat: magick affine deformation realization of delayed affine transforms --- R/methods-affine.R | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/R/methods-affine.R b/R/methods-affine.R index f333a85c..03aaf82c 100644 --- a/R/methods-affine.R +++ b/R/methods-affine.R @@ -215,6 +215,52 @@ setMethod("affine", signature(x = "affine2d", y = "matrix"), function( } +# perform the actual affine operation +.gaffine_realize_magick <- function(x, size = 5e5, ...) { + mg <- .spatraster_sample_values(x, output = "magick", size = size, ...) + aff <- x@affine + dummy_sl <- .magick_image_corners(mg) + aff_dummy_sl <- affine(dummy_sl, .aff_linear_2d(aff)) %>% + flip() + + .sl_to_mat <- function(x) { + x[][, c("sdimx", "sdimy")] %>% t() + } + + # convert spatlocs of dummy points to matrix + ctrl_pts_a <- .sl_to_mat(flip(dummy_sl)) + ctrl_pts_b <- .sl_to_mat(aff_dummy_sl) + + ctrl_pts <- c( + ctrl_pts_a[, 1], ctrl_pts_b[, 1], + ctrl_pts_a[, 2], ctrl_pts_b[, 2], + ctrl_pts_a[, 3], ctrl_pts_b[, 3] + ) + names(ctrl_pts) <- NULL + + mg_aff <- magick::image_distort( + mg, distortion = "Affine", coordinates = ctrl_pts, bestfit = TRUE + ) + + d <- .bound_poly(x) %>% + affine(aff) + + affine_gimg <- giottoImage( + name = paste(objName(x), "affine", collapse = "_"), + mg_object = mg_aff, + minmax = c(xmax_sloc = 10, xmin_sloc = 0, + ymax_sloc = 10, ymin_sloc = 0), + boundaries = c(xmax_adj = 0, xmin_adj = 0, + ymax_adj = 0, ymin_adj = 0) + ) + + # assign ext from dummy + ext(affine_gimg) <- ext(d) + + return(initialize(affine_gimg)) +} + + From f8400ee2d6e3c3aa007535aeb63cc9edb234b151 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:45:57 -0400 Subject: [PATCH 063/160] feat: `plot()` for gaImage --- R/methods-plot.R | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/R/methods-plot.R b/R/methods-plot.R index 54a93a13..9be6540b 100644 --- a/R/methods-plot.R +++ b/R/methods-plot.R @@ -86,6 +86,13 @@ setMethod( } ) +#' @rdname plot-generic +#' @export +setMethod("plot", signature(x = "giottoAffineImage", y = "missing"), + function(x, ...) { + .plot_giottoaffineimage(x, ...) + }) + #' @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 #' @param type what to plot: either 'poly' (default) or polygon 'centroid' @@ -530,7 +537,16 @@ setMethod("plot", signature(x = "affine2d", y = "missing"), function(x, ...) { } } - +.plot_giottoaffineimage <- function(x, maxcell = 5e5, ...) { + pargs <- get_args_list(...) + gimg <- x@funs$realize_magick() + pargs$x <- gimg + do.call(plot, args = pargs) + # TODO things to be implemented for this pipeline: + # col (the trip the magick-image flattened the image without applying col) + # max_intensity same as above + # the above options are also stripped when the fresh largeImage is created +} From 3d40ab827408de405b1fa0ec31d0d0d448372710 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:50:05 -0400 Subject: [PATCH 064/160] chore: update NEWS --- NEWS.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 57b5d7a4..fc6bf070 100644 --- a/NEWS.md +++ b/NEWS.md @@ -15,11 +15,14 @@ - `affine()` for `giottoPolygon`, `giottoPoints`, `spatLocsObj` - `shear()` for `giottoPoints`, `giottoPolygon`, `spatLocsObj`, `affine2d` - `affine2d` class for accumulating linear transforms to be used with `affine()` -- `spin()`, `rescale`, `spatShift()` methods for `affine2d` +- `spin()`, `rescale`, `spatShift()`, `affine()` methods for `affine2d` - `giottoAffineImage` class for just-in-time affine transformed images -- `as()` conversion from `giottoLargeImage` to `giottoAffineImage` - `initialize()`, method for `giottoLargeImage` - `initialize()`, `[`, `$`, `show()`, `plot()` methods for `affine2d` +- `initialize()`, `ext()`, `crop()`, `rescale()`, `spatShift()`, `plot()` methods for `giottoAffineImage` +- `rescale()` method for `giottoImage` +- `spin()`, `shear()`, `affine()` methods for `giottoAffineImage` and `giottoLargeImage` (which converts to `giottoAffineImage`) +- `as()` conversion from `giottoLargeImage` to `giottoAffineImage` - `.get_centroid_xy()` internal for getting numeric centroid xy values of any object that responds to `ext()` - `.bound_poly()` internal for generating a dummy polygon from the extent of any object that responds to `ext()` - `.aff_shift_2d()`, `.aff_shift_2d<-()`, `.aff_linear_2d`, `.aff_linear_2d()<-` internals for accessing and manipulating affine matrices From 8ee6c2ec1f247995bba10512dc1ed8b79fbf12be Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:50:56 -0400 Subject: [PATCH 065/160] chore: document --- man/affine.Rd | 9 +++++++++ man/anndataToGiotto.Rd | 8 ++++---- man/crop.Rd | 3 +++ man/ext.Rd | 3 +++ man/giottoAffineImage-class.Rd | 20 ++++++++++++++++++++ man/giottoLargeImage-class.Rd | 10 +++++++--- man/giottoToSeuratV5.Rd | 9 ++++++++- man/plot-generic.Rd | 3 +++ man/rescale.Rd | 6 ++++++ man/seuratToGiottoV4.Rd | 6 ++++++ man/shear.Rd | 6 ++++++ man/spatShift.Rd | 3 +++ man/spin.Rd | 6 ++++++ 13 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 man/giottoAffineImage-class.Rd diff --git a/man/affine.Rd b/man/affine.Rd index d0436f67..890cb9f7 100644 --- a/man/affine.Rd +++ b/man/affine.Rd @@ -8,6 +8,9 @@ \alias{affine,giottoPoints,matrix-method} \alias{affine,giottoPolygon,matrix-method} \alias{affine,spatLocsObj,matrix-method} +\alias{affine,giottoLargeImage,matrix-method} +\alias{affine,giottoAffineImage,matrix-method} +\alias{affine,affine2d,matrix-method} \title{Affine transformations} \usage{ \S4method{affine}{ANY,missing}(x) @@ -21,6 +24,12 @@ \S4method{affine}{giottoPolygon,matrix}(x, y, inv = FALSE, ...) \S4method{affine}{spatLocsObj,matrix}(x, y, inv = FALSE, ...) + +\S4method{affine}{giottoLargeImage,matrix}(x, y, inv = FALSE, ...) + +\S4method{affine}{giottoAffineImage,matrix}(x, y, inv = FALSE, ...) + +\S4method{affine}{affine2d,matrix}(x, y, inv = FALSE, ...) } \arguments{ \item{x}{object} diff --git a/man/anndataToGiotto.Rd b/man/anndataToGiotto.Rd index e894dfe2..9219fd74 100644 --- a/man/anndataToGiotto.Rd +++ b/man/anndataToGiotto.Rd @@ -23,7 +23,7 @@ anndataToGiotto( neighbors(). If multiple spatial networks are in the anndata object, a list of key_added terms may be provided. If converting an anndata object from giottoToAnnData, a .txt file may be provided, which was generated in that -function, i.e. {spat_unit}_{feat_type}_nn_network_keys_added.txt. Cannot +function, i.e. \{spat_unit\}_\{feat_type\}_nn_network_keys_added.txt. Cannot be "spatial". This becomes the name of the nearest network in the gobject.} \item{spatial_n_key_added}{equivalent of "key_added" argument from @@ -35,11 +35,11 @@ i.e. {spat_unit}_{feat_type}_spatial_network_keys_added.txt Cannot be the same as n_key_added.} \item{delaunay_spat_net}{binary parameter for spatial network. If TRUE, the -spatial network is a delaunay network.} +spatial network is a deluanay network.} -\item{spat_unit}{desired spatial unit for conversion, default NULL} +\item{spat_unit}{desired spatial unit to use for conversion, default NULL} -\item{feat_type}{desired feature type for conversion, default NULL} +\item{feat_type}{desired feature type to use for conversion, default NULL} \item{h5_file}{name to create and on-disk HDF5 file} diff --git a/man/crop.Rd b/man/crop.Rd index 2effbd66..6dae9f8f 100644 --- a/man/crop.Rd +++ b/man/crop.Rd @@ -3,6 +3,7 @@ \name{crop} \alias{crop} \alias{crop,giottoLargeImage-method} +\alias{crop,giottoAffineImage-method} \alias{crop,spatLocsObj-method} \alias{crop,spatialNetworkObj-method} \alias{crop,giottoPoints-method} @@ -11,6 +12,8 @@ \usage{ \S4method{crop}{giottoLargeImage}(x, y, ...) +\S4method{crop}{giottoAffineImage}(x, y, ...) + \S4method{crop}{spatLocsObj}(x, y, ...) \S4method{crop}{spatialNetworkObj}(x, y, ...) diff --git a/man/ext.Rd b/man/ext.Rd index 9203f5b0..2e1fa453 100644 --- a/man/ext.Rd +++ b/man/ext.Rd @@ -10,6 +10,7 @@ \alias{ext,giottoLargeImage-method} \alias{ext,giottoImage-method} \alias{ext,giotto-method} +\alias{ext,giottoAffineImage-method} \alias{ext<-,giottoPoints,SpatExtent-method} \alias{ext<-,giottoPolygon,SpatExtent-method} \alias{ext<-,giottoLargeImage,SpatExtent-method} @@ -40,6 +41,8 @@ ... ) +\S4method{ext}{giottoAffineImage}(x, ...) + \S4method{ext}{giottoPoints,SpatExtent}(x) <- value \S4method{ext}{giottoPolygon,SpatExtent}(x) <- value diff --git a/man/giottoAffineImage-class.Rd b/man/giottoAffineImage-class.Rd new file mode 100644 index 00000000..d0b229d2 --- /dev/null +++ b/man/giottoAffineImage-class.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/classes.R +\docType{class} +\name{giottoAffineImage-class} +\alias{giottoAffineImage-class} +\title{S4 giottoAffineImage Class} +\description{ +Class extending \code{giottoLargeImage}. When \code{shear()} or \code{spin()} operations +are performed on +} +\section{Slots}{ + +\describe{ +\item{\code{affine}}{contains \code{affine2d} object allowing lazily performed spatial +transforms} + +\item{\code{funs}}{list of functions associated with the object. Primarily to +perform the delayed/lazy operations} +}} + diff --git a/man/giottoLargeImage-class.Rd b/man/giottoLargeImage-class.Rd index f339c0be..83c7014a 100644 --- a/man/giottoLargeImage-class.Rd +++ b/man/giottoLargeImage-class.Rd @@ -9,15 +9,19 @@ giottoLargeImage } \description{ -class to handle images too large to load in normally through -magick +Image class for Giotto that uses \pkg{terra} \code{SpatRaster} as +a backend. If images are loaded from a file on disk then they are worked +with lazily, where only the values needed at any moment are loaded/sampled +into memory. Since \code{SpatRaster} objects are C pointers, \code{giottoLargeImage} +and inheriting classes need to run \code{reconnect()} after loading from a +saved object. } \section{Slots}{ \describe{ \item{\code{name}}{name of large Giotto image} -\item{\code{raster_object}}{terra raster object} +\item{\code{raster_object}}{terra \code{SpatRaster} object} \item{\code{extent}}{tracks the extent of the raster object. Note that most processes should rely on the extent of the raster object instead of this.} diff --git a/man/giottoToSeuratV5.Rd b/man/giottoToSeuratV5.Rd index d06ceca7..1bb21413 100644 --- a/man/giottoToSeuratV5.Rd +++ b/man/giottoToSeuratV5.Rd @@ -4,13 +4,20 @@ \alias{giottoToSeuratV5} \title{Convert Giotto to Seurat V5} \usage{ -giottoToSeuratV5(gobject, spat_unit = NULL, ...) +giottoToSeuratV5( + gobject, + spat_unit = NULL, + res_type = c("hires", "lowres", "fullres"), + ... +) } \arguments{ \item{gobject}{Giotto object} \item{spat_unit}{spatial unit (e.g. 'cell')} +\item{res_type}{type of 10x image output resolution} + \item{...}{additional params to pass to \code{\link{get_spatial_locations}}} } \value{ diff --git a/man/plot-generic.Rd b/man/plot-generic.Rd index 4fd11dd5..9388b733 100644 --- a/man/plot-generic.Rd +++ b/man/plot-generic.Rd @@ -5,6 +5,7 @@ \alias{plot} \alias{plot,giottoImage,missing-method} \alias{plot,giottoLargeImage,missing-method} +\alias{plot,giottoAffineImage,missing-method} \alias{plot,giottoPolygon,missing-method} \alias{plot,giottoPoints,missing-method} \alias{plot,spatLocsObj,missing-method} @@ -29,6 +30,8 @@ ... ) +\S4method{plot}{giottoAffineImage,missing}(x, y, ...) + \S4method{plot}{giottoPolygon,missing}( x, point_size = 0.6, diff --git a/man/rescale.Rd b/man/rescale.Rd index 7f2f05cb..41340e96 100644 --- a/man/rescale.Rd +++ b/man/rescale.Rd @@ -7,7 +7,9 @@ \alias{rescale,data.frame-method} \alias{rescale,giottoPolygon-method} \alias{rescale,giottoPoints-method} +\alias{rescale,giottoImage-method} \alias{rescale,giottoLargeImage-method} +\alias{rescale,giottoAffineImage-method} \alias{rescale,affine2d-method} \title{Rescale an object} \usage{ @@ -39,8 +41,12 @@ \S4method{rescale}{giottoPoints}(x, fx = 1, fy = fx, x0, y0) +\S4method{rescale}{giottoImage}(x, fx = 1, fy = fx, x0, y0) + \S4method{rescale}{giottoLargeImage}(x, fx = 1, fy = fx, x0, y0) +\S4method{rescale}{giottoAffineImage}(x, fx = 1, fy = fx, x0, y0) + \S4method{rescale}{affine2d}(x, fx = 1, fy = fx, x0, y0) } \arguments{ diff --git a/man/seuratToGiottoV4.Rd b/man/seuratToGiottoV4.Rd index 842dad1c..06e2b5f9 100644 --- a/man/seuratToGiottoV4.Rd +++ b/man/seuratToGiottoV4.Rd @@ -39,5 +39,11 @@ stored in it. \description{ Convert a Seurat V4 object to a Giotto object } +\examples{ +m_expression <- Matrix::Matrix(rnorm(100), nrow = 10, sparse = TRUE) +s <- Seurat::CreateSeuratObject(counts = m_expression) + +seuratToGiottoV5(s, spatial_assay = "RNA") +} \keyword{interoperability} \keyword{seurat} diff --git a/man/shear.Rd b/man/shear.Rd index 2a3b4e55..570a39d5 100644 --- a/man/shear.Rd +++ b/man/shear.Rd @@ -6,6 +6,8 @@ \alias{shear,SpatVector-method} \alias{shear,giottoPoints-method} \alias{shear,giottoPolygon-method} +\alias{shear,giottoLargeImage-method} +\alias{shear,giottoAffineImage-method} \title{Apply a shear tranform} \usage{ \S4method{shear}{spatLocsObj}(x, fx = 0, fy = 0, x0, y0, ...) @@ -15,6 +17,10 @@ \S4method{shear}{giottoPoints}(x, fx = 0, fy = 0, x0, y0, ...) \S4method{shear}{giottoPolygon}(x, fx = 0, fy = 0, x0, y0, ...) + +\S4method{shear}{giottoLargeImage}(x, fx = 0, fy = 0, x0, y0, ...) + +\S4method{shear}{giottoAffineImage}(x, fx = 0, fy = 0, x0, y0, ...) } \arguments{ \item{x}{object} diff --git a/man/spatShift.Rd b/man/spatShift.Rd index 7014ea0d..f367611b 100644 --- a/man/spatShift.Rd +++ b/man/spatShift.Rd @@ -11,6 +11,7 @@ \alias{spatShift,giottoPoints-method} \alias{spatShift,giottoLargeImage-method} \alias{spatShift,giottoImage-method} +\alias{spatShift,giottoAffineImage-method} \alias{spatShift,affine2d-method} \title{Spatially shift an object} \usage{ @@ -47,6 +48,8 @@ \S4method{spatShift}{giottoImage}(x, dx = 0, dy = 0, ...) +\S4method{spatShift}{giottoAffineImage}(x, dx = 0, dy = 0, ...) + \S4method{spatShift}{affine2d}(x, dx = 0, dy = 0, ...) } \arguments{ diff --git a/man/spin.Rd b/man/spin.Rd index 748fea53..42df7eb6 100644 --- a/man/spin.Rd +++ b/man/spin.Rd @@ -7,6 +7,8 @@ \alias{spin,giottoPoints-method} \alias{spin,spatLocsObj-method} \alias{spin,data.frame-method} +\alias{spin,giottoLargeImage-method} +\alias{spin,giottoAffineImage-method} \alias{spin,affine2d-method} \title{Spin an object} \usage{ @@ -39,6 +41,10 @@ geom = c("sdimx", "sdimy", "sdimz") ) +\S4method{spin}{giottoLargeImage}(x, angle = NULL, x0 = NULL, y0 = NULL, ...) + +\S4method{spin}{giottoAffineImage}(x, angle = NULL, x0 = NULL, y0 = NULL, ...) + \S4method{spin}{affine2d}(x, angle = NULL, x0 = NULL, y0 = NULL) } \arguments{ From 146582931eaf7ec17fbf592edea87fab3a8a5ceb Mon Sep 17 00:00:00 2001 From: iqraAmin Date: Thu, 4 Jul 2024 07:17:33 -0400 Subject: [PATCH 066/160] Minor Fix giottoToSeuratV5() --- R/interoperability.R | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/R/interoperability.R b/R/interoperability.R index 4e5b08af..c2b29e3b 100644 --- a/R/interoperability.R +++ b/R/interoperability.R @@ -1694,13 +1694,12 @@ giottoToSeuratV5 <- function( # spatial coordinates loc_use <- getSpatialLocations( - gobject = gobject, - spat_unit = spat_unit, - output = "spatLocsObj", - output = "data.table", - copy_obj = TRUE, - ... # allow setting of spat_loc_name through additional params - ) + gobject = gobject, + spat_unit = spat_unit, + output = "spatLocsObj", + copy_obj = TRUE, + ... # allow setting of spat_loc_name through additional params + ) # flip y vals From f82abd675a0bfa4347ca169c3557653162b9c3e0 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 8 Jul 2024 14:48:41 -0400 Subject: [PATCH 067/160] fix: initialize() needs to provide names for giottoLargeImage extent slot vector --- R/methods-initialize.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/methods-initialize.R b/R/methods-initialize.R index cd4e1f3d..5c55dcbe 100644 --- a/R/methods-initialize.R +++ b/R/methods-initialize.R @@ -620,6 +620,7 @@ setMethod("initialize", signature("giottoLargeImage"), function(.Object, ...) { # extent .Object@extent <- as.vector(terra::ext(r)) + names(.Object@extent) <- c("xmin", "xmax", "ymin", "ymax") .Object@overall_extent <- .Object@overall_extent %null% as.vector(terra::ext(r)) From a7c1b7c7c4f63870b34117efed7446fe50829d78 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 8 Jul 2024 14:49:36 -0400 Subject: [PATCH 068/160] fix: bad written file extension for affine images --- R/images.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/images.R b/R/images.R index 36c0637a..a593c51a 100644 --- a/R/images.R +++ b/R/images.R @@ -284,7 +284,7 @@ get_adj_rescale_img <- function(img_minmax, stopifnot(inherits(x, "magick-image")) stopifnot(length(x) == 1L) format <- tolower(magick::image_info(x[1])$format) - tmp <- file.path(tempdir(), paste0(tempname, format, collapse = ".")) + tmp <- file.path(tempdir(), paste(tempname, format, sep = ".")) vmsg(.is_debug = TRUE, "`.magick_preview()` saving as", format) image_write(x, path = tmp, format = format) return(tmp) From e14b26f8a617bc3e42b8ccb3f0c7ac26ca3fd95c Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 8 Jul 2024 14:50:46 -0400 Subject: [PATCH 069/160] change: use `initialize()` instead of other code in `crop()` method --- R/methods-crop.R | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/R/methods-crop.R b/R/methods-crop.R index c00a445c..9edbdae0 100644 --- a/R/methods-crop.R +++ b/R/methods-crop.R @@ -38,12 +38,7 @@ setMethod("crop", signature("giottoLargeImage"), function(x, y, ...) { warning("crop region is empty", call. = FALSE) } 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 + return(initialize(x)) }) # * giottoAffineImage #### From 288760bd2e3f0cd68ba34698162f49edaf4cb2a8 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 8 Jul 2024 14:51:28 -0400 Subject: [PATCH 070/160] enh: mask out blurred regions of magick affine distort --- R/methods-initialize.R | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/R/methods-initialize.R b/R/methods-initialize.R index 5c55dcbe..770bc0f2 100644 --- a/R/methods-initialize.R +++ b/R/methods-initialize.R @@ -660,6 +660,13 @@ setMethod("initialize", signature("giottoAffineImage"), function(.Object, ...) { gimg <- .magick_preview(mg@mg_object, tempname = tempname) %>% createGiottoLargeImage() ext(gimg) <- ext(.Object) + + # mask image + aff <- .Object@affine + m <- .bound_poly(ext(aff@anchor)) + m <- affine(m, aff) + gimg@raster_object <- terra::mask(gimg@raster_object, mask = m) + return(gimg) # TODO things to be implemented for this pipeline: # col (the trip the magick-image flattened the image without applying col) From 46307d6dd93e811fd4e35761b358c25d301879f1 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 8 Jul 2024 20:04:11 -0400 Subject: [PATCH 071/160] fix: incorrect image downscaling by magick affine --- R/methods-affine.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/R/methods-affine.R b/R/methods-affine.R index 03aaf82c..c250e93e 100644 --- a/R/methods-affine.R +++ b/R/methods-affine.R @@ -221,7 +221,10 @@ setMethod("affine", signature(x = "affine2d", y = "matrix"), function( aff <- x@affine dummy_sl <- .magick_image_corners(mg) aff_dummy_sl <- affine(dummy_sl, .aff_linear_2d(aff)) %>% - flip() + flip() %>% + rescale(fx = 1 / aff$scale[["x"]], fy = 1 / aff$scale[["y"]]) + # no rescaling should be performed at this step. Otherwise magick + # will generate a differently sized image during distortion .sl_to_mat <- function(x) { x[][, c("sdimx", "sdimy")] %>% t() From 2c0882a295abd223847483a1dd9c18a227e7c95d Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 8 Jul 2024 20:31:43 -0400 Subject: [PATCH 072/160] change: restrict to 256 color during plot previewing --- R/images.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/images.R b/R/images.R index a593c51a..9422d11a 100644 --- a/R/images.R +++ b/R/images.R @@ -286,7 +286,7 @@ get_adj_rescale_img <- function(img_minmax, format <- tolower(magick::image_info(x[1])$format) tmp <- file.path(tempdir(), paste(tempname, format, sep = ".")) vmsg(.is_debug = TRUE, "`.magick_preview()` saving as", format) - image_write(x, path = tmp, format = format) + image_write(x, path = tmp, format = format, depth = 8) return(tmp) } From 00507401e4ceca680e2637b10c2271ba9ab55abc Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 9 Jul 2024 01:17:05 -0400 Subject: [PATCH 073/160] enh: improve crop - add a standard warning when crop area ia empty - ignore crops larger than the source image, return the input directly for speed --- R/methods-crop.R | 80 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 27 deletions(-) diff --git a/R/methods-crop.R b/R/methods-crop.R index 9edbdae0..6ad1d244 100644 --- a/R/methods-crop.R +++ b/R/methods-crop.R @@ -25,8 +25,6 @@ NULL - - # methods #### @@ -34,9 +32,8 @@ NULL #' @rdname crop #' @export setMethod("crop", signature("giottoLargeImage"), function(x, y, ...) { - if (is.null(terra::intersect(terra::ext(x), terra::ext(y)))) { - warning("crop region is empty", call. = FALSE) - } + do_crop <- .crop_check(x, y) + if (!do_crop) return(initialize(x)) x@raster_object <- terra::crop(x@raster_object, y, ...) return(initialize(x)) }) @@ -49,8 +46,10 @@ setMethod("crop", signature("giottoAffineImage"), function(x, y, ...) { d <- .bound_poly(crop_ext) aff <- x@affine img_crop_ext <- ext(affine(d, aff, inv = TRUE)) # find extent in img space - x@raster_object <- terra::crop(x@raster_object, img_crop_ext) + do_crop <- .crop_check(x@raster_object, img_crop_ext) + if (!do_crop) return(initialize(x)) + x@raster_object <- terra::crop(x@raster_object, img_crop_ext) return(initialize(x)) }) @@ -60,11 +59,11 @@ setMethod("crop", signature("giottoAffineImage"), function(x, y, ...) { setMethod("crop", signature("spatLocsObj"), function(x, y, ...) { # NSE vars sdimx <- sdimy <- NULL - e <- ext(y) - if (is.null(terra::intersect(terra::ext(x), e))) { - warning("crop region is empty", call. = FALSE) - } + + do_crop <- .crop_check(x, y) + if (!do_crop) return(x) + b <- .ext_to_num_vec(e) # bounds as a numerical vector x[] <- x[][sdimx >= b[1] & sdimx <= b[2] & sdimy >= b[3] & sdimy <= b[4]] return(x) @@ -77,11 +76,11 @@ setMethod("crop", signature("spatLocsObj"), function(x, y, ...) { setMethod("crop", signature("spatialNetworkObj"), function(x, y, ...) { # NSE vars sdimx_begin <- sdimy_begin <- sdimx_end <- sdimy_end <- NULL - e <- ext(y) - if (is.null(terra::intersect(terra::ext(x), e))) { - warning("crop region is empty", call. = FALSE) - } + + do_crop <- .crop_check(x, y) + if (!do_crop) return(x) + b <- .ext_to_num_vec(e) # bounds as a numerical vector x[] <- x[][sdimx_begin >= b[1] & sdimx_begin <= b[2] & sdimy_begin >= b[3] & sdimy_begin <= b[4]] @@ -115,6 +114,9 @@ setMethod( b <- .determine_crop_bounds( x, y, missing_y, n_single_bounds, xmin, xmax, ymin, ymax ) + + do_crop <- .crop_check(x, b) + if (!do_crop) return(x) # 2. convert to DT sv <- x@spatVector @@ -125,18 +127,14 @@ setMethod( , which(x >= b[[1]] & x <= b[2] & y >= b[3] & y <= b[4]) ] - if (length(sub_idx) == 0L) { - warning("crop region is empty", call. = FALSE) - } # 4. update x x@spatVector <- sv[sub_idx] } else { # non-DT method. terra default. - if (is.null(terra::intersect(terra::ext(x), terra::ext(y)))) { - warning("crop region is empty", call. = FALSE) - } + do_crop <- .crop_check(x, y) + if (!do_crop) return(x) x@spatVector <- terra::crop(x@spatVector, y, ...) } @@ -175,6 +173,9 @@ setMethod( b <- .determine_crop_bounds( x, y, missing_y, n_single_bounds, xmin, xmax, ymin, ymax ) + + do_crop <- .crop_check(x, b) + if (!do_crop) return(x) # 2. convert to DT sv <- x@spatVectorCentroids @@ -189,9 +190,6 @@ setMethod( , which(x >= b[[1]] & x <= b[2] & y >= b[3] & y <= b[4]) ] - if (length(sub_idx) == 0L) { - warning("crop region is empty", call. = FALSE) - } # 4. update x x@spatVector <- x@spatVector[sub_idx] @@ -200,10 +198,9 @@ setMethod( x@unique_ID_cache <- spatDT[sub_idx, get("poly_ID")] } else { # non-DT method. terra default. - - if (is.null(terra::intersect(terra::ext(x), terra::ext(y)))) { - warning("crop region is empty", call. = FALSE) - } + + do_crop <- .crop_check(x, y) + if (!do_crop) return(x) args <- list(y = y, ...) x <- .do_gpoly(x, what = terra::crop, args = args) @@ -279,3 +276,32 @@ setMethod( "extent" = e ) } + +# warning if crop area is empty +# TRUE if crop is needed +# FALSE if crop extent is larger than all available data +# when FALSE, original data can be returned directly without modification +.crop_check <- function(x, y) { + ex <- ext(x) + ey <- ext(y) + exv <- .ext_to_num_vec(ex) + eyv <- .ext_to_num_vec(ey) + + # no overlap in extents + if (is.null(terra::intersect(ex, ey))) { + warning("crop region is empty", call. = FALSE) + return(TRUE) # this will likely be an empty object though + } + + # if crop ext (y) fully encapsulates object ext (x): + # yes, return FALSE, meaning no crop is needed + # no, return TRUE, meaning crop is needed + if (eyv[[1]] <= exv[[1]] && + eyv[[2]] >= exv[[2]] && + eyv[[3]] <= exv[[3]] && + eyv[[4]] >= exv[[4]]) { + return(FALSE) + } else { + return(TRUE) + } +} From 528b04054c5edf6c4e0688600817da2e280e3893 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 9 Jul 2024 14:00:54 -0400 Subject: [PATCH 074/160] chore: formatting --- R/python_environment.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/python_environment.R b/R/python_environment.R index d8e12418..2c9cde90 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -644,7 +644,7 @@ set_giotto_python_path <- function( #' @returns numeric .py_install_prompt <- function(package = NULL, env = NULL) { - if (is.null(package) | is.null(env)) { + if (is.null(package) || is.null(env)) { stop(GiottoUtils::wrap_txt("Incorrect Usage.\n", errWidth = TRUE)) } From d94dadb75c5dfb567dcc3245aceae6fa835bbf8b Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 9 Jul 2024 15:21:40 -0400 Subject: [PATCH 075/160] chore: formatting --- R/interoperability.R | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/R/interoperability.R b/R/interoperability.R index c2b29e3b..302d1342 100644 --- a/R/interoperability.R +++ b/R/interoperability.R @@ -1694,11 +1694,11 @@ giottoToSeuratV5 <- function( # spatial coordinates loc_use <- getSpatialLocations( - gobject = gobject, - spat_unit = spat_unit, - output = "spatLocsObj", - copy_obj = TRUE, - ... # allow setting of spat_loc_name through additional params + gobject = gobject, + spat_unit = spat_unit, + output = "spatLocsObj", + copy_obj = TRUE, + ... # allow setting of spat_loc_name through additional params ) # flip y vals From f288cf05331bcbcc5cab1bc554c61b67bf006470 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 12 Jul 2024 17:40:00 -0400 Subject: [PATCH 076/160] fix: return initialized from affine --- R/methods-affine.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/methods-affine.R b/R/methods-affine.R index c250e93e..8e80e85a 100644 --- a/R/methods-affine.R +++ b/R/methods-affine.R @@ -119,7 +119,7 @@ setMethod("affine", signature(x = "giottoAffineImage", y = "matrix"), function( a$x <- aff # update affine x@affine <- do.call(affine, args = a) - return(x) + return(initialize(x)) }) #' @rdname affine From d50f556940e1489aac10a265d918706f89fb49ba Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Sat, 13 Jul 2024 23:30:57 -0400 Subject: [PATCH 077/160] chore: raise gutils reqirement for `dir_manifest()` --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 6827402b..61e77c31 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -34,7 +34,7 @@ Imports: data.table (>= 1.12.2), dbscan (>= 1.1-3), deldir (>= 1.0.6), - GiottoUtils (>= 0.1.7), + GiottoUtils (>= 0.1.10), graphics, grDevices, igraph (>= 1.2.4.1), From 4616f35efaa8bfe86de3846eafae2402d893c69d Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:23:09 -0400 Subject: [PATCH 078/160] seems to work --- DESCRIPTION | 2 +- R/save_load.R | 631 +++++++++++++++++++---------------- man/get_expression_values.Rd | 2 +- 3 files changed, 354 insertions(+), 281 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 61e77c31..048e5b5e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -24,7 +24,7 @@ Description: This package contains the Giotto object and subobject class License: MIT + file LICENSE Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.1 +RoxygenNote: 7.3.2 Depends: base (>= 4.4.0), utils (>= 4.4.0), diff --git a/R/save_load.R b/R/save_load.R index ce1ef0fd..992ebd4b 100644 --- a/R/save_load.R +++ b/R/save_load.R @@ -271,6 +271,7 @@ saveGiotto <- function( } + #' @title loadGiotto #' @name loadGiotto #' @description Saves a Giotto object to a specific folder structure @@ -307,301 +308,49 @@ loadGiotto <- function(path_to_folder, img_type <- NULL path_to_folder <- path.expand(path_to_folder) + vmsg(.v = verbose, .is_debug = TRUE, "load from:", path_to_folder) if (!file.exists(path_to_folder)) { stop("path_to_folder does not exist \n") } ## 1. load giotto object - vmsg(.v = verbose, "1. read Giotto object") - - gobject_file <- list.files(path_to_folder, pattern = "gobject") - - if (identical(gobject_file, character(0))) { - vmsg(.v = verbose, "giotto object was not found - skip loading giotto object") - } else if (length(gobject_file) > 1) { - vmsg(.v = verbose, "more than 1 giotto object was found - skip loading giotto object") - } else { - if (grepl(".RDS", x = gobject_file)) { - gobject <- do.call( - "readRDS", - c( - file = paste0(path_to_folder, "/", "gobject.RDS"), - load_params - ) - ) - } - - if (grepl(".qs", x = gobject_file)) { - package_check(pkg_name = "qs", repository = "CRAN") - qread_fun <- get("qread", asNamespace("qs")) - gobject <- do.call( - qread_fun, - c( - file = paste0(path_to_folder, "/", "gobject.qs"), - load_params - ) - ) - } - } - - - - - - - ## 2. read in features - vmsg(.v = verbose, "2. read Giotto feature information") - feat_files <- list.files( - path = paste0(path_to_folder, "/Features"), - pattern = ".shp" + gobject <- .load_gobject_core( + path_to_folder = path_to_folder, + load_params = load_params, + verbose = verbose + ) + + ### ### spatial information loading ### ### + # terra vector objects are serialized as .shp files. + # These .shp files have to be read back in and then the relevant objects + # in the giotto object need to be regenerated. + + ## 2. read in spatial features + gobject <- .load_giotto_feature_info( + gobject = gobject, + path_to_folder = path_to_folder, + verbose = verbose ) - - if (length(feat_files) != 0) { - feat_names <- gsub(feat_files, - pattern = "_feature_spatVector.shp", - replacement = "" - ) - feat_paths <- list.files( - path = paste0(path_to_folder, "/Features"), - pattern = ".shp", full.names = TRUE - ) - - vector_names_paths <- list.files( - path = paste0(path_to_folder, "/Features"), pattern = ".txt", - full.names = TRUE - ) - - for (feat_i in seq_len(length(feat_names))) { - if (verbose) wrap_msg(feat_paths[feat_i]) - spatVector <- terra::vect(x = feat_paths[feat_i]) - - # read in original column names and assign to spatVector - spatVector_names <- fread( - input = vector_names_paths[feat_i], - header = FALSE - )[["V1"]] - names(spatVector) <- spatVector_names - - feat_name <- feat_names[feat_i] - if (verbose) wrap_msg(feat_name) - gobject@feat_info[[feat_name]]@spatVector <- spatVector - } - } ## 3. read in spatial polygons - vmsg(.v = verbose, "3. read Giotto spatial information") - - spat_paths <- list.files( - path = paste0(path_to_folder, "/SpatialInfo"), - pattern = "spatVector.shp", - full.names = TRUE - ) - spat_files <- basename(spat_paths) - - vector_names_paths <- list.files( - path = paste0(path_to_folder, "/SpatialInfo"), - pattern = "spatVector_names.txt", - full.names = TRUE + gobject <- .load_giotto_spatial_info( + gobject = gobject, + path_to_folder = path_to_folder, + verbose = verbose ) - if (length(spat_files) != 0) { - ## 3.1. shapes - if (isTRUE(verbose)) { - wrap_msg("3.1 read Giotto spatial shape information") - wrap_msg(spat_files) - } - - spat_names <- gsub(spat_files, - pattern = "_spatInfo_spatVector.shp", - replacement = "" - ) - - for (spat_i in seq_len(length(spat_names))) { - spatVector <- terra::vect(x = spat_paths[spat_i]) - - # read in original column names and assign to spatVector - spatVector_names <- fread( - input = vector_names_paths[spat_i], - header = FALSE - )[["V1"]] - names(spatVector) <- spatVector_names - - spat_name <- spat_names[spat_i] - if (isTRUE(verbose)) message(spat_name) - gobject@spatial_info[[spat_name]]@spatVector <- spatVector - } - - ## 3.2. centroids - if (isTRUE(verbose)) { - wrap_msg("\n 3.2 read Giotto spatial centroid information \n") - } - - centroid_search_term <- gsub(spat_files, - pattern = "_spatInfo_spatVector.shp", - replacement = "_spatInfo_spatVectorCentroids.shp" - ) - centroid_paths <- vapply( - centroid_search_term, - function(gp_centroid) { - list.files( - path = paste0(path_to_folder, "/SpatialInfo"), - pattern = gp_centroid, full.names = TRUE - ) - }, - FUN.VALUE = character(1L), - USE.NAMES = FALSE) - - # check if centroid are provided for spatvector polygons - test_missing <- unlist(lapply(centroid_paths, - FUN = function(x) identical(x, character(0)) - )) - centroid_paths <- centroid_paths[!test_missing] - - if (length(centroid_paths) == 0) { - if (verbose) { - wrap_msg("No centroids were found, centroid loading will be - skipped \n") - } - } else { - centroid_files <- basename(centroid_paths) - - if (length(centroid_files != 0)) { - spat_names <- gsub(centroid_files, - pattern = "_spatInfo_spatVectorCentroids.shp", - replacement = "" - ) - - vector_names_paths <- list.files( - path = paste0(path_to_folder, "/SpatialInfo"), - pattern = "spatVectorCentroids_names.txt", - full.names = TRUE - ) - - for (spat_i in seq_len(length(spat_names))) { - spatVector <- terra::vect(x = centroid_paths[spat_i]) - - # read in original column names and assign to spatVector - spatVector_names <- fread( - input = vector_names_paths[spat_i], - header = FALSE - )[["V1"]] - names(spatVector) <- spatVector_names - - spat_name <- spat_names[spat_i] - if (isTRUE(verbose)) message(spat_name) - gobject@spatial_info[[spat_name]]@spatVectorCentroids <- - spatVector - } - } - } - - - ## 3.3. overlaps - if (isTRUE(verbose)) { - wrap_msg("\n3.3 read Giotto spatial overlap information \n") - } - - overlap_search_term <- gsub(spat_files, - pattern = "_spatInfo_spatVector.shp", - replacement = "_spatInfo_spatVectorOverlaps.shp" - ) - overlap_files <- list.files( - path = paste0(path_to_folder, "/SpatialInfo"), - pattern = "spatVectorOverlaps.shp" - ) - - # check if overlap information is available - if (length(overlap_files) == 0) { - if (verbose) { - wrap_msg("No overlaps were found, overlap loading will be - skipped") - } - } else { - wrap_msg(overlap_files) - - # find overlaps per spatVector - for (sv_i in seq_along(overlap_search_term)) { - overlap_paths <- list.files( - path = paste0(path_to_folder, "/SpatialInfo"), - pattern = overlap_search_term[sv_i], full.names = TRUE - ) - overlap_filenames <- basename(overlap_paths) - - # get matching names files for the spatVector.shp files - overlap_column_names <- gsub(overlap_filenames, - pattern = "spatVectorOverlaps.shp", - replacement = "spatVectorOverlaps_names.txt" - ) - overlap_paths_colnames <- paste0( - dirname(overlap_paths), "/", - overlap_column_names - ) - - for (spat_i in seq_along(overlap_filenames)) { - spatVector <- terra::vect(x = overlap_paths[spat_i]) - - # read in original column names and assign to spatVector - spatVector_names <- fread( - input = overlap_paths_colnames[spat_i], - header = FALSE - )[["V1"]] - if (verbose) wrap_msg(spatVector_names) - names(spatVector) <- spatVector_names - - feat_name <- gsub(overlap_filenames[spat_i], - pattern = paste0("_", overlap_search_term[sv_i]), - replacement = "" - ) - spat_name <- gsub(overlap_filenames[spat_i], - pattern = paste0(feat_name, "_"), - replacement = "" - ) - spat_name <- gsub(spat_name, - pattern = "_spatInfo_spatVectorOverlaps.shp", - replacement = "" - ) - - if (isTRUE(verbose)) wrap_msg(spat_name, " and ", feat_name) - gobject@spatial_info[[spat_name]]@overlaps[[feat_name]] <- - spatVector - } - } - } - } - - - ## 4. images - vmsg(.v = verbose, "\n4. read Giotto image information") - # compatibility for pre-v0.3.0 gobject <- .update_image_slot(gobject) - - image_files <- list.files(path = paste0(path_to_folder, "/Images")) - if (length(image_files) != 0) { - image_names <- unique(gsub(image_files, - pattern = "_spatRaster.*", - replacement = "" - )) - for (image_i in seq_len(length(image_names))) { - image_name <- image_names[image_i] - if (verbose) image_name - new_path <- paste0( - path_to_folder, "/Images", "/", image_name, - "_spatRaster" - ) - spatRaster <- terra::rast(x = new_path) - - gobject@images[[image_name]]@raster_object <- spatRaster - gobject@images[[image_name]]@file_path <- new_path - } - } - + gobject <- .load_giotto_images( + gobject = gobject, + path_to_folder = path_to_folder, + verbose = verbose + ) + if (isTRUE(reconnect_giottoImage)) { if (!is.null(list_images(gobject))) { if (list_images(gobject)[img_type == "image", .N] > 0) { @@ -644,3 +393,327 @@ loadGiotto <- function(path_to_folder, return(gobject) } + +# internals #### + + +# load in the gobject S4 object. +# the contained point-based information will need to be regenerated/reconnected +# returns either a gobject or nothing if the file is missing or errors +.load_gobject_core <- function( + path_to_folder, load_params, verbose = NULL +) { + vmsg(.v = verbose, "1. read Giotto object") + + # gobject is expected to be saved with a filename like gobject.[ext] + # This item is the main S4 structure. + gobject_file <- list.files(path_to_folder, pattern = "gobject") + + if (identical(gobject_file, character(0))) { # no matches + vmsg(.v = verbose, "giotto object was not found + skip loading giotto object") + } else if (length(gobject_file) > 1) { # more than one match + vmsg(.v = verbose, "more than 1 giotto object was found + skip loading giotto object") + } else { + + # pick a reading function + read_fun <- NULL + if (grepl(".RDS", x = gobject_file)) { # .RDS file + read_fun <- "readRDS" + full_path <- file.path(path_to_folder, "gobject.RDS") + } + if (grepl(".qs", x = gobject_file)) { # .qs file + package_check(pkg_name = "qs", repository = "CRAN") + read_fun <- get("qread", asNamespace("qs")) + full_path <- file.path(path_to_folder, "gobject.qs") + } + + if (is.null(read_fun)) { # unrecognized file + stop("object is not a recognized save format.\n ", + ".RDS, .qs are supported\n") + } + + # read in the object + gobject <- do.call( + read_fun, args = c(file = full_path, load_params) + ) + return(gobject) + } +} + +# load and append spatial feature information +.load_giotto_feature_info <- function( + gobject, path_to_folder, verbose = NULL +) { + vmsg(.v = verbose, "2. read Giotto feature information") + vmsg(.v = verbose, .is_debug = TRUE, .initial = " ", + box_chars()$l, "subdir: /Features/", sep = "") + + feats_dir <- file.path(path_to_folder, "Features") + manifest <- dir_manifest(feats_dir) + basenames <- names(manifest) + + # basenames of .shp files to load + shp_files <- basenames[grepl(".shp", basenames)] + + # return early if none, also catches when dir does not exist + if (length(shp_files) == 0) return(gobject) + + # parse the feature type(s) to load from the .shp basenames + feats <- gsub(shp_files, + pattern = "_feature_spatVector.shp", replacement = "" + ) + + # basenames of .txt files to load + # These have attribute info names (e.g. feat_ID, feat_ID_uniq) + # this is done since serialized SpatVectors may have clipped names. + txt_files <- paste0(feats, "_feature_spatVector_names.txt") + + # ordering of files follow feats. + # Apply name to make indexing simple and unique + names(shp_files) <- names(txt_files) <- feats + + # iterate through features discovered and load/regenerate each + # then append the information to the gobject + for (feat in feats) { + load_shp <- manifest[[shp_files[[feat]]]] + load_txt <- manifest[[txt_files[[feat]]]] + + vmsg(.v = verbose, .is_debug = TRUE, .initial = " ", + sprintf("[%s] %s", feat, basename(load_shp))) + spatVector <- terra::vect(x = load_shp) + + # read in original column names and assign to SpatVector + spatVector_names <- data.table::fread( + input = load_txt, header = FALSE + )[["V1"]] + names(spatVector) <- spatVector_names + + gobject@feat_info[[feat]]@spatVector <- spatVector + } + + return(gobject) +} + +# load and append to gobject the spatial polygon information +.load_giotto_spatial_info <- function( + gobject, path_to_folder, verbose = NULL +) { + vmsg(.v = verbose, "3. read Giotto spatial information") + vmsg(.v = verbose, .is_debug = TRUE, .initial = " ", + box_chars()$l, "subdir: /SpatialInfo/", sep = "") + + spat_dir <- file.path(path_to_folder, "SpatialInfo") + manifest <- dir_manifest(spat_dir) + basenames <- names(manifest) + + # basenames of .shp files to load + # there are other .shp files for centroids and overlaps in this dir + # so the search term is more specific + shp_files <- basenames[grepl("spatVector.shp", basenames)] + + # return early if none, also catches when dir does not exist + if (length(shp_files) == 0) return(gobject) + + ## 3.1. shapes + vmsg(.v = verbose, "3.1 read Giotto spatial shape information") + + # parse the spatial unit(s) to load from the .shp basenames + spats <- gsub(shp_files, + pattern = "_spatInfo_spatVector.shp", replacement = "" + ) + + # basenames of .txt files to load + # .shp files may clip these normally, so we load them separately + txt_files <- paste0(spats, "_spatInfo_spatVector_names.txt") + + # ordering of files follow spats. + # Apply name to make indexing simple and unique + names(shp_files) <- names(txt_files) <- spats + + # iterate through spat units discovered and load/regen each + # then append the info to the gobject + for (spat in spats) { + load_shp <- manifest[[shp_files[[spat]]]] + load_txt <- manifest[[txt_files[[spat]]]] + + vmsg(.v = verbose, .is_debug = TRUE, .initial = " ", + sprintf("[%s] %s", spat, basename(load_shp))) + spatVector <- terra::vect(x = load_shp) + + # read in original column names and assign to spatVector + spatVector_names <- data.table::fread( + input = load_txt, header = FALSE + )[["V1"]] + names(spatVector) <- spatVector_names + + gobject@spatial_info[[spat]]@spatVector <- spatVector + } + + + # load centroids of gpoly + gobject <- .load_giotto_spatial_info_centroids( + gobject = gobject, + manifest = manifest, + basenames = basenames, + spats = spats, + verbose = verbose + ) + + # load overlaps of gpoly + gobject <- .load_giotto_spatial_info_overlaps( + gobject = gobject, + manifest = manifest, + verbose = verbose + ) + + return(gobject) +} + +# load and append to gobject the polygons centroids information +.load_giotto_spatial_info_centroids <- function( + gobject, manifest, basenames, spats, verbose = NULL +) { + ## 3.2. centroids + vmsg(.v = verbose, "3.2 read Giotto spatial centroid information \n") + + # these files are optional, depending on if they have been calculated. + # They may not exist + + shp_search <- paste0(spats, "_spatInfo_spatVectorCentroids.shp") + shp_files <- basenames[basenames %in% shp_search] + + # return early if none exist + if (length(shp_files) == 0) return(gobject) + + txt_files <- paste0(spats, "_spatInfo_spatVectorCentroids_names.txt") + + # ordering of files follow spats + # apply name for simple and unique indexing + names(shp_files) <- names(txt_files) <- spats + + # iterate through spat_units and load/regen then append the data + # to the gobject + for (spat in spats) { + load_shp <- manifest[[shp_files[[spat]]]] + load_txt <- manifest[[txt_files[[spat]]]] + + if (is.null(load_shp)) next # skip to next spat_unit if none + vmsg(.v = verbose, .is_debug = TRUE, .initial = " ", + sprintf("[%s] %s", spat, basename(load_shp))) + spatVector <- terra::vect(load_shp) + + # read in original column names and assign to spatVector + spatVector_names <- data.table::fread( + input = load_txt, header = FALSE + )[["V1"]] + names(spatVector) <- spatVector_names + + gobject@spatial_info[[spat]]@spatVectorCentroids <- spatVector + } + return(gobject) +} + +# load and append to gobject the polygons overlaps information +.load_giotto_spatial_info_overlaps <- function( + gobject, manifest, verbose = NULL +) { + ## 3.3. overlaps + vmsg(.v = verbose, "3.3 read Giotto spatial overlap information \n") + + si <- get_polygon_info_list(gobject) # none case taken care of in 3.1 + spats <- names(si) + + # These files are optional, depending on if they have been calculated. + # They may not exist + # They are named in "feattype_spatunit_postfix.extension" convention + + for (spat in spats) { + feats <- .gpoly_overlap_names(si[[spat]], type = "point") + if (is.null(feats)) next # goto next spat_unit if no overlaps + + for(feat in feats) { + + # format: feattype_spatunit + comb <- paste(feat, spat, sep = "_") + + # format: feattype_spatunit_postfix.extension + shp_file <- paste0(comb, "_spatInfo_spatVectorOverlaps.shp") + txt_file <- paste0(comb, "_spatInfo_spatVectorOverlaps_names.txt") + load_shp <- manifest[[shp_file]] + load_txt <- manifest[[txt_file]] + + vmsg(.v = verbose, .is_debug = TRUE, .initial = " ", + sprintf("[%s and %s] %s", spat, feat, basename(load_shp))) + spatVector <- terra::vect(load_shp) + + # read in original column names + spatVector_names <- data.table::fread( + input = load_txt, header = FALSE + )[["V1"]] + names(spatVector) <- spatVector_names + + # append + gobject@spatial_info[[spat]]@overlaps[[feat]] <- spatVector + } + } + + return(gobject) +} + + +.load_giotto_images <- function(gobject, path_to_folder, verbose = NULL) { + + vmsg(.v = verbose, "4. read Giotto image information") + vmsg(.v = verbose, .is_debug = TRUE, .initial = " ", + box_chars()$l, "subdir: /Images/", sep = "") + + imgs_dir <- file.path(path_to_folder, "Images") + manifest <- dir_manifest(imgs_dir) + basenames <- names(manifest) + + # basenames of imgs to load + img_files <- basenames[grepl("_spatRaster$", basenames)] + + # return early if none, also catches when dir does not exist + if (length(img_files) == 0) return(gobject) + + # parse the image name to load + imgs <- gsub(img_files, pattern = "_spatRaster", replacement = "") + + names(img_files) <- imgs + + for (img in imgs) { + load_img <- manifest[[img_files[[img]]]] + + vmsg(.v = verbose, .is_debug = TRUE, .initial = " ", + sprintf("[%s] %s", img, basename(load_img))) + spatRaster <- terra::rast(load_img) + + gobject@images[[img]]@raster_object <- spatRaster + gobject@images[[img]]@file_path <- load_img + } + + return(gobject) +} + +.gpoly_overlap_names <- function(x, type = c("point", "intensity")) { + type <- match.arg(type, choices = c("point", "intensity")) + ovlps <- overlaps(x) + if (is.null(ovlps)) return(NULL) + + switch(type, + "point" = { + res <- names(ovlps) + res <- res[res != "intensity"] + if (length(res) == 0) res <- NULL + return(res) + }, + "intensity" = { + res <- names(ovlps$intensity) + } + ) + return(res) +} + diff --git a/man/get_expression_values.Rd b/man/get_expression_values.Rd index 79408e12..28aba2a0 100644 --- a/man/get_expression_values.Rd +++ b/man/get_expression_values.Rd @@ -8,7 +8,7 @@ get_expression_values( gobject, spat_unit = NULL, feat_type = NULL, - values = NULL, + values = c("raw", "normalized", "scaled"), output = c("exprObj", "matrix"), set_defaults = TRUE ) From 50719e7de9c0248897037f4515d87c660c5f2b14 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 15 Jul 2024 11:37:55 -0400 Subject: [PATCH 079/160] chore: update news --- NEWS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS.md b/NEWS.md index fc6bf070..e5fd23e1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,6 +5,9 @@ - python environment installation and how it relates to default settings such as .condarc may have changed. - `giottoImage` `name` slot now requires `character` and will not accept `NULL` +## bug fixes +- `loadGiotto()` no longer errors with similarly named spat_units or feat_types (e.g. "cell" and "new_cell" would previously throw an error) + ## enhancements - `verbose` param for `createNearestNetwork()` - `checkGiottoEnvironment()` in addition to full filepaths, also now supports name of environment or installation directory From 774a9d617b779de57c36fec2e34c0df24672d71a Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 15 Jul 2024 13:58:00 -0400 Subject: [PATCH 080/160] chore: update tests and silence some functions --- R/auxilliary.R | 8 ++++---- R/methods-initialize.R | 2 +- R/slot_check.R | 2 +- tests/testthat/test-auxiliary.R | 28 +++++++++++++++++++++------- tests/testthat/test-save_load.R | 2 ++ tests/testthat/test-slot_accessors.R | 6 +++--- 6 files changed, 32 insertions(+), 16 deletions(-) diff --git a/R/auxilliary.R b/R/auxilliary.R index d278fbba..653a264d 100644 --- a/R/auxilliary.R +++ b/R/auxilliary.R @@ -792,7 +792,7 @@ create_average_DT <- function(gobject, expression_values, unique(c("normalized", "scaled", "custom", expression_values)) ) - expr_data <- get_expression_values( + expr_data <- getExpression( gobject = gobject, spat_unit = spat_unit, feat_type = feat_type, @@ -863,7 +863,7 @@ create_average_detection_DT <- function(gobject, expression_values, unique(c("normalized", "scaled", "custom", expression_values)) ) - expr_data <- get_expression_values( + expr_data <- getExpression( gobject = gobject, spat_unit = spat_unit, feat_type = feat_type, @@ -1081,7 +1081,7 @@ calculateMetaTable <- function(gobject, expression_values )) ) - expr_values <- get_expression_values( + expr_values <- getExpression( gobject = gobject, spat_unit = spat_unit, feat_type = feat_type, @@ -1396,7 +1396,7 @@ createMetafeats <- function(gobject, expression_values )) ) - exprobj <- get_expression_values( + exprobj <- getExpression( gobject = gobject, spat_unit = spat_unit, feat_type = feat_type, diff --git a/R/methods-initialize.R b/R/methods-initialize.R index 770bc0f2..535a5f0e 100644 --- a/R/methods-initialize.R +++ b/R/methods-initialize.R @@ -272,7 +272,7 @@ setMethod("initialize", signature("giotto"), function(.Object, ...) { if (!is.null(avail_expr)) { if (nrow(avail_expr[spat_unit == spatial_unit & feat_type == feature_type]) != 0L) { - provenance <- prov(get_expression_values( + provenance <- prov(getExpression( gobject = .Object, spat_unit = spatial_unit, feat_type = feature_type, diff --git a/R/slot_check.R b/R/slot_check.R index 1d94879d..9e8578cf 100644 --- a/R/slot_check.R +++ b/R/slot_check.R @@ -161,7 +161,7 @@ ft_fm <- avail_fm[feat_type == ft_i, ] lapply(seq(nrow(ft_fm)), function(obj_i) { su_i <- ft_fm$spat_unit[[obj_i]] - +browser() # get metadata meta <- getFeatureMetadata( gobject = gobject, diff --git a/tests/testthat/test-auxiliary.R b/tests/testthat/test-auxiliary.R index 59022af8..271c3b01 100644 --- a/tests/testthat/test-auxiliary.R +++ b/tests/testthat/test-auxiliary.R @@ -16,6 +16,7 @@ m <- matrix( e <- exprObj( exprMat = m, spat_unit = "cell", + provenance = "cell", feat_type = "test_feat", name = "test" ) @@ -36,13 +37,15 @@ df_clus_weight <- data.frame( ) test_that("createMetafeat can calculate mean values", { + rlang::local_options(lifecycle_verbosity = "quiet") expect_m <- matrix(rep(c(2, 5, 8), 3), nrow = 3) g <- createMetafeats( g, stat = "mean", expression_values = "test", feat_clusters = num_vec_clus, - name = "chara_vec_mean" + name = "chara_vec_mean", + verbose = FALSE ) enr <- getSpatialEnrichment(g, name = "chara_vec_mean", output = "data.table") @@ -55,7 +58,8 @@ test_that("createMetafeat can calculate mean values", { g, stat = "mean", expression_values = "test", feat_clusters = df_clus, - name = "df_mean" + name = "df_mean", + verbose = FALSE ) enr <- getSpatialEnrichment(g, name = "df_mean", output = "data.table") @@ -65,13 +69,15 @@ test_that("createMetafeat can calculate mean values", { }) test_that("createMetafeat can calculate sum values", { + rlang::local_options(lifecycle_verbosity = "quiet") expect_m <- matrix(c(6, 15, 24, 4, 10, 16, 2, 5, 8), nrow = 3) g <- createMetafeats( g, stat = "sum", expression_values = "test", feat_clusters = num_vec_clus, - name = "sum" + name = "sum", + verbose = FALSE ) enr <- getSpatialEnrichment(g, name = "sum", output = "data.table") @@ -81,13 +87,15 @@ test_that("createMetafeat can calculate sum values", { }) test_that("createMetafeat can calculate min values", { + rlang::local_options(lifecycle_verbosity = "quiet") expect_m <- matrix(c(1L, 4L, 7L, 1L, 4L, 7L, 2L, 5L, 8L), nrow = 3) g <- createMetafeats( g, stat = "min", expression_values = "test", feat_clusters = num_vec_clus, - name = "min" + name = "min", + verbose = FALSE ) enr <- getSpatialEnrichment(g, name = "min", output = "data.table") @@ -97,13 +105,15 @@ test_that("createMetafeat can calculate min values", { }) test_that("createMetafeat can calculate max values", { + rlang::local_options(lifecycle_verbosity = "quiet") expect_m <- matrix(c(3L, 6L, 9L, 3L, 6L, 9L, 2L, 5L, 8L), nrow = 3) g <- createMetafeats( g, stat = "max", expression_values = "test", feat_clusters = num_vec_clus, - name = "max" + name = "max", + verbose = FALSE ) enr <- getSpatialEnrichment(g, name = "max", output = "data.table") @@ -113,13 +123,15 @@ test_that("createMetafeat can calculate max values", { }) test_that("createMetafeat can use weights", { + rlang::local_options(lifecycle_verbosity = "quiet") expect_m <- matrix(c(4, 10, 16, 0.4, 1.3, 2.2, 2, 5, 8), nrow = 3) g <- createMetafeats( g, stat = "mean", expression_values = "test", feat_clusters = df_clus_weight, - name = "weighted_means" + name = "weighted_means", + verbose = FALSE ) enr <- getSpatialEnrichment(g, name = "weighted_means", output = "data.table") @@ -130,6 +142,7 @@ test_that("createMetafeat can use weights", { }) test_that("createMetafeat can use rescale", { + rlang::local_options(lifecycle_verbosity = "quiet") expect_m <- matrix(rep(c(0, 0.5, 1), 3), nrow = 3) g <- createMetafeats( @@ -137,7 +150,8 @@ test_that("createMetafeat can use rescale", { expression_values = "test", feat_clusters = num_vec_clus, rescale_to = c(0, 1), - name = "scaled_means" + name = "scaled_means", + verbose = FALSE ) enr <- getSpatialEnrichment(g, name = "scaled_means", output = "data.table") diff --git a/tests/testthat/test-save_load.R b/tests/testthat/test-save_load.R index bb58d017..79142a4e 100644 --- a/tests/testthat/test-save_load.R +++ b/tests/testthat/test-save_load.R @@ -3,6 +3,7 @@ g <- GiottoData::loadGiottoMini("viz") test <- tempdir() test_that("gobject can be saved and loaded - qs", { + rlang::local_options(lifecycle_verbosity = "quiet") saveGiotto(g, dir = test, method = "qs", overwrite = TRUE, verbose = FALSE) g2 <<- loadGiotto(file.path(test, "saveGiottoDir")) @@ -10,6 +11,7 @@ test_that("gobject can be saved and loaded - qs", { }) test_that("gobject an be ovewritten and loaded - qs", { + rlang::local_options(lifecycle_verbosity = "quiet") saveGiotto(g2, dir = test, method = "qs", overwrite = TRUE, verbose = FALSE) g3 <- loadGiotto(file.path(test, "saveGiottoDir")) diff --git a/tests/testthat/test-slot_accessors.R b/tests/testthat/test-slot_accessors.R index ba9c1cfb..a44b1549 100644 --- a/tests/testthat/test-slot_accessors.R +++ b/tests/testthat/test-slot_accessors.R @@ -20,7 +20,8 @@ test_that("Not found exprObj returns error", { expect_error( getExpression(giotto_object, spat_unit = "none", - feat_type = "none", values = "raw" + feat_type = "none", + values = "raw" ) ) }) @@ -31,8 +32,7 @@ test_that("Not found CellMetadata returns error", { getCellMetadata( giotto_object, spat_unit = "none", - feat_type = "none", - values = "raw" + feat_type = "none" ) ) }) From 4587f0e016d26e66b8aa1ef545d4edc90ea5d6dd Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 15 Jul 2024 13:58:27 -0400 Subject: [PATCH 081/160] chore: remove stray browser --- R/slot_check.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/slot_check.R b/R/slot_check.R index 9e8578cf..1d94879d 100644 --- a/R/slot_check.R +++ b/R/slot_check.R @@ -161,7 +161,7 @@ ft_fm <- avail_fm[feat_type == ft_i, ] lapply(seq(nrow(ft_fm)), function(obj_i) { su_i <- ft_fm$spat_unit[[obj_i]] -browser() + # get metadata meta <- getFeatureMetadata( gobject = gobject, From 1f4a6ce556f8f28e3466b5ba9a481e655a28c32f Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 15 Jul 2024 14:31:52 -0400 Subject: [PATCH 082/160] chore: update expression accessor usage `get_expression_values()` -> `getExpression()` --- R/NN_network.R | 2 +- R/aggregate.R | 2 +- R/interoperability.R | 12 ++++++------ R/join.R | 2 +- R/slot_accessors.R | 4 ++-- R/slot_check.R | 2 +- R/slot_show.R | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/R/NN_network.R b/R/NN_network.R index d14b4607..66cc7cdc 100644 --- a/R/NN_network.R +++ b/R/NN_network.R @@ -704,7 +704,7 @@ createNearestNetwork <- function( expression_values )) ) - expr_obj <- get_expression_values( + expr_obj <- getExpression( gobject = gobject, feat_type = feat_type, spat_unit = spat_unit, diff --git a/R/aggregate.R b/R/aggregate.R index 4b3f7fa2..e30e1ef7 100644 --- a/R/aggregate.R +++ b/R/aggregate.R @@ -1900,7 +1900,7 @@ aggregateStacksExpression <- function(gobject, # aggregate matrices matrix_list <- list() for (spat_unit in spat_units) { - mat <- get_expression_values(gobject, + mat <- getExpression(gobject, spat_unit = spat_unit, feat_type = feat_type, values = values, diff --git a/R/interoperability.R b/R/interoperability.R index 302d1342..30edf4bb 100644 --- a/R/interoperability.R +++ b/R/interoperability.R @@ -691,7 +691,7 @@ giottoToAnnData <- function( for (en in expr_names) { if (en == "raw") { - raw_x <- get_expression_values( + raw_x <- getExpression( gobject = gobject, values = en, spat_unit = su, @@ -703,7 +703,7 @@ giottoToAnnData <- function( } else { ad_layer_name <- paste0(su, "_", ft, "_", en) - x <- get_expression_values( + x <- getExpression( gobject = gobject, values = en, spat_unit = su, @@ -1222,7 +1222,7 @@ giottoToSeuratV4 <- function( expr_use <- lapply( avail_expr[feat_type == assay_use, name], function(x) { - get_expression_values( + getExpression( gobject = gobject, spat_unit = spat_unit, feat_type = assay_use, @@ -1503,7 +1503,7 @@ giottoToSeuratV5 <- function( expr_use <- lapply( avail_expr[feat_type == assay_use, name], function(x) { - get_expression_values( + getExpression( gobject = gobject, spat_unit = spat_unit, feat_type = assay_use, @@ -2613,7 +2613,7 @@ giottoToSpatialExperiment <- function(giottoObj, verbose = TRUE) { "' for spatial unit: '", spatialUnits[su], "'" ) } - exprMat <- get_expression_values( + exprMat <- getExpression( gobject = giottoObj, spat_unit = spatialUnits[su], feat_type = giottoExpr[1]$feat_type, @@ -2657,7 +2657,7 @@ giottoToSpatialExperiment <- function(giottoObj, verbose = TRUE) { spatialUnits[su] ), withDimnames = FALSE - ) <- get_expression_values( + ) <- getExpression( gobject = giottoObj, spat_unit = spatialUnits[su], feat_type = giottoExpr[i]$feat_type, diff --git a/R/join.R b/R/join.R index 5d3e886a..dbac99dd 100644 --- a/R/join.R +++ b/R/join.R @@ -647,7 +647,7 @@ joinGiottoObjects <- function(gobject_list, } else { for (exprObj_i in seq(nrow(avail_expr))) { expr_list <- lapply(updated_object_list, function(gobj) { - get_expression_values( + getExpression( gobject = gobj, spat_unit = avail_expr$spat_unit[[exprObj_i]], feat_type = avail_expr$feat_type[[exprObj_i]], diff --git a/R/slot_accessors.R b/R/slot_accessors.R index 597df24a..ec793e8c 100644 --- a/R/slot_accessors.R +++ b/R/slot_accessors.R @@ -284,7 +284,7 @@ set_cell_id <- function(gobject, # get cell ID values if (spat_unit %in% expr_avail$spat_unit) { # preferred from expression - cell_IDs <- spatIDs(get_expression_values( + cell_IDs <- spatIDs(getExpression( gobject = gobject, spat_unit = spat_unit, feat_type = expr_avail$feat_type[[1L]], @@ -424,7 +424,7 @@ set_feat_id <- function(gobject, if (feat_type %in% expr_avail$feat_type) { # preferred from expression - feat_IDs <- featIDs(get_expression_values( + feat_IDs <- featIDs(getExpression( gobject = gobject, spat_unit = expr_avail$spat_unit[[1L]], feat_type = feat_type, diff --git a/R/slot_check.R b/R/slot_check.R index 1d94879d..7bd01032 100644 --- a/R/slot_check.R +++ b/R/slot_check.R @@ -178,7 +178,7 @@ } if (!nrow(avail_ex[spat_unit == su_i & feat_type == ft_i]) == 0L) { - IDs <- featIDs(get_expression_values( + IDs <- featIDs(getExpression( gobject = gobject, spat_unit = su_i, feat_type = ft_i, diff --git a/R/slot_show.R b/R/slot_show.R index d34e82ac..3f223a36 100644 --- a/R/slot_show.R +++ b/R/slot_show.R @@ -33,7 +33,7 @@ showGiottoExpression <- function(gobject, nrows = 4, ncols = 4) { objPrints <- list() for (obj_i in seq(nrow(available_data))) { # get object - dataObj <- get_expression_values( + dataObj <- getExpression( gobject = gobject, values = available_data$name[[obj_i]], spat_unit = available_data$spat_unit[[obj_i]], From 62591b1f4b2d1ef77bfac75188c65cb93934a0cc Mon Sep 17 00:00:00 2001 From: Iqra Amin <90134115+iqraAmin@users.noreply.github.com> Date: Wed, 17 Jul 2024 02:52:43 +0500 Subject: [PATCH 083/160] Update DESCRIPTION --- DESCRIPTION | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 048e5b5e..0bc1343c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -26,9 +26,9 @@ Encoding: UTF-8 Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.2 Depends: - base (>= 4.4.0), - utils (>= 4.4.0), - R (>= 4.4.0), + base (>= 4.3.1), + utils (>= 4.3.1), + R (>= 4.3.1), Imports: checkmate, data.table (>= 1.12.2), From 2181c618b225d484d9687d17c5d5ebdd3c964ed9 Mon Sep 17 00:00:00 2001 From: Iqra Amin <90134115+iqraAmin@users.noreply.github.com> Date: Wed, 17 Jul 2024 03:00:00 +0500 Subject: [PATCH 084/160] Update DESCRIPTION --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 0bc1343c..714c462f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -34,7 +34,7 @@ Imports: data.table (>= 1.12.2), dbscan (>= 1.1-3), deldir (>= 1.0.6), - GiottoUtils (>= 0.1.10), + GiottoUtils (>= 0.1.9), graphics, grDevices, igraph (>= 1.2.4.1), From d3470f8e7305505780076b6283e467d1b1c4f198 Mon Sep 17 00:00:00 2001 From: Iqra Amin <90134115+iqraAmin@users.noreply.github.com> Date: Wed, 17 Jul 2024 15:26:28 +0500 Subject: [PATCH 085/160] Update DESCRIPTION --- DESCRIPTION | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 714c462f..048e5b5e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -26,15 +26,15 @@ Encoding: UTF-8 Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.2 Depends: - base (>= 4.3.1), - utils (>= 4.3.1), - R (>= 4.3.1), + base (>= 4.4.0), + utils (>= 4.4.0), + R (>= 4.4.0), Imports: checkmate, data.table (>= 1.12.2), dbscan (>= 1.1-3), deldir (>= 1.0.6), - GiottoUtils (>= 0.1.9), + GiottoUtils (>= 0.1.10), graphics, grDevices, igraph (>= 1.2.4.1), From ee267b1551dd07890db730defa2f568bb8855d1f Mon Sep 17 00:00:00 2001 From: iqraAmin Date: Wed, 17 Jul 2024 08:37:48 -0400 Subject: [PATCH 086/160] Updated Seurat Functions to Work with COSMX Data --- R/interoperability.R | 88 ++++++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/R/interoperability.R b/R/interoperability.R index 30edf4bb..4e78f5c7 100644 --- a/R/interoperability.R +++ b/R/interoperability.R @@ -23,8 +23,8 @@ #' @export gefToGiotto <- function( - gef_file, - bin_size = "bin100", + gef_file, + bin_size = "bin100", verbose = FALSE, h5_file = NULL) { # data.table vars @@ -1473,7 +1473,7 @@ giottoToSeuratV5 <- function( feat_type <- name <- dim_type <- nn_type <- NULL res_type <- match.arg(res_type, choices = c("hires", "lowres", "fullres")) - + # set default spat_unit and feat_type to be extracted as a Seurat assay spat_unit <- set_default_spat_unit( gobject = gobject, @@ -1589,7 +1589,8 @@ giottoToSeuratV5 <- function( ) } sobj <- Seurat::AddMetaData(sobj, - metadata = meta_cells[Seurat::Cells(sobj), ] + metadata = meta_cells[Seurat::Cells(sobj), ], + col.name = names(meta_cells) ) # add feature metadata @@ -1603,11 +1604,19 @@ giottoToSeuratV5 <- function( ) ) rownames(meta_genes) <- meta_genes$feat_ID - for (i in seq(sobj@assays)) { - sobj@assays[[i]]@meta.data <- meta_genes + for (i in seq_along(sobj@assays)) { + assay_slot <- sobj@assays[[i]] + + # Check if assay_slot has @meta.data or @meta.features + if ("meta.data" %in% slotNames(assay_slot)) { + assay_slot@meta.data <- meta_genes + } else if ("meta.features" %in% slotNames(assay_slot)) { + assay_slot@meta.features <- meta_genes + } else { + warning(paste("No suitable metadata slot found for assay", i)) + } } - # dim reduction # note: Seurat requires assay name specification for each dim reduc avail_dr <- list_dim_reductions( @@ -1700,12 +1709,12 @@ giottoToSeuratV5 <- function( copy_obj = TRUE, ... # allow setting of spat_loc_name through additional params ) - + # flip y vals - + loc_use <- flip(loc_use)[] %>% data.table::setDF() - + rownames(loc_use) <- loc_use$cell_ID sobj <- Seurat::AddMetaData(sobj, metadata = loc_use) # add spatial coordinates as new dim reduct object @@ -1759,9 +1768,9 @@ giottoToSeuratV5 <- function( imagerow <- loc_use$sdimy imagecol <- loc_use$sdimx img_array <- as(gimg, "array") - img_array <- img_array / 255 + img_array <- img_array / 255 coord <- data.frame( - imagerow = imagerow, imagecol = imagecol, + imagerow = imagerow, imagecol = imagecol, row.names = loc_use$cell_ID ) scalef <- .estimate_scalefactors( @@ -1786,8 +1795,8 @@ giottoToSeuratV5 <- function( Class = "VisiumV1", image = img_array, scale.factors = scalefactors, - coordinates = coord, - spot.radius = + coordinates = coord, + spot.radius = scalef$fiducial * scalef$lowres / max(dim(img_array)), key = paste0(key, "_") ) @@ -1807,11 +1816,11 @@ giottoToSeuratV5 <- function( #' @noRd .estimate_scalefactors <- function( - x, + x, res_type = c("hires", "lowres", "fullres"), spatlocs ){ - res_type <- match.arg(res_type, + res_type <- match.arg(res_type, choices = c("hires", "lowres", "fullres")) pxdims <- dim(x)[1:2] edims <- range(ext(x)) @@ -1825,9 +1834,9 @@ giottoToSeuratV5 <- function( # No way to guess hires or lowres scalefs so use arbitrary values. hres_scalef <- switch(res_type, "hires" = scalef, - "lowres" = scalef * res_ratio, + "lowres" = scalef * res_ratio, "fullres" = 0.08250825 # arbitrary - + ) lres_scalef <- switch(res_type, "hires" = scalef / res_ratio, @@ -1841,15 +1850,15 @@ giottoToSeuratV5 <- function( coords <- data.table::as.data.table(spatlocs) # create a delaunay dnet <- createNetwork( - as.matrix(coords[, c("sdimx", "sdimy")]), + as.matrix(coords[, c("sdimx", "sdimy")]), type = "delaunay", method = "geometry", - include_distance = TRUE, - as.igraph = FALSE, - include_weight = TRUE, + include_distance = TRUE, + as.igraph = FALSE, + include_weight = TRUE, verbose = FALSE ) - + # expect center to center be most common edge distance # this gives CC dist as fullres px distance distances <- sort(unique(dnet$distance)) @@ -1866,7 +1875,7 @@ scalef_list <- list( lowres = lres_scalef ) return(scalef_list) - + } @@ -2193,10 +2202,10 @@ seuratToGiottoV5 <- function( nn_network = NULL, verbose = TRUE) { package_check("Seurat") - + # NSE vars sdimy <- NULL - + if (is.null(Seurat::GetAssayData( object = sobject, slot = "counts", assay = spatial_assay @@ -2236,7 +2245,7 @@ seuratToGiottoV5 <- function( cell_metadata <- sobject@meta.data cell_metadata <- data.table::as.data.table( cell_metadata, keep.rownames = TRUE) - + # Feat Metadata feat_metadata <- sobject[[]] feat_metadata <- data.table::as.data.table( @@ -2310,18 +2319,18 @@ seuratToGiottoV5 <- function( } spat_loc <- data.table::as.data.table(spat_coord) - + # seurat has coords following imaging conventions # flip them for Giotto spat_loc[, sdimy := -sdimy] data.table::setcolorder( spat_loc, neworder = c("sdimx", - "sdimy", + "sdimy", "cell_ID" ) ) - + } else { message("Images for RNA assay not found in the data. Skipping image processing.") @@ -2401,19 +2410,20 @@ seuratToGiottoV5 <- function( } # Find SueratImages, extract them, and pass to create image - + image_list <- list() for (i in names(sobject@images)) { simg <- sobject[[i]] # check if image slot has image in it if ("image" %in% slotNames(simg)) { img_array <- slot(simg, "image") - if (!is.null(img_array)) { + if (!is.null(img_array)) { scalef <- Seurat::ScaleFactors(simg) gImg <- createGiottoLargeImage( raster_object = terra::rast(img_array) * 255, name = i, scale_factor = 1 / scalef$lowres ) + image_list[[i]] <- gImg } } } @@ -2531,11 +2541,11 @@ seuratToGiottoV5 <- function( } } gobject <- addCellMetadata( - gobject = gobject, new_metadata = cell_metadata, + gobject = gobject, new_metadata = cell_metadata, by_column = TRUE, column_cell_ID = "rn") - + gobject <- addFeatMetadata( - gobject = gobject, new_metadata = feat_metadata, + gobject = gobject, new_metadata = feat_metadata, by_column = TRUE, column_feat_ID = "rn") if (exists("gpoints")) { @@ -2555,7 +2565,7 @@ seuratToGiottoV5 <- function( if (exists("gImg")) { gobject <- addGiottoLargeImage( gobject = gobject, - largeImages = list(gImg) + largeImages = image_list ) } return(gobject) @@ -3391,7 +3401,7 @@ spatialdataToGiotto <- function( feat_type = NULL, python_path = NULL, env_name = NULL) { - + # File check if (is.null(spatialdata_path)) { stop("Please provide a path to SpatialData object for conversion.\n") @@ -3716,7 +3726,7 @@ giottoToSpatialData <- function( python_path = NULL, env_name = NULL, save_directory = NULL) { - + # Initialize reticulate instrs <- createGiottoInstructions(python_path = python_path) @@ -3758,7 +3768,7 @@ giottoToSpatialData <- function( overwrite = TRUE, verbose = TRUE ) - + spat_locs <- getSpatialLocations(gobject, output="data.table") # Create SpatialData object From 15c5d9ab9016375683013444d1351e7e0ac2e3bd Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 17 Jul 2024 10:42:02 -0400 Subject: [PATCH 087/160] chore: change xml pkg --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 048e5b5e..521a3587 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -79,7 +79,7 @@ Suggests: SummarizedExperiment, testthat (>= 3.0.0), qs, - XML + xml2 Config/testthat/edition: 3 Collate: 'package_imports.R' From dc62ff360d39e820a51d68fe090356ba45c70252 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 17 Jul 2024 10:46:10 -0400 Subject: [PATCH 088/160] enh: update meta reader --- R/images.R | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/R/images.R b/R/images.R index 9422d11a..0b06b289 100644 --- a/R/images.R +++ b/R/images.R @@ -2796,19 +2796,26 @@ ometif_to_tif <- function(input_file, #' @name ometif_metadata #' @title Read metadata of an ometif #' @description Use the python package tifffile to get the the XML metadata -#' of a .ome.tif file. The R package XML is then used to parse the metadata +#' of a .ome.tif file. The R package xml2 is then used to parse the metadata #' as a list. #' @param path character. filepath to .ome.tif image #' @returns list of image metadata information #' @export -ometif_metadata <- function(path) { +ometif_metadata <- function(path, output = c("xml", "list")) { checkmate::assert_file_exists(path) package_check( - pkg_name = c("tifffile", "XML"), - repository = c("pip:tifffile", "CRAN:XML") + pkg_name = c("tifffile", "xml2"), + repository = c("pip:tifffile", "CRAN:xml2") ) TIF <- reticulate::import("tifffile", convert = TRUE, delay_load = TRUE) img <- TIF$TiffFile(path) - XML::xmlToList(img$ome_metadata) + out <- xml2::read_xml(img$ome_metadata) + + if (output == "list") out <- xml2::as_list(out) + return(out) } + +. + + From 4ad8199e404bc2766e434bad92b1581b0af9bff4 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 17 Jul 2024 14:44:46 -0400 Subject: [PATCH 089/160] fix: remove stray period --- R/images.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/images.R b/R/images.R index 0b06b289..136e5959 100644 --- a/R/images.R +++ b/R/images.R @@ -2816,6 +2816,6 @@ ometif_metadata <- function(path, output = c("xml", "list")) { return(out) } -. + From 3156ed826e123774a3849901ebf2b7f0a8359845 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 18 Jul 2024 02:25:31 -0400 Subject: [PATCH 090/160] enh: `flip()` for `giottoAffineImage` --- R/methods-flip.R | 50 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/R/methods-flip.R b/R/methods-flip.R index ddfbaf77..457bc125 100644 --- a/R/methods-flip.R +++ b/R/methods-flip.R @@ -154,7 +154,7 @@ setMethod( } ) -#' @describeIn flip Flip a SpatExtent +#' @rdname flip #' @export setMethod( "flip", signature(x = "SpatExtent"), @@ -163,6 +163,54 @@ setMethod( } ) +#' @rdname flip +#' @export +setMethod("flip", signature("giottoLargeImage"), function( + x, direction = "vertical", x0 = 0, y0 = 0 +) { + a <- get_args_list() + a$x <- as(x, "giottoAffineImage") # convert to giottoAffineImage + res <- do.call(flip, args = a) + return(res) +}) + +#' @rdname flip +#' @export +setMethod("flip", signature("giottoAffineImage"), function( + x, direction = "vertical", x0 = 0, y0 = 0 +) { + a <- get_args_list() + a$x <- x@affine + # update affine + x@affine <- do.call(flip, args = a) + + return(initialize(x)) +}) + +#' @rdname flip +#' @export +setMethod("flip", signature("affine2d"), function( + x, direction = "vertical", x0 = 0, y0 = 0 +) { + direction <- match.arg(direction, choices = c("vertical", "horizontal")) + + aff <- x@affine + switch(direction, + "vertical" = { + flip_m <- diag(c(1, -1)) + xyshift <- c(0, y0 * 2) + .aff_shift_2d(aff) * c(1, -1) + }, + "horizontal" = { + flip_m <- diag(c(-1, 1)) + xyshift <- c(x0 * 2, 0) + .aff_shift_2d(aff) * c(-1, 1) + } + ) + .aff_linear_2d(aff) <- .aff_linear_2d(aff) %*% flip_m + .aff_shift_2d(aff) <- xyshift + + x@affine <- aff + return(initialize(x)) +}) # internals #### From 47745ac74b0620dffe0fec033af1bd9b5a19bc25 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 18 Jul 2024 02:28:44 -0400 Subject: [PATCH 091/160] chore: document --- NEWS.md | 4 ++-- man/flip.Rd | 12 +++++++++--- man/ometif_metadata.Rd | 4 ++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/NEWS.md b/NEWS.md index e5fd23e1..70072a11 100644 --- a/NEWS.md +++ b/NEWS.md @@ -22,9 +22,9 @@ - `giottoAffineImage` class for just-in-time affine transformed images - `initialize()`, method for `giottoLargeImage` - `initialize()`, `[`, `$`, `show()`, `plot()` methods for `affine2d` -- `initialize()`, `ext()`, `crop()`, `rescale()`, `spatShift()`, `plot()` methods for `giottoAffineImage` +- `initialize()`, `ext()`, `crop()`, `rescale()`, `spatShift()`, `plot()`, methods for `giottoAffineImage` - `rescale()` method for `giottoImage` -- `spin()`, `shear()`, `affine()` methods for `giottoAffineImage` and `giottoLargeImage` (which converts to `giottoAffineImage`) +- `spin()`, `shear()`, `affine()`, `flip()` methods for `giottoAffineImage` and `giottoLargeImage` (which converts to `giottoAffineImage`) - `as()` conversion from `giottoLargeImage` to `giottoAffineImage` - `.get_centroid_xy()` internal for getting numeric centroid xy values of any object that responds to `ext()` - `.bound_poly()` internal for generating a dummy polygon from the extent of any object that responds to `ext()` diff --git a/man/flip.Rd b/man/flip.Rd index c465eb45..fbbfeaa9 100644 --- a/man/flip.Rd +++ b/man/flip.Rd @@ -9,6 +9,8 @@ \alias{flip,spatialNetworkObj-method} \alias{flip,giottoLargeImage-method} \alias{flip,SpatExtent-method} +\alias{flip,giottoAffineImage-method} +\alias{flip,affine2d-method} \title{Flip an object} \usage{ \S4method{flip}{giotto}( @@ -29,9 +31,15 @@ \S4method{flip}{spatialNetworkObj}(x, direction = "vertical", x0 = 0, y0 = 0, ...) -\S4method{flip}{giottoLargeImage}(x, direction = "vertical", x0 = 0, y0 = 0, ...) +\S4method{flip}{giottoLargeImage}(x, direction = "vertical", x0 = 0, y0 = 0) \S4method{flip}{SpatExtent}(x, direction = "vertical", x0 = 0, y0 = 0) + +\S4method{flip}{giottoLargeImage}(x, direction = "vertical", x0 = 0, y0 = 0) + +\S4method{flip}{giottoAffineImage}(x, direction = "vertical", x0 = 0, y0 = 0) + +\S4method{flip}{affine2d}(x, direction = "vertical", x0 = 0, y0 = 0) } \arguments{ \item{x}{object} @@ -70,8 +78,6 @@ direction param input. Note that this behavior may be different from terra's \item \code{flip(giottoLargeImage)}: Flip a giottoLargeImage -\item \code{flip(SpatExtent)}: Flip a SpatExtent - }} \examples{ g <- GiottoData::loadSubObjectMini("spatLocsObj") diff --git a/man/ometif_metadata.Rd b/man/ometif_metadata.Rd index d5109961..6404c400 100644 --- a/man/ometif_metadata.Rd +++ b/man/ometif_metadata.Rd @@ -4,7 +4,7 @@ \alias{ometif_metadata} \title{Read metadata of an ometif} \usage{ -ometif_metadata(path) +ometif_metadata(path, output = c("xml", "list")) } \arguments{ \item{path}{character. filepath to .ome.tif image} @@ -14,6 +14,6 @@ list of image metadata information } \description{ Use the python package tifffile to get the the XML metadata -of a .ome.tif file. The R package XML is then used to parse the metadata +of a .ome.tif file. The R package xml2 is then used to parse the metadata as a list. } From e6b50cce784066c22e133e47db9e9d271e5ad680 Mon Sep 17 00:00:00 2001 From: iqraAmin Date: Thu, 18 Jul 2024 14:09:05 -0400 Subject: [PATCH 092/160] Error Fixed in giottoToSpatialExperiment() --- R/interoperability.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/interoperability.R b/R/interoperability.R index 4e78f5c7..5ccf189a 100644 --- a/R/interoperability.R +++ b/R/interoperability.R @@ -2726,7 +2726,7 @@ giottoToSpatialExperiment <- function(giottoObj, verbose = TRUE) { ) } SpatialExperiment::spatialCoords(spe) <- data.matrix( - spatialLocs[, seq_len(2)] + spatialLocs[, 0:2] ) } else { if (verbose) { From 7825894b2f3ef99ba8f4d7098494238e3df133db Mon Sep 17 00:00:00 2001 From: iqraAmin Date: Thu, 18 Jul 2024 19:37:52 -0400 Subject: [PATCH 093/160] Update Seurat Functions --- R/interoperability.R | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/R/interoperability.R b/R/interoperability.R index 5ccf189a..0ae589ba 100644 --- a/R/interoperability.R +++ b/R/interoperability.R @@ -1605,13 +1605,13 @@ giottoToSeuratV5 <- function( ) rownames(meta_genes) <- meta_genes$feat_ID for (i in seq_along(sobj@assays)) { - assay_slot <- sobj@assays[[i]] + #assay_slot <- sobj@assays[[i]] # Check if assay_slot has @meta.data or @meta.features - if ("meta.data" %in% slotNames(assay_slot)) { - assay_slot@meta.data <- meta_genes - } else if ("meta.features" %in% slotNames(assay_slot)) { - assay_slot@meta.features <- meta_genes + if ("meta.data" %in% slotNames(sobj@assays[[i]])) { + sobj@assays[[i]]@meta.data <- meta_genes + } else if ("meta.features" %in% slotNames(sobj@assays[[i]])) { + sobj@assays[[i]]@meta.features <- meta_genes } else { warning(paste("No suitable metadata slot found for assay", i)) } @@ -2545,8 +2545,7 @@ seuratToGiottoV5 <- function( by_column = TRUE, column_cell_ID = "rn") gobject <- addFeatMetadata( - gobject = gobject, new_metadata = feat_metadata, - by_column = TRUE, column_feat_ID = "rn") + gobject = gobject, new_metadata = feat_metadata) if (exists("gpoints")) { gobject <- addGiottoPoints( From 35313373f7603377c43008b192b2798314c0b20d Mon Sep 17 00:00:00 2001 From: iqraAmin Date: Fri, 19 Jul 2024 08:23:41 -0400 Subject: [PATCH 094/160] Update SpatialExperimentToGiotto Function --- R/interoperability.R | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/R/interoperability.R b/R/interoperability.R index 0ae589ba..ee982dff 100644 --- a/R/interoperability.R +++ b/R/interoperability.R @@ -1605,7 +1605,6 @@ giottoToSeuratV5 <- function( ) rownames(meta_genes) <- meta_genes$feat_ID for (i in seq_along(sobj@assays)) { - #assay_slot <- sobj@assays[[i]] # Check if assay_slot has @meta.data or @meta.features if ("meta.data" %in% slotNames(sobj@assays[[i]])) { @@ -2724,9 +2723,15 @@ giottoToSpatialExperiment <- function(giottoObj, verbose = TRUE) { spatialUnits[su], "'" ) } - SpatialExperiment::spatialCoords(spe) <- data.matrix( - spatialLocs[, 0:2] - ) + if (all(colnames(spatialLocs[, seq_along(2)]) == c("sdimx", "sdimy"))) { + spatialLocs <- spatialLocs[, c("sdimx", "sdimy"), drop = FALSE] + } else { + # Rename the first two columns to sdimx and sdimy + colnames(spatialLocs)[seq_along(2)] <- c("sdimx", "sdimy") + spatialLocs <- spatialLocs[, c("sdimx", "sdimy"), drop = FALSE] + } + SpatialExperiment::spatialCoords(spe) <- data.matrix(spatialLocs) + } else { if (verbose) { message("No spatial locations found in the input Giotto object") From 8b0f251b912ed470126e99eca672e2cf5f17315d Mon Sep 17 00:00:00 2001 From: iqraAmin Date: Sun, 21 Jul 2024 18:14:54 -0400 Subject: [PATCH 095/160] Update Seurat Functions --- R/interoperability.R | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/R/interoperability.R b/R/interoperability.R index ee982dff..33b97996 100644 --- a/R/interoperability.R +++ b/R/interoperability.R @@ -2482,8 +2482,14 @@ seuratToGiottoV5 <- function( es = igraph::E(sobjIgraph), names = TRUE ) + DT$from <- edges[, 1] DT$to <- edges[, 2] + num_rows <- nrow(DT) + DT$sdimx_begin <- as.numeric(rep(NA, num_rows)) + DT$sdimy_begin <- as.numeric(rep(NA, num_rows)) + DT$sdimx_end <- as.numeric(rep(NA, num_rows)) + DT$sdimy_end <- as.numeric(rep(NA, num_rows)) ed_attr <- igraph::edge.attributes(sobjIgraph) DT$weight <- ed_attr[1] DT$distance <- ed_attr[2] From 042378e316cdffb8eca4189a6773b98e6df6b196 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 22 Jul 2024 08:30:17 -0400 Subject: [PATCH 096/160] feat: improve `ometif_metadata()` --- R/images.R | 36 +++++++++++++++++++++++++++++------- R/methods-flip.R | 10 +++++----- man/flip.Rd | 13 ------------- man/ometif_metadata.Rd | 19 ++++++++++++++++--- man/ometif_to_tif.Rd | 5 +++++ 5 files changed, 55 insertions(+), 28 deletions(-) diff --git a/R/images.R b/R/images.R index 136e5959..a6a1a9b0 100644 --- a/R/images.R +++ b/R/images.R @@ -2737,6 +2737,7 @@ add_img_array_alpha <- function(x, #' @param overwrite logical. Default = FALSE. Whether to overwrite if the #' filename already exists. #' @returns returns the written filepath invisibly +#' @family ometif utility functions #' @export ometif_to_tif <- function(input_file, output_dir = file.path(dirname(input_file), "tif_exports"), @@ -2796,12 +2797,21 @@ ometif_to_tif <- function(input_file, #' @name ometif_metadata #' @title Read metadata of an ometif #' @description Use the python package tifffile to get the the XML metadata -#' of a .ome.tif file. The R package xml2 is then used to parse the metadata -#' as a list. +#' of a .ome.tif file. The R package xml2 is then used to work with it to +#' retrieve specific nodes in the xml data and extract data. #' @param path character. filepath to .ome.tif image +#' @param node character vector. Specific xml node to get. More terms can be +#' added to get a node from a specific hierarchy. +#' @param output character. One of "data.frame" to return a data.frame of the +#' attributes information of the xml node, "xmL" for an xml2 representation +#' of the node, or "list" for an R native list (note that many items in the +#' list may have overlapping names that make indexing difficult). #' @returns list of image metadata information +#' @family ometif utility functions #' @export -ometif_metadata <- function(path, output = c("xml", "list")) { +ometif_metadata <- function( + path, node = NULL, output = c("data.frame", "xml", "list") +) { checkmate::assert_file_exists(path) package_check( pkg_name = c("tifffile", "xml2"), @@ -2810,10 +2820,22 @@ ometif_metadata <- function(path, output = c("xml", "list")) { TIF <- reticulate::import("tifffile", convert = TRUE, delay_load = TRUE) img <- TIF$TiffFile(path) - out <- xml2::read_xml(img$ome_metadata) - - if (output == "list") out <- xml2::as_list(out) - return(out) + x <- xml2::read_xml(img$ome_metadata) + + if (!is.null(node)) { + node <- paste(node, collapse = "/") + x <- xml2::xml_find_all(x, sprintf("//d1:%s", node), ns = xml_ns(x)) + } + + switch(output, + "data.frame" = { + x = Reduce("rbind", xml2::xml_attrs(x)) + rownames(x) <- NULL + return(x) + }, + "xml" = return(x), + "list" = return(xml2::as_list(x)) + ) } diff --git a/R/methods-flip.R b/R/methods-flip.R index 457bc125..ff7609cd 100644 --- a/R/methods-flip.R +++ b/R/methods-flip.R @@ -108,7 +108,7 @@ setMethod( } ) -#' @describeIn flip Flip a giottoPolygon object +#' @rdname flip #' @export setMethod( "flip", signature(x = "giottoPolygon"), @@ -117,7 +117,7 @@ setMethod( } ) -#' @describeIn flip Flip a giottoPoints object +#' @rdname flip #' @export setMethod( "flip", signature(x = "giottoPoints"), @@ -126,7 +126,7 @@ setMethod( } ) -#' @describeIn flip Flip a spatLocsObj +#' @rdname flip #' @export setMethod( "flip", signature(x = "spatLocsObj"), @@ -135,7 +135,7 @@ setMethod( } ) -#' @describeIn flip Flip a spatialNetworkObj +#' @rdname flip #' @export setMethod( "flip", signature(x = "spatialNetworkObj"), @@ -145,7 +145,7 @@ setMethod( ) # TODO apply as instructions for lazy eval after crop/resampling -#' @describeIn flip Flip a giottoLargeImage +#' @rdname flip #' @export setMethod( "flip", signature(x = "giottoLargeImage"), diff --git a/man/flip.Rd b/man/flip.Rd index fbbfeaa9..1fa10182 100644 --- a/man/flip.Rd +++ b/man/flip.Rd @@ -66,19 +66,6 @@ flipped object Flip an object over a designated x or y value depending on direction param input. Note that this behavior may be different from terra's } -\section{Methods (by class)}{ -\itemize{ -\item \code{flip(giottoPolygon)}: Flip a giottoPolygon object - -\item \code{flip(giottoPoints)}: Flip a giottoPoints object - -\item \code{flip(spatLocsObj)}: Flip a spatLocsObj - -\item \code{flip(spatialNetworkObj)}: Flip a spatialNetworkObj - -\item \code{flip(giottoLargeImage)}: Flip a giottoLargeImage - -}} \examples{ g <- GiottoData::loadSubObjectMini("spatLocsObj") diff --git a/man/ometif_metadata.Rd b/man/ometif_metadata.Rd index 6404c400..1b06dd79 100644 --- a/man/ometif_metadata.Rd +++ b/man/ometif_metadata.Rd @@ -4,16 +4,29 @@ \alias{ometif_metadata} \title{Read metadata of an ometif} \usage{ -ometif_metadata(path, output = c("xml", "list")) +ometif_metadata(path, node = NULL, output = c("data.frame", "xml", "list")) } \arguments{ \item{path}{character. filepath to .ome.tif image} + +\item{node}{character vector. Specific xml node to get. More terms can be +added to get a node from a specific hierarchy.} + +\item{output}{character. One of "data.frame" to return a data.frame of the +attributes information of the xml node, "xmL" for an xml2 representation +of the node, or "list" for an R native list (note that many items in the +list may have overlapping names that make indexing difficult).} } \value{ list of image metadata information } \description{ Use the python package tifffile to get the the XML metadata -of a .ome.tif file. The R package xml2 is then used to parse the metadata -as a list. +of a .ome.tif file. The R package xml2 is then used to work with it to +retrieve specific nodes in the xml data and extract data. } +\seealso{ +Other ometif utility functions: +\code{\link{ometif_to_tif}()} +} +\concept{ometif utility functions} diff --git a/man/ometif_to_tif.Rd b/man/ometif_to_tif.Rd index 0c622352..f9c6cc57 100644 --- a/man/ometif_to_tif.Rd +++ b/man/ometif_to_tif.Rd @@ -31,3 +31,8 @@ Simple converter from .ome.tif to .tif format. Utilizes the python \pkg{tifffile} package. Performs image conversions one page at a time. Wrap this in a for loop or lapply for more than one image or page. } +\seealso{ +Other ometif utility functions: +\code{\link{ometif_metadata}()} +} +\concept{ometif utility functions} From 4365cceabf64bfe454d487ae43e73139fd071c4d Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 22 Jul 2024 09:01:32 -0400 Subject: [PATCH 097/160] fix: `ometif_metadata()` --- R/images.R | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/R/images.R b/R/images.R index a6a1a9b0..8a19cdfa 100644 --- a/R/images.R +++ b/R/images.R @@ -2820,11 +2820,15 @@ ometif_metadata <- function( TIF <- reticulate::import("tifffile", convert = TRUE, delay_load = TRUE) img <- TIF$TiffFile(path) + output <- match.arg(output, choices = c("data.frame", "xml", "list")) x <- xml2::read_xml(img$ome_metadata) if (!is.null(node)) { node <- paste(node, collapse = "/") - x <- xml2::xml_find_all(x, sprintf("//d1:%s", node), ns = xml_ns(x)) + x <- xml2::xml_find_all( + x, sprintf("//d1:%s", node), + ns = xml2::xml_ns(x) + ) } switch(output, From 3b78c866698dc5f51fab7b7a42644224de3cdad2 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 22 Jul 2024 09:15:38 -0400 Subject: [PATCH 098/160] fix: `ometif_metadata()` DF output --- R/images.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/images.R b/R/images.R index 8a19cdfa..76102b86 100644 --- a/R/images.R +++ b/R/images.R @@ -2835,6 +2835,7 @@ ometif_metadata <- function( "data.frame" = { x = Reduce("rbind", xml2::xml_attrs(x)) rownames(x) <- NULL + x <- as.data.frame(x) return(x) }, "xml" = return(x), From 402d28dd2aed2eec1b449dbb2e9d9e8529b94685 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 22 Jul 2024 09:38:26 -0400 Subject: [PATCH 099/160] enh: `ometif_metadata()` can now show structure --- R/images.R | 14 ++++++++++---- man/ometif_metadata.Rd | 12 +++++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/R/images.R b/R/images.R index 76102b86..ff4c72c9 100644 --- a/R/images.R +++ b/R/images.R @@ -2804,13 +2804,15 @@ ometif_to_tif <- function(input_file, #' added to get a node from a specific hierarchy. #' @param output character. One of "data.frame" to return a data.frame of the #' attributes information of the xml node, "xmL" for an xml2 representation -#' of the node, or "list" for an R native list (note that many items in the -#' list may have overlapping names that make indexing difficult). +#' of the node, "list" for an R native list (note that many items in the +#' list may have overlapping names that make indexing difficult), or +#' "structure" to invisibly return NULL, but print the structure of the XML +#' document or node. #' @returns list of image metadata information #' @family ometif utility functions #' @export ometif_metadata <- function( - path, node = NULL, output = c("data.frame", "xml", "list") + path, node = NULL, output = c("data.frame", "xml", "list", "structure") ) { checkmate::assert_file_exists(path) package_check( @@ -2839,7 +2841,11 @@ ometif_metadata <- function( return(x) }, "xml" = return(x), - "list" = return(xml2::as_list(x)) + "list" = return(xml2::as_list(x)), + "structure" = { + xml2::xml_structure(x) + return(invisible()) + } ) } diff --git a/man/ometif_metadata.Rd b/man/ometif_metadata.Rd index 1b06dd79..d2077c2f 100644 --- a/man/ometif_metadata.Rd +++ b/man/ometif_metadata.Rd @@ -4,7 +4,11 @@ \alias{ometif_metadata} \title{Read metadata of an ometif} \usage{ -ometif_metadata(path, node = NULL, output = c("data.frame", "xml", "list")) +ometif_metadata( + path, + node = NULL, + output = c("data.frame", "xml", "list", "structure") +) } \arguments{ \item{path}{character. filepath to .ome.tif image} @@ -14,8 +18,10 @@ added to get a node from a specific hierarchy.} \item{output}{character. One of "data.frame" to return a data.frame of the attributes information of the xml node, "xmL" for an xml2 representation -of the node, or "list" for an R native list (note that many items in the -list may have overlapping names that make indexing difficult).} +of the node, "list" for an R native list (note that many items in the +list may have overlapping names that make indexing difficult), or +"structure" to invisibly return NULL, but print the structure of the XML +document or node.} } \value{ list of image metadata information From 49074c706375fae34d42c931c70c730d1be8f7e6 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 22 Jul 2024 12:30:50 -0400 Subject: [PATCH 100/160] fix: access to structure option --- R/images.R | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/R/images.R b/R/images.R index ff4c72c9..70531fbc 100644 --- a/R/images.R +++ b/R/images.R @@ -2822,7 +2822,9 @@ ometif_metadata <- function( TIF <- reticulate::import("tifffile", convert = TRUE, delay_load = TRUE) img <- TIF$TiffFile(path) - output <- match.arg(output, choices = c("data.frame", "xml", "list")) + output <- match.arg( + output, choices = c("data.frame", "xml", "list", "structure") + ) x <- xml2::read_xml(img$ome_metadata) if (!is.null(node)) { From 4168c67838b7842e172cd9d0e64cb0842c707435 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 22 Jul 2024 17:42:47 -0400 Subject: [PATCH 101/160] fix: `plotGiottoImage()` --- R/images.R | 5 ++--- R/methods-plot.R | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/R/images.R b/R/images.R index 70531fbc..226c084c 100644 --- a/R/images.R +++ b/R/images.R @@ -2025,19 +2025,18 @@ plotGiottoImage <- function(gobject = NULL, if (!is.null(gobject)) { img_obj <- getGiottoImage( gobject = gobject, - image_type = image_type, name = image_name ) + if (inherits(img_obj, "giottoLargeImage")) image_type = "largeImage" + if (inherits(img_obj, "giottoImage")) image_type = "image" } if (!is.null(giottoImage)) { img_obj <- giottoImage image_type <- "image" - image_name <- img_obj@name } if (!is.null(giottoLargeImage)) { img_obj <- giottoLargeImage image_type <- "largeImage" - image_name <- img_obj@name } # Select plotting function diff --git a/R/methods-plot.R b/R/methods-plot.R index 9be6540b..809e9049 100644 --- a/R/methods-plot.R +++ b/R/methods-plot.R @@ -507,7 +507,7 @@ setMethod("plot", signature(x = "affine2d", y = "missing"), function(x, ...) { # Determine likely image bitdepth if (is.null(max_intensity)) { - bitDepth <- ceiling(log(x = a$x@max_intensity, base = 2)) + bitDepth <- ceiling(log(x = giottoLargeImage@max_intensity, base = 2)) # Assign discovered bitdepth as max_intensity max_intensity <- 2^bitDepth - 1 From 7e92d071d06f18455bef18332724b5667c29a003 Mon Sep 17 00:00:00 2001 From: iqraAmin Date: Tue, 23 Jul 2024 17:24:55 -0400 Subject: [PATCH 102/160] Update Seurat Function --- R/interoperability.R | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/R/interoperability.R b/R/interoperability.R index 33b97996..f33327a0 100644 --- a/R/interoperability.R +++ b/R/interoperability.R @@ -2196,7 +2196,7 @@ seuratToGiottoV5 <- function( sobject, spatial_assay = "Spatial", dim_reduction = c("pca", "umap"), - subcellular_assay = "Vizgen", + subcellular_assay = "SCT", sp_network = NULL, nn_network = NULL, verbose = TRUE) { @@ -2341,7 +2341,8 @@ seuratToGiottoV5 <- function( # if (!is.null(subcellular_assay)){ if (length(sobject@assays[[subcellular_assay]]) == 1) { spat_coord <- Seurat::GetTissueCoordinates(sobject) - colnames(spat_coord) <- c("sdimx", "sdimy", "cell_ID") + colnames(spat_coord) <- c("sdimx", "sdimy") + spat_coord$cell_ID <- rownames(spat_coord) exp <- exp[, c(intersect(spat_coord$cell_ID, colnames(exp)))] spat_loc <- spat_coord } From 842f0e2dbca5b6aecf9faaff6185d606eaa7f404 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 24 Jul 2024 20:26:43 -0400 Subject: [PATCH 103/160] feat: `t()` for `affine2d` and image classes - also update of `giotto` method to include `t()` of images --- NEWS.md | 6 +- R/methods-transpose.R | 72 ++++++++++++++++++---- man/{transpose-generic.Rd => transpose.Rd} | 19 ++++-- 3 files changed, 76 insertions(+), 21 deletions(-) rename man/{transpose-generic.Rd => transpose.Rd} (67%) diff --git a/NEWS.md b/NEWS.md index 70072a11..3fb164a6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -18,13 +18,13 @@ - `affine()` for `giottoPolygon`, `giottoPoints`, `spatLocsObj` - `shear()` for `giottoPoints`, `giottoPolygon`, `spatLocsObj`, `affine2d` - `affine2d` class for accumulating linear transforms to be used with `affine()` -- `spin()`, `rescale`, `spatShift()`, `affine()` methods for `affine2d` +- `initialize()`, `[`, `$`, `show()`, `plot()`, methods for `affine2d` +- `spin()`, `rescale`, `spatShift()`, `affine()`, `flip()`, `shear()` `t()` methods for `affine2d` - `giottoAffineImage` class for just-in-time affine transformed images - `initialize()`, method for `giottoLargeImage` -- `initialize()`, `[`, `$`, `show()`, `plot()` methods for `affine2d` - `initialize()`, `ext()`, `crop()`, `rescale()`, `spatShift()`, `plot()`, methods for `giottoAffineImage` - `rescale()` method for `giottoImage` -- `spin()`, `shear()`, `affine()`, `flip()` methods for `giottoAffineImage` and `giottoLargeImage` (which converts to `giottoAffineImage`) +- `spin()`, `shear()`, `affine()`, `flip()`, `t()` methods for `giottoAffineImage` and `giottoLargeImage` (which converts to `giottoAffineImage`) - `as()` conversion from `giottoLargeImage` to `giottoAffineImage` - `.get_centroid_xy()` internal for getting numeric centroid xy values of any object that responds to `ext()` - `.bound_poly()` internal for generating a dummy polygon from the extent of any object that responds to `ext()` diff --git a/R/methods-transpose.R b/R/methods-transpose.R index 33ecc66b..464fecb0 100644 --- a/R/methods-transpose.R +++ b/R/methods-transpose.R @@ -2,19 +2,21 @@ # S4 methods #' @title Transpose -#' @name transpose-generic +#' @name transpose +#' @description +#' Spatially transpose an object #' @param x object to be transposed #' @aliases t #' @returns transposed object #' @examples -#' m <- matrix(rnorm(10), nrow = 5) +#' sl <- GiottoData::loadSubObjectMini("spatLocsObj") #' -#' t(m) +#' plot(t(sl)) NULL - -#' @rdname transpose-generic +#* giotto #### +#' @rdname transpose #' @export setMethod( "t", signature("giotto"), @@ -77,14 +79,22 @@ setMethod( x <- setFeatureInfo(x, pt, verbose = FALSE, initialize = FALSE) } } - + + # images ----------------------------------------------------------- # + imgs <- get_giotto_image_list(x) + if (!is.null(imgs)) { + for (img in imgs) { + img <- t(img) + x <- setGiotto(x, img, verbose = FALSE) + } + } return(initialize(x)) # init not necessarily needed } ) - -#' @rdname transpose-generic +# * spatLocsObj #### +#' @rdname transpose #' @export setMethod("t", signature("spatLocsObj"), function(x) { sdimy <- sdimx <- NULL @@ -92,7 +102,9 @@ setMethod("t", signature("spatLocsObj"), function(x) { x@coordinates[, c("sdimx", "sdimy") := .(sdimy, sdimx)] return(x) }) -#' @rdname transpose-generic + +# * spatialNetworkObj #### +#' @rdname transpose #' @export setMethod("t", signature("spatialNetworkObj"), function(x) { sdimx_begin <- sdimx_end <- sdimy_begin <- sdimy_end <- NULL @@ -109,21 +121,55 @@ setMethod("t", signature("spatialNetworkObj"), function(x) { } return(x) }) -#' @rdname transpose-generic + +# * giottoPoints #### +#' @rdname transpose #' @export setMethod("t", signature("giottoPoints"), function(x) { x[] <- t(x[]) x }) -#' @rdname transpose-generic + +# * giottoPolygon #### +#' @rdname transpose #' @export setMethod("t", signature("giottoPolygon"), function(x) { x <- .do_gpoly(x, "t") x }) +# * giottoLargeImage #### +#' @rdname transpose +#' @export +setMethod("t", signature("giottoLargeImage"), function(x) { + x <- as(x, "giottoAffineImage") # convert to giottoAffineImage + x <- t(x) + return(x) +}) + +# * giottoAffineImage #### +#' @rdname transpose +#' @export +setMethod("t", signature("giottoAffineImage"), function(x) { + aff <- x@affine + # update affine + x@affine <- t(aff) + + return(initialize(x)) +}) + +# * affine2d #### +#' @rdname transpose +#' @export +setMethod("t", signature("affine2d"), function(x) { + x <- flip(x, direction = "vertical") + spin(x, -90, x0 = 0, y0 = 0) +}) + + + # s3 methods -#' @rdname transpose-generic +#' @rdname transpose #' @method t spatLocsObj #' @export t.spatLocsObj <- function(x) { @@ -134,7 +180,7 @@ t.spatLocsObj <- function(x) { } -#' @rdname transpose-generic +#' @rdname transpose #' @method t spatialNetworkObj #' @export t.spatialNetworkObj <- function(x) { diff --git a/man/transpose-generic.Rd b/man/transpose.Rd similarity index 67% rename from man/transpose-generic.Rd rename to man/transpose.Rd index 978d7a60..a85ebbb3 100644 --- a/man/transpose-generic.Rd +++ b/man/transpose.Rd @@ -1,13 +1,16 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/methods-transpose.R -\name{transpose-generic} -\alias{transpose-generic} +\name{transpose} +\alias{transpose} \alias{t} \alias{t,giotto-method} \alias{t,spatLocsObj-method} \alias{t,spatialNetworkObj-method} \alias{t,giottoPoints-method} \alias{t,giottoPolygon-method} +\alias{t,giottoLargeImage-method} +\alias{t,giottoAffineImage-method} +\alias{t,affine2d-method} \alias{t.spatLocsObj} \alias{t.spatialNetworkObj} \title{Transpose} @@ -22,6 +25,12 @@ \S4method{t}{giottoPolygon}(x) +\S4method{t}{giottoLargeImage}(x) + +\S4method{t}{giottoAffineImage}(x) + +\S4method{t}{affine2d}(x) + \method{t}{spatLocsObj}(x) \method{t}{spatialNetworkObj}(x) @@ -33,10 +42,10 @@ transposed object } \description{ -Transpose +Spatially transpose an object } \examples{ -m <- matrix(rnorm(10), nrow = 5) +sl <- GiottoData::loadSubObjectMini("spatLocsObj") -t(m) +plot(t(sl)) } From 0e628f9d4ee4d1dbb67b0a7c0fbe2b4be0cab79d Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 24 Jul 2024 22:04:59 -0400 Subject: [PATCH 104/160] enh: make `t()` fully work for `giotto` --- R/methods-transpose.R | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/R/methods-transpose.R b/R/methods-transpose.R index 464fecb0..b654258f 100644 --- a/R/methods-transpose.R +++ b/R/methods-transpose.R @@ -50,25 +50,25 @@ setMethod( initialize = FALSE ) } + } - # TODO remove this after spatial info is removed from - # spatialNetwork objs - sn_list <- get_spatial_network_list( - gobject = x, - spat_unit = ":all:", - output = "spatialNetworkObj", - copy_obj = FALSE - ) - if (length(sn_list) > 0) { - warning(wrap_txt( - "spatial locations have been modified. - Relevant spatial networks may need to be regenerated" - ), call. = FALSE) + # spatnets --------------------------------------------------------- # + # TODO remove this after spatial info is removed from + # spatialNetwork objs + sn_list <- get_spatial_network_list( + gobject = x, + spat_unit = ":all:", + output = "spatialNetworkObj", + copy_obj = FALSE + ) + if (length(sn_list) > 0) { + for (sn in sn_list) { + sn <- t(sn) + x <- setGiotto(x, sn, verbose = FALSE, initialize = FALSE) } } - # points ----------------------------------------------------------- # pts <- get_feature_info_list( gobject = x, return_giottoPoints = TRUE From 4f7e34c9d0fdcbf6122630a5f2f03998553d342f Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 25 Jul 2024 01:50:59 -0400 Subject: [PATCH 105/160] `affine()` `giotto` - document --- NEWS.md | 3 +- R/methods-affine.R | 126 +++++++++++++++++++++++++++++++++++++++++++-- R/methods-shear.R | 7 +++ man/affine.Rd | 37 +++++++++++-- 4 files changed, 163 insertions(+), 10 deletions(-) diff --git a/NEWS.md b/NEWS.md index 3fb164a6..a44e6ba8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -13,9 +13,10 @@ - `checkGiottoEnvironment()` in addition to full filepaths, also now supports name of environment or installation directory - `installGiottoEnvironment()`, `removeGiottoEnvironment()` now have `conda` param for setting path to conda executable and `envname` param for specifying environment by name - `installGiottoEnvironment()` now has `confirm` param for skipping path input checks +- `t()` for `giotto` now affects images as well. ## new -- `affine()` for `giottoPolygon`, `giottoPoints`, `spatLocsObj` +- `affine()` for `giottoPolygon`, `giottoPoints`, `spatLocsObj`, `giotto` - `shear()` for `giottoPoints`, `giottoPolygon`, `spatLocsObj`, `affine2d` - `affine2d` class for accumulating linear transforms to be used with `affine()` - `initialize()`, `[`, `$`, `show()`, `plot()`, methods for `affine2d` diff --git a/R/methods-affine.R b/R/methods-affine.R index 8e80e85a..ab626ba7 100644 --- a/R/methods-affine.R +++ b/R/methods-affine.R @@ -6,13 +6,14 @@ #' @name affine #' @description Apply an affine transformation matrix to a spatial object. #' Currently only works for 2D transforms. -#' @param x object -#' @param m `matrix` or coercible to `matrix`. Should be a matrix with either -#' 2 or 3 columns (linear or affine). +#' @param x object to affine transform or a `matrix` +#' @param y `matrix` or coercible to `matrix` (such as `affine2d`). Should +#' be a matrix with either 2 or 3 columns (linear or affine). #' @param inv logical. Whether the inverse of the affine transform should #' be applied. #' @param ... additional args to pass (none implemented) -#' @returns affine transformed object +#' @returns affine transformed object or an `affine2d` if a `matrix` was +#' passed to `x` #' @examples #' m <- diag(rep(1, 3)) #' trans_m <- matrix(c(1, 0, 0, 0, 1, 0, 200, 300, 1), nrow = 3) @@ -22,6 +23,11 @@ #' gpoints <- GiottoData::loadSubObjectMini("giottoPoints") #' gpoly <- GiottoData::loadSubObjectMini("giottoPolygon") #' sl <- GiottoData::loadSubObjectMini("spatLocsObj") +#' +#' # creation of affine2d +#' aff <- affine(m) +#' aff <- spin(flip(shear(aff, fx = 0.2)), 45) +#' plot(aff) # blue is start, red is end #' #' # giottoPoints ############################################## #' plot(gpoints) @@ -30,6 +36,7 @@ #' # giottoPolygon ############################################# #' plot(gpoly) #' plot(affine(gpoly, scale_m)) +#' plot(affine(gpoly, aff)) # affine() with `affine2d` #' #' # spatLocsObj ############################################### #' plot(affine(sl, m)) @@ -42,6 +49,109 @@ NULL # ---------------------------------------------------------------- # +# * giotto #### +#' @rdname affine +#' @param spat_unit character vector. spatial units to affect. The :all: token +#' to affect all can be used. +#' @param feat_type character vector. feature types to affect. The :all: token +#' to affect all can be used. +#' @param images character vector. Images to affect. The :all: token +#' to affect all can be used. +#' @export +setMethod( + "affine", signature(x = "giotto", y = "matrix"), function( + x, y, inv = FALSE, + spat_unit = ":all:", feat_type = ":all:", images = ":all:", + ... + ) { + a <- list(y = y, inv = inv, ...) + + spat_unit <- set_default_spat_unit( + gobject = x, spat_unit = spat_unit + ) + feat_type <- set_default_feat_type( + gobject = x, spat_unit = spat_unit, feat_type = feat_type + ) + + all_su <- spat_unit == ":all:" + all_ft <- feat_type == ":all:" + + # polygons --------------------------------------------------------- # + polys <- get_polygon_info_list( + gobject = x, return_giottoPolygon = TRUE + ) + if (!all_su) { + polys <- polys[spatUnit(polys) %in% spat_unit] + } + if (!is.null(polys)) { + for(poly in polys) { + poly <- do.call(affine, args = c(list(x = poly), a)) + x <- setGiotto(x, poly, verbose = FALSE, initialize = FALSE) + } + } + + # spatlocs --------------------------------------------------------- # + sls <- get_spatial_locations_list( + gobject = x, + spat_unit = ":all:", + output = "spatLocsObj", + copy_obj = FALSE + ) + if (!all_su) { + sls[spatUnit(sls) %in% spat_unit] + } + if (!is.null(sls)) { + for (sl in sls) { + sl <- do.call(affine, args = c(list(x = sl), a)) + x <- setGiotto(x, sl, verbose = FALSE, initialize = FALSE) + } + + # TODO remove this after spatial info is removed from + # spatialNetwork objs + sn_list <- get_spatial_network_list( + gobject = x, + spat_unit = ":all:", + output = "spatialNetworkObj", + copy_obj = FALSE + ) + if (length(sn_list) > 0) { + warning(wrap_txt("spatial locations have been modified. + Relevant spatial networks may need to be + regenerated"), call. = FALSE) + } + } + + # points ----------------------------------------------------------- # + + pts <- get_feature_info_list( + gobject = x, return_giottoPoints = TRUE + ) + if (!all_ft) { + pts <- pts[featType(pts) %in% feat_type] + } + if (!is.null(pts)) { + for(pt in pts) { + pt <- do.call(affine, args = c(list(x = pt), a)) + x <- setGiotto(x, pt, verbose = FALSE, initialize = FALSE) + } + } + # images ----------------------------------------------------------- # + + imgs <- get_giotto_image_list(x) + if (!is.null(imgs)) { + if (!inherits(imgs, "list")) imgs <- list(imgs) + for (img in imgs) { + img <- do.call(affine, args = c(list(x = img), a)) + x <- setGiotto(x, img, verbose = FALSE) + } + } + + return(initialize(x)) # init not necessarily needed + } +) + + +# * ANY #### #' @rdname affine #' @export setMethod("affine", signature(x = "ANY", y = "missing"), function(x) { @@ -52,6 +162,7 @@ setMethod("affine", signature(x = "ANY", y = "missing"), function(x) { return(res) }) +# * ANY, affine2d #### #' @rdname affine #' @export setMethod("affine", signature(x = "ANY", y = "affine2d"), function(x, y, ...) { @@ -60,6 +171,7 @@ setMethod("affine", signature(x = "ANY", y = "affine2d"), function(x, y, ...) { do.call(affine, args = a) }) +# * SpatVector, matrix #### #' @rdname affine #' @export setMethod("affine", signature(x = "SpatVector", y = "matrix"), @@ -67,6 +179,7 @@ setMethod("affine", signature(x = "SpatVector", y = "matrix"), .affine_sv(x, m = y, inv, ...) }) +# * giottoPoints, matrix #### #' @rdname affine #' @export setMethod( @@ -77,6 +190,7 @@ setMethod( } ) +# * giottoPolygon, matrix #### #' @rdname affine #' @export setMethod( @@ -86,6 +200,7 @@ setMethod( } ) +# * spatLocsObj, matrix #### #' @rdname affine #' @export setMethod( @@ -98,6 +213,7 @@ setMethod( } ) +# * giottoLargeImage, matrix #### #' @rdname affine #' @export setMethod("affine", signature(x = "giottoLargeImage", y = "matrix"), function( @@ -109,6 +225,7 @@ setMethod("affine", signature(x = "giottoLargeImage", y = "matrix"), function( return(res) }) +# * giottoAffineImage, matrix #### #' @rdname affine #' @export setMethod("affine", signature(x = "giottoAffineImage", y = "matrix"), function( @@ -122,6 +239,7 @@ setMethod("affine", signature(x = "giottoAffineImage", y = "matrix"), function( return(initialize(x)) }) +# * affine2d, matrix #### #' @rdname affine #' @export setMethod("affine", signature(x = "affine2d", y = "matrix"), function( diff --git a/R/methods-shear.R b/R/methods-shear.R index 05dfa671..9bbb5373 100644 --- a/R/methods-shear.R +++ b/R/methods-shear.R @@ -28,6 +28,7 @@ NULL # ---------------------------------------------------------------- # +# * spatLocsObj #### #' @rdname shear #' @export setMethod("shear", signature("spatLocsObj"), function( @@ -39,6 +40,7 @@ setMethod("shear", signature("spatLocsObj"), function( return(x) }) +# * SpatVector #### #' @rdname shear #' @export setMethod("shear", signature("SpatVector"), function( @@ -48,6 +50,7 @@ setMethod("shear", signature("SpatVector"), function( do.call(.shear_sv, args = a) }) +# * giottoPoints #### #' @rdname shear #' @export setMethod("shear", signature("giottoPoints"), function( @@ -60,6 +63,7 @@ setMethod("shear", signature("giottoPoints"), function( return(x) }) +# * giottoPolygon #### #' @rdname shear #' @export setMethod("shear", signature("giottoPolygon"), function( @@ -70,6 +74,7 @@ setMethod("shear", signature("giottoPolygon"), function( .do_gpoly(x, what = .shear_sv, args = a) }) +# * giottoLargeImage #### #' @rdname shear #' @export setMethod("shear", signature("giottoLargeImage"), function( @@ -81,6 +86,7 @@ setMethod("shear", signature("giottoLargeImage"), function( return(res) }) +# * giottoAffineImage #### #' @rdname shear #' @export setMethod("shear", signature("giottoAffineImage"), function( @@ -94,6 +100,7 @@ setMethod("shear", signature("giottoAffineImage"), function( return(initialize(x)) }) +# * affine2d #### setMethod("shear", signature("affine2d"), function( x, fx = 0, fy = 0, x0, y0, ... ) { diff --git a/man/affine.Rd b/man/affine.Rd index 890cb9f7..32b1004d 100644 --- a/man/affine.Rd +++ b/man/affine.Rd @@ -2,6 +2,7 @@ % Please edit documentation in R/methods-affine.R \name{affine} \alias{affine} +\alias{affine,giotto,matrix-method} \alias{affine,ANY,missing-method} \alias{affine,ANY,affine2d-method} \alias{affine,SpatVector,matrix-method} @@ -13,6 +14,16 @@ \alias{affine,affine2d,matrix-method} \title{Affine transformations} \usage{ +\S4method{affine}{giotto,matrix}( + x, + y, + inv = FALSE, + spat_unit = ":all:", + feat_type = ":all:", + images = ":all:", + ... +) + \S4method{affine}{ANY,missing}(x) \S4method{affine}{ANY,affine2d}(x, y, ...) @@ -32,18 +43,28 @@ \S4method{affine}{affine2d,matrix}(x, y, inv = FALSE, ...) } \arguments{ -\item{x}{object} +\item{x}{object to affine transform or a \code{matrix}} -\item{...}{additional args to pass (none implemented)} +\item{y}{\code{matrix} or coercible to \code{matrix} (such as \code{affine2d}). Should +be a matrix with either 2 or 3 columns (linear or affine).} \item{inv}{logical. Whether the inverse of the affine transform should be applied.} -\item{m}{\code{matrix} or coercible to \code{matrix}. Should be a matrix with either -2 or 3 columns (linear or affine).} +\item{spat_unit}{character vector. spatial units to affect. The :all: token +to affect all can be used.} + +\item{feat_type}{character vector. feature types to affect. The :all: token +to affect all can be used.} + +\item{images}{character vector. Images to affect. The :all: token +to affect all can be used.} + +\item{...}{additional args to pass (none implemented)} } \value{ -affine transformed object +affine transformed object or an \code{affine2d} if a \code{matrix} was +passed to \code{x} } \description{ Apply an affine transformation matrix to a spatial object. @@ -59,6 +80,11 @@ gpoints <- GiottoData::loadSubObjectMini("giottoPoints") gpoly <- GiottoData::loadSubObjectMini("giottoPolygon") sl <- GiottoData::loadSubObjectMini("spatLocsObj") +# creation of affine2d +aff <- affine(m) +aff <- spin(flip(shear(aff, fx = 0.2)), 45) +plot(aff) # blue is start, red is end + # giottoPoints ############################################## plot(gpoints) plot(affine(gpoints, trans_m)) @@ -66,6 +92,7 @@ plot(affine(gpoints, trans_m)) # giottoPolygon ############################################# plot(gpoly) plot(affine(gpoly, scale_m)) +plot(affine(gpoly, aff)) # affine() with `affine2d` # spatLocsObj ############################################### plot(affine(sl, m)) From 6c86f862c48ce14e3a1b643e9053f8de0c58733f Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 26 Jul 2024 14:23:48 -0400 Subject: [PATCH 106/160] chore: document --- man/seuratToGiottoV5.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/seuratToGiottoV5.Rd b/man/seuratToGiottoV5.Rd index b72e2f28..eca79076 100644 --- a/man/seuratToGiottoV5.Rd +++ b/man/seuratToGiottoV5.Rd @@ -8,7 +8,7 @@ seuratToGiottoV5( sobject, spatial_assay = "Spatial", dim_reduction = c("pca", "umap"), - subcellular_assay = "Vizgen", + subcellular_assay = "SCT", sp_network = NULL, nn_network = NULL, verbose = TRUE From f827f9f93fd0bcbda23647aefb41bbb1ab65438c Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 26 Jul 2024 14:42:57 -0400 Subject: [PATCH 107/160] chore: update news --- NEWS.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index a44e6ba8..30ebec09 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,5 @@ -# GiottoClass 0.3.2 +# GiottoClass 0.3.2 (2024/07/26) ## breaking changes - python environment installation and how it relates to default settings such as .condarc may have changed. @@ -7,6 +7,9 @@ ## bug fixes - `loadGiotto()` no longer errors with similarly named spat_units or feat_types (e.g. "cell" and "new_cell" would previously throw an error) +- fix in `giottoToSpatialExperiment()` +- fix for `giottoToSeuratV5` for cosmx mini dataset [#989](https://github.com/drieslab/Giotto/issues/989) by guillermoturiel +- fix issue with prints in `createGiottoCosMxObject()` [#960](https://github.com/drieslab/Giotto/issues/960) by GBeattie ## enhancements - `verbose` param for `createNearestNetwork()` From 541eb5b04117f13f50e44fa32a122b77ba0f798d Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 29 Jul 2024 16:28:01 -0400 Subject: [PATCH 108/160] chore: bump version for dev --- DESCRIPTION | 2 +- NEWS.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 521a3587..bf01ad6c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: GiottoClass Title: Giotto Suite object definitions and framework -Version: 0.3.2 +Version: 0.3.3 Authors@R: c( person("Ruben", "Dries", email = "rubendries@gmail.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-7650-7754")), diff --git a/NEWS.md b/NEWS.md index 30ebec09..d2490621 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,7 @@ +# GiottoClass 0.3.3 + + # GiottoClass 0.3.2 (2024/07/26) ## breaking changes From cbd9100386fbd47d4d65989a95660c8be0ec215b Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 29 Jul 2024 16:30:14 -0400 Subject: [PATCH 109/160] enh: `affine()` `missing` method --- NEWS.md | 2 ++ R/methods-affine.R | 7 +++++++ man/affine.Rd | 3 +++ 3 files changed, 12 insertions(+) diff --git a/NEWS.md b/NEWS.md index d2490621..55c6cc77 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,8 @@ # GiottoClass 0.3.3 +## enhancements +- `missing` method for `affine()` instantiates an `affine2d` object # GiottoClass 0.3.2 (2024/07/26) diff --git a/R/methods-affine.R b/R/methods-affine.R index ab626ba7..4606798b 100644 --- a/R/methods-affine.R +++ b/R/methods-affine.R @@ -150,6 +150,13 @@ setMethod( } ) +# * missing #### +#' @rdname affine +#' @export +setMethod("affine", signature(x = "missing", y = "missing"), function(x) { + new("affine2d", affine = diag(c(1, 1))) +}) + # * ANY #### #' @rdname affine diff --git a/man/affine.Rd b/man/affine.Rd index 32b1004d..c3c0b36c 100644 --- a/man/affine.Rd +++ b/man/affine.Rd @@ -3,6 +3,7 @@ \name{affine} \alias{affine} \alias{affine,giotto,matrix-method} +\alias{affine,missing,missing-method} \alias{affine,ANY,missing-method} \alias{affine,ANY,affine2d-method} \alias{affine,SpatVector,matrix-method} @@ -24,6 +25,8 @@ ... ) +\S4method{affine}{missing,missing}(x) + \S4method{affine}{ANY,missing}(x) \S4method{affine}{ANY,affine2d}(x, y, ...) From 9b8d649f5ad8bfb84b47f2bd9798019b4ca1b35d Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 29 Jul 2024 21:38:27 -0400 Subject: [PATCH 110/160] fix: flipping problem with certain transforms in `giottoAffineImage` --- R/giotto_structures.R | 8 ++++++++ R/methods-affine.R | 19 ++++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/R/giotto_structures.R b/R/giotto_structures.R index 8867f2b9..5d03cc95 100644 --- a/R/giotto_structures.R +++ b/R/giotto_structures.R @@ -185,6 +185,14 @@ .magick_image_corners <- function(x) { checkmate::assert_class(x, "magick-image") im_info <- magick::image_info(x) + + # generate spatLocsObj as a set of control points for magick distort. # + # ------------------------------------------------------------------- # + # - magick uses 0.5 to refer to the center of pixels + # - 3 points are needed for an affine distort + # pt1: bottom left + # pt2: top left + # pt3: bottom right spatLocsObj( name = "mg_ctrl_coords", coordinates = data.table::data.table( diff --git a/R/methods-affine.R b/R/methods-affine.R index 4606798b..21fc9b11 100644 --- a/R/methods-affine.R +++ b/R/methods-affine.R @@ -150,7 +150,7 @@ setMethod( } ) -# * missing #### +# * missing, missing #### #' @rdname affine #' @export setMethod("affine", signature(x = "missing", y = "missing"), function(x) { @@ -158,7 +158,7 @@ setMethod("affine", signature(x = "missing", y = "missing"), function(x) { }) -# * ANY #### +# * ANY, missing #### #' @rdname affine #' @export setMethod("affine", signature(x = "ANY", y = "missing"), function(x) { @@ -344,12 +344,21 @@ setMethod("affine", signature(x = "affine2d", y = "matrix"), function( .gaffine_realize_magick <- function(x, size = 5e5, ...) { mg <- .spatraster_sample_values(x, output = "magick", size = size, ...) aff <- x@affine + + # create a dummy spatLocsObj to act as control points + # pt1: bottom left + # pt2: top left + # pt3: bottom right dummy_sl <- .magick_image_corners(mg) - aff_dummy_sl <- affine(dummy_sl, .aff_linear_2d(aff)) %>% + aff_dummy_sl <- dummy_sl %>% + affine(.aff_linear_2d(aff)) %>% flip() %>% - rescale(fx = 1 / aff$scale[["x"]], fy = 1 / aff$scale[["y"]]) - # no rescaling should be performed at this step. Otherwise magick + rescale(fx = 1 / abs(aff$scale[["x"]]), #*see below + fy = 1 / abs(aff$scale[["y"]])) + # *no scaling should be performed at this step. Otherwise magick # will generate a differently sized image during distortion + # To prevent the scaling change, we use the decomposed scale values. + # However, flips ARE desired, so we make sure the use the abs() values. .sl_to_mat <- function(x) { x[][, c("sdimx", "sdimy")] %>% t() From 21d5a2726b86797fad043e212827e819e4a2c65b Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 29 Jul 2024 21:39:29 -0400 Subject: [PATCH 111/160] chore: update news --- NEWS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS.md b/NEWS.md index 55c6cc77..2b69ea9a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,9 @@ # GiottoClass 0.3.3 +## bug fixes +- fix flipping issue with `giottoAffineImage` for certain affine transforms + ## enhancements - `missing` method for `affine()` instantiates an `affine2d` object From fd2e7f71eda07af180edec9222309bd33d6a504f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wen=20Wang=20=28=E7=8E=8B=E6=96=87=29?= Date: Sun, 4 Aug 2024 00:51:33 -0400 Subject: [PATCH 112/160] Add: support for ndarray and DataFrame anndata --- R/interoperability.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/interoperability.R b/R/interoperability.R index f33327a0..4f4907c9 100644 --- a/R/interoperability.R +++ b/R/interoperability.R @@ -237,6 +237,7 @@ anndataToGiotto <- function( X <- extract_expression(adata) cID <- extract_cell_IDs(adata) fID <- extract_feat_IDs(adata) + X <- methods::as(as.matrix(X), "sparseMatrix") X@Dimnames[[1]] <- fID X@Dimnames[[2]] <- cID # Expression matrix X ready From 0ff236c1d79438f0921b9fbfcc9444aff502a7d9 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Sun, 4 Aug 2024 01:17:37 -0400 Subject: [PATCH 113/160] chore: update news --- DESCRIPTION | 2 +- NEWS.md | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index bf01ad6c..b08f3fcc 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: GiottoClass Title: Giotto Suite object definitions and framework -Version: 0.3.3 +Version: 0.3.4 Authors@R: c( person("Ruben", "Dries", email = "rubendries@gmail.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-7650-7754")), diff --git a/NEWS.md b/NEWS.md index 2b69ea9a..e67bb608 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,10 @@ -# GiottoClass 0.3.3 +# GiottoClass 0.3.4 (2024/08/04) + +## bug fixes +- hotfix anndata matrix support [#216](https://github.com/drieslab/GiottoClass/issues/216) by wwang-chcn + +# GiottoClass 0.3.3 (2024/07/29) ## bug fixes - fix flipping issue with `giottoAffineImage` for certain affine transforms From 1befb1f51646a5dec499091503444f25136074e3 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Sun, 11 Aug 2024 19:31:43 -0400 Subject: [PATCH 114/160] update py path setting - bump dev version - `set_giotto_python_path()` will now also initialize python env to set by default and print which python env is active, but otherwise do nothing if any python env has already been initialized. --- DESCRIPTION | 2 +- NEWS.md | 6 ++++++ R/python_environment.R | 33 ++++++++++++++++++++++++++++----- man/checkPythonPackage.Rd | 2 +- man/set_giotto_python_path.Rd | 14 ++++++++++---- 5 files changed, 46 insertions(+), 11 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index b08f3fcc..997b3ffe 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: GiottoClass Title: Giotto Suite object definitions and framework -Version: 0.3.4 +Version: 0.3.5 Authors@R: c( person("Ruben", "Dries", email = "rubendries@gmail.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-7650-7754")), diff --git a/NEWS.md b/NEWS.md index e67bb608..c23a4f5e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,10 @@ +# GiottoClass 0.3.4 + +## breaking changes +- `set_giotto_python_path()` will now also initialize python env to set by default and print which python env is active, but otherwise do nothing if any python env has already been initialized. + + # GiottoClass 0.3.4 (2024/08/04) ## bug fixes diff --git a/R/python_environment.R b/R/python_environment.R index 2c9cde90..426397b2 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -536,15 +536,20 @@ removeGiottoEnvironment <- function( #' 1. User provided (when `python_path` is not `NULL`) #' 2. Any provided path or envname in option `"giotto.py_path"` #' 3. Default expected giotto environment location based on -#' `reticulate::miniconda_path()` +#' [reticulate::miniconda_path()] #' 4. Envname "giotto_env" #' 5. System default python environment #' -#' This function exits without doing anything if option -#' `"giotto.use_conda"` is `FALSE`. +#' This function exits without doing anything if option `"giotto.use_conda"` +#' is `FALSE`. By default this function will also force initialization of the +#' python to set, locking the session to the set python. This can be skipped +#' if `initialize = FALSE`, however the actual python path set may differ from +#' what is expected and reported by this function. Additionally, +#' [reticulate::py_available()] will still show as `FALSE`. #' @param python_path character. Name of environment or full path to python #' executable. #' @param verbose be verbose +#' @param initialize force initialization of set python path. Default = TRUE. #' @returns path to python executable #' @keywords internal #' @examples @@ -552,12 +557,26 @@ removeGiottoEnvironment <- function( #' @export set_giotto_python_path <- function( python_path = NULL, - verbose = NULL + verbose = NULL, + initialize = TRUE ) { if (isFALSE(getOption("giotto.use_conda", TRUE))) { return(invisible(NULL)) # exit early } + # if py_active_env() is character then an environment has already been + # initialized. Return early with a verbose message + py <- py_active_env() + if (is.character(py)) { + vmsg(.v = verbose, sprintf( + "%s\n%s '%s'\n%s %s", + "python already initialized in this session", + "active environment:", py, + "python version:", getOption("giotto.py_active_ver") + )) + return(invisible(NULL)) # exit early + } + # get path in order of DECREASING priority # # ---------------------------------------- # found <- vector(mode = "numeric") @@ -612,7 +631,11 @@ set_giotto_python_path <- function( # --------------------------------------------------------------------- # if (!is.null(python_path)) { vmsg(.v = verbose, sprintf("Using python path:\n\"%s\"", python_path)) + # this is applying a setting that will sit in reticulate:::.globals + # python is still not initialized reticulate::use_python(required = TRUE, python = python_path) + # py_config will force initialization + if (initialize) (reticulate::py_config()) return(python_path) } @@ -772,7 +795,7 @@ set_giotto_python_path <- function( #' `package_name`, i.e. if both are provided, only the github #' URL will be installed. This function should only be provided #' one parameter, or the other. -#' @keywords export +#' @keywords internal checkPythonPackage <- function(package_name = NULL, github_package_url = NULL, env_to_use = "giotto_env") { diff --git a/man/checkPythonPackage.Rd b/man/checkPythonPackage.Rd index 23f29a84..1f4e4a59 100644 --- a/man/checkPythonPackage.Rd +++ b/man/checkPythonPackage.Rd @@ -34,4 +34,4 @@ Parameter \code{github_package_url} takes precedent over URL will be installed. This function should only be provided one parameter, or the other. } -\keyword{export} +\keyword{internal} diff --git a/man/set_giotto_python_path.Rd b/man/set_giotto_python_path.Rd index d5d61a02..70a71630 100644 --- a/man/set_giotto_python_path.Rd +++ b/man/set_giotto_python_path.Rd @@ -4,13 +4,15 @@ \alias{set_giotto_python_path} \title{set_giotto_python_path} \usage{ -set_giotto_python_path(python_path = NULL, verbose = NULL) +set_giotto_python_path(python_path = NULL, verbose = NULL, initialize = TRUE) } \arguments{ \item{python_path}{character. Name of environment or full path to python executable.} \item{verbose}{be verbose} + +\item{initialize}{force initialization of set python path. Default = TRUE.} } \value{ path to python executable @@ -23,13 +25,17 @@ final path to use is determined as follows in decreasing priority: \item User provided (when \code{python_path} is not \code{NULL}) \item Any provided path or envname in option \code{"giotto.py_path"} \item Default expected giotto environment location based on -\code{reticulate::miniconda_path()} +\code{\link[reticulate:miniconda_path]{reticulate::miniconda_path()}} \item Envname "giotto_env" \item System default python environment } -This function exits without doing anything if option -\code{"giotto.use_conda"} is \code{FALSE}. +This function exits without doing anything if option \code{"giotto.use_conda"} +is \code{FALSE}. By default this function will also force initialization of the +python to set, locking the session to the set python. This can be skipped +if \code{initialize = FALSE}, however the actual python path set may differ from +what is expected and reported by this function. Additionally, +\code{\link[reticulate:py_available]{reticulate::py_available()}} will still show as \code{FALSE}. } \examples{ set_giotto_python_path() From 62bce4de23b1c960cf10974d5217e1fff2e011e5 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Sun, 11 Aug 2024 20:03:59 -0400 Subject: [PATCH 115/160] package checking changes --- R/interoperability.R | 25 ++++++++++++++++++------- R/python_bento.R | 14 +++----------- man/anndataToGiotto.Rd | 2 +- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/R/interoperability.R b/R/interoperability.R index 4f4907c9..57924b22 100644 --- a/R/interoperability.R +++ b/R/interoperability.R @@ -187,7 +187,7 @@ check_py_for_scanpy <- function() { #' @param env_name name of environment containing python_path executable #' #' @details Function in beta. Converts a .h5ad file into a Giotto object. -#' The returned Giotto Object will take default insructions with the +#' The returned Giotto Object will take default instructions with the #' exception of the python path, which may be customized. #' See \code{\link{changeGiottoInstructions}} to modify instructions after #' creation. @@ -222,11 +222,13 @@ anndataToGiotto <- function( } } - # Required step to properly initialize reticualte + # Required step to properly initialize reticulate instrs <- createGiottoInstructions(python_path = python_path) - scanpy_installed <- checkPythonPackage("scanpy", env_to_use = env_name) - # should trigger a stop() downstream if not installed + package_check( + pkg_name = c("anndata", "scanpy"), + repository = c("pip:anndata", "pip:scanpy") + ) # Import ad2g, a python module for parsing anndata ad2g_path <- system.file("python", "ad2g.py", package = "GiottoClass") @@ -613,7 +615,10 @@ giottoToAnnData <- function( stop(wrap_msg("Please provide a valid Giotto Object for conversion.")) } - scanpy_installed <- checkPythonPackage("scanpy", env_to_use = env_name) + package_check( + pkg_name = c("anndata", "scanpy"), + repository = c("pip:anndata", "pip:scanpy") + ) # Python module import g2ad_path <- system.file("python", "g2ad.py", package = "GiottoClass") @@ -3441,7 +3446,10 @@ spatialdataToGiotto <- function( ) # Check spatialdata dependencies - spatialdata_installed <- checkPythonPackage(package_name = "spatialdata", env_to_use = env_name) + package_check( + pkg_name = "spatialdata", + repository = "pip:spatialdata" + ) # Import sd2g, a python module for parsing SpatialData sd2g_path <- system.file("python", "sd2g.py", package = "GiottoClass") @@ -3743,7 +3751,10 @@ giottoToSpatialData <- function( instrs <- createGiottoInstructions(python_path = python_path) # Check spatialdata dependencies - spatialdata_installed <- checkPythonPackage(package_name = "spatialdata", env_to_use = env_name) + package_check( + pkg_name = "spatialdata", + repository = "pip:spatialdata" + ) # Import sd2g, a python module for parsing SpatialData g2sd_path <- system.file("python", "g2sd.py", package = "GiottoClass") diff --git a/R/python_bento.R b/R/python_bento.R index d0de24a0..26056488 100644 --- a/R/python_bento.R +++ b/R/python_bento.R @@ -40,18 +40,10 @@ createBentoAdata <- function(gobject = NULL, ) # Install bento-tools / Check python environment for bento-tools - bento_installed <- checkPythonPackage( - package_name = "bento-tools", - env_to_use = env_to_use + package_check( + pkg_name = "bento-tools", + repository = "pip:git+https://github.com/wwang-chcn/bento-tools.git" ) - if (!bento_installed) { - bento_installed <- checkPythonPackage( - github_package_url = "git+https://github.com/wwang-chcn/bento-tools.git", - env_to_use = env_to_use - ) - } - # Will crash downstream if installation unsuccessful/denied - # or if the package is not found. # Create AnnData object g2bento_path <- system.file("python", "g2bento.py", package = "GiottoClass") diff --git a/man/anndataToGiotto.Rd b/man/anndataToGiotto.Rd index 9219fd74..74efa2ba 100644 --- a/man/anndataToGiotto.Rd +++ b/man/anndataToGiotto.Rd @@ -57,7 +57,7 @@ Giotto object } \details{ Function in beta. Converts a .h5ad file into a Giotto object. -The returned Giotto Object will take default insructions with the +The returned Giotto Object will take default instructions with the exception of the python path, which may be customized. See \code{\link{changeGiottoInstructions}} to modify instructions after creation. From 821b682f95a23958a4145236a38903b9cbbb0f56 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 12 Aug 2024 10:38:41 -0400 Subject: [PATCH 116/160] fix `set_giotto_python_path()` MUST return path --- R/python_environment.R | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 426397b2..d7f1b93d 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -571,10 +571,9 @@ set_giotto_python_path <- function( vmsg(.v = verbose, sprintf( "%s\n%s '%s'\n%s %s", "python already initialized in this session", - "active environment:", py, - "python version:", getOption("giotto.py_active_ver") + "active environment :", py, + "python version :", getOption("giotto.py_active_ver") )) - return(invisible(NULL)) # exit early } # get path in order of DECREASING priority # From d58bf17e033be07197fc31717921676c1f4a8899 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 14 Aug 2024 12:30:21 -0400 Subject: [PATCH 117/160] change: change the way `checkGiottoEnvironment()` works - now uses `set_giotto_python_path()` to perform check - does not initialize python --- R/python_environment.R | 86 +++++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 34 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index d7f1b93d..23a9d621 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -6,13 +6,14 @@ #' @title checkGiottoEnvironment #' @name checkGiottoEnvironment #' @description -#' Based on `envname`, detect if there is a conda or miniconda installation. +#' Based on `envname`, detect if there is a conda or miniconda installation +#' without initializing any python environments. #' This is done by detecting if there is a python executable in the -#' expected location. The default behavior is to only check for giotto's -#' default environment called "giotto_env" +#' expected location. Leaving `envname` as `NULL` (default) will let +#' \pkg{Giotto} autodetect a python env to use. See +#' [set_giotto_python_path()] for details on the autodetection. #' @param envname character. (optional) The name of or path to a miniconda or -#' conda environment directory or python executable. Default is -#' `reticulate::miniconda_path()`. +#' conda environment directory or python executable. #' @param mini_install_path deprecated #' @param verbose be verbose #' @details Checks if a miniconda giotto environment can be found. @@ -34,7 +35,7 @@ #' } #' @export checkGiottoEnvironment <- function( - envname = "giotto_env", + envname = NULL, mini_install_path = deprecated(), verbose = NULL ) { @@ -47,31 +48,42 @@ checkGiottoEnvironment <- function( ) envname <- mini_install_path } - envname <- envname %null% "giotto_env" - # check for envnames, if found, get the path - if (!.is_path(envname)) { - # if a condaenv matches envname, return fullpath - # otherwise return envname without modification - envname <- .envname_to_pypath(envname, must_exist = FALSE) + py_path <- set_giotto_python_path( + python_path = envname, verbose = FALSE, initialize = FALSE + ) + # set_giotto_python_path() returns the path if found. + found <- is.character(py_path) + + if (found) { + vmsg(.v = verbose, "giotto environment found at\n", py_path) } - # complete any directory inputs - # if path does not exist, return NULL - py_path <- .full_miniconda_path(path = envname) + return(found) - if (is.null(py_path)) { - vmsg( - .v = verbose, - " Unable to find conda directory", envname, - "\nPlease ensure the directory exists and is provided as", - "character." - ) - return(FALSE) - } - - vmsg(.v = verbose, "giotto environment found at\n", py_path) - return(TRUE) + # # check for envnames, if found, get the path + # if (!.is_path(envname)) { + # # if a condaenv matches envname, return fullpath + # # otherwise return envname without modification + # envname <- .envname_to_pypath(envname, must_exist = FALSE) + # } + # + # # complete any directory inputs + # # if path does not exist, return NULL + # py_path <- .full_miniconda_path(path = envname) + # + # if (is.null(py_path)) { + # vmsg( + # .v = verbose, + # " Unable to find conda directory", envname, + # "\nPlease ensure the directory exists and is provided as", + # "character." + # ) + # return(FALSE) + # } + # + # vmsg(.v = verbose, "giotto environment found at\n", py_path) + # return(TRUE) } @@ -629,12 +641,17 @@ set_giotto_python_path <- function( # if any working python path found; activate the environment and return # # --------------------------------------------------------------------- # if (!is.null(python_path)) { - vmsg(.v = verbose, sprintf("Using python path:\n\"%s\"", python_path)) - # this is applying a setting that will sit in reticulate:::.globals - # python is still not initialized - reticulate::use_python(required = TRUE, python = python_path) - # py_config will force initialization - if (initialize) (reticulate::py_config()) + if (isTRUE(initialize)) { + vmsg(.v = verbose, + sprintf("Using python path:\n\"%s\"", python_path)) + + # `use_python()` applies a setting in `reticulate:::.globals` + # but, python is still not initialized + reticulate::use_python(required = TRUE, python = python_path) + # `py_config()` will force initialization + reticulate::py_config() + } + return(python_path) } @@ -649,6 +666,7 @@ set_giotto_python_path <- function( installed") vmsg('Set options(\"giotto.use_conda\" = FALSE) if python functionalities are not needed') + return(invisible()) } @@ -1002,7 +1020,7 @@ checkPythonPackage <- function(package_name = NULL, return(envname) } -# get full path to miniconda executable +# Guess full path to miniconda executable # if a full path to the executable is provided, it will be used # if a directory is provided, it will be completed with `.os_py_path` # if an envname is given, it will be completed with `.os_py_path` based on From f09fa444cf209ad868f5f37de3ebc107637658f9 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 14 Aug 2024 15:47:21 -0400 Subject: [PATCH 118/160] chore: combine python function docs --- R/python_environment.R | 233 ++++++++++++++++++------------- man/checkGiottoEnvironment.Rd | 49 ------- man/giotto_python.Rd | 237 ++++++++++++++++++++++++++++++++ man/installGiottoEnvironment.Rd | 119 ---------------- man/removeGiottoEnvironment.Rd | 35 ----- man/set_giotto_python_path.Rd | 43 ------ 6 files changed, 373 insertions(+), 343 deletions(-) delete mode 100644 man/checkGiottoEnvironment.Rd create mode 100644 man/giotto_python.Rd delete mode 100644 man/installGiottoEnvironment.Rd delete mode 100644 man/removeGiottoEnvironment.Rd delete mode 100644 man/set_giotto_python_path.Rd diff --git a/R/python_environment.R b/R/python_environment.R index 23a9d621..dcd40499 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -1,26 +1,123 @@ +#' @title Giotto python environment +#' @name giotto_python +#' @description +#' \pkg{Giotto} has several functions that utilize python packages. To +#' facilitate this, utilities are provided for creating, removing, and +#' attaching python environments. Python environments are currently handled +#' entirely through \pkg{reticulate}. +#' +#' **Creating an environment** +#' +#' `installGiottoEnvironment()` can be used to create a default environment +#' called `giotto_env` that includes some commonly used python packages. See +#' the **python versions** section for specific packages and version numbers. +#' +#' Custom environments managed through \pkg{reticulate} are also compatible +#' and can be hooked into by Giotto after creation. +#' +#' +#' **Choosing environments** +#' +#' Only one python environment may be initialized and used by \pkg{reticulate} +#' during a single R session. In order to switch to another environment, the +#' R session must be restarted. +#' +#' Whenever any of the following happens for the first time in a session: +#' +#' - `giotto` object creation +#' - `giottoInstructions` creation (`createGiottoInstructions()`) +#' - `GiottoClass::set_giotto_python_path()` is called (most straightforward) +#' +#' Giotto automatically detects AND activates a python environment based on the +#' following defaults in decreasing priority: +#' +#' 1. User provided (when `python_path` is not `NULL`) +#' 2. Any provided path or envname in option `"giotto.py_path"` +#' 3. Default expected giotto environment location based on +#' [reticulate::miniconda_path()] +#' 4. Envname `"giotto_env"` +#' 5. System default python environment +#' +#' This behavior is mediated by the `set_giotto_python_path()` utility +#' function, which will find an environment and then initialize it. You can +#' also call `checkGiottoEnvironment()` in order to detect if there is an +#' environment usable by Giotto without initializing. +#' +#' +#' # python versions +#' By default, Python v3.10.2 will be used with the following python modules +#' for giotto environment installation: +#' \preformatted{ +#' - pandas==1.5.1 +#' - networkx==2.8.8 +#' - python-igraph==0.10.2 +#' - leidenalg==0.9.0 +#' - python-louvain==0.16 +#' - python.app==1.4 +#' - scikit-learn==1.1.3 +#' } +#' +#' The giotto environment can be custom installed by changing the +#' python_version parameter and module versions in the +#' `packages_to_install` parameter. +#' +#' For example, this giotto environment works as well, and was the +#' default environment status for past releases of Giotto. +#' Python v3.6 +#' \preformatted{ +#' - pandas==1.1.5 +#' - networkx==2.6.3 +#' - python-igraph==0.9.6 +#' - leidenalg==0.8.7 +#' - python-louvain==0.15 +#' - python.app==2 # macOS only +#' - scikit-learn==0.24.2 +#' } +#' +#' # .yml installs +#' Please note that multiple .yml files are provided in the +#' repository for advanced installation and convenience. To install the most +#' up-to-date Giotto environment using a .yml file, open a shell compatible +#' with conda/miniconda and navigate to the directory specified by +#' `system.file(package = "Giotto", "python/configuration")`. Once in this +#' directory, run the following to create your environment in one step: +#' +#' \preformatted{conda env create -n giotto_env -f ./genv.yml} +#' +#' @param envname character. (optional) The name of or path to a miniconda or +#' conda environment directory or python executable. When using +#' `installGiottoEnvironment()`, the default is `"giotto_env"` +#' @param conda either "auto" (default) to allow reticulate to handle it, or +#' the full filepath to the conda executable. You can also set the option +#' `"reticulate.conda_binary"` or `Sys.setenv()` `"RETICULATE_CONDA"` to tell +#' reticulate where to look. +#' @param verbose be verbose +#' +NULL + + + + + + # check #### -#' @title checkGiottoEnvironment -#' @name checkGiottoEnvironment -#' @description -#' Based on `envname`, detect if there is a conda or miniconda installation +#' @describeIn giotto_python +#' +#' - Based on `envname`, detect if there is a conda or miniconda installation #' without initializing any python environments. #' This is done by detecting if there is a python executable in the #' expected location. Leaving `envname` as `NULL` (default) will let -#' \pkg{Giotto} autodetect a python env to use. See -#' [set_giotto_python_path()] for details on the autodetection. -#' @param envname character. (optional) The name of or path to a miniconda or -#' conda environment directory or python executable. -#' @param mini_install_path deprecated -#' @param verbose be verbose -#' @details Checks if a miniconda giotto environment can be found. -#' Can be installed with \code{\link{installGiottoEnvironment}}. -#' @returns logical +#' \pkg{Giotto} autodetect a python env to use. See section for +#' `set_giotto_python_path()` for details on the autodetection. +#' - Returns `TRUE` if an env is detected and accessible by Giotto. `FALSE` +#' if not. Will not initialize a python environment during detection. #' @examples -#' # check default location +#' # detect without initialization +#' # check default env location #' checkGiottoEnvironment() #' #' # use environment name @@ -342,11 +439,16 @@ checkGiottoEnvironment <- function( -#' @title installGiottoEnvironment -#' @description Installs a giotto python environment. This includes a -#' miniconda installation and also a set of python packages that Giotto may -#' often use. See details for further information on setting up an +#' @describeIn giotto_python +#' +#' - Install a giotto python environment using the miniconda system as +#' implemented by \pkg{reticulate}. Once this environment is installed it +#' will be automatically detected when you run the +#' \pkg{Giotto} toolbox. \cr This includes a +#' miniconda installation and also a set of python packages that \pkg{Giotto} +#' may often use. See details for further information on setting up an #' environment with a .yml +#' - Returns `NULL` #' @param packages_to_install python modules (packages) to install for Giotto. #' @param python_version python version to use within the giotto conda #' environment. Default is v3.10.2 @@ -354,69 +456,12 @@ checkGiottoEnvironment <- function( #' Default is chosen by `reticulate::install_miniconda()` #' @param confirm whether to pause for confirmation of conda environment #' install location (default = TRUE) -#' @param envname name to assign environment. Default = "giotto_env" -#' @param conda either "auto" (default) to allow reticulate to handle it, or -#' the full filepath to the conda executable. You can also set the option -#' "reticulate.conda_binary" or `Sys.setenv()` "RETICULATE_CONDA" to tell -#' reticulate where to look. #' @param force_miniconda force reinstallation of miniconda #' @param force_environment force reinstallation of the giotto environment -#' @param verbose be verbose -#' @returns installs a giotto environment using the reticulate miniconda system -#' @details This function will install a local giotto environment using -#' the miniconda system as implemented by \pkg{reticulate}. Once this giotto -#' environment is installed it will be automatically detected when you run the -#' Giotto toolbox. \cr -#' -#' # custom python paths -#' If you want to use your own python path then you can set the python_path in -#' the `"giotto.py_path"` option or \code{\link{createGiottoInstructions}} -#' and provide the instructions to the \code{\link{createGiottoObject}} -#' function. -#' -#' # python versions -#' By default, Python v3.10.2 will be used with the following python modules -#' for Giotto Suite implementations: -#' \preformatted{ -#' - pandas==1.5.1 -#' - networkx==2.8.8 -#' - python-igraph==0.10.2 -#' - leidenalg==0.9.0 -#' - python-louvain==0.16 -#' - python.app==1.4 -#' - scikit-learn==1.1.3 -#' } -#' -#' The giotto environment can be custom installed by changing the -#' python_version parameter and module versions in the -#' packages_to_install parameter. -#' -#' For example, this giotto environment works as well, and was the -#' default environment status for past releases of Giotto. -#' Python v3.6 -#' \preformatted{ -#' - pandas==1.1.5 -#' - networkx==2.6.3 -#' - python-igraph==0.9.6 -#' - leidenalg==0.8.7 -#' - python-louvain==0.15 -#' - python.app==2 # macOS only -#' - scikit-learn==0.24.2 -#' } -#' -#' # .yml installs -#' Please note that multiple .yml files are provided in the -#' repository for advanced installation and convenience. To install the most -#' up-to-date Giotto environment using a .yml file, open a shell compatible -#' with conda/miniconda and navigate to the directory specified by -#' `system.file(package = "Giotto", "python/configuration")`. Once in this -#' directory, run the following to create your environment in one step: -#' -#' `conda env create -n giotto_env -f ./genv.yml` #' #' @examples #' if (FALSE) { -#' # default install +#' # default environment installation #' installGiottoEnvironment() #' #' # install to alternate location @@ -425,7 +470,8 @@ checkGiottoEnvironment <- function( #' } #' #' @export -installGiottoEnvironment <- function(packages_to_install = c( +installGiottoEnvironment <- function( + packages_to_install = c( "pandas==1.5.1", "networkx==2.8.8", "python-igraph==0.10.2", @@ -441,7 +487,8 @@ installGiottoEnvironment <- function(packages_to_install = c( conda = "auto", force_miniconda = FALSE, force_environment = FALSE, - verbose = NULL) { + verbose = NULL +) { ## 1. check and install miniconda locally if necessary conda_path <- reticulate::conda_binary(conda = conda) @@ -478,20 +525,12 @@ installGiottoEnvironment <- function(packages_to_install = c( # remove #### -#' @title removeGiottoEnvironment -#' @name removeGiottoEnvironment -#' @description -#' Remove a Giotto environment -#' @param envname name of environment to remove (e.g. "giotto_env") + +#' @describeIn giotto_python +#' +#' - Remove a python environment +#' - Returns `NULL` #' @param mini_path deprecated -#' @param conda either "auto" (default) to allow reticulate to handle it, or -#' the full filepath to the conda executable. You can also set the option -#' "reticulate.conda_binary" or `Sys.setenv()` "RETICULATE_CONDA" to tell -#' reticulate where to look. -#' @param verbose be verbose -#' @returns character or NULL -#' @details Removes a previously installed giotto environment. -#' See \code{\link{installGiottoEnvironment}}. #' @export removeGiottoEnvironment <- function( envname = "giotto_env", @@ -539,9 +578,9 @@ removeGiottoEnvironment <- function( # detect and activate #### -#' @title set_giotto_python_path -#' @name set_giotto_python_path -#' @description Detect and activate a python path. The `python_path` param +#' @describeIn giotto_python +#' +#' - Detect and activate a python path. The `python_path` param #' accepts both full filepaths to the python executable and envnames. The #' final path to use is determined as follows in decreasing priority: #' @@ -552,19 +591,19 @@ removeGiottoEnvironment <- function( #' 4. Envname "giotto_env" #' 5. System default python environment #' -#' This function exits without doing anything if option `"giotto.use_conda"` +#' - This function exits without doing anything if option `"giotto.use_conda"` #' is `FALSE`. By default this function will also force initialization of the #' python to set, locking the session to the set python. This can be skipped #' if `initialize = FALSE`, however the actual python path set may differ from #' what is expected and reported by this function. Additionally, #' [reticulate::py_available()] will still show as `FALSE`. +#' - Returns detected path to python binary or `NULL` if none found. #' @param python_path character. Name of environment or full path to python #' executable. -#' @param verbose be verbose #' @param initialize force initialization of set python path. Default = TRUE. -#' @returns path to python executable #' @keywords internal #' @examples +#' # detect AND initialize a python environment #' set_giotto_python_path() #' @export set_giotto_python_path <- function( diff --git a/man/checkGiottoEnvironment.Rd b/man/checkGiottoEnvironment.Rd deleted file mode 100644 index 36f7f849..00000000 --- a/man/checkGiottoEnvironment.Rd +++ /dev/null @@ -1,49 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/python_environment.R -\name{checkGiottoEnvironment} -\alias{checkGiottoEnvironment} -\title{checkGiottoEnvironment} -\usage{ -checkGiottoEnvironment( - envname = "giotto_env", - mini_install_path = deprecated(), - verbose = NULL -) -} -\arguments{ -\item{envname}{character. (optional) The name of or path to a miniconda or -conda environment directory or python executable. Default is -\code{reticulate::miniconda_path()}.} - -\item{mini_install_path}{deprecated} - -\item{verbose}{be verbose} -} -\value{ -logical -} -\description{ -Based on \code{envname}, detect if there is a conda or miniconda installation. -This is done by detecting if there is a python executable in the -expected location. The default behavior is to only check for giotto's -default environment called "giotto_env" -} -\details{ -Checks if a miniconda giotto environment can be found. -Can be installed with \code{\link{installGiottoEnvironment}}. -} -\examples{ -# check default location -checkGiottoEnvironment() - -# use environment name -checkGiottoEnvironment("giotto_env") - -# full path -# (use this if a different install location specified with .condarc) -if (FALSE) { -checkGiottoEnvironment( - "/Users/example/Library/r-miniconda-arm64/envs/giotto_env/bin/pythonw" -) -} -} diff --git a/man/giotto_python.Rd b/man/giotto_python.Rd new file mode 100644 index 00000000..4301981b --- /dev/null +++ b/man/giotto_python.Rd @@ -0,0 +1,237 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/python_environment.R +\name{giotto_python} +\alias{giotto_python} +\alias{checkGiottoEnvironment} +\alias{installGiottoEnvironment} +\alias{removeGiottoEnvironment} +\alias{set_giotto_python_path} +\title{Giotto python environment} +\usage{ +checkGiottoEnvironment( + envname = NULL, + mini_install_path = deprecated(), + verbose = NULL +) + +installGiottoEnvironment( + packages_to_install = c("pandas==1.5.1", "networkx==2.8.8", "python-igraph==0.10.2", + "leidenalg==0.9.0", "python-louvain==0.16", "python.app==1.4", "scikit-learn==1.1.3"), + python_version = "3.10.2", + mini_install_path = NULL, + confirm = TRUE, + envname = "giotto_env", + conda = "auto", + force_miniconda = FALSE, + force_environment = FALSE, + verbose = NULL +) + +removeGiottoEnvironment( + envname = "giotto_env", + mini_path = deprecated(), + conda = "auto", + verbose = TRUE +) + +set_giotto_python_path(python_path = NULL, verbose = NULL, initialize = TRUE) +} +\arguments{ +\item{envname}{character. (optional) The name of or path to a miniconda or +conda environment directory or python executable. When using +\code{installGiottoEnvironment()}, the default is \code{"giotto_env"}} + +\item{mini_install_path}{(optional) desired miniconda installation location. +Default is chosen by \code{reticulate::install_miniconda()}} + +\item{verbose}{be verbose} + +\item{packages_to_install}{python modules (packages) to install for Giotto.} + +\item{python_version}{python version to use within the giotto conda +environment. Default is v3.10.2} + +\item{confirm}{whether to pause for confirmation of conda environment +install location (default = TRUE)} + +\item{conda}{either "auto" (default) to allow reticulate to handle it, or +the full filepath to the conda executable. You can also set the option +\code{"reticulate.conda_binary"} or \code{Sys.setenv()} \code{"RETICULATE_CONDA"} to tell +reticulate where to look.} + +\item{force_miniconda}{force reinstallation of miniconda} + +\item{force_environment}{force reinstallation of the giotto environment} + +\item{mini_path}{deprecated} + +\item{python_path}{character. Name of environment or full path to python +executable.} + +\item{initialize}{force initialization of set python path. Default = TRUE.} +} +\description{ +\pkg{Giotto} has several functions that utilize python packages. To +facilitate this, utilities are provided for creating, removing, and +attaching python environments. Python environments are currently handled +entirely through \pkg{reticulate}. + +\strong{Creating an environment} + +\code{installGiottoEnvironment()} can be used to create a default environment +called \code{giotto_env} that includes some commonly used python packages. See +the \strong{python versions} section for specific packages and version numbers. + +Custom environments managed through \pkg{reticulate} are also compatible +and can be hooked into by Giotto after creation. + +\strong{Choosing environments} + +Only one python environment may be initialized and used by \pkg{reticulate} +during a single R session. In order to switch to another environment, the +R session must be restarted. + +Whenever any of the following happens for the first time in a session: +\itemize{ +\item \code{giotto} object creation +\item \code{giottoInstructions} creation (\code{createGiottoInstructions()}) +\item \code{GiottoClass::set_giotto_python_path()} is called (most straightforward) +} + +Giotto automatically detects AND activates a python environment based on the +following defaults in decreasing priority: +\enumerate{ +\item User provided (when \code{python_path} is not \code{NULL}) +\item Any provided path or envname in option \code{"giotto.py_path"} +\item Default expected giotto environment location based on +\code{\link[reticulate:miniconda_path]{reticulate::miniconda_path()}} +\item Envname \code{"giotto_env"} +\item System default python environment +} + +This behavior is mediated by the \code{set_giotto_python_path()} utility +function, which will find an environment and then initialize it. You can +also call \code{checkGiottoEnvironment()} in order to detect if there is an +environment usable by Giotto without initializing. +} +\section{Functions}{ +\itemize{ +\item \code{checkGiottoEnvironment()}: \itemize{ +\item Based on \code{envname}, detect if there is a conda or miniconda installation +without initializing any python environments. +This is done by detecting if there is a python executable in the +expected location. Leaving \code{envname} as \code{NULL} (default) will let +\pkg{Giotto} autodetect a python env to use. See section for +\code{set_giotto_python_path()} for details on the autodetection. +\item Returns \code{TRUE} if an env is detected and accessible by Giotto. \code{FALSE} +if not. Will not initialize a python environment during detection. +} + +\item \code{installGiottoEnvironment()}: \itemize{ +\item Install a giotto python environment using the miniconda system as +implemented by \pkg{reticulate}. Once this environment is installed it +will be automatically detected when you run the +\pkg{Giotto} toolbox. \cr This includes a +miniconda installation and also a set of python packages that \pkg{Giotto} +may often use. See details for further information on setting up an +environment with a .yml +\item Returns \code{NULL} +} + +\item \code{removeGiottoEnvironment()}: \itemize{ +\item Remove a python environment +\item Returns \code{NULL} +} + +\item \code{set_giotto_python_path()}: \itemize{ +\item Detect and activate a python path. The \code{python_path} param +accepts both full filepaths to the python executable and envnames. The +final path to use is determined as follows in decreasing priority: +\enumerate{ +\item User provided (when \code{python_path} is not \code{NULL}) +\item Any provided path or envname in option \code{"giotto.py_path"} +\item Default expected giotto environment location based on +\code{\link[reticulate:miniconda_path]{reticulate::miniconda_path()}} +\item Envname "giotto_env" +\item System default python environment +} +\item This function exits without doing anything if option \code{"giotto.use_conda"} +is \code{FALSE}. By default this function will also force initialization of the +python to set, locking the session to the set python. This can be skipped +if \code{initialize = FALSE}, however the actual python path set may differ from +what is expected and reported by this function. Additionally, +\code{\link[reticulate:py_available]{reticulate::py_available()}} will still show as \code{FALSE}. +\item Returns detected path to python binary or \code{NULL} if none found. +} + +}} +\section{python versions}{ +By default, Python v3.10.2 will be used with the following python modules +for giotto environment installation: +\preformatted{ + - pandas==1.5.1 + - networkx==2.8.8 + - python-igraph==0.10.2 + - leidenalg==0.9.0 + - python-louvain==0.16 + - python.app==1.4 + - scikit-learn==1.1.3 +} + +The giotto environment can be custom installed by changing the +python_version parameter and module versions in the +\code{packages_to_install} parameter. + +For example, this giotto environment works as well, and was the +default environment status for past releases of Giotto. +Python v3.6 +\preformatted{ + - pandas==1.1.5 + - networkx==2.6.3 + - python-igraph==0.9.6 + - leidenalg==0.8.7 + - python-louvain==0.15 + - python.app==2 # macOS only + - scikit-learn==0.24.2 +} +} + +\section{.yml installs}{ +Please note that multiple .yml files are provided in the +repository for advanced installation and convenience. To install the most +up-to-date Giotto environment using a .yml file, open a shell compatible +with conda/miniconda and navigate to the directory specified by +\code{system.file(package = "Giotto", "python/configuration")}. Once in this +directory, run the following to create your environment in one step: + +\preformatted{conda env create -n giotto_env -f ./genv.yml} +} + +\examples{ +# detect without initialization +# check default env location +checkGiottoEnvironment() + +# use environment name +checkGiottoEnvironment("giotto_env") + +# full path +# (use this if a different install location specified with .condarc) +if (FALSE) { +checkGiottoEnvironment( + "/Users/example/Library/r-miniconda-arm64/envs/giotto_env/bin/pythonw" +) +} +if (FALSE) { +# default environment installation +installGiottoEnvironment() + +# install to alternate location +temp_env <- tempdir() +installGiottoEnvironment(mini_install_path = temp_env) +} + +# detect AND initialize a python environment +set_giotto_python_path() +} +\keyword{internal} diff --git a/man/installGiottoEnvironment.Rd b/man/installGiottoEnvironment.Rd deleted file mode 100644 index 50a1b293..00000000 --- a/man/installGiottoEnvironment.Rd +++ /dev/null @@ -1,119 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/python_environment.R -\name{installGiottoEnvironment} -\alias{installGiottoEnvironment} -\title{installGiottoEnvironment} -\usage{ -installGiottoEnvironment( - packages_to_install = c("pandas==1.5.1", "networkx==2.8.8", "python-igraph==0.10.2", - "leidenalg==0.9.0", "python-louvain==0.16", "python.app==1.4", "scikit-learn==1.1.3"), - python_version = "3.10.2", - mini_install_path = NULL, - confirm = TRUE, - envname = "giotto_env", - conda = "auto", - force_miniconda = FALSE, - force_environment = FALSE, - verbose = NULL -) -} -\arguments{ -\item{packages_to_install}{python modules (packages) to install for Giotto.} - -\item{python_version}{python version to use within the giotto conda -environment. Default is v3.10.2} - -\item{mini_install_path}{(optional) desired miniconda installation location. -Default is chosen by \code{reticulate::install_miniconda()}} - -\item{confirm}{whether to pause for confirmation of conda environment -install location (default = TRUE)} - -\item{envname}{name to assign environment. Default = "giotto_env"} - -\item{conda}{either "auto" (default) to allow reticulate to handle it, or -the full filepath to the conda executable. You can also set the option -"reticulate.conda_binary" or \code{Sys.setenv()} "RETICULATE_CONDA" to tell -reticulate where to look.} - -\item{force_miniconda}{force reinstallation of miniconda} - -\item{force_environment}{force reinstallation of the giotto environment} - -\item{verbose}{be verbose} -} -\value{ -installs a giotto environment using the reticulate miniconda system -} -\description{ -Installs a giotto python environment. This includes a -miniconda installation and also a set of python packages that Giotto may -often use. See details for further information on setting up an -environment with a .yml -} -\details{ -This function will install a local giotto environment using -the miniconda system as implemented by \pkg{reticulate}. Once this giotto -environment is installed it will be automatically detected when you run the -Giotto toolbox. \cr -} -\section{custom python paths}{ -If you want to use your own python path then you can set the python_path in -the \code{"giotto.py_path"} option or \code{\link{createGiottoInstructions}} -and provide the instructions to the \code{\link{createGiottoObject}} -function. -} - -\section{python versions}{ -By default, Python v3.10.2 will be used with the following python modules -for Giotto Suite implementations: -\preformatted{ - - pandas==1.5.1 - - networkx==2.8.8 - - python-igraph==0.10.2 - - leidenalg==0.9.0 - - python-louvain==0.16 - - python.app==1.4 - - scikit-learn==1.1.3 -} - -The giotto environment can be custom installed by changing the -python_version parameter and module versions in the -packages_to_install parameter. - -For example, this giotto environment works as well, and was the -default environment status for past releases of Giotto. -Python v3.6 -\preformatted{ - - pandas==1.1.5 - - networkx==2.6.3 - - python-igraph==0.9.6 - - leidenalg==0.8.7 - - python-louvain==0.15 - - python.app==2 # macOS only - - scikit-learn==0.24.2 -} -} - -\section{.yml installs}{ -Please note that multiple .yml files are provided in the -repository for advanced installation and convenience. To install the most -up-to-date Giotto environment using a .yml file, open a shell compatible -with conda/miniconda and navigate to the directory specified by -\code{system.file(package = "Giotto", "python/configuration")}. Once in this -directory, run the following to create your environment in one step: - -\verb{conda env create -n giotto_env -f ./genv.yml} -} - -\examples{ -if (FALSE) { -# default install -installGiottoEnvironment() - -# install to alternate location -temp_env <- tempdir() -installGiottoEnvironment(mini_install_path = temp_env) -} - -} diff --git a/man/removeGiottoEnvironment.Rd b/man/removeGiottoEnvironment.Rd deleted file mode 100644 index b117f695..00000000 --- a/man/removeGiottoEnvironment.Rd +++ /dev/null @@ -1,35 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/python_environment.R -\name{removeGiottoEnvironment} -\alias{removeGiottoEnvironment} -\title{removeGiottoEnvironment} -\usage{ -removeGiottoEnvironment( - envname = "giotto_env", - mini_path = deprecated(), - conda = "auto", - verbose = TRUE -) -} -\arguments{ -\item{envname}{name of environment to remove (e.g. "giotto_env")} - -\item{mini_path}{deprecated} - -\item{conda}{either "auto" (default) to allow reticulate to handle it, or -the full filepath to the conda executable. You can also set the option -"reticulate.conda_binary" or \code{Sys.setenv()} "RETICULATE_CONDA" to tell -reticulate where to look.} - -\item{verbose}{be verbose} -} -\value{ -character or NULL -} -\description{ -Remove a Giotto environment -} -\details{ -Removes a previously installed giotto environment. -See \code{\link{installGiottoEnvironment}}. -} diff --git a/man/set_giotto_python_path.Rd b/man/set_giotto_python_path.Rd deleted file mode 100644 index 70a71630..00000000 --- a/man/set_giotto_python_path.Rd +++ /dev/null @@ -1,43 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/python_environment.R -\name{set_giotto_python_path} -\alias{set_giotto_python_path} -\title{set_giotto_python_path} -\usage{ -set_giotto_python_path(python_path = NULL, verbose = NULL, initialize = TRUE) -} -\arguments{ -\item{python_path}{character. Name of environment or full path to python -executable.} - -\item{verbose}{be verbose} - -\item{initialize}{force initialization of set python path. Default = TRUE.} -} -\value{ -path to python executable -} -\description{ -Detect and activate a python path. The \code{python_path} param -accepts both full filepaths to the python executable and envnames. The -final path to use is determined as follows in decreasing priority: -\enumerate{ -\item User provided (when \code{python_path} is not \code{NULL}) -\item Any provided path or envname in option \code{"giotto.py_path"} -\item Default expected giotto environment location based on -\code{\link[reticulate:miniconda_path]{reticulate::miniconda_path()}} -\item Envname "giotto_env" -\item System default python environment -} - -This function exits without doing anything if option \code{"giotto.use_conda"} -is \code{FALSE}. By default this function will also force initialization of the -python to set, locking the session to the set python. This can be skipped -if \code{initialize = FALSE}, however the actual python path set may differ from -what is expected and reported by this function. Additionally, -\code{\link[reticulate:py_available]{reticulate::py_available()}} will still show as \code{FALSE}. -} -\examples{ -set_giotto_python_path() -} -\keyword{internal} From c8e69c6d2b97292fe1b31de8fabed4f91244b16d Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 14 Aug 2024 15:50:42 -0400 Subject: [PATCH 119/160] Update NEWS.md --- NEWS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index c23a4f5e..cf5581c8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,10 +1,11 @@ -# GiottoClass 0.3.4 +# GiottoClass 0.3.5 ## breaking changes - `set_giotto_python_path()` will now also initialize python env to set by default and print which python env is active, but otherwise do nothing if any python env has already been initialized. + # GiottoClass 0.3.4 (2024/08/04) ## bug fixes From 5971d9bfe6f44ea53f4984ec3736dc9b197f09b4 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 15 Aug 2024 09:21:04 -0400 Subject: [PATCH 120/160] defaults changes --- NEWS.md | 5 +++++ R/methods-initialize.R | 5 +++-- R/methods-plot.R | 4 ++-- man/plot-generic.Rd | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/NEWS.md b/NEWS.md index cf5581c8..c247d17a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,11 @@ ## breaking changes - `set_giotto_python_path()` will now also initialize python env to set by default and print which python env is active, but otherwise do nothing if any python env has already been initialized. +- `checkGiottoEnvironment()` no longer checks specifically for the `"giotto_env"` environment, but is instead a general check for whether Giotto can detect a python environment and also which it is. + +## bug fixes +- intensity images now automatically scale to estimated highest value +- `giottoPolygon` `plot()` default `max_poly` raised to `1e6` diff --git a/R/methods-initialize.R b/R/methods-initialize.R index 535a5f0e..fb15232e 100644 --- a/R/methods-initialize.R +++ b/R/methods-initialize.R @@ -625,8 +625,9 @@ setMethod("initialize", signature("giottoLargeImage"), function(.Object, ...) { as.vector(terra::ext(r)) # max window - .Object@max_window <- .Object@max_window %na% - .bitdepth(.Object@max_intensity, return_max = TRUE) + .Object@max_window <- .Object@max_intensity + # .Object@max_window <- .Object@max_window %na% + # .bitdepth(.Object@max_intensity, return_max = TRUE) return(.Object) }) diff --git a/R/methods-plot.R b/R/methods-plot.R index 809e9049..8e53a170 100644 --- a/R/methods-plot.R +++ b/R/methods-plot.R @@ -112,7 +112,7 @@ setMethod( x, point_size = 0.6, type = c("poly", "centroid"), - max_poly = getOption("giotto.plot_max_poly", 1e4), + max_poly = getOption("giotto.plot_max_poly", 1e6), ...) { if (length(x@unique_ID_cache) == 0) { stop(wrap_txt("No geometries to plot"), call. = FALSE) @@ -325,7 +325,7 @@ setMethod("plot", signature(x = "affine2d", y = "missing"), function(x, ...) { } .plot_spatlocs_3d <- function(x, ...) { - engine <- (getOption("giotto.plotengine3d", "rgl")) + engine <- getOption("giotto.plotengine3d", "rgl") switch(engine, "rgl" = .plot_spatlocs_3d_rgl(x, ...), diff --git a/man/plot-generic.Rd b/man/plot-generic.Rd index 9388b733..bfc6b490 100644 --- a/man/plot-generic.Rd +++ b/man/plot-generic.Rd @@ -36,7 +36,7 @@ x, point_size = 0.6, type = c("poly", "centroid"), - max_poly = getOption("giotto.plot_max_poly", 10000), + max_poly = getOption("giotto.plot_max_poly", 1e+06), ... ) From 51fd59f5d2006e2aeaef3dc011310f4486174a00 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 15 Aug 2024 09:35:13 -0400 Subject: [PATCH 121/160] fix: overwriting with repeated inits --- R/methods-initialize.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/methods-initialize.R b/R/methods-initialize.R index fb15232e..a37e403d 100644 --- a/R/methods-initialize.R +++ b/R/methods-initialize.R @@ -625,7 +625,7 @@ setMethod("initialize", signature("giottoLargeImage"), function(.Object, ...) { as.vector(terra::ext(r)) # max window - .Object@max_window <- .Object@max_intensity + .Object@max_window <- .Object@max_window %null% .Object@max_intensity # .Object@max_window <- .Object@max_window %na% # .bitdepth(.Object@max_intensity, return_max = TRUE) From 54a772ccf061d0fc3f4bcbffa88f376fe7dc2032 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 15 Aug 2024 21:26:54 -0400 Subject: [PATCH 122/160] feat!: deprecate instructions functions --- NAMESPACE | 1 + NEWS.md | 4 ++ R/instructions.R | 65 +++++++++++++++++++++++++++----- R/methods-instructions.R | 22 ++++++++++- man/changeGiottoInstructions.Rd | 3 +- man/instructions-generic.Rd | 22 ++++++++++- man/readGiottoInstructions.Rd | 3 +- man/replaceGiottoInstructions.Rd | 3 +- man/showGiottoInstructions.Rd | 3 +- 9 files changed, 111 insertions(+), 15 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index d0579a65..1792fc1d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -9,6 +9,7 @@ S3method(.DollarNames,terraVectData) S3method(as.data.table,SpatVector) S3method(as.data.table,giottoPoints) S3method(as.data.table,giottoPolygon) +S3method(print,giottoInstructions) S3method(t,spatLocsObj) S3method(t,spatialNetworkObj) export(addCellMetadata) diff --git a/NEWS.md b/NEWS.md index c247d17a..166c9cb7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,11 +4,15 @@ ## breaking changes - `set_giotto_python_path()` will now also initialize python env to set by default and print which python env is active, but otherwise do nothing if any python env has already been initialized. - `checkGiottoEnvironment()` no longer checks specifically for the `"giotto_env"` environment, but is instead a general check for whether Giotto can detect a python environment and also which it is. +- deprecated `readGiottoInstructions()`, `showGiottoInstructions()`, `changeGiottoInstructions()`, `replaceGiottoInstructions()` in favor of `instructions()` generic ## bug fixes - intensity images now automatically scale to estimated highest value - `giottoPolygon` `plot()` default `max_poly` raised to `1e6` +- `giottoInstructions` no longer lose class when specific params are replaced +## enhancements +- `print()` method for `giottoInstructions` # GiottoClass 0.3.4 (2024/08/04) diff --git a/R/instructions.R b/R/instructions.R index da738fb0..728561ee 100644 --- a/R/instructions.R +++ b/R/instructions.R @@ -175,7 +175,13 @@ create_giotto_instructions <- function(python_path = NULL, } -#' @title Read giotto instructions associated with giotto object + +# deprecated #### + +# These functions have been made internal. They will stop being exported +# in a future version of GiottoClass + +#' @title deprecated #' @name readGiottoInstructions #' @description Retrieves the instruction associated with the provided parameter #' @param giotto_instructions giotto object or result from @@ -190,9 +196,17 @@ create_giotto_instructions <- function(python_path = NULL, #' param = "show_plot" #' ) #' @export +#' @keywords internal readGiottoInstructions <- function(giotto_instructions, param = NULL, default) { + + deprecate_warn( + when = "0.3.5", + what = "readGiottoInstructions()", + with = "instructions()" + ) + # get instructions if provided the giotto object if (inherits(giotto_instructions, "giotto")) { giotto_instructions <- giotto_instructions@instructions @@ -213,7 +227,7 @@ readGiottoInstructions <- function(giotto_instructions, } -#' @title Show giotto instructions associated with giotto object +#' @title deprecated #' @name showGiottoInstructions #' @description Function to display all instructions from giotto object #' @param gobject giotto object @@ -223,13 +237,21 @@ readGiottoInstructions <- function(giotto_instructions, #' #' showGiottoInstructions(g) #' @export +#' @keywords internal showGiottoInstructions <- function(gobject) { + + deprecate_warn( + when = "0.3.5", + what = "showGiottoInstructions()", + with = "instructions()" + ) + instrs <- gobject@instructions return(instrs) } -#' @title Change giotto instruction(s) associated with giotto object +#' @title deprecated #' @name changeGiottoInstructions #' @description Function to change one or more instructions from giotto object. #' If more than one item is supplied to \code{params} and \code{new_values}, use @@ -248,11 +270,20 @@ showGiottoInstructions <- function(gobject) { #' new_values = TRUE #' ) #' @export +#' @keywords internal changeGiottoInstructions <- function(gobject, params = NULL, new_values = NULL, return_gobject = TRUE, init_gobject = TRUE) { + + deprecate_warn( + when = "0.3.5", + what = "changeGiottoInstructions()", + with = "instructions()" + ) + + instrs <- gobject@instructions if (is.null(params) | is.null(new_values)) { @@ -263,10 +294,6 @@ changeGiottoInstructions <- function(gobject, stop("\t length of params need to be the same as new values \t") } - # if(!all(params %in% names(instrs))) { - # stop('\t all params need to be part of Giotto instructions \t') - # } - ## swap with new values instrs[params] <- new_values @@ -289,7 +316,7 @@ changeGiottoInstructions <- function(gobject, }) names(new_instrs) <- names(instrs) - + class(new_instrs) <- "giottoInstructions" if (isTRUE(return_gobject)) { @@ -303,7 +330,7 @@ changeGiottoInstructions <- function(gobject, -#' @title Replace all giotto instructions in giotto object +#' @title deprecated #' @name replaceGiottoInstructions #' @description Function to replace all instructions from giotto object. Does #' not call \code{initialize} on the giotto object @@ -321,9 +348,17 @@ changeGiottoInstructions <- function(gobject, #' instructions = createGiottoInstructions() #' ) #' @export +#' @keywords internal replaceGiottoInstructions <- function(gobject, instructions = NULL, init_gobject = TRUE) { + + deprecate_warn( + when = "0.3.5", + what = "replaceGiottoInstructions()", + with = "instructions()" + ) + instrs_needed <- names(create_giotto_instructions()) # validate new instructions @@ -338,3 +373,15 @@ replaceGiottoInstructions <- function(gobject, return(gobject) } } + + +# internals #### + +#' @export +print.giottoInstructions <- function(x) { + cat(sprintf("<%s>\n", class(x)[1])) + print_list(x) +} + + + diff --git a/R/methods-instructions.R b/R/methods-instructions.R index d615f687..a3a6e0e3 100644 --- a/R/methods-instructions.R +++ b/R/methods-instructions.R @@ -19,7 +19,27 @@ NULL #' @examples #' g <- GiottoData::loadGiottoMini("visium") #' -#' showGiottoInstructions(g) +#' # get instructions +#' instrs <- instructions(g) +#' force(instrs) +#' +#' # get single instructions param +#' instructions(g, "show_plot") +#' +#' # replace single instruction param +#' instructions(g, "show_plot") <- FALSE +#' instructions(g, "show_plot") +#' +#' # replace multiple instruction params +#' instructions(g) +#' instructions(g, c("show_plot", "dpi")) <- list(TRUE, 600) +#' instructions(g) +#' +#' # replace instructions +#' i <- createGiottoInstructions() +#' instructions(g) <- i +#' instructions(g) +#' NULL #' @title Active spatial unit diff --git a/man/changeGiottoInstructions.Rd b/man/changeGiottoInstructions.Rd index 8db4cc15..caa90dc9 100644 --- a/man/changeGiottoInstructions.Rd +++ b/man/changeGiottoInstructions.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/instructions.R \name{changeGiottoInstructions} \alias{changeGiottoInstructions} -\title{Change giotto instruction(s) associated with giotto object} +\title{deprecated} \usage{ changeGiottoInstructions( gobject, @@ -39,3 +39,4 @@ changeGiottoInstructions( new_values = TRUE ) } +\keyword{internal} diff --git a/man/instructions-generic.Rd b/man/instructions-generic.Rd index fa2af3ea..8b3f071e 100644 --- a/man/instructions-generic.Rd +++ b/man/instructions-generic.Rd @@ -46,5 +46,25 @@ initialize param is TRUE \examples{ g <- GiottoData::loadGiottoMini("visium") -showGiottoInstructions(g) +# get instructions +instrs <- instructions(g) +force(instrs) + +# get single instructions param +instructions(g, "show_plot") + +# replace single instruction param +instructions(g, "show_plot") <- FALSE +instructions(g, "show_plot") + +# replace multiple instruction params +instructions(g) +instructions(g, c("show_plot", "dpi")) <- list(TRUE, 600) +instructions(g) + +# replace instructions +i <- createGiottoInstructions() +instructions(g) <- i +instructions(g) + } diff --git a/man/readGiottoInstructions.Rd b/man/readGiottoInstructions.Rd index b79a52e5..3a1b9ca5 100644 --- a/man/readGiottoInstructions.Rd +++ b/man/readGiottoInstructions.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/instructions.R \name{readGiottoInstructions} \alias{readGiottoInstructions} -\title{Read giotto instructions associated with giotto object} +\title{deprecated} \usage{ readGiottoInstructions(giotto_instructions, param = NULL, default) } @@ -27,3 +27,4 @@ readGiottoInstructions( param = "show_plot" ) } +\keyword{internal} diff --git a/man/replaceGiottoInstructions.Rd b/man/replaceGiottoInstructions.Rd index 3834d208..4abcc883 100644 --- a/man/replaceGiottoInstructions.Rd +++ b/man/replaceGiottoInstructions.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/instructions.R \name{replaceGiottoInstructions} \alias{replaceGiottoInstructions} -\title{Replace all giotto instructions in giotto object} +\title{deprecated} \usage{ replaceGiottoInstructions(gobject, instructions = NULL, init_gobject = TRUE) } @@ -30,3 +30,4 @@ replaceGiottoInstructions( instructions = createGiottoInstructions() ) } +\keyword{internal} diff --git a/man/showGiottoInstructions.Rd b/man/showGiottoInstructions.Rd index 6f1e8e5a..7c66519d 100644 --- a/man/showGiottoInstructions.Rd +++ b/man/showGiottoInstructions.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/instructions.R \name{showGiottoInstructions} \alias{showGiottoInstructions} -\title{Show giotto instructions associated with giotto object} +\title{deprecated} \usage{ showGiottoInstructions(gobject) } @@ -20,3 +20,4 @@ g <- GiottoData::loadGiottoMini("visium") showGiottoInstructions(g) } +\keyword{internal} From c00c7e1d4176e9abbe31309e70ae65633a887faf Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 16 Aug 2024 02:13:21 -0400 Subject: [PATCH 123/160] chore: combine instructions docs --- R/instructions.R | 9 +-- R/methods-instructions.R | 37 +++++---- man/createGiottoInstructions.Rd | 69 ----------------- man/giotto_instructions.Rd | 129 ++++++++++++++++++++++++++++++++ man/instructions-generic.Rd | 70 ----------------- 5 files changed, 154 insertions(+), 160 deletions(-) delete mode 100644 man/createGiottoInstructions.Rd create mode 100644 man/giotto_instructions.Rd delete mode 100644 man/instructions-generic.Rd diff --git a/R/instructions.R b/R/instructions.R index 728561ee..45271499 100644 --- a/R/instructions.R +++ b/R/instructions.R @@ -1,9 +1,7 @@ # Giotto instructions #### -#' @title Create instructions for giotto functions -#' @name createGiottoInstructions -#' @description Function to set global instructions for giotto functions +#' @rdname giotto_instructions #' @param python_path path to python binary to use or directory one level #' up from the `env` directory (similar to output of #' `reticulate::miniconda_path()`) @@ -22,11 +20,6 @@ #' @param fiji_path path to fiji executable #' @param no_python_warn turn off warning that no compatible python env has #' been detected -#' @returns named vector with giotto instructions -#' @seealso More online information can be found -#' here \url{http://giottosuite.com} -#' @examples -#' createGiottoInstructions() #' @export createGiottoInstructions <- function( python_path = getOption("giotto.py_path"), diff --git a/R/methods-instructions.R b/R/methods-instructions.R index a3a6e0e3..317bf89f 100644 --- a/R/methods-instructions.R +++ b/R/methods-instructions.R @@ -3,19 +3,30 @@ NULL # docs ----------------------------------------------------------- # -#' @title Access giotto instructions -#' @name instructions-generic +#' @title Giotto instructions +#' @name giotto_instructions #' @aliases instructions instructions<- -#' @description Retrieve or set giotto instructions. Specific instructions can -#' be replaced using the \code{field} param. Additionally, when using -#' instructions<-, \code{initialize()} will be called on the giotto object if -#' initialize param is TRUE +#' @description +#' Giotto instructions are default settings that are applied at the `giotto` +#' object level. Once added to an object, they affect the way that the object +#' behaves. You can create a `giottoInstructions` object using +#' `createGiottoInstructions()` and add them to the `giotto` object during +#' creation or using the `instructions()` generic. Specific settings can be +#' replaced or retrieved using the `param` argument. Additionally, when using +#' `instructions<-()` as a replacement function, `initialize()` will be called +#' on the `giotto` object if `initialize = TRUE`. +#' +#' If no `giottoInstructions` object is provided during `giotto` object +#' creation, then a default one will be created during `giotto` object +#' initialization. +#' #' @inheritParams data_access_params #' @param param Specific param in instructions to access or modify #' @param initialize (boolean, default = TRUE) whether to initialize the giotto #' object #' @param value value to set -#' @returns giotto instructions +#' @returns `giottoInstructions`, instructions settings, or `giotto` objects +#' with modified instructions #' @examples #' g <- GiottoData::loadGiottoMini("visium") #' @@ -74,7 +85,7 @@ NULL # instructions() method #### # Get instructions object -#' @rdname instructions-generic +#' @rdname giotto_instructions #' @export setMethod( "instructions", signature(gobject = "giotto", param = "missing"), @@ -84,7 +95,7 @@ setMethod( ) # Set instructions object -#' @rdname instructions-generic +#' @rdname giotto_instructions #' @export setMethod( "instructions<-", @@ -100,7 +111,7 @@ setMethod( return(gobject) } ) -#' @rdname instructions-generic +#' @rdname giotto_instructions #' @export setMethod( "instructions<-", @@ -118,7 +129,7 @@ setMethod( ) # Get specific field -#' @rdname instructions-generic +#' @rdname giotto_instructions #' @export setMethod( "instructions", signature(gobject = "giotto", param = "character"), @@ -132,7 +143,7 @@ setMethod( ) # Set specific field -#' @rdname instructions-generic +#' @rdname giotto_instructions #' @export setMethod( "instructions<-", @@ -151,7 +162,7 @@ setMethod( return(gobject) } ) -#' @rdname instructions-generic +#' @rdname giotto_instructions #' @export setMethod( "instructions<-", diff --git a/man/createGiottoInstructions.Rd b/man/createGiottoInstructions.Rd deleted file mode 100644 index 6f989ab1..00000000 --- a/man/createGiottoInstructions.Rd +++ /dev/null @@ -1,69 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/instructions.R -\name{createGiottoInstructions} -\alias{createGiottoInstructions} -\title{Create instructions for giotto functions} -\usage{ -createGiottoInstructions( - python_path = getOption("giotto.py_path"), - show_plot = NULL, - return_plot = NULL, - save_plot = NULL, - save_dir = NULL, - plot_format = NULL, - dpi = NULL, - units = NULL, - height = NULL, - width = NULL, - is_docker = FALSE, - plot_count = 0, - fiji_path = NULL, - no_python_warn = FALSE -) -} -\arguments{ -\item{python_path}{path to python binary to use or directory one level -up from the \code{env} directory (similar to output of -\code{reticulate::miniconda_path()})} - -\item{show_plot}{print plot to console, default = TRUE} - -\item{return_plot}{return plot as object, default = TRUE} - -\item{save_plot}{automatically save plot, dafault = FALSE} - -\item{save_dir}{path to directory where to save plots} - -\item{plot_format}{format of plots (defaults to png)} - -\item{dpi}{resolution for raster images} - -\item{units}{units of format (defaults to in)} - -\item{height}{height of plots} - -\item{width}{width of plots} - -\item{is_docker}{using docker implementation of Giotto (defaults to FALSE)} - -\item{plot_count}{(global option) start count for creating automatic unique -plots} - -\item{fiji_path}{path to fiji executable} - -\item{no_python_warn}{turn off warning that no compatible python env has -been detected} -} -\value{ -named vector with giotto instructions -} -\description{ -Function to set global instructions for giotto functions -} -\examples{ -createGiottoInstructions() -} -\seealso{ -More online information can be found -here \url{http://giottosuite.com} -} diff --git a/man/giotto_instructions.Rd b/man/giotto_instructions.Rd new file mode 100644 index 00000000..97bf5db6 --- /dev/null +++ b/man/giotto_instructions.Rd @@ -0,0 +1,129 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/instructions.R, R/methods-instructions.R +\name{createGiottoInstructions} +\alias{createGiottoInstructions} +\alias{giotto_instructions} +\alias{instructions} +\alias{instructions<-} +\alias{instructions,giotto,missing-method} +\alias{instructions<-,giotto,missing,missing-method} +\alias{instructions<-,giotto,missing,logical-method} +\alias{instructions,giotto,character-method} +\alias{instructions<-,giotto,character,missing-method} +\alias{instructions<-,giotto,character,logical-method} +\title{Giotto instructions} +\usage{ +createGiottoInstructions( + python_path = getOption("giotto.py_path"), + show_plot = NULL, + return_plot = NULL, + save_plot = NULL, + save_dir = NULL, + plot_format = NULL, + dpi = NULL, + units = NULL, + height = NULL, + width = NULL, + is_docker = FALSE, + plot_count = 0, + fiji_path = NULL, + no_python_warn = FALSE +) + +\S4method{instructions}{giotto,missing}(gobject) + +\S4method{instructions}{giotto,missing,missing}(gobject, initialize) <- value + +\S4method{instructions}{giotto,missing,logical}(gobject, initialize) <- value + +\S4method{instructions}{giotto,character}(gobject, param) + +\S4method{instructions}{giotto,character,missing}(gobject, param, initialize) <- value + +\S4method{instructions}{giotto,character,logical}(gobject, param, initialize) <- value +} +\arguments{ +\item{python_path}{path to python binary to use or directory one level +up from the \code{env} directory (similar to output of +\code{reticulate::miniconda_path()})} + +\item{show_plot}{print plot to console, default = TRUE} + +\item{return_plot}{return plot as object, default = TRUE} + +\item{save_plot}{automatically save plot, dafault = FALSE} + +\item{save_dir}{path to directory where to save plots} + +\item{plot_format}{format of plots (defaults to png)} + +\item{dpi}{resolution for raster images} + +\item{units}{units of format (defaults to in)} + +\item{height}{height of plots} + +\item{width}{width of plots} + +\item{is_docker}{using docker implementation of Giotto (defaults to FALSE)} + +\item{plot_count}{(global option) start count for creating automatic unique +plots} + +\item{fiji_path}{path to fiji executable} + +\item{no_python_warn}{turn off warning that no compatible python env has +been detected} + +\item{gobject}{giotto object} + +\item{initialize}{(boolean, default = TRUE) whether to initialize the giotto +object} + +\item{value}{value to set} + +\item{param}{Specific param in instructions to access or modify} +} +\value{ +\code{giottoInstructions}, instructions settings, or \code{giotto} objects +with modified instructions +} +\description{ +Giotto instructions are default settings that are applied at the \code{giotto} +object level. Once added to an object, they affect the way that the object +behaves. You can create a \code{giottoInstructions} object using +\code{createGiottoInstructions()} and add them to the \code{giotto} object during +creation or using the \code{instructions()} generic. Specific settings can be +replaced or retrieved using the \code{param} argument. Additionally, when using +\verb{instructions<-()} as a replacement function, \code{initialize()} will be called +on the \code{giotto} object if \code{initialize = TRUE}. + +If no \code{giottoInstructions} object is provided during \code{giotto} object +creation, then a default one will be created during \code{giotto} object +initialization. +} +\examples{ +g <- GiottoData::loadGiottoMini("visium") + +# get instructions +instrs <- instructions(g) +force(instrs) + +# get single instructions param +instructions(g, "show_plot") + +# replace single instruction param +instructions(g, "show_plot") <- FALSE +instructions(g, "show_plot") + +# replace multiple instruction params +instructions(g) +instructions(g, c("show_plot", "dpi")) <- list(TRUE, 600) +instructions(g) + +# replace instructions +i <- createGiottoInstructions() +instructions(g) <- i +instructions(g) + +} diff --git a/man/instructions-generic.Rd b/man/instructions-generic.Rd deleted file mode 100644 index 8b3f071e..00000000 --- a/man/instructions-generic.Rd +++ /dev/null @@ -1,70 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/methods-instructions.R -\name{instructions-generic} -\alias{instructions-generic} -\alias{instructions} -\alias{instructions<-} -\alias{instructions,giotto,missing-method} -\alias{instructions<-,giotto,missing,missing-method} -\alias{instructions<-,giotto,missing,logical-method} -\alias{instructions,giotto,character-method} -\alias{instructions<-,giotto,character,missing-method} -\alias{instructions<-,giotto,character,logical-method} -\title{Access giotto instructions} -\usage{ -\S4method{instructions}{giotto,missing}(gobject) - -\S4method{instructions}{giotto,missing,missing}(gobject, initialize) <- value - -\S4method{instructions}{giotto,missing,logical}(gobject, initialize) <- value - -\S4method{instructions}{giotto,character}(gobject, param) - -\S4method{instructions}{giotto,character,missing}(gobject, param, initialize) <- value - -\S4method{instructions}{giotto,character,logical}(gobject, param, initialize) <- value -} -\arguments{ -\item{gobject}{giotto object} - -\item{initialize}{(boolean, default = TRUE) whether to initialize the giotto -object} - -\item{value}{value to set} - -\item{param}{Specific param in instructions to access or modify} -} -\value{ -giotto instructions -} -\description{ -Retrieve or set giotto instructions. Specific instructions can -be replaced using the \code{field} param. Additionally, when using -instructions<-, \code{initialize()} will be called on the giotto object if -initialize param is TRUE -} -\examples{ -g <- GiottoData::loadGiottoMini("visium") - -# get instructions -instrs <- instructions(g) -force(instrs) - -# get single instructions param -instructions(g, "show_plot") - -# replace single instruction param -instructions(g, "show_plot") <- FALSE -instructions(g, "show_plot") - -# replace multiple instruction params -instructions(g) -instructions(g, c("show_plot", "dpi")) <- list(TRUE, 600) -instructions(g) - -# replace instructions -i <- createGiottoInstructions() -instructions(g) <- i -instructions(g) - -} From 90ad3003781822cb37146f7e59db40c3b60fd3ec Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 21 Aug 2024 09:13:08 -0400 Subject: [PATCH 124/160] chore: change instructions deprecate to soft --- R/instructions.R | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/R/instructions.R b/R/instructions.R index 45271499..340fb98b 100644 --- a/R/instructions.R +++ b/R/instructions.R @@ -194,7 +194,7 @@ readGiottoInstructions <- function(giotto_instructions, param = NULL, default) { - deprecate_warn( + deprecate_soft( when = "0.3.5", what = "readGiottoInstructions()", with = "instructions()" @@ -233,7 +233,7 @@ readGiottoInstructions <- function(giotto_instructions, #' @keywords internal showGiottoInstructions <- function(gobject) { - deprecate_warn( + deprecate_soft( when = "0.3.5", what = "showGiottoInstructions()", with = "instructions()" @@ -270,7 +270,7 @@ changeGiottoInstructions <- function(gobject, return_gobject = TRUE, init_gobject = TRUE) { - deprecate_warn( + deprecate_soft( when = "0.3.5", what = "changeGiottoInstructions()", with = "instructions()" @@ -346,7 +346,7 @@ replaceGiottoInstructions <- function(gobject, instructions = NULL, init_gobject = TRUE) { - deprecate_warn( + deprecate_soft( when = "0.3.5", what = "replaceGiottoInstructions()", with = "instructions()" From 8646f9f628cea5dd7e80ab448f062e06ad8826cd Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 21 Aug 2024 11:28:08 -0400 Subject: [PATCH 125/160] fix: update ometif converter reqs --- R/images.R | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/R/images.R b/R/images.R index 226c084c..b763892c 100644 --- a/R/images.R +++ b/R/images.R @@ -2745,7 +2745,11 @@ ometif_to_tif <- function(input_file, a <- list(input_file = input_file) # get tifffile py - package_check("tifffile", repository = "pip:tifffile") + package_check( + pkg_name = c("tifffile", "imagecodecs"), + repository = c("pip:tifffile", "pip:imagecodecs") + ) + ometif2tif_path <- system.file( "python", "ometif_convert.py", package = "GiottoClass" From 9c6674dfaf344ae5e933f907a2928e2a6648a385 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:10:19 -0400 Subject: [PATCH 126/160] fix: prevent erroring during checking giotto env --- R/python_environment.R | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/R/python_environment.R b/R/python_environment.R index dcd40499..63ff079a 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -1012,7 +1012,9 @@ checkPythonPackage <- function(package_name = NULL, os = get_os(), must_exist = TRUE ) { - checkmate::assert_directory_exists(path) + if (!checkmate::test_directory_exists(path)) { + vmsg(.is_debug = TRUE, ".os_py_path: base dir not found!") + } env_level <- file.path(path, "envs", envname) full_path <- switch(os, "osx" = file.path(env_level, "bin/pythonw"), From 75adeea3512eab1d9aa87c4e0d1c8b7f2a1bfa38 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Sun, 25 Aug 2024 04:30:14 -0400 Subject: [PATCH 127/160] fix: checking now properly returns NULL when py path was specified --- R/python_environment.R | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 63ff079a..209e2cee 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -638,13 +638,29 @@ set_giotto_python_path <- function( "a system default python environment was found" ) + # `specified` flag + # flag for when path is directly intended. When not NULL, instead of + # quietly passing to next default, send message and immediately return + # NULL + specified <- NULL + # (1.) from user (when `python_path` != NULL) - if (!is.null(python_path)) found <- c(found, 1) + if (!is.null(python_path)) { + found <- c(found, 1) + specified <- sprintf("`envname` = '%s'", python_path) + } # (2.) check option (default is null) python_path <- python_path %null% getOption("giotto.py_path") - if (!is.null(python_path)) found <- c(found, 2) - + if (!is.null(python_path) && length(found) == 0L) { + found <- c(found, 2) + specified <- sprintf( + "%s: \"%s\"", + "option 'giotto.py_path'", + getOption("giotto.py_path") + ) + } + # (3.) check default install path; if not existing, returns NULL # will return NULL for .condarc alternate location "giotto_env" installs python_path <- python_path %null% .os_py_path(must_exist = TRUE) @@ -665,6 +681,12 @@ set_giotto_python_path <- function( # if python_path thus far is not completable to an existing path # return NULL, otherwise return existing path python_path <- .full_miniconda_path(path = python_path) + + # early return NULL if specified and NOT found. + if (is.null(python_path) && !is.null(specified)) { + vmsg(sprintf("specified py env from %s not found\n", specified)) + return(invisible()) + } # (5.) detect from system call; return NULL if not found python_path <- python_path %null% .sys_detect_py() From 1f2c64c9ee840fce1a24fecb2380dc2ce3489cc4 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 26 Aug 2024 01:55:26 -0400 Subject: [PATCH 128/160] fix: giottoInstructions definition --- R/instructions.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/instructions.R b/R/instructions.R index 340fb98b..32d714db 100644 --- a/R/instructions.R +++ b/R/instructions.R @@ -371,7 +371,7 @@ replaceGiottoInstructions <- function(gobject, # internals #### #' @export -print.giottoInstructions <- function(x) { +print.giottoInstructions <- function(x, ...) { cat(sprintf("<%s>\n", class(x)[1])) print_list(x) } From 48101b7e17e5106b4c53e36846b9153f4dd31d7e Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 26 Aug 2024 01:55:39 -0400 Subject: [PATCH 129/160] fix: add spatialdata globals --- R/globals.R | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/R/globals.R b/R/globals.R index ae48bfec..7c6a770e 100644 --- a/R/globals.R +++ b/R/globals.R @@ -4,7 +4,9 @@ utils::globalVariables( "python_leiden", "python_louvain", "python_spatial_genes", "Spatial_DE_AEH", "Spatial_DE", "silhouette_rank", "python_scrublet", "python_create_mesmer_app", - "python_segment_image", "ad_guard", "dir_guard", "ad_obj", + "python_segment_image", + # anndata interop + "ad_guard", "dir_guard", "ad_obj", "lay_inv", "set_adg_layer_data", "set_adg_spat_locs", "set_adg_metadata", "set_adg_pca", "set_adg_umap", "set_adg_tsne", "write_ad_h5ad", "read_anndata_from_path", @@ -15,6 +17,11 @@ utils::globalVariables( "extract_layered_data", "set_adg_nn", "find_NN_keys", "extract_NN_connectivities", "extract_NN_distances", "extract_NN_info", "align_network_data", "extract_SN_connectivities", - "extract_SN_distances", "set_adg_sn", "create_AnnData", "ometif_2_tif" + "extract_SN_distances", "set_adg_sn", "create_AnnData", + # tifffile + "ometif_2_tif", + # spatialdata interop + "createSpatialData", "read_spatialdata_from_path", "extract_spatial", + "extract_image" ) ) From d7c9b46473022cfaf063223a6d2e1e27101675a4 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 26 Aug 2024 01:55:51 -0400 Subject: [PATCH 130/160] chore: docs formatting --- R/interoperability.R | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/R/interoperability.R b/R/interoperability.R index 57924b22..8253a337 100644 --- a/R/interoperability.R +++ b/R/interoperability.R @@ -175,10 +175,10 @@ check_py_for_scanpy <- function() { #' anndata object, a list of key_added terms may be provided. If converting an #' anndata object from giottoToAnnData, a .txt file may be provided, which was #' generated in that function, -#' i.e. {spat_unit}_{feat_type}_spatial_network_keys_added.txt +#' i.e. \{spat_unit\}_\{feat_type\}_spatial_network_keys_added.txt #' Cannot be the same as n_key_added. #' @param delaunay_spat_net binary parameter for spatial network. If TRUE, the -#' spatial network is a deluanay network. +#' spatial network is a delaunay network. #' @param spat_unit desired spatial unit to use for conversion, default NULL #' @param feat_type desired feature type to use for conversion, default NULL #' @param h5_file name to create and on-disk HDF5 file @@ -3383,20 +3383,22 @@ giottoMasterToSuite <- function( #' #' @param spatialdata_path path to SpatialData object #' @param n_key_added equivalent of "key_added" argument from scanpy.pp.neighbors(). -#' If multiple spatial networks are in the anndata object, a list of key_added -#' terms may be provided. -#' If converting an anndata object from giottoToAnnData, a .txt file may be -#' provided, which was generated in that function, -#' i.e. {spat_unit}_{feat_type}_nn_network_keys_added.txt -#' Cannot be "spatial". This becomes the name of the nearest network in the gobject. -#' @param spatial_n_key_added equivalent of "key_added" argument from squidpy.gr.spatial_neighbors. -#' If multiple spatial networks are in the anndata object, a list of key_added -#' terms may be provided. -#' If converting an anndata object from giottoToAnnData, a .txt file may be -#' provided, which was generated in that function, -#' i.e. {spat_unit}_{feat_type}_spatial_network_keys_added.txt -#' Cannot be the same as n_key_added. -#' @param delaunay_spat_net binary parameter for spatial network. If TRUE, the spatial network is a delaunay network. +#' If multiple spatial networks are in the anndata object, a list of key_added +#' terms may be provided. +#' If converting an anndata object from giottoToAnnData, a .txt file may be +#' provided, which was generated in that function, +#' i.e. \{spat_unit\}_\{feat_type\}_nn_network_keys_added.txt +#' Cannot be "spatial". This becomes the name of the nearest network in the gobject. +#' @param spatial_n_key_added +#' equivalent of "key_added" argument from squidpy.gr.spatial_neighbors. +#' If multiple spatial networks are in the anndata object, a list of key_added +#' terms may be provided. +#' If converting an anndata object from giottoToAnnData, a .txt file may be +#' provided, which was generated in that function, +#' i.e. \{spat_unit\}_\{feat_type\}_spatial_network_keys_added.txt +#' Cannot be the same as n_key_added. +#' @param delaunay_spat_net binary parameter for spatial network. If TRUE, +#' the spatial network is a delaunay network. #' @param spat_unit desired spatial unit for conversion, default NULL #' @param feat_type desired feature type for conversion, default NULL #' @param python_path path to python executable within a conda/miniconda environment From 464e258dd9ff51ea2e42912c208b187757509216 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 26 Aug 2024 01:57:21 -0400 Subject: [PATCH 131/160] fix: dev GHA script --- .github/workflows/dev_check.yml | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/.github/workflows/dev_check.yml b/.github/workflows/dev_check.yml index c38f4fb1..df79c7a6 100644 --- a/.github/workflows/dev_check.yml +++ b/.github/workflows/dev_check.yml @@ -87,24 +87,21 @@ jobs: - name: setup giotto_env shell: Rscript {0} run: | - path_to_python <- reticulate::virtualenv_create( - envname = "giotto_env", - python = Sys.which("python"), # placed on PATH by the setup-python action - packages = c( - "pandas==1.5.1", - "networkx==2.8.8", - "python-igraph==0.10.2", - "leidenalg==0.9.0", - "python-louvain==0.16", - "scikit-learn==1.1.3", - "scipy==1.13.0", - "scanpy" - ) - ) - - writeLines(sprintf("RETICULATE_PYTHON=%s", path_to_python), - Sys.getenv("GITHUB_ENV")) + if (!GiottoClass::checkGiottoEnvironment(envname = "giotto_env")) { + GiottoClass::installGiottoEnvironment() + } + reticulate::conda_install( + envname = 'giotto_env', + packages = 'scanpy', + pip = TRUE + ) + + path_to_python <- GiottoClass::set_giotto_python_path() + + writeLines(sprintf("RETICULATE_PYTHON=%s", path_to_python), + Sys.getenv("GITHUB_ENV")) + - name: Run R CMD check uses: r-lib/actions/check-r-package@v2 with: From 3622964a2196850ae73b9de2fcd3e2544f230b2e Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 26 Aug 2024 02:00:13 -0400 Subject: [PATCH 132/160] fix: update example using native pipe --- R/methods-affine.R | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/R/methods-affine.R b/R/methods-affine.R index 21fc9b11..50599db7 100644 --- a/R/methods-affine.R +++ b/R/methods-affine.R @@ -435,16 +435,16 @@ setMethod("affine", signature(x = "affine2d", y = "matrix"), function( #' #' # perform piecewise transforms with decomp #' -#' sl_shear_piecewise <- sl %>% -#' spin(GiottoUtils::degrees(s$rotate), x0 = 0, y0 = 0) %>% -#' shear(fx = s$shear[["x"]], fy = s$shear[["y"]], x0 = 0, y0 = 0) %>% -#' rescale(fx = s$scale[["x"]], fy = s$scale[["y"]], x0 = 0, y0 = 0) %>% +#' sl_shear_piecewise <- sl |> +#' spin(GiottoUtils::degrees(s$rotate), x0 = 0, y0 = 0) |> +#' shear(fx = s$shear[["x"]], fy = s$shear[["y"]], x0 = 0, y0 = 0) |> +#' rescale(fx = s$scale[["x"]], fy = s$scale[["y"]], x0 = 0, y0 = 0) |> #' spatShift(dx = s$translate[["x"]], dy = s$translate[["y"]]) #' -#' sl_aff_piecewise <- sl %>% -#' spin(GiottoUtils::degrees(a$rotate), x0 = 0, y0 = 0) %>% -#' shear(fx = a$shear[["x"]], fy = a$shear[["y"]], x0 = 0, y0 = 0) %>% -#' rescale(fx = a$scale[["x"]], fy = a$scale[["y"]], x0 = 0, y0 = 0) %>% +#' sl_aff_piecewise <- sl |> +#' spin(GiottoUtils::degrees(a$rotate), x0 = 0, y0 = 0) |> +#' shear(fx = a$shear[["x"]], fy = a$shear[["y"]], x0 = 0, y0 = 0) |> +#' rescale(fx = a$scale[["x"]], fy = a$scale[["y"]], x0 = 0, y0 = 0) |> #' spatShift(dx = a$translate[["x"]], dy = a$translate[["y"]]) #' #' plot(affine(sl, shear_m)) From fdca37663b7432e1581208b2a0937c1ef6b2fe0e Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 26 Aug 2024 02:56:07 -0400 Subject: [PATCH 133/160] chore: docs for as.character --- R/methods-show.R | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/R/methods-show.R b/R/methods-show.R index 0c479779..05ff7333 100644 --- a/R/methods-show.R +++ b/R/methods-show.R @@ -1,6 +1,19 @@ #' @include classes.R NULL +#' @name as.character +#' @title Create a text representation of an object +#' @description +#' Create a text representation of an object +#' @param x object +#' @examples +#' img <- GiottoData::loadSubObjectMini("giottoLargeImage") +#' as.character(img) +#' +NULL + + + # ------------------------------------------------------ # @@ -721,7 +734,9 @@ setMethod( } ) -# internal + +#' @rdname as.character +#' @export setMethod("as.character", signature("giottoImage"), function(x, ...) { sprintf("<%s> %s", class(x), objName(x)) }) @@ -808,7 +823,8 @@ setMethod("show", signature("affine2d"), function(object) { }) -# internal +#' @rdname as.character +#' @export setMethod("as.character", signature("giottoLargeImage"), function(x, ...) { sprintf("<%s> %s", class(x), objName(x)) }) From 97802bf6e14a2b96e0215bacb160902de761314d Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 26 Aug 2024 02:57:08 -0400 Subject: [PATCH 134/160] chore: docs for hist and density --- R/images.R | 28 ++++++++++++++++++---------- R/package_imports.R | 1 + 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/R/images.R b/R/images.R index b763892c..f9927e03 100644 --- a/R/images.R +++ b/R/images.R @@ -2644,23 +2644,31 @@ distGiottoImage <- function( #' gimg <- createGiottoLargeImage(f, use_rast_ext = TRUE) #' #' density(gimg) +NULL + +#' @rdname density #' @export setMethod( "density", signature("giottoLargeImage"), function(x, show_max = TRUE, ...) { - a <- list(x = x@raster_object, ...) - res <- do.call(terra::density, args = a) - - if (isFALSE(a$plot)) { - return(res) - } - - if (isTRUE(show_max)) { - graphics::abline(v = x@max_window, col = "red") - } + a <- get_args_list(...) + do.call(.density_giottolargeimage, args = a) } ) +.density_giottolargeimage <- function(x, show_max = TRUE, ...) { + a <- list(x = x@raster_object, ...) + res <- do.call(terra::density, args = a) + + if (isFALSE(a$plot)) { + return(res) + } + + if (isTRUE(show_max)) { + graphics::abline(v = x@max_window, col = "red") + } +} + #' @name hist #' @title Histogram diff --git a/R/package_imports.R b/R/package_imports.R index 07526325..fae1d313 100644 --- a/R/package_imports.R +++ b/R/package_imports.R @@ -36,6 +36,7 @@ #' @importMethodsFrom terra as.polygons as.points #' @importMethodsFrom terra nrow ncol #' @importMethodsFrom terra zoom +#' @importMethodsFrom terra hist density #' @importClassesFrom terra SpatExtent #' @importClassesFrom terra SpatVector #' @import GiottoUtils From e5dba662b50b31e705e7278dd349788a1f7ea157 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 26 Aug 2024 02:57:22 -0400 Subject: [PATCH 135/160] chore: document --- NAMESPACE | 3 +++ man/anndataToGiotto.Rd | 4 ++-- man/as.character.Rd | 23 +++++++++++++++++++++++ man/decomp_affine.Rd | 16 ++++++++-------- man/density.Rd | 1 + man/spatialdataToGiotto.Rd | 7 ++++--- 6 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 man/as.character.Rd diff --git a/NAMESPACE b/NAMESPACE index 1792fc1d..a96b9758 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -325,6 +325,7 @@ exportMethods("spatUnit<-") exportMethods(activeFeatType) exportMethods(activeSpatUnit) exportMethods(affine) +exportMethods(as.character) exportMethods(as.matrix) exportMethods(as.points) exportMethods(as.polygons) @@ -409,8 +410,10 @@ importMethodsFrom(terra,as.points) importMethodsFrom(terra,as.polygons) importMethodsFrom(terra,centroids) importMethodsFrom(terra,crop) +importMethodsFrom(terra,density) importMethodsFrom(terra,ext) importMethodsFrom(terra,flip) +importMethodsFrom(terra,hist) importMethodsFrom(terra,ncol) importMethodsFrom(terra,nrow) importMethodsFrom(terra,plot) diff --git a/man/anndataToGiotto.Rd b/man/anndataToGiotto.Rd index 74efa2ba..853f63d9 100644 --- a/man/anndataToGiotto.Rd +++ b/man/anndataToGiotto.Rd @@ -31,11 +31,11 @@ squidpy.gr.spatial_neighbors. If multiple spatial networks are in the anndata object, a list of key_added terms may be provided. If converting an anndata object from giottoToAnnData, a .txt file may be provided, which was generated in that function, -i.e. {spat_unit}_{feat_type}_spatial_network_keys_added.txt +i.e. \{spat_unit\}_\{feat_type\}_spatial_network_keys_added.txt Cannot be the same as n_key_added.} \item{delaunay_spat_net}{binary parameter for spatial network. If TRUE, the -spatial network is a deluanay network.} +spatial network is a delaunay network.} \item{spat_unit}{desired spatial unit to use for conversion, default NULL} diff --git a/man/as.character.Rd b/man/as.character.Rd new file mode 100644 index 00000000..1225d0c1 --- /dev/null +++ b/man/as.character.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/methods-show.R +\name{as.character} +\alias{as.character} +\alias{as.character,giottoImage-method} +\alias{as.character,giottoLargeImage-method} +\title{Create a text representation of an object} +\usage{ +\S4method{as.character}{giottoImage}(x, ...) + +\S4method{as.character}{giottoLargeImage}(x, ...) +} +\arguments{ +\item{x}{object} +} +\description{ +Create a text representation of an object +} +\examples{ +img <- GiottoData::loadSubObjectMini("giottoLargeImage") +as.character(img) + +} diff --git a/man/decomp_affine.Rd b/man/decomp_affine.Rd index b50d0792..f4a74675 100644 --- a/man/decomp_affine.Rd +++ b/man/decomp_affine.Rd @@ -44,16 +44,16 @@ force(a) # perform piecewise transforms with decomp -sl_shear_piecewise <- sl \%>\% - spin(GiottoUtils::degrees(s$rotate), x0 = 0, y0 = 0) \%>\% - shear(fx = s$shear[["x"]], fy = s$shear[["y"]], x0 = 0, y0 = 0) \%>\% - rescale(fx = s$scale[["x"]], fy = s$scale[["y"]], x0 = 0, y0 = 0) \%>\% +sl_shear_piecewise <- sl |> + spin(GiottoUtils::degrees(s$rotate), x0 = 0, y0 = 0) |> + shear(fx = s$shear[["x"]], fy = s$shear[["y"]], x0 = 0, y0 = 0) |> + rescale(fx = s$scale[["x"]], fy = s$scale[["y"]], x0 = 0, y0 = 0) |> spatShift(dx = s$translate[["x"]], dy = s$translate[["y"]]) -sl_aff_piecewise <- sl \%>\% - spin(GiottoUtils::degrees(a$rotate), x0 = 0, y0 = 0) \%>\% - shear(fx = a$shear[["x"]], fy = a$shear[["y"]], x0 = 0, y0 = 0) \%>\% - rescale(fx = a$scale[["x"]], fy = a$scale[["y"]], x0 = 0, y0 = 0) \%>\% +sl_aff_piecewise <- sl |> + spin(GiottoUtils::degrees(a$rotate), x0 = 0, y0 = 0) |> + shear(fx = a$shear[["x"]], fy = a$shear[["y"]], x0 = 0, y0 = 0) |> + rescale(fx = a$scale[["x"]], fy = a$scale[["y"]], x0 = 0, y0 = 0) |> spatShift(dx = a$translate[["x"]], dy = a$translate[["y"]]) plot(affine(sl, shear_m)) diff --git a/man/density.Rd b/man/density.Rd index cbb50762..2cc80a2a 100644 --- a/man/density.Rd +++ b/man/density.Rd @@ -2,6 +2,7 @@ % Please edit documentation in R/images.R \name{density} \alias{density} +\alias{density,giottoLargeImage-method} \title{Density plot} \usage{ \S4method{density}{giottoLargeImage}(x, show_max = TRUE, ...) diff --git a/man/spatialdataToGiotto.Rd b/man/spatialdataToGiotto.Rd index 5e0f238e..935e7dbe 100644 --- a/man/spatialdataToGiotto.Rd +++ b/man/spatialdataToGiotto.Rd @@ -23,7 +23,7 @@ If multiple spatial networks are in the anndata object, a list of key_added terms may be provided. If converting an anndata object from giottoToAnnData, a .txt file may be provided, which was generated in that function, -i.e. {spat_unit}_{feat_type}_nn_network_keys_added.txt +i.e. \{spat_unit\}_\{feat_type\}_nn_network_keys_added.txt Cannot be "spatial". This becomes the name of the nearest network in the gobject.} \item{spatial_n_key_added}{equivalent of "key_added" argument from squidpy.gr.spatial_neighbors. @@ -31,10 +31,11 @@ If multiple spatial networks are in the anndata object, a list of key_added terms may be provided. If converting an anndata object from giottoToAnnData, a .txt file may be provided, which was generated in that function, -i.e. {spat_unit}_{feat_type}_spatial_network_keys_added.txt +i.e. \{spat_unit\}_\{feat_type\}_spatial_network_keys_added.txt Cannot be the same as n_key_added.} -\item{delaunay_spat_net}{binary parameter for spatial network. If TRUE, the spatial network is a delaunay network.} +\item{delaunay_spat_net}{binary parameter for spatial network. If TRUE, +the spatial network is a delaunay network.} \item{spat_unit}{desired spatial unit for conversion, default NULL} From 509bd3b7c1bf44a3dc5057d5717605e2df29e90b Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 26 Aug 2024 09:07:01 -0400 Subject: [PATCH 136/160] chore: docs fixes --- R/methods-rbind.R | 2 -- R/methods-shear.R | 2 ++ R/methods-spin.R | 4 +++- man/rbind2_giotto_polygon_hetero.Rd | 3 --- man/shear.Rd | 3 +++ man/spin.Rd | 5 ++++- 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/R/methods-rbind.R b/R/methods-rbind.R index 9a904fbd..0896c3f0 100644 --- a/R/methods-rbind.R +++ b/R/methods-rbind.R @@ -107,8 +107,6 @@ rbind2_giotto_polygon_homo <- function(x, y) { #' also becomes a combination of both previous names #' @param x \code{giottoPolygon} 1 #' @param y \code{giottoPolygon} 2 -#' @param poly_names sorted polygon names to be used in the -#' combined \code{giottoPolygon} object #' @param add_list_ID whether to include the name of the #' origin \code{giottoPolygons} as a new 'list_ID' attribute #' @returns giottoPolygon diff --git a/R/methods-shear.R b/R/methods-shear.R index 9bbb5373..25dbe1d2 100644 --- a/R/methods-shear.R +++ b/R/methods-shear.R @@ -101,6 +101,8 @@ setMethod("shear", signature("giottoAffineImage"), function( }) # * affine2d #### +#' @rdname shear +#' @export setMethod("shear", signature("affine2d"), function( x, fx = 0, fy = 0, x0, y0, ... ) { diff --git a/R/methods-spin.R b/R/methods-spin.R index 8c227a15..d5eb979f 100644 --- a/R/methods-spin.R +++ b/R/methods-spin.R @@ -2,13 +2,15 @@ #' @title Spin an object #' @name spin -#' @description Spin (rotate) an object spatially (limited to xy rotations) +#' @description Spin (rotate) an object spatially (usually limited to xy +#' rotations) #' @param x object #' @param angle numeric. Angle of rotation in degrees #' @param x0 numeric. x-coordinate of the center of rotation. Defaults to #' center x val if not given. #' @param y0 numeric. y-coordinate of the center of rotation. Defaults to #' center y val if not given. +#' @param ... additional params to pass #' @returns spun object #' @examples #' g <- GiottoData::loadSubObjectMini("spatLocsObj") diff --git a/man/rbind2_giotto_polygon_hetero.Rd b/man/rbind2_giotto_polygon_hetero.Rd index d2a75590..264d57ca 100644 --- a/man/rbind2_giotto_polygon_hetero.Rd +++ b/man/rbind2_giotto_polygon_hetero.Rd @@ -13,9 +13,6 @@ rbind2_giotto_polygon_hetero(x, y, new_name, add_list_ID = TRUE) \item{add_list_ID}{whether to include the name of the origin \code{giottoPolygons} as a new 'list_ID' attribute} - -\item{poly_names}{sorted polygon names to be used in the -combined \code{giottoPolygon} object} } \value{ giottoPolygon diff --git a/man/shear.Rd b/man/shear.Rd index 570a39d5..b72f7df2 100644 --- a/man/shear.Rd +++ b/man/shear.Rd @@ -8,6 +8,7 @@ \alias{shear,giottoPolygon-method} \alias{shear,giottoLargeImage-method} \alias{shear,giottoAffineImage-method} +\alias{shear,affine2d-method} \title{Apply a shear tranform} \usage{ \S4method{shear}{spatLocsObj}(x, fx = 0, fy = 0, x0, y0, ...) @@ -21,6 +22,8 @@ \S4method{shear}{giottoLargeImage}(x, fx = 0, fy = 0, x0, y0, ...) \S4method{shear}{giottoAffineImage}(x, fx = 0, fy = 0, x0, y0, ...) + +\S4method{shear}{affine2d}(x, fx = 0, fy = 0, x0, y0, ...) } \arguments{ \item{x}{object} diff --git a/man/spin.Rd b/man/spin.Rd index 42df7eb6..2efc2f03 100644 --- a/man/spin.Rd +++ b/man/spin.Rd @@ -76,12 +76,15 @@ Overrides angle param} \item{geom}{character. Named vector of colnames of x, y, (z) coordinate columns. Default is \code{c("sdimx", "sdimy", "sdimz")}} + +\item{...}{additional params to pass} } \value{ spun object } \description{ -Spin (rotate) an object spatially (limited to xy rotations) +Spin (rotate) an object spatially (usually limited to xy +rotations) } \examples{ g <- GiottoData::loadSubObjectMini("spatLocsObj") From be572f3713ef021e82cbb6a99e285511629cccc4 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 26 Aug 2024 08:55:24 -0400 Subject: [PATCH 137/160] fix: docs --- R/images.R | 3 +++ R/methods-affine.R | 3 +++ R/methods-show.R | 1 + man/as.character.Rd | 2 ++ man/decomp_affine.Rd | 3 +++ man/hist.Rd | 1 + 6 files changed, 13 insertions(+) diff --git a/R/images.R b/R/images.R index f9927e03..40a18b52 100644 --- a/R/images.R +++ b/R/images.R @@ -2685,6 +2685,9 @@ setMethod( #' gimg <- createGiottoLargeImage(f, use_rast_ext = TRUE, verbose = FALSE) #' #' hist(gimg) +NULL + +#' @rdname hist #' @export setMethod( "hist", signature("giottoLargeImage"), diff --git a/R/methods-affine.R b/R/methods-affine.R index 50599db7..f4bfaebe 100644 --- a/R/methods-affine.R +++ b/R/methods-affine.R @@ -412,6 +412,9 @@ setMethod("affine", signature(x = "affine2d", y = "matrix"), function( #' @returns a list of transforms information. #' @keywords internal #' @examples +#' # load example data +#' sl <- GiottoData::loadSubObjectMini("spatLocsObj") +#' #' # affine transform matrices #' m <- diag(rep(1, 3)) #' shear_m <- trans_m <- m diff --git a/R/methods-show.R b/R/methods-show.R index 05ff7333..565a9901 100644 --- a/R/methods-show.R +++ b/R/methods-show.R @@ -6,6 +6,7 @@ NULL #' @description #' Create a text representation of an object #' @param x object +#' @param ... additional params to pass (none implemented) #' @examples #' img <- GiottoData::loadSubObjectMini("giottoLargeImage") #' as.character(img) diff --git a/man/as.character.Rd b/man/as.character.Rd index 1225d0c1..a7a56969 100644 --- a/man/as.character.Rd +++ b/man/as.character.Rd @@ -12,6 +12,8 @@ } \arguments{ \item{x}{object} + +\item{...}{additional params to pass (none implemented)} } \description{ Create a text representation of an object diff --git a/man/decomp_affine.Rd b/man/decomp_affine.Rd index f4a74675..23a7a134 100644 --- a/man/decomp_affine.Rd +++ b/man/decomp_affine.Rd @@ -21,6 +21,9 @@ needed to perform them as a list of class \code{affine}. Works only for 2D transforms. Logic from \url{https://math.stackexchange.com/a/3521141} } \examples{ +# load example data +sl <- GiottoData::loadSubObjectMini("spatLocsObj") + # affine transform matrices m <- diag(rep(1, 3)) shear_m <- trans_m <- m diff --git a/man/hist.Rd b/man/hist.Rd index 266acd56..24bef91a 100644 --- a/man/hist.Rd +++ b/man/hist.Rd @@ -2,6 +2,7 @@ % Please edit documentation in R/images.R \name{hist} \alias{hist} +\alias{hist,giottoLargeImage-method} \title{Histogram} \usage{ \S4method{hist}{giottoLargeImage}(x, show_max = TRUE, ...) From 31e1cff10deb0adcc25610c43566caea402bcc7a Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 26 Aug 2024 11:41:22 -0400 Subject: [PATCH 138/160] chore: docs reorganization --- R/methods-extract.R | 148 ++++++++++++++++--------- man/extract-methods.Rd | 246 +---------------------------------------- man/replace_bracket.Rd | 115 +++++++++++++++++++ man/subset_bracket.Rd | 203 ++++++++++++++++++++++++++++++++++ 4 files changed, 418 insertions(+), 294 deletions(-) create mode 100644 man/replace_bracket.Rd create mode 100644 man/subset_bracket.Rd diff --git a/R/methods-extract.R b/R/methods-extract.R index e68f4f89..9b94ce89 100644 --- a/R/methods-extract.R +++ b/R/methods-extract.R @@ -4,20 +4,66 @@ NULL # Documentations ------------------------------------------------------------ # +#' @title Subset part of an object +#' @name subset_bracket +#' @aliases `[` +#' @description Extract values from Giotto classes. Providing empty brackets +#' will usually extract the contained data representation. +#' @param x Giotto S4 object to extract columns from +#' @param i,j indices specifying elements to extract. Indices are numeric or +#' character vectors, or empty +#' @returns Same as `x` unless brackets are empty in which case, the main +#' internal representation is returned. +#' @examples +#' gpoints <- GiottoData::loadSubObjectMini("giottoPoints") +#' +#' # extract contained `SpatVector` +#' gpoints[] +#' +#' # subset by feature +#' gpoints[c("Mlc1", "Gfap")] +#' +#' # subset by feature and colname +#' gpoints["Mlc1", c("feat_ID", "feat_ID_uniq")] +#' +#' # subset by index +#' gpoints[seq(20)] +#' +#' @seealso [`[<-`()] [`$`()] [`$<-`()] +NULL + +#' @title Replace part of an object +#' @name replace_bracket +#' @aliases `[<-` +#' @description Replace values from Giotto Classes. Providing empty brackets +#' will usually replace the entire contained data representation. +#' @param x Giotto S4 object to replace information in +#' @param i,j indices specifying elements to replace. Indices are numeric or +#' character vectors or empty +#' @param value values(s) to set +#' @returns same as `x` +#' @examples +#' gpoints <- GiottoData::loadSubObjectMini("giottoPoints") +#' +#' gpoints[] <- gpoints[] +#' +#' @seealso [`[`()] [`$`()] [`$<-`()] +NULL + #' @title Extract or replace parts of an object #' @name extract-methods #' @docType methods -#' @aliases `[` `[<-` `$` `$<-` +#' @aliases `$` `$<-` #' @description Operators Giotto S4 internal data.tables to extract #' or replace parts. #' @param x Giotto S4 object to extract columns from #' @param i,j indices specifying elements to extract or replace. Indices are #' numeric or character vectors or empty #' @param name A literal character string (possibly backtick quoted). -#' @param value value(s) to set #' This is normally matched to the colnames of the data.table object within #' the S4. +#' @param value value(s) to set #' @returns columns or values from a data.table #' @section \code{`$`} methods: #' @section \code{`$<-`} methods: @@ -210,7 +256,7 @@ setMethod("$", signature("affine2d"), function(x, name) { ## * gdtData #### # Make it so that i and j subsets can be written independently -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", signature(x = "gdtData", i = "gIndex", j = "gIndex", drop = "missing"), @@ -221,7 +267,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", signature( @@ -246,7 +292,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", signature( @@ -277,7 +323,7 @@ setMethod( # enforce subsetting by character for gdtData so that cols to keep can be # checked for id col -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", signature( @@ -291,7 +337,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", signature( @@ -309,7 +355,7 @@ setMethod( ## * coordDataDT #### -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", signature(x = "coordDataDT", i = "ANY", j = "ANY", drop = "missing"), @@ -319,7 +365,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", signature( @@ -332,7 +378,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", signature( @@ -393,7 +439,7 @@ setMethod( # # }) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", @@ -404,7 +450,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @aliases [,coordDataDT,missing,missing,missing-method #' @section \code{`[`} methods: #' Return \code{coordinates} slot data.table from giotto S4 @@ -420,7 +466,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @aliases [<-,coordDataDT,missing,missing, #' ANY-method [<-,coordDataDT,missing,missing-method #' @docType methods @@ -435,7 +481,7 @@ setReplaceMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", @@ -455,7 +501,7 @@ setMethod( ## * metaData #### -#' @rdname extract-methods +#' @rdname subset_bracket #' @section \code{`[`} methods: #' Select rows (i) and cols (j) from giotto S4 metaDT slot #' @export @@ -467,7 +513,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", @@ -479,7 +525,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", signature(x = "metaData", i = "ANY", j = "missing", drop = "missing"), @@ -489,7 +535,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @section \code{`[`} methods: #' Return \code{metaDT} slot data.table from giotto S4 #' @export @@ -501,7 +547,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname replace_bracket #' @aliases [<-,metaData,missing,missing, #' ANY-method [<-,metaData,missing,missing-method #' @docType methods @@ -520,7 +566,7 @@ setMethod( ## * dimObj #### -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", signature(x = "dimObj", i = "ANY", j = "ANY", drop = "missing"), @@ -530,7 +576,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @section \code{`[`} methods: #' Return \code{coordinates} slot matrix from giotto S4 dimObj #' @export @@ -542,7 +588,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname replace_bracket #' @aliases [<-,dimObj,missing,missing, #' ANY-method [<-,dimObj,missing,missing-method #' @docType methods @@ -559,7 +605,7 @@ setMethod( ## * exprData #### -#' @rdname extract-methods +#' @rdname subset_bracket #' @section \code{`[`} methods: #' Select rows (i) and cols (j) from giotto S4 exprMat slot #' @export @@ -571,7 +617,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", signature(x = "exprData", i = "ANY", j = "missing", drop = "missing"), @@ -581,7 +627,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", signature(x = "exprData", i = "ANY", j = "ANY", drop = "missing"), @@ -591,7 +637,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @section \code{`[`} methods: #' Return \code{exprMat} slot Matrix object from giotto S4 #' @export @@ -603,7 +649,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname replace_bracket #' @aliases [<-,exprData,missing,missing, #' ANY-method [<-,exprData,missing,missing-method #' @docType methods @@ -620,7 +666,7 @@ setMethod( ) # * spatNetData #### -#' @rdname extract-methods +#' @rdname subset_bracket #' @section \code{`[`} methods: #' Return \code{spatNetData} slot network data.table object from giotto S4 #' @export @@ -635,7 +681,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname replace_bracket #' @aliases [<-,spatNetData,missing,missing, #' ANY-method [<-,spatNetData,missing,missing-method #' @docType methods @@ -653,7 +699,7 @@ setMethod( # * nnData #### -#' @rdname extract-methods +#' @rdname subset_bracket #' @section \code{`[`} methods: #' Return \code{nnData} slot igraph object from giotto S4 #' @export @@ -665,7 +711,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname replace_bracket #' @aliases [<-,nnData,missing,missing, #' ANY-method [<-,nnData,missing,missing-method #' @docType methods @@ -682,7 +728,7 @@ setMethod( # * enrData #### -#' @rdname extract-methods +#' @rdname subset_bracket #' @section \code{`[`} methods: #' Return \code{enrData} slot enrichment data.table object from giotto S4 #' @export @@ -694,7 +740,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", signature(x = "enrData", i = "ANY", j = "missing", drop = "missing"), @@ -704,7 +750,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", signature(x = "enrData", i = "missing", j = "ANY", drop = "missing"), @@ -714,7 +760,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", @@ -727,7 +773,7 @@ setMethod( -#' @rdname extract-methods +#' @rdname replace_bracket #' @aliases [<-,enrData,missing,missing, #' ANY-method [<-,enrData,missing,missing-method #' @docType methods @@ -744,7 +790,7 @@ setMethod( ) # * spatGridData #### -#' @rdname extract-methods +#' @rdname subset_bracket #' @section \code{`[`} methods: #' Return \code{spatGridData} slot data.table object from giotto S4 #' @export @@ -759,7 +805,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname replace_bracket #' @aliases [<-,spatGridData,missing,missing, #' ANY-method [<-,spatGridData,missing,missing-method #' @docType methods @@ -776,7 +822,7 @@ setMethod( ) # * giottoPoints #### -#' @rdname extract-methods +#' @rdname subset_bracket #' @section \code{`[`} methods: #' Return \code{giottoPoints} spatVector slot #' @export @@ -791,7 +837,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", @@ -809,7 +855,7 @@ setMethod( # this behavior is different from normal spatvectors # SpatVector defaults to col subsetting when character is provided to i # subsetting on feat_ID col makes more sense for giottoPoints -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", @@ -823,7 +869,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", @@ -843,7 +889,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname replace_bracket #' @aliases [<-,giottoPoints,missing,missing, #' ANY-method [<-,giottoPoints,missing,missing-method #' @docType methods @@ -860,7 +906,7 @@ setMethod( ) # * giottoPolygon #### -#' @rdname extract-methods +#' @rdname subset_bracket #' @section \code{`[`} methods: #' Return \code{giottoPolygon} spatVector slot #' @export @@ -875,7 +921,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", @@ -906,7 +952,7 @@ setMethod( # this behavior is different from normal spatvectors # SpatVector defaults to col subsetting when character is provided to i # subsetting on poly_ID col makes more sense for giottoPolygon -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", @@ -920,7 +966,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", @@ -941,7 +987,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", @@ -958,7 +1004,7 @@ setMethod( -#' @rdname extract-methods +#' @rdname replace_bracket #' @aliases [<-,giottoPolygon,missing,missing, #' ANY-method [<-,giottoPolygon,missing,missing-method #' @docType methods @@ -974,7 +1020,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname subset_bracket #' @export setMethod( "[", @@ -986,7 +1032,7 @@ setMethod( } ) -#' @rdname extract-methods +#' @rdname replace_bracket #' @aliases [<-,affine2d,missing,missing, #' ANY-method [<-,affine2d,missing,missing-method #' @docType methods diff --git a/man/extract-methods.Rd b/man/extract-methods.Rd index 50c938c3..e3b766ee 100644 --- a/man/extract-methods.Rd +++ b/man/extract-methods.Rd @@ -3,8 +3,6 @@ \docType{methods} \name{extract-methods} \alias{extract-methods} -\alias{`[`} -\alias{`[<-`} \alias{`$`} \alias{`$<-`} \alias{$,coordDataDT-method} @@ -18,77 +16,6 @@ \alias{$,terraVectData-method} \alias{$<-,terraVectData-method} \alias{$,affine2d-method} -\alias{[,gdtData,gIndex,gIndex,missing-method} -\alias{[,gdtData,logical,missing,missing-method} -\alias{[,gdtData,character,missing,missing-method} -\alias{[,gdtData,missing,numeric,missing-method} -\alias{[,gdtData,missing,logical,missing-method} -\alias{[,coordDataDT,ANY,ANY,missing-method} -\alias{[,coordDataDT,missing,ANY,missing-method} -\alias{[,coordDataDT,missing,character,missing-method} -\alias{[,coordDataDT,ANY,missing,missing-method} -\alias{[,coordDataDT,missing,missing,missing-method} -\alias{[<-,coordDataDT,missing,missing,ANY-method} -\alias{[<-,coordDataDT,missing,missing,} -\alias{ANY-method} -\alias{[<-,coordDataDT,missing,missing-method} -\alias{[,giottoPoints,gIndex,missing,missing-method} -\alias{[,metaData,missing,ANY,missing-method} -\alias{[,metaData,missing,character,missing-method} -\alias{[,metaData,ANY,missing,missing-method} -\alias{[,metaData,missing,missing,missing-method} -\alias{[<-,metaData,missing,missing,ANY-method} -\alias{[<-,metaData,missing,missing,} -\alias{[<-,metaData,missing,missing-method} -\alias{[,dimObj,ANY,ANY,missing-method} -\alias{[,dimObj,missing,missing,missing-method} -\alias{[<-,dimObj,missing,missing,ANY-method} -\alias{[<-,dimObj,missing,missing,} -\alias{[<-,dimObj,missing,missing-method} -\alias{[,exprData,missing,ANY,missing-method} -\alias{[,exprData,ANY,missing,missing-method} -\alias{[,exprData,ANY,ANY,missing-method} -\alias{[,exprData,missing,missing,missing-method} -\alias{[<-,exprData,missing,missing,ANY-method} -\alias{[<-,exprData,missing,missing,} -\alias{[<-,exprData,missing,missing-method} -\alias{[,spatNetData,missing,missing,missing-method} -\alias{[<-,spatNetData,missing,missing,ANY-method} -\alias{[<-,spatNetData,missing,missing,} -\alias{[<-,spatNetData,missing,missing-method} -\alias{[,nnData,missing,missing,missing-method} -\alias{[<-,nnData,missing,missing,ANY-method} -\alias{[<-,nnData,missing,missing,} -\alias{[<-,nnData,missing,missing-method} -\alias{[,enrData,missing,missing,missing-method} -\alias{[,enrData,ANY,missing,missing-method} -\alias{[,enrData,missing,ANY,missing-method} -\alias{[,enrData,missing,character,missing-method} -\alias{[<-,enrData,missing,missing,ANY-method} -\alias{[<-,enrData,missing,missing,} -\alias{[<-,enrData,missing,missing-method} -\alias{[,spatGridData,missing,missing,missing-method} -\alias{[<-,spatGridData,missing,missing,ANY-method} -\alias{[<-,spatGridData,missing,missing,} -\alias{[<-,spatGridData,missing,missing-method} -\alias{[,giottoPoints,missing,missing,missing-method} -\alias{[,giottoPoints,character,missing,missing-method} -\alias{[,giottoPoints,missing,gIndex,missing-method} -\alias{[<-,giottoPoints,missing,missing,ANY-method} -\alias{[<-,giottoPoints,missing,missing,} -\alias{[<-,giottoPoints,missing,missing-method} -\alias{[,giottoPolygon,missing,missing,missing-method} -\alias{[,giottoPolygon,gIndex,missing,missing-method} -\alias{[,giottoPolygon,character,missing,missing-method} -\alias{[,giottoPolygon,missing,gIndex,missing-method} -\alias{[,terraVectData,gIndex,gIndex,missing-method} -\alias{[<-,giottoPolygon,missing,missing,ANY-method} -\alias{[<-,giottoPolygon,missing,missing,} -\alias{[<-,giottoPolygon,missing,missing-method} -\alias{[,affine2d,missing,missing,missing-method} -\alias{[<-,affine2d,missing,missing,ANY-method} -\alias{[<-,affine2d,missing,missing,} -\alias{[<-,affine2d,missing,missing-method} \title{Extract or replace parts of an object} \usage{ \S4method{$}{coordDataDT}(x, name) @@ -112,114 +39,16 @@ \S4method{$}{terraVectData}(x, name) <- value \S4method{$}{affine2d}(x, name) - -\S4method{[}{gdtData,gIndex,gIndex,missing}(x, i, j) - -\S4method{[}{gdtData,logical,missing,missing}(x, i, j) - -\S4method{[}{gdtData,character,missing,missing}(x, i, j) - -\S4method{[}{gdtData,missing,numeric,missing}(x, i, j) - -\S4method{[}{gdtData,missing,logical,missing}(x, i, j) - -\S4method{[}{coordDataDT,ANY,ANY,missing}(x, i, j) - -\S4method{[}{coordDataDT,missing,ANY,missing}(x, i, j) - -\S4method{[}{coordDataDT,missing,character,missing}(x, i, j) - -\S4method{[}{coordDataDT,ANY,missing,missing}(x, i, j) - -\S4method{[}{coordDataDT,missing,missing,missing}(x, i, j) - -\S4method{[}{coordDataDT,missing,missing,ANY}(x, i, j) <- value - -\S4method{[}{giottoPoints,gIndex,missing,missing}(x, i, j) - -\S4method{[}{metaData,missing,ANY,missing}(x, i, j) - -\S4method{[}{metaData,missing,character,missing}(x, i, j) - -\S4method{[}{metaData,ANY,missing,missing}(x, i, j) - -\S4method{[}{metaData,missing,missing,missing}(x, i, j) - -\S4method{[}{metaData,missing,missing,ANY}(x, i, j) <- value - -\S4method{[}{dimObj,ANY,ANY,missing}(x, i, j) - -\S4method{[}{dimObj,missing,missing,missing}(x, i, j) - -\S4method{[}{dimObj,missing,missing,ANY}(x, i, j) <- value - -\S4method{[}{exprData,missing,ANY,missing}(x, i, j) - -\S4method{[}{exprData,ANY,missing,missing}(x, i, j) - -\S4method{[}{exprData,ANY,ANY,missing}(x, i, j) - -\S4method{[}{exprData,missing,missing,missing}(x, i, j) - -\S4method{[}{exprData,missing,missing,ANY}(x, i, j) <- value - -\S4method{[}{spatNetData,missing,missing,missing}(x, i, j) - -\S4method{[}{spatNetData,missing,missing,ANY}(x, i, j) <- value - -\S4method{[}{nnData,missing,missing,missing}(x, i, j) - -\S4method{[}{nnData,missing,missing,ANY}(x, i, j) <- value - -\S4method{[}{enrData,missing,missing,missing}(x, i, j) - -\S4method{[}{enrData,ANY,missing,missing}(x, i, j) - -\S4method{[}{enrData,missing,ANY,missing}(x, i, j) - -\S4method{[}{enrData,missing,character,missing}(x, i, j) - -\S4method{[}{enrData,missing,missing,ANY}(x, i, j) <- value - -\S4method{[}{spatGridData,missing,missing,missing}(x, i, j) - -\S4method{[}{spatGridData,missing,missing,ANY}(x, i, j) <- value - -\S4method{[}{giottoPoints,missing,missing,missing}(x, i, j) - -\S4method{[}{giottoPoints,gIndex,missing,missing}(x, i, j) - -\S4method{[}{giottoPoints,character,missing,missing}(x, i, j) - -\S4method{[}{giottoPoints,missing,gIndex,missing}(x, i, j) - -\S4method{[}{giottoPoints,missing,missing,ANY}(x, i, j) <- value - -\S4method{[}{giottoPolygon,missing,missing,missing}(x, i, j) - -\S4method{[}{giottoPolygon,gIndex,missing,missing}(x, i, j) - -\S4method{[}{giottoPolygon,character,missing,missing}(x, i, j) - -\S4method{[}{giottoPolygon,missing,gIndex,missing}(x, i, j) - -\S4method{[}{terraVectData,gIndex,gIndex,missing}(x, i, j) - -\S4method{[}{giottoPolygon,missing,missing,ANY}(x, i, j) <- value - -\S4method{[}{affine2d,missing,missing,missing}(x) - -\S4method{[}{affine2d,missing,missing,ANY}(x) <- value } \arguments{ \item{x}{Giotto S4 object to extract columns from} -\item{name}{A literal character string (possibly backtick quoted).} - -\item{value}{value(s) to set +\item{name}{A literal character string (possibly backtick quoted). This is normally matched to the colnames of the data.table object within the S4.} +\item{value}{value(s) to set} + \item{i, j}{indices specifying elements to extract or replace. Indices are numeric or character vectors or empty} } @@ -275,79 +104,10 @@ Set values by colname into giotto S4 spatVector slot. \section{\code{`[`} methods}{ - - -Return \code{coordinates} slot data.table from giotto S4 - - -Select rows (i) and cols (j) from giotto S4 metaDT slot - - -Return \code{metaDT} slot data.table from giotto S4 - - -Return \code{coordinates} slot matrix from giotto S4 dimObj - - -Select rows (i) and cols (j) from giotto S4 exprMat slot - - -Return \code{exprMat} slot Matrix object from giotto S4 - - -Return \code{spatNetData} slot network data.table object from giotto S4 - - -Return \code{nnData} slot igraph object from giotto S4 - - -Return \code{enrData} slot enrichment data.table object from giotto S4 - - -Return \code{spatGridData} slot data.table object from giotto S4 - - -Return \code{giottoPoints} spatVector slot - - -Return \code{giottoPolygon} spatVector slot } \section{\code{`[<-`} methods}{ - - -Assign to \code{coordinates} slot in giotto S4 - - -Assign to \code{metaDT} slot in giotto S4 - - -Assign to \code{coordinates} slot in giotto S4 dimObj - - -Assign to \code{exprMat} slot in giotto S4 - - -Assign to \code{networkDT} slot in giotto S4 - - -Assign to \code{igraph} slot in giotto S4 - - -Assign to \code{enrichDT} slot in giotto S4 - - -Assign to \code{gridDT} slot in giotto S4 - - -Assign to \code{spatVector} slot in giotto S4 - - -Assign to \code{spatVector} slot in giottoPolygon - - -Assign to \code{affine} slot in affine2d } \examples{ diff --git a/man/replace_bracket.Rd b/man/replace_bracket.Rd new file mode 100644 index 00000000..953ff47c --- /dev/null +++ b/man/replace_bracket.Rd @@ -0,0 +1,115 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/methods-extract.R +\docType{methods} +\name{replace_bracket} +\alias{replace_bracket} +\alias{`[<-`} +\alias{[<-,metaData,missing,missing,ANY-method} +\alias{[<-,metaData,missing,missing,} +\alias{ANY-method} +\alias{[<-,metaData,missing,missing-method} +\alias{[<-,dimObj,missing,missing,ANY-method} +\alias{[<-,dimObj,missing,missing,} +\alias{[<-,dimObj,missing,missing-method} +\alias{[<-,exprData,missing,missing,ANY-method} +\alias{[<-,exprData,missing,missing,} +\alias{[<-,exprData,missing,missing-method} +\alias{[<-,spatNetData,missing,missing,ANY-method} +\alias{[<-,spatNetData,missing,missing,} +\alias{[<-,spatNetData,missing,missing-method} +\alias{[<-,nnData,missing,missing,ANY-method} +\alias{[<-,nnData,missing,missing,} +\alias{[<-,nnData,missing,missing-method} +\alias{[<-,enrData,missing,missing,ANY-method} +\alias{[<-,enrData,missing,missing,} +\alias{[<-,enrData,missing,missing-method} +\alias{[<-,spatGridData,missing,missing,ANY-method} +\alias{[<-,spatGridData,missing,missing,} +\alias{[<-,spatGridData,missing,missing-method} +\alias{[<-,giottoPoints,missing,missing,ANY-method} +\alias{[<-,giottoPoints,missing,missing,} +\alias{[<-,giottoPoints,missing,missing-method} +\alias{[<-,giottoPolygon,missing,missing,ANY-method} +\alias{[<-,giottoPolygon,missing,missing,} +\alias{[<-,giottoPolygon,missing,missing-method} +\alias{[<-,affine2d,missing,missing,ANY-method} +\alias{[<-,affine2d,missing,missing,} +\alias{[<-,affine2d,missing,missing-method} +\title{Replace part of an object} +\usage{ +\S4method{[}{metaData,missing,missing,ANY}(x, i, j) <- value + +\S4method{[}{dimObj,missing,missing,ANY}(x, i, j) <- value + +\S4method{[}{exprData,missing,missing,ANY}(x, i, j) <- value + +\S4method{[}{spatNetData,missing,missing,ANY}(x, i, j) <- value + +\S4method{[}{nnData,missing,missing,ANY}(x, i, j) <- value + +\S4method{[}{enrData,missing,missing,ANY}(x, i, j) <- value + +\S4method{[}{spatGridData,missing,missing,ANY}(x, i, j) <- value + +\S4method{[}{giottoPoints,missing,missing,ANY}(x, i, j) <- value + +\S4method{[}{giottoPolygon,missing,missing,ANY}(x, i, j) <- value + +\S4method{[}{affine2d,missing,missing,ANY}(x) <- value +} +\arguments{ +\item{x}{Giotto S4 object to replace information in} + +\item{i, j}{indices specifying elements to replace. Indices are numeric or +character vectors or empty} + +\item{value}{values(s) to set} +} +\value{ +same as \code{x} +} +\description{ +Replace values from Giotto Classes. Providing empty brackets +will usually replace the entire contained data representation. +} +\section{\code{`[<-`} methods}{ + +Assign to \code{metaDT} slot in giotto S4 + + +Assign to \code{coordinates} slot in giotto S4 dimObj + + +Assign to \code{exprMat} slot in giotto S4 + + +Assign to \code{networkDT} slot in giotto S4 + + +Assign to \code{igraph} slot in giotto S4 + + +Assign to \code{enrichDT} slot in giotto S4 + + +Assign to \code{gridDT} slot in giotto S4 + + +Assign to \code{spatVector} slot in giotto S4 + + +Assign to \code{spatVector} slot in giottoPolygon + + +Assign to \code{affine} slot in affine2d +} + +\examples{ +gpoints <- GiottoData::loadSubObjectMini("giottoPoints") + +gpoints[] <- gpoints[] + +} +\seealso{ +[\code{[}()] +} diff --git a/man/subset_bracket.Rd b/man/subset_bracket.Rd new file mode 100644 index 00000000..7c8f1a7c --- /dev/null +++ b/man/subset_bracket.Rd @@ -0,0 +1,203 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/methods-extract.R +\docType{methods} +\name{subset_bracket} +\alias{subset_bracket} +\alias{`[`} +\alias{[,gdtData,gIndex,gIndex,missing-method} +\alias{[,gdtData,logical,missing,missing-method} +\alias{[,gdtData,character,missing,missing-method} +\alias{[,gdtData,missing,numeric,missing-method} +\alias{[,gdtData,missing,logical,missing-method} +\alias{[,coordDataDT,ANY,ANY,missing-method} +\alias{[,coordDataDT,missing,ANY,missing-method} +\alias{[,coordDataDT,missing,character,missing-method} +\alias{[,coordDataDT,ANY,missing,missing-method} +\alias{[,coordDataDT,missing,missing,missing-method} +\alias{[<-,coordDataDT,missing,missing,ANY-method} +\alias{[<-,coordDataDT,missing,missing,} +\alias{ANY-method} +\alias{[<-,coordDataDT,missing,missing-method} +\alias{[,giottoPoints,gIndex,missing,missing-method} +\alias{[,metaData,missing,ANY,missing-method} +\alias{[,metaData,missing,character,missing-method} +\alias{[,metaData,ANY,missing,missing-method} +\alias{[,metaData,missing,missing,missing-method} +\alias{[,dimObj,ANY,ANY,missing-method} +\alias{[,dimObj,missing,missing,missing-method} +\alias{[,exprData,missing,ANY,missing-method} +\alias{[,exprData,ANY,missing,missing-method} +\alias{[,exprData,ANY,ANY,missing-method} +\alias{[,exprData,missing,missing,missing-method} +\alias{[,spatNetData,missing,missing,missing-method} +\alias{[,nnData,missing,missing,missing-method} +\alias{[,enrData,missing,missing,missing-method} +\alias{[,enrData,ANY,missing,missing-method} +\alias{[,enrData,missing,ANY,missing-method} +\alias{[,enrData,missing,character,missing-method} +\alias{[,spatGridData,missing,missing,missing-method} +\alias{[,giottoPoints,missing,missing,missing-method} +\alias{[,giottoPoints,character,missing,missing-method} +\alias{[,giottoPoints,missing,gIndex,missing-method} +\alias{[,giottoPolygon,missing,missing,missing-method} +\alias{[,giottoPolygon,gIndex,missing,missing-method} +\alias{[,giottoPolygon,character,missing,missing-method} +\alias{[,giottoPolygon,missing,gIndex,missing-method} +\alias{[,terraVectData,gIndex,gIndex,missing-method} +\alias{[,affine2d,missing,missing,missing-method} +\title{Subset part of an object} +\usage{ +\S4method{[}{gdtData,gIndex,gIndex,missing}(x, i, j) + +\S4method{[}{gdtData,logical,missing,missing}(x, i, j) + +\S4method{[}{gdtData,character,missing,missing}(x, i, j) + +\S4method{[}{gdtData,missing,numeric,missing}(x, i, j) + +\S4method{[}{gdtData,missing,logical,missing}(x, i, j) + +\S4method{[}{coordDataDT,ANY,ANY,missing}(x, i, j) + +\S4method{[}{coordDataDT,missing,ANY,missing}(x, i, j) + +\S4method{[}{coordDataDT,missing,character,missing}(x, i, j) + +\S4method{[}{coordDataDT,ANY,missing,missing}(x, i, j) + +\S4method{[}{coordDataDT,missing,missing,missing}(x, i, j) + +\S4method{[}{coordDataDT,missing,missing,ANY}(x, i, j) <- value + +\S4method{[}{giottoPoints,gIndex,missing,missing}(x, i, j) + +\S4method{[}{metaData,missing,ANY,missing}(x, i, j) + +\S4method{[}{metaData,missing,character,missing}(x, i, j) + +\S4method{[}{metaData,ANY,missing,missing}(x, i, j) + +\S4method{[}{metaData,missing,missing,missing}(x, i, j) + +\S4method{[}{dimObj,ANY,ANY,missing}(x, i, j) + +\S4method{[}{dimObj,missing,missing,missing}(x, i, j) + +\S4method{[}{exprData,missing,ANY,missing}(x, i, j) + +\S4method{[}{exprData,ANY,missing,missing}(x, i, j) + +\S4method{[}{exprData,ANY,ANY,missing}(x, i, j) + +\S4method{[}{exprData,missing,missing,missing}(x, i, j) + +\S4method{[}{spatNetData,missing,missing,missing}(x, i, j) + +\S4method{[}{nnData,missing,missing,missing}(x, i, j) + +\S4method{[}{enrData,missing,missing,missing}(x, i, j) + +\S4method{[}{enrData,ANY,missing,missing}(x, i, j) + +\S4method{[}{enrData,missing,ANY,missing}(x, i, j) + +\S4method{[}{enrData,missing,character,missing}(x, i, j) + +\S4method{[}{spatGridData,missing,missing,missing}(x, i, j) + +\S4method{[}{giottoPoints,missing,missing,missing}(x, i, j) + +\S4method{[}{giottoPoints,gIndex,missing,missing}(x, i, j) + +\S4method{[}{giottoPoints,character,missing,missing}(x, i, j) + +\S4method{[}{giottoPoints,missing,gIndex,missing}(x, i, j) + +\S4method{[}{giottoPolygon,missing,missing,missing}(x, i, j) + +\S4method{[}{giottoPolygon,gIndex,missing,missing}(x, i, j) + +\S4method{[}{giottoPolygon,character,missing,missing}(x, i, j) + +\S4method{[}{giottoPolygon,missing,gIndex,missing}(x, i, j) + +\S4method{[}{terraVectData,gIndex,gIndex,missing}(x, i, j) + +\S4method{[}{affine2d,missing,missing,missing}(x) +} +\arguments{ +\item{x}{Giotto S4 object to extract columns from} + +\item{i, j}{indices specifying elements to extract. Indices are numeric or +character vectors, or empty} +} +\value{ +Same as \code{x} unless brackets are empty in which case, the main +internal representation is returned. +} +\description{ +Extract values from Giotto classes. Providing empty brackets +will usually extract the contained data representation. +} +\section{\code{`[`} methods}{ + +Return \code{coordinates} slot data.table from giotto S4 + + +Select rows (i) and cols (j) from giotto S4 metaDT slot + + +Return \code{metaDT} slot data.table from giotto S4 + + +Return \code{coordinates} slot matrix from giotto S4 dimObj + + +Select rows (i) and cols (j) from giotto S4 exprMat slot + + +Return \code{exprMat} slot Matrix object from giotto S4 + + +Return \code{spatNetData} slot network data.table object from giotto S4 + + +Return \code{nnData} slot igraph object from giotto S4 + + +Return \code{enrData} slot enrichment data.table object from giotto S4 + + +Return \code{spatGridData} slot data.table object from giotto S4 + + +Return \code{giottoPoints} spatVector slot + + +Return \code{giottoPolygon} spatVector slot +} + +\section{\code{`[<-`} methods}{ + +Assign to \code{coordinates} slot in giotto S4 +} + +\examples{ +gpoints <- GiottoData::loadSubObjectMini("giottoPoints") + +# extract contained `SpatVector` +gpoints[] + +# subset by feature +gpoints[c("Mlc1", "Gfap")] + +# subset by feature and colname +gpoints["Mlc1", c("feat_ID", "feat_ID_uniq")] + +# subset by index +gpoints[seq(20)] + +} +\seealso{ +[\verb{[<-}()] +} From 170bf3065a43481377cd7b96b328c25968920a15 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 26 Aug 2024 12:59:14 -0400 Subject: [PATCH 139/160] chore: continue reogranization and fixes to docs --- R/methods-extract.R | 92 ++++++++++++++++++-------------- man/extract-methods.Rd | 117 ----------------------------------------- man/replace_bracket.Rd | 19 +++++-- man/replace_dollar.Rd | 64 ++++++++++++++++++++++ man/subset_bracket.Rd | 22 ++------ man/subset_dollar.Rd | 70 ++++++++++++++++++++++++ 6 files changed, 205 insertions(+), 179 deletions(-) delete mode 100644 man/extract-methods.Rd create mode 100644 man/replace_dollar.Rd create mode 100644 man/subset_dollar.Rd diff --git a/R/methods-extract.R b/R/methods-extract.R index 9b94ce89..acc220e8 100644 --- a/R/methods-extract.R +++ b/R/methods-extract.R @@ -4,12 +4,12 @@ NULL # Documentations ------------------------------------------------------------ # -#' @title Subset part of an object +#' @title Subset part of an object with `[` #' @name subset_bracket #' @aliases `[` #' @description Extract values from Giotto classes. Providing empty brackets -#' will usually extract the contained data representation. -#' @param x Giotto S4 object to extract columns from +#' such as: `x[]` will usually extract the main contained data representation. +#' @param x Giotto S4 object to subset information from #' @param i,j indices specifying elements to extract. Indices are numeric or #' character vectors, or empty #' @returns Same as `x` unless brackets are empty in which case, the main @@ -29,14 +29,15 @@ NULL #' # subset by index #' gpoints[seq(20)] #' -#' @seealso [`[<-`()] [`$`()] [`$<-`()] +#' @seealso [[<-()] [$()] [$<-()] NULL -#' @title Replace part of an object +#' @title Replace part of an object with `[<-` #' @name replace_bracket #' @aliases `[<-` #' @description Replace values from Giotto Classes. Providing empty brackets -#' will usually replace the entire contained data representation. +#' such as `x[] <- value` will usually replace the entire contained data +#' representation. #' @param x Giotto S4 object to replace information in #' @param i,j indices specifying elements to replace. Indices are numeric or #' character vectors or empty @@ -47,32 +48,43 @@ NULL #' #' gpoints[] <- gpoints[] #' -#' @seealso [`[`()] [`$`()] [`$<-`()] +#' @seealso [[()] [$()] [$<-()] NULL +#' @title Replace part of an object with `$<-` +#' @name replace_dollar +#' @aliases `$<-` +#' @description +#' Replace values from Giotto Classes using `$<-` operator. +#' @param x Giotto S4 object to replace columns from +#' @param name A literal character string (possibly backtick quoted). +#' This is normally matched to the colnames. +#' @param value values(s) to set to a column +#' @returns same as `x` +#' @examples +#' gpoints <- GiottoData::loadSubObjectMini("giottoPoints") +#' +#' gpoints$new_col <- sprintf("feat_%d", seq(nrow(gpoints))) +#' +#' @seealso [$()] [[()] [[<-()] +NULL -#' @title Extract or replace parts of an object -#' @name extract-methods -#' @docType methods -#' @aliases `$` `$<-` -#' @description Operators Giotto S4 internal data.tables to extract -#' or replace parts. +#' @title Subset part of an object with `$` +#' @name subset_dollar +#' @aliases `$` +#' @description Subset values from a Giotto Class using `$` operator. #' @param x Giotto S4 object to extract columns from #' @param i,j indices specifying elements to extract or replace. Indices are #' numeric or character vectors or empty #' @param name A literal character string (possibly backtick quoted). -#' This is normally matched to the colnames of the data.table object within -#' the S4. -#' @param value value(s) to set -#' @returns columns or values from a data.table +#' This is normally matched to the colnames. +#' @returns vector of values from a requested column #' @section \code{`$`} methods: -#' @section \code{`$<-`} methods: -#' @section \code{`[`} methods: -#' @section \code{`[<-`} methods: #' @examples -#' g <- GiottoData::loadSubObjectMini("spatEnrObj") +#' enr <- GiottoData::loadSubObjectMini("spatEnrObj") #' -#' g$cell_ID +#' enr$cell_ID +#' @seealso [$<-()] [[()] [[<-()] NULL @@ -82,7 +94,7 @@ NULL ## * coordDataDT #### -#' @rdname extract-methods +#' @rdname subset_dollar #' @section \code{`$`} methods: #' Select by colname from giotto S4 data.table coordinates slot. #' @export @@ -92,7 +104,7 @@ setMethod( ) -#' @rdname extract-methods +#' @rdname replace_dollar #' @section \code{`$<-`} methods: #' Set values by colname into giotto S4 data.table coordinates slot. #' Works via data.table methods @@ -116,9 +128,9 @@ setMethod( ## * spatEnrObj #### -#' @rdname extract-methods +#' @rdname subset_dollar #' @section \code{`$`} methods: -#' Select by colname from giotto S4 enrObj +#' Select by colname from giotto S4 spatEnrObj #' @export setMethod( "$", signature(x = "spatEnrObj"), @@ -127,9 +139,9 @@ setMethod( } ) -#' @rdname extract-methods -#' @section \code{`$`} methods: -#' Set values by colname into giotto S4 dimObj. +#' @rdname replace_dollar +#' @section \code{`$<-`} methods: +#' Set values by colname into giotto S4 spatEnrObj. #' @export setMethod( "$<-", signature(x = "spatEnrObj"), @@ -147,7 +159,7 @@ setMethod( ## * dimObj #### -#' @rdname extract-methods +#' @rdname subset_dollar #' @section \code{`$`} methods: #' Select entries in misc slot from giotto S4 dimObj. #' @export @@ -156,8 +168,8 @@ setMethod( function(x, name) x@misc[[name]] ) -#' @rdname extract-methods -#' @section \code{`$`} methods: +#' @rdname replace_dollar +#' @section \code{`$<-`} methods: #' Set entries in misc slot from giotto S4 dimObj. #' @export setMethod( @@ -180,7 +192,7 @@ setMethod( colnames(x@metaDT) } -#' @rdname extract-methods +#' @rdname subset_dollar #' @section \code{`$`} methods: #' Select by colname from giotto S4 data.table metaDT slot. #' @export @@ -190,7 +202,7 @@ setMethod( ) -#' @rdname extract-methods +#' @rdname replace_dollar #' @section \code{`$<-`} methods: #' Set values by colname into giotto S4 data.table metaDT slot. #' Works via data.table methods @@ -206,7 +218,7 @@ setMethod( ## * terraVectData * #### -#' @rdname extract-methods +#' @rdname subset_dollar #' @section \code{`$`} methods: #' Select by colname from giotto S4 spatVector slot. #' @export @@ -215,7 +227,7 @@ setMethod( function(x, name) terra::as.list(x@spatVector)[[name]] ) -#' @rdname extract-methods +#' @rdname replace_dollar #' @section \code{`$<-`} methods: #' Set values by colname into giotto S4 spatVector slot. #' @export @@ -232,7 +244,7 @@ setMethod( names(x@spatVector) } -#' @rdname extract-methods +#' @rdname subset_dollar #' @section \code{`$`} methods: #' Select piecewise transform values from `affine2d` #' @export @@ -466,7 +478,7 @@ setMethod( } ) -#' @rdname subset_bracket +#' @rdname replace_bracket #' @aliases [<-,coordDataDT,missing,missing, #' ANY-method [<-,coordDataDT,missing,missing-method #' @docType methods @@ -1027,7 +1039,7 @@ setMethod( signature( x = "affine2d", i = "missing", j = "missing", drop = "missing" ), - function(x) { + function(x, i, j) { x@affine } ) @@ -1042,7 +1054,7 @@ setMethod( setMethod( "[<-", signature(x = "affine2d", i = "missing", j = "missing", value = "ANY"), - function(x, value) { + function(x, i, j, value) { x@affine <- value return(initialize(x)) } diff --git a/man/extract-methods.Rd b/man/extract-methods.Rd deleted file mode 100644 index e3b766ee..00000000 --- a/man/extract-methods.Rd +++ /dev/null @@ -1,117 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/methods-extract.R -\docType{methods} -\name{extract-methods} -\alias{extract-methods} -\alias{`$`} -\alias{`$<-`} -\alias{$,coordDataDT-method} -\alias{$<-,coordDataDT-method} -\alias{$,spatEnrObj-method} -\alias{$<-,spatEnrObj-method} -\alias{$,dimObj-method} -\alias{$<-,dimObj-method} -\alias{$,metaData-method} -\alias{$<-,metaData-method} -\alias{$,terraVectData-method} -\alias{$<-,terraVectData-method} -\alias{$,affine2d-method} -\title{Extract or replace parts of an object} -\usage{ -\S4method{$}{coordDataDT}(x, name) - -\S4method{$}{coordDataDT}(x, name) <- value - -\S4method{$}{spatEnrObj}(x, name) - -\S4method{$}{spatEnrObj}(x, name) <- value - -\S4method{$}{dimObj}(x, name) - -\S4method{$}{dimObj}(x, name) <- value - -\S4method{$}{metaData}(x, name) - -\S4method{$}{metaData}(x, name) <- value - -\S4method{$}{terraVectData}(x, name) - -\S4method{$}{terraVectData}(x, name) <- value - -\S4method{$}{affine2d}(x, name) -} -\arguments{ -\item{x}{Giotto S4 object to extract columns from} - -\item{name}{A literal character string (possibly backtick quoted). -This is normally matched to the colnames of the data.table object within -the S4.} - -\item{value}{value(s) to set} - -\item{i, j}{indices specifying elements to extract or replace. Indices are -numeric or character vectors or empty} -} -\value{ -columns or values from a data.table -} -\description{ -Operators Giotto S4 internal data.tables to extract -or replace parts. -} -\section{\code{`$`} methods}{ - - - -Select by colname from giotto S4 data.table coordinates slot. - - -Select by colname from giotto S4 enrObj - - -Set values by colname into giotto S4 dimObj. - - -Select entries in misc slot from giotto S4 dimObj. - - -Set entries in misc slot from giotto S4 dimObj. - - -Select by colname from giotto S4 data.table metaDT slot. - - -Select by colname from giotto S4 spatVector slot. - - -Select piecewise transform values from \code{affine2d} -} - -\section{\code{`$<-`} methods}{ - - - -Set values by colname into giotto S4 data.table coordinates slot. -Works via data.table methods - - -Set values by colname into giotto S4 data.table metaDT slot. -Works via data.table methods - - -Set values by colname into giotto S4 spatVector slot. -} - -\section{\code{`[`} methods}{ - -} - -\section{\code{`[<-`} methods}{ - -} - -\examples{ -g <- GiottoData::loadSubObjectMini("spatEnrObj") - -g$cell_ID -} diff --git a/man/replace_bracket.Rd b/man/replace_bracket.Rd index 953ff47c..18182367 100644 --- a/man/replace_bracket.Rd +++ b/man/replace_bracket.Rd @@ -4,9 +4,12 @@ \name{replace_bracket} \alias{replace_bracket} \alias{`[<-`} +\alias{[<-,coordDataDT,missing,missing,ANY-method} +\alias{[<-,coordDataDT,missing,missing,} +\alias{ANY-method} +\alias{[<-,coordDataDT,missing,missing-method} \alias{[<-,metaData,missing,missing,ANY-method} \alias{[<-,metaData,missing,missing,} -\alias{ANY-method} \alias{[<-,metaData,missing,missing-method} \alias{[<-,dimObj,missing,missing,ANY-method} \alias{[<-,dimObj,missing,missing,} @@ -35,8 +38,10 @@ \alias{[<-,affine2d,missing,missing,ANY-method} \alias{[<-,affine2d,missing,missing,} \alias{[<-,affine2d,missing,missing-method} -\title{Replace part of an object} +\title{Replace part of an object with \verb{[<-}} \usage{ +\S4method{[}{coordDataDT,missing,missing,ANY}(x, i, j) <- value + \S4method{[}{metaData,missing,missing,ANY}(x, i, j) <- value \S4method{[}{dimObj,missing,missing,ANY}(x, i, j) <- value @@ -55,7 +60,7 @@ \S4method{[}{giottoPolygon,missing,missing,ANY}(x, i, j) <- value -\S4method{[}{affine2d,missing,missing,ANY}(x) <- value +\S4method{[}{affine2d,missing,missing,ANY}(x, i, j) <- value } \arguments{ \item{x}{Giotto S4 object to replace information in} @@ -70,10 +75,14 @@ same as \code{x} } \description{ Replace values from Giotto Classes. Providing empty brackets -will usually replace the entire contained data representation. +such as \code{x[] <- value} will usually replace the entire contained data +representation. } \section{\code{`[<-`} methods}{ +Assign to \code{coordinates} slot in giotto S4 + + Assign to \code{metaDT} slot in giotto S4 @@ -111,5 +120,5 @@ gpoints[] <- gpoints[] } \seealso{ -[\code{[}()] +[\code{\link[=]{()}} \code{\link[=$]{$()}} \code{\link[=$<-]{$<-()}} } diff --git a/man/replace_dollar.Rd b/man/replace_dollar.Rd new file mode 100644 index 00000000..b4d9cc5d --- /dev/null +++ b/man/replace_dollar.Rd @@ -0,0 +1,64 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/methods-extract.R +\name{replace_dollar} +\alias{replace_dollar} +\alias{`$<-`} +\alias{$<-,coordDataDT-method} +\alias{$<-,spatEnrObj-method} +\alias{$<-,dimObj-method} +\alias{$<-,metaData-method} +\alias{$<-,terraVectData-method} +\title{Replace part of an object with \verb{$<-}} +\usage{ +\S4method{$}{coordDataDT}(x, name) <- value + +\S4method{$}{spatEnrObj}(x, name) <- value + +\S4method{$}{dimObj}(x, name) <- value + +\S4method{$}{metaData}(x, name) <- value + +\S4method{$}{terraVectData}(x, name) <- value +} +\arguments{ +\item{x}{Giotto S4 object to replace columns from} + +\item{name}{A literal character string (possibly backtick quoted). +This is normally matched to the colnames.} + +\item{value}{values(s) to set to a column} +} +\value{ +same as \code{x} +} +\description{ +Replace values from Giotto Classes using \verb{$<-} operator. +} +\section{\code{`$<-`} methods}{ + +Set values by colname into giotto S4 data.table coordinates slot. +Works via data.table methods + + +Set values by colname into giotto S4 spatEnrObj. + + +Set entries in misc slot from giotto S4 dimObj. + + +Set values by colname into giotto S4 data.table metaDT slot. +Works via data.table methods + + +Set values by colname into giotto S4 spatVector slot. +} + +\examples{ +gpoints <- GiottoData::loadSubObjectMini("giottoPoints") + +gpoints$new_col <- sprintf("feat_\%d", seq(nrow(gpoints))) + +} +\seealso{ +\code{\link[=$]{$()}} [\code{\link[=]{()}} [\code{\link[=<-]{<-()}} +} diff --git a/man/subset_bracket.Rd b/man/subset_bracket.Rd index 7c8f1a7c..c75310eb 100644 --- a/man/subset_bracket.Rd +++ b/man/subset_bracket.Rd @@ -1,6 +1,5 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/methods-extract.R -\docType{methods} \name{subset_bracket} \alias{subset_bracket} \alias{`[`} @@ -14,10 +13,6 @@ \alias{[,coordDataDT,missing,character,missing-method} \alias{[,coordDataDT,ANY,missing,missing-method} \alias{[,coordDataDT,missing,missing,missing-method} -\alias{[<-,coordDataDT,missing,missing,ANY-method} -\alias{[<-,coordDataDT,missing,missing,} -\alias{ANY-method} -\alias{[<-,coordDataDT,missing,missing-method} \alias{[,giottoPoints,gIndex,missing,missing-method} \alias{[,metaData,missing,ANY,missing-method} \alias{[,metaData,missing,character,missing-method} @@ -45,7 +40,7 @@ \alias{[,giottoPolygon,missing,gIndex,missing-method} \alias{[,terraVectData,gIndex,gIndex,missing-method} \alias{[,affine2d,missing,missing,missing-method} -\title{Subset part of an object} +\title{Subset part of an object with \code{[}} \usage{ \S4method{[}{gdtData,gIndex,gIndex,missing}(x, i, j) @@ -67,8 +62,6 @@ \S4method{[}{coordDataDT,missing,missing,missing}(x, i, j) -\S4method{[}{coordDataDT,missing,missing,ANY}(x, i, j) <- value - \S4method{[}{giottoPoints,gIndex,missing,missing}(x, i, j) \S4method{[}{metaData,missing,ANY,missing}(x, i, j) @@ -123,10 +116,10 @@ \S4method{[}{terraVectData,gIndex,gIndex,missing}(x, i, j) -\S4method{[}{affine2d,missing,missing,missing}(x) +\S4method{[}{affine2d,missing,missing,missing}(x, i, j) } \arguments{ -\item{x}{Giotto S4 object to extract columns from} +\item{x}{Giotto S4 object to subset information from} \item{i, j}{indices specifying elements to extract. Indices are numeric or character vectors, or empty} @@ -137,7 +130,7 @@ internal representation is returned. } \description{ Extract values from Giotto classes. Providing empty brackets -will usually extract the contained data representation. +such as: \code{x[]} will usually extract the main contained data representation. } \section{\code{`[`} methods}{ @@ -177,11 +170,6 @@ Return \code{giottoPoints} spatVector slot Return \code{giottoPolygon} spatVector slot } -\section{\code{`[<-`} methods}{ - -Assign to \code{coordinates} slot in giotto S4 -} - \examples{ gpoints <- GiottoData::loadSubObjectMini("giottoPoints") @@ -199,5 +187,5 @@ gpoints[seq(20)] } \seealso{ -[\verb{[<-}()] +[\code{\link[=<-]{<-()}} \code{\link[=$]{$()}} \code{\link[=$<-]{$<-()}} } diff --git a/man/subset_dollar.Rd b/man/subset_dollar.Rd new file mode 100644 index 00000000..7739fd5c --- /dev/null +++ b/man/subset_dollar.Rd @@ -0,0 +1,70 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/methods-extract.R +\name{subset_dollar} +\alias{subset_dollar} +\alias{`$`} +\alias{$,coordDataDT-method} +\alias{$,spatEnrObj-method} +\alias{$,dimObj-method} +\alias{$,metaData-method} +\alias{$,terraVectData-method} +\alias{$,affine2d-method} +\title{Subset part of an object with \code{$}} +\usage{ +\S4method{$}{coordDataDT}(x, name) + +\S4method{$}{spatEnrObj}(x, name) + +\S4method{$}{dimObj}(x, name) + +\S4method{$}{metaData}(x, name) + +\S4method{$}{terraVectData}(x, name) + +\S4method{$}{affine2d}(x, name) +} +\arguments{ +\item{x}{Giotto S4 object to extract columns from} + +\item{name}{A literal character string (possibly backtick quoted). +This is normally matched to the colnames.} + +\item{i, j}{indices specifying elements to extract or replace. Indices are +numeric or character vectors or empty} +} +\value{ +vector of values from a requested column +} +\description{ +Subset values from a Giotto Class using \code{$} operator. +} +\section{\code{`$`} methods}{ + + + +Select by colname from giotto S4 data.table coordinates slot. + + +Select by colname from giotto S4 spatEnrObj + + +Select entries in misc slot from giotto S4 dimObj. + + +Select by colname from giotto S4 data.table metaDT slot. + + +Select by colname from giotto S4 spatVector slot. + + +Select piecewise transform values from \code{affine2d} +} + +\examples{ +enr <- GiottoData::loadSubObjectMini("spatEnrObj") + +enr$cell_ID +} +\seealso{ +\code{\link[=$<-]{$<-()}} [\code{\link[=]{()}} [\code{\link[=<-]{<-()}} +} From 78623edab687c5939e62688e09bfb7eb5cb13f4c Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 26 Aug 2024 14:36:08 -0400 Subject: [PATCH 140/160] chore: fix empty links in docs --- R/methods-extract.R | 10 ++++------ man/replace_bracket.Rd | 2 +- man/replace_dollar.Rd | 2 +- man/subset_bracket.Rd | 2 +- man/subset_dollar.Rd | 5 +---- 5 files changed, 8 insertions(+), 13 deletions(-) diff --git a/R/methods-extract.R b/R/methods-extract.R index acc220e8..0c8fd7ac 100644 --- a/R/methods-extract.R +++ b/R/methods-extract.R @@ -29,7 +29,7 @@ NULL #' # subset by index #' gpoints[seq(20)] #' -#' @seealso [[<-()] [$()] [$<-()] +#' @seealso [replace_bracket] [subset_dollar] [replace_dollar] NULL #' @title Replace part of an object with `[<-` @@ -48,7 +48,7 @@ NULL #' #' gpoints[] <- gpoints[] #' -#' @seealso [[()] [$()] [$<-()] +#' @seealso [subset_bracket] [subset_dollar] [replace_dollar] NULL #' @title Replace part of an object with `$<-` @@ -66,7 +66,7 @@ NULL #' #' gpoints$new_col <- sprintf("feat_%d", seq(nrow(gpoints))) #' -#' @seealso [$()] [[()] [[<-()] +#' @seealso [subset_bracket] [replace_bracket] [subset_dollar] NULL #' @title Subset part of an object with `$` @@ -74,8 +74,6 @@ NULL #' @aliases `$` #' @description Subset values from a Giotto Class using `$` operator. #' @param x Giotto S4 object to extract columns from -#' @param i,j indices specifying elements to extract or replace. Indices are -#' numeric or character vectors or empty #' @param name A literal character string (possibly backtick quoted). #' This is normally matched to the colnames. #' @returns vector of values from a requested column @@ -84,7 +82,7 @@ NULL #' enr <- GiottoData::loadSubObjectMini("spatEnrObj") #' #' enr$cell_ID -#' @seealso [$<-()] [[()] [[<-()] +#' @seealso [subset_bracket] [replace_bracket] [replace_dollar] NULL diff --git a/man/replace_bracket.Rd b/man/replace_bracket.Rd index 18182367..1407978f 100644 --- a/man/replace_bracket.Rd +++ b/man/replace_bracket.Rd @@ -120,5 +120,5 @@ gpoints[] <- gpoints[] } \seealso{ -[\code{\link[=]{()}} \code{\link[=$]{$()}} \code{\link[=$<-]{$<-()}} +\link{subset_bracket} \link{subset_dollar} \link{replace_dollar} } diff --git a/man/replace_dollar.Rd b/man/replace_dollar.Rd index b4d9cc5d..62146595 100644 --- a/man/replace_dollar.Rd +++ b/man/replace_dollar.Rd @@ -60,5 +60,5 @@ gpoints$new_col <- sprintf("feat_\%d", seq(nrow(gpoints))) } \seealso{ -\code{\link[=$]{$()}} [\code{\link[=]{()}} [\code{\link[=<-]{<-()}} +\link{subset_bracket} \link{replace_bracket} \link{subset_dollar} } diff --git a/man/subset_bracket.Rd b/man/subset_bracket.Rd index c75310eb..f8c67477 100644 --- a/man/subset_bracket.Rd +++ b/man/subset_bracket.Rd @@ -187,5 +187,5 @@ gpoints[seq(20)] } \seealso{ -[\code{\link[=<-]{<-()}} \code{\link[=$]{$()}} \code{\link[=$<-]{$<-()}} +\link{replace_bracket} \link{subset_dollar} \link{replace_dollar} } diff --git a/man/subset_dollar.Rd b/man/subset_dollar.Rd index 7739fd5c..554a9bd4 100644 --- a/man/subset_dollar.Rd +++ b/man/subset_dollar.Rd @@ -28,9 +28,6 @@ \item{name}{A literal character string (possibly backtick quoted). This is normally matched to the colnames.} - -\item{i, j}{indices specifying elements to extract or replace. Indices are -numeric or character vectors or empty} } \value{ vector of values from a requested column @@ -66,5 +63,5 @@ enr <- GiottoData::loadSubObjectMini("spatEnrObj") enr$cell_ID } \seealso{ -\code{\link[=$<-]{$<-()}} [\code{\link[=]{()}} [\code{\link[=<-]{<-()}} +\link{subset_bracket} \link{replace_bracket} \link{replace_dollar} } From c05b8b7c461a7fa6dc74710f616eebef9983caf7 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 26 Aug 2024 14:36:46 -0400 Subject: [PATCH 141/160] fix: genv checking in installGiottoEnvironment() --- R/python_environment.R | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 209e2cee..09c96661 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -153,7 +153,12 @@ checkGiottoEnvironment <- function( found <- is.character(py_path) if (found) { - vmsg(.v = verbose, "giotto environment found at\n", py_path) + vmsg(.v = verbose, sprintf( + "Giotto can access environment found at: \n'%s'\n%s\n%s", + py_path, + "If this is the wrong environment, try specifying `envname` param", + "or set option \"giotto.py_path\" with the desired envname or path" + )) } return(found) @@ -397,14 +402,15 @@ checkGiottoEnvironment <- function( # first see if Giotto environment is already installed giotto_installed <- checkGiottoEnvironment( - envname = mini_install_path, + envname = envname, verbose = FALSE ) # already installed and no force: do nothing & return if (isTRUE(giotto_installed) && !isTRUE(force_environment)) { vmsg(.v = verbose, - "Giotto environment is already installed, + "An environment usable by Giotto is already installed + Run `checkGiottoEnvironment()` to see which is being detected. set force_environment = TRUE to reinstall" ) return(invisible()) # return early @@ -684,7 +690,8 @@ set_giotto_python_path <- function( # early return NULL if specified and NOT found. if (is.null(python_path) && !is.null(specified)) { - vmsg(sprintf("specified py env from %s not found\n", specified)) + vmsg(.v = verbose, + sprintf("specified py env from %s not found\n", specified)) return(invisible()) } From a2b6b0d209a01b3cc407b6c98b7e40c2b411b5c0 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 26 Aug 2024 14:36:55 -0400 Subject: [PATCH 142/160] chore: update news --- NEWS.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 166c9cb7..8abf142d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,5 @@ -# GiottoClass 0.3.5 +# GiottoClass 0.3.5 (2024/08/26) ## breaking changes - `set_giotto_python_path()` will now also initialize python env to set by default and print which python env is active, but otherwise do nothing if any python env has already been initialized. @@ -10,6 +10,8 @@ - intensity images now automatically scale to estimated highest value - `giottoPolygon` `plot()` default `max_poly` raised to `1e6` - `giottoInstructions` no longer lose class when specific params are replaced +- fix error in documentation [#214](https://github.com/drieslab/GiottoClass/issues/214) by shaojunyu +- fix error in `installGiottoEnvironment()` [#1006](https://github.com/drieslab/Giotto/issues/1006) by 13954380607 ## enhancements - `print()` method for `giottoInstructions` From 513aea67f43a3bf647b06bbce9cc4d562ed3050e Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Mon, 26 Aug 2024 17:43:11 -0400 Subject: [PATCH 143/160] chore: docs updates --- NEWS.md | 2 ++ R/python_environment.R | 2 +- man/giotto_python.Rd | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 8abf142d..41f741bf 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,6 +10,8 @@ - intensity images now automatically scale to estimated highest value - `giottoPolygon` `plot()` default `max_poly` raised to `1e6` - `giottoInstructions` no longer lose class when specific params are replaced +- `ometif_to_tif()` now checks for _imagecodecs_ package as well +- `anndataToGiotto()` & `giottoToAnndata` now check for _anndata_ package as well. - fix error in documentation [#214](https://github.com/drieslab/GiottoClass/issues/214) by shaojunyu - fix error in `installGiottoEnvironment()` [#1006](https://github.com/drieslab/Giotto/issues/1006) by 13954380607 diff --git a/R/python_environment.R b/R/python_environment.R index 09c96661..4c37b80b 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -108,7 +108,7 @@ NULL #' @describeIn giotto_python #' #' - Based on `envname`, detect if there is a conda or miniconda installation -#' without initializing any python environments. +#' accessible by \pkg{Giotto} without initializing any python environments. #' This is done by detecting if there is a python executable in the #' expected location. Leaving `envname` as `NULL` (default) will let #' \pkg{Giotto} autodetect a python env to use. See section for diff --git a/man/giotto_python.Rd b/man/giotto_python.Rd index 4301981b..1e202d7d 100644 --- a/man/giotto_python.Rd +++ b/man/giotto_python.Rd @@ -118,7 +118,7 @@ environment usable by Giotto without initializing. \itemize{ \item \code{checkGiottoEnvironment()}: \itemize{ \item Based on \code{envname}, detect if there is a conda or miniconda installation -without initializing any python environments. +accessible by \pkg{Giotto} without initializing any python environments. This is done by detecting if there is a python executable in the expected location. Leaving \code{envname} as \code{NULL} (default) will let \pkg{Giotto} autodetect a python env to use. See section for From 3b140c4c9938dc69309d4cf16f742b1a2e20a9b4 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 27 Aug 2024 07:47:31 -0400 Subject: [PATCH 144/160] change: checkGiottoEnv should look for giotto_env by default --- R/python_environment.R | 28 +++++++++++++++++----------- man/giotto_python.Rd | 13 ++++++------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 4c37b80b..2faa42d3 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -107,12 +107,11 @@ NULL #' @describeIn giotto_python #' -#' - Based on `envname`, detect if there is a conda or miniconda installation -#' accessible by \pkg{Giotto} without initializing any python environments. -#' This is done by detecting if there is a python executable in the -#' expected location. Leaving `envname` as `NULL` (default) will let -#' \pkg{Giotto} autodetect a python env to use. See section for -#' `set_giotto_python_path()` for details on the autodetection. +#' - Based on `envname`, detect if there a conda or miniconda installation +#' accessible by \pkg{Giotto}. By default, the `envname` `"giotto_env"` is +#' checked, but an alternative can be provided. Leaving `envname` as `NULL` +#' will let \pkg{Giotto} autodetect a python env to use. +#' See section for `set_giotto_python_path()` for details on the autodetection. #' - Returns `TRUE` if an env is detected and accessible by Giotto. `FALSE` #' if not. Will not initialize a python environment during detection. #' @examples @@ -132,7 +131,7 @@ NULL #' } #' @export checkGiottoEnvironment <- function( - envname = NULL, + envname = "giotto_env", mini_install_path = deprecated(), verbose = NULL ) { @@ -154,13 +153,20 @@ checkGiottoEnvironment <- function( if (found) { vmsg(.v = verbose, sprintf( - "Giotto can access environment found at: \n'%s'\n%s\n%s", - py_path, - "If this is the wrong environment, try specifying `envname` param", - "or set option \"giotto.py_path\" with the desired envname or path" + "Giotto can access environment found at: \n'%s'", py_path + )) + } else { + vmsg(.v = verbose, sprintf( + "Giotto cannot find python environment with `envname`: '%s'", + envname )) } + vmsg(.v = verbose, .initial = " ", + "If this is the wrong environment, try specifying `envname` param + or set option \"giotto.py_path\" with the desired envname or path" + ) + return(found) # # check for envnames, if found, get the path diff --git a/man/giotto_python.Rd b/man/giotto_python.Rd index 1e202d7d..57a6390c 100644 --- a/man/giotto_python.Rd +++ b/man/giotto_python.Rd @@ -9,7 +9,7 @@ \title{Giotto python environment} \usage{ checkGiottoEnvironment( - envname = NULL, + envname = "giotto_env", mini_install_path = deprecated(), verbose = NULL ) @@ -117,12 +117,11 @@ environment usable by Giotto without initializing. \section{Functions}{ \itemize{ \item \code{checkGiottoEnvironment()}: \itemize{ -\item Based on \code{envname}, detect if there is a conda or miniconda installation -accessible by \pkg{Giotto} without initializing any python environments. -This is done by detecting if there is a python executable in the -expected location. Leaving \code{envname} as \code{NULL} (default) will let -\pkg{Giotto} autodetect a python env to use. See section for -\code{set_giotto_python_path()} for details on the autodetection. +\item Based on \code{envname}, detect if there a conda or miniconda installation +accessible by \pkg{Giotto}. By default, the \code{envname} \code{"giotto_env"} is +checked, but an alternative can be provided. Leaving \code{envname} as \code{NULL} +will let \pkg{Giotto} autodetect a python env to use. +See section for \code{set_giotto_python_path()} for details on the autodetection. \item Returns \code{TRUE} if an env is detected and accessible by Giotto. \code{FALSE} if not. Will not initialize a python environment during detection. } From c84d5dced1bab65319ed78c660ede8278dbab52c Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 27 Aug 2024 07:51:33 -0400 Subject: [PATCH 145/160] Update NEWS.md --- NEWS.md | 1 - 1 file changed, 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 41f741bf..c8a53cbf 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,7 +3,6 @@ ## breaking changes - `set_giotto_python_path()` will now also initialize python env to set by default and print which python env is active, but otherwise do nothing if any python env has already been initialized. -- `checkGiottoEnvironment()` no longer checks specifically for the `"giotto_env"` environment, but is instead a general check for whether Giotto can detect a python environment and also which it is. - deprecated `readGiottoInstructions()`, `showGiottoInstructions()`, `changeGiottoInstructions()`, `replaceGiottoInstructions()` in favor of `instructions()` generic ## bug fixes From ebf9192b2057ae9d6fd336c83e5063d595f56ce1 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 27 Aug 2024 09:54:27 -0400 Subject: [PATCH 146/160] allow checkGiottoenv to check option and switch to auto detect --- R/python_environment.R | 38 ++++++++++++++++++++++++-------------- man/giotto_python.Rd | 31 +++++++++++++++++-------------- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 2faa42d3..196d7a16 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -108,10 +108,12 @@ NULL #' @describeIn giotto_python #' #' - Based on `envname`, detect if there a conda or miniconda installation -#' accessible by \pkg{Giotto}. By default, the `envname` `"giotto_env"` is -#' checked, but an alternative can be provided. Leaving `envname` as `NULL` -#' will let \pkg{Giotto} autodetect a python env to use. -#' See section for `set_giotto_python_path()` for details on the autodetection. +#' accessible by \pkg{Giotto}. By default, the `envname` `"giotto_env"`, then +#' the option `"giotto.py_path"` is checked, but an alternative can be +#' provided. +#' - Setting `envname` as `":auto:"` will let \pkg{Giotto} autodetect a python +#' env to use. See section for `set_giotto_python_path()` for details on the +#' autodetection. #' - Returns `TRUE` if an env is detected and accessible by Giotto. `FALSE` #' if not. Will not initialize a python environment during detection. #' @examples @@ -131,7 +133,7 @@ NULL #' } #' @export checkGiottoEnvironment <- function( - envname = "giotto_env", + envname = NULL, mini_install_path = deprecated(), verbose = NULL ) { @@ -145,6 +147,13 @@ checkGiottoEnvironment <- function( envname <- mini_install_path } + if (identical(envname, ":auto:")) { + envname <- NULL + } else { + envname <- envname %null% getOption("giotto.py_path") + envname <- envname %null% "giotto_env" + } + py_path <- set_giotto_python_path( python_path = envname, verbose = FALSE, initialize = FALSE ) @@ -453,10 +462,10 @@ checkGiottoEnvironment <- function( #' @describeIn giotto_python #' -#' - Install a giotto python environment using the miniconda system as -#' implemented by \pkg{reticulate}. Once this environment is installed it -#' will be automatically detected when you run the -#' \pkg{Giotto} toolbox. \cr This includes a +#' - Install a giotto python environment using miniconda through +#' \pkg{reticulate}. By default, the envname used will be `"giotto_env"`. If +#' another name is used, you will have to provide that envname at the start of +#' a session (see **Choosing an environment** above). \cr This includes a #' miniconda installation and also a set of python packages that \pkg{Giotto} #' may often use. See details for further information on setting up an #' environment with a .yml @@ -604,11 +613,12 @@ removeGiottoEnvironment <- function( #' 5. System default python environment #' #' - This function exits without doing anything if option `"giotto.use_conda"` -#' is `FALSE`. By default this function will also force initialization of the -#' python to set, locking the session to the set python. This can be skipped -#' if `initialize = FALSE`, however the actual python path set may differ from -#' what is expected and reported by this function. Additionally, -#' [reticulate::py_available()] will still show as `FALSE`. +#' is `FALSE`. +#' - By default this function will force initialization of the python +#' environment to set, locking the session to that environment. +#' This can be skipped if `initialize = FALSE`, however in that case, the +#' actual python path set downstream may differ from what is expected and +#' reported by this function. #' - Returns detected path to python binary or `NULL` if none found. #' @param python_path character. Name of environment or full path to python #' executable. diff --git a/man/giotto_python.Rd b/man/giotto_python.Rd index 57a6390c..f2f9b5bc 100644 --- a/man/giotto_python.Rd +++ b/man/giotto_python.Rd @@ -9,7 +9,7 @@ \title{Giotto python environment} \usage{ checkGiottoEnvironment( - envname = "giotto_env", + envname = NULL, mini_install_path = deprecated(), verbose = NULL ) @@ -118,19 +118,21 @@ environment usable by Giotto without initializing. \itemize{ \item \code{checkGiottoEnvironment()}: \itemize{ \item Based on \code{envname}, detect if there a conda or miniconda installation -accessible by \pkg{Giotto}. By default, the \code{envname} \code{"giotto_env"} is -checked, but an alternative can be provided. Leaving \code{envname} as \code{NULL} -will let \pkg{Giotto} autodetect a python env to use. -See section for \code{set_giotto_python_path()} for details on the autodetection. +accessible by \pkg{Giotto}. By default, the \code{envname} \code{"giotto_env"}, then +the option \code{"giotto.py_path"} is checked, but an alternative can be +provided. +\item Setting \code{envname} as \code{":auto:"} will let \pkg{Giotto} autodetect a python +env to use. See section for \code{set_giotto_python_path()} for details on the +autodetection. \item Returns \code{TRUE} if an env is detected and accessible by Giotto. \code{FALSE} if not. Will not initialize a python environment during detection. } \item \code{installGiottoEnvironment()}: \itemize{ -\item Install a giotto python environment using the miniconda system as -implemented by \pkg{reticulate}. Once this environment is installed it -will be automatically detected when you run the -\pkg{Giotto} toolbox. \cr This includes a +\item Install a giotto python environment using miniconda through +\pkg{reticulate}. By default, the envname used will be \code{"giotto_env"}. If +another name is used, you will have to provide that envname at the start of +a session (see \strong{Choosing an environment} above). \cr This includes a miniconda installation and also a set of python packages that \pkg{Giotto} may often use. See details for further information on setting up an environment with a .yml @@ -155,11 +157,12 @@ final path to use is determined as follows in decreasing priority: \item System default python environment } \item This function exits without doing anything if option \code{"giotto.use_conda"} -is \code{FALSE}. By default this function will also force initialization of the -python to set, locking the session to the set python. This can be skipped -if \code{initialize = FALSE}, however the actual python path set may differ from -what is expected and reported by this function. Additionally, -\code{\link[reticulate:py_available]{reticulate::py_available()}} will still show as \code{FALSE}. +is \code{FALSE}. +\item By default this function will force initialization of the python +environment to set, locking the session to that environment. +This can be skipped if \code{initialize = FALSE}, however in that case, the +actual python path set downstream may differ from what is expected and +reported by this function. \item Returns detected path to python binary or \code{NULL} if none found. } From 777d21dd3321aedf94fb70ad2479008a881a1b45 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 27 Aug 2024 09:55:11 -0400 Subject: [PATCH 147/160] Update NEWS.md --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index c8a53cbf..bd4526ef 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,5 @@ -# GiottoClass 0.3.5 (2024/08/26) +# GiottoClass 0.3.5 (2024/08/27) ## breaking changes - `set_giotto_python_path()` will now also initialize python env to set by default and print which python env is active, but otherwise do nothing if any python env has already been initialized. From 6d6329911f197f1ebcb4a2a0913cdf9c2959b938 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:34:04 -0400 Subject: [PATCH 148/160] fix: z stacking --- NEWS.md | 2 ++ R/join.R | 20 +++++-------- R/methods-dims.R | 34 ++++++++++----------- R/methods-rbind.R | 48 ++++++++++++++++++++++++++++++ R/methods-show.R | 76 ++++++++++++++++++----------------------------- 5 files changed, 102 insertions(+), 78 deletions(-) diff --git a/NEWS.md b/NEWS.md index bd4526ef..1d0403cf 100644 --- a/NEWS.md +++ b/NEWS.md @@ -11,11 +11,13 @@ - `giottoInstructions` no longer lose class when specific params are replaced - `ometif_to_tif()` now checks for _imagecodecs_ package as well - `anndataToGiotto()` & `giottoToAnndata` now check for _anndata_ package as well. +- fix `joinGiottoObjects()` `"z_stack"` join method - fix error in documentation [#214](https://github.com/drieslab/GiottoClass/issues/214) by shaojunyu - fix error in `installGiottoEnvironment()` [#1006](https://github.com/drieslab/Giotto/issues/1006) by 13954380607 ## enhancements - `print()` method for `giottoInstructions` +- `rbind()` for `spatLocsObj` # GiottoClass 0.3.4 (2024/08/04) diff --git a/R/join.R b/R/join.R index dbac99dd..5dcd4674 100644 --- a/R/join.R +++ b/R/join.R @@ -44,9 +44,8 @@ #' @name .join_spatlocs #' @keywords internal #' @noRd -.join_spatlocs <- function(dt_list) { - final_list <- do.call("rbind", dt_list) # breaks DT reference - return(final_list) +.join_spatlocs <- function(x) { + do.call("rbind", x) # breaks DT reference } #' @title .join_cell_meta @@ -491,7 +490,7 @@ joinGiottoObjects <- function(gobject_list, # spatial shifts if (join_method == "z_stack") { - spatShift(sl, dz = z_vals[gobj_i]) + sl <- spatShift(sl, dz = z_vals[gobj_i]) } return(sl) }) @@ -708,16 +707,11 @@ joinGiottoObjects <- function(gobject_list, warning(wrap_txt("spatial locations: provenance mismatch")) } - combspatlocs <- .join_spatlocs(dt_list = lapply( - sl_list, - function(sl) sl[] - )) - sl_list[[1]][] <- combspatlocs + combspatlocs <- .join_spatlocs(x = sl_list) ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### - comb_gobject <- set_spatial_locations(comb_gobject, - spatlocs = sl_list[[1]], - set_defaults = FALSE + comb_gobject <- setGiotto( + comb_gobject, combspatlocs, initialize = FALSE, verbose = FALSE ) ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### } @@ -889,7 +883,7 @@ joinGiottoObjects <- function(gobject_list, ## If no feature_metadata exists, then generate now if (is.null(list_cell_metadata(comb_gobject))) { - comb_gobject <- init_feat_metadata() + comb_gobject <- init_feat_metadata(comb_gobject) } diff --git a/R/methods-dims.R b/R/methods-dims.R index 006ecfe7..a6368cb2 100644 --- a/R/methods-dims.R +++ b/R/methods-dims.R @@ -7,6 +7,7 @@ NULL #' @description Find the dimensions of an object #' @param x object to check dimensions of #' @returns numeric +#' @keywords internal #' @examples #' g <- GiottoData::loadSubObjectMini("giottoPoints") #' @@ -19,22 +20,21 @@ NULL # nrow #### -#' @describeIn dims-generic Find rows of giottoPoints object +#' @rdname dims-generic #' @export setMethod( "nrow", signature("giottoPoints"), function(x) terra::nrow(x@spatVector) ) -#' @describeIn dims-generic Find rows of giottoPolygon object +#' @rdname dims-generic #' @export setMethod( "nrow", signature("giottoPolygon"), function(x) terra::nrow(x@spatVector) ) -#' @describeIn dims-generic Find rows of giotto S4s with data.table -#' based \code{coordinates} slots +#' @rdname dims-generic #' @export setMethod("nrow", signature("spatLocsObj"), function(x) nrow(x@coordinates)) @@ -42,17 +42,15 @@ setMethod("nrow", signature("spatLocsObj"), function(x) nrow(x@coordinates)) # TODO # setMethod('dims', signature('coordDataMT'), function(x) nrow(x@coordinates)) -#' @describeIn dims-generic Find rows of giotto S4s with data.table -#' based \code{coordinates} slots +#' @rdname dims-generic #' @export setMethod("nrow", signature("exprData"), function(x) nrow(x@exprMat)) -#' @describeIn dims-generic Find rows of giotto S4s with data.table -#' based \code{coordinates} slots +#' @rdname dims-generic #' @export setMethod("nrow", signature("metaData"), function(x) nrow(x@metaDT)) -#' @describeIn dims-generic Find rows of spatialNetworkObj +#' @rdname dims-generic #' @export setMethod( "nrow", signature("spatialNetworkObj"), @@ -81,17 +79,15 @@ setMethod("nrow", signature("dimObj"), function(x) nrow(x@coordinates)) # }) -#' @describeIn dims-generic Find cols of giotto S4s with Matrix -#' based \code{exprMat} slots +#' @rdname dims-generic #' @export setMethod("ncol", signature("exprData"), function(x) ncol(x@exprMat)) -#' @describeIn dims-generic Find cols of giotto S4s with data.table -#' based \code{metaDT} slots +#' @rdname dims-generic #' @export setMethod("ncol", signature("metaData"), function(x) ncol(x@metaDT)) -#' @describeIn dims-generic Find cols of giotto S4s with enrData +#' @rdname dims-generic #' @export setMethod("ncol", signature("enrData"), function(x) ncol(x@enrichDT)) @@ -105,13 +101,15 @@ setMethod("ncol", signature("dimObj"), function(x) ncol(x@coordinates)) ## dim() generic #### -#' @describeIn dims-generic Find dimensions of giotto S4s with Matrix -#' based \code{exprMat} slots +#' @rdname dims-generic +#' @export +setMethod("dim", signature("spatLocsObj"), function(x) dim(x@coordinates)) + +#' @rdname dims-generic #' @export setMethod("dim", signature("exprData"), function(x) dim(x@exprMat)) -#' @describeIn dims-generic Find dimensions of giotto S4s with data.table -#' based \code{metaDT} slots +#' @rdname dims-generic #' @export setMethod("dim", signature("metaData"), function(x) dim(x@metaDT)) diff --git a/R/methods-rbind.R b/R/methods-rbind.R index 0896c3f0..a3b2c71f 100644 --- a/R/methods-rbind.R +++ b/R/methods-rbind.R @@ -1,6 +1,10 @@ #' @include generics.R NULL +# NOTE: +# rbind2 methods will only work if the object already has nrow and dim +# generics defined. + # docs ----------------------------------------------------------- # #' @title Combine objects by rows (Giotto-related) #' @name rbind-generic @@ -18,7 +22,30 @@ NULL NULL # ---------------------------------------------------------------- # +#' @rdname rbind-generic +#' @export +setMethod( + "rbind2", signature(x = "spatLocsObj", y = "spatLocsObj"), + function(x, y, ...) { + # catch same IDs + if (any(duplicated(c(spatIDs(x), spatIDs(y))))) { + stop("rbind: `spatLocsObj` with the same IDs cannot be joined", + call. = FALSE) + } + + # if one is 3d, ensure both are 3d + x3 <- .is_3d_spatlocs(x) + y3 <- .is_3d_spatlocs(y) + if (any(c(x3, y3)) && !(x3 && y3)) { + if (!x3) x <- .make_spatlocs_3d(x) + if (!y3) y <- .make_spatlocs_3d(y) + } + + x[] <- rbind(x[], y[]) + return(x) + } +) #' @describeIn rbind-generic Append giottoPolygon objects #' @export @@ -56,11 +83,32 @@ setMethod("rbind", "giottoPolygon", function(..., deparse.level = 1) { }) +setMethod("rbind", "spatLocsObj", function(..., deparse.level = 1) { + if (nargs() <= 2L) { + rbind2(...) + } else { + xs <- list(...) + rbind2(xs[[1L]], do.call(Recall, xs[-1L])) + } +}) # internals #### + +.is_3d_spatlocs <- function(x) { + "sdimz" %in% colnames(x) +} + +.make_spatlocs_3d <- function(x, z_val = 0) { + x[][["sdimz"]] <- z_val + data.table::setcolorder(x[], c("sdimx", "sdimy", "sdimz")) + return(x) +} + + + #' @title Append giotto polygons of the same name #' @name rbind2_giotto_polygon_homo #' @description Append two giotto polygons together of the same name. diff --git a/R/methods-show.R b/R/methods-show.R index 565a9901..ffd861b5 100644 --- a/R/methods-show.R +++ b/R/methods-show.R @@ -13,8 +13,16 @@ NULL #' NULL - - +#' @name show +#' @title Show methods for Giotto classes +#' @description Show methods for Giotto classes +#' @param object object to show +#' @keywords internal +#' @examples +#' sl <- data.frame(seq(10), seq(10), letters[seq(10)]) |> +#' createSpatLocsObj(verbose = FALSE) +#' show(sl) +NULL # ------------------------------------------------------ # @@ -23,12 +31,7 @@ NULL # Giotto #### -#' show method for giotto class -#' @param object giotto object -#' @aliases show,giotto-method -#' @docType methods -#' @returns giotto object or subobject -#' @rdname show-methods +#' @rdname show setMethod( f = "show", signature = "giotto", @@ -150,6 +153,7 @@ setMethod( # packedGiotto #### +#' @rdname show setMethod( "show", signature(object = "packedGiotto"), function(object) { @@ -171,11 +175,7 @@ setMethod( ## exprObj #### -#' show method for exprObj class -#' @param object expression object -#' @aliases show,exprObj-method -#' @docType methods -#' @rdname show-methods +#' @rdname show setMethod( f = "show", signature("exprObj"), function(object) { .show_class_and_name(object) @@ -236,6 +236,7 @@ setMethod( ## cellMetaObj #### +#' @rdname show setMethod("show", signature("cellMetaObj"), function(object) { cat("An object of class", class(object), "\n") .show_spat_and_feat(object) @@ -248,6 +249,7 @@ setMethod("show", signature("cellMetaObj"), function(object) { ## featMetaObj #### +#' @rdname show setMethod("show", signature("featMetaObj"), function(object) { cat("An object of class", class(object), "\n") .show_spat_and_feat(object) @@ -269,10 +271,7 @@ setMethod("show", signature("featMetaObj"), function(object) { ## dimObj #### #' Show method for dimObj class -#' @param object dimension reduction object -#' @aliases show,dimObj-method -#' @docType methods -#' @rdname show-methods +#' @rdname show setMethod( f = "show", signature("dimObj"), function(object) { .show_class_and_name(object) @@ -313,10 +312,7 @@ setMethod( ## nnNetObj #### #' Show method for nnNetObj class -#' @param object nearest neigbor network object -#' @aliases show,nnNetObj-method -#' @docType methods -#' @rdname show-methods +#' @rdname show setMethod( f = "show", signature("nnNetObj"), function(object) { .show_class_and_name(object) @@ -357,16 +353,13 @@ setMethod( ## spatLocsObj #### #' show method for spatLocsObj class -#' @param object spatial locations object -#' @aliases show,spatLocsObj-method -#' @docType methods -#' @rdname show-methods +#' @rdname show setMethod("show", signature("spatLocsObj"), function(object) { .show_class_and_name(object) .show_spat(object) .show_prov(object) + cat("dimensions:", dim(object), '\npreview :\n') - cat(" ------------------------\n\npreview:\n") if (!is.null(slot(object, "coordinates"))) { show(head(slot(object, "coordinates"), 3L)) } @@ -399,10 +392,7 @@ setMethod("show", signature("spatLocsObj"), function(object) { ## spatialNetworkObj #### #' show method for spatialNetworkObj class -#' @param object spatial network object -#' @aliases show,spatialNetworkObj-method -#' @docType methods -#' @rdname show-methods +#' @rdname show setMethod( f = "show", signature("spatialNetworkObj"), function(object) { .show_class_and_name(object) @@ -439,10 +429,7 @@ setMethod( ## spatialGridObj #### #' show method for spatialGridObj class -#' @param object spatial grid object -#' @aliases show,spatialGridObj-method -#' @docType methods -#' @rdname show-methods +#' @rdname show setMethod( f = "show", signature("spatialGridObj"), function(object) { # define for data.table @@ -529,10 +516,7 @@ setMethod( ## spatEnrObj #### #' show method for spatEnrObj class -#' @param object spatial locations object -#' @aliases show,spatEnrObj-method -#' @docType methods -#' @rdname show-methods +#' @rdname show setMethod( f = "show", signature("spatEnrObj"), function(object) { .show_class_and_name(object) @@ -579,6 +563,7 @@ setMethod( ## giottoPolygon #### +#' @rdname show setMethod("show", signature = "giottoPolygon", function(object) { cat("An object of class giottoPolygon\n") .show_spat(object) @@ -612,6 +597,7 @@ setMethod("show", signature = "giottoPolygon", function(object) { ## packedGiottoPolygon #### +#' @rdname show setMethod( "show", signature(object = "packedGiottoPolygon"), function(object) { @@ -631,6 +617,7 @@ setMethod( ## giottoPoints #### +#' @rdname show setMethod("show", signature = "giottoPoints", function(object) { cat("An object of class giottoPoints\n") .show_feat(object) @@ -651,6 +638,7 @@ setMethod("show", signature = "giottoPoints", function(object) { ## packedGiottoPoints #### +#' @rdname show setMethod( "show", signature(object = "packedGiottoPoints"), function(object) { @@ -674,10 +662,7 @@ setMethod( ## giottoImage #### #' show method for giottoImage class -#' @param object giottoImage object -#' @aliases show,giottoImage-method -#' @docType methods -#' @rdname show-methods +#' @rdname show setMethod( f = "show", signature = "giottoImage", @@ -752,10 +737,7 @@ setMethod("as.character", signature("giottoImage"), function(x, ...) { # giottoLargeImage #### #' show method for giottoLargeImage class -#' @param object giottoLargeImage object -#' @aliases show,giottoLargeImage-method -#' @docType methods -#' @rdname show-methods +#' @rdname show setMethod( f = "show", signature = "giottoLargeImage", @@ -796,7 +778,7 @@ setMethod( -#' @rdname show-methods +#' @rdname show setMethod("show", signature("affine2d"), function(object) { cat("\n") .anchor_print <- function() { From 4ee0a48792bd4cd1eb9587be6299f04ed50387d8 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 28 Aug 2024 02:24:23 -0400 Subject: [PATCH 149/160] chore: docs --- man/dims-generic.Rd | 36 +++----------------- man/rbind-generic.Rd | 7 ++-- man/{show-methods.Rd => show.Rd} | 58 ++++++++++++++++++-------------- 3 files changed, 41 insertions(+), 60 deletions(-) rename man/{show-methods.Rd => show.Rd} (53%) diff --git a/man/dims-generic.Rd b/man/dims-generic.Rd index a94e62cd..986ccb3c 100644 --- a/man/dims-generic.Rd +++ b/man/dims-generic.Rd @@ -14,6 +14,7 @@ \alias{ncol,metaData-method} \alias{ncol,enrData-method} \alias{ncol,dimObj-method} +\alias{dim,spatLocsObj-method} \alias{dim,exprData-method} \alias{dim,metaData-method} \alias{dim,enrData-method} @@ -46,6 +47,8 @@ \S4method{ncol}{dimObj}(x) +\S4method{dim}{spatLocsObj}(x) + \S4method{dim}{exprData}(x) \S4method{dim}{metaData}(x) @@ -67,40 +70,9 @@ numeric \description{ Find the dimensions of an object } -\section{Functions}{ -\itemize{ -\item \code{nrow(giottoPoints)}: Find rows of giottoPoints object - -\item \code{nrow(giottoPolygon)}: Find rows of giottoPolygon object - -\item \code{nrow(spatLocsObj)}: Find rows of giotto S4s with data.table -based \code{coordinates} slots - -\item \code{nrow(exprData)}: Find rows of giotto S4s with data.table -based \code{coordinates} slots - -\item \code{nrow(metaData)}: Find rows of giotto S4s with data.table -based \code{coordinates} slots - -\item \code{nrow(spatialNetworkObj)}: Find rows of spatialNetworkObj - -\item \code{ncol(exprData)}: Find cols of giotto S4s with Matrix -based \code{exprMat} slots - -\item \code{ncol(metaData)}: Find cols of giotto S4s with data.table -based \code{metaDT} slots - -\item \code{ncol(enrData)}: Find cols of giotto S4s with enrData - -\item \code{dim(exprData)}: Find dimensions of giotto S4s with Matrix -based \code{exprMat} slots - -\item \code{dim(metaData)}: Find dimensions of giotto S4s with data.table -based \code{metaDT} slots - -}} \examples{ g <- GiottoData::loadSubObjectMini("giottoPoints") nrow(g) } +\keyword{internal} diff --git a/man/rbind-generic.Rd b/man/rbind-generic.Rd index bc719877..1a2978aa 100644 --- a/man/rbind-generic.Rd +++ b/man/rbind-generic.Rd @@ -2,9 +2,12 @@ % Please edit documentation in R/methods-rbind.R \name{rbind-generic} \alias{rbind-generic} +\alias{rbind2,spatLocsObj,spatLocsObj-method} \alias{rbind2,giottoPolygon,giottoPolygon-method} \title{Combine objects by rows (Giotto-related)} \usage{ +\S4method{rbind2}{spatLocsObj,spatLocsObj}(x, y, ...) + \S4method{rbind2}{giottoPolygon,giottoPolygon}(x, y, add_list_ID = TRUE, ...) } \arguments{ @@ -12,10 +15,10 @@ \item{y}{item 2 to rbind} +\item{\dots}{additional params to pass to methods} + \item{add_list_ID}{whether to generate a list_ID column when giottoPolygons to append have different names} - -\item{\dots}{additional params to pass to methods} } \value{ object with appended rows diff --git a/man/show-methods.Rd b/man/show.Rd similarity index 53% rename from man/show-methods.Rd rename to man/show.Rd index 22d76430..f32bad5f 100644 --- a/man/show-methods.Rd +++ b/man/show.Rd @@ -1,24 +1,37 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/methods-show.R -\docType{methods} -\name{show,giotto-method} +\name{show} +\alias{show} \alias{show,giotto-method} +\alias{show,packedGiotto-method} \alias{show,exprObj-method} +\alias{show,cellMetaObj-method} +\alias{show,featMetaObj-method} \alias{show,dimObj-method} \alias{show,nnNetObj-method} \alias{show,spatLocsObj-method} \alias{show,spatialNetworkObj-method} \alias{show,spatialGridObj-method} \alias{show,spatEnrObj-method} +\alias{show,giottoPolygon-method} +\alias{show,packedGiottoPolygon-method} +\alias{show,giottoPoints-method} +\alias{show,packedGiottoPoints-method} \alias{show,giottoImage-method} \alias{show,giottoLargeImage-method} \alias{show,affine2d-method} -\title{show method for giotto class} +\title{Show methods for Giotto classes} \usage{ \S4method{show}{giotto}(object) +\S4method{show}{packedGiotto}(object) + \S4method{show}{exprObj}(object) +\S4method{show}{cellMetaObj}(object) + +\S4method{show}{featMetaObj}(object) + \S4method{show}{dimObj}(object) \S4method{show}{nnNetObj}(object) @@ -31,6 +44,14 @@ \S4method{show}{spatEnrObj}(object) +\S4method{show}{giottoPolygon}(object) + +\S4method{show}{packedGiottoPolygon}(object) + +\S4method{show}{giottoPoints}(object) + +\S4method{show}{packedGiottoPoints}(object) + \S4method{show}{giottoImage}(object) \S4method{show}{giottoLargeImage}(object) @@ -38,29 +59,14 @@ \S4method{show}{affine2d}(object) } \arguments{ -\item{object}{giottoLargeImage object} -} -\value{ -giotto object or subobject +\item{object}{object to show} } \description{ -show method for giotto class - -show method for exprObj class - -Show method for dimObj class - -Show method for nnNetObj class - -show method for spatLocsObj class - -show method for spatialNetworkObj class - -show method for spatialGridObj class - -show method for spatEnrObj class - -show method for giottoImage class - -show method for giottoLargeImage class +Show methods for Giotto classes +} +\examples{ +sl <- data.frame(seq(10), seq(10), letters[seq(10)]) |> + createSpatLocsObj(verbose = FALSE) +show(sl) } +\keyword{internal} From 20140ecf138ea700028c6d0de3651ac9f8259c44 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 28 Aug 2024 02:25:20 -0400 Subject: [PATCH 150/160] fix: miniconda installation --- R/python_environment.R | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 196d7a16..cb62590c 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -512,13 +512,17 @@ installGiottoEnvironment <- function( ) { ## 1. check and install miniconda locally if necessary - conda_path <- reticulate::conda_binary(conda = conda) + conda_found <- .check_conda(conda = conda, error = FALSE) # install miniconda if needed - if (!file.exists(conda_path) || isTRUE(force_miniconda)) { + if (isFALSE(conda_found) || isTRUE(force_miniconda)) { vmsg(.v = verbose, .initial = " ", "|---- install local miniconda ----|") + if (identical(conda, "auto")) { + conda_path <- reticulate::miniconda_path() + } + reticulate::install_miniconda( path = conda_path, force = force_miniconda @@ -648,7 +652,7 @@ set_giotto_python_path <- function( "python version :", getOption("giotto.py_active_ver") )) } - + # get path in order of DECREASING priority # # ---------------------------------------- # found <- vector(mode = "numeric") @@ -1045,6 +1049,31 @@ checkPythonPackage <- function(package_name = NULL, # common internals #### + +# determine if a conda binary is accessible by reticulate +# return path to binary if found +# return FALSE if `error` != TRUE ignoring, reticulate's thrown error +# +# param conda - what conda path to use. +# param error - whether to stop execution when conda not found +.check_conda <- function(conda = "auto", error = TRUE) { + res <- try(reticulate::conda_binary(conda = conda), silent = TRUE) + if (inherits(res, "try-error")) res <- FALSE + + if (isFALSE(res) && isTRUE(error)) { + stop(wrap_txt( + "Unable to find a conda binary. + Use `installGiottoEnvironment()` or install a custom conda."), + call. = FALSE + ) + } + return(res) +} + + + + + # construct path to miniconda executable when the python directory is given # python directory should be provided in the same way as # `reticulate::miniconda_path()` where it is one level above the `envs` @@ -1092,9 +1121,12 @@ checkPythonPackage <- function(package_name = NULL, gsub(remove, "", python_path) } +# first function in detection path to check conda envs # if found, return the fullpath # if not, return without modification .envname_to_pypath <- function(envname, must_exist = TRUE) { + .check_conda() + envs <- reticulate::conda_list() enames <- envs$name epaths <- envs$python From a2dacffb2ce6f77666a1e8eb57df6cab53a6f813 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 28 Aug 2024 02:25:27 -0400 Subject: [PATCH 151/160] chore: update news --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 1d0403cf..c22425ec 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,7 +10,7 @@ - `giottoPolygon` `plot()` default `max_poly` raised to `1e6` - `giottoInstructions` no longer lose class when specific params are replaced - `ometif_to_tif()` now checks for _imagecodecs_ package as well -- `anndataToGiotto()` & `giottoToAnndata` now check for _anndata_ package as well. +- `anndataToGiotto()` and `giottoToAnndata` now check for _anndata_ package as well. - fix `joinGiottoObjects()` `"z_stack"` join method - fix error in documentation [#214](https://github.com/drieslab/GiottoClass/issues/214) by shaojunyu - fix error in `installGiottoEnvironment()` [#1006](https://github.com/drieslab/Giotto/issues/1006) by 13954380607 From a084f15d28d3ccba376fbf209b2ff2a1853518ee Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 28 Aug 2024 02:27:15 -0400 Subject: [PATCH 152/160] Update NEWS.md --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index c22425ec..455f9315 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,5 @@ -# GiottoClass 0.3.5 (2024/08/27) +# GiottoClass 0.3.5 (2024/08/28) ## breaking changes - `set_giotto_python_path()` will now also initialize python env to set by default and print which python env is active, but otherwise do nothing if any python env has already been initialized. From e21368d37e69edf7352e4e5a302235a74d03b612 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 28 Aug 2024 10:20:12 -0400 Subject: [PATCH 153/160] fix: py check should not error for conda --- R/python_environment.R | 44 ++++++++++++++++++++++++++++-------------- man/giotto_python.Rd | 34 ++++++++++++++++++-------------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index cb62590c..20cf2648 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -10,13 +10,17 @@ #' #' **Creating an environment** #' -#' `installGiottoEnvironment()` can be used to create a default environment -#' called `giotto_env` that includes some commonly used python packages. See -#' the **python versions** section for specific packages and version numbers. +#' `installGiottoEnvironment()` can be used to create a default miniconda +#' environment called `giotto_env` that includes some commonly used python +#' packages. See the **python versions** section for specific packages and +#' version numbers. #' -#' Custom environments managed through \pkg{reticulate} are also compatible +#' Custom environments manageable through \pkg{reticulate} are also compatible #' and can be hooked into by Giotto after creation. #' +#' `checkGiottoEnvironment()` can be used in order to test if an envname or +#' full python path is accessible by Giotto. It will also check the +#' `"giotto.py_path"` option. #' #' **Choosing environments** #' @@ -26,14 +30,15 @@ #' #' Whenever any of the following happens for the first time in a session: #' -#' - `giotto` object creation +#' - `giotto` object creation (due to creation of a default +#' `giottoInstructions`) #' - `giottoInstructions` creation (`createGiottoInstructions()`) -#' - `GiottoClass::set_giotto_python_path()` is called (most straightforward) +#' - `GiottoClass::set_giotto_python_path()` is called (most direct) #' -#' Giotto automatically detects AND activates a python environment based on the -#' following defaults in decreasing priority: +#' For the above, Giotto automatically detects AND activates a python +#' environment based on the following defaults in decreasing priority: #' -#' 1. User provided (when `python_path` is not `NULL`) +#' 1. User provided (when `python_path` param is not `NULL`) #' 2. Any provided path or envname in option `"giotto.py_path"` #' 3. Default expected giotto environment location based on #' [reticulate::miniconda_path()] @@ -41,9 +46,7 @@ #' 5. System default python environment #' #' This behavior is mediated by the `set_giotto_python_path()` utility -#' function, which will find an environment and then initialize it. You can -#' also call `checkGiottoEnvironment()` in order to detect if there is an -#' environment usable by Giotto without initializing. +#' function, which will find an environment and then initialize it. #' #' #' # python versions @@ -86,8 +89,8 @@ #' #' \preformatted{conda env create -n giotto_env -f ./genv.yml} #' -#' @param envname character. (optional) The name of or path to a miniconda or -#' conda environment directory or python executable. When using +#' @param envname character. (optional) The name of a miniconda or conda +#' environment OR path to a python executable. When using #' `installGiottoEnvironment()`, the default is `"giotto_env"` #' @param conda either "auto" (default) to allow reticulate to handle it, or #' the full filepath to the conda executable. You can also set the option @@ -107,7 +110,7 @@ NULL #' @describeIn giotto_python #' -#' - Based on `envname`, detect if there a conda or miniconda installation +#' - Based on `envname`, detect if there a conda or miniconda environment #' accessible by \pkg{Giotto}. By default, the `envname` `"giotto_env"`, then #' the option `"giotto.py_path"` is checked, but an alternative can be #' provided. @@ -153,6 +156,17 @@ checkGiottoEnvironment <- function( envname <- envname %null% getOption("giotto.py_path") envname <- envname %null% "giotto_env" } + + if (!file.exists(envname) && isFALSE(.check_conda(error = FALSE))) { + # - a conda binary must be detected to use an envname + # - if an envname is not provided, the full path to the python binary + # is needed + vmsg(.v = verbose, "Unable to find a conda binary. + Use `installGiottoEnvironment()` or install a custom conda.") + return(FALSE) + # this is also checked in set_giotto_python_path() within + # .envname_to_pypath(), but that throws an error instead. + } py_path <- set_giotto_python_path( python_path = envname, verbose = FALSE, initialize = FALSE diff --git a/man/giotto_python.Rd b/man/giotto_python.Rd index f2f9b5bc..539326a0 100644 --- a/man/giotto_python.Rd +++ b/man/giotto_python.Rd @@ -37,8 +37,8 @@ removeGiottoEnvironment( set_giotto_python_path(python_path = NULL, verbose = NULL, initialize = TRUE) } \arguments{ -\item{envname}{character. (optional) The name of or path to a miniconda or -conda environment directory or python executable. When using +\item{envname}{character. (optional) The name of a miniconda or conda +environment OR path to a python executable. When using \code{installGiottoEnvironment()}, the default is \code{"giotto_env"}} \item{mini_install_path}{(optional) desired miniconda installation location. @@ -78,13 +78,18 @@ entirely through \pkg{reticulate}. \strong{Creating an environment} -\code{installGiottoEnvironment()} can be used to create a default environment -called \code{giotto_env} that includes some commonly used python packages. See -the \strong{python versions} section for specific packages and version numbers. +\code{installGiottoEnvironment()} can be used to create a default miniconda +environment called \code{giotto_env} that includes some commonly used python +packages. See the \strong{python versions} section for specific packages and +version numbers. -Custom environments managed through \pkg{reticulate} are also compatible +Custom environments manageable through \pkg{reticulate} are also compatible and can be hooked into by Giotto after creation. +\code{checkGiottoEnvironment()} can be used in order to test if an envname or +full python path is accessible by Giotto. It will also check the +\code{"giotto.py_path"} option. + \strong{Choosing environments} Only one python environment may be initialized and used by \pkg{reticulate} @@ -93,15 +98,16 @@ R session must be restarted. Whenever any of the following happens for the first time in a session: \itemize{ -\item \code{giotto} object creation +\item \code{giotto} object creation (due to creation of a default +\code{giottoInstructions}) \item \code{giottoInstructions} creation (\code{createGiottoInstructions()}) -\item \code{GiottoClass::set_giotto_python_path()} is called (most straightforward) +\item \code{GiottoClass::set_giotto_python_path()} is called (most direct) } -Giotto automatically detects AND activates a python environment based on the -following defaults in decreasing priority: +For the above, Giotto automatically detects AND activates a python +environment based on the following defaults in decreasing priority: \enumerate{ -\item User provided (when \code{python_path} is not \code{NULL}) +\item User provided (when \code{python_path} param is not \code{NULL}) \item Any provided path or envname in option \code{"giotto.py_path"} \item Default expected giotto environment location based on \code{\link[reticulate:miniconda_path]{reticulate::miniconda_path()}} @@ -110,14 +116,12 @@ following defaults in decreasing priority: } This behavior is mediated by the \code{set_giotto_python_path()} utility -function, which will find an environment and then initialize it. You can -also call \code{checkGiottoEnvironment()} in order to detect if there is an -environment usable by Giotto without initializing. +function, which will find an environment and then initialize it. } \section{Functions}{ \itemize{ \item \code{checkGiottoEnvironment()}: \itemize{ -\item Based on \code{envname}, detect if there a conda or miniconda installation +\item Based on \code{envname}, detect if there a conda or miniconda environment accessible by \pkg{Giotto}. By default, the \code{envname} \code{"giotto_env"}, then the option \code{"giotto.py_path"} is checked, but an alternative can be provided. From ca8fef6a357021c9c506f5dd16f9bf0914a0ce4a Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 28 Aug 2024 10:39:11 -0400 Subject: [PATCH 154/160] chore: GHA updates --- .github/workflows/covr.yml | 49 ++++++++++++++++++++++++++++++-- .github/workflows/dev_check.yml | 2 +- .github/workflows/main_check.yml | 40 +++++++++++++++++++++++--- 3 files changed, 84 insertions(+), 7 deletions(-) diff --git a/.github/workflows/covr.yml b/.github/workflows/covr.yml index 4d4e9d89..a9af3859 100644 --- a/.github/workflows/covr.yml +++ b/.github/workflows/covr.yml @@ -36,20 +36,65 @@ jobs: dependencies: '"hard"' # do not use suggested dependencies install-pandoc: false extra-packages: | - github::drieslab/GiottoData any::rcmdcheck any::testthat any::rlang any::R.utils + any::knitr + any::rmarkdown + any::qs any::sp any::stars any::raster any::sf + any::scattermore + any::exactextractr any::RTriangle any::geometry - any::covr + any::qs + any::future.apply + any::Biobase + any::chihaya + any::DelayedArray + any::DelayedMatrixStats + any::HDF5Array + any::plotly + any::rgl + any::rhdf5 + any::S4Vectors + any::ScaledMatrix + any::XML + any::Seurat + any::SeuratObject + any::SingleCellExperiment + any::SpatialExperiment + any::STexampleData + any::SummarizedExperiment + github::drieslab/GiottoData needs: coverage + - uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: setup giotto_env + shell: Rscript {0} + run: | + if (!GiottoClass::checkGiottoEnvironment()) { + GiottoClass::installGiottoEnvironment() + } + + reticulate::conda_install( + envname = 'giotto_env', + packages = 'scanpy', + pip = TRUE + ) + + path_to_python <- GiottoClass::set_giotto_python_path() + + writeLines(sprintf("RETICULATE_PYTHON=%s", path_to_python), + Sys.getenv("GITHUB_ENV")) + - name: Generate coverage report run: | covr::codecov( diff --git a/.github/workflows/dev_check.yml b/.github/workflows/dev_check.yml index df79c7a6..8d0f5add 100644 --- a/.github/workflows/dev_check.yml +++ b/.github/workflows/dev_check.yml @@ -87,7 +87,7 @@ jobs: - name: setup giotto_env shell: Rscript {0} run: | - if (!GiottoClass::checkGiottoEnvironment(envname = "giotto_env")) { + if (!GiottoClass::checkGiottoEnvironment()) { GiottoClass::installGiottoEnvironment() } diff --git a/.github/workflows/main_check.yml b/.github/workflows/main_check.yml index ae8ba3d2..21485fec 100644 --- a/.github/workflows/main_check.yml +++ b/.github/workflows/main_check.yml @@ -11,7 +11,7 @@ name: R-CMD-check on: pull_request: - types: closed + types: opened branches: [ "main" ] permissions: @@ -64,9 +64,9 @@ jobs: any::testthat any::rlang any::R.utils - any::remotes any::knitr any::rmarkdown + any::qs any::sp any::stars any::raster @@ -77,14 +77,46 @@ jobs: any::geometry any::qs any::future.apply + any::Biobase + any::chihaya + any::DelayedArray + any::DelayedMatrixStats + any::HDF5Array + any::plotly + any::rgl + any::rhdf5 + any::S4Vectors + any::ScaledMatrix + any::XML + any::Seurat + any::SeuratObject + any::SingleCellExperiment + any::SpatialExperiment + any::STexampleData + any::SummarizedExperiment github::drieslab/GiottoData - - name: Test python env build + - uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: setup giotto_env + shell: Rscript {0} run: | if (!GiottoClass::checkGiottoEnvironment()) { GiottoClass::installGiottoEnvironment() } - shell: Rscript {0} + + reticulate::conda_install( + envname = 'giotto_env', + packages = 'scanpy', + pip = TRUE + ) + + path_to_python <- GiottoClass::set_giotto_python_path() + + writeLines(sprintf("RETICULATE_PYTHON=%s", path_to_python), + Sys.getenv("GITHUB_ENV")) - name: Run R CMD check uses: r-lib/actions/check-r-package@v2 From d0f5d46e45d94fc399ca567c455f10530e43a73a Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 28 Aug 2024 10:42:04 -0400 Subject: [PATCH 155/160] chore: fix covr GHA --- .github/workflows/covr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/covr.yml b/.github/workflows/covr.yml index a9af3859..e29855b8 100644 --- a/.github/workflows/covr.yml +++ b/.github/workflows/covr.yml @@ -4,7 +4,7 @@ name: code coverage on: push: - branches: [ "dev2 " ] + branches: [ "dev2" ] schedule: - cron: '16 20 * * 2' From 27900be442314cd20de7d2b092671b20af9e1565 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 28 Aug 2024 10:51:46 -0400 Subject: [PATCH 156/160] chore: fix covr gha --- .github/workflows/covr.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/covr.yml b/.github/workflows/covr.yml index e29855b8..32223e2e 100644 --- a/.github/workflows/covr.yml +++ b/.github/workflows/covr.yml @@ -36,6 +36,8 @@ jobs: dependencies: '"hard"' # do not use suggested dependencies install-pandoc: false extra-packages: | + github::drieslab/GiottoData + any::covr any::rcmdcheck any::testthat any::rlang @@ -70,7 +72,7 @@ jobs: any::SpatialExperiment any::STexampleData any::SummarizedExperiment - github::drieslab/GiottoData + needs: coverage - uses: actions/setup-python@v5 From 8638293e4ecf7567280367f97a2080bab2263055 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Wed, 28 Aug 2024 11:57:39 -0400 Subject: [PATCH 157/160] chore: gitignore pkgdown --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4524317a..d65339ec 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,5 @@ inst/doc .Rprofile docs codecov.yml - +pkgdown cell_rna* From 01c6605a8a7ec61b2687b5492c966a14e9f29e1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wen=20Wang=20=28=E7=8E=8B=E6=96=87=29?= Date: Wed, 28 Aug 2024 15:59:34 -0400 Subject: [PATCH 158/160] Add: pip_packages param to allow repository selection when install conda env --- R/python_environment.R | 34 +++++++++++++++++---------- man/dot-install_giotto_environment.Rd | 3 ++- man/giotto_python.Rd | 7 +++++- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/R/python_environment.R b/R/python_environment.R index 20cf2648..08585dd7 100644 --- a/R/python_environment.R +++ b/R/python_environment.R @@ -275,6 +275,8 @@ checkGiottoEnvironment <- function( #' @title .install_giotto_environment_specific #' @description installation of giotto environment #' @param packages_to_install python packages to install with giotto env +#' @param pip_packages python packages mush installed with pip, only names +#' are needed #' @param python_version python version to install #' @param mini_install_path directory to install the environment to. #' @param create_dir whether to create the directory specified by @@ -288,8 +290,9 @@ checkGiottoEnvironment <- function( .install_giotto_environment_specific <- function(packages_to_install = c( "pandas", "networkx", "python-igraph", "leidenalg", "python-louvain", "python.app", - "scikit-learn" + "scikit-learn", "smfishhmrf", "session-info" ), + pip_packages = c("python-louvain", "smfishhmrf", "session-info"), python_version = "3.10.2", mini_install_path = NULL, confirm = TRUE, @@ -359,18 +362,15 @@ checkGiottoEnvironment <- function( )] } - # python-louvain must be installed with pip, not with conda-forge + # some python packages must be installed with pip, not with conda-forge # `pip_packages` will be installed with pip # `forge_packages` will be installed with conda-forge - forge_packages <- packages_to_install - py_lou <-"python-louvain" - pip_packages <- c("smfishhmrf", "session-info") - if (py_lou %in% packages_to_install) { - pip_packages <- c(pip_packages, py_lou) - forge_packages <- forge_packages[ - forge_packages != py_lou - ] - } + pip_pkg_indices <- grep(paste0( + "^(", paste(pip_packages, collapse = "|"), + ")" + ), packages_to_install, ignore.case = TRUE) + forge_packages <- packages_to_install[-pip_pkg_indices] + pip_packages <- packages_to_install[pip_pkg_indices] ## create conda env ## ## ---------------- ## @@ -419,8 +419,9 @@ checkGiottoEnvironment <- function( packages_to_install = c( "pandas", "networkx", "python-igraph", "leidenalg", "python-louvain", "python.app", - "scikit-learn" + "scikit-learn", "smfishhmrf", "session-info" ), + pip_packages = c("python-louvain", "smfishhmrf", "session-info"), python_version = "3.10.2", mini_install_path = NULL, confirm = TRUE, @@ -462,6 +463,7 @@ checkGiottoEnvironment <- function( # install giotto environment .install_giotto_environment_specific( packages_to_install = packages_to_install, + pip_packages = pip_packages, python_version = python_version, mini_install_path = mini_install_path, confirm = confirm, @@ -485,6 +487,8 @@ checkGiottoEnvironment <- function( #' environment with a .yml #' - Returns `NULL` #' @param packages_to_install python modules (packages) to install for Giotto. +#' @param pip_packages python packages mush installed with pip, only names +#' are needed #' @param python_version python version to use within the giotto conda #' environment. Default is v3.10.2 #' @param mini_install_path (optional) desired miniconda installation location. @@ -513,8 +517,11 @@ installGiottoEnvironment <- function( "leidenalg==0.9.0", "python-louvain==0.16", "python.app==1.4", - "scikit-learn==1.1.3" + "scikit-learn==1.1.3", + "smfishhmrf", + "session-info" ), + pip_packages = c("python-louvain", "smfishhmrf", "session-info"), python_version = "3.10.2", mini_install_path = NULL, confirm = TRUE, @@ -551,6 +558,7 @@ installGiottoEnvironment <- function( .install_giotto_environment( force_environment = force_environment, packages_to_install = packages_to_install, + pip_packages = pip_packages, python_version = python_version, mini_install_path = mini_install_path, confirm = confirm, diff --git a/man/dot-install_giotto_environment.Rd b/man/dot-install_giotto_environment.Rd index bb39be5e..d11c4ed2 100644 --- a/man/dot-install_giotto_environment.Rd +++ b/man/dot-install_giotto_environment.Rd @@ -7,7 +7,8 @@ .install_giotto_environment( force_environment = FALSE, packages_to_install = c("pandas", "networkx", "python-igraph", "leidenalg", - "python-louvain", "python.app", "scikit-learn"), + "python-louvain", "python.app", "scikit-learn", "smfishhmrf", "session-info"), + pip_packages = c("python-louvain", "smfishhmrf", "session-info"), python_version = "3.10.2", mini_install_path = NULL, confirm = TRUE, diff --git a/man/giotto_python.Rd b/man/giotto_python.Rd index 539326a0..8bba6d79 100644 --- a/man/giotto_python.Rd +++ b/man/giotto_python.Rd @@ -16,7 +16,9 @@ checkGiottoEnvironment( installGiottoEnvironment( packages_to_install = c("pandas==1.5.1", "networkx==2.8.8", "python-igraph==0.10.2", - "leidenalg==0.9.0", "python-louvain==0.16", "python.app==1.4", "scikit-learn==1.1.3"), + "leidenalg==0.9.0", "python-louvain==0.16", "python.app==1.4", "scikit-learn==1.1.3", + "smfishhmrf", "session-info"), + pip_packages = c("python-louvain", "smfishhmrf", "session-info"), python_version = "3.10.2", mini_install_path = NULL, confirm = TRUE, @@ -48,6 +50,9 @@ Default is chosen by \code{reticulate::install_miniconda()}} \item{packages_to_install}{python modules (packages) to install for Giotto.} +\item{pip_packages}{python packages mush installed with pip, only names +are needed} + \item{python_version}{python version to use within the giotto conda environment. Default is v3.10.2} From 56f92a1539fbbe4d8e773ad5ab28298f3be4e033 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 30 Aug 2024 11:17:38 -0400 Subject: [PATCH 159/160] fix: dimnames/colnames generics --- R/join.R | 1 - R/methods-names.R | 28 +++++++++++++++++++++++++++- R/methods-rbind.R | 2 +- man/dimnames.Rd | 12 ++++++++++++ man/row-plus-colnames-generic.Rd | 4 ++++ 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/R/join.R b/R/join.R index 5dcd4674..c6e2a4d3 100644 --- a/R/join.R +++ b/R/join.R @@ -686,7 +686,6 @@ joinGiottoObjects <- function(gobject_list, - ## spatial locations vmsg(.v = verbose, "3. spatial locations") diff --git a/R/methods-names.R b/R/methods-names.R index bbb9d7af..0cb6a215 100644 --- a/R/methods-names.R +++ b/R/methods-names.R @@ -1,12 +1,17 @@ #' @include generics.R NULL +# NOTE: +# dimnames MUST be provided for rownames and colnames methods to be well +# behaved + #' @title Row and column names #' @name row-plus-colnames-generic #' @aliases colnames rownames #' @description Retrieve or set the row or column names of an object #' @param x object #' @return A character vector of row or col names +#' @keywords internal #' @examples #' g <- GiottoData::loadSubObjectMini("exprObj") #' @@ -19,6 +24,7 @@ NULL #' Retrieve or set the dimnames of an object #' @param x object #' @returns character +#' @keywords internal #' @examples #' g <- GiottoData::loadSubObjectMini("exprObj") #' @@ -60,7 +66,9 @@ setMethod("rownames", signature(x = "exprObj"), function(x) rownames(x[])) #' @export setMethod("rownames", signature(x = "dimObj"), function(x) rownames(x[])) - +#' @rdname row-plus-colnames-generic +#' @export +setMethod("rownames", signature(x = "metaData"), function(x) rownames(x[])) @@ -71,3 +79,21 @@ setMethod("dimnames", signature(x = "exprObj"), function(x) dimnames(x[])) #' @rdname dimnames #' @export setMethod("dimnames", signature(x = "dimObj"), function(x) dimnames(x[])) + +#' @rdname dimnames +#' @export +setMethod("dimnames", signature(x = "spatLocsObj"), function(x) dimnames(x[])) + +#' @rdname dimnames +#' @export +setMethod("dimnames", signature(x = "metaData"), function(x) dimnames(x[])) + +#' @rdname dimnames +#' @export +setMethod("dimnames", signature(x = "enrData"), function(x) dimnames(x[])) + +#' @rdname dimnames +#' @export +setMethod("dimnames", signature(x = "dimObj"), function(x) dimnames(x[])) + + diff --git a/R/methods-rbind.R b/R/methods-rbind.R index a3b2c71f..dcd08031 100644 --- a/R/methods-rbind.R +++ b/R/methods-rbind.R @@ -33,7 +33,7 @@ setMethod( stop("rbind: `spatLocsObj` with the same IDs cannot be joined", call. = FALSE) } - + # if one is 3d, ensure both are 3d x3 <- .is_3d_spatlocs(x) y3 <- .is_3d_spatlocs(y) diff --git a/man/dimnames.Rd b/man/dimnames.Rd index 0be71b51..dcad2fc1 100644 --- a/man/dimnames.Rd +++ b/man/dimnames.Rd @@ -4,10 +4,21 @@ \alias{dimnames} \alias{dimnames,exprObj-method} \alias{dimnames,dimObj-method} +\alias{dimnames,spatLocsObj-method} +\alias{dimnames,metaData-method} +\alias{dimnames,enrData-method} \title{Dimnames of an object} \usage{ \S4method{dimnames}{exprObj}(x) +\S4method{dimnames}{dimObj}(x) + +\S4method{dimnames}{spatLocsObj}(x) + +\S4method{dimnames}{metaData}(x) + +\S4method{dimnames}{enrData}(x) + \S4method{dimnames}{dimObj}(x) } \arguments{ @@ -24,3 +35,4 @@ g <- GiottoData::loadSubObjectMini("exprObj") dimnames(g) } +\keyword{internal} diff --git a/man/row-plus-colnames-generic.Rd b/man/row-plus-colnames-generic.Rd index ba9cf466..6bbd5a91 100644 --- a/man/row-plus-colnames-generic.Rd +++ b/man/row-plus-colnames-generic.Rd @@ -12,6 +12,7 @@ \alias{colnames,dimObj-method} \alias{rownames,exprObj-method} \alias{rownames,dimObj-method} +\alias{rownames,metaData-method} \title{Row and column names} \usage{ \S4method{colnames}{exprObj}(x) @@ -29,6 +30,8 @@ \S4method{rownames}{exprObj}(x) \S4method{rownames}{dimObj}(x) + +\S4method{rownames}{metaData}(x) } \arguments{ \item{x}{object} @@ -44,3 +47,4 @@ g <- GiottoData::loadSubObjectMini("exprObj") colnames(g) } +\keyword{internal} From 1e5d90e1256a465787df38fc8248d2f741c15952 Mon Sep 17 00:00:00 2001 From: George Chen <72078254+jiajic@users.noreply.github.com> Date: Fri, 30 Aug 2024 11:17:47 -0400 Subject: [PATCH 160/160] chore: update news --- NEWS.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/NEWS.md b/NEWS.md index 455f9315..abd10a28 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,12 @@ +# GiottoClass 0.3.6 (2024/08/30) + +## bug fixes +- fix `dimnames()` for some subobjects + +## enhancements +- python packages to install through pip is now settable in `installGiottoEnvironment()` + # GiottoClass 0.3.5 (2024/08/28) ## breaking changes