Spaces:
Sleeping
Sleeping
--- | |
title: "Bioinformatics Dashboard v0.0 🧬 🦠 🧫" | |
output: | |
flexdashboard::flex_dashboard: | |
orientation: columns | |
vertical_layout: fill | |
runtime: shiny | |
--- | |
```{r setup, include=FALSE} | |
if (!requireNamespace("pacman", quietly = TRUE)) { | |
install.packages("pacman") | |
} | |
pacman::p_load(flexdashboard, shiny, ggplot2, plotly, clusterProfiler, readxl, tidyverse, DESeq2, biomaRt, tidyr, shinyjs, rentrez, dplyr, ggtext, cowplot, UpSetR) | |
library(flexdashboard) | |
library(shiny) | |
library(ggplot2) | |
library(plotly) | |
library(clusterProfiler) | |
library(readxl) | |
library(tidyverse) | |
library(DESeq2) | |
library(biomaRt) | |
library(tidyr) | |
library(shinyjs) | |
library(rentrez) | |
library(dplyr) | |
library(ggtext) | |
library(cowplot) | |
library(UpSetR) | |
``` | |
Column {.tabset} | |
----------------------------------------------------------------------- | |
### RNAseq analysis | |
Analyzes RNAseq data using DESeq2 and GSEA. Visualizes using volcano plot, and other plots to show the GSEA analysis results. Please make sure the uploaded data is in xlsx format, has the first column with the gene names, and there is an even number of data columns. The control condition should be first, the mutant condition second. | |
```{r} | |
ui <- fluidPage( | |
titlePanel("Interactive Volcano Plot with Gene and GO Term Search"), | |
useShinyjs(), | |
passwordInput("password", "Enter Password:", value = "", placeholder = "Password"), | |
actionButton("submit_password", "Submit"), | |
uiOutput("main_ui"), | |
#if you define a side_ui --> absolute panel, it would have to be defined here | |
) | |
# Server logic | |
server <- function(input, output, session) { | |
# Password handling | |
correct_password <- "my_secret_password" | |
observeEvent(input$submit_password, { | |
if (input$password == correct_password) { | |
showModal(modalDialog( | |
title = "Access Granted", | |
"Welcome! You can now search for genes and view the volcano plot.", | |
easyClose = TRUE, | |
footer = NULL | |
)) | |
# Hide the password input and button after validation | |
shinyjs::hide("password") | |
shinyjs::hide("submit_password") | |
# Main UI appears after password is correct | |
output$main_ui <- renderUI({ | |
sidebarLayout( | |
sidebarPanel( | |
fluidRow( | |
fileInput("file", "Choose XLSX File", multiple = FALSE, accept = c(".xlsx", "text/xlsx")), | |
actionButton("analyze_button", "Analyze"), | |
tags$hr(), | |
textInput("gene_search", "Search for a gene or keyword (separate multiple genes with ';'):", ""), | |
actionButton("search_gene", "Search Gene"), | |
tags$hr(), | |
selectInput("GO_search", "Select a GO term:", choices = NULL), | |
actionButton("search_GO_term", "Search GO Term"), | |
tags$hr(), | |
selectInput("description_search", "Search for the name of a pathway:", choices = NULL), | |
actionButton("search_description", "Search Description"), | |
tags$hr(), | |
sliderInput("pvalue", "P-value: ", | |
min = 0, max = 1, | |
value = 0.01, step = 0.00001), | |
tags$hr(), | |
sliderInput("log2fc", "Log2FoldChange: ", | |
min = 0.0001, max = 100, | |
value = 2.5, step = 0.05), | |
tags$hr(), | |
actionButton("visualize_gse", "Visualize the GSEGO Results:") | |
) | |
), | |
mainPanel( | |
plotlyOutput("volcanoPlot"), | |
plotOutput("dotPlotTitle", width = "100%", height = "100px"), | |
plotOutput("dotPlot", width = "100%", height = "1000px"), | |
plotOutput("conceptNetworkTitle", width = "100%", height = "100px"), | |
plotOutput("conceptNetwork", width = "100%", height = "600px"), | |
plotOutput("heatMapTitle", width = "100%", height = "100px"), | |
plotOutput("heatMap", width = "100%", height = "400px"), | |
plotOutput("upsetPlotTitle", width = "100%", height = "100px"), | |
plotOutput("upsetPlot", width = "100%", height = "1000px"), | |
plotOutput("pubmedPathwayPlotTitle", width = "100%", height = "100px"), | |
plotOutput("pubmedPathwayPlot", width = "100%", height = "1500px") | |
) | |
) | |
}) | |
# Reactive values to store results and search criteria | |
searchValues <- reactiveValues( | |
gene_search = "", | |
GO_search = "All", | |
description_search = "", | |
df_inverted = NULL # Store df_inverted here | |
) | |
# Process uploaded file and perform DESeq2 analysis | |
observeEvent(input$analyze_button, { | |
req(input$file) # Ensure a file is uploaded | |
# Read in gene counts data | |
genecounts <- tryCatch({ | |
read_excel(input$file$datapath, sheet = 1, col_names = TRUE) | |
}, error = function(e) { | |
showModal(modalDialog(title = "Error", "Could not read the Excel file.", easyClose = TRUE)) | |
return(NULL) | |
}) | |
if (is.null(genecounts)) return(NULL) # Stop further processing if reading failed | |
genecounts <- as | .frame(genecounts)|
rownames(genecounts) <- genecounts[, 1] | |
genecounts$Gene_Name <- NULL | |
genecounts <- genecounts[, -1] | |
num_samples <- ncol(genecounts) | |
# Check if the number of samples is even | |
if (num_samples %% 2 != 0) { | |
showModal(modalDialog( | |
title = "Error", | |
"The number of samples must be even for proper grouping.", | |
easyClose = TRUE | |
)) | |
return(NULL) | |
} | |
# Create the condition data frame | |
condition <- data.frame(genotype = rep(c('C', 'R'), each = num_samples / 2), row.names = colnames(genecounts)) | |
# Create DESeq2 dataset | |
dds <- DESeqDataSetFromMatrix(countData = genecounts, colData = condition, design = ~genotype) | |
de <- DESeq(dds) | |
res_reactive <- reactiveVal() | |
res_reactive(results(de)) | |
res <<- results(de) | |
# Create additional columns for plotting | |
res$pvalue_log10 <- -log10(res$pvalue) | |
pvalue_threshold <- 0.05 | |
fold_change_threshold <- 2 | |
res$significance <- ifelse(res$pvalue < pvalue_threshold, "Significant", "Not Significant") | |
res$new_column <- rownames(res) | |
res$diffexpressed <- ifelse(res$log2FoldChange > 0, "UP", ifelse(res$log2FoldChange < 0, "DOWN", "NO_CHANGE")) | |
# Generate gene list for GSEA | |
organism = "org.Hs.eg.db" | |
original_gene_list <- res$log2FoldChange | |
names(original_gene_list) <- res$new_column | |
gene_list <<- na.omit(original_gene_list) | |
gene_list = sort(gene_list, decreasing = TRUE) | |
# Perform GO enrichment analysis | |
gse <<- gseGO(geneList = gene_list, | |
ont = "ALL", | |
keyType = "SYMBOL", | |
minGSSize = 3, | |
maxGSSize = 800, | |
pvalueCutoff = 0.05, | |
verbose = TRUE, | |
OrgDb = organism, | |
pAdjustMethod = "none") | |
# Store inverted results for GO terms in reactive values | |
searchValues$df_inverted <- gse@result %>% separate_rows(core_enrichment, sep = "/") | |
# Update GO term and description choices in UI | |
updateSelectInput(session, "GO_search", choices = unique(searchValues$df_inverted$ID)) | |
updateSelectInput(session, "description_search", choices = unique(searchValues$df_inverted$Description)) | |
# Reactive filtering of results based on user input | |
filteredRes <- reactive({ | |
data <- as | .frame(res)|
# Apply gene search filter | |
if (searchValues$gene_search != "") { | |
genes <- strsplit(searchValues$gene_search, ";")[[1]] | |
genes <- trimws(genes) | |
data <- data %>% | |
filter(rowSums(sapply(genes, function(gene) grepl(gene, new_column, ignore.case = TRUE))) > 0) | |
} | |
# Apply GO term filter | |
if (searchValues$GO_search != "All") { | |
selected_genes <- searchValues$df_inverted %>% | |
filter(ID == searchValues$GO_search) %>% | |
pull(core_enrichment) | |
data <- data %>% | |
filter(new_column %in% selected_genes) | |
} | |
# Apply description search filter | |
if (searchValues$description_search != "") { | |
selected_genes <- searchValues$df_inverted %>% | |
filter(Description == searchValues$description_search) %>% | |
pull(core_enrichment) | |
data <- data %>% | |
filter(new_column %in% selected_genes) | |
} | |
data | |
}) | |
# Render volcano plot based on filtered results | |
output$volcanoPlot <- renderPlotly({ | |
data_res <- filteredRes() | |
p_value <- input$pvalue #need to add slides here | |
log2fc <- input$log2fc #need to add slider here | |
p <- ggplot(data_res, aes(x = log2FoldChange, y = pvalue_log10, | |
text = paste("Gene:", new_column, "<br>Log2 Fold Change:", log2FoldChange, | |
"<br>P-value:", pvalue, "<br>Significance:", significance, | |
"<br>Differentially Expressed:", diffexpressed, "<br>-log10 Values:", pvalue_log10))) + | |
geom_point(aes(color = log2FoldChange, shape = diffexpressed)) + | |
geom_hline(yintercept = -log10(p_value), linetype = "dotted", color = "red") + | |
geom_vline(xintercept = c(-log2fc, log2fc), linetype = "dotted", color = "darkblue") + | |
xlim(-5, 5) + | |
xlab("Log2 Fold Change") + | |
ylab("-log10(P-value)") + | |
ggtitle("Volcano Plot") + | |
scale_color_gradient2(low = "green", mid = "pink", high = "blue", midpoint = 0, | |
name = "Log2 Fold Change") # Add a custom color scale for the color legends | |
ggplotly(p, tooltip = "text") | |
}) | |
}) | |
# Update search criteria based on user actions | |
observeEvent(input$search_gene, { | |
searchValues$gene_search <- input$gene_search | |
searchValues$GO_search <- "All" | |
searchValues$description_search <- "" | |
}) | |
observeEvent(input$search_GO_term, { | |
searchValues$GO_search <- input$GO_search | |
searchValues$gene_search <- "" | |
searchValues$description_search <- "" | |
}) | |
observeEvent(input$search_description, { | |
searchValues$description_search <- input$description_search | |
searchValues$GO_search <- "All" | |
searchValues$gene_search <- "" | |
}) | |
observeEvent(input$visualize_gse, { | |
library(ggplot2) | |
library(ggtext) | |
library(gridExtra) | |
output$dotPlotTitle <- renderPlot({ | |
txt <- "Dot Plot with 10 Pathways" | |
title_plot <- ggplot() + | |
geom_textbox( | |
aes(x = 0, y = 0, label = txt), | |
size = 18 / .pt, | |
width = unit(6, "inches") | |
) + | |
theme_void() | |
print(title_plot) | |
}) | |
output$dotPlot <- renderPlot({ | |
dot_plot <- dotplot(gse, showCategory = 10) | |
print(dot_plot) | |
}) | |
output$conceptNetworkTitle <- renderPlot({ | |
txt <- "Gene Concept Network" | |
title_plot <- ggplot() + | |
geom_textbox( | |
aes(x = 0, y = 0, label = txt), | |
size = 18 / .pt, | |
width = unit(6, "inches") | |
) + | |
theme_void() | |
print(title_plot) | |
}) | |
output$conceptNetwork <- renderPlot({ | |
gsex <- setReadable(gse, 'org.Hs.eg.db', 'ENTREZID') | |
geneList <- gse@geneList | |
p1 <- cnetplot(gsex, foldChange = geneList, max.overlaps = 100) | |
p2 <- cnetplot(gsex, categorySize = "pvalue", foldChange = geneList, max.overlaps = 100) | |
p3 <- cnetplot(gsex, foldChange = geneList, circular = TRUE, colorEdge = TRUE, max.overlaps = 100) | |
maingene_plot <- cowplot::plot_grid(p1, p2, p3, ncol = 3, labels = LETTERS[1:3], rel_widths = c(.8, .8, 1.2)) | |
print(maingene_plot) | |
}) | |
output$heatMapTitle <- renderPlot({ | |
txt <- "Heatmap-Like Functional Classification" | |
title_plot <- ggplot() + | |
geom_textbox( | |
aes(x = 0, y = 0, label = txt), | |
size = 18 / .pt, | |
width = unit(6, "inches") | |
) + | |
theme_void() | |
print(title_plot) | |
}) | |
output$heatMap <- renderPlot({ | |
gsex <- setReadable(gse, 'org.Hs.eg.db', 'ENTREZID') | |
geneList <- gse@geneList | |
p1 <- heatplot(gsex, showCategory=5) | |
p2 <- heatplot(gsex, foldChange=geneList, showCategory=5) | |
mainheatmap_plot <- cowplot::plot_grid(p1, p2, ncol=1, labels=LETTERS[1:2]) | |
print(mainheatmap_plot) | |
}) | |
output$upsetPlotTitle <- renderPlot({ | |
txt <- "UpSet Plot" | |
title_plot <- ggplot() + | |
geom_textbox( | |
aes(x = 0, y = 0, label = txt), | |
size = 18 / .pt, | |
width = unit(6, "inches") | |
) + | |
theme_void() | |
print(title_plot) | |
}) | |
output$upsetPlot <- renderPlot({ | |
gse_df <- gse@result | |
top_terms <- gse_df %>% arrange(pvalue) %>% head(10) | |
top_gene_sets <- strsplit(top_terms$core_enrichment, "/") | |
gene_sets_list <- lapply(top_gene_sets, function(x) unique(trimws(x))) | |
gene_sets_df <- fromList(setNames(gene_sets_list, top_terms$ID)) | |
# Create the UpSet plot | |
upset_plot <- upset(gene_sets_df, | |
sets = names(gene_sets_df), | |
main.bar.color = "steelblue", | |
sets.bar.color = "darkred", | |
order.by = "freq", | |
matrix.color = "gray", | |
keep.order = TRUE) | |
print(upset_plot) | |
}) | |
output$pubmedPathwayPlotTitle <- renderPlot({ | |
txt <- "PubMed Pathway Enrichment" | |
title_plot <- ggplot() + | |
geom_textbox( | |
aes(x = 0, y = 0, label = txt), | |
size = 18 / .pt, | |
width = unit(6, "inches") | |
) + | |
theme_void() | |
print(title_plot) | |
}) | |
output$pubmedPathwayPlot <- renderPlot({ | |
results <- data.frame(Term = character(), Year = integer(), Count = integer(), stringsAsFactors = FALSE) | |
terms <- tail(gse$Description, n = 10) | |
results <- data.frame() | |
titles_2024 <- data.frame() | |
for (term in terms) { | |
for (year in 2014:2024) { | |
query <- paste(term, "[Title/Abstract] AND", year, "[PDAT]") | |
# Count results for each term and year | |
search_results <- entrez_search(db = "pubmed", term = query, retmax = 0) | |
results <- rbind(results, data.frame(Term = term, Year = year, Count = search_results$count)) | |
# If the year is 2024, retrieve the first 10 article titles | |
if (year == 2024) { | |
search_results_2024 <- entrez_search(db = "pubmed", term = query, retmax = 10) | |
if (search_results_2024$count > 0) { | |
article_ids <- search_results_2024$ids | |
articles <- entrez_fetch(db = "pubmed", id = article_ids, rettype = "abstract", retmode = "text") | |
titles <- sapply(strsplit(articles, "\n"), function(x) x[1]) | |
titles_2024 <- reactive({rbind(titles_2024, data.frame(Term = term, Title = titles, stringsAsFactors = FALSE))}) | |
} | |
} | |
} | |
} | |
total_counts <- results %>% | |
group_by(Year) %>% | |
summarize(Total_Count = sum(Count), .groups = 'drop') | |
results <- results %>% | |
left_join(total_counts, by = "Year") | |
results <- results %>% | |
mutate(Ratio = Count / Total_Count) | |
print(results) | |
mainpubmed_plot <- ggplot(results, aes(x = Year, y = Ratio, color = Term)) + | |
geom_line() + | |
geom_point(size = 3, shape = 20, fill = "white", stroke = 1) + # Bolded dots | |
scale_x_continuous(limits = c(2013, 2025), breaks = seq(2013, 2025, by = 2.5)) + # 2.5-year breaks | |
labs(title = "Publication Ratio for Enriched Terms", x = "Year", y = "Publication Ratio") + | |
theme_minimal() | |
print(mainpubmed_plot) | |
}) | |
}) | |
} else { | |
showModal(modalDialog( | |
title = "Access Denied", | |
"Incorrect password. Please try again.", | |
easyClose = TRUE, | |
footer = NULL | |
)) | |
} | |
}) | |
} | |
shinyApp(ui = ui, server = server) | |
``` | |
### Proteomics analysis | |
Analyzes proteomics data using DESeq2 and GSEA. Visualizes using volcano plot, and other plots to show the GSEA analysis results. Please make sure the uploaded data is in xlsx format, has the first column with the gene names, and the second column has the expanded name of each gene and there is an even number of data columns. The control condition should be first, the mutant condition second. | |
```{r} | |
ui <- fluidPage( | |
titlePanel("Interactive Volcano Plot with Gene and GO Term Search"), | |
useShinyjs(), | |
passwordInput("password", "Enter Password:", value = "", placeholder = "Password"), | |
actionButton("submit_password", "Submit"), | |
uiOutput("main_ui"), | |
#if you define a side_ui --> absolute panel, it would have to be defined here | |
) | |
# Server logic | |
server <- function(input, output, session) { | |
# Password handling | |
correct_password <- "my_secret_password" | |
observeEvent(input$submit_password, { | |
if (input$password == correct_password) { | |
showModal(modalDialog( | |
title = "Access Granted", | |
"Welcome! You can now search for genes and view the volcano plot.", | |
easyClose = TRUE, | |
footer = NULL | |
)) | |
# Hide the password input and button after validation | |
shinyjs::hide("password") | |
shinyjs::hide("submit_password") | |
# Main UI appears after password is correct | |
output$main_ui <- renderUI({ | |
sidebarLayout( | |
sidebarPanel( | |
fluidRow( | |
fileInput("file", "Choose XLSX File", multiple = FALSE, accept = c(".xlsx", "text/xlsx")), | |
actionButton("analyze_button", "Analyze"), | |
tags$hr(), | |
textInput("gene_search", "Search for a gene or keyword (separate multiple genes with ';'):", ""), | |
actionButton("search_gene", "Search Gene"), | |
tags$hr(), | |
selectInput("GO_search", "Select a GO term:", choices = NULL), | |
actionButton("search_GO_term", "Search GO Term"), | |
tags$hr(), | |
selectInput("description_search", "Search for the name of a pathway:", choices = NULL), | |
actionButton("search_description", "Search Description"), | |
tags$hr(), | |
sliderInput("pvalue", "P-value: ", | |
min = 0, max = 1, | |
value = 0.01, step = 0.00001), | |
tags$hr(), | |
sliderInput("log2fc", "Log2FoldChange: ", | |
min = 0.0001, max = 100, | |
value = 2.5, step = 0.05), | |
tags$hr(), | |
actionButton("visualize_gse", "Visualize the GSEGO Results:") | |
) | |
), | |
mainPanel( | |
plotlyOutput("volcanoPlot"), | |
plotOutput("dotPlotTitle", width = "100%", height = "100px"), | |
plotOutput("dotPlot", width = "100%", height = "1000px"), | |
plotOutput("conceptNetworkTitle", width = "100%", height = "100px"), | |
plotOutput("conceptNetwork", width = "100%", height = "600px"), | |
plotOutput("heatMapTitle", width = "100%", height = "100px"), | |
plotOutput("heatMap", width = "100%", height = "400px"), | |
plotOutput("upsetPlotTitle", width = "100%", height = "100px"), | |
plotOutput("upsetPlot", width = "100%", height = "1000px"), | |
plotOutput("pubmedPathwayPlotTitle", width = "100%", height = "100px"), | |
plotOutput("pubmedPathwayPlot", width = "100%", height = "1500px") | |
) | |
) | |
}) | |
# Reactive values to store results and search criteria | |
searchValues <- reactiveValues( | |
gene_search = "", | |
GO_search = "All", | |
description_search = "", | |
df_inverted = NULL # Store df_inverted here | |
) | |
# Process uploaded file and perform DESeq2 analysis | |
observeEvent(input$analyze_button, { | |
req(input$file) # Ensure a file is uploaded | |
# Read in gene counts data | |
genecounts <- tryCatch({ | |
read_excel(input$file$datapath, sheet = 1, col_names = TRUE) | |
}, error = function(e) { | |
showModal(modalDialog(title = "Error", "Could not read the Excel file.", easyClose = TRUE)) | |
return(NULL) | |
}) | |
if (is.null(genecounts)) return(NULL) # Stop further processing if reading failed | |
genecounts <- as | .frame(genecounts)|
rownames(genecounts) <- genecounts[, 1] | |
genecounts <- genecounts[, -1] | |
descriptions <<- data.frame(Description = genecounts[, 1]) | |
rownames(descriptions) <- rownames(genecounts) | |
genecounts <- genecounts[, -1] | |
num_samples <- ncol(genecounts) | |
num_samples <- ncol(genecounts) | |
# Check if the number of samples is even | |
if (num_samples %% 2 != 0) { | |
showModal(modalDialog( | |
title = "Error", | |
"The number of samples must be even for proper grouping.", | |
easyClose = TRUE | |
)) | |
return(NULL) | |
} | |
# Create the condition data frame | |
condition <- data.frame(genotype = rep(c('C', 'R'), each = num_samples / 2), row.names = colnames(genecounts)) | |
# Create DESeq2 dataset | |
dds <- DESeqDataSetFromMatrix(countData = genecounts, colData = condition, design = ~genotype) | |
de <- DESeq(dds) | |
res_reactive <- reactiveVal() | |
res_reactive(results(de)) | |
res <<- results(de) | |
# Create additional columns for plotting | |
res$pvalue_log10 <- -log10(res$pvalue) | |
pvalue_threshold <- 0.05 | |
fold_change_threshold <- 2 | |
res$significance <- ifelse(res$pvalue < pvalue_threshold, "Significant", "Not Significant") | |
res$new_column <- rownames(res) | |
res$diffexpressed <- ifelse(res$log2FoldChange > 0, "UP", ifelse(res$log2FoldChange < 0, "DOWN", "NO_CHANGE")) | |
# Generate gene list for GSEA | |
organism = "org.Hs.eg.db" | |
original_gene_list <- res$log2FoldChange | |
names(original_gene_list) <- res$new_column | |
gene_list <<- na.omit(original_gene_list) | |
gene_list = sort(gene_list, decreasing = TRUE) | |
# Perform GO enrichment analysis | |
gse <<- gseGO(geneList = gene_list, | |
ont = "ALL", | |
keyType = "SYMBOL", | |
minGSSize = 3, | |
maxGSSize = 800, | |
pvalueCutoff = 0.05, | |
verbose = TRUE, | |
OrgDb = organism, | |
pAdjustMethod = "none") | |
# Store inverted results for GO terms in reactive values | |
searchValues$df_inverted <- gse@result %>% separate_rows(core_enrichment, sep = "/") | |
# Update GO term and description choices in UI | |
updateSelectInput(session, "GO_search", choices = unique(searchValues$df_inverted$ID)) | |
updateSelectInput(session, "description_search", choices = unique(searchValues$df_inverted$Description)) | |
# Reactive filtering of results based on user input | |
filteredRes <- reactive({ | |
data <- as | .frame(res)|
# Apply gene search filter | |
if (searchValues$gene_search != "") { | |
genes <- strsplit(searchValues$gene_search, ";")[[1]] | |
genes <- trimws(genes) | |
data <- data %>% | |
filter(rowSums(sapply(genes, function(gene) grepl(gene, new_column, ignore.case = TRUE))) > 0) | |
} | |
# Apply GO term filter | |
if (searchValues$GO_search != "All") { | |
selected_genes <- searchValues$df_inverted %>% | |
filter(ID == searchValues$GO_search) %>% | |
pull(core_enrichment) | |
data <- data %>% | |
filter(new_column %in% selected_genes) | |
} | |
# Apply description search filter | |
if (searchValues$description_search != "") { | |
selected_genes <- searchValues$df_inverted %>% | |
filter(Description == searchValues$description_search) %>% | |
pull(core_enrichment) | |
data <- data %>% | |
filter(new_column %in% selected_genes) | |
} | |
data | |
}) | |
# Render volcano plot based on filtered results | |
output$volcanoPlot <- renderPlotly({ | |
data_res <- filteredRes() | |
p_value <- input$pvalue #need to add slides here | |
log2fc <- input$log2fc #need to add slider here | |
p <- ggplot(data_res, aes(x = log2FoldChange, y = pvalue_log10, | |
text = paste("Gene:", new_column, "<br>Log2 Fold Change:", log2FoldChange, | |
"<br>P-value:", pvalue, "<br>Significance:", significance, | |
"<br>Differentially Expressed:", diffexpressed, "<br>-log10 Values:", pvalue_log10))) + | |
geom_point(aes(color = log2FoldChange, shape = diffexpressed)) + | |
geom_hline(yintercept = -log10(p_value), linetype = "dotted", color = "red") + | |
geom_vline(xintercept = c(-log2fc, log2fc), linetype = "dotted", color = "darkblue") + | |
xlim(-5, 5) + | |
xlab("Log2 Fold Change") + | |
ylab("-log10(P-value)") + | |
ggtitle("Volcano Plot") + | |
scale_color_gradient2(low = "green", mid = "pink", high = "blue", midpoint = 0, | |
name = "Log2 Fold Change") # Add a custom color scale for the color legends | |
ggplotly(p, tooltip = "text") | |
}) | |
}) | |
# Update search criteria based on user actions | |
observeEvent(input$search_gene, { | |
searchValues$gene_search <- input$gene_search | |
searchValues$GO_search <- "All" | |
searchValues$description_search <- "" | |
}) | |
observeEvent(input$search_GO_term, { | |
searchValues$GO_search <- input$GO_search | |
searchValues$gene_search <- "" | |
searchValues$description_search <- "" | |
}) | |
observeEvent(input$search_description, { | |
searchValues$description_search <- input$description_search | |
searchValues$GO_search <- "All" | |
searchValues$gene_search <- "" | |
}) | |
observeEvent(input$visualize_gse, { | |
library(ggplot2) | |
library(ggtext) | |
library(gridExtra) | |
output$dotPlotTitle <- renderPlot({ | |
txt <- "Dot Plot with 10 Pathways" | |
title_plot <- ggplot() + | |
geom_textbox( | |
aes(x = 0, y = 0, label = txt), | |
size = 18 / .pt, | |
width = unit(6, "inches") | |
) + | |
theme_void() | |
print(title_plot) | |
}) | |
output$dotPlot <- renderPlot({ | |
dot_plot <- dotplot(gse, showCategory = 10) | |
print(dot_plot) | |
}) | |
output$conceptNetworkTitle <- renderPlot({ | |
txt <- "Gene Concept Network" | |
title_plot <- ggplot() + | |
geom_textbox( | |
aes(x = 0, y = 0, label = txt), | |
size = 18 / .pt, | |
width = unit(6, "inches") | |
) + | |
theme_void() | |
print(title_plot) | |
}) | |
output$conceptNetwork <- renderPlot({ | |
gsex <- setReadable(gse, 'org.Hs.eg.db', 'ENTREZID') | |
geneList <- gse@geneList | |
p1 <- cnetplot(gsex, foldChange = geneList, max.overlaps = 100) | |
p2 <- cnetplot(gsex, categorySize = "pvalue", foldChange = geneList, max.overlaps = 100) | |
p3 <- cnetplot(gsex, foldChange = geneList, circular = TRUE, colorEdge = TRUE, max.overlaps = 100) | |
maingene_plot <- cowplot::plot_grid(p1, p2, p3, ncol = 3, labels = LETTERS[1:3], rel_widths = c(.8, .8, 1.2)) | |
print(maingene_plot) | |
}) | |
output$heatMapTitle <- renderPlot({ | |
txt <- "Heatmap-Like Functional Classification" | |
title_plot <- ggplot() + | |
geom_textbox( | |
aes(x = 0, y = 0, label = txt), | |
size = 18 / .pt, | |
width = unit(6, "inches") | |
) + | |
theme_void() | |
print(title_plot) | |
}) | |
output$heatMap <- renderPlot({ | |
gsex <- setReadable(gse, 'org.Hs.eg.db', 'ENTREZID') | |
geneList <- gse@geneList | |
p1 <- heatplot(gsex, showCategory=5) | |
p2 <- heatplot(gsex, foldChange=geneList, showCategory=5) | |
mainheatmap_plot <- cowplot::plot_grid(p1, p2, ncol=1, labels=LETTERS[1:2]) | |
print(mainheatmap_plot) | |
}) | |
output$upsetPlotTitle <- renderPlot({ | |
txt <- "UpSet Plot" | |
title_plot <- ggplot() + | |
geom_textbox( | |
aes(x = 0, y = 0, label = txt), | |
size = 18 / .pt, | |
width = unit(6, "inches") | |
) + | |
theme_void() | |
print(title_plot) | |
}) | |
output$upsetPlot <- renderPlot({ | |
gse_df <- gse@result | |
top_terms <- gse_df %>% arrange(pvalue) %>% head(10) | |
top_gene_sets <- strsplit(top_terms$core_enrichment, "/") | |
gene_sets_list <- lapply(top_gene_sets, function(x) unique(trimws(x))) | |
gene_sets_df <- fromList(setNames(gene_sets_list, top_terms$ID)) | |
# Create the UpSet plot | |
upset_plot <- upset(gene_sets_df, | |
sets = names(gene_sets_df), | |
main.bar.color = "steelblue", | |
sets.bar.color = "darkred", | |
order.by = "freq", | |
matrix.color = "gray", | |
keep.order = TRUE) | |
print(upset_plot) | |
}) | |
output$pubmedPathwayPlotTitle <- renderPlot({ | |
txt <- "PubMed Pathway Enrichment" | |
title_plot <- ggplot() + | |
geom_textbox( | |
aes(x = 0, y = 0, label = txt), | |
size = 18 / .pt, | |
width = unit(6, "inches") | |
) + | |
theme_void() | |
print(title_plot) | |
}) | |
output$pubmedPathwayPlot <- renderPlot({ | |
results <- data.frame(Term = character(), Year = integer(), Count = integer(), stringsAsFactors = FALSE) | |
terms <- tail(gse$Description, n = 10) | |
results <- data.frame() | |
titles_2024 <- data.frame() | |
for (term in terms) { | |
for (year in 2014:2024) { | |
query <- paste(term, "[Title/Abstract] AND", year, "[PDAT]") | |
# Count results for each term and year | |
search_results <- entrez_search(db = "pubmed", term = query, retmax = 0) | |
results <- rbind(results, data.frame(Term = term, Year = year, Count = search_results$count)) | |
# If the year is 2024, retrieve the first 10 article titles | |
if (year == 2024) { | |
search_results_2024 <- entrez_search(db = "pubmed", term = query, retmax = 10) | |
if (search_results_2024$count > 0) { | |
article_ids <- search_results_2024$ids | |
articles <- entrez_fetch(db = "pubmed", id = article_ids, rettype = "abstract", retmode = "text") | |
titles <- sapply(strsplit(articles, "\n"), function(x) x[1]) | |
titles_2024 <- reactive({rbind(titles_2024, data.frame(Term = term, Title = titles, stringsAsFactors = FALSE))}) | |
} | |
} | |
} | |
} | |
total_counts <- results %>% | |
group_by(Year) %>% | |
summarize(Total_Count = sum(Count), .groups = 'drop') | |
results <- results %>% | |
left_join(total_counts, by = "Year") | |
results <- results %>% | |
mutate(Ratio = Count / Total_Count) | |
print(results) | |
mainpubmed_plot <- ggplot(results, aes(x = Year, y = Ratio, color = Term)) + | |
geom_line() + | |
geom_point(size = 3, shape = 20, fill = "white", stroke = 1) + # Bolded dots | |
scale_x_continuous(limits = c(2013, 2025), breaks = seq(2013, 2025, by = 2.5)) + # 2.5-year breaks | |
labs(title = "Publication Ratio for Enriched Terms", x = "Year", y = "Publication Ratio") + | |
theme_minimal() | |
print(mainpubmed_plot) | |
}) | |
}) | |
} else { | |
showModal(modalDialog( | |
title = "Access Denied", | |
"Incorrect password. Please try again.", | |
easyClose = TRUE, | |
footer = NULL | |
)) | |
} | |
}) | |
} | |
shinyApp(ui = ui, server = server) | |
``` |