diff --git a/API.md b/API.md new file mode 100644 index 00000000..dd843774 --- /dev/null +++ b/API.md @@ -0,0 +1,502 @@ +# GET: /SessionInfo +Returns high-level configuration info on this VISION session. Mostly used +to enable/disable features in the visualizer. + +- 'name': A title for this session (shown in the top title bar) +- 'meta\_sigs': Names of meta-data signatures. Sent here as a convenience as +numeric meta-data signatures and gene signatures get combined in the display +and often lookups are needed to distinguish. +- 'ncells': Total number of cells +- 'pooled': Whether or not there is micro-pooling +- 'has\_sigs': Whether or not there are gene signatures +- 'has\_proteins': Whether or not there are CITE-seq proteins +- 'has\_lca': Whether or not LC Annotator analysis is available +- 'has\_tree': Whether or not Trajectories are available + +Response structure: +``` + { + 'name': 'Session Name', + 'meta_sigs': [list of string], + 'ncells': int, + 'pooled': bool, + 'has_sigs': bool, + 'has_proteins': bool, + 'has_lca': bool, + 'has_tree': bool, + } +``` + +# GET: /Signature/Scores/ +Return the per-cell signature scores for signature: `` +Data comes from obj@SigScores matrix + +Response structure: + +``` + { + 'cells': [list of str, cell ids...], + 'values': [list of Number, per cell signature scores], + } +``` + +# GET: /Signature/Meta/ +Return the per-cell meta-data values for variable: `` +Data comes from obj@metaData dataframe + +Response structure: + +``` + { + 'cells': [list of str, cell ids...], + 'values': [list of Number or string, per-cell meta-data values], + } +``` + +# GET: /Signature/Info/ +Returns information associated with a signature +Data comes from object@sigData + +Response structure: + +``` + { + 'sigDict': { # signature-gene weights + 'GeneName1': 1, + 'GeneName2': -1, + ... + }, + 'name': 'Signature Name', + 'source': 'Signature source', # typically filename where signature was loaded from + 'metaData': 'Signature description...', # second column in .gmt file + 'geneImportance': { # signature-gene importance values + 'GeneName1': .1, + 'GeneName2': .01, + ... + } + } +``` + +# GET: /Signature/Expression// +Returns expression values for `` grouped by ``. +This is used to generate the gene x cluster heatmap in the bottom left +Values are computed on the fly at the server + +Response structure +``` +{ + 'data': list of list of Number (2d matrix, outer index is row index) + 'sample_labels': column labels for the matrix in 'data' + 'gene_labels': row labels for the matrix in 'data' +} +``` + +# GET: /Proteins/\/Values +Returns the per-cell protein expression values for `` +Data comes from obj@proteinData matrix + +Response structure: +``` + { + 'cells': [list of str, cell ids...], + 'values': [list of Number, per cell protein expression], + } +``` + +# GET: /FilterGroup/SigClusters/Normal +For each signature, describes the assignment of signatures to signature-clusters +This is used to group signatures in the upper-left section + +Response structure: +``` +{ + "Signature Name" (str): (int), + ... +} +``` + +# GET: /FilterGroup/SigClusters/Proteins +For each protein, describes the assignment of proteins to protein-clusters +Proteins aren't actually clustered in the interface. Every protein is assigned to cluster #1 + +Response structure: +``` +{ + "Protein Name" (str): 1, + ... +} +``` + +# GET: /FilterGroup/SigClusters/Meta +For each meta-data variable, describes the assignment of each variable to meta-data clusters +This is used when micropools are created to group factor variables with their expanded +percent-value-per-micropool representations + +Response structure: +``` +{ + "Metadata variable Name" (str): (int), + ... +} +``` + +# GET: /Projections//coordinates/ +Returns the coordinates for projection `` in column `` +Since the scatter plot can show more than just projects, this has been expanded to also +return coordinates from the latent space or other meta-data variables. `` can +come from names in object@Projections, or can be "Meta Data" to refer to object@metaData or +"Latent Space" to refer to object@LatentSpace. In either case `` should refer +to an associated column. + +Response structure: + +List of list of `[coordinate, 'cell id']` + +``` +[ + [coordinate (float): 'cell id' (str)], + [coordinate (float): 'cell id' (str)], + [coordinate (float): 'cell id' (str)], + ... +[ +``` + +# GET: /Projections/list +Returns information on projections and other variables that can be plotted in the main +scatter-plot panel. Used to create the dropdown menus. + +Response structure: + +Dictionary where keys are the name of projections/meta data/latent space and the values are +a list of the associated columns + +``` +{ + 'projection_name_1': list of column names in the projection, + 'projection_name_2': list of column names in the projection, + 'Meta Data': list of numeric meta-data variables, + 'Latent Space': list of column names in the latent space +} +``` + +# GET: /PearsonCorr/Normal +Gets information for the LC Annotator - the correlation of each signature with each latent component + +Response structure: +``` +{ + "zscores": list of list of correlation coefficients (N signatures x N components), + "pvals": list of list of p-values (N signatures x N components), + "proj_labels": list of latent space column names in the same order as columns of 'zscores'/'pvals', + "sig_labels": list of signature names in the same order as columns of 'zscores'/'pvals', +} +``` + +# GET: /PearsonCorr/Proteins +Gets information for the LC Annotator - the correlation of each protein with each latent component + +Response structure: +``` +{ + "zscores": list of list of correlation coefficients (N proteins x N components), + "pvals": list of list of p-values (N proteins x N components), + "proj_labels": list of latent space column names in the same order as columns of 'zscores'/'pvals', + "sig_labels": list of proteins names in the same order as columns of 'zscores'/'pvals', +} +``` + +# GET: /PearsonCorr/Meta +Gets information for the LC Annotator - the correlation of each numeric meta-data variable with each latent component + +Response structure: +``` +{ + "zscores": list of list of correlation coefficients (N variables x N components), + "pvals": list of list of p-values (N variables x N components), + "proj_labels": list of latent space column names in the same order as columns of 'zscores'/'pvals', + "sig_labels": list of variables names in the same order as columns of 'zscores'/'pvals', +} +``` + +# POST: /DE +Requests a differential expression analysis from the server. + +Determines the set of cells used for the numerator (i.e. _num or _n) and for the denominator (i.e. _denom or _d) + +Examples: +- To select cells in cluster 5 for the numerator set `'type_n': 'meta'`, `'subtype_n': 'cluster'`, `'group_num': 'Cluster 5'` +- To select cells in a saved manual selection for the numerator set `'type_n': 'saved_selection'`, `'group_num': 'name_of_selection'` +- To select a specific set of cell ids for the numerator set `'type_n': 'current'`, `'group_num': list of cell ids` + +Posted data structure: +``` +{ + 'type_n': either 'current', 'meta', or 'saved_selection' + 'type_d': either 'remainder', 'meta', or 'saved_selection' + 'subtype_n': which meta-data variable to group cells by if type_n is 'meta' + 'subtype_d': which meta-data variable to group cells by if type_d is 'meta' + 'group_num': list of cell ids (if type_n is 'current') OR name of saved selection (if type_n is 'saved_selection') + OR value of categorical meta-data variable (if type_n is 'meta') + 'group_denom': same behavior as 'group_num' + 'min_cells': (int) pre-filter genes expressed in less than this many cells + 'subsample_groups': (bool), whether or not to subsample each comparison group first + 'subsample_N': (int) size of the groups after subsampling. Ignored if 'subsample_groups' is false +} +``` + +Response structure: + +DE Results table with {'column name' -> list of values} + +``` +{ + 'Feature': list of feature (gene or protein) names + 'Type': list of either 'Gene' or 'Protein' + 'logFC': list of log-fold-change values + 'stat': list of AUC values + 'pval': list of FDR-corrected p-values +} +``` + + +# GET: /Clusters/MetaLevels +The display of the top-left area for signatures/proteins/meta-data depends on the selected +grouping variable in the dropdown. Commands scoped to a particular grouping variable are +nested under "/Clusters". + +This call returns a list of grouping variables and the levels/categories associated with them. + +Response structure: +``` + { + 'name of variable': [list of str - values this variable can take], + 'name of variable': [list of str - values this variable can take], + 'Cell Type': ['CD4+', 'CD8+', 'NK'], # For example + } +``` + +# GET: /Clusters//SigProjMatrix/Normal +Returns matrices consisting of test statistic and p-value for 1 vs. all differential signature +tests and for local autocorrelation. + +First column is "Score" and values are for local autocorrelation. Statistic is the 1 - Geary's C. + +Other columns are for 1 vs. all differential signature tests for each value in the selected grouping +variable in the dropdown. Test statistic are the AUC values from a ranksums test. P-values also +from this test. + +Response structure: +``` + { + 'sig_labels': [list of str] # Rows of matrices in zscores and pvals + 'proj_labels': [list of str] # Columns of the matrices in zscores and pvals + 'zscores': [list of list of number] # signatures x cell group (+ 'Score') matrix of test statistics + 'pvals': [list of list of number] # signatures x cell group (+ 'Score') matrix of p-values + } +``` + +# GET: /Clusters//SigProjMatrix/Meta +Same as `/Clusters//SigProjMatrix/Normal`, but for meta-data variables + +Response structure: +``` + { + 'sig_labels': [list of str] # Rows of matrices in zscores and pvals + 'proj_labels': [list of str] # Columns of the matrices in zscores and pvals + 'zscores': [list of list of number] # variables x cell group (+ 'Score') matrix of test statistics + 'pvals': [list of list of number] # variables x cell group (+ 'Score') matrix of p-values + } +``` +# GET: /Clusters//ProteinMatrix +Same as `/Clusters//SigProjMatrix/Normal`, but for CITE proteins + +Response structure: +``` + { + 'sig_labels': [list of str] # Rows of matrices in zscores and pvals + 'proj_labels': [list of str] # Columns of the matrices in zscores and pvals + 'zscores': [list of list of number] # proteins x cell group (+ 'Score') matrix of test statistics + 'pvals': [list of list of number] # proteins x cell group (+ 'Score') matrix of p-values + } +``` + +# GET: /Clusters/list +Not used anymore + +# GET: /Clusters//Cells +Not used anymore + + +# GET: /Expression/Genes/List +Retrieves a list of genes for which expression values can be plotted. +Used to populate the dropdown in the 'Genes' tab. + +Response structure: +``` +[list of str - gene names] +``` +# GET: /Expression/Gene/ +Gets the per-cell expression of the gene specified by ``. +Expression values returned are on a log2 scale. + +Response structure: +Items in 'values' correspond to the cells in 'cells' in order +``` + { + 'cells': [list of str - cell identifiers], + 'values': [list of number - gene expression values], + } +``` + +# GET: /Cell//Meta +Retrieves meta-data information for an individual cell specified by `` + +Response structure: +``` + { + 'variable name': value (str or number), + 'variable name': value (str or number), + 'variable name': value (str or number), + ... + } +``` + +# POST: /Cells/Meta +Retrieves meta-data information for a group of cells + +Posted data structure +``` +[list of cell id] +``` + +Response structure: +``` + { + 'numeric': { + '': { + 'Min': , + 'Median': , + 'Max': , + }, + '': { + 'Min': , + 'Median': , + 'Max': , + }, + # Repeat for additional numeric meta-data variables + }, + 'factor': { + '': { + '': number (proportion of cells assigned to this level, + '': number (proportion of cells assigned to this level, + '': number (proportion of cells assigned to this level, + ... + } + # Repeat for additional factor meta-data variables + } + } +``` + +# GET: /Cells/Selections +Used when loading a selection of cells. + +Response structure: +``` +[list of str - names of saved selections] +``` + +# GET: /Cells/Selections/ +Retrieves the cells associated with the selection, `` + +Response structure: +``` +[list of str - cell ids in the indicated cell selection] +``` +# POST: /Cells/Selections/ +Saves a cell selection with name `` + +``` +[list of str - cell ids to be assigned to this cell selection] +``` + +# GET: /Tree/Projections/list +Get the list of different tree layouts that are available +Used to populate the 'Projection' dropdown under the 'Trajectories' view + +R version: returns the names of object@TrajectoryProjections + +Response structure: +``` +[list of str - names of tree projections] +``` + +# GET: /Tree/Projections//coordinates +Returns the coordinates for the tree layout `` in addition +to the position of individual cells + +Response structure: +``` + [ + [ + [, , ], # coordinates for individual cells + [, , ], + [, , ], + ... + ], + [ + [, ], # coordinates for internal tree nodes + [, ], + [, ], + ... + ], + [list of list of number] # 0/1 adjacency matrix for internal tree nodes + ] +``` + + +# GET: /Tree/SigProjMatrix/Normal +Returns matrices consisting of test statistic and p-value trajectory autocorrelation +Format is similar to `/Clusters//SigProjMatrix/Normal`, but without +the 1 vs all test results. + +'zscores' and 'pvals' matrices have just a single column + +Response structure: +``` + { + 'sig_labels': [list of str] # Rows of matrices in zscores and pvals + 'proj_labels': ["Score"], + 'zscores': [list of list of number] # signatures x 1 matrix of test statistics + 'pvals': [list of list of number] # signatures x 1 matrix of p-values + } +``` + +# GET: /Tree/SigProjMatrix/Meta +Same as `/Tree/SigProjMatrix/Normal` but for meta-data variables + +'zscores' and 'pvals' matrices have just a single column + +Response structure: +``` + { + 'sig_labels': [list of str] # Rows of matrices in zscores and pvals + 'proj_labels': ["Score"], + 'zscores': [list of list of number] # variables x 1 matrix of test statistics + 'pvals': [list of list of number] # variables x 1 matrix of p-values + } +``` + +# GET: /Tree/ProteinMatrix +Same as `/Tree/SigProjMatrix/Normal` but for CITE protein expression values + +'zscores' and 'pvals' matrices have just a single column + +Response structure: +``` + { + 'sig_labels': [list of str] # Rows of matrices in zscores and pvals + 'proj_labels': ["Score"], + 'zscores': [list of list of number] # proteins x 1 matrix of test statistics + 'pvals': [list of list of number] # proteins x 1 matrix of p-values + } +``` diff --git a/DESCRIPTION b/DESCRIPTION index b5731929..88026868 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,15 +1,17 @@ Package: VISION Title: Functional interpretation of single cell RNA-seq latent manifolds -Version: 2.1.0 +Version: 3.0.0 Authors@R: c(person("Matt", "Jones", email = "mattjones315@gmail.com", role = c("aut", "cre")), person("David", "Detomaso", email = "david.detomaso@berkeley.edu", role = c("aut", "cre")), person("Tal", "Ashuach", email = "tal_ashuach@berkeley.edu", role = c("aut")), + person("Yanay", "Rosen", email = "yanayrosen@berkeley.edu", role = c("aut")), person("Nir", "Yosef", email = "niryosef@berkeley.edu", role = c("ctb", "cph"))) Author: Matt Jones [aut, cre], David Detomaso [aut, cre], Tal Ashuach [aut], Nir Yosef [ctb] Maintainer: Matt Jones Description: VISION provides functional interpretation of single cell RNA-seq (scRNA-seq) latent manifolds through the use of biological signatures (which can be downloaded from online databases). VISION can operate downstream of other common analyses such as dimensionality reduction, clustering, or trajectory analysis of scRNA-seq data. VISION produces an interactive web-based output report that can be easily shared with other collaborators or the greater scientific community. Depends: R (>= 3.4) Imports: + dplyr, fastICA, igraph, irlba, @@ -40,7 +42,7 @@ Encoding: UTF-8 LazyData: true URL: https://yoseflab.github.io/VISION, https://github.com/yoseflab/VISION BugReports: https://github.com/YosefLab/VISION/issues -RoxygenNote: 7.1.0 +RoxygenNote: 7.1.1 Suggests: Biobase, BiocStyle, diff --git a/NAMESPACE b/NAMESPACE index 3eddf38e..0f3f698f 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,19 +1,37 @@ # Generated by roxygen2: do not edit by hand +export(PhyloVision) export(Vision) +export(addHotspotToVision) export(addSignatures) export(addTSNE) export(addUMAP) +export(analyzeHotspotObjectVision) export(analyzeLocalCorrelations) export(analyzeLocalCorrelationsModules) export(annotateLatentComponents) export(applyMicroClustering) export(calcModuleScores) export(calcSignatureScores) +export(calc_mod_sig_enrichment) +export(calc_set_enrichment) +export(clusterModScores) export(clusterSigScores) export(computeLatentSpace) export(convertGeneIds) export(createGeneSignature) +export(depthBasedCladewiseTreeCluster) +export(depthBasedTreeCluster) +export(draw_hotspot_heatmap) +export(generateOverlapSignatures) +export(group_modules_enrichment) +export(hsCalculateModuleScores) +export(hsComputeAutoCorrelations) +export(hsComputeLocalCorrelations) +export(hsCreateKnnGraph) +export(hsInit) +export(lca_based_depth) +export(loadHotspotObject) export(poolMatrixCols) export(poolMatrixRows) export(poolMetaData) @@ -21,6 +39,11 @@ export(read_10x) export(read_10x_h5) export(read_10x_h5_v2) export(read_10x_h5_v3) +export(runHotspot) +export(saveHSBytestToPickle) +export(treeClusterMinCladeSize) +export(trivial_dist) +exportMethods(PhyloVision) exportMethods(Vision) exportMethods(addProjection) exportMethods(analyze) @@ -33,6 +56,7 @@ exportMethods(getSelections) exportMethods(getSignatureAutocorrelation) exportMethods(getSignatureDifferential) exportMethods(getSignatureScores) +exportMethods(phyloAnalyze) exportMethods(saveAndViewResults) exportMethods(viewResults) import(Matrix) diff --git a/NEWS.md b/NEWS.md index fc8b5f31..7ada7135 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,14 @@ +# VISION 3.0.0 + +Major version bump! + +* Added support for Phylogenies as latent spaces in core VISION and integrated with VISION api +* Re-engineered UI into Signature Autocorrelation and Hotspot views +* Integrated [Hotspot](https://yoseflab.github.io/Hotspot/index.html) into VISION analysis and report UI. +* Deprecated support for trajectories and LC Annotator. +* New color-scheme for gene expression values + + # VISION 2.1.0 Added parameter `sig_gene_threshold` with **changed default behavior** diff --git a/R/AllClasses.R b/R/AllClasses.R index 11f87891..935cd28b 100644 --- a/R/AllClasses.R +++ b/R/AllClasses.R @@ -10,6 +10,8 @@ setClassUnion("numericORNULL", members = c("numeric", "NULL")) setClassUnion("matrixORSparse", members = c("matrix", "dgCMatrix")) setClassUnion("matrixORNULL", members = c("matrix", "NULL")) setClassUnion("dataframeORNULL", members = c("data.frame", "NULL")) +setClassUnion("rawORNULL", members = c("raw", "NULL")) + # setClassUnion("treeorNull", members=c("phylo", "NULL")) # setClassUnion("pythonorNull", members = c("python.builtin.object", "NULL")) @@ -121,7 +123,7 @@ Vision <- setClass("Vision", Pools = "list", LatentSpace = "matrix", LatentTrajectory = "trajectoryORNULL", - Hotspot = "list", + Hotspot = "rawORNULL", ModuleSignatureEnrichment = "list", ModuleHotspotScores = "data.frame", Viewer = "list", @@ -148,7 +150,7 @@ Vision <- setClass("Vision", Pools = list(), LatentSpace = matrix(NA, 1, 1), LatentTrajectory = NULL, - Hotspot = list(), + Hotspot = NULL, ModuleSignatureEnrichment = list(), ModuleHotspotScores = data.frame(), Viewer = list(), diff --git a/R/AllGenerics.R b/R/AllGenerics.R index b76e8a82..69d7e677 100644 --- a/R/AllGenerics.R +++ b/R/AllGenerics.R @@ -4,6 +4,8 @@ setGeneric("Vision", function(data, ...) { standardGeneric("Vision") }) +#' @rdname PhyloVision-class +#' @export setGeneric("PhyloVision", function(tree, ...) { standardGeneric("PhyloVision") }) diff --git a/R/AnalysisFunctions.R b/R/AnalysisFunctions.R index d272dee9..bc8a7a67 100644 --- a/R/AnalysisFunctions.R +++ b/R/AnalysisFunctions.R @@ -18,7 +18,7 @@ clusterCells <- function(object, tree=FALSE) { } else { message("Using Tree to compute clusters...\n") # Get the MRCA matrix and convert the node indexes to depths - cl <- treeCluster3(object@tree) + cl <- maxSizeCladewiseTreeCluster(object@tree) } names(cl) <- paste('Cluster', seq(length(cl))) diff --git a/R/Microclusters.R b/R/Microclusters.R index afb0459a..f7d0870e 100644 --- a/R/Microclusters.R +++ b/R/Microclusters.R @@ -326,6 +326,7 @@ readjust_clusters <- function(clusters, data, cellsPerPartition=100) { return(clusters) } + #' Pools columns of a numeric matrix #' #' Uses the provided pools to merge columns of the supplied data matrix @@ -383,6 +384,7 @@ poolMatrixRows <- function(data, pools) { return(pooled_data) } + #' create "super-cells" by pooling together single cells #' @param expr expression data (genes x cells matrix) #' @param pools cluster association of each cell @@ -418,13 +420,15 @@ poolMatrixCols_Inner <- function(expr, pools) { #' Performs a binary search on a depth d such that -#' if depth(u, v) <= d then u and v are in the same cluster +#' if depth(LCA(u, v)) <= d then u and v are in the same cluster #' #' @param tree object of class phylo -#' @param reach number of clusters to attempt to generate +#' @param target number of clusters to attempt to generate #' @return List of clusters, each entry being a vector of indices representing #' samples in the cluster. -treeCluster <- function(tree, reach=10) { +#' +#' @export +depthBasedTreeCluster <- function(tree, target=10) { high <- length(tree$tip.label) low <- 0 while (T) { @@ -453,12 +457,12 @@ treeCluster <- function(tree, reach=10) { } } - if (num_clusters >= reach) { + if (num_clusters >= target) { if(low == d) { break } low <- d - } else if (num_clusters < reach) { + } else if (num_clusters < target) { if(high == d) { break } @@ -470,15 +474,17 @@ treeCluster <- function(tree, reach=10) { } -#' Performs a breadth first search to create a specific number of clusters -#' Clusters are split based on depth +#' Performs a breadth first search to create a specific number of clusters. +#' Clusters are split based on depth. #' #' @param tree object of class phylo -#' @param reach number of clusters to attempt to generate +#' @param target number of clusters to attempt to generate #' @return List of clusters, each entry being a vector of indices representing #' samples in the cluster. -treeCluster2 <- function(tree, reach=10) { - if (reach > length(tree$tip.label)) { +#' +#' @export +depthBasedCladewiseTreeCluster <- function(tree, target=10) { + if (target > length(tree$tip.label)) { stop("Number of clusters is too high.") } @@ -498,7 +504,7 @@ treeCluster2 <- function(tree, reach=10) { cluster_parents[[as.name(child)]] <- node_depths[child] } - if (length(cluster_parents) >= reach) { + if (length(cluster_parents) >= target) { break } } @@ -515,19 +521,18 @@ treeCluster2 <- function(tree, reach=10) { } -#' Performs a bread first search to create a specific number of clusters -#' Clusters are split to prioritize cluster size +#' Performs a breadth first search to create a specific number of clusters +#' Clusters are split to prioritize max cluster size #' #' @param tree object of class phylo -#' @param reach number of clusters to attempt to generate -#' @return List of clusters, each entry being a vector of indices representing +#' @param target number of clusters to attempt to generate +#' @return List of clusters, each entry being a vector of tips representing #' samples in the cluster. -treeCluster3 <- function(tree, reach=10) { - if (reach > length(tree$tip.label)) { +maxSizeCladewiseTreeCluster <- function(tree, target=10) { + if (target > length(tree$tip.label)) { stop("Number of clusters is too high.") } - # node_depths <- node.depth(tree) root <- find_root(tree) cluster_parents <- c() cluster_parents[[as.name(root)]] <- get_max_cluster_size(tree, root) @@ -548,7 +553,6 @@ treeCluster3 <- function(tree, reach=10) { } } - cl <- list() for (cluster in seq_len(length(cluster_parents))) { cellId <- as.integer(names(cluster_parents)[cluster]) @@ -557,25 +561,71 @@ treeCluster3 <- function(tree, reach=10) { cl[[cluster]] <- all_children } - while (length(cl) > reach) { - cs <- c() - for (c in cl) { - cs <- append(cs, length(c)) - } - - smallest_i <- which.min(cs) - tip1 <- which(tree$tip.label == cl[[smallest_i]][1]) - dists <- c() - for (i in 1:length(cl)) { - tip2 <- which(tree$tip.label == cl[[i]][1]) - dists <- append(dists, trivial_dist(tree, tip1, tip2)) - } - - dists[smallest_i] <- dists[smallest_i] + max(dists) - closest_cluster_i <- which.min(dists) - cl[[min(c(closest_cluster_i, smallest_i))]] <- append(cl[[smallest_i]], cl[[closest_cluster_i]]) - cl[[max(c(closest_cluster_i, smallest_i))]] <- NULL + while (length(cl) > target) { + cs <- c() + for (c in cl) { + cs <- append(cs, length(c)) + } + + smallest_i <- which.min(cs) + tip1 <- which(tree$tip.label == cl[[smallest_i]][1]) + dists <- c() + for (i in 1:length(cl)) { + tip2 <- which(tree$tip.label == cl[[i]][1]) + dists <- append(dists, trivial_dist(tree, tip1, tip2)) + } + + dists[smallest_i] <- dists[smallest_i] + max(dists) + closest_cluster_i <- which.min(dists) + cl[[min(c(closest_cluster_i, smallest_i))]] <- append(cl[[smallest_i]], cl[[closest_cluster_i]]) + cl[[max(c(closest_cluster_i, smallest_i))]] <- NULL } return(cl) } + + +#' Generate clade-clusters for a tree of minimum size (unless children of root) +#' +#' +#' @param tree object of class phylo +#' @param minSize minimum clade size for a clade to be expanded +#' @return List of clusters, each entry being a vector of tips representing +#' WARNING: This won't work well for tree's with broad multifurcations +#' @export +treeClusterMinCladeSize <- function(tree, minSize=30) { + nodeLabels <- tree$node.label + numC <- length(tree$tip.label) + + # split into clusters for each one + cl <- list() + seen <- c() + i <- 1 # current cluster number + # sort groups by min cluster_size first + root <- find_root(tree) + queue <- c(root) + while (TRUE) { + # BFS on internal nodes + if (length(queue) < 1) { + break + } + internalNode <- queue[1] + queue <- queue[-1] + + + children <- get_children(tree, internalNode) + for (child in children) { + childMinSize <- get_min_cluster_size(tree, child) + if (childMinSize >= minSize){ + # continue expanding this child + queue <- append(queue, child) + } else { + # make this child a cluster + cl[[i]] <- get_all_children(tree, child) %>% (function(x) {return(tree$tip.label[x])}) + i <- i + 1 + } + } + + } + return(cl) +} \ No newline at end of file diff --git a/R/Projections.R b/R/Projections.R index 14b3316a..43f8e525 100644 --- a/R/Projections.R +++ b/R/Projections.R @@ -378,20 +378,28 @@ setMethod("computeKNNWeights", signature(object = "matrix"), ) -#' compute for each vector the weights to apply to it's K nearest neighbors +#' Compute for each vector the weights to apply to it's K nearest neighbors +#' #' @importFrom Matrix rowSums #' @importFrom Matrix sparseMatrix #' @importFrom matrixStats rowMaxs #' @param object tree to use for KNN #' @param K Number of neighbors to consider. +#' @param lcaKNN whether to use LCA based KNN (cluster by minimum size), if false defaults to cophenetic distance (random tie breaking). +#' WARNING: lcaKNN doesn't perform well with broad multifurcations #' @return a list of two items: #' indices: matrix, cells X neighbors #' Each row specifies indices of nearest neighbors #' weights: matrix, cells X neighbors #' Corresponding weights to nearest neighbors setMethod("computeKNNWeights", signature(object = "phylo"), - function(object, K = round(sqrt(length(object$tip.label)))) { - k <- find_knn_parallel_tree(object, K) + function(object, K = round(sqrt(length(object$tip.label))), lcaKNN=FALSE, minSize=20) { + if (lcaKNN) { + k <- lcaBasedTreeKNN(object, minSize = minSize) + } else { + k <- find_knn_parallel_tree(object, K) + } + nn <- k[[1]] d <- k[[2]] diff --git a/R/Utilities.R b/R/Utilities.R index 99bc5840..598ed805 100644 --- a/R/Utilities.R +++ b/R/Utilities.R @@ -245,7 +245,7 @@ matrix_wilcox <- function(ranks, cluster_ii, #' @return pval - numeric vector, pvalue for each row #' @return stat - numeric vector, test statistic (AUC) for each row matrix_wilcox_cpp <- function(data, cluster_num, cluster_denom, - jobs = getOption("mc.cores", 2L)) { + jobs = getOption("mc.cores", 1L)) { # Subsetting individual rows is bad with a sparse matrix # instead we subset chunks at a time @@ -806,7 +806,6 @@ knn_tree <- function(leaves, k, distances) { } - #' Parallel KNN for Trees #' #' Computes nearest-neighbor indices and distances @@ -852,6 +851,46 @@ find_knn_parallel_tree <- function(tree, K) { return(list(index=idx, dist=dists)) } + + +#' Generate neighbors and weights for a tree object, based on LCA. +#' +#' @param tree object of class phylo +#' @param minSize the minimum number of neighbors per node +#' @return the hotspot object +lcaBasedTreeKNN <- function(tree, minSize=20) { + tips <- tree$tip.label + nTips <- length(tips) + neighbors <- data.frame(t(matrix(seq_len(nTips), ncol = nTips, nrow= nTips))) + rownames(neighbors) <- tips + + + weights <- data.frame(matrix(0, ncol = nTips, nrow= nTips)) + for (tip in seq_len(nTips)) { + my_neighbors <- minSizeCladeNeighbors(tree, tip, minSize) + + weights[tip, my_neighbors] <- 1 + } + + neighbors_no_diag <- data.frame(matrix(ncol = nTips -1, nrow= nTips)) + weights_no_diag <- data.frame(matrix(ncol = nTips -1, nrow= nTips)) + + for (tip in seq_len(nTips)) { + neighbors_no_diag[tip, ] <- neighbors[tip, -tip] + weights_no_diag[tip, ] <- weights[tip, -tip] + } + + rownames(neighbors_no_diag) <- tips + rownames(weights_no_diag) <- tips + + colnames(neighbors_no_diag) <- seq_len(nTips-1) - 1 + colnames(weights_no_diag) <- seq_len(nTips-1) - 1 + return(list("neighbors"=as.matrix(neighbors_no_diag), "weights"=as.matrix(weights_no_diag))) +} + + + + #' Generate an ultrametric tree #' #' @param tree an object of class phylo @@ -910,6 +949,40 @@ get_children <- function(tree, node) { return(children) } +#' Get the parent of a node +#' @param tree an object of class phylo +#' @param node the node to get parent +#' +#' @return the immediate parent of the mode, or the node if it is root +get_parent <- function(tree, node) { + edges <- tree$edge + parent <- edges[, 1][edges[, 2] == node] + if (length(parent) > 0){ + return(parent) + } + return(node) +} + + +#' Get's the nearest >= min size neighbors of a node based on clade structure +#' @param tree an object of class phylo +#' @param tip the tip to find the neighbors of +#' @param minSize the minimum number of neighbors of the node (excludes self) +#' +#' @return the neighbors +minSizeCladeNeighbors <- function(tree, tip, minSize=20) { + node <- tip + while (T) { + neighbors <- get_all_children(tree, node) + clade_size <- length(neighbors) + if (clade_size > minSize) { + return(neighbors) + } else { + node <- get_parent(tree, node) + } + } +} + #' Check if a child is a tip #' #' @param tree an object of class phylo @@ -948,7 +1021,10 @@ get_all_children <- function(tree, node) { return(tips) } - +#' Tree method for getting the max child clade size of a node +#' @param tree an object of class phylo +#' @param node the node to check +#' @return the size of the largest child clade get_max_cluster_size <- function(tree, node) { children <- get_children(tree, node) num_children <- c() @@ -959,32 +1035,90 @@ get_max_cluster_size <- function(tree, node) { } +#' Tree method for getting the min child clade size of a node +#' @param tree an object of class phylo +#' @param node the node to check +#' @return the size of the smallest child clade +get_min_cluster_size <- function(tree, node) { + children <- get_children(tree, node) + num_children <- c() + for (child in children) { + num_children <- append(num_children, length(get_all_children(tree, child))) + } + return(min(num_children)) +} + + +#' Trivial distance function for arbitrary tree clustering +#' +#' Number of mutations along path from tip1 to LCA(tip1, tip2) +#' Ensures if on same clade, join. +#' +#' @param tree an object of class phylo +#' @param tip1 the first leaf +#' @param tip2 the second leaf +#' @return the trivial distance between tip1, tip2 +#' +#' @export trivial_dist <- function(tree, tip1, tip2) { - depths <- node.depth(tree) - edges <- tree$edge - path1 <- c(tip1) - root <- find_root(tree) - parent <- tip1 - while (T) { - parent <- edges[, 1][edges[, 2] == parent] - path1 <- append(path1, parent) - if (parent == root) { - break - } + # node depths of tree + edges <- tree$edge + # Get the path from tip1 to root + path1 <- c(tip1) + root <- find_root(tree) + parent <- tip1 + while (T) { + parent <- edges[, 1][edges[, 2] == parent] + path1 <- append(path1, parent) + if (parent == root) { + break } - - path2 <- c(tip2) - parent <- tip2 - while (T) { - parent <- edges[, 1][edges[, 2] == parent] - path2 <- append(path2, parent) - if (parent == root || parent %in% path1) { - break - } + } + + mrca <- getMRCA(tree, c(tip1, tip2)) # MRCA of both + + + # Depths of the internal nodes that represent the parents of tip1, tip2 right before LCA + # ie the 'diverging' point or first split + path_length <- which(path1 == mrca) + + # Return the absolute difference between the depths + return(path_length) +} + + + + + +#' Depth of tip1 parent immediately after LCA(tip1, tip2) +#' +#' @param tree an object of class phylo +#' @param tip1 the first leaf +#' @param tip2 the second leaf +#' @return the trivial distance between tip1, tip2 +#' +#' @export +lca_based_depth <- function(tree, tip1, tip2) { + depths <- node.depth(tree) + edges <- tree$edge + # Get the path from tip1 to root + path1 <- c(tip1) + root <- find_root(tree) + parent <- tip1 + while (T) { + parent <- edges[, 1][edges[, 2] == parent] + path1 <- append(path1, parent) + if (parent == root) { + break } - - tip1_depth_prev <- depths[path1[which(path1 == path2[length(path2)]) - 1]] - tip2_depth_prev <- depths[path2[length(path2)] - 1] - - return(abs(tip1_depth_prev - tip2_depth_prev)) + } + + mrca <- getMRCA(tree, c(tip1, tip2)) # MRCA of both + + # Depths of the internal nodes that represent the parents of tip1, tip2 right before LCA + # ie the 'diverging' point or first split + lca_child_depth <- depths[path1[which(path1 == mrca) - 1]] + + # Return the absolute difference between the depths + return(lca_child_depth) } \ No newline at end of file diff --git a/R/methods-Module.R b/R/methods-Module.R index 114c77c3..34cf6ffe 100644 --- a/R/methods-Module.R +++ b/R/methods-Module.R @@ -1,88 +1,220 @@ +#' Perform Hotspot analysis on Vision Object +#' +#' @param object Vision Object +#' @param model model argument for Hotspot, one of \itemize{ +#' \item normal +#' \item danb +#' \item bernoulli +#' \item none +#' } +#' @param tree whether to use tree as latent space. If TRUE, object should have +#' a tree slot. +#' @param number_top_genes Hotspot argument for number of genes to consider +#' @param num_umi optional dataframe containing umi counts in first column for +#' barcodes +#' @param min_gene_threshold minimum number of genes in Hotspot module +#' @param n_neighbors number of neighbors to consider in latent space +#' @param autocorrelation_fdr threshold for significance for genes autocorr +#' @param clustering_fdr threshold for significance for clustering modules +#' @param logdata boolean, log the expression data, avoid for danb +#' Populates the modData, HotspotModuleScores, ModuleSignatureEnrichment +#' and HotspotObject slots of object, as well as recalculates signature scores +#' for new modules. +#' @return the modified Vision object +#' +#' @export +runHotspot <- function(object, model="normal", tree=FALSE, + number_top_genes=1000, num_umi=NULL, + min_gene_threshold=20, n_neighbors=NULL, + autocorrelation_fdr=0.05, clustering_fdr=0.5, logdata=FALSE) { + + # Init Hotspot + hs <- hsInit(object, model, tree, num_umi, logdata) + # Init Hotspot KNN + hs <- hsCreateKnnGraph(hs, object, n_neighbors=n_neighbors) + # perform Hotspot analysis and store results in R + hs_genes <- hsComputeAutoCorrelations(hs, number_top_genes=number_top_genes, autocorrelation_fdr=autocorrelation_fdr) + # Compute localcorr + hs <- hsComputeLocalCorrelations(hs, hs_genes) + # Calculate Hotspot Module Scores for informative genes + hs <- hsCalculateModuleScores(hs, min_gene_threshold, clustering_fdr) + # Cluster Hotspot modules and perform Vision based analysis on HS Modules and + object <- analyzeHotspotObjectVision(object, hs, tree) + + return(object) +} -calcHotspotModules <- function(object, model="normal", tree=FALSE, number_top_genes=1000, - num_umi=NULL, min_gene_threshold=20, n_neighbors=NULL, - fdr_threshold=0.05) { +#' Init Hotspot object from Vision Object +#' +#' @param object the Vision Object +#' @param model the model for Hotspot (ie "normal", "danb"...) +#' @param tree boolean, whether to use the tree as ls +#' @param num_umi df of barcodes x num_umi +#' @param logdata boolean, log the expression data, avoid for danb +#' +#' @return the Hotspot object +#' +#' @export +hsInit <- function(object, model="normal", tree=F, num_umi=NULL, logdata=FALSE) { + hotspot <- import("hotspot", convert=F) + + workers <- getOption("mc.cores") + if (is.null(workers)){ + workers <- 1 + } + + if (!logdata) { + # Don't take the log + exprData = object@exprData + } else { + # take the log2 otherwise + exprData = matLog2(object@exprData) + } + + gene_subset <- object@params$latentSpace$projectionGenes + + if (any(is.na(gene_subset))) { + gene_subset <- applyFilters(exprData, + object@params$latentSpace$projectionGenesMethod, + object@params$latentSpace$threshold, 2) + } + + exprData = as.data.frame(as.matrix(exprData)[gene_subset,]) + + # remove genes that do not have any standard deviation + sds = apply(exprData, 1, sd) + exprData = exprData[which(sds > 0), ] + + # generate the Hotspot object in python, potentially using the tree + if (tree) { + message("Using Tree") + ete3 <- import("ete3", convert=F) + nwk <- write.tree(object@tree) + pyTree <- ete3$Tree(nwk, format = 8L) + if (is.null(num_umi)) { + hs <- hotspot$Hotspot(exprData, tree=pyTree, model=model) + } else { + py$umi_df <- r_to_py(num_umi) + py_run_string("umi_counts = umi_df.iloc[:, 0]") + hs <- hotspot$Hotspot(exprData, tree=pyTree, model=model, umi_counts=py$umi_counts) + } + + } else { + if (is.null(num_umi)) { + hs <- hotspot$Hotspot(exprData, latent=as.data.frame(object@LatentSpace), model=model) + } else { + py$umi_df <- r_to_py(num_umi) + py_run_string("umi_counts = umi_df.iloc[:, 0]") + hs <- hotspot$Hotspot(exprData, latent=as.data.frame(object@LatentSpace), model=model, umi_counts=py$umi_counts) + } + } + + return(hs) +} - hotspot <- import("hotspot", convert=F) - workers <- getOption("mc.cores") - if (is.null(workers)){ - workers <- 1 - } +#' Init KNN graph in Hotspot object +#' +#' @return the Hotspot object with KNN initialized +#' +#' @export +hsCreateKnnGraph <- function(hs, object, n_neighbors=NULL) { + # create knn graph, specify nn or use object default + if (is.null(n_neighbors)) { + hs$create_knn_graph(F, n_neighbors = as.integer(object@params$numNeighbors)) + } else { + hs$create_knn_graph(F, n_neighbors = as.integer(n_neighbors)) + } + return(hs) +} - exprData = matLog2(object@exprData) - gene_subset = object@params$latentSpace$projectionGenes +#' Compute Hotspot auto correlations +#' +#' @param hs the Hotspot object +#' @param number_top_genes Hotspot argument for number of genes to consider +#' @param autocorrelation_fdr threshold for significance for genes autocorr +#' @return list of HS genes +#' +#' @export +hsComputeAutoCorrelations <- function(hs, number_top_genes=1000, autocorrelation_fdr=0.05) { + workers <- getOption("mc.cores") + if (is.null(workers)){ + workers <- 1 + } + + hs_results <- hs$compute_autocorrelations(jobs=as.integer(workers)) + hs_genes <- hs_results$loc[hs_results$FDR$le(autocorrelation_fdr)]$sort_values('Z', ascending=F)$head(as.integer(number_top_genes))$index + return(hs_genes) +} - if (is.null(gene_subset)) { - gene_subset <- applyFilters(exprData, - object@params$latentSpace$projectionGenesMethod, - object@params$latentSpace$threshold, 2) - } - exprData = as.data.frame(as.matrix(object@exprData)[gene_subset,]) +#' Interface function to compute local correlations for Hotspot +#' Warning: modifies the hs argument +#' @param hs the Hotspot object +#' @param hs_genes Hotspot genes +#' @return the populated hs object +#' +#' @export +hsComputeLocalCorrelations <- function(hs, hs_genes) { + workers <- getOption("mc.cores") + if (is.null(workers)){ + workers <- 1 + } + hs$compute_local_correlations(hs_genes, jobs=as.integer(workers)) + return(hs) +} - # remove genes that do not have any standard deviation - sds = apply(exprData, 1, sd) - exprData = exprData[which(sds > 0), ] - # TODO add UMI support - if (tree) { - message("Using Tree") - ete3 <- import("ete3", convert=F) - nwk <- write.tree(object@tree) - pyTree <- ete3$Tree(nwk, format = 8L) - if (is.null(num_umi)) { - hs <- hotspot$Hotspot(exprData, tree=pyTree, model=model) - } else { - py$umi_df <- r_to_py(num_umi) - py_run_string("umi_counts = umi_df.iloc[:, 0]") - hs <- hotspot$Hotspot(exprData, tree=pyTree, model=model, umi_counts=py$umi_counts) - } - - } else { - if (is.null(num_umi)) { - hs <- hotspot$Hotspot(exprData, latent=as.data.frame(object@LatentSpace), model=model) - } else { - py$umi_df <- r_to_py(num_umi) - py_run_string("umi_counts = umi_df.iloc[:, 0]") - hs <- hotspot$Hotspot(exprData, latent=as.data.frame(object@LatentSpace), model=model, umi_counts=py$umi_counts) - } - } +#' Analyze a Hotspot object using built in methods such +#' such as local correlation, signature overlap, etc. +#' Necessary to run this function for Hotspot functionality in viewer to work. +#' +#' @param object the VISION object +#' @param hs the Hotspot python object loaded by Reticulate +#' @param tree whether to use tree as latent space. If TRUE, object should have a tree +#' +#' @return the modified VISION object with the following slots filled: +#' Populates the modData, HotspotModuleScores, ModuleSignatureEnrichment +#' and HotspotObject slots of object, as well as recalculates signature scores +#' for new modules. +#' +#' @export +analyzeHotspotObjectVision <- function(object, hs, tree=FALSE) { + hs_module_scores <- hs$module_scores + hs_modules <- hs$modules - if (is.null(n_neighbors)) { - hs$create_knn_graph(F, n_neighbors = as.integer(object@params$numNeighbors)) - } else { - hs$create_knn_graph(F, n_neighbors = as.integer(n_neighbors)) + # handle annoying reticulate conversion issues when writing to a file + if (!is.data.frame(hs_module_scores)) { + hs_module_scores <- py_to_r(hs_module_scores) } - - hs_results <- hs$compute_autocorrelations(jobs=as.integer(workers)) - hs_genes <- hs_results$loc[hs_results$FDR$le(fdr_threshold)]$sort_values('Z', ascending=F)$head(as.integer(number_top_genes))$index - hs$compute_local_correlations(hs_genes, jobs=as.integer(workers)) - hs$create_modules(min_gene_threshold=as.integer(min_gene_threshold)) - hs_module_scores <- py_to_r(hs$calculate_module_scores()) - hs_modules <- py_to_r(hs$modules) + if (!is.array(hs_modules)) { + hs_modules <- py_to_r(hs_modules) + } modules <- list() + # add the modules with name scheme HOTSPOT_{TREE if using TREE}_# + model <- hs$model for (i in unique(c(hs_modules))) { if (i !=-1) { names <- dimnames(hs_modules[hs_modules == i])[[1]] v <- rep(1, length(names)) names(v) <- names if (tree) { - new_sig <- Signature(sigDict = v, name=paste("HOTSPOT_TREE", i, sep = "_"), source="Hotspot", meta=paste("Hotspot on tree, model:", model)) - modules[[paste("HOTSPOT_TREE", i, sep = "_")]] <- new_sig + new_sig <- Signature(sigDict = v, name=paste("HOTSPOT_TREE", i, sep = "_"), source="Hotspot", meta=paste("Hotspot on tree, model:", model)) + modules[[paste("HOTSPOT_TREE", i, sep = "_")]] <- new_sig } else { - new_sig <- Signature(sigDict = v, name=paste("HOTSPOT", i, sep = "_"), source="Hotspot", meta=paste("Hotspot, model:", model)) - modules[[paste("HOTSPOT", i, sep = "_")]] <- new_sig + new_sig <- Signature(sigDict = v, name=paste("HOTSPOT", i, sep = "_"), source="Hotspot", meta=paste("Hotspot, model:", model)) + modules[[paste("HOTSPOT", i, sep = "_")]] <- new_sig } } } - colnames(hs_module_scores) <- names(modules) + # store module scores + colnames(hs_module_scores) <- sort(names(modules)) object@modData <- modules if (length(object@sigData) > 0) { @@ -94,22 +226,62 @@ calcHotspotModules <- function(object, model="normal", tree=FALSE, number_top_ge # calculate overlap signatures object <- generateOverlapSignatures(object) - # normal analysis + # re run normal analysis object <- calcModuleScores(object) object <- clusterModScores(object) - object@Hotspot <- list(hs) + object@ModuleHotspotScores <- hs_module_scores object <- analyzeLocalCorrelationsModules(object, tree) - + # save the Hotspot object + object <- addHotspotToVision(object, hs) return(object) } +#' Create Hotspot Modules and calculate module scores given a HS object +#' with local correlations already calculated +#' +#' @param hs the Hotspot object, must have ran compute_local_correlations already +#' @param min_gene_threshold min genes per module +#' @param clustering_fdr p value for clustering genes +#' @return the modified hs object +#' +#' @export +hsCalculateModuleScores <- function(hs, min_gene_threshold=20, clustering_fdr=0.5, plot=F) { + hs$create_modules(min_gene_threshold=as.integer(min_gene_threshold), fdr_threshold=clustering_fdr) + hs$calculate_module_scores() + + if (plot) { + draw_hotspot_heatmap(hs) + } + + return(hs) +} + + +#' Add HS python obj to vision OBJECT +#' +#' @param object Vision object +#' @param hs python hs object +#' @return Vision object with hs populated +#' +#' @export +addHotspotToVision <- function(object, hs) { + # save the Hotspot object + pickle <- import("pickle", convert=F) + py$hs <- hs + py$pickle <- pickle + py_run_string("hs_byte_array = bytearray(pickle.dumps(hs))") + hs_pickled_r <- as.raw(py$hs_byte_array) + object@Hotspot <- hs_pickled_r + + return(object) +} -#' calculate module scores +#' Calculate module scores (signature scores but on the modules) #' #' For each module-cell pair, compute a score that captures the level of #' correspondence between the cell and the module. @@ -123,6 +295,7 @@ calcHotspotModules <- function(object, model="normal", tree=FALSE, number_top_ge #' the overall signature score. Default = TRUE. This is used for inspecting #' genes in a signature in the output report #' @return the VISION object, with the @ModScores and @ModGeneImportance slots populated +#' #' @export calcModuleScores <- function( object, mod_norm_method = NULL, mod_gene_importance = TRUE) { @@ -178,16 +351,17 @@ calcModuleScores <- function( } - - #' Compute local correlations for all modules #' #' This is the main analysis function. For each filtered dataset, a set of #' different projection onto low-dimensional space are computed, and the #' consistency of the resulting space with the signature scores is computed #' to find signals that are captured successfully by the projections. +#' #' @param object the VISION object +#' @param tree whether to use the tree object as latent space for neighbors #' @return the VISION object with values set for the analysis results +#' #' @export analyzeLocalCorrelationsModules <- function(object, tree=FALSE) { @@ -230,13 +404,26 @@ analyzeLocalCorrelationsModules <- function(object, tree=FALSE) { return(object) } -calc_mod_sig_enrichment <- function(object) { + +#' Computes the hypergeometric overlap test for modules and signatures +#' +#' @param object the Vision object. +#' @param skip_down whether to ignore down signatures in overlap +#' @return list(statistic values, p values, clusters of signatures) +#' +#' @export +calc_mod_sig_enrichment <- function(object, skip_down=TRUE) { modules <- object@modData original_signatures <- object@sigData signatures <- list() sig_names <- list() for (signature in original_signatures) { + # calculate enrichment for both the up signal and down signal signature genes directional <- all(c(1, -1) %in% signature@sigDict) + down_reg <- all(signature@sigDict == -1) + if (skip_down && down_reg) { + next + } if (directional) { up <- names(which(signature@sigDict == 1)) down <- names(which(signature@sigDict == -1)) @@ -245,10 +432,13 @@ calc_mod_sig_enrichment <- function(object) { down_name <- paste(signature@name, "_DOWN", sep = "") signatures <- c(signatures, list(up)) - signatures <- c(signatures, list(down)) - sig_names <- append(sig_names, up_name) - sig_names <- append(sig_names, down_name) + + if (!skip_down) { + signatures <- c(signatures, list(down)) + sig_names <- append(sig_names, down_name) + } + } else { signatures <- c(signatures, list(names(signature@sigDict))) sig_names <- append(sig_names, signature@name) @@ -257,6 +447,7 @@ calc_mod_sig_enrichment <- function(object) { genes <- rownames(object@exprData) + # calculate the enrichments stats <- c() p_values <- c() for (signature in signatures) { @@ -284,13 +475,23 @@ calc_mod_sig_enrichment <- function(object) { colnames(p_values) <- mod_names rownames(p_values) <- sig_names + # group the signatures assignments <- group_modules_enrichment(stats, p_values) return(list("statistics"=stats, "p_vals"=p_values, "cl"=assignments)) } - +#' Calculate the hypergeometric enrichment for two sets from a population +#' Statisic = log (observed overlap / expected overlap) +#' P value = 1- hypergeometric(observed overlap -1, max(|set1|, |set2|), |genes| - |set1|, min(|set1|, |set2|)) +#' +#' @param set1 the first gene set +#' @param set2 the second gene set +#' @param genes the population +#' @return c(statistic, p value) +#' +#' @export calc_set_enrichment <- function(set1, set2, genes) { N <- length(genes) m <- max(length(set1), length(set2)) @@ -310,6 +511,15 @@ calc_set_enrichment <- function(set1, set2, genes) { } +#' Make the clusters for the modules by enrichment. +#' For now we just assign each signature to each cluster, could filter to only include once, +#' so that each one appears in the modules x sigs table. +#' +#' @param stats overlap stats from calc_set_enrichment +#' @param pvals overlap p values from calc_set_enrichment +#' @return assignments of each signature to each module +#' +#' @export group_modules_enrichment <- function(stats, pvals) { sigs <- rownames(stats) mods <- colnames(stats) @@ -321,6 +531,11 @@ group_modules_enrichment <- function(stats, pvals) { } +#' Generates signature objects for the overlap sets between modules and signatures +#' @param object the Vision object +#' @return Vision Object, populates the modData slot with overlap signatures. +#' +#' @export generateOverlapSignatures <- function(object) { message("Generating Module Signature Overlaps...\n") sigs <- rownames(object@ModuleSignatureEnrichment$statistics) @@ -348,8 +563,6 @@ generateOverlapSignatures <- function(object) { } - - #' Compute Ranksums Test, for all factor meta data. One level vs all others #' #' @importFrom pbmcapply pbmclapply @@ -358,6 +571,7 @@ generateOverlapSignatures <- function(object) { #' @param object the VISION object #' @param variables which columns of the meta-data to use for comparisons #' @return the VISION object with the @ClusterComparisons modules slot populated +#' #' @export clusterModScores <- function(object, variables = "All") { @@ -430,7 +644,121 @@ clusterModScores <- function(object, variables = "All") { object@ClusterComparisons[["Modules"]] <- out return(object) +} + + +#' Load in an existing Hotspot object from bytes or a file +#' +#' @param file optional path to an existing file containing pickled bytes (format 0) +#' @param bytes optional R character vector of bytes created by calcHotspotModules +#' @return an externalptr to a Hotspot Object loaded in the R reticulate session +#' +#' @export +loadHotspotObject <- function(file=NULL, bytes=NULL) { + hotspot <- import("hotspot", convert=F) + pickle <- import("pickle", convert=F) + py$pickle <- pickle + + if (!is.null(file)) { + # load file + hs <- py_load_object(file) + return(hs) + } else if (!is.null(bytes)) { + py$hs_bytes <- r_to_py(bytes) + py_run_string("hs = pickle.loads(hs_bytes)") + return(py$hs) + } else { + return(NULL) + } +} + + +#' Save bytes in the Hotspot object slot to a file +#' @param path the file path +#' @param bytes the raw bytes, like in the Hotspot slot of a VISION Object +#' +#' @export +saveHSBytestToPickle <- function(path, bytes) { + py_save_object(obj=loadHotspotObject(bytes=bytes), path) +} + + +#' Add custom tree based neighbor and weights to a Hotspot object +#' +#' @param tree object of class phylo +#' @param the Hotspot object to add the nw to +#' @param minSize the minimum number of neighbors of the node +#' @return the Hotspot object +#' +#' @export +lcaBasedHotspotNeighbors <- function(tree, hotspot, minSize=20) { + tips <- tree$tip.label + nTips <- length(tips) + neighbors <- data.frame(t(matrix(seq_len(nTips) -1, ncol = nTips, nrow= nTips))) + rownames(neighbors) <- tips + + weights <- data.frame(matrix(0, ncol = nTips, nrow= nTips)) + for (tip in seq_len(nTips)) { + my_neighbors <- minSizeCladeNeighbors(tree, tip, minSize) + + weights[tip, my_neighbors] <- 1 + } + + neighbors_no_diag <- data.frame(matrix(ncol = nTips -1, nrow= nTips)) + weights_no_diag <- data.frame(matrix(ncol = nTips -1, nrow= nTips)) + + for (tip in seq_len(nTips)) { + neighbors_no_diag[tip, ] <- neighbors[tip, -tip] + weights_no_diag[tip, ] <- weights[tip, -tip] + } + + rownames(neighbors_no_diag) <- tips + rownames(weights_no_diag) <- tips + + colnames(neighbors_no_diag) <- seq_len(nTips-1) - 1 + colnames(weights_no_diag) <- seq_len(nTips-1) - 1 + return(list("neighbors"=neighbors_no_diag, "weights"=weights_no_diag)) } +#' Draw Modules Heatmap (Gene x Gene) +#' +#' @param hs the Hotspot Object +#' @param palette palette +#' @export +draw_hotspot_heatmap <- function(hs, palette = paletteer_d("ggsci::default_nejm")) { + scipy_hierarchy <- import("scipy.cluster.hierarchy", convert=F) + np <- import("numpy") + linkage <- hs$linkage + py_dend = scipy_hierarchy$dendrogram(linkage) + lcz = hs$local_correlation_z + gene_order = colnames(lcz)[np$array(py_dend$leaves)+1] + col_mapping = c() + module_to_col = list() + hs$modules = as.character(hs$modules) + unique_mods = as.character(unique(hs$modules)) + example_genes = list() + col_mapping[["-1"]] = "#ffffff" + for (i in 1:length(unique_mods)) { + mod = unique_mods[[i]] + if (mod != -1) { + col_mapping[[mod]] = palette[[i]] + module_to_col[[mod]] = palette[[i]] + example_genes[[mod]] = sample(hs$modules[hs$modules == mod], 5) + } + } + + modules = data.frame("module" = hs$modules) + modules$module = as.character(modules$module) + ha = rowAnnotation(df = modules, + col = col_mapping, + simple_anno_size = unit(0.5, "in")) + ht = Heatmap(as.matrix(lcz), name = "mat", + show_row_names=F, show_column_names=F, show_row_dend=F, show_column_dend=F, + row_order = gene_order, column_order=gene_order, + right_annotation=ha, + column_names_gp = gpar(fontsize = c(1)), + width = unit(5, "in"), height = unit(5, "in")) + draw(ht) +} diff --git a/R/methods-Signature.R b/R/methods-Signature.R index 6943c4a5..309270c3 100644 --- a/R/methods-Signature.R +++ b/R/methods-Signature.R @@ -61,8 +61,6 @@ Signature <- function(sigDict, name, source, metaData="") { stop("Missing source file.") } - names(sigDict) <- toupper(names(sigDict)) - .Object <- new("Signature", sigDict = sigDict, name = name, source = source, metaData = metaData) diff --git a/R/methods-Vision.R b/R/methods-Vision.R index 9082dd60..5d95d54e 100644 --- a/R/methods-Vision.R +++ b/R/methods-Vision.R @@ -90,7 +90,7 @@ setMethod("Vision", signature(data = "matrixORSparse"), "rank_norm_columns"), pool="auto", cellsPerPartition=10, name=NULL, num_neighbors = NULL, latentSpace = NULL, latentSpaceName = NULL, latentTrajectory = NULL, - tree = NULL, modData = list(), hotspot= list(), pools=list()) { + tree = NULL, modData = list(), hotspot= NULL, pools=list()) { .Object <- new("Vision") @@ -107,7 +107,6 @@ setMethod("Vision", signature(data = "matrixORSparse"), .Object@params$signatures <- list() .Object@params$micropooling <- list() - rownames(data) <- toupper(rownames(data)) toRemove <- rownames(data)[duplicated(rownames(data))] if (length(toRemove) > 0){ message(sprintf( @@ -120,7 +119,10 @@ setMethod("Vision", signature(data = "matrixORSparse"), } if (!is.null(tree)) { - data = data[,tree$tip.label] + # Subset matrix + data <- data[,tree$tip.label] + # Subset Tree + tree <- keep.tip(tree, colnames(data)) } .Object@exprData <- data @@ -139,7 +141,6 @@ setMethod("Vision", signature(data = "matrixORSparse"), } # unnormalizedData might have more genes than exprData # and it might have more cells than exprData - rownames(unnormalizedData) <- toupper(rownames(unnormalizedData)) HAS_CORRECT_CELLS <- length(setdiff( colnames(.Object@exprData), colnames(unnormalizedData) @@ -267,10 +268,8 @@ setMethod("Vision", signature(data = "matrixORSparse"), .Object@params$latentSpace$projectionGenesMethod <- projection_genes .Object@params$latentSpace$projectionGenes <- NA } else { - print("Here") .Object@params$latentSpace$projectionGenesMethod <- NA - .Object@params$latentSpace$projectionGenes <- vapply( - projection_genes, toupper, "", USE.NAMES = FALSE) + .Object@params$latentSpace$projectionGenes <- projection_genes .Object@params$latentSpace$projectionGenes = intersect(rownames(.Object@exprData), .Object@params$latentSpace$projectionGenes) } @@ -411,6 +410,13 @@ setMethod("Vision", signature(data = "matrixORSparse"), } ) + +#' Initializes a new PhyloVision Object +#' +#' @param tree parsed ape tree +#' @param ... arguments passed to the base Vision constructor +#' @rdname PhyloVision-class +#' @export setMethod("PhyloVision", signature(tree="phylo"), function(tree, ...) { obj <- Vision(...) @@ -726,7 +732,7 @@ setMethod("analyze", signature(object="Vision"), if (hotspot) { message("Hotspot Analysis") - object <- calcHotspotModules(object, model="danb", tree) + object <- runHotspot(object, model="danb", tree) } @@ -735,6 +741,12 @@ setMethod("analyze", signature(object="Vision"), return(object) }) + +#' Analyze a PhyloVision object +#' +#' @param ... arguments passed to the base Vision constructor +#' @aliases phyloAnalyze +#' @export setMethod("phyloAnalyze", signature(object="PhyloVision"), function(object, hotspot=FALSE) { object <- analyze(object, tree=TRUE, hotspot=hotspot) diff --git a/docs/404.html b/docs/404.html new file mode 100644 index 00000000..945dddb6 --- /dev/null +++ b/docs/404.html @@ -0,0 +1,194 @@ + + + + + + + + +Page not found (404) • VISION + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+
+ + +Content not found. Please use links in the navbar. + +
+ + + +
+ + + +
+ + +
+

