#' Wrapper class for gene expression object for JSON.
#'
#' @param data numeric matrix
#' @param sample_labels Labels of samples in expression data
#' @param gene_labels Lables of genes in expression data
#' @return ServerExpression object
ServerExpression <- function(data, sample_labels, gene_labels) {
.Object <- new("ServerExpression", data=data,
sample_labels=sample_labels,
gene_labels=gene_labels)
return(.Object)
}
#' Wrapper class for Signature Projection Matrix
#'
#' @param zscores numeric matrix
#' @param pvals numeric matrix
#' @param proj_labels Projection names
#' @param sig_labels Names of signatures
#' @return ServerSigProjMatrix object
ServerSigProjMatrix <- function(zscores, pvals, proj_labels, sig_labels) {
.Object <- new("ServerSigProjMatrix",
zscores = zscores, pvals = pvals,
proj_labels = proj_labels, sig_labels = sig_labels)
return(.Object)
}
#' Converts Signature object to JSON
#' @importFrom jsonlite toJSON
#' @param sig Signature object
#' @param geneImportance named numeric vector with gene correlations
#' @return JSON formatted Signature object.
signatureToJSON <- function(sig, geneImportance) {
# Pass in a Signature object from an R Object to be converted into a JSON object
out <- list()
out$sigDict <- as.list(sig@sigDict)
out$name <- sig@name
out$source <- sig@source
out$metaData <- sig@metaData
out$geneImportance <- as.list(geneImportance)
json <- toJSON(
out, force = TRUE, pretty = TRUE,
auto_unbox = TRUE, digits = I(4))
return(json)
}
#' Converts row of signatures score matrix to JSON
#' @importFrom jsonlite toJSON
#' @param names character vector of labels for signatures
#' @param values numeric vector for signature values
#' @return Signature scores list to JSON, with names of each entry that of the list names
sigScoresToJSON <- function(names, values) {
out <- list(cells = names, values = values)
json <- toJSON(
out, force = TRUE, pretty = TRUE,
auto_unbox = TRUE, digits = I(4)
)
return(json)
}
#' Converts a projection into a JSON object mapping each sample to a projection coordinate.
#' @importFrom jsonlite toJSON
#' @param p Projection coordinate data (NUM_SAMPLES x NUM_COMPONENTS)
#' @return JSON object mapping each sample to a projection coordinate.
coordinatesToJSON <- function(p) {
coord <- as.data.frame(p)
# This switching is needed because toJSON will drop row labels
# if they are integers for some reason
coord["sample_labels"] <- rownames(coord)
rownames(coord) <- NULL
json <- toJSON(
coord, force = TRUE, pretty = TRUE,
auto_unbox = TRUE, dataframe = "values",
digits = I(4)
)
return(json)
}
#' Converts a sigProjMatrix from an R Object to a JSON object
#' @importFrom jsonlite toJSON
#' @param sigzscores Matrix of signature z-scores
#' @param sigpvals Matrix of signature p-values
#' @param sigs Signatures to subset zscores/pvalues
#' @return Subsetted sigProjMatrix converted to JSON
sigProjMatrixToJSON <- function(sigzscores, sigpvals, sigs) {
sigs <- intersect(sigs, rownames(sigzscores))
sigpvals <- sigpvals[sigs, , drop = FALSE]
sigzscores <- sigzscores[rownames(sigpvals), , drop = FALSE]
sigzscores <- sigzscores[, colnames(sigpvals), drop = FALSE]
sSPM <- ServerSigProjMatrix(unname(sigzscores), unname(sigpvals), colnames(sigpvals), rownames(sigpvals))
json <- toJSON(sSPM, force = TRUE, pretty = TRUE, digits = I(4))
return(json)
}
#' convert perason correlation coeffcients between PCs and signatures into a JSON object
#' @param pc the pearson correlation coefficients matrix
#' @param sigs the signatures of interest
#' @return Subsetted pearson correlations converted to JSON
pearsonCorrToJSON <- function(pc, sigs) {
pc <- pc[sigs, , drop = FALSE]
cn <- colnames(pc)
if (is.null(cn)){
cn <- paste0("Comp ", seq_len(ncol(pc)))
}
sPC <- ServerSigProjMatrix(unname(pc), unname(pc), cn, sigs)
json <- toJSON(sPC, force = TRUE, pretty = TRUE, digits = I(4))
return(json)
}
compressJSONResponse <- function(req, res){
res$headers[["Content-type"]] <- "application/json"
if (!is.null(req$HTTP_ACCEPT_ENCODING) &&
grepl("gzip", req$HTTP_ACCEPT_ENCODING, ignore.case = TRUE)
){
res$setHeader("Content-Encoding", "gzip")
GZIP_HEADER <- as.raw(c(31, 139, 8, 0, 0, 0, 0, 0, 4, 3))
compressed <- memCompress(charToRaw(res$body))
compressed <- compressed[-c(1, 2)]
compressed <- compressed[- (
(length(compressed) - 3):length(compressed)
)]
compressed <- c(GZIP_HEADER, compressed)
res$body <- compressed
}
}
#' Lanch the server
#' @importFrom jsonlite fromJSON
#' @importFrom utils browseURL URLdecode stack
#' @importFrom plumber plumber forward
#' @importFrom Matrix rowMeans
#' @importFrom stats dist
#' @importFrom stats hclust
#' @importFrom stats setNames
#' @importFrom mime guess_type
#' @param object Vision object
#' @param port The port on which to serve the output viewer. If omitted, a
#' random port between 8000 and 9999 is chosen.
#' @param host The host used to serve the output viewer. If omitted, "127.0.0.1"
#' is used.
#' @param browser Whether or not to launch the web browser
#' @return object
launchServer <- function(object, port=NULL, host=NULL, browser=TRUE) {
if (is.null(port)) {
port <- sample(8000:9999, 1)
}
if (is.null(host)) {
host <- "127.0.0.1"
}
# Make sure all projections have column names
projections <- object@Projections
n <- names(projections)
projections <- lapply(setNames(n, n), function(pname){
proj <- projections[[pname]]
if (is.null(colnames(proj))){
colnames(proj) <- paste0(pname, "-", seq_len(ncol(proj)))
}
return(proj)
})
if (object@version < 1.11 && "Latent Space" %in% names(projections)){
projections[["Latent Space"]] <- NULL
}
object@Projections <- projections
# Make sure latent space columns have names
if (is.null(colnames(object@LatentSpace))) {
colnames(object@LatentSpace) <- paste0("Comp ", seq_len(ncol(object@LatentSpace)))
}
# Ensure the 'Viewer' list is fully initialized
if (!("selections" %in% names(object@Viewer))){
object@Viewer[["selections"]] <- list()
}
if (!("de_cache" %in% names(object@Viewer))){
object@Viewer[["de_cache"]] <- list()
}
# Load the static file whitelist
whitelist_file <- system.file("html_output/whitelist.txt",
package = "VISION")
static_whitelist <- scan(whitelist_file, what = "",
quiet = TRUE)
url <- paste0("http://", host, ":", port, "/Results.html")
message(paste("Navigate to", url, "in a browser to interact with the app."))
if(browser){
browseURL(url)
}
# Define the API
pr <- plumber$new()
pr$filter("defaultHeaders", function(req, res){
res$setHeader("Cache-Control", "max-age=7200")
res$setHeader("Content-type", "application/json")
forward()
})
pr$handle("GET", "/Signature/Scores/<sig_name>",
function(req, res, sig_name) {
sigMatrix <- object@SigScores
name <- URLdecode(sig_name)
# For modules we've split up the up/down groups in signatures
upDown <- grepl("_UP$|_DOWN$", name, fixed=F)
if (upDown) {
name_subbed <- gsub("_UP$|_DOWN$", "", name)
}
if (name %in% colnames(sigMatrix)) {
values <- sigMatrix[, name]
names <- rownames(sigMatrix)
res$body <- sigScoresToJSON(names, values)
compressJSONResponse(req, res)
return(res)
} else if (name %in% colnames(object@ModScores)) {
sigMatrix <- object@ModScores
values <- sigMatrix[, name]
names <- rownames(sigMatrix)
res$body <- sigScoresToJSON(names, values)
compressJSONResponse(req, res)
return(res)
} else if (upDown && name_subbed %in% colnames(sigMatrix)) {
values <- sigMatrix[, name]
names <- rownames(sigMatrix)
res$body <- sigScoresToJSON(names, values)
compressJSONResponse(req, res)
return(res)
} #else if (grepl("_OVERLAP_", name, fixed=T)) {
# name_split <- strsplit(name, "_OVERLAP_")[[1]]
# if (length(name_split) != 2) {
# res$body <- out
# return(res)
# }
#
# # we might have a proper split now.
# name <- name_split[1]
# mod_name <- name_split[2]
#
#
# mod_genes <- names(object@modData[[mod_name]]@sigDict)
#
# upDown <- grepl("_UP$|_DOWN$", name, fixed=F)
# if (upDown) {
# name_subbed <- gsub("_UP$|_DOWN$", "", name)
# }
# if (name %in% colnames(sigMatrix)) {
# values <- sigMatrix[, name]
# names <- rownames(sigMatrix)
# res$body <- sigScoresToJSON(names, values)
# compressJSONResponse(req, res)
# return(res)
# } else if (upDown && name_subbed %in% colnames(sigMatrix)) {
# values <- sigMatrix[, name]
# names <- rownames(sigMatrix)
# res$body <- sigScoresToJSON(names, values)
# compressJSONResponse(req, res)
# return(res)
# }
#
#
# }
else {
return("Signature does not exist!")
}
})
pr$handle("GET", "/Signature/Meta/<sig_name>",
function(req, res, sig_name) {
metaData <- object@metaData
name <- URLdecode(sig_name)
upDown <- grepl("_UP$|_DOWN$", name, fixed=F)
if (upDown) {
name_subbed <- gsub("_UP$|_DOWN$", "", name)
}
if (name %in% colnames(metaData)) {
names <- rownames(metaData)
values <- metaData[[name]]
res$body <- sigScoresToJSON(names, values)
compressJSONResponse(req, res)
return(res)
} else if (upDown && name_subbed %in% colnames(metaData)) {
names <- rownames(metaData)
values <- metaData[[name_subbed]]
res$body <- sigScoresToJSON(names, values)
compressJSONResponse(req, res)
} else {
return("Signature does not exist!")
}
})
pr$handle("GET", "/Signature/Info/<sig_name>",
function(req, res, sig_name){
signatures <- object@sigData
name <- URLdecode(sig_name)
out <- "Signature does not exist!"
upDown <- grepl("_UP$|_DOWN$", name, fixed=F)
if (upDown) {
name_subbed <- gsub("_UP$|_DOWN$", "", name)
}
if (name %in% names(signatures)) {
sig <- signatures[[name]]
if (.hasSlot(object, "SigGeneImportance")) {
geneImportance <- object@SigGeneImportance[[name]]
} else {
geneImportance <- sig@sigDict * 0
}
out <- signatureToJSON(sig, geneImportance)
} else if (upDown && name_subbed %in% names(signatures)) {
sig <- signatures[[name_subbed]]
directed <- sig@sigDict
if (grepl("_UP$", name, fixed=F)) {
genes <- names(directed[directed == 1])
} else {
genes <- names(directed[directed == -1])
}
directed <- directed[genes]
sig@sigDict <- directed
sig@name <- name
if (.hasSlot(object, "SigGeneImportance")) {
geneImportance <- object@SigGeneImportance[[name_subbed]][genes]
} else {
geneImportance <- sig@sigDict[genes] * 0
}
out <- signatureToJSON(sig, geneImportance)
} else if (name %in% names(object@modData)) {
signatures <- object@modData
sig <- signatures[[name]]
if (.hasSlot(object, "ModGeneImportance")) {
geneImportance <- object@ModGeneImportance[[name]]
} else {
geneImportance <- sig@sigDict * 0
}
out <- signatureToJSON(sig, geneImportance)
} # else if (grepl("_OVERLAP_", name, fixed=T)) {
# name_split <- strsplit(name, "_OVERLAP_")[[1]]
# if (length(name_split) != 2) {
# res$body <- out
# return(res)
# }
#
# # we might have a proper split now.
# name <- name_split[1]
# mod_name <- name_split[2]
#
#
# mod_genes <- names(object@modData[[mod_name]]@sigDict)
#
#
# upDown <- grepl("_UP$|_DOWN$", name, fixed=F)
# if (upDown) {
# name_subbed <- gsub("_UP$|_DOWN$", "", name)
# }
#
# if (name %in% names(signatures)) {
# sig <- signatures[[name]]
# intersect_mod <- intersect(mod_genes, names(sig@sigDict))
# sig@sigDict <- sig@sigDict[intersect_mod]
# if (.hasSlot(object, "SigGeneImportance")) {
# geneImportance <- object@SigGeneImportance[[name]][intersect_mod]
# } else {
# geneImportance <- sig@sigDict * 0
# }
# sig@name <- paste(name, " Overlap ", mod_name);
# out <- signatureToJSON(sig, geneImportance)
# } else if (upDown && name_subbed %in% names(signatures)) {
# sig <- signatures[[name_subbed]]
# intersect_mod <- intersect(mod_genes, names(sig@sigDict))
# sig@sigDict <- sig@sigDict[intersect_mod]
# directed <- sig@sigDict
# if (grepl("_UP$", name, fixed=F)) {
# genes <- names(directed[directed == 1])
# } else {
# genes <- names(directed[directed == -1])
# }
#
# genes <- intersect(genes, mod_genes)
# directed <- directed[genes]
# sig@sigDict <- directed
# sig@name <- paste(name, " Overlap ", mod_name);
#
# if (.hasSlot(object, "SigGeneImportance")) {
# geneImportance <- object@SigGeneImportance[[name_subbed]][genes]
# } else {
# geneImportance <- sig@sigDict[genes] * 0
# }
# out <- signatureToJSON(sig, geneImportance)
# }
#
#
# res$body <- out
# return(res)
# }
res$body <- out
return(res)
})
pr$handle("GET", "/Modules/LC",
function(req, res) {
# exclude overlap sigs
modules <- colnames(object@ModuleSignatureEnrichment$statistics)
lcs <- object@LocalAutocorrelation$Modules[sort(modules), ]
out <- toJSON(lcs)
res$body <- out
return(res)
}
)
pr$handle("GET", "/Signature/Expression/<sig_name>/<cluster_var>",
function(req, res, sig_name, cluster_var) {
all_names <- vapply(object@sigData, function(x) x@name, "")
all_names_mod <- vapply(object@modData, function(x) x@name, "")
name <- URLdecode(sig_name)
index <- match(name, all_names)
indexMod <- match(name, all_names_mod)
upDown <- grepl("_UP$|_DOWN$", name, fixed=F)
if (upDown) {
name_subbed <- gsub("_UP$|_DOWN$", "", name)
indexSubbed <- match(name_subbed, all_names)
}
if (is.na(index) && !upDown && !is.na(indexMod)) {
# received a module
sig <- object@modData[[indexMod]]
} else if (!is.na(index) && !upDown) {
# received a normal signature name with no up/downage
sig <- object@sigData[[index]]
} else if (upDown && !is.na(indexSubbed)){
# a up down signature name
sig <- object@sigData[[indexSubbed]]
directed <- sig@sigDict
if (grepl("_UP$", name, fixed=F)) {
genes <- names(directed[directed == 1])
} else {
genes <- names(directed[directed == -1])
}
sig@sigDict <- sig@sigDict[genes]
sig@name <- name
}# else if (grepl("_OVERLAP_", name, fixed=T)) {
# # yanay rnow
# # overlap inputted, re proccess
# name_split <- strsplit(name, "_OVERLAP_")[[1]]
# if (length(name_split) != 2) {
# return("Signature does not exist!")
# }
#
# # we might have a proper split now.
# overlap_name <- name
# name <- name_split[1]
# mod_name <- name_split[2]
#
#
# mod_genes <- names(object@modData[[mod_name]]@sigDict)
#
#
# upDown <- grepl("_UP$|_DOWN$", name, fixed=F)
# if (upDown) {
# name_subbed <- gsub("_UP$|_DOWN$", "", name)
# }
# index <- match(name, all_names)
# if (!is.na(index) && !upDown) {
# # received a normal signature name with no up/downage
# sig <- object@sigData[[index]]
# sig@sigDict <- sig@sigDict[intersect(mod_genes, names(sig@sigDict))]
# sig@name <- overlap_name
# } else if (upDown && !is.na(indexSubbed)){
# # a up down signature name
# sig <- object@sigData[[indexSubbed]]
# directed <- sig@sigDict
# if (grepl("_UP$", name, fixed=F)) {
# genes <- names(directed[directed == 1])
# } else {
# genes <- names(directed[directed == -1])
# }
# sig@sigDict <- sig@sigDict[intersect(genes, mod_genes)]
# sig@name <- overlap_name
# }
#
# }
else {
return("Signature does not exist!")
}
genes <- names(sig@sigDict)
expMat <- object@exprData[genes, ]
# transpose to aggregate
# note only agg over genes in sig
# on click gene plots gene
expMat <- t(expMat)
clusters <- object@metaData[rownames(expMat), cluster_var]
clusters <- as.factor(clusters)
onehot <- lapply(setNames(levels(clusters), levels(clusters)),
function(level) ifelse(clusters == level, 1, 0)
)
onehot <- t(do.call(cbind, onehot))
onehot <- onehot / rowSums(onehot)
x <- onehot %*% expMat
# get rid of aggregate artifact and redo transpose
y <- as.matrix(t(x))
rownames(y) <- colnames(expMat)
# z-score before cluster
rm <- matrixStats::rowMeans2(y)
rsd <- matrixStats::rowSds(y)
rsd[rsd == 0] <- 1.0
y <- (y - rm) / rsd
# Cluster the rows
d <- dist(y, method = "euclidean")
fit <- hclust(d, method = "average")
y <- y[fit$order, , drop = FALSE]
# Cluster the columns
d <- dist(t(y), method = "euclidean")
fit <- hclust(d, method = "average")
y <- y[, fit$order, drop = FALSE]
sExpr <- ServerExpression(y, colnames(y), rownames(y))
json_out <- toJSON(
sExpr, force = TRUE, pretty = TRUE, auto_unbox = TRUE,
digits = I(4)
)
res$body <- json_out
compressJSONResponse(req, res)
return(res)
})
pr$handle("GET", "/Proteins/<protein_name>/Values",
function(req, res, protein_name) {
proteinMatrix <- object@proteinData
name <- URLdecode(protein_name)
if (name %in% colnames(proteinMatrix)) {
values <- proteinMatrix[, name]
names <- rownames(proteinMatrix)
res$body <- sigScoresToJSON(names, values)
compressJSONResponse(req, res)
return(res)
} else {
return("Proteins does not exist!")
}
})
pr$handle("GET", "/FilterGroup/SigClusters/Normal", function(req, res) {
cls <- object@LocalAutocorrelation$Clusters
cls <- cls$Computed
res$body <- toJSON(cls, auto_unbox = TRUE)
return(res)
})
pr$handle("GET", "/FilterGroup/SigClusters/Modules", function(req, res) {
# Fix for signatures vs modules enrichment tab in genes panel
# yanay yanay
mods <- colnames(object@ModScores)
cls <- list()
module_names <- sort(colnames(object@ModuleSignatureEnrichment$p_vals))
for (mod in mods) {
if (grepl("_OVERLAP_", mod, fixed=T)) {
name_split <- strsplit(mod, "_OVERLAP_")[[1]]
sig_name <- name_split[1]
mod_name <- name_split[2]
idx <- match(mod_name, module_names)
cls[mod] = idx
} else {
idx = match(mod, module_names)
cls[mod] = idx
}
}
res$body <- toJSON(cls, auto_unbox = TRUE)
return(res)
})
pr$handle("GET", "/FilterGroup/SigClusters/Proteins", function(req, res) {
# Everything is in cluster 1
cls <- as.list(numeric(nrow(object@LocalAutocorrelation$Proteins)) + 1)
names(cls) <- rownames(object@LocalAutocorrelation$Proteins)
res$body <- toJSON(cls, auto_unbox = TRUE)
return(res)
})
pr$handle("GET", "/FilterGroup/SigClusters/Meta", function(req, res) {
cls <- object@LocalAutocorrelation$Clusters
cls <- cls$Meta
res$body <- toJSON(cls, auto_unbox = TRUE)
return(res)
})
pr$handle("GET", "/Projections/<proj_name>/coordinates/<proj_col>",
function(req, res, proj_name, proj_col) {
proj <- URLdecode(proj_name)
col <- URLdecode(proj_col)
if (proj %in% names(object@Projections)) {
coords <- object@Projections[[proj]][, col, drop = FALSE]
} else if (proj == "Meta Data") {
coords <- object@metaData[, col, drop = FALSE]
} else {
coords <- object@LatentSpace[, col, drop = FALSE]
}
res$body <- coordinatesToJSON(coords)
compressJSONResponse(req, res)
return(res)
})
pr$handle("GET", "/Projections/list",
function(req, res) {
proj_names <- lapply(object@Projections, colnames)
# Add in Latent Space
latentSpaceName <- getParam(object, "latentSpace", "name")
proj_names[[latentSpaceName]] <- colnames(object@LatentSpace)
# Add in Meta-Data if it's numeric
numericMeta <- vapply(seq_len(ncol(object@metaData)),
function(i) is.numeric(object@metaData[[i]]),
FUN.VALUE = TRUE)
numericMeta <- colnames(object@metaData)[numericMeta]
if (length(numericMeta) > 1){
proj_names[["Meta Data"]] <- numericMeta
}
proj_names <- proj_names[order(names(proj_names), decreasing = TRUE)] # hack to make tsne on top
res$body <- toJSON(proj_names)
return(res)
})
pr$handle("GET", "/Tree/Projections/list",
function(req, res) {
if (is.null(object@TrajectoryProjections)){
proj_names <- character()
} else {
proj_names <- names(object@TrajectoryProjections)
}
res$body <- toJSON(proj_names)
return(res)
})
pr$handle("GET", "/Tree/Projections/<proj_name>/coordinates",
function(req, res, proj_name) {
proj <- URLdecode(proj_name)
coords <- object@TrajectoryProjections[[proj]]@pData
C <- object@TrajectoryProjections[[proj]]@vData
W <- object@TrajectoryProjections[[proj]]@adjMat
coords <- as.data.frame(coords)
coords["sample_labels"] <- rownames(coords)
rownames(coords) <- NULL
out <- list(coords, C, W)
res$body <- toJSON(
out, force = TRUE, pretty = TRUE,
auto_unbox = TRUE, dataframe = "values", digits = I(4)
)
compressJSONResponse(req, res)
return(res)
})
pr$handle("GET", "/Tree/SigProjMatrix/Normal", function(req, res) {
metaData <- object@metaData
meta_n <- vapply(names(metaData),
function(metaName) is.numeric(metaData[, metaName]),
FUN.VALUE = TRUE)
meta_n <- colnames(metaData)[meta_n]
data <- object@TrajectoryAutocorrelation$Signatures
stat_s <- as.matrix(data[, "C", drop = F])
pval_s <- as.matrix(data[, "FDR", drop = F])
data <- object@TrajectoryAutocorrelation$Meta[meta_n, , drop = F]
stat_p <- as.matrix(data[, "C", drop = F])
pval_p <- as.matrix(data[, "FDR", drop = F])
stat <- rbind(stat_s, stat_p)
pval <- rbind(pval_s, pval_p)
colnames(stat) <- "Score"
colnames(pval) <- "Score"
res$body <- sigProjMatrixToJSON(stat, pval, sigs = rownames(stat))
return(res)
})
pr$handle("GET", "/Tree/ProteinMatrix", function(req, res) {
data <- object@TrajectoryAutocorrelation$Proteins
stat <- as.matrix(data[, "C", drop = F])
pval <- as.matrix(data[, "FDR", drop = F])
colnames(stat) <- "Score"
colnames(pval) <- "Score"
res$body <- sigProjMatrixToJSON(stat, pval, sigs = rownames(stat))
return(res)
})
pr$handle("GET", "/Tree/SigProjMatrix/Meta", function(req, res) {
data <- object@TrajectoryAutocorrelation$Meta
stat <- as.matrix(data[, "C", drop = F])
pval <- as.matrix(data[, "FDR", drop = F])
colnames(stat) <- "Score"
colnames(pval) <- "Score"
res$body <- sigProjMatrixToJSON(stat, pval, sigs = rownames(stat))
return(res)
})
pr$handle("GET", "/PearsonCorr/Normal", function(req, res) {
pc <- object@LCAnnotatorData@pearsonCorr
sigs <- rownames(pc)
res$body <- pearsonCorrToJSON(pc, sigs)
return(res)
})
pr$handle("GET", "/PearsonCorr/Proteins", function(req, res) {
pc <- object@LCAnnotatorData@pearsonCorrProteins
sigs <- rownames(pc)
res$body <- pearsonCorrToJSON(pc, sigs)
return(res)
})
pr$handle("GET", "/PearsonCorr/Meta", function(req, res) {
sigs <- colnames(object@metaData)
numericMeta <- vapply(sigs,
function(x) is.numeric(object@metaData[[x]]),
FUN.VALUE = TRUE)
sigs <- sigs[numericMeta]
pc <- object@LCAnnotatorData@pearsonCorr
res$body <- pearsonCorrToJSON(pc, sigs)
return(res)
})
pr$handle("GET", "/Expression/Genes/List", function(req, res) {
if (hasUnnormalizedData(object)) {
data <- object@unnormalizedData
} else {
data <- object@exprData
}
genes <- rownames(data)
res$body <- toJSON(genes, force = TRUE, pretty = TRUE)
compressJSONResponse(req, res)
return(res)
})
pr$handle("GET", "/Expression/Gene/<gene_name>",
function(req, res, gene_name) {
gene_name <- URLdecode(gene_name)
if (hasUnnormalizedData(object)) {
data <- object@unnormalizedData
} else {
data <- object@exprData
}
cells <- colnames(data)
data <- log2(as.numeric(data[gene_name, ]) + 1)
out <- list(cells = cells, values = data)
res$body <- toJSON(
out, force = TRUE, pretty = TRUE, auto_unbox = TRUE,
digits = I(4)
)
compressJSONResponse(req, res)
return(res)
})
pr$handle("GET", "/Clusters/list",
function(req, res) {
cluster_vars <- names(object@ClusterComparisons[[1]])
res$body <- toJSON(cluster_vars, force = TRUE, pretty = TRUE)
return(res)
})
pr$handle("POST", "/DE", function(req, res) {
# Params
body <- fromJSON(req$postBody)
exprData <- object@exprData
type_n <- body$type_n
type_d <- body$type_d
subtype_n <- body$subtype_n
subtype_d <- body$subtype_d
group_num <- body$group_num
group_denom <- body$group_denom
cells_min <- as.numeric(body$min_cells) # default 1
subsample_groups <- body$subsample_groups
subsample_cells_n <- as.numeric(body$subsample_N)
# Add option for test types
de_test_type <- body$de_test_type
# I want to skip caching a manual selection because the hash would be complicated
skip_cache <- FALSE;
if (type_n == "current") {
skip_cache <- TRUE;
} else {
# hash by the params as a string
hashed_body <- paste(type_n, type_d, subtype_n, subtype_d, group_num,
group_denom, subsample_cells_n, cells_min, subsample_groups, de_test_type, sep = " ")
}
if (skip_cache || is.null(object@Viewer$de_cache[[hashed_body]])) {
# The case where we know the de calculation is not cached, so we have to actually
# calculate it.
selections <- getSelections(object)
if (type_n == "current") {
cells_num <- unlist(strsplit(group_num, ","))
} else if (type_n == "saved_selection") {
cells_num <- selections[[group_num]]
} else if (type_n == "meta") {
cells_num <- rownames(object@metaData)[
which(object@metaData[[subtype_n]] == group_num)
]
} else {
print("ERROR! Num type unrecognized: " + type_n)
}
if (type_d == "remainder") {
cells_denom <- setdiff(colnames(exprData), cells_num)
} else if (type_d == "saved_selection") {
cells_denom <- selections[[group_denom]]
} else if (type_d == "meta") {
cells_denom <- rownames(object@metaData)[
which(object@metaData[[subtype_d]] == group_denom)
]
} else {
print("ERROR! Denom type unrecognized: " + type_d)
}
# subsample the numerator and denominator groups
if (subsample_groups) {
if (length(cells_num) > subsample_cells_n) {
# if possible, the numerator becomes a random sample of size subsample_cells_n
cells_num <- sample(cells_num, size = subsample_cells_n)
}
if (length(cells_denom) > subsample_cells_n) {
# if possible, the denominator becomes a random sample of size subsample_cells_n
cells_denom <- sample(cells_denom, size = subsample_cells_n)
}
}
# subset to only genes expressed in at least min cells
if (cells_min < length(colnames(exprData)) && cells_min > 0) {
exprDataSubset <- exprData[rowSums(exprData > 0) >= cells_min, , drop = FALSE]
} else {
exprDataSubset <- exprData
}
cluster_num <- match(cells_num, colnames(exprDataSubset))
cluster_denom <- match(cells_denom, colnames(exprDataSubset))
# Needed for sparse subsetting
cluster_num <- na.omit(as.numeric(cluster_num))
cluster_denom <- na.omit(as.numeric(cluster_denom))
# Calculate the DE using different types
if (de_test_type == "wilcox"){
out <- matrix_wilcox_cpp(exprDataSubset, cluster_num, cluster_denom)
} else {
# Use Seurat
# Some of these tests are not in the ui but included in case want to support counts
library(Seurat) # make sure it's loaded
use <- ""
if (de_test_type =="swilcox") {
use="wilcox"
} else if (de_test_type =="sbimod") {
use="bimod"
} else if (de_test_type =="sroc") {
use="roc"
} else if (de_test_type =="st") {
use="t"
} else if (de_test_type =="spoisson") {
use="poisson"
} else if (de_test_type =="snegbinom") {
use="negbinom"
} else if (de_test_type =="slr") {
use="LR"
} else if (de_test_type =="smast") {
use="MAST"
} else if (de_test_type =="sdeseq2") {
use="DESeq2"
}
cell_1_names <- colnames(exprDataSubset)[cluster_num]
cell_2_names <- colnames(exprDataSubset)[cluster_denom]
s_obj <- CreateAssayObject(exprDataSubset)
out <- FindMarkers(s_obj, cells.1=cell_1_names, cells.2=cell_2_names, test.use=use, min.pct = -1, min.cells.feature = 0, logfc.threshold = 0, verbose = TRUE)
out$pval <- out$p_val # Gets adjusted later
}
out$Feature <- rownames(out)
rownames(out) <- NULL
numMean <- rowMeans(exprDataSubset[, cluster_num])
denomMean <- rowMeans(exprDataSubset[, cluster_denom])
bias <- 1 / sqrt(length(cluster_num) * length(cluster_denom))
# filter for Seurat
lfc <- log2( (numMean + bias) / (denomMean + bias) )
out$logFC <- lfc[out$Feature]
out <- out[, c("Feature", "logFC", "pval"), drop = FALSE]
out$Type <- "Gene"
if (hasProteinData(object)) {
proteinData <- t(object@proteinData)[, colnames(exprData), drop = FALSE]
out_p <- matrix_wilcox_cpp(proteinData, cluster_num, cluster_denom)
out_p$pval <- p.adjust(out_p$pval, method = "fdr")
out_p$stat <- pmax(out_p$AUC, 1 - out_p$AUC)
out_p$Feature <- rownames(out_p)
rownames(out_p) <- NULL
numMean <- rowMeans(proteinData[, cluster_num])
denomMean <- rowMeans(proteinData[, cluster_denom])
bias <- 1 / sqrt(length(cluster_num) * length(cluster_denom))
out_p$logFC <- log2( (numMean + bias) / (denomMean + bias) )
out_p <- out_p[, c("Feature", "logFC", "pval"), drop = FALSE]
out_p$Type <- "Protein"
out <- rbind(out, out_p)
}
out$pval <- p.adjust(out$pval, method = "fdr")
# add the calculated results to the object, unless it was a user selection
if (!skip_cache) {
object@Viewer$de_cache[[hashed_body]] <<- out;
# add to object body, removing the first stored item
# TODO could implement a lru cache?
# storing 20 max TODO decide on max size for cache
if (length(object@Viewer$de_cache) > 20) {
# remove first cached item
object@Viewer$de_cache[1] <<- NULL;
}
}
} else {
# we have a cached result for these exact params, return it
out <- object@Viewer$de_cache[[hashed_body]]
}
out <- as.list(out)
result <- toJSON(
out, force = TRUE, pretty = TRUE,
auto_unbox = TRUE, use_signif = TRUE
)
res$body <- result
compressJSONResponse(req, res)
return(res)
})
pr$handle("GET", "/Clusters/<cluster_variable>/Cells",
function(req, res, cluster_variable) {
metaData <- object@metaData
cluster_variable <- URLdecode(cluster_variable)
if (cluster_variable %in% colnames(metaData)) {
res$body <- sigScoresToJSON(
names = rownames(metaData),
values = metaData[[cluster_variable]]
)
compressJSONResponse(req, res)
return(res)
} else {
return("No Clusters!")
}
})
pr$handle("GET", "/Clusters/MetaLevels", function(req, res) {
out <- list()
metaData <- object@metaData
for (cluster_variable in names(object@ClusterComparisons[[1]])) {
out[[cluster_variable]] <- levels(metaData[[cluster_variable]])
}
res$body <- toJSON(
out,
force = TRUE, pretty = TRUE, auto_unbox = TRUE
)
compressJSONResponse(req, res)
return(res)
})
pr$handle("GET", "/Clusters/<cluster_variable>/SigProjMatrix/Normal",
function(req, res, cluster_variable) {
# Gather signatures and numeric meta-data names
sigs <- colnames(object@SigScores)
metaData <- object@metaData
meta_n <- vapply(names(metaData),
function(metaName) is.numeric(metaData[, metaName]),
FUN.VALUE = TRUE)
meta_n <- colnames(metaData)[meta_n]
pvals_s <- object@LocalAutocorrelation$Signatures[sigs, "FDR", drop = F]
stat_s <- object@LocalAutocorrelation$Signatures[sigs, "C", drop = F]
pvals_p <- object@LocalAutocorrelation$Meta[meta_n, "FDR", drop = F]
stat_p <- object@LocalAutocorrelation$Meta[meta_n, "C", drop = F]
pvals <- rbind(pvals_s, pvals_p)
stat <- rbind(stat_s, stat_p)
colnames(stat) <- "Score"
colnames(pvals) <- "Score"
stat <- as.matrix(stat)
pvals <- as.matrix(pvals)
cluster_variable <- URLdecode(cluster_variable)
# Get Signature Cluster Comparisons
var_res <- object@ClusterComparisons$Signatures[[cluster_variable]]
cluster_pval_s <- lapply(var_res, function(var_level_res){
var_level_res["FDR"]
})
cluster_pval_s <- as.matrix(do.call(cbind, cluster_pval_s))
colnames(cluster_pval_s) <- names(var_res)
cluster_stat_s <- lapply(var_res, function(var_level_res){
var_level_res["stat"]
})
cluster_stat_s <- as.matrix(do.call(cbind, cluster_stat_s))
colnames(cluster_stat_s) <- names(var_res)
# Get Meta Cluster Comparisons
var_res <- object@ClusterComparisons$Meta[[cluster_variable]]
cluster_pval_p <- lapply(var_res, function(var_level_res){
var_level_res["FDR"]
})
cluster_pval_p <- as.matrix(do.call(cbind, cluster_pval_p))
colnames(cluster_pval_p) <- names(var_res)
cluster_stat_p <- lapply(var_res, function(var_level_res){
var_level_res["stat"]
})
cluster_stat_p <- as.matrix(do.call(cbind, cluster_stat_p))
colnames(cluster_stat_p) <- names(var_res)
# Combine together
cluster_pval <- rbind(cluster_pval_s, cluster_pval_p)
cluster_stat <- rbind(cluster_stat_s, cluster_stat_p)
cluster_pval <- cluster_pval[rownames(pvals), , drop = F]
cluster_stat <- cluster_stat[rownames(pvals), , drop = F]
pvals <- cbind(pvals, cluster_pval)
stat <- cbind(stat, cluster_stat)
res$body <- sigProjMatrixToJSON(stat, pvals, sigs = rownames(stat))
return(res)
})
pr$handle("GET", "/Clusters/<cluster_variable>/ModProjMatrix/Normal",
function(req, res, cluster_variable) {
# Gather signatures and numeric meta-data names
mods <- colnames(object@ModScores)
pvals_s <- c()
stat_s <- c()
for (mod in mods) {
if (grepl("_OVERLAP_", mod, fixed=T)) {
# yanay rnow
# overlap inputted, re proccess
name_split <- strsplit(mod, "_OVERLAP_")[[1]]
sig_name <- name_split[1]
mod_name <- name_split[2]
pval <- object@ModuleSignatureEnrichment$p_vals[sig_name, mod_name]
stat <- object@ModuleSignatureEnrichment$statistics[sig_name, mod_name]
pvals_s <- append(pvals_s, pval)
stat_s <- append(stat_s, stat)
} else {
mod_genes <- names(object@modData[[mod]]@sigDict)
mod_hyp_test <- calc_set_enrichment(mod_genes, mod_genes, rownames(object@exprData))
pvals_s <- append(pvals_s, mod_hyp_test[2])
stat_s <- append(stat_s, mod_hyp_test[1])
}
}
stat <- as.matrix(stat_s)
pvals <- as.matrix(pvals_s)
cluster_variable <- URLdecode(cluster_variable)
# Get Modules Cluster Comparisons
var_res <- object@ClusterComparisons$Modules[[cluster_variable]]
cluster_pval_s <- lapply(var_res, function(var_level_res){
var_level_res["FDR"]
})
cluster_pval_s <- as.matrix(do.call(cbind, cluster_pval_s))
colnames(cluster_pval_s) <- names(var_res)
cluster_stat_s <- lapply(var_res, function(var_level_res){
var_level_res["stat"]
})
cluster_stat_s <- as.matrix(do.call(cbind, cluster_stat_s))
colnames(cluster_stat_s) <- names(var_res)
pvals <- cbind(pvals, cluster_pval_s)
stat <- cbind(stat, cluster_stat_s)
colnames(pvals)[1] <- "Overlap"
colnames(stat)[1] <- "Overlap"
stat <- stat[order(stat[,1],decreasing=TRUE), ]
res$body <- sigProjMatrixToJSON(stat, pvals, sigs = rownames(stat))
return(res)
})
pr$handle("GET", "/Modules/Enrichment",
function(req, res) {
pvals <- object@ModuleSignatureEnrichment$p_vals
stat <- object@ModuleSignatureEnrichment$statistics
res$body <- sigProjMatrixToJSON(stat, pvals, sigs = rownames(stat))
return(res)
})
pr$handle("GET", "/Modules/HotspotScore/<module_name>",
function(req, res, module_name) {
module_name <- URLdecode(module_name)
# change back to modulehotspot scores if want hotspot scores
# instead of signature scores for the hotspot modules.
if (module_name %in% colnames(object@ModScores)) {
names <- rownames(object@ModScores)
values <- as.data.frame(object@ModScores)[[module_name]]
res$body <- sigScoresToJSON(names, values)
compressJSONResponse(req, res)
return(res)
} else {
return("Module not found!")
}
})
pr$handle("GET", "/Modules/GeneList/<module_name>",
function(req, res, module_name) {
module_name <- URLdecode(module_name)
# change back to module hotspot scores if want hotspot scores
# instead of signature scores for the hotspot modules.
if (module_name %in% names(object@modData)) {
mod <- object
genes <- names(object@modData[[module_name]]@sigDict)
res$body <- toJSON(genes, force = TRUE, pretty = TRUE)
compressJSONResponse(req, res)
return(res)
} else {
return("Module not found!")
}
})
pr$handle("GET", "/Clusters/<cluster_variable>/SigProjMatrix/Meta",
function(req, res, cluster_variable) {
cluster_variable <- URLdecode(cluster_variable)
pvals <- object@LocalAutocorrelation$Meta[, "FDR", drop = F]
stat <- object@LocalAutocorrelation$Meta[, "C", drop = F]
colnames(stat) <- "Score"
colnames(pvals) <- "Score"
stat <- as.matrix(stat)
pvals <- as.matrix(pvals)
var_res <- object@ClusterComparisons$Meta[[cluster_variable]]
cluster_pval <- lapply(var_res, function(var_level_res){
var_level_res["FDR"]
})
cluster_pval <- as.matrix(do.call(cbind, cluster_pval))
colnames(cluster_pval) <- names(var_res)
cluster_stat <- lapply(var_res, function(var_level_res){
var_level_res["stat"]
})
cluster_stat <- as.matrix(do.call(cbind, cluster_stat))
colnames(cluster_stat) <- names(var_res)
cluster_pval <- cluster_pval[rownames(pvals), , drop = F]
cluster_stat <- cluster_stat[rownames(pvals), , drop = F]
pvals <- cbind(pvals, cluster_pval)
stat <- cbind(stat, cluster_stat)
res$body <- sigProjMatrixToJSON(stat, pvals, sigs = rownames(stat))
return(res)
})
pr$handle("GET", "/Clusters/<cluster_variable>/ProteinMatrix",
function(req, res, cluster_variable) {
proteins <- colnames(object@proteinData)
cluster_variable <- URLdecode(cluster_variable)
pvals <- object@LocalAutocorrelation$Proteins[, "FDR", drop = F]
stat <- object@LocalAutocorrelation$Proteins[, "C", drop = F]
colnames(stat) <- "Score"
colnames(pvals) <- "Score"
stat <- as.matrix(stat)
pvals <- as.matrix(pvals)
var_res <- object@ClusterComparisons$Proteins[[cluster_variable]]
cluster_pval <- lapply(var_res, function(var_level_res){
var_level_res["FDR"]
})
cluster_pval <- as.matrix(do.call(cbind, cluster_pval))
colnames(cluster_pval) <- names(var_res)
cluster_stat <- lapply(var_res, function(var_level_res){
var_level_res["stat"]
})
cluster_stat <- as.matrix(do.call(cbind, cluster_stat))
colnames(cluster_stat) <- names(var_res)
cluster_pval <- cluster_pval[rownames(pvals), , drop = F]
cluster_stat <- cluster_stat[rownames(pvals), , drop = F]
pvals <- cbind(pvals, cluster_pval)
stat <- cbind(stat, cluster_stat)
res$body <- sigProjMatrixToJSON(stat, pvals, proteins)
return(res)
})
pr$handle("GET", "/SessionInfo", function(req, res) {
info <- list()
info["name"] <- getParam(object, "name")
W <- object@LatentTrajectory
hasTree <- !is.null(W)
info["has_tree"] <- hasTree
info[["meta_sigs"]] <- colnames(object@metaData)
info[["pooled"]] <- object@params$micropooling$pool
info[["ncells"]] <- nrow(object@metaData)
info[["has_sigs"]] <- length(object@sigData) > 0
info[["has_mods"]] <- length(object@modData) > 0
info[["has_proteins"]] <- hasProteinData(object)
info[["has_lca"]] <- !is.null(object@LCAnnotatorData)
if (.hasSlot(object, "tree") && !is.null(object@tree)) {
info[["dendrogram"]] <- write.tree(object@tree)
}
info[["has_seurat"]] <- requireNamespace("Seurat", quietly = TRUE)
info[["has_dendrogram"]] <- .hasSlot(object, "tree") && !is.null(object@tree)
res$body <- toJSON(info, force = TRUE,
pretty = TRUE, auto_unbox = TRUE)
return(res)
})
pr$handle("GET", "/Cell/<cell_id>/Meta",
function(req, res, cell_id) {
cell_id <- URLdecode(cell_id)
cell_meta <- as.list(object@metaData[cell_id, ])
res$body <- toJSON(cell_meta, auto_unbox = TRUE)
return(res)
})
pr$handle("POST", "/Cells/Meta", function(req, res) {
subset <- fromJSON(req$postBody)
subset <- subset[!is.na(subset)]
if (object@params$micropooling$pool){
cells <- unname(unlist(object@Pools[subset]))
} else {
cells <- subset
}
metaSubset <- object@metaData[cells, ]
numericMeta <- vapply(metaSubset, is.numeric, FUN.VALUE = TRUE)
metaSummaryNumeric <-
lapply(metaSubset[numericMeta], function(item){
vals <- quantile(item, probs = c(0, .5, 1), na.rm = TRUE)
names(vals) <- c("Min", "Median", "Max")
return(as.list(vals))
})
metaSummaryFactor <-
lapply(metaSubset[!numericMeta], function(item){
vals <- sort(table(droplevels(item)),
decreasing = TRUE) # top factor
vals <- vals / length(item) * 100 # percent
if (length(unique(item)) == 1) {
entropy <- 0
} else {
frequencies <- table(as.character(item)) / length(item)
entropy <- -sum(frequencies * log2(frequencies))
}
return(list(levels=as.list(vals), entropy=entropy))
})
metaSummary <- list(numeric = metaSummaryNumeric,
factor = metaSummaryFactor
)
res$body <- toJSON(
metaSummary, force = TRUE, pretty = TRUE,
auto_unbox = TRUE, digits = I(4)
)
return(res)
})
pr$handle("GET", "/Cells/Selections", function(req, res) {
# Disable caching for this request
res$headers[["Cache-Control"]] <- NULL
selections <- getSelections(object)
selectionNames <- as.character(names(selections))
res$body <- toJSON(selectionNames)
return(res)
})
pr$handle("GET", "/Cells/Selections/<selection_id>",
function(req, res, selection_id) {
# Disable caching for this request
res$headers[["Cache-Control"]] <- NULL
selection_id <- URLdecode(selection_id)
selections <- getSelections(object)
selectionCells <- selections[[selection_id]]
res$body <- toJSON(selectionCells, auto_unbox = TRUE)
return(res)
})
pr$handle("POST", "/Cells/Selections/<selection_id>",
function(req, res, selection_id) {
selection_id <- URLdecode(selection_id)
selections <- getSelections(object)
cell_ids <- fromJSON(req$postBody)
object@Viewer$selections[[selection_id]] <<- cell_ids # Super assignment!
res$body <- "null" # Empty body for successful POST
return(res)
})
pr$handle("GET", "/Download/DE", function(req, res) {
res$headers[["Content-Disposition"]] <- "attachment; filename=de.json"
res$headers[["fileName"]] <- "de.json"
res$headers[["Cache-Control"]] <- NULL
object@Viewer$de_cache
})
pr$handle("GET", "/Download/Selections", function(req, res) {
res$headers[["Content-Disposition"]] <- "attachment; filename=selections.json"
res$headers[["Cache-Control"]] <- NULL
res$headers[["fileName"]] <- "selections.json"
getSelections(object)
})
# Assume all other paths are files or 404
pr$filter("filterFilter", function(req, res) {
if (req$PATH_INFO == "/") {
path <- "Results.html"
} else {
path <- substring(req$PATH_INFO, 2) # remove first / character
}
path <- paste0("html_output/", path)
file_index <- match(path, static_whitelist)
if (is.na(file_index)) {
forward()
return()
}
file_path <- system.file(static_whitelist[file_index],
package = "VISION")
mime_type <- mime::guess_type(file_path)
res$headers[["Content-type"]] <- mime_type
data <- readBin(file_path, "raw", n = file.info(file_path)$size)
if (grepl("image|octet|pdf", mime_type)) {
res$body <- data
} else {
res$body <- rawToChar(data)
}
return(res)
})
tryCatch({
pr$run(host = host, port = port, swagger = FALSE)
},
interrupt = function(i){
message("Server Exited")
})
return(object)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.