satijalab / seurat

R toolkit for single cell genomics
http://www.satijalab.org/seurat
Other
2.3k stars 917 forks source link

`DimPlot` convenience functions infer arguments from the call stack #9436

Open rharao opened 2 weeks ago

rharao commented 2 weeks ago

The convenience functions for DimPlot through SpecificDimPlot (namely, PCAPlot, TSNEPlot, and UMAPPlot) rely on false assumptions.

Example: Try running Seurat::UMAPPlot (specifying the namespace rather than just getting UMAPPlot from the search list) on a Seurat object that has a "umap" reduction. One should expect the function to access this with .[["umap"]].

Error in object[[reduction]] : 
  'seurat::umap' not found in this Seurat object

It's trying to find .[["seurat::umap"]] because, instead of UMAPPlot just calling DimPlot with reduction = "umap", SpecificDimPlot is doing string manipulations on the call stack to guess which particular convenience function was called.

Existing code for UMAPPlot, TSNEPlot, and PCAPlot are identical down to the bytecode: they pass their object and dots arguments, unmodified, to the non-exported SpecificDimPlot, and return the result, unmodified. There is no logic on either side and they are bare aliases for the unexposed function; their only purpose is to show up on the call stack.

SpecificDimPlot as it is (comments mine):

function (object, ...) 
{
    funs <- sys.calls()
    # Get the name of the preceding function on the call stack as a string
    name <- as.character(x = funs[[length(x = funs) - 1]])[1]
    # Remove the substring "Plot", if it's there, and convert to lowercase
    # This string is the guessed reduction name for now
    name <- tolower(x = gsub(pattern = "Plot", replacement = "", 
        x = name))
    # Put the input args in a list
    args <- list(object = object)
    args <- c(args, list(...))
    # Tentative better guess (this is undocumented):
    # Search in the names of the object for any string that has _both_
    # the guessed reduction name (case insensitive) _and_
    # the object's default assay name (case sensitive) as substrings
    reduc <- grep(pattern = name, x = names(x = object), value = TRUE, 
        ignore.case = TRUE)
    reduc <- grep(pattern = DefaultAssay(object = object), x = reduc, 
        value = TRUE)
    # If zero or multiple of those strings were found, just use the first guess
    # Update the args list with the guess
    args$reduction <- ifelse(test = length(x = reduc) == 1, yes = reduc, 
        no = name)
    # Now pass the whole thing on to `DimPlot` and hope the guess was right
    tryCatch(expr = return(do.call(what = "DimPlot", args = args)), 
        error = function(e) {
            stop(e)
        })
}

Some situations in which this can mislead or stop the user:

Here is my general idea for how this could be replaced:

# Not exported
SpecificDimPlot <- function(object, ..., .reduction) {
  dots <- list(...)
  if ("reduction" %in% names(dots) && dots$reduction != .reduction) {
    warning(
    "SpecificDimPlot: Ignoring supplied `reduction` argument in favor of '",
    .reduction,
    "'. Use DimPlot to choose any reduction.")
  }
  dots$reduction <- NULL
  reductions <- Reductions(object = object)
  if (! .reduction %in% reductions) {
    reductions <- grep(
      pattern = .reduction,
      x = reductions,
      ignore.case = TRUE,
      value = TRUE)
    if (length(reductions) > 0) {
      # If the requested reduction is not available but others pass grep,
      # use the first one with a warning
      warning(
        "SpecificDimPlot: '",
        .reduction,
        "' not found in this object's reductions. Using '",
        .reduction <- reductions[1],
        "' instead. Use DimPlot to choose any reduction.")
    } else {
      stop(
        "Could not find '",
        .reduction,
        "' in this object's reductions. Use DimPlot to choose any reduction.")
    }
  }
  args <- c(list(object = object, reduction = .reduction), dots)
  tryCatch(
    expr = return(do.call(what = "DimPlot", args = args)),
    error = \(e) stop(e)
  )
}

# Exported
PCAPlot <- \(object, ...) {
  return(SpecificDimPlot(object = object, ..., .reduction = "pca"))
}
TSNEPlot <- \(object, ...) {
  return(SpecificDimPlot(object = object, ..., .reduction = "tsne" ))
}
UMAPPlot <- \(object, ...) {
  return(SpecificDimPlot(object = object, ..., .reduction = "umap"))
}