Site built with pkgdown 1.6.1.

+
+ +
+
+ + + + + + + + diff --git a/docs/API.html b/docs/API.html new file mode 100644 index 00000000..6cd6af69 --- /dev/null +++ b/docs/API.html @@ -0,0 +1,634 @@ + + + + + + + + +GET: /SessionInfo • VISION + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ +
+
+ + + +
+ +

Returns high-level configuration info on this VISION session. Mostly used to enable/disable features in the visualizer.

+
    +
  • ‘name’: A title for this session (shown in the top title bar)
  • +
  • ‘meta_sigs’: Names of meta-data signatures. Sent here as a convenience as numeric meta-data signatures and gene signatures get combined in the display and often lookups are needed to distinguish.
  • +
  • ‘ncells’: Total number of cells
  • +
  • ‘pooled’: Whether or not there is micro-pooling
  • +
  • ‘has_sigs’: Whether or not there are gene signatures
  • +
  • ‘has_proteins’: Whether or not there are CITE-seq proteins
  • +
  • ‘has_lca’: Whether or not LC Annotator analysis is available
  • +
  • ‘has_tree’: Whether or not Trajectories are available
  • +
+

Response structure:

+
    {
+        'name': 'Session Name',
+        'meta_sigs': [list of string],
+        'ncells': int,
+        'pooled': bool,
+        'has_sigs': bool,
+        'has_proteins': bool,
+        'has_lca': bool,
+        'has_tree': bool,
+    }
+
+
+

