#if (interactive()) {
requireNamespace('av'); requireNamespace('BiocGenerics'); requireNamespace('DESeq2');
requireNamespace('dendextend'); requireNamespace('dynamicTreeCut'); requireNamespace('flashClust');
requireNamespace('ggdendro'); requireNamespace('HDF5Array'); requireNamespace('magick'); requireNamespace('DT');
requireNamespace('pROC'); requireNamespace('shinyWidgets'); requireNamespace('shinyjs'); requireNamespace('htmltools');
requireNamespace('shinyBS'); requireNamespace('sortable'); requireNamespace('org.Hs.eg.db'); requireNamespace('org.Mm.eg.db')
requireNamespace('org.At.tair.db'); requireNamespace('org.Dr.eg.db'); requireNamespace('org.Dm.eg.db');
requireNamespace('AnnotationDbi'); requireNamespace('sparkline'); requireNamespace('spsComps'); requireNamespace('spsUtil');
requireNamespace('visNetwork'); requireNamespace('WGCNA')
#}
# Accessing local html files by iframes.
# addResourcePath("tmpuser", getwd())
# Application-level cache, max size is 1G.
shiny::shinyOptions(cache = cachem::cache_disk(dir="./app_cache/cache/", max_size = 1024 * 1024^2))
dat.no <- 'none'; dat.no.dis <- 'Choosing a dataset'
na.sgl.def <- '^covis_'
na.cus <- c('customBulkData', 'customCovisData')
na.cus.covis <- c('customCovisData')
na.cus.dis <- c('customBulkData', 'customCovisData')
na.sgl <- c('^covis_|^customCovisData$')
met.pat <- '^metadata$|^link$|^type$|^total$|^method$'
# Temporary directory.
tmp.dir <- normalizePath(tempdir(check=TRUE), winslash="/", mustWork=FALSE)
tmp.file <- normalizePath(tempfile(), winslash='/', mustWork=FALSE)
# Tooltip of colData table in covis.
msg.meta.ann <- 'Metadata of single-cell (see "bulkCell") data. "label", "label1": cell group labels obtained from annotation labels, marker genes, etc.'
msg.meta.coclus <- "Metadata of bulk and single-cell data after co-clustering. <br/> 1. 'cluster': clusters containing only cells or cells and tissues (co-clusters); <br/> 2. 'bulkCell': 'bulk' and 'cell' indicate tissues and cells respectively; <br/> 3. 'assignedBulk': tissue lables assinged to cells as group labels, 'none' indicates no assignment; <br/> 4. 'similarity': Spearman correlation efficient used for tissue-cell assignment through a nearest-neighbor approach."
# Run button colors.
hp <- 'background-color:#e7e7e7'
hp.txt <- 'color:black'
run.msg <- 'Always click the <span style="color:white;font-weight:bold;background-color:#369ef7;font-size:20px">"Run"</span> button to see the latest results!'
run.col <- "color:white;background-color:#369ef7;border-color:#ddd"
run.top <- "margin-top:24px;color:white;background-color:#369ef7;border-color:#ddd"
# Confirm buttons.
conf.col <- 'margin-top:2px;margin-bottom:5px;margin-left:20px;padding-top:2px;padding-bottom:2px;color:white;background-color:#369ef7;border-color:#ddd'
# Rectangle.
rec <- 'border-color:#3c8dbc;border-width:1px;border-style:solid'
# Bitmap extensions accepted in uploaded images.
raster.ext <- c('.jpg', '.JPG', '.png', '.PNG')
# Confirm button labels.
lab.sgl <- 'Select gene IDs with auto-completion.'
lab.mul <- 'Use comma or space to separate gene IDs (e.g. Cav2,Apoh).'
# Search portion of URLs on the dataset page.
# Extract parameter values from url.
url_val <- function(na, lis.url, def=NULL) {
# if (!exists('lis.url')) return('null')
if (!na %in% names(lis.url$par)) val <- 'null' else if (length(lis.url$par)==0) val <- 'null' else val <- lis.url$par[[na]]
# In "ifelse", the length of returned value is same with the first argument.
# val <- ifelse(length(lis.url$par)==0, 'null', lis.url$par[[na]])
val <- gsub('\\"', '', val)
if (!is.null(def)) ifelse('null' %in% val[1], def, val) else val
}
# Import internal functions.
read_svg <- get('read_svg', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
read_svg_m <- memoise::memoise(read_svg, cache = getShinyOption("cache"))
reduce_dim <- get('reduce_dim', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
reduce_dim_m <- memoise::memoise(reduce_dim, cache = getShinyOption("cache"))
norm_cell <- get('norm_cell', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
norm_cell_m <- memoise::memoise(norm_cell, cache = getShinyOption("cache"))
cbind_se <- get('cbind_se', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
ovl_dat_db <- get('ovl_dat_db', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
check_se <- get('check_se', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
check_sce <- get('check_sce', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
cut_dendro <- get('cut_dendro', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
com_roc <- get('com_roc', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
qc_cell <- get('qc_cell', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
check_exp <- get('check_exp', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
check_obj <- get('check_obj', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
#img_pa_na <- get('img_pa_na', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
covis_trans <- get('covis_trans', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
svg_separ <- get('svg_separ', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
sc_qc_plot <- get('sc_qc_plot', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
detect_cluster <- get('detect_cluster', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
detect_cluster_m <- memoise::memoise(detect_cluster, cache = getShinyOption("cache"))
dim_color_idp <- get('dim_color_idp', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
dim_color_coclus <- get('dim_color_coclus', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
dim_color2cell <- get('dim_color2cell', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
dim_color <- get('dim_color', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
nn_graph <- get('nn_graph', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
svg_raster <- get('svg_raster', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
raster_path <- get('raster_path', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
# dat_fun <- get('dat_fun', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
df_is_as <- get('df_is_as', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
thrsd <- get('thrsd', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
scale_all <- get('scale_all', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
edgeR <- get('edgeR', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
limma <- get('limma', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
deseq2 <- get('deseq2', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
# distt <- get('distt', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
sf_var <- get('sf_var', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
up_dn <- get('up_dn', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
deg_ovl_mat <- get('deg_ovl_mat', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
deter_core <- get('deter_core', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
rela_size <- get('rela_size', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
norm_data <- get('norm_data', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
cord_parent <- get('cord_parent', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
use <- get('use', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
cord <- get('cord', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
xy0 <- get('xy0', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
xy <- get('xy', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
tit_id <- get('tit_id', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
out_ply <- get('out_ply', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
sort_gen_con <- get('sort_gen_con', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
test_ffm <- get('test_ffm', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
matrix_hm <- get('matrix_hm', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
# Function to extract nearest genes.
sub_na <- get('sub_na', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
adj_mod <- get('adj_mod', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
filter_data <- get('filter_data', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
col_bar <- get('col_bar', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
lay_shm <- get('lay_shm', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
nod_lin <- get('nod_lin', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
# Break combined path to a group (g=TRUE) or siblings (g=FALSE).
path_br <- get('path_br', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
# The outline or tissue nodes are checked for combines paths. If combined paths are detected, those outside a group are broken to a group while those inside a group are broken as siblings.
path_br_all <- get('path_br_all', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
# 'a' nodes are not removed.
svg_attr <- get('svg_attr', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
svg_df <- get('svg_df', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
# Separate SHMs of grob and ggplot. Different SHMs (under different SVGs) of same 'gene_condition' are indexed with suffixed of '_1', '_2', ...
gg_shm <- get('gg_shm', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
# Application-level cache.
gg_shm_m <- memoise::memoise(gg_shm, cache = getShinyOption("cache"))
grob_shm <- get('grob_shm', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
#grob_shm_m <- memoise::memoise(grob_shm, cache = getShinyOption("cache"))
# Subset data matrix by correlation or distance measure.
submatrix <- get('submatrix', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
# Adjust legend key size and rows in ggplot.
gg_lgd <- get('gg_lgd', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
# Add value keys SHMs.
gg_2lgd <- get('gg_2lgd', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
# Prepare interactive SHMs in html.
html_ly <- get('html_ly', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
# Make videos.
video <- get('video', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
# Shown popup window.
show_mod <- get('show_mod', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
modal <- get('modal', envir=asNamespace('spatialHeatmap'), inherits=FALSE)
# Extract a 1-column data frame of URLs. If no column of URL is present, the default google-search URLs are composed.
link_dat <- function(df.met, link.only=TRUE) {
# save(df.met, link.only, file='link.dat.arg')
cna <- colnames(df.met); rna <- rownames(df.met)
link.idx <- grep('link|links', cna, ignore.case=TRUE)[1]
if (is.na(link.idx)) {
# Iterative operation on data frame: vectorization is faster than for/lapply loop.
link <- paste0('<a href=\"https://www.google.com/search?q=', rna, '" target="_blank">link</a>')
# link <- lapply(rownames(df.met), function(x) a("link", href=paste0('https://www.google.com/search?q=', x), target="_blank"))
# link <- unlist(lapply(link, as.character))
} else { link <- df.met[, link.idx]
link <- paste0('<a href="', gsub('\\\\"', '\'', link), '" target="_blank">link</a>')
}
df.lk <- data.frame(link=link, row.names=rownames(df.met))
# df.met: 0 or 1 column, return(df.lk)
if (link.only==TRUE | ncol(df.met)==0) return(df.lk) else if (link.only==FALSE & ncol(df.met)==1) {
if (cna!='link') return(cbind(df.met, df.lk)) else return(df.lk)
}
else {
cna.other <- setdiff(colnames(df.met), colnames(df.lk))
df.met <- cbind(df.met[, cna.other[1], drop=FALSE], df.lk, df.met[, cna.other[setdiff(seq_along(cna.other), 1)], drop=FALSE]); return(df.met)
}
}
# Import input matrix, able to deal with separate numeric matrix, character matrix, and mixture of both.
fread_df <- function(input, isRowGene=TRUE, header=TRUE, sep='auto', fill=TRUE, rep.aggr='mean', check.names=FALSE) {
if (is(input, 'dgCMatrix')|is(input, 'matrix')|is(input, 'data.frame')|is(input, 'DFrame')|is(input, 'DelayedMatrix')) input <- as.data.frame(as.matrix(input))
if (!is(input, 'data.frame')) {
df0 <- tryCatch({
fread(input=input, header=header, sep=sep, fill=fill, check.names=check.names)
}, error = function(error_condition) {
# Deals with only one column with row names.
fread(input = input, header = FALSE, sep = sep, fill = FALSE, check.names = check.names)
})
cna <- make.names(colnames(df0))
if (cna[1]=='V1') cna <- cna[-1] else cna <- cna[-ncol(df0)]
df1 <- as.data.frame(df0); rownames(df1) <- make.names(df1[, 1])
df1 <- df1[, -1, drop = FALSE]; colnames(df1) <- cna
if(isRowGene==FALSE) df1 <- t(df1)
cna <- colnames(df1); rna <- rownames(df1)
} else { df1 <- input; rna <- rownames(df1); cna <- colnames(df1) }
# Covert factors to character. Only data.frame works not matrix.
fct.idx <- vapply(df1, is.factor, logical(1))
df1[fct.idx] <- lapply(df1[fct.idx], as.character)
# Subsetting identical column names in a matrix will not trigger appending numbers.
df1 <- as.matrix(df1)
# Isolate data and row metadata.
na <- vapply(seq_len(ncol(df1)), function(i) { tryCatch({ as.numeric(df1[, i]) }, warning=function(w) { return(rep(NA, nrow(df1))) }, error=function(e) { stop("Please make sure input data are numeric!") }) }, FUN.VALUE=numeric(nrow(df1)) )
if (nrow(df1)==1) na <- matrix(na, byrow=TRUE, ncol=ncol(df1))
na <- as.data.frame(na); rownames(na) <- rna; colnames(na) <- cna
vap <- df_is_as(na, is.na); idx <- colSums(vap)!=0
df.num <- na[!idx]; colnames(df.num) <- cna <- cna[!idx]
df.met.all <- as.data.frame(df1)[idx]
cat('Preparing URLs .. \n')
df.link <- link_dat(df.met.all) # Works if ncol(df.met.all) is 0.
if (ncol(df.met.all) > 0) {
cat('Preparing metadata .. \n')
met.idx <- grep('^metadata$', colnames(df.met.all), ignore.case = TRUE)[1]
if (!is.na(met.idx)) {
df.met <- df.met.all[, met.idx, drop = FALSE]
colnames(df.met) <- 'metadata'
df.met <- cbind(df.met, df.link)
} else df.met <- df.link
} else df.met <- df.link
# Only row metadata.
if (ncol(df.num) == 0) {
return(list(df.aggr = NULL, df.met=as.data.frame(df.met), df.rep = NULL, con.na = FALSE))
}
form <- grepl("__", cna); if (sum(form)==0) { cna <- colnames(df.num) <- paste0(cna, '__', 'con'); con.na <- FALSE } else con.na <- TRUE
sf <- gsub('(.*)__(.*)', '\\1', cna)
vari <- gsub('(.*)__(.*)', '\\2', cna)
df.cdat <- DataFrame(spFeature=sf, variable=vari)
if(sum(is.na(as.numeric(as.matrix(df.num))))>=1) return('Make sure all values in data matrix are numeric.')
df.rep <- df.num; df.rep <- df_is_as(df.rep, as.numeric)
#if (TRUE %in% rdat) {
# rdat <- cbind(DataFrame(df.met[, !colnames(df.met) %in% colnames(rdat)]), DataFrame(rdat))
# } else rdat <- NULL
se.rep <- SummarizedExperiment(assays=list(rep=as.matrix(df.rep)), colData=df.cdat, rowData=df.met)
if (!is.null(rep.aggr)) {
se.aggr <- aggr_rep(data=se.rep, assay.na=NULL, sam.factor=NULL, con.factor=NULL, aggr=rep.aggr)
assayNames(se.aggr) <- 'aggr'
} else se.aggr <- NULL
return(list(se.rep=se.rep, se.aggr=se.aggr, con.na=con.na))
}
# Separate colour ingredients.
col_sep <- function(color) {
color <- gsub(' |\\.|-|;|,|/', '_', color)
color <- strsplit(color, '_')[[1]]
color <- color[color!='']; return(color)
}
# Extract target svgs in tar into tmp folder, and return the paths.
extr_svg <- function(file, name) {
dir <- paste0(tempdir(check=TRUE), '/svg_shm')
if (!dir.exists(dir)) dir.create(dir, recursive=TRUE)
untar(file, exdir=dir, tar='tar')
pa <- paste0(dir, '/', name)
if (file.exists(pa)) return(pa) else return()
}
# Extract svg path/na from uploaded or internal tar files if not found in 'data' folder.
svg_pa_na <- function(svg.path, pa.svg.upl, raster.ext) {
svg.na <- NULL; for (i in seq_along(svg.path)) {
# Extract svg names.
str <- strsplit(svg.path[[i]], '/')[[1]]
na0 <- str[length(str)]
if (!grepl(paste0('\\', c('.svg', raster.ext), '$', collapse='|'), na0)) return('No aSVG/template file is detected! Solution: 1) select another aSVG and rematch it to data; 2) add an aSVG/template file for the selected data in the backend aSVG tar file or uploaded aSVG tar file.')
svg.na <- c(svg.na, na0)
# Complete uploaded svg paths.
if (!grepl('data/', svg.path[[i]])) {
# The data/svg precedence: uploaded tar > internal tar > default examples. The duplicated data/svgs are removed according to this precedence when processing data/svg upstream.
pa0 <- NULL; if (!is.null(pa.svg.upl)) pa0 <- extr_svg(file=pa.svg.upl, name=na0)
if (is.null(pa.svg.upl)|is.null(pa0)) {
tar.all <- list.files('data', pattern='\\.tar$', full.names=TRUE)
tar.svg <- tar.all[!grepl('data_shm.tar$', tar.all)][1]
pa0 <- extr_svg(file=tar.svg, name=na0)
}; if (is.null(pa0)) return(paste0("This aSVG/template file is not detected: ", na0, "!")) else svg.path[[i]] <- pa0
}
}; return(list(svg.path=svg.path, svg.na=svg.na))
}
# Check suffixes if multiple svgs.
svg_suffix <- function(svg.path, svg.na, raster.ext) {
if (length(svg.na)>1) {
ext <- paste0('_shm\\d+\\', c('.svg', raster.ext), '$', collapse='|')
if (!all(grepl(ext, svg.na, perl=TRUE))) return("Suffixes of aSVGs and templates should be indexed as '_shm1.svg', '_shm1.png', '_shm2.svg', '_shm2.png', '_shm3.svg', '_shm3.png', ...")
ord <- order(gsub('.*_(shm.*)$', '\\1', svg.na))
svg.path <- svg.path[ord]; svg.na <- svg.na[ord]
}; return(list(svg.path=svg.path, svg.na=svg.na))
}
# Convert aSVG features to draggable items.
# ns() is the namespace in shiny modules.
ft2tag <- function(ft){
lapply(ft, function(i) { tag("span", list(class = class(i), tags$span(class = "glyphicon glyphicon-move"), i)) }
)
}
## Rematch features.
# Create a panel for each data feature, where aSVG features can be dropped.
# ns() is the namespace in shiny modules.
ft_dat <- function(x, ns) {
span(class = "panel panel-default",
div(class = "panel-heading", x),
div(class = "panel-body", id = ns(x))
)
}
ft_lis_dat <- function(x, ns) {
span(class = "panel panel-default",
div(class = "panel-heading", names(x)),
div(class = "panel-body", id = ns(names(x)), ft2tag(x[[1]]))
)
}
# Allow features are draggable across panels.
# ns() is the namespace in shiny modules.
ft_js <- function(x, ns) {
sortable_js(css_id = ns(x),
options = sortable_options(
multiDrag = NULL, sort = FALSE, animation = 1000, direction = NULL,
group = list(name = "sortGroup1", put = TRUE),
onSort = sortable_js_capture_input(ns(x))
)
)
}
# Complete matching interface.
match_interface <- function(to.ft, to.div.id='ftSVG', to.div.tit='Features in aSVG', from.ft, from.div.tit='Features in data', ns) {
to.ft <- sort(to.ft); from.ft <- sort(from.ft)
frow <- fluidRow(
span(class = "panel panel-default", style = 'margin-left:0px',
div(class = "panel-heading", strong(to.div.tit)),
div(class = "panel-body", id = ns(to.div.id), ft2tag(to.ft))
),
div(class = "panel panel-default",
div(class = "panel-heading", strong(from.div.tit)),
lapply(from.ft, ft_dat, ns = ns)
), lapply(c(to.div.id, from.ft), ft_js, ns = ns) # Items are interchangeable across ftSVG and sam.all.
); return(frow)
}
# Clean temporary files in data mining.
data_mining_rm <- function() {
if (dir.exists('www/tmp/')) {
message("Removing files in 'www/tmp/' ... \n")
files <- list.files('www/tmp/', '*.txt$', full.names=TRUE)
file.remove(grep('README', list.files('www/tmp/', '*.txt$', full.names=TRUE), invert=TRUE, value=TRUE))
}
}
# Clean trash files in animation and video.
ggly_rm <- function() {
if (dir.exists('www/html_shm')) {
cat("Removing animation files in 'www/html_shm' ... \n")
unlink('www/html_shm/lib', recursive=TRUE)
file.remove(list.files('www/html_shm/', '*.html$', full.names=TRUE))
} else dir.create('www/html_shm', recursive=TRUE)
if (dir.exists('R/www')) {
cat("Removing animation files in 'R/www/html_shm' ... \n")
unlink('R/www', recursive=TRUE)
}
}
vdo_rm <- function() {
if (dir.exists('www/video/')) {
cat("Removing video file in 'www/video/' ... \n")
file.remove(list.files('www/video/', '*.mp4$', full.names=TRUE))
} else dir.create('www/video/', recursive=TRUE)
if (dir.exists('R/www')) {
cat("Removing video file in 'R/www/video' ... \n")
unlink('R/www', recursive=TRUE)
}
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.