Would the maintainers be open to a PR regarding this?

Session info ``` - Session info ---------------------------------------------------------------- setting value version R version 4.2.2 Patched (2022-11-10 r83330) os Debian GNU/Linux 12 (bookworm) system x86_64, linux-gnu ui RStudio language (EN) collate en_US.UTF-8 ctype en_US.UTF-8 tz US/Eastern date 2024-10-25 rstudio 2023.12.1+402 Ocean Storm (server) pandoc 3.1.1 @ /usr/lib/rstudio-server/bin/quarto/bin/tools/ (via rmarkdown) - Packages -------------------------------------------------------------------- package * version date (UTC) lib source abind 1.4-5 2016-07-21 [1] CRAN (R 4.2.2) AnnotationDbi 1.60.2 2023-03-10 [1] Bioconductor AnnotationFilter 1.22.0 2022-11-01 [1] Bioconductor beachmat 2.14.2 2023-04-07 [1] Bioconductor beeswarm 0.4.0 2021-06-01 [1] CRAN (R 4.2.2) Biobase 2.58.0 2022-11-01 [1] Bioconductor BiocFileCache 2.6.1 2023-02-17 [1] Bioconductor BiocGenerics 0.44.0 2022-11-01 [1] Bioconductor BiocIO 1.8.0 2022-11-01 [1] Bioconductor BiocNeighbors 1.16.0 2022-11-01 [1] Bioconductor BiocParallel 1.32.6 2023-03-17 [1] Bioconductor BiocSingular 1.14.0 2022-11-01 [1] Bioconductor biomaRt 2.54.1 2023-03-20 [1] Bioconductor Biostrings 2.66.0 2022-11-01 [1] Bioconductor bit 4.0.5 2022-11-15 [1] CRAN (R 4.2.2) bit64 4.0.5 2020-08-30 [1] CRAN (R 4.2.2) bitops 1.0-8 2024-07-29 [1] CRAN (R 4.2.2) blob 1.2.4 2023-03-17 [1] CRAN (R 4.2.2) bluster 1.8.0 2022-11-01 [1] Bioconductor cachem 1.1.0 2024-05-16 [1] CRAN (R 4.2.2) cli 3.6.3 2024-06-21 [1] CRAN (R 4.2.2) clipr 0.8.0 2022-02-22 [1] CRAN (R 4.2.2) cluster 2.1.4 2022-08-22 [4] CRAN (R 4.2.1) codetools 0.2-19 2023-02-01 [4] CRAN (R 4.2.2) colorspace 2.1-1 2024-07-26 [1] CRAN (R 4.2.2) cowplot 1.1.3 2024-01-22 [1] CRAN (R 4.2.2) crayon 1.5.3 2024-06-20 [1] CRAN (R 4.2.2) curl 5.2.2 2024-08-26 [1] CRAN (R 4.2.2) data.table 1.16.0 2024-08-27 [1] CRAN (R 4.2.2) DBI 1.2.3 2024-06-02 [1] CRAN (R 4.2.2) dbplyr 2.5.0 2024-03-19 [1] CRAN (R 4.2.2) DelayedArray 0.24.0 2022-11-01 [1] Bioconductor DelayedMatrixStats 1.20.0 2022-11-01 [1] Bioconductor deldir 2.0-4 2024-02-28 [1] CRAN (R 4.2.2) digest 0.6.37 2024-08-19 [1] CRAN (R 4.2.2) dotCall64 1.1-1 2023-11-28 [1] CRAN (R 4.2.2) dplyr 1.1.4 2023-11-17 [1] CRAN (R 4.2.2) dqrng 0.4.1 2024-05-28 [1] CRAN (R 4.2.2) edgeR 3.40.2 2023-01-19 [1] Bioconductor ensembldb 2.22.0 2022-11-01 [1] Bioconductor evaluate 0.24.0 2024-06-10 [1] CRAN (R 4.2.2) fansi 1.0.6 2023-12-08 [1] CRAN (R 4.2.2) farver 2.1.2 2024-05-13 [1] CRAN (R 4.2.2) fastDummies 1.7.4 2024-08-16 [1] CRAN (R 4.2.2) fastmap 1.2.0 2024-05-15 [1] CRAN (R 4.2.2) filelock 1.0.3 2023-12-11 [1] CRAN (R 4.2.2) fitdistrplus 1.2-1 2024-07-12 [1] CRAN (R 4.2.2) future 1.34.0 2024-07-29 [1] CRAN (R 4.2.2) future.apply 1.11.2 2024-03-28 [1] CRAN (R 4.2.2) generics 0.1.3 2022-07-05 [1] CRAN (R 4.2.2) GenomeInfoDb 1.34.9 2023-02-02 [1] Bioconductor GenomeInfoDbData 1.2.9 2024-04-01 [1] Bioconductor GenomicAlignments 1.34.1 2023-03-09 [1] Bioconductor GenomicFeatures 1.50.4 2023-01-24 [1] Bioconductor GenomicRanges 1.50.2 2022-12-16 [1] Bioconductor ggbeeswarm 0.7.2 2023-04-29 [1] CRAN (R 4.2.2) ggplot2 3.5.1 2024-04-23 [1] CRAN (R 4.2.2) ggrastr 1.0.2 2023-06-01 [1] CRAN (R 4.2.2) ggrepel 0.9.5 2024-01-10 [1] CRAN (R 4.2.2) ggridges 0.5.6 2024-01-23 [1] CRAN (R 4.2.2) globals 0.16.3 2024-03-08 [1] CRAN (R 4.2.2) glue 1.7.0 2024-01-09 [1] CRAN (R 4.2.2) goftest 1.2-3 2021-10-07 [1] CRAN (R 4.2.2) gridExtra 2.3 2017-09-09 [1] CRAN (R 4.2.2) gtable 0.3.5 2024-04-22 [1] CRAN (R 4.2.2) hms 1.1.3 2023-03-21 [1] CRAN (R 4.2.2) htmltools 0.5.8.1 2024-04-04 [1] CRAN (R 4.2.2) htmlwidgets 1.6.4 2023-12-06 [1] CRAN (R 4.2.2) httpuv 1.6.15 2024-03-26 [1] CRAN (R 4.2.2) httr 1.4.7 2023-08-15 [1] CRAN (R 4.2.2) ica 1.0-3 2022-07-08 [1] CRAN (R 4.2.2) igraph 2.0.3 2024-03-13 [1] CRAN (R 4.2.2) IRanges 2.32.0 2022-11-01 [1] Bioconductor irlba 2.3.5.1 2022-10-03 [1] CRAN (R 4.2.2) jsonlite 1.8.8 2023-12-04 [1] CRAN (R 4.2.2) KEGGREST 1.38.0 2022-11-01 [1] Bioconductor KernSmooth 2.23-20 2021-05-03 [4] CRAN (R 4.0.4) knitr 1.48 2024-07-07 [1] CRAN (R 4.2.2) labeling 0.4.3 2023-08-29 [1] CRAN (R 4.2.2) later 1.3.2 2023-12-06 [1] CRAN (R 4.2.2) lattice 0.20-45 2021-09-22 [4] CRAN (R 4.2.0) lazyeval 0.2.2 2019-03-15 [1] CRAN (R 4.2.2) leiden 0.4.3.1 2023-11-17 [1] CRAN (R 4.2.2) lifecycle 1.0.4 2023-11-07 [1] CRAN (R 4.2.2) limma 3.54.2 2023-02-28 [1] Bioconductor listenv 0.9.1 2024-01-29 [1] CRAN (R 4.2.2) lmtest 0.9-40 2022-03-21 [1] CRAN (R 4.2.2) locfit 1.5-9.10 2024-06-24 [1] CRAN (R 4.2.2) magrittr 2.0.3 2022-03-30 [1] CRAN (R 4.2.2) MASS 7.3-58.2 2023-01-23 [4] CRAN (R 4.2.2) Matrix 1.6-5 2024-01-11 [1] CRAN (R 4.2.2) MatrixGenerics 1.10.0 2022-11-01 [1] Bioconductor matrixStats 1.1.0 2023-11-07 [1] CRAN (R 4.2.2) memoise 2.0.1 2021-11-26 [1] CRAN (R 4.2.2) metapod 1.6.0 2022-11-01 [1] Bioconductor mime 0.12 2021-09-28 [1] CRAN (R 4.2.2) miniUI 0.1.1.1 2018-05-18 [1] CRAN (R 4.2.2) munsell 0.5.1 2024-04-01 [1] CRAN (R 4.2.2) nlme 3.1-162 2023-01-31 [4] CRAN (R 4.2.2) parallelly 1.38.0 2024-07-27 [1] CRAN (R 4.2.2) patchwork 1.2.0 2024-01-08 [1] CRAN (R 4.2.2) pbapply 1.7-2 2023-06-27 [1] CRAN (R 4.2.2) pillar 1.9.0 2023-03-22 [1] CRAN (R 4.2.2) pkgconfig 2.0.3 2019-09-22 [1] CRAN (R 4.2.2) pkgload 1.4.0 2024-06-28 [1] CRAN (R 4.2.2) plotly 4.10.4 2024-01-13 [1] CRAN (R 4.2.2) plyr 1.8.9 2023-10-02 [1] CRAN (R 4.2.2) png 0.1-8 2022-11-29 [1] CRAN (R 4.2.2) polyclip 1.10-7 2024-07-23 [1] CRAN (R 4.2.2) prettyunits 1.2.0 2023-09-24 [1] CRAN (R 4.2.2) progress 1.2.3 2023-12-06 [1] CRAN (R 4.2.2) progressr 0.14.0 2023-08-10 [1] CRAN (R 4.2.2) promises 1.3.0 2024-04-05 [1] CRAN (R 4.2.2) ProtGenerics 1.30.0 2022-11-01 [1] Bioconductor purrr 1.0.2 2023-08-10 [1] CRAN (R 4.2.2) R6 2.5.1 2021-08-19 [1] CRAN (R 4.2.2) RANN 2.6.2 2024-08-25 [1] CRAN (R 4.2.2) rappdirs 0.3.3 2021-01-31 [1] CRAN (R 4.2.2) RColorBrewer 1.1-3 2022-04-03 [1] CRAN (R 4.2.2) Rcpp 1.0.13 2024-07-17 [1] CRAN (R 4.2.2) RcppAnnoy 0.0.22 2024-01-23 [1] CRAN (R 4.2.2) RcppHNSW 0.6.0 2024-02-04 [1] CRAN (R 4.2.2) RCurl 1.98-1.16 2024-07-11 [1] CRAN (R 4.2.2) reshape2 1.4.4 2020-04-09 [1] CRAN (R 4.2.2) restfulr 0.0.15 2022-06-16 [1] CRAN (R 4.2.2) reticulate 1.38.0 2024-06-19 [1] CRAN (R 4.2.2) rjson 0.2.21 2022-01-09 [1] CRAN (R 4.2.2) rlang 1.1.4 2024-06-04 [1] CRAN (R 4.2.2) rmarkdown 2.28 2024-08-17 [1] CRAN (R 4.2.2) ROCR 1.0-11 2020-05-02 [1] CRAN (R 4.2.2) Rsamtools 2.14.0 2022-11-01 [1] Bioconductor RSpectra 0.16-2 2024-07-18 [1] CRAN (R 4.2.2) RSQLite 2.3.7 2024-05-27 [1] CRAN (R 4.2.2) rstudioapi 0.16.0 2024-03-24 [1] CRAN (R 4.2.2) rsvd 1.0.5 2021-04-16 [1] CRAN (R 4.2.2) rtracklayer 1.58.0 2022-11-01 [1] Bioconductor Rtsne 0.17 2023-12-07 [1] CRAN (R 4.2.2) S4Vectors 0.36.2 2023-02-26 [1] Bioconductor ScaledMatrix 1.6.0 2022-11-01 [1] Bioconductor scales 1.3.0 2023-11-28 [1] CRAN (R 4.2.2) scater 1.26.1 2022-11-13 [1] Bioconductor scattermore 1.2 2023-06-12 [1] CRAN (R 4.2.2) scran 1.26.2 2023-01-19 [1] Bioconductor sctransform 0.4.1 2023-10-19 [1] CRAN (R 4.2.2) scuttle 1.8.4 2023-01-19 [1] Bioconductor sessioninfo 1.2.2 2021-12-06 [1] CRAN (R 4.2.2) Seurat 5.1.0 2024-05-10 [1] CRAN (R 4.2.2) SeuratObject * 5.0.2 2024-05-08 [1] CRAN (R 4.2.2) shiny 1.9.1 2024-08-01 [1] CRAN (R 4.2.2) SingleCellExperiment 1.20.1 2023-03-17 [1] Bioconductor sp * 2.1-4 2024-04-30 [1] CRAN (R 4.2.2) spam 2.10-0 2023-10-23 [1] CRAN (R 4.2.2) sparseMatrixStats 1.10.0 2022-11-01 [1] Bioconductor spatstat.data 3.1-2 2024-06-21 [1] CRAN (R 4.2.2) spatstat.explore 3.3-2 2024-08-21 [1] CRAN (R 4.2.2) spatstat.geom 3.3-2 2024-07-15 [1] CRAN (R 4.2.2) spatstat.random 3.3-1 2024-07-15 [1] CRAN (R 4.2.2) spatstat.sparse 3.1-0 2024-06-21 [1] CRAN (R 4.2.2) spatstat.univar 3.0-0 2024-06-28 [1] CRAN (R 4.2.2) spatstat.utils 3.1-0 2024-08-17 [1] CRAN (R 4.2.2) statmod 1.5.0 2023-01-06 [1] CRAN (R 4.2.2) stringi 1.8.4 2024-05-06 [1] CRAN (R 4.2.2) stringr 1.5.1 2023-11-14 [1] CRAN (R 4.2.2) SummarizedExperiment 1.28.0 2022-11-01 [1] Bioconductor survival 3.5-3 2023-02-12 [4] CRAN (R 4.2.2) tensor 1.5 2012-05-05 [1] CRAN (R 4.2.2) tibble 3.2.1 2023-03-20 [1] CRAN (R 4.2.2) tidyr 1.3.1 2024-01-24 [1] CRAN (R 4.2.2) tidyselect 1.2.1 2024-03-11 [1] CRAN (R 4.2.2) utf8 1.2.4 2023-10-22 [1] CRAN (R 4.2.2) uwot 0.2.2 2024-04-21 [1] CRAN (R 4.2.2) vctrs 0.6.5 2023-12-01 [1] CRAN (R 4.2.2) vipor 0.4.7 2023-12-18 [1] CRAN (R 4.2.2) viridis 0.6.5 2024-01-29 [1] CRAN (R 4.2.2) viridisLite 0.4.2 2023-05-02 [1] CRAN (R 4.2.2) withr 3.0.1 2024-07-31 [1] CRAN (R 4.2.2) xfun 0.47 2024-08-17 [1] CRAN (R 4.2.2) XML 3.99-0.17 2024-06-25 [1] CRAN (R 4.2.2) xml2 1.3.6 2023-12-04 [1] CRAN (R 4.2.2) xtable 1.8-4 2019-04-21 [1] CRAN (R 4.2.2) XVector 0.38.0 2022-11-01 [1] Bioconductor yaml 2.3.10 2024-07-26 [1] CRAN (R 4.2.2) zlibbioc 1.44.0 2022-11-01 [1] Bioconductor zoo 1.8-12 2023-04-13 [1] CRAN (R 4.2.2) [1] /home/rao/R/x86_64-pc-linux-gnu-library/4.2 [2] /usr/local/lib/R/site-library [3] /usr/lib/R/site-library [4] /usr/lib/R/library ------------------------------------------------------------------------------- ```
rharao commented 2 days ago

@samuel-marsh Please excuse the tag; as somebody who is more familiar with the codebase, would you recommend that I continue waiting for a response on this issue, or just go ahead and start on the PR? I'm hesitant because there are, perhaps, other ways to solve the problem, and because the CI pipeline seems to be broken at the moment.

samuel-marsh commented 1 day ago

Hi @rharao,

I would go ahead and submit PR with idea and just add in the comments referencing this issue and being open to different fix if dev team has different ideas. I don't actually really use the convenience functions much anymore and instead just rely on DimPlot. In fact I'm not sure of the specific dev reason why those functions don't just call DimPlot with the reduction specified.

I have kind of related issue on plotting side which I posed in SeuratObject repo while back about whether the devs would be open to PR implementing a DefaultDimReduc<- function to allow users to specify default dimreduc (can be helpful if users has multiple umaps/tsnes etc run if different ways but all within the same assay) (https://github.com/satijalab/seurat-object/issues/203) but haven't had response but also haven't had bandwidth to do PR.

So I'd say if you have bandwidth put PR in and see what devs say.

Best, Sam