+GET: /Signature/Scores/ +

+

Return the per-cell signature scores for signature: <sig_name> Data comes from matrix

+

Response structure:

+
    {
+        'cells': [list of str,  cell ids...],
+        'values': [list of Number, per cell signature scores],
+    }
+
+
+

+GET: /Signature/Meta/ +

+

Return the per-cell meta-data values for variable: <sig_name> Data comes from dataframe

+

Response structure:

+
    {
+        'cells': [list of str,  cell ids...],
+        'values': [list of Number or string, per-cell meta-data values],
+    }
+
+
+

+GET: /Signature/Info/ +

+

Returns information associated with a signature Data comes from

+

Response structure:

+
    {
+        'sigDict': { # signature-gene weights
+            'GeneName1': 1, 
+            'GeneName2': -1,
+            ...
+        },
+        'name': 'Signature Name',
+        'source': 'Signature source', # typically filename where signature was loaded from
+        'metaData': 'Signature description...', # second column in .gmt file
+        'geneImportance': { # signature-gene importance values
+            'GeneName1': .1,
+            'GeneName2': .01, 
+            ...
+        }
+    }
+
+
+

+GET: /Signature/Expression// +

+

Returns expression values for <sig_name> grouped by <cluster_var>. This is used to generate the gene x cluster heatmap in the bottom left Values are computed on the fly at the server

