# Module for uploading data.
upload_server <- function(id, lis.url=NULL, prt=NULL, session) {
moduleServer(id, function(input, output, session) {
message('Upload module starts ... '); ns <- session$ns
observeEvent(input$dathelp, {
showModal(modal(title='Quick start!', msg = NULL, img='dataset.jpg', img.w="100%"))
})
output$bulk.sce <- renderUI({
ns <- session$ns; fileIn <- input$fileIn
if (fileIn=='customBulkData') {
list(
fluidRow(splitLayout(cellWidths=c('10px', '280px', '1px'), '', h4(strong("Step2: upload custom assay data")), '')),
fluidRow(splitLayout(cellWidths=c('10px', '180px', '1px', '200px', '1px', '230px', '1px', '190px', '1px', '210px'), '',
tags$div(class='tp', span(class='tpt', 'A tabular file or ".rds" file ("SummarizedExperiment" saved with "saveRDS")'), fileInput(ns("geneInpath"), "2A: formatted assay data", accept=c(".txt", ".csv", '.rds'), multiple=FALSE)), '',
selectInput(ns('dimName'), label='2B: genes in column or row?', choices=c("Row", "Column"), selected='Row'), '',
tags$div(class='tp', span(class='tpt', 'Ensure "columns in the data matrix corresponds with "rows" in the targets file respectively.'),
fileInput(ns("target"), "2C (optional): sample targets file", accept=c(".txt", ".csv"), multiple=FALSE)), '',
tags$div(class='tp', span(class='tpt', 'Ensure "rows" in the data matrix corresponds with "rows" in the row metadata file respectively.'),
fileInput(ns("met"), "2D (optional): row metadata", accept=c(".txt", ".csv"), multiple=FALSE)), '',
tags$div(class='tp', span(class='tpt', 'Assay metadata in a tabular file.'),
fileInput(ns("asymet"), "2E (optional): assay metadata", accept=c(".txt", ".csv"), multiple=FALSE)))
)
)
} else if (fileIn=='customCovisData') {
list(
fluidRow(splitLayout(cellWidths=c('10px', '280px', '1px'), '', h4(strong("Step2: upload custom assay data")), '')),
fluidRow(splitLayout(cellWidths=c('10px', '300px', '1px', '200px', '1px', '230px', '1px', '190px', '1px', '210px'), '',
div(class='tp', span(class='tpt', 'A tabular file or ".rds" file ("SingleCellExperiment" that combines bulk & single-cell data, saved with "saveRDS")'),
fileInput(ns("sglCell"), "2A: formatted bulk & single-cell assay data", accept=c(".txt", ".csv", ".rds"), multiple=FALSE)
), '',
selectInput(ns('dimNaCovis'), label='2B: genes in column or row?', choices=c("Row", "Column"), selected='Row'), '',
tags$div(class='tp', span(class='tpt', 'Ensure "columns in the data matrix corresponds with "rows" in the targets file, respectively.'),
fileInput(ns("tarCovis"), "2C: sample targets file", accept=c(".txt", ".csv"), multiple=FALSE)), '',
tags$div(class='tp', span(class='tpt', 'Ensure "rows" in the data matrix corresponds with "rows" in the row metadata file, respectively.'),
fileInput(ns("rmetCovis"), "2D (optional): row metadata", accept=c(".txt", ".csv"), multiple=FALSE)), '',
tags$div(class='tp', span(class='tpt', 'Assay metadata in a tabular file.'),
fileInput(ns("metCovis"), "2E (optional): assay metadata", accept=c(".txt", ".csv"), multiple=FALSE)))
)
)
}
})
output$svg.upl <- renderUI({
ns <- session$ns; fileIn <- input$fileIn
if (fileIn %in% na.cus) {
list(
h4(strong("Step3: upload custom aSVG(s)")),
fluidRow(splitLayout(cellWidths=c('10px', '500px', '1px', '500px'), '',
tags$div(class='tp', span(class='tpt', 'The assay data is matched with a single aSVG file.'),
fileInput(ns("svgInpath1"), "3A: one aSVG file", accept=c('.svg', raster.ext), multiple=TRUE)), '',
tags$div(class='tp', span(class='tpt', 'The assay data is matched with multiple aSVG files (e.g. developmental stages).'),
fileInput(ns("svgInpath2"), "3B (optional): multiple aSVG files", accept=c('.svg', raster.ext), multiple=TRUE))
))
)}
})
cfg <- reactiveValues(lis.dat=NULL, lis.dld=NULL, lis.par=NULL, na.def=NULL, dat.def=NULL, svg.def=NULL, pa.upl=NULL, pa.dat.upl=NULL, pa.svg.upl=NULL, na.cus=NULL, pa.svg.reg=NULL)
lis.cfg <- yaml.load_file('config/config.yaml')
lis.cfg <- lis.cfg[!vapply(lis.cfg, is.null, logical(1))]
# Separate default datasets, downloadable datasets, and parameters.
lis.dat <- lis.cfg[grepl('^dataset\\d+', names(lis.cfg))]
db.pa <- 'data/data_shm.tar'
# Merge separate data sets and data base.
if (file.exists(db.pa)) {
lis.dat.db <- ovl_dat_db(data=lis.dat, db=db.pa)
lis.dat <- lis.dat.db$data; db.dat <- lis.dat.db$dat.db
lis.dat <- c(lis.dat, db.dat)
names(lis.dat) <- paste0('dataset', seq_along(lis.dat))
}
dld.na <- c('download_single', 'download_multiple', 'download_multiple_variables', 'download_batched_data_aSVGs', 'download_covisualization')
lis.dld <- lis.cfg[grepl(paste0(dld.na, collapse='|'), names(lis.cfg))]
cnt.ldg <- reactiveValues(v=0)
observe({
message('Config file ...')
tabTop <- prt$input$tabTop; if (!check_obj(tabTop)) return()
if (tabTop %in% c('ldg', 'about') & cnt.ldg$v==0) return()
cnt.ldg$v <- 1
if (is.null(input$config)) lis.par <- lis.cfg[!grepl(paste0(c('^dataset\\d+', dld.na), collapse='|'), names(lis.cfg))] else lis.par <- yaml.load_file(input$config$datapath[1])
upl.size <- toupper(lis.par$max.upload.size)
num <- as.numeric(gsub('(\\d+)(G|M)', '\\1', upl.size))
if (grepl('\\d+G$', upl.size)) max.size <- num*1024^3
if (grepl('\\d+M$', upl.size)) max.size <- num*1024^2
options(shiny.maxRequestSize=max.size)
# Organise configuration parameters in a data frame.
for (i in seq_along(lis.par)) {
lis0 <- lis.par[[i]]; if (length(lis0)>1) {
name <- default <- NULL; for (j in seq_along(lis0)) {
pair <- strsplit(lis0[j], ':')[[1]]
name <- c(name, pair[1]); default <- c(default, pair[2])
}; df0 <- data.frame(name=name, default=default)
rownames(df0) <- df0$name; lis.par[[i]] <- df0
}
}
# Separate data, svg.
na.ipt <- dis.ipt <- dat.ipt <- svg.ipt <- NULL; for (i in lis.dat) {
na.ipt <- c(na.ipt, i$name); dat.ipt <- c(dat.ipt, i$data)
svg.ipt <- c(svg.ipt, list(i$svg)); dis.ipt <- c(dis.ipt, i$display);
}; names(dat.ipt) <- names(svg.ipt) <- na.ipt
# Uploaded tar files.
df.tar <- input$tar; dat.upl <- svg.upl <- NULL
tar.num <- grepl('\\.tar$', df.tar$datapath)
if (!is.null(df.tar)) validate(need(try(sum(tar.num)==2), 'Two separate tar files of respective data and aSVGs are expected!'))
if (sum(tar.num)==2) {
cat('Processing uploaded tar files ... \n')
p <- df.tar$datapath[1]; strs <- strsplit(p, '/')[[1]]
cfg$pa.upl <- pa.svg <- paste0(strs[grep('\\.tar$', strs, invert=TRUE)], collapse='/')
dat.idx <- grepl('data_shm.tar$', df.tar$name)
cfg$pa.svg.upl <- df.tar$datapath[!dat.idx]
# system(paste0('tar -xf', ' ', svg.tar, ' -C ', pa.svg))
cfg$pa.dat.upl <- dat.pa <- df.tar$datapath[dat.idx]
df.pair.upl <- read_hdf5(dat.pa, 'df_pair')[[1]]
pair.na <- df.pair.upl$name; dat.upl <- df.pair.upl$data
svg.upl <- as.list(df.pair.upl$aSVG); names(dat.upl) <- names(svg.upl) <- pair.na
# Process multiple aSVGs under the same data.
for (i in seq_along(svg.upl)) {
svg0 <- svg.upl[[i]]; if (grepl(';| |,', svg0)) {
strs <- strsplit(svg0, ';| |,')[[1]]; svg.upl[[i]] <- strs[strs!='']
}
}; cat('Done! \n')
}
# Separate data, svg of default and customization.
idx.def <- !na.ipt %in% na.cus; na.def <- na.ipt[idx.def]
dis.def <- dis.ipt[idx.def]
# Data in uploaded tar files are also included in default.
dat.def <- c(dat.upl, dat.ipt[na.def]); svg.def <- c(svg.upl, svg.ipt[na.def])
dis.def <- unique(c(names(dat.upl), dis.def))
# If data/svg are duplicated between the server and upload, the data/svg on server side is removed.
dat.def <- dat.def[unique(names(dat.def))]; svg.def <- svg.def[unique(names(svg.def))]
cfg$lis.dat <- lis.dat; cfg$lis.dld <- lis.dld; cfg$lis.par <- lis.par; cfg$na.def <- setNames(names(dat.def), dis.def)
cfg$svg.def <- svg.def; cfg$dat.def <- dat.def; cfg$na.cus <- setNames(na.cus, na.cus.dis)
dat.nas <- c(dat.no, na.cus, names(dat.def)); names(dat.nas) <- c(dat.no.dis, na.cus.dis, dis.def)
cfg$dat.nas <- dat.nas
})
observeEvent(cfg$dat.nas, {
tabTop <- prt$input$tabTop; lis.par <- cfg$lis.par; dat.nas <- cfg$dat.nas
req(check_obj(list(tabTop, lis.par, dat.nas)))
if (tabTop %in% c('ldg', 'about') & cnt.ldg$v==0) return()
url.val <- url_val('upl-fileIn', lis.url)
updateSelectInput(session, 'fileIn', choices=dat.nas, selected=ifelse(url.val=='null', lis.par$default.dataset, url.val))
})
observe({ # aSVG uploaded in regular files (not tar), used in re-matching.
if (is.null(input$svgInpath2)) svgIn.df <- input$svgInpath1 else svgIn.df <- input$svgInpath2
if (is.null(svgIn.df)) return()
if (input$fileIn %in% na.cus) {
svg.path <- svgIn.df$datapath; svg.na <- svgIn.df$name
# Raster images uploaded.
if (any(!grepl('\\.svg$', svg.na))) svg_raster(svg.na, raster.ext)
# SVG and template paths are processed in the same way, and both are placed in the same list.
pa.svg.reg <- list(unlist(lapply(seq_along(svg.na), function(x) {
strs <- strsplit(svg.path[x], '/')[[1]]
strs <- strs[-length(strs)]
paste0(c(strs, svg.na[x]), collapse='/')
}
))); names(pa.svg.reg) <- 'uploaded'; #save(pa.svg.reg, file='pa.svg.reg')
# Original copy used for regular SHMs, the 2nd copy used in rematching.
file.copy(svg.path, pa.svg.reg[[1]])
cfg$pa.svg.reg <- pa.svg.reg
}
})
observe({
input$fileIn; input$geneInpath
#updateRadioButtons(session, inputId="dimName", selected="None")
})
observe({
dld.exp <- reactiveValues(sgl=NULL, mul=NULL, st=NULL, bat = NULL)
dld.exp$sgl <- cfg$lis.dld$download_single
dld.exp$mul <- cfg$lis.dld$download_multiple
dld.exp$st <- cfg$lis.dld$download_multiple_variables
dld.exp$bat <- cfg$lis.dld$download_batched_data_aSVGs
dld.exp$covis <- cfg$lis.dld$download_covisualization
output$dld.cfg <- downloadHandler(
filename=function(){ "config_par.yaml" },
content=function(file=paste0(tmp.dir, '/config_par.yaml')){
lis.cfg <- yaml.load_file('config/config.yaml')
par.na <- c("max.upload.size", "default.dataset", "col.row.gene", "separator", "data.matrix", "shm.img", "shm.anm", "shm.video", "legend", "mhm", "network")
par.na <- par.na[par.na %in% names(lis.cfg)]
lis.par <- lis.cfg[par.na]; write_yaml(lis.par, file)
}
)
output$dld.sgl <- downloadHandler(
filename=function(){ "single_aSVG_data.zip" }, content=function(file=paste0(tmp.dir, '/single_aSVG_data.zip')){ zip(file, c(dld.exp$sgl$data, dld.exp$sgl$svg)) }
)
output$dld.mul <- downloadHandler(
filename=function(){ "multiple_aSVG_data.zip" }, content=function(file=paste0(tmp.dir, '/multiple_aSVG_data.zip')){ zip(file, c(dld.exp$mul$data, dld.exp$mul$svg)) }
)
output$dld.st <- downloadHandler(
filename=function(){ "multiVariables_aSVG_data.zip" },
content=function(file=paste0(tmp.dir, '/multiVariables_aSVG_data.zip')){ zip(file, c(dld.exp$st$data, dld.exp$st$svg)) }
)
output$dld.covis <- downloadHandler(
filename=function(){ "covisualization_aSVG_data.zip" },
)
output$dld.bat <- downloadHandler(
filename=function(){ "batched_data_aSVGs.zip" },
content=function(file=paste0(tmp.dir, '/batched_data_aSVGs.zip')){ zip(file, c(dld.exp$bat$data, dld.exp$bat$svg)) }
)
})
observeEvent(list(input$geneInpath), {
pa <- input$geneInpath$datapath;
if (sum(grepl('\\.rds$', pa))==1) {
hide(id='dimName'); hide(id='target')
hide(id='met'); hide(id='asymet')
} else {
shinyjs::show(id='dimName')
shinyjs::show(id='target')
shinyjs::show(id='met')
shinyjs::show(id='asymet')
}
})
observeEvent(list(input$sglCell), {
pa <- input$sglCell$datapath;
if (sum(grepl('\\.rds$', pa))==1) {
hide(id='dimNaCovis'); hide(id='tarCovis')
hide(id='rmetCovis'); hide(id='metCovis')
} else {
shinyjs::show(id='dimNaCovis')
shinyjs::show(id='tarCovis')
shinyjs::show(id='rmetCovis')
shinyjs::show(id='metCovis')
}
})
output$help <- renderUI({
tags$iframe(seamless="seamless", src= "html/shm_shiny_manual.html#1_Datasets", width='100%', height='100%')
})
# Switch to avoid files uploaded previously. E.g. 1. upload 'sce.rds' under 'customSingleCell'. 2. select 'human_brain'. 3. re-select 'customSingleCell', and 'sce.rds' in step 1 is avoided.
# fileInput cannot be set NULL with Shiny.setInputValue, since the uploaded file is cached.
covis.pa <- reactiveValues(val=TRUE)
observeEvent(list(input$fileIn), {
sce$val <- NULL
covis.pa$dat <- covis.pa$svg1 <- covis.pa$svg2 <- NULL
})
observeEvent(list(input$sglCell), { covis.pa$dat <- input$sglCell$datapath })
observeEvent(list(input$svgInpath1), { covis.pa$svg1 <- input$svgInpath1$datapath })
observeEvent(list(input$svgInpath2), { covis.pa$svg2 <- input$svgInpath2$datapath })
sce <- reactiveValues()
observeEvent(list(covis.pa$dat, input$fileIn, cfg$dat.def, cfg$na.cus, input$sglCell, input$dimNaCovis, input$rmetCovis, input$metCovis, input$svgInpath1, input$svgInpath2), {
library(SingleCellExperiment)
library(scater); library(scran); library(BiocSingular)
fileIn <- input$fileIn; pa <- NULL
req(check_obj(list(fileIn, cfg$na.cus, cfg$dat.def)))
# Uploaded data path.
if (is.null(covis.pa$dat)) { sce$val <- NULL } else {
pa <- covis.pa$dat
svgInpa1 <- covis.pa$svg1; svgInpa2 <- covis.pa$svg2
req(check_obj(list(pa, !is.null(svgInpa1)|!is.null(svgInpa2))))
if (grepl('\\.rds$', pa)) sce$val <- readRDS(pa) else { # Tabular files uploaded.
message('Importing covis data from tabular files ... ')
if (fileIn %in% na.cus.covis) {
withProgress(message="Loading covis data from tabular files: ", value = 0, {
dimNa <- input$dimNaCovis; req(check_obj(list(dimNa)))
incProgress(0.25, detail="importing data matrix ...")
message('Importing covis assay data ... ')
dat.cus <- fread_df(read_fr(pa), isRowGene=(dimNa=='Row'), rep.aggr=NULL)
tarCovis <- input$tarCovis$datapath; lgc.tar <- is.null(tarCovis)
if (lgc.tar) showModal(modal(msg = 'When uploading tabular files for covisualization, a targets file is required!')); req(!lgc.tar)
incProgress(0.3, detail="importing targets file ...")
sce.rep <- as(dat.cus$se.rep, "SingleCellExperiment")
message('Importing covis targets file ... ')
df.tar <- read_fr(tarCovis)
lgc.tar <- nrow(df.tar) == ncol(sce.rep)
if (!lgc.tar) showModal(modal(msg = 'Ensure "columns" in the assay matrix corresponds with "rows" in the targets file, respectively!')); req(lgc.tar)
colData(sce.rep) <- DataFrame(df.tar)
rmetCovis <- input$rmetCovis$datapath
if (!is.null(rmetCovis)) {
incProgress(0.3, detail="importing row metadata ...")
message('Importing covis row metadata ... ')
df.rmet <- read_fr(rmetCovis); lgc.met <- nrow(df.rmet) == nrow(sce.rep)
if (!lgc.met) showModal(modal(msg = 'Ensure "rows" in the assay matrix corresponds with "rows" in the row metadata file, respectively!'))
req(lgc.met); rowData(sce.rep) <- DataFrame(df.rmet)
}
metCovis <- input$metCovis$datapath
if (!is.null(metCovis)) {
incProgress(0.3, detail="importing assay metadata ...")
message('Importing covis metadata ... ')
df.meta <- read_fr(metCovis)
if (!is.null(df.meta)) {
lgc.met <- ncol(data.frame(df.meta))<2
if (lgc.met) {
msg <- 'The assay metadata should be a "data.frame" with at least two columns!';
if (lgc.met) showModal(modal(msg = msg)); req(!lgc.met)
}; metadata(sce.rep)$df.meta <- df.meta
}
}; incProgress(0.3, detail="done!")
sce$val <- sce.rep; message('Done! \n')
})
}
}
}
# Default data path of covis data.
if (grepl(na.sgl.def, fileIn)) {
pa <- cfg$dat.def[fileIn]; req(check_obj(list(pa)))
if (grepl('\\.rds$', pa)) sce$val <- readRDS(pa)
}
if (!is.null(sce$val)) {
lgc.na <- length(assayNames(sce$val))>1
if (lgc.na) showModal(modal(msg = 'Only one count matrix is expected in "assay(<SingleCellExperiment>)"!')); req(!lgc.na)
assayNames(sce$val) <- 'counts'
}
})
onBookmark(function(state) { state })
return(list(ipt = input, cfg = cfg, sce=sce, covis.pa=covis.pa))
})}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.