Skip to content

Commit 5c085cb

Browse files
authored
Merge pull request #51 from YosefLab/staging
Merge Staging to Master
2 parents 96d671e + a67b824 commit 5c085cb

File tree

166 files changed

+2483
-591
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

166 files changed

+2483
-591
lines changed

.travis.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ cache: packages
55

66
r:
77
- bioc-release
8-
- bioc-devel
8+
- devel
9+
- oldrel
10+
- 3.4
911

1012
sudo: false
1113

DESCRIPTION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: VISION
22
Title: Functional interpretation of single cell RNA-seq latent manifolds
3-
Version: 1.0.1
3+
Version: 1.1.0
44
Authors@R: c(person("Matt", "Jones", email = "mattjones315@gmail.com", role = c("aut", "cre")),
55
person("David", "Detomaso", email = "david.detomaso@berkeley.edu", role = c("aut", "cre")),
66
person("Tal", "Ashuach", email = "tal_ashuach@berkeley.edu", role = c("aut")),
@@ -13,7 +13,6 @@ Imports:
1313
fastICA,
1414
igraph,
1515
jsonlite,
16-
jug,
1716
loe,
1817
logging,
1918
parallel,
@@ -22,6 +21,7 @@ Imports:
2221
matrixStats,
2322
mclust,
2423
methods,
24+
plumber,
2525
Rcpp,
2626
rsvd,
2727
stats,

NAMESPACE

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ exportMethods(saveAndViewResults)
2525
exportMethods(viewResults)
2626
import(Matrix)
2727
import(Rcpp)
28-
import(jug)
2928
import(loe)
3029
import(logging)
3130
import(methods)
@@ -65,6 +64,8 @@ importFrom(mclust,Mclust)
6564
importFrom(mclust,mclustBIC)
6665
importFrom(parallel,mclapply)
6766
importFrom(pbmcapply,pbmclapply)
67+
importFrom(plumber,forward)
68+
importFrom(plumber,plumber)
6869
importFrom(rsvd,rsvd)
6970
importFrom(stats,chisq.test)
7071
importFrom(stats,kmeans)

NEWS.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
# VISION 1.1.0
2+
3+
* Added differential expression testing to the output report
4+
* Thanks to @Yanay1 (Yanay Rosen)
5+
* Added gene-signature importance calculation
6+
* More flexible projection plotting
7+
* Added UMAP as a projection method
8+
19
# VISION 1.0.1
210

311
* Bugfixes related to caching in the output report

R/AllClasses.R

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,11 @@ Vision <- setClass("Vision",
9898
projection_methods = "character",
9999
Projections = "list",
100100
TrajectoryProjections = "list", # list of TrajectoryProjection
101+
SigGeneImportance = "list",
101102
pools = "list",
102103
inputProjections = "list",
103104
name = "character",
105+
num_neighbors = "numericORNULL",
104106
latentSpace = "matrix",
105107
latentTrajectory = "Trajectory",
106108
version = "numeric",
@@ -126,9 +128,11 @@ Vision <- setClass("Vision",
126128
projection_methods = character(),
127129
Projections = list(),
128130
TrajectoryProjections = list(),
131+
SigGeneImportance = list(),
129132
pools = list(),
130133
inputProjections = list(),
131134
name = "",
135+
num_neighbors = NULL,
132136
latentSpace = matrix(NA, 1, 1),
133137
latentTrajectory = NULL,
134138
version = 1.1,

R/AnalysisFunctions.R

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ clusterCells <- function(object) {
1313
n_workers <- getOption("mc.cores")
1414
n_workers <- if (is.null(n_workers)) 2 else n_workers
1515

16+
K <- min(object@num_neighbors, 30)
1617
kn <- ball_tree_knn(res,
17-
min(round(sqrt(nrow(res))), 30),
18+
K,
1819
n_workers)
1920

2021
cl <- louvainCluster(kn, res)
@@ -67,7 +68,8 @@ poolCells <- function(object,
6768
cellsPerPartition = object@cellsPerPartition,
6869
filterInput = object@projection_genes,
6970
filterThreshold = object@threshold,
70-
latentSpace = object@latentSpace)
71+
latentSpace = object@latentSpace,
72+
K = object@num_neighbors)
7173

7274
object@pools <- pools
7375
}
@@ -232,6 +234,82 @@ calcSignatureScores <- function(object,
232234
return(object)
233235
}
234236

237+
238+
#' calculate gene-signature importance
239+
#'
240+
#' For each signature, the contribution of each gene to the signature score
241+
#' is evaluated by calculating the covariance between signature scores and expression
242+
#' The correlation of genes with a negative sign in the signature are inverted.
243+
#'
244+
#' @importFrom pbmcapply pbmclapply
245+
#' @importFrom matrixStats colSds
246+
#' @importFrom matrixStats rowSds
247+
#'
248+
#' @param object the VISION object
249+
#' @return the VISION object, with SigGeneImportance slot populated
250+
evalSigGeneImportance <- function(object){
251+
252+
message("Evaluating signature-gene importance...\n")
253+
254+
sigScores <- object@sigScores
255+
256+
if (length(object@sigData) == 0) {
257+
object@SigGeneImportance <- list()
258+
return(object)
259+
}
260+
261+
if (length(sigScores) <= 1){
262+
stop(
263+
sprintf("Signature scores have not yet been computed. `calcSignatureScores` must be run before running `evalSigGeneImportance`")
264+
)
265+
}
266+
267+
normExpr <- getNormalizedCopy(object@exprData, object@sig_norm_method)
268+
269+
# Center each column of sigScores first
270+
271+
mu <- colMeans(sigScores)
272+
273+
sigScores <- t(sigScores)
274+
sigScores <- (sigScores - mu)
275+
sigScores <- t(sigScores)
276+
277+
# Center each row of normExpr
278+
mu <- rowMeans(normExpr)
279+
280+
normExpr <- (normExpr - mu)
281+
282+
# Compute Covariances
283+
sigData <- object@sigData
284+
285+
sigGene <- function(signame) {
286+
sigdata <- sigData[[signame]]
287+
288+
genes <- sigdata@sigDict
289+
290+
sigvals <- sigScores[, signame]
291+
292+
geneIndices <- match(names(genes), rownames(normExpr))
293+
294+
corr <- sigGeneInner(sigvals, normExpr, geneIndices)
295+
296+
names(corr) <- names(genes)
297+
298+
corr <- corr * genes
299+
300+
return(corr)
301+
}
302+
303+
sigs <- colnames(sigScores)
304+
res <- pbmclapply(setNames(sigs, sigs), sigGene)
305+
306+
object@SigGeneImportance <- res
307+
308+
309+
return(object)
310+
}
311+
312+
235313
#' Computes the latent space of the expression matrix using PCA
236314
#'
237315
#' @param object the VISION object for which compute the latent space
@@ -302,13 +380,24 @@ generateProjections <- function(object) {
302380
projections <- generateProjectionsInner(object@exprData,
303381
object@latentSpace,
304382
projection_genes = object@projection_genes,
305-
projection_methods = object@projection_methods)
383+
projection_methods = object@projection_methods,
384+
K = object@num_neighbors)
306385

307386
# Add inputProjections
308387
for (proj in names(object@inputProjections)){
309388
projections[[proj]] <- object@inputProjections[[proj]]
310389
}
311390

391+
# Make sure all projections have column names
392+
n <- names(projections)
393+
projections <- lapply(setNames(n, n), function(pname){
394+
proj <- projections[[pname]]
395+
if (is.null(colnames(proj))){
396+
colnames(proj) <- paste0(pname, "-", seq_len(ncol(proj)))
397+
}
398+
return(proj)
399+
})
400+
312401
object@Projections <- projections
313402

314403
message("")
@@ -337,7 +426,8 @@ analyzeLocalCorrelations <- function(object, signatureBackground = NULL) {
337426
object@latentSpace,
338427
object@sigScores,
339428
object@metaData,
340-
signatureBackground)
429+
signatureBackground,
430+
object@num_neighbors)
341431

342432
message("Clustering signatures...\n")
343433
sigClusters <- clusterSignatures(object@sigScores,

R/Microclusters.R

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#' If greater than 1, this specifies the number of cells in which a gene must be detected
1919
#' for it to be used when computing PCA. If less than 1, this instead specifies the proportion of cells needed
2020
#' @param latentSpace (Optional) Latent space to be used instead of PCA numeric matrix cells x components
21+
#' @param K Number of neighbors to use for finding pools.
2122
#' @importFrom Matrix tcrossprod
2223
#' @importFrom Matrix rowMeans
2324
#' @return pooled cells - named list of vectors - cells in each supercell
@@ -26,7 +27,7 @@ applyMicroClustering <- function(
2627
exprData, cellsPerPartition=10,
2728
filterInput = "fano",
2829
filterThreshold = round(ncol(exprData) * 0.05),
29-
latentSpace = NULL) {
30+
latentSpace = NULL, K=round(sqrt(ncol(exprData)))) {
3031

3132
if (is.data.frame(exprData)){
3233
exprData <- data.matrix(exprData)
@@ -92,7 +93,7 @@ applyMicroClustering <- function(
9293
n_workers <- if (is.null(n_workers)) 2 else n_workers
9394

9495
kn <- ball_tree_knn(res,
95-
min(round(sqrt(nrow(res))), 30),
96+
min(K, 30),
9697
n_workers)
9798

9899
cl <- louvainCluster(kn, res)

R/Projections.R

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@ registerMethods <- function(projection_methods, numCells) {
2525
#' @param latentSpace numeric matrix cells x components
2626
#' @param projection_genes character vector of gene names to use for projections
2727
#' @param projection_methods character vector of projection methods to use
28+
#' @param K Number of neighbors to use in projections.
2829
#' @return list of Projection objects
29-
generateProjectionsInner <- function(expr, latentSpace, projection_genes=NULL, projection_methods = NULL) {
30+
generateProjectionsInner <- function(expr, latentSpace, projection_genes=NULL, projection_methods = NULL, K = round(sqrt(ncol(expr)))) {
3031

3132
NUM_CELLS <- nrow(latentSpace)
3233
methodList <- registerMethods(projection_methods, NUM_CELLS)
3334

3435
projections <- list()
3536

36-
projections[["PCA: 1,2"]] <- latentSpace[, c(1, 2)]
37-
projections[["PCA: 1,3"]] <- latentSpace[, c(1, 3)]
38-
projections[["PCA: 2,3"]] <- latentSpace[, c(2, 3)]
37+
projections[["Latent Space"]] <- latentSpace
38+
3939
N <- length(methodList)
4040
for (i in seq_len(N)){
4141
method <- names(methodList)[i]
@@ -55,6 +55,9 @@ generateProjectionsInner <- function(expr, latentSpace, projection_genes=NULL, p
5555

5656
res <- methodList[[method]](exprData)
5757
projections[[method]] <- res
58+
} else if (method == "UMAP") {
59+
res <- methodList[[method]](t(latentSpace), K)
60+
projections[[method]] <- res
5861
} else { ## run on reduced data
5962
res <- methodList[[method]](t(latentSpace))
6063
projections[[method]] <- res
@@ -248,10 +251,11 @@ applySpectralEmbedding <- function(exprData) {
248251
#' Performs UMAP on data
249252
#'
250253
#' @param exprData Expression data, NUM_GENES x NUM_SAMPLES
251-
#'
254+
#' @param K Number of neighbors to use in UMAP projection.
252255
#' @return Reduced data NUM_SAMPLES x NUM_COMPONENTS
253-
applyUMAP <- function(exprData) {
256+
applyUMAP <- function(exprData, K) {
254257

258+
print(requireNamespace('uwot'))
255259
if (!requireNamespace("uwot", quietly = TRUE)){
256260
stop("Package \"uwot\" needed to run UMAP. Please install it using:\n\n devtools::install_github(\"jlmelville/uwot\")\n\n",
257261
call. = FALSE)
@@ -261,7 +265,7 @@ applyUMAP <- function(exprData) {
261265
n_workers <- getOption("mc.cores")
262266
n_workers <- if (is.null(n_workers)) 2 else n_workers
263267
res <- uwot::umap(
264-
ndataT, n_neighbors = round(sqrt(ncol(exprData))),
268+
ndataT, n_neighbors = K,
265269
n_threads = n_workers, ret_nn = T
266270
)
267271
res <- res$embedding
@@ -389,7 +393,7 @@ clipBottom <- function(x, mi) {
389393
#' @importFrom Matrix sparseMatrix
390394
#' @importFrom matrixStats rowMaxs
391395
#' @param object matrix to use for KNN
392-
#' @param K number of neighbors to compute this for
396+
#' @param K Number of neighbors to consider.
393397
#' @return a list of two items:
394398
#' indices: matrix, cells X neighbors
395399
#' Each row specifies indices of nearest neighbors
@@ -398,6 +402,7 @@ clipBottom <- function(x, mi) {
398402
setMethod("computeKNNWeights", signature(object = "matrix"),
399403
function(object, K = round(sqrt(nrow(object)))) {
400404

405+
print(K)
401406
n_workers <- getOption("mc.cores")
402407
n_workers <- if (is.null(n_workers)) 2 else n_workers
403408

@@ -406,6 +411,7 @@ setMethod("computeKNNWeights", signature(object = "matrix"),
406411
d <- k[[2]]
407412

408413
sigma <- rowMaxs(d)
414+
sigma[sigma == 0] <- 1.0 # Can happen if all neighbors at same point as cell
409415
sparse_weights <- exp(-1 * (d * d) / sigma ^ 2)
410416

411417
# Normalize row sums = 1

R/RcppExports.R

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,11 @@ multMat <- function(X, Y) {
4141
.Call('_VISION_multMat', PACKAGE = 'VISION', X, Y)
4242
}
4343

44+
sigGeneInner <- function(sigScores, exp, geneIndices) {
45+
.Call('_VISION_sigGeneInner', PACKAGE = 'VISION', sigScores, exp, geneIndices)
46+
}
47+
48+
wilcox_subset <- function(vals, indicesA, indicesB) {
49+
.Call('_VISION_wilcox_subset', PACKAGE = 'VISION', vals, indicesA, indicesB)
50+
}
51+

0 commit comments

Comments
 (0)