+

Response structure

+
{
+    'data': list of list of Number  (2d matrix, outer index is row index)
+    'sample_labels': column labels for the matrix in 'data'
+    'gene_labels': row labels for the matrix in 'data'
+}
+
+
+

+GET: /Proteins/<protein_name>/Values

+

Returns the per-cell protein expression values for <protein_name> Data comes from matrix

+

Response structure:

+
    {
+        'cells': [list of str,  cell ids...],
+        'values': [list of Number, per cell protein expression],
+    }
+
+
+

+GET: /FilterGroup/SigClusters/Normal

+

For each signature, describes the assignment of signatures to signature-clusters This is used to group signatures in the upper-left section

+

Response structure:

+
{
+    "Signature Name" (str): <cluster_number> (int),
+    ...
+}
+
+
+

+GET: /FilterGroup/SigClusters/Proteins

+

For each protein, describes the assignment of proteins to protein-clusters Proteins aren’t actually clustered in the interface. Every protein is assigned to cluster #1

+

Response structure:

+
{
+    "Protein Name" (str): 1,
+    ...
+}
+
+
+

+GET: /FilterGroup/SigClusters/Meta

+

For each meta-data variable, describes the assignment of each variable to meta-data clusters This is used when micropools are created to group factor variables with their expanded percent-value-per-micropool representations

