From 8c96f1a3172ee2c585a192acb41d4d8ce701c241 Mon Sep 17 00:00:00 2001 From: Tanushree Tunstall Date: Mon, 12 Dec 2022 08:34:03 +0000 Subject: [PATCH] shiny-server version --- app.R | 14 ++-- server.R | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ ui.R | 66 +++++++++++++++ 3 files changed, 313 insertions(+), 5 deletions(-) create mode 100644 server.R create mode 100644 ui.R diff --git a/app.R b/app.R index 487c360..93d9167 100644 --- a/app.R +++ b/app.R @@ -34,8 +34,8 @@ options(DT.options = list(scrollX = TRUE)) # Gitea access token access_token = read_lines("~/secret-token") -gene_url = "https://git.tunstall.in/api/v1/repos/tanu/fellowship_dcdf/raw/tb_data_fc/dashboard/list_unique_missense_genes.csv" -missense_gene_url = "https://git.tunstall.in/api/v1/repos/tanu/fellowship_dcdf/raw/tb_data_fc/dashboard/missense_genes_params.csv" +gene_url = "https://git.tunstall.in/api/v1/repos/tanu/fellowship_dcdf/raw/tb_data_fc/data_dashboard/list_unique_missense_genes.csv" +missense_gene_url = "https://git.tunstall.in/api/v1/repos/tanu/fellowship_dcdf/raw/tb_data_fc/data_dashboard/missense_genes_params.csv" alphafold_url = "https://alphafold.ebi.ac.uk/files/" genes=read_csv(paste0(gene_url,"?token=",access_token)) @@ -229,7 +229,10 @@ server <- function(input, output) { #"PROVEAN: ", as.character(unique_missense_genes[input$table_rows_selected,"provean_score"]), "
", "PROVEAN Outcome: ", as.character(unique_missense_genes[input$table_rows_selected,"provean_outcome"]), "
", "RSA: ", as.character(unique_missense_genes[input$table_rows_selected,"rsa"]), "
", - "Residue Depth: ", as.character(unique_missense_genes[input$table_rows_selected,"rd_values"]), "
" + "Residue Depth: ", as.character(unique_missense_genes[input$table_rows_selected,"rd_values"]), "
", + "Total Samples: ", as.character(unique_missense_genes[input$table_rows_selected,"total_sample_count"]), "
", + "Distinct Lineages: ", as.character(unique_missense_genes[input$table_rows_selected,"distinct_lineage_count"]), "
" + ) ) @@ -286,7 +289,7 @@ server <- function(input, output) { opacity = 0.2 ) ) %>% - addSelection(type="spacefill", + addSelection(type="ball+stick", #spacefill param = list(name = "all_mutations", color="orange", sele = mutations @@ -304,7 +307,7 @@ server <- function(input, output) { opacity = 0.2 ) ) %>% - addSelection(type="spacefill", + addSelection(type="ball+stick", #spacefill param = list(name = "all_mutations", color="orange", sele = mutations @@ -318,3 +321,4 @@ server <- function(input, output) { # Run the application shinyApp(ui = ui, server = server) + diff --git a/server.R b/server.R new file mode 100644 index 0000000..1a4a43a --- /dev/null +++ b/server.R @@ -0,0 +1,238 @@ +library(shiny) +library(shinyjs) +library(shinydashboard) +#library("wesanderson") # ayyyy lmao hipster af +library(dplyr) +library(DT) +library(ggplot2) +library(grid) # for the info box +library(plotly) +library(shinycssloaders) +library(NGLVieweR) +library(httr) +library(readr) +library(RCurl) + +shinyServer(function(input, output) { + + output$distPlot <- renderPlot({ + # generate bins based on input$bins from ui.R + x <- faithful[, 2] + bins <- seq(min(x), max(x), length.out = input$bins + 1) + + # draw the histogram with the specified number of bins + hist(x, breaks = bins, col = 'darkgray', border = 'white', + xlab = 'Waiting time to next eruption (in mins)', + main = 'Histogram of waiting times') + }) + ### NGLViewer #### + # Structure Viewer WebGL/NGLViewR window + output$structure <- renderNGLVieweR({ + selected_gene=input$gene + ngl_gene=as.character(genes[genes$Gene==selected_gene,"PDB"]) + NGLVieweR(ngl_gene) %>% + addRepresentation("cartoon", + param = list(name = "cartoon", + color="tan", + #colorScheme = "bfactor", + opacity = 1 + ) + ) %>% + stageParameters(backgroundColor = "white") %>% + setQuality("high") %>% + setFocus(0) %>% + setSpin(FALSE) + }) + output$af_structure <- renderNGLVieweR({ + selected_af_gene=input$gene + ngl_af_gene=as.character(genes[genes$Gene==selected_af_gene,"AF_PDB"]) + + #af_pdb=cat(content(GET(paste0(alphafold_url,"AF-",ngl_af_gene,"-F1-model_v4.pdb")), as="text"), "\n") + af_pdb=content(GET(paste0(alphafold_url,"AF-",ngl_af_gene,"-F1-model_v4.pdb")), as="text") + #print(af_pdb) + #ngl_pdb_file=paste0(load_dir, "Data/", ngl_drug, '/output/depth/', ngl_gene, '_complex.pdb') + NGLVieweR(af_pdb, format="pdb") %>% + addRepresentation("cartoon", + param = list(name = "cartoon", + #color="tan" + colorScheme = "bfactor", + opacity = 1 + ) + ) %>% + stageParameters(backgroundColor = "white") %>% + setQuality("high") %>% + setFocus(0) %>% + setSpin(FALSE) + }) + + # output$table <- DT::renderDataTable({ + # selected_gene=input$gene + # gene=as.character(genes[genes$Gene==selected_gene,"Gene"]) + # #unique_missense_genes[unique_missense_genes$gene_name==gene,] + # unique_missense_genes + # }, + # selection = "single", + # search = list(search="alr")) + output$table <- DT::renderDataTable( + unique_missense_genes, + selection = "single", + options=list( + search = list(search=as.character(genes[genes$Gene==input$gene,"Gene"])) + ) + ) + + observeEvent(input$table_rows_selected,{ + #req(length(input$table_row_selected) > 0) + mutation = as.character(unique_missense_genes[input$table_rows_selected,"hgvd_p"]) + chain = as.character(unique_missense_genes[input$table_rows_selected,"chain"]) + # what the absolute FUCK is this mess? I JUST WANT THE MATCH ASDLASJASDASHFKLJASDFK + # coming down from the trees was a mistake, and abandoning Perl doubly so. + clicked_position = regmatches(mutation, regexpr("[0-9]+", mutation, perl=TRUE)) + + # Now update the 3D structure to highlight the clicked thing and then zoom in. + + NGLVieweR_proxy("structure") %>% + #addSelection('ball+stick' + addSelection('spacefill' + , param = list( + name = "Pos" + , sele = trimws(paste0(clicked_position,':', chain)) + , color = "red" + #, colorValue="00ff00" + #, colorScheme="element" + ) + ) + NGLVieweR_proxy("af_structure") %>% + #addSelection('ball+stick' + addSelection('spacefill' + , param = list( + name = "Pos" + , sele = clicked_position + , color = "red" + #, colorValue="00ff00" + #, colorScheme="element" + ) + ) + + NGLVieweR_proxy("af_structure") %>% updateZoomMove( + center = clicked_position, + zoom = clicked_position, + duration = 1000, # animation time in ms + z_offSet = -1 + ) + NGLVieweR_proxy("structure") %>% updateZoomMove( + center = trimws(paste0(clicked_position,':', chain)), + zoom = trimws(paste0(clicked_position,':', chain)), + duration = 1000, # animation time in ms + z_offSet = -1 + ) + output$information <- renderUI({ + selected_gene=input$gene + HTML(paste0("Mutation: ", as.character(unique_missense_genes[input$table_rows_selected,"mutationinformation"]),"
", + "PDB ID: ", as.character(genes[genes$Gene==selected_gene,"PDB"]),"
", + "AlphaFold ID: ", as.character(genes[genes$Gene==selected_gene,"AF_PDB"]), "
", + "Ligand Distance: ", as.character(unique_missense_genes[input$table_rows_selected,"ligand_distance"]), "
", + "mCSM Lig: ", as.character(unique_missense_genes[input$table_rows_selected,"mcsm_lig"]), "
", + "mmCSM Lig: ", as.character(unique_missense_genes[input$table_rows_selected,"mmcsm_lig"]), "
", + "mCSM DUET: ", as.character(unique_missense_genes[input$table_rows_selected,"ddg_duet"]), "
", + "FoldX: ", as.character(unique_missense_genes[input$table_rows_selected,"ddg_foldx"]), "
", + "DeepDDG: ", as.character(unique_missense_genes[input$table_rows_selected,"ddg_deepddg"]), "
", + "Dynamut2: ", as.character(unique_missense_genes[input$table_rows_selected,"ddg_dynamut2"]), "
", + "mCSM PPI2: ", as.character(unique_missense_genes[input$table_rows_selected,"mcsm_ppi2_affinity"]), "
", + "Interface Distance: ", as.character(unique_missense_genes[input$table_rows_selected,"interface_dist"]), "
", + "mCSM NA: ", as.character(unique_missense_genes[input$table_rows_selected,"mcsm_na_affinity"]), "
", + "Consurf: ", as.character(unique_missense_genes[input$table_rows_selected,"consurf_score"]), "
", + #"SNAP2: ", as.character(unique_missense_genes[input$table_rows_selected,"snap2_score"]), "
", + "SNAP2 Outcome: ", as.character(unique_missense_genes[input$table_rows_selected,"snap2_outcome"]), "
", + #"PROVEAN: ", as.character(unique_missense_genes[input$table_rows_selected,"provean_score"]), "
", + "PROVEAN Outcome: ", as.character(unique_missense_genes[input$table_rows_selected,"provean_outcome"]), "
", + "RSA: ", as.character(unique_missense_genes[input$table_rows_selected,"rsa"]), "
", + "Residue Depth: ", as.character(unique_missense_genes[input$table_rows_selected,"rd_values"]), "
", + "Total Samples: ", as.character(unique_missense_genes[input$table_rows_selected,"total_sample_count"]), "
", + "Distinct Lineages: ", as.character(unique_missense_genes[input$table_rows_selected,"distinct_lineage_count"]), "
" + + ) + ) + + }) + + # output$debug <- renderPrint({ + # print(c(mutation, clicked_position)) + # }) + }) + observeEvent( + { + input$clear_ngl + }, { + NGLVieweR_proxy("structure") %>% + removeSelection("Pos") %>% + removeSelection("all_mutations_surface") %>% + updateVisibility("cartoon", TRUE) %>% + removeSelection("all_mutations") + NGLVieweR_proxy("af_structure") %>% + removeSelection("Pos") %>% + removeSelection("all_mutations_surface") %>% + updateVisibility("cartoon", TRUE) %>% + removeSelection("all_mutations") + }) + # add a surface representation and highlight all mutations on it + observeEvent( + { + input$all_mutations + }, { + gene = input$gene + mutations = paste0(":", + as.matrix(unique_missense_genes[unique_missense_genes$gene_name == gene,c("chain")])[1], + " and (", + paste0( + apply( + unique_missense_genes[unique_missense_genes$gene_name == gene,c("position","chain")], + 1, + function(x){ + paste0(trimws(x[1]) + )} + ), + collapse=", " + ), ")" + ) + #print(mutations) + + + NGLVieweR_proxy("structure") %>% + updateVisibility("cartoon", FALSE) %>% + addSelection(type="cartoon", + param = list(name = "all_mutations_surface", + sele = "all", + color="tan", + opacity = 0.2 + ) + ) %>% + addSelection(type="ball+stick", #spacefill + param = list(name = "all_mutations", + color="orange", + sele = mutations + #colorScheme = "bfactor", + #opacity = 1 + ) + ) + NGLVieweR_proxy("af_structure") %>% + updateVisibility("cartoon", FALSE) %>% + addSelection(type="cartoon", + param = list(name = "all_mutations_surface", + sele = "all", + #color="tan", + colorScheme = "bfactor", + opacity = 0.2 + ) + ) %>% + addSelection(type="ball+stick", #spacefill + param = list(name = "all_mutations", + color="orange", + sele = mutations + #colorScheme = "bfactor", + #opacity = 1 + ) + ) + }) +} +) diff --git a/ui.R b/ui.R new file mode 100644 index 0000000..5c50730 --- /dev/null +++ b/ui.R @@ -0,0 +1,66 @@ +library(shiny) +library(shinyjs) +library(shinydashboard) +#library("wesanderson") # ayyyy lmao hipster af +library(dplyr) +library(DT) +library(ggplot2) +library(grid) # for the info box +library(plotly) +library(shinycssloaders) +library(NGLVieweR) +library(httr) +library(readr) +library(RCurl) + +dashboardPage(skin="purple", + dashboardHeader(title="Tuberculosis Host"), + dashboardSidebar( + radioButtons("gene", + label="Gene", + choices = genes$Gene, + selected="alr" # "alr" is a value + ), + actionButton("clear_ngl", + "Reset Structures"), + actionButton("all_mutations", + "All Mutations") + ), + dashboardBody( + useShinyjs(), + fluidRow( + box( + title="Crystallised Structure", + width=5, + column( + NGLVieweROutput("structure"), + width=12 + ) + ), + box( + title="AlphaFold Structure", + width=5, + column( + NGLVieweROutput("af_structure"), + width=12 + ) + ), + box( + title="Mutation Information", + width=2, + column( + htmlOutput("information"), + width=12 + ) + ) + ), + fluidRow( + column( + DT::dataTableOutput('table'), + width=12 + ) + ), + verbatimTextOutput("debug") + ) +) +