Nothing
server <- function(input, output, session) {
## ----------------------------------- Startup notification ------------------
observe({
showNotification("Welcome to the CHETAH shiny application.
Here, you can interact with your data and the CHETAH output.
Most plots have a help-message that can be viewed by hovering over the title of the plot.
Download buttons are present below each plot.
(These functions work better in a web-browser: click 'Open in Browser' on top of the Rstudio-window.)
Each t-SNE plot is interactive, so you can zoom in and out. Other plots will adapt
to only show information of the cells in the currently selected t-SNE window.
See the 'Info' tab for info about the method.", duration = 60)
})
## Make short links (variables) to the chetah data [links without adjustment don't take up space]
coor <- SingleCellExperiment::reducedDim(CHETAH:::ch_env$chetah, CHETAH:::ch_env$redD)
counts <- SummarizedExperiment::assay(CHETAH:::ch_env$chetah, CHETAH:::ch_env$input_c)
conf_scores <- CHETAH:::ch_env$chetah@int_colData$CHETAH$conf_scores
prof_scores <- CHETAH:::ch_env$chetah@int_colData$CHETAH$prof_scores
meta_data <- CHETAH:::ch_env$chetah@int_metadata$CHETAH
chetah <- CHETAH:::ch_env$chetah
redD <- CHETAH:::ch_env$redD
input_c <- CHETAH:::ch_env$input_c
## ----------------------------------- Select colors ------------------
## Confidence t-SNE color gradient
grad_col <- c(gplots::colorpanel(n = 50, low = '#2f2bad', mid = '#68cded', high = '#f4f4f4'),
gplots::colorpanel(n = 50, low = '#f4f4f4', mid = "#ff9f19", high = '#d60000'))
## Cell type colors
Clrs <- reactive({
req(chetah)
colors <- c ('blue', 'gold', 'cyan3', 'navy',
'forestgreen', 'orange', 'darkolivegreen3',
'brown', 'green', 'purple','deepskyblue', 'cyan',
'orangered3', 'coral', 'yellow3', "black",
'yellow1', 'darkorchid1', 'darksalmon', 'darkseagreen1',
'darkslategrey', 'deeppink4', 'green2', 'lemonchiffon1',
'lightcyan', 'midnightblue', 'maroon1', 'orange3', 'palegreen',
'palevioletred1', 'peru', 'seagreen1', 'red3', 'snow2',
'steelblue1', 'turquoise')
nnodes <- names(meta_data$nodetypes[[1]])
nodes <- c("Unassigned", paste0("Node", seq_len(length(meta_data$nodetypes) - 1)))
if(input$colornodes) {
n <- nodes
nodes <- nnodes
nnodes <- n
rm(n)
}
if (length(nodes) < 24) {
gray <- paste0('gray', rev(seq(2, 92, 4)))
} else if (length(nodes) < 24) {
gray <- paste0('gray', rev(seq(2, 92, 2)))
} else {
gray <- rep('gray70', length(nodes))
}
if (length(nnodes) > 36) colors <- grDevices::rainbow(length(nnodes) + 1)
names(colors) <- nnodes
names(gray) <- nodes
cols <- c(gray, colors)
cols <- cols[!is.na(names(cols))]
return(cols)
})
## Reactive event definition
ReDefineData <- function(event, data, coor) {
data <- data.frame(data)
if (!is.null(event)) {
if(names(event)[1] == "xaxis.range[0]") {
select <- rownames(coor)[coor[,1] > event[["xaxis.range[0]"]] &
coor[,1] < event[["xaxis.range[1]"]] &
coor[,2] > event[["yaxis.range[0]"]] &
coor[,2] < event[["yaxis.range[1]"]]]
data <- data[rownames(data) %in% select, , drop = FALSE]
}
}
return(data)
}
## ----------------------------------- Render UI ---------------------------
## Extract classification
classification <- reactive({
req(input$conf_thresh, chetah)
Classify(chetah, input$conf_thresh, return_clas = TRUE)
})
## Select a node
output$nodebutton <- renderUI ({
req(chetah)
splitmax <- length(conf_scores)
choices <- seq_len(splitmax)
names(choices) <- c(0, seq_len(splitmax - 1))
selectInput(inputId = "whichnode",
label = p("Choose a Node", class = 'opt'),
choices = choices)
})
## Select a type
output$typebutton <- renderUI ({
req(input$whichnode)
choices <- names(meta_data$nodetypes[[as.numeric(input$whichnode)]])
selectInput(inputId = "whichtype",
label = p("Choose a Type", class = 'opt'),
choices = choices)
})
## Select a type for differential expression
output$typebutton_DE <- renderUI ({
req(input$whichnode)
choices <- names(meta_data$nodetypes[[1]])
selectInput(inputId = "whichtype_DE",
label = p("Choose a Type", class = 'opt'),
choices = choices)
})
## Check whether the current type is in the current branch, otherwise stop plotting
typecorrect <- reactive({
req(input$whichtype, input$whichnode)
input$whichtype %in% names(meta_data$nodetypes[[as.numeric(input$whichnode)]])
})
## Select a gene for Tab 5
output$geneselection <- renderUI ({
req(counts)
choices <- rownames(counts)
selectInput(inputId = "whichgene",
label = p("Choose a Gene", class = 'opt'),
choices = choices)
})
## ----------------------------------- Tab 1 ---------------------------
## Classification t-SNE
classTsne <- reactive({
req(classification(), coor)
toplot <- classification()
toplot[toplot == "Unassigned"] <- "Unassigned (Node0)"
u_toplot <- unique(toplot)
toplot <- data.frame(factor(toplot, levels = c(u_toplot[grepl("Unassigned", u_toplot)],
sort(u_toplot[grepl("Node", u_toplot) & !grepl("\\(Node0)", u_toplot)]),
sort(u_toplot[!grepl("Node|Unassigned", u_toplot)]))))
colnames(toplot) <- 'Cell type'
clrs <- Clrs()
names(clrs)[names(clrs) == "Unassigned"] <- "Unassigned (Node0)"
PlotTSNE(toplot = toplot, input = chetah, redD = redD, col = clrs,
pt.size = input$ptsize, return = TRUE, shiny = 'Cell type: ') +
guides(color=guide_legend(title="Cell types")) +
guides(color=guide_legend(override.aes = list(size=6)), legend_label = 'Cell type')
})
output$classTsne <- plotly::renderPlotly({
classTsne_plot <- plotly::ggplotly(classTsne(), tooltip = 'text')
plotly::config(classTsne_plot, modeBarButtonsToRemove = c('toggleSpikelines','lasso2d', 'select2d', 'hoverCompareCartesian'), collaborate = FALSE)
})
output$dwn_clTsne <- downloadHandler(
filename = function() { paste0('CHETAH_classification_', input$conf_thresh, '.png') },
content = function(file) {
ggsave(file, plot = classTsne(), device = "png", width = 20, height = 12, dpi = 400)
}
)
## Classification Tree output
classTree <- reactive({
req(Clrs())
if (input$colornodes) interm <- TRUE else interm <- FALSE
if(interm) PlotTree(input = chetah, col_nodes = Clrs(), no_bgc = TRUE) else {
PlotTree(input = chetah, col = Clrs()) + ggtitle('')
}
})
output$classTree <- renderPlot({ classTree() })
output$dwn_clTree <- downloadHandler(
filename = function() { 'CHETAH_tree.png' },
content = function(file) {
ggsave(file, plot = classTree(), device = "png", width = 20, height = 12, dpi = 400)
}
)
## Calculate cell type percentage
typestable <- reactive({
req(classification())
types <- unique(classification())
types <- c(sort(types[!grepl('Node|Unassigned', types)]), types[grepl('Unassigned', types)] , sort(types[grepl('Node', types)]))
perc <- vector()
for (i in types) perc <- c(perc, round(sum(classification() == i)/length(classification()), 4)*100)
data <- data.frame(types, perc, stringsAsFactors = TRUE)
data$types <- factor(types, levels = types)
ggplot(data, aes_string(x = 'types', y = 'perc', label = 'perc')) +
geom_bar(stat = 'identity', aes_string(fill = 'types')) +
theme_classic() +
scale_fill_manual(values =Clrs()) +
geom_text(vjust = -0.5, fontface = 'bold')
})
output$typestable <- renderPlot({ typestable() })
output$dwn_ttable <- downloadHandler(
filename = function() { 'CHETAH_percentages.png' },
content = function(file) {
ggsave(file, plot = typestable(), device = "png", width = 20, height = 12, dpi = 400)
}
)
## ----------------------------------- Tab 2 ---------------------------
## Plot colored classification tree
confTree <- reactive({
req(Clrs(), input$whichnode)
## All black labels
nodecl <- rep('#000000', length(Clrs()))
names(nodecl) <- names(Clrs())
## Color the branches of the current node
which <- as.numeric(input$whichnode)
nodetp <- meta_data$nodetypes[[which]]
lowerns <- (which+1):length(conf_scores)
nodes <- unlist(lapply(meta_data$nodetypes[lowerns], function (x) {
if (all(names(x) %in% names(meta_data$nodetypes[[which]]))) {
nodetp[names(x)][1]
} else 3
}))
names(nodes) <- paste0('Node', lowerns - 1) ## The names are shifted 1 place
nodes <- nodes[nodes != 3]
nodecl[c(names(nodetp)[nodetp == 1], names(nodes)[nodes == 1])] <- '#ff0a0a'
nodecl[c(names(nodetp)[nodetp == 2], names(nodes)[nodes == 2])] <- '#00a1ff'
## Plot tree
PlotTree(chetah, col = nodecl, col_nodes = nodecl, no_bgc = TRUE) + ggtitle('')
})
output$confTree <- renderPlot({ confTree() })
output$dwn_confTree <- downloadHandler(
filename = function() { paste0('CHETAHtree_node', input$whichnode, '.png') },
content = function(file) {
ggsave(file, plot = confTree(), device = "png", width = 20, height = 12, dpi = 400)
}
)
## Select the max confidence of a cell in the current node
MaxConf <- reactive ({
req(input$whichnode)
which <- as.numeric(input$whichnode)
data <- conf_scores[[which]]
maxs <- apply(as.matrix(data), 1, max)
wmax <- apply(as.matrix(data), 1, which.max)
wmax <- meta_data$nodetypes[[which]][colnames(data)][wmax]
maxs[wmax == 2] <- -maxs[wmax == 2]
return(maxs)
})
## Select current types incl nodes
SlctNodes <- reactive ({
req(input$whichnode)
which <- as.numeric(input$whichnode)
nodes <- unlist(lapply(meta_data$nodetypes[(which):length(conf_scores)], function (x) {
all(names(x) %in% names(meta_data$nodetypes[[which]]))
}))
nodes <- paste0('Node', ((which - 1):(length(conf_scores) - 1))[nodes])
nodes[grepl("Node0", nodes)] <- "Unassigned"
nodes <- c(nodes, names(meta_data$nodetypes[[which]]))
return(nodes)
})
## Select the input cell still in the current branch
SlctCells <- reactive ({
req(SlctNodes, classification())
cellnms <- names(classification())[classification() %in% SlctNodes()]
return(cellnms)
})
## Confidence t-SNE
confTsne <- reactive({
req(SlctCells(), MaxConf(), input$whichnode)
data <- data.frame(MaxConf()[SlctCells()], classification()[SlctCells()])
colnames(data) <- c('Confidence', 'cell type')
coor_prof <- coor[SlctCells(), ]
coor_prof <- coor_prof[rownames(data), ]
pl <- PlotTSNE(toplot = data, input = chetah, redD = redD,
col = grad_col, limits = c(-2,2),
pt.size = input$ptsize, return = TRUE, shiny = 'confidence score: ',
x_limits = c(min(coor[,1]), max(coor[,1])),
y_limits = c(min(coor[,2]), max(coor[,2])),
legend_label = 'Confidence')
pl + labs(color = 'Confidence')
})
output$confTsne <- plotly::renderPlotly({
confTsne_plot <- plotly::ggplotly(confTsne(), tooltip = c('text'), source = 'conf')
plotly::config(confTsne_plot, modeBarButtonsToRemove = c('toggleSpikelines','lasso2d', 'select2d', 'hoverCompareCartesian'), collaborate = FALSE)
})
output$dwn_confTsne <- downloadHandler(
filename = function() { paste0('CHETAH_confidence_node', input$whichnode, '.png') },
content = function(file) {
ggsave(filename = file, plot = confTsne(), device = "png", width = 20, height = 12, dpi = 400)
}
)
## Observe plotly_event, but update to null, when new node is chosen: this doesn't happen automatically
zoom <- reactive ({ plotly::event_data("plotly_relayout", source = 'conf') })
rv <- reactiveValues(conf = NULL)
observeEvent(zoom(), {
rv$conf <- zoom()
})
observeEvent(input$whichnode, {
rv$conf <- NULL
})
## Confidence heatmap
confHM <- reactive({
req(SlctCells(), MaxConf(), input$whichnode, rv)
## select the data and sort
which <- as.numeric(input$whichnode)
data <- prof_scores[[which]]
branchtypes <- sort(meta_data$nodetypes[[which]])
data <- data[ ,names(branchtypes)]
data <- data[names(sort(MaxConf())), ]
data <- data[rownames(data) %in% SlctCells(), ]
data <- ReDefineData(event = rv$conf, data = data, coor = coor)
classif <- data.frame('celltypes' = classification()[rownames(data)])
if (nrow(data) > 0) {
if (input$sortByType) data <- data[rownames(classif)[order(classif)], ]
ann_col <- list('celltypes' = Clrs()[SlctNodes()])
## Rescale gradient colors
rng <- (range(data) + 1)*50
grad_clrs <- grad_col[rng[1]:rng[2]]
pheatmap::pheatmap(t(data),
color = grad_clrs,
border_color = NA,
cluster_cols = FALSE,
cluster_rows = FALSE,
show_colnames = FALSE,
scale = "none",
annotation_col = classif,
annotation_colors = ann_col,
height = input$matrixheight)
} else {
NULL
}
})
output$confHM <- renderPlot({
if ('RStudioGD' %in% names(dev.list())) dev.off(which = which(names(dev.list()) == 'RStudioGD') + 1)
print(confHM())
})
output$dwn_confHM <- downloadHandler(
filename = function() { paste0('CHETAH_prof_score_heatmap_node', input$whichnode, '.png') },
content = function(file) {
png(file, width = 20, height = 12, res = 400, units = 'in')
print(confHM())
dev.off()
}
)
## ----------------------------------- Tab 3 ---------------------------
## Zoom of tSNE must be retained when new data is plotted: this doesn't happen automatically
zoom2 <- reactive ({ plotly::event_data("plotly_relayout", source = 'prof') })
rv2 <- reactiveValues(prof = NULL)
observeEvent(input$whichnode, {
rv2$prof <- zoom2()
})
observeEvent(input$whichtype, {
rv2$prof <- zoom2()
})
observeEvent(zoom2(), {
rv2$prof <- NULL
})
## Profiel score t-SNE
profTsne <- reactive({
req(typecorrect(), chetah, rv2)
toplot <- data.frame(prof_scores[[as.numeric(input$whichnode)]][ ,input$whichtype, drop = FALSE],
classification())
colnames(toplot) <- c('Profile score', 'cell type')
if (!is.null(rv2$prof)) toplot <- ReDefineData(event = zoom2(), data = toplot, coor = coor)
coor <- coor[rownames(toplot), ]
pl <- PlotTSNE(toplot, input = chetah, redD = redD,
col = grad_col,
limits = c(-1,1),
pt.size = input$ptsize, return = TRUE, shiny = 'Profile score: ',
legend_label = 'Profile score') +
labs(color = 'Profile score')
pl
})
output$profTsne <- plotly::renderPlotly({
profTsne_plot <- plotly::ggplotly(profTsne(), tooltip = c('text'), source = 'prof')
plotly::config(profTsne_plot, modeBarButtonsToRemove = c('toggleSpikelines','lasso2d', 'select2d', 'hoverCompareCartesian'), collaborate = FALSE)
})
output$dwn_profTsne <- downloadHandler(
filename = function() { paste0('CHETAH_prof_scores_node', input$whichnode, 'type_', input$whichtype, '.png') },
content = function(file) {
png(file, width = 20, height = 12, res = 400, units = 'in')
print(profTsne())
dev.off()
}
)
## Profile score Boxplot
profBox <- reactive({
req(typecorrect(), chetah)
toplot <- as.data.frame(prof_scores[[as.numeric(input$whichnode)]][ ,input$whichtype, drop = FALSE])
clas <- as.data.frame(classification())
event <- plotly::event_data("plotly_relayout", source = 'prof')
toplot <- ReDefineData(event = event, data = toplot, coor = coor)
clas <- ReDefineData(event = event, data = clas, coor = coor)
CHETAH:::PlotBox(class = clas,
toplot = toplot,
col = Clrs())
})
output$profBox <- renderPlot({ profBox() })
output$dwn_profBox <- downloadHandler(
filename = function() { paste0('CHETAHboxpl_prof_scores_node', input$whichnode, 'type_', input$whichtype, '.png') },
content = function(file) {
png(file, width = 20, height = 12, res = 400, units = 'in')
print(profBox())
dev.off()
}
)
## Plot colored classification tree
celltTree <- reactive({
req(typecorrect())
function(){
## All black labels
nodecl <- rep('#000000', length(Clrs()))
names(nodecl) <- names(Clrs())
## Color the current type in the current node
which <- as.numeric(input$whichnode)
lowerns <- (which+1):length(meta_data$nodetypes)
nodetp <- meta_data$nodetypes[[which]]
nodes <- unlist(lapply(meta_data$nodetypes[lowerns], function (x) {
if (all(names(x) %in% names(meta_data$nodetypes[[which]]))) {
nodetp[names(x)][1]
} else 3
}))
names(nodes) <- paste0('Node', lowerns - 1)
nodes <- nodes[nodes != 3]
if (input$whichtype %in% names(nodetp)[nodetp == 1]) {
nodecl[c(names(nodetp)[nodetp == 2], names(nodes)[nodes == 2])] <- '#ff0a0a'
nodecl[input$whichtype] <- '#00a1ff'
} else {
nodecl[c(names(nodetp)[nodetp == 1], names(nodes)[nodes == 1])] <- '#00a1ff'
nodecl[input$whichtype] <- '#ff0a0a'
}
## Plot tree
PlotTree(chetah, col = nodecl, col_nodes = nodecl, no_bgc = TRUE) + ggtitle('')
}
})
output$profTree <- renderPlot({ celltTree()() })
## ----------------------------------- Tab4 ---------------------------
## Select cells
HMcells <- reactive({
req(typecorrect(), classification(), SlctNodes())
which <- as.numeric(input$whichnode)
## Select cells
branchtypes <- names(sort(meta_data$nodetypes[[which]]))
if (input$inclnodes) {
branchtypes <- c(branchtypes, SlctNodes()[grepl("Node|Unassigned", SlctNodes())])
}
cells <- classification()[classification() %in% branchtypes]
cells <- cells[order(match(cells, branchtypes))]
validate(
need(cells > 0, "
No cells to display in this Node. Lowering the 'Confidence Threshold' might work.
Please check the 'Classification' tab to see the classification with the current 'Confidence Threshold'")
)
return(cells)
})
## Select genes
HMgenes <- reactive({
req(HMcells())
which <- as.numeric(input$whichnode)
## Select Genes
if (input$largediff) {
finaltypes <- sort(meta_data$nodetypes[[which]])
lh_genes <- meta_data$genes[[which]][[input$whichtype]]
data <- as.matrix(counts[names(lh_genes), names(HMcells())])
r_branch <- apply(as.matrix(data[ ,names(HMcells())[HMcells() %in% names(finaltypes)[finaltypes == 1]]]), 1, mean)
l_branch <- apply(as.matrix(data[ ,names(HMcells())[HMcells() %in% names(finaltypes)[finaltypes == 2]]]), 1, mean)
lh_genes <- lh_genes[names(sort(abs(r_branch - l_branch), decreasing = TRUE))[seq_len(input$n_genes)]]
lh_genes <- sort(lh_genes)
## If no cells in one of the two branches: Don't sort
if (length(lh_genes) == 0) lh_genes <- sort(meta_data$genes[[which]][[input$whichtype]][seq_len(input$n_genes)])
} else {
lh_genes <- sort(meta_data$genes[[which]][[input$whichtype]][seq_len(input$n_genes)])
}
lh_genes[lh_genes == 0] <- 'lowly'
lh_genes[lh_genes == 1] <- 'highly'
return(lh_genes)
})
## Gene heatmap
exprHM <- reactive({
req(HMgenes())
which <- as.numeric(input$whichnode)
## Select cells
branchtypes <- names(sort(meta_data$nodetypes[[which]]))
if (input$inclnodes) {
branchtypes <- c(branchtypes, SlctNodes()[grepl("Node|Unassigned", SlctNodes())])
}
genes <- names(HMgenes())
data <- as.matrix(counts[genes, names(HMcells())])
hl_clrs <- c('black', 'gray80')
names(hl_clrs) <- c('lowly', 'highly')
annotation_col <- data.frame('celltypes' = HMcells())
annotation_row <- data.frame('Expressed_in_this_type' = HMgenes())
ann_col <- list('celltypes' = Clrs()[branchtypes],
'Expressed_in_this_type' = hl_clrs)
if (input$scaling) scale <- 'row' else scale <- 'none'
## Plot
pheatmap::pheatmap(data,
color = grad_col,
border_color = NA,
cluster_cols = FALSE,
cluster_rows = FALSE,
show_colnames = FALSE,
scale = scale,
annotation_col = annotation_col,
annotation_row = annotation_row,
annotation_colors = ann_col,
fontsize_row = input$lettersize,
annotation_names_row = FALSE)
})
output$exprHM <- renderPlot({
if ('RStudioGD' %in% names(dev.list())) dev.off(which = which(names(dev.list()) == 'RStudioGD') + 1)
exprHM()
})
output$dwn_exprHM <- downloadHandler(
filename = function() { paste0('CHETAH_HM_node', input$whichnode, '_', input$whichtype, '.png') },
content = function(file) {
png(file, width = 20, height = 12, res = 400, units = 'in')
print(exprHM())
dev.off()
}
)
## Download the genes!
output$dwn_genes <- downloadHandler(
filename = function() { paste0('CHETAHgenes_node', input$whichnode, '_', input$whichtype, '.txt') },
content = function(con) {
write.table(matrix(names(HMgenes()), ncol = 1), file = con, sep = '\t', quote = FALSE, row.names = FALSE, col.names = FALSE)
}
)
## Plot classification tree
output$genesTree <- renderPlot({ celltTree()() })
## ----------------------------------- Tab5 ---------------------------
geneExpr <- reactive({
req(input$whichgene, classification())
genes <- counts[input$whichgene, ]
#if(!is.null(log)) genes <- log2(genes + 1)
genes <- cbind.data.frame(genes, as.data.frame(classification()))
#if(!is.null(sub)) genes <- genes[genes$type %in% sub, ]
colnames(genes) <- c('gene', 'type')
suppressMessages(genes <- reshape2::melt(genes))
ggplot(genes, aes(x=type, y = value)) +
geom_jitter(aes(color = type), size = 2) +
geom_boxplot(aes(color = type), fill = rgb(1,1,1,0.5), outlier.colour = "NA") +
theme_classic() +
theme(axis.text.x = element_text(angle = 60, hjust = 1, size = 10),
axis.title.x = element_blank()) +
guides(color=FALSE) +
scale_color_manual(values = Clrs())
})
output$geneExpr <- renderPlot({ geneExpr() })
output$dwn_geneExpr <- downloadHandler(
filename = function() { paste0('CHETAH_gene_exp_', input$whichgene, '.png') },
content = function(file) {
png(file, width = 20, height = 12, res = 400, units = 'in')
print(geneExpr())
dev.off()
}
)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.