+

Response structure:

+
{
+    "Metadata variable Name" (str): <cluster_number> (int),
+    ...
+}
+
+
+

+GET: /Projections//coordinates/ +

+

Returns the coordinates for projection <proj_name> in column <proj_col> Since the scatter plot can show more than just projects, this has been expanded to also return coordinates from the latent space or other meta-data variables. <proj_name> can come from names in , or can be “Meta Data” to refer to or “Latent Space” to refer to . In either case <proj_name> should refer to an associated column.

+

Response structure:

+

List of list of [coordinate, 'cell id']

+
[
+    [coordinate (float): 'cell id' (str)],
+    [coordinate (float): 'cell id' (str)],
+    [coordinate (float): 'cell id' (str)],
+    ...
+[
+
+
+

+GET: /Projections/list

+

Returns information on projections and other variables that can be plotted in the main scatter-plot panel. Used to create the dropdown menus.

+

Response structure:

+

Dictionary where keys are the name of projections/meta data/latent space and the values are a list of the associated columns

+
{
+    'projection_name_1': list of column names in the projection,
+    'projection_name_2': list of column names in the projection,
+    'Meta Data': list of numeric meta-data variables,
+    'Latent Space': list of column names in the latent space
+}
+
+
+

+GET: /PearsonCorr/Normal

+

Gets information for the LC Annotator - the correlation of each signature with each latent component

+

Response structure:

+
{
+    "zscores": list of list of correlation coefficients (N signatures x N components),
+    "pvals": list of list of p-values (N signatures x N components),
+    "proj_labels": list of latent space column names in the same order as columns of 'zscores'/'pvals',
+    "sig_labels": list of signature names in the same order as columns of 'zscores'/'pvals',
+}
+
+
+

+GET: /PearsonCorr/Proteins

+

Gets information for the LC Annotator - the correlation of each protein with each latent component

+

Response structure:

+
{
+    "zscores": list of list of correlation coefficients (N proteins x N components),
+    "pvals": list of list of p-values (N proteins x N components),
+    "proj_labels": list of latent space column names in the same order as columns of 'zscores'/'pvals',
+    "sig_labels": list of proteins names in the same order as columns of 'zscores'/'pvals',
+}
+
+
+

+GET: /PearsonCorr/Meta

+

Gets information for the LC Annotator - the correlation of each numeric meta-data variable with each latent component

+

Response structure:

+
{
+    "zscores": list of list of correlation coefficients (N variables x N components),
+    "pvals": list of list of p-values (N variables x N components),
+    "proj_labels": list of latent space column names in the same order as columns of 'zscores'/'pvals',
+    "sig_labels": list of variables names in the same order as columns of 'zscores'/'pvals',
+}
+
+
+

+POST: /DE

+

Requests a differential expression analysis from the server.

+

Determines the set of cells used for the numerator (i.e. _num or _n) and for the denominator (i.e. _denom or _d)

+

Examples:

+
    +
  • To select cells in cluster 5 for the numerator set 'type_n': 'meta', 'subtype_n': 'cluster', 'group_num': 'Cluster 5' +
  • +
  • To select cells in a saved manual selection for the numerator set 'type_n': 'saved_selection', 'group_num': 'name_of_selection' +
  • +
  • To select a specific set of cell ids for the numerator set 'type_n': 'current', 'group_num': list of cell ids +
  • +
+

Posted data structure:

+
{
+    'type_n': either 'current', 'meta', or 'saved_selection'
+    'type_d':  either 'remainder', 'meta', or 'saved_selection'
+    'subtype_n': which meta-data variable to group cells by if type_n is 'meta'
+    'subtype_d': which meta-data variable to group cells by if type_d is 'meta'
+    'group_num': list of cell ids (if type_n is 'current') OR name of saved selection (if type_n is 'saved_selection')
+                 OR value of categorical meta-data variable (if type_n is 'meta')
+    'group_denom': same behavior as 'group_num'
+    'min_cells': (int) pre-filter genes expressed in less than this many cells
+    'subsample_groups': (bool), whether or not to subsample each comparison group first
+    'subsample_N': (int) size of the groups after subsampling.  Ignored if 'subsample_groups' is false
+}
+

Response structure:

+

DE Results table with {‘column name’ -> list of values}

+
{
+    'Feature': list of feature (gene or protein) names
+    'Type': list of either 'Gene' or 'Protein' 
+    'logFC': list of log-fold-change values
+    'stat': list of AUC values
+    'pval': list of FDR-corrected p-values
+}
+
+
+

+GET: /Clusters/MetaLevels

+

The display of the top-left area for signatures/proteins/meta-data depends on the selected grouping variable in the dropdown. Commands scoped to a particular grouping variable are nested under “/Clusters”.

+

This call returns a list of grouping variables and the levels/categories associated with them.

+

Response structure:

+
    {
+        'name of variable': [list of str - values this variable can take],
+        'name of variable': [list of str - values this variable can take],
+        'Cell Type': ['CD4+', 'CD8+', 'NK'],   # For example
+    }
+
+
+

+GET: /Clusters//SigProjMatrix/Normal +

+

Returns matrices consisting of test statistic and p-value for 1 vs. all differential signature tests and for local autocorrelation.

+

First column is “Score” and values are for local autocorrelation. Statistic is the 1 - Geary’s C.

+

Other columns are for 1 vs. all differential signature tests for each value in the selected grouping variable in the dropdown. Test statistic are the AUC values from a ranksums test. P-values also from this test.

+

Response structure:

+
    {
+        'sig_labels': [list of str]  # Rows of matrices in zscores and pvals
+        'proj_labels': [list of str] # Columns of the matrices in zscores and pvals
+        'zscores': [list of list of number]  # signatures x cell group (+ 'Score') matrix of test statistics
+        'pvals': [list of list of number] # signatures x cell group (+ 'Score') matrix of p-values
+    }
+
+
+

+GET: /Clusters//SigProjMatrix/Meta +

+

Same as /Clusters/<cluster_variable>/SigProjMatrix/Normal, but for meta-data variables

+

Response structure:

+
    {
+        'sig_labels': [list of str]  # Rows of matrices in zscores and pvals
+        'proj_labels': [list of str] # Columns of the matrices in zscores and pvals
+        'zscores': [list of list of number]  # variables x cell group (+ 'Score') matrix of test statistics
+        'pvals': [list of list of number] # variables x cell group (+ 'Score') matrix of p-values
+    }
+
+
+

+GET: /Clusters//ProteinMatrix +

+

Same as /Clusters/<cluster_variable>/SigProjMatrix/Normal, but for CITE proteins

+

Response structure:

+
    {
+        'sig_labels': [list of str]  # Rows of matrices in zscores and pvals
+        'proj_labels': [list of str] # Columns of the matrices in zscores and pvals
+        'zscores': [list of list of number]  # proteins x cell group (+ 'Score') matrix of test statistics
+        'pvals': [list of list of number] # proteins x cell group (+ 'Score') matrix of p-values
+    }
+
+
+

+GET: /Clusters/list

+

Not used anymore

+
+
+

+GET: /Clusters//Cells +

+

Not used anymore

+
+
+

+GET: /Expression/Genes/List

+

Retrieves a list of genes for which expression values can be plotted. Used to populate the dropdown in the ‘Genes’ tab.

+

Response structure:

+
[list of str - gene names]
+
+
+

+GET: /Expression/Gene/ +

+

Gets the per-cell expression of the gene specified by <gene_name>. Expression values returned are on a log2 scale.

+

Response structure: Items in ‘values’ correspond to the cells in ‘cells’ in order

+
    {
+        'cells': [list of str - cell identifiers],
+        'values': [list of number - gene expression values],
+    }
+
+
+

+GET: /Cell//Meta +

+

Retrieves meta-data information for an individual cell specified by <cell_id>

+

Response structure:

+
    {
+        'variable name': value (str or number),
+        'variable name': value (str or number),
+        'variable name': value (str or number),
+        ...
+    }
+
+
+

+POST: /Cells/Meta

+

Retrieves meta-data information for a group of cells

+

Posted data structure

+
[list of cell id]
+

Response structure:

+
    {
+        'numeric': {
+            '<variable name>': {
+                'Min': <min value>,
+                'Median': <median value>,
+                'Max': <max value>,
+            },
+            '<variable name>': {
+                'Min': <min value>,
+                'Median': <median value>,
+                'Max': <max value>,
+            },
+            # Repeat for additional numeric meta-data variables
+        },
+        'factor': {
+            '<variable name>': {
+                '<factor level 1>': number (proportion of cells assigned to this level,
+                '<factor level 2>': number (proportion of cells assigned to this level,
+                '<factor level 3>': number (proportion of cells assigned to this level,
+                ...
+            }
+            # Repeat for additional factor meta-data variables
+        }
+    }
+
+
+

+GET: /Cells/Selections

+

Used when loading a selection of cells.

+

Response structure:

+
[list of str - names of saved selections]
+
+
+

+GET: /Cells/Selections/ +

+

Retrieves the cells associated with the selection, <selection_id>

+

Response structure:

+
[list of str - cell ids in the indicated cell selection]
+
+
+

+POST: /Cells/Selections/ +

+

Saves a cell selection with name <selection_id>

+
[list of str - cell ids to be assigned to this cell selection]
+
+
+

+GET: /Tree/Projections/list

+

Get the list of different tree layouts that are available Used to populate the ‘Projection’ dropdown under the ‘Trajectories’ view

+

R version: returns the names of

+

Response structure:

+
[list of str - names of tree projections]
+
+
+

+GET: /Tree/Projections//coordinates +

+

Returns the coordinates for the tree layout <proj_name> in addition to the position of individual cells

+

Response structure:

+
    [
+        [
+            [<x val>, <y val>, <cell id>],  # coordinates for individual cells
+            [<x val>, <y val>, <cell id>],
+            [<x val>, <y val>, <cell id>],
+            ...
+        ],
+        [
+            [<x val>, <y val>],  # coordinates for internal tree nodes
+            [<x val>, <y val>], 
+            [<x val>, <y val>], 
+            ...
+        ],
+        [list of list of number]  # 0/1 adjacency matrix for internal tree nodes
+    ]
+
+
+

+GET: /Tree/SigProjMatrix/Normal

+

Returns matrices consisting of test statistic and p-value trajectory autocorrelation Format is similar to /Clusters/<cluster_variable>/SigProjMatrix/Normal, but without the 1 vs all test results.

+

‘zscores’ and ‘pvals’ matrices have just a single column

+

Response structure:

+
    {
+        'sig_labels': [list of str]  # Rows of matrices in zscores and pvals
+        'proj_labels': ["Score"],
+        'zscores': [list of list of number]  # signatures x 1 matrix of test statistics
+        'pvals': [list of list of number] # signatures x 1 matrix of p-values
+    }
+
+
+

+GET: /Tree/SigProjMatrix/Meta

+

Same as /Tree/SigProjMatrix/Normal but for meta-data variables

+

‘zscores’ and ‘pvals’ matrices have just a single column

+

Response structure:

+
    {
+        'sig_labels': [list of str]  # Rows of matrices in zscores and pvals
+        'proj_labels': ["Score"],
+        'zscores': [list of list of number]  # variables x 1 matrix of test statistics
+        'pvals': [list of list of number] # variables x 1 matrix of p-values
+    }
+
+
+

+GET: /Tree/ProteinMatrix

+

Same as /Tree/SigProjMatrix/Normal but for CITE protein expression values

+

‘zscores’ and ‘pvals’ matrices have just a single column

+

Response structure:

+
    {
+        'sig_labels': [list of str]  # Rows of matrices in zscores and pvals
+        'proj_labels': ["Score"],
+        'zscores': [list of list of number]  # proteins x 1 matrix of test statistics
+        'pvals': [list of list of number] # proteins x 1 matrix of p-values
+    }
+
+ + +
+ + + +
+ + + +
+ + +
+

Site built with pkgdown 1.6.1.

+
+ +
+
+ + + + + + + + diff --git a/docs/LICENSE-text.html b/docs/LICENSE-text.html index 536364b6..6f105d34 100644 --- a/docs/LICENSE-text.html +++ b/docs/LICENSE-text.html @@ -81,7 +81,7 @@ VISION - 2.1.0 + 3.0.0 @@ -89,7 +89,7 @@