softwareDevelopment/BSA-SNPindex
0
1library(shiny)2library(QTLseqr)3library(data.table)4library(dplyr)5library(tidyr)6library(vcfR)7library(ggplot2)8options(shiny.maxRequestSize = 50*1024^3)9options(timeout = 3600) 10 11# QTL-seq Analysis Function12qtlseq <- function(input_csv = NULL,13 output_table = "/tmp/output_file.table",14 delta_snp_plot = NULL,15 qtlseq_csv = "/tmp/BSA_QTLseq.csv",16 refAlleleFreq = 0.20,17 minTotalDepth = 100,18 maxTotalDepth = 400,19 minSampleDepth = 40,20 minGQ = 99,21 windowSize = NULL,22 popStruc = NULL,23 bulkSize = NULL,24 replications = 10000,25 intervals = c(95, 99),26 alpha = 0.01) {27 28 data <- read.csv(input_csv)29 write.table(data, file = output_table, sep = "\t", row.names = FALSE, quote = FALSE)30 31 col_data <- colnames(data[5:ncol(data)])32 unique_samples <- unique(sub("\\..*", "", col_data))33 34 HighBulk <- unique_samples[1]35 LowBulk <- unique_samples[2]36 chroms <- as.vector(unique(data[1]))37 df <- importFromGATK(file = output_table, highBulk = HighBulk, lowBulk = LowBulk)38 39 df_filt <- filterSNPs(40 SNPset = df,41 refAlleleFreq = refAlleleFreq,42 minTotalDepth = minTotalDepth,43 maxTotalDepth = maxTotalDepth,44 minSampleDepth = minSampleDepth,45 minGQ = minGQ46 )47 48 df_filt <- runGprimeAnalysis(49 SNPset = df_filt,50 windowSize = windowSize,51 outlierFilter = "deltaSNP"52 )53 54 df_filt1 <- runQTLseqAnalysis(55 SNPset = df_filt,56 windowSize = windowSize,57 popStruc = popStruc,58 bulkSize = bulkSize,59 replications = replications,60 intervals = intervals61 )62 63 p <- ggplot(df_filt1, aes(x = POS)) +64 geom_point(aes(y = deltaSNP), color = "#3b82f6", size = 0.5) +65 geom_line(aes(y = tricubeDeltaSNP), color = "#ef4444", size = 0.8) +66 geom_line(aes(y = CI_95), color = "#f97316", linetype = "solid", size = 0.6) +67 geom_line(aes(y = -CI_95), color = "#f97316", linetype = "solid", size = 0.6) +68 geom_line(aes(y = CI_99), color = "#10b981", linetype = "solid", size = 0.6) +69 geom_line(aes(y = -CI_99), color = "#10b981", linetype = "solid", size = 0.6) +70 geom_hline(yintercept = c(-1, 0, 1), linetype = "dashed", color = "#0ea5e9") +71 facet_wrap(~CHROM, ncol = 4, scales = "free_x") +72 labs(x = "Position (Mb)", y = expression(Delta *"SNP-index")) +73 theme_minimal(base_size = 12) +74 theme(75 strip.text = element_text(face = "bold"),76 axis.title = element_text(face = "bold")77 )78 79 ggsave("/tmp/deltaSNPIndex.png", plot = p, dpi = 600, width = 12, height = 10, units = "in")80 81 getQTLTable(SNPset = df_filt1, alpha = alpha, export = TRUE, fileName = qtlseq_csv)82 83 return(list(QTLseqResults = df_filt1, GprimeResults = df_filt, plot = p))84}85 86# UI87ui <- fluidPage(88 tags$head(89 tags$style(HTML("90 @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap');91 92 body {93 font-family: 'Poppins', sans-serif;94 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);95 min-height: 100vh;96 padding: 20px;97 }98 99 .main-container {100 background: white;101 border-radius: 20px;102 box-shadow: 0 20px 60px rgba(0,0,0,0.3);103 padding: 0;104 overflow: hidden;105 max-width: 1400px;106 margin: 0 auto;107 }108 109 .header {110 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);111 color: white;112 padding: 30px 40px;113 text-align: center;114 }115 116 .header h1 {117 margin: 0;118 font-size: 2.5em;119 font-weight: 700;120 text-shadow: 2px 2px 4px rgba(0,0,0,0.2);121 }122 123 .header p {124 margin: 10px 0 0 0;125 font-size: 1.1em;126 opacity: 0.95;127 }128 129 .content-wrapper {130 padding: 40px;131 }132 133 .section-title {134 color: #667eea;135 font-size: 1.5em;136 font-weight: 600;137 margin-bottom: 20px;138 padding-bottom: 10px;139 border-bottom: 3px solid #667eea;140 }141 142 .card {143 background: #f8f9fa;144 border-radius: 15px;145 padding: 25px;146 margin-bottom: 30px;147 box-shadow: 0 4px 6px rgba(0,0,0,0.1);148 transition: transform 0.3s ease;149 }150 151 .card:hover {152 transform: translateY(-5px);153 box-shadow: 0 8px 12px rgba(0,0,0,0.15);154 }155 156 .upload-area {157 border: 3px dashed #667eea;158 border-radius: 15px;159 padding: 30px;160 text-align: center;161 background: linear-gradient(135deg, #f0f4ff 0%, #e9d5ff 100%);162 transition: all 0.3s ease;163 }164 165 .upload-area:hover {166 border-color: #764ba2;167 background: linear-gradient(135deg, #e9d5ff 0%, #f0f4ff 100%);168 }169 170 .btn-primary {171 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);172 border: none;173 color: white;174 padding: 12px 30px;175 font-size: 1.1em;176 font-weight: 600;177 border-radius: 25px;178 cursor: pointer;179 transition: all 0.3s ease;180 box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);181 }182 183 .btn-primary:hover {184 transform: translateY(-2px);185 box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);186 }187 188 .shiny-input-container {189 margin-bottom: 20px;190 }191 192 .shiny-input-container label {193 color: #4a5568;194 font-weight: 600;195 margin-bottom: 8px;196 display: block;197 }198 199 input[type='number'], input[type='text'], select {200 width: 100%;201 padding: 12px;202 border: 2px solid #e2e8f0;203 border-radius: 10px;204 font-size: 1em;205 transition: all 0.3s ease;206 font-family: 'Poppins', sans-serif;207 }208 209 input[type='number']:focus, input[type='text']:focus, select:focus {210 outline: none;211 border-color: #667eea;212 box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);213 }214 215 .param-grid {216 display: grid;217 grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));218 gap: 20px;219 }220 221 .progress-section {222 background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);223 border-radius: 15px;224 padding: 20px;225 margin: 20px 0;226 text-align: center;227 }228 229 .results-section {230 background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);231 border-radius: 15px;232 padding: 25px;233 margin-top: 20px;234 }235 236 .plot-container {237 background: white;238 border-radius: 10px;239 padding: 20px;240 box-shadow: 0 4px 6px rgba(0,0,0,0.1);241 margin-top: 20px;242 }243 244 .download-btn {245 background: linear-gradient(135deg, #10b981 0%, #059669 100%);246 border: none;247 color: white;248 padding: 10px 25px;249 font-weight: 600;250 border-radius: 20px;251 cursor: pointer;252 margin: 5px;253 transition: all 0.3s ease;254 }255 256 .download-btn:hover {257 transform: translateY(-2px);258 box-shadow: 0 4px 12px rgba(16, 185, 129, 0.4);259 }260 261 .info-box {262 background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%);263 border-left: 4px solid #3b82f6;264 padding: 15px;265 border-radius: 10px;266 margin: 15px 0;267 }268 269 .shiny-notification {270 position: fixed;271 top: 20px;272 right: 20px;273 border-radius: 10px;274 font-family: 'Poppins', sans-serif;275 }276 "))277 ),278 279 div(class = "main-container",280 div(class = "header",281 h1("๐งฌ QTL-seq Analysis Platform"),282 p("Quantitative Trait Loci Sequencing Analysis Tool")283 ),284 285 div(class = "content-wrapper",286 # File Upload Section287 div(class = "card",288 h3(class = "section-title", "๐ Data Input"),289 div(class = "upload-area",290 fileInput("csvFile", 291 label = NULL,292 accept = c(".csv"),293 buttonLabel = "Browse...",294 placeholder = "Select CSV file"),295 p(style = "color: #667eea; font-weight: 600; margin-top: 10px;",296 "Upload your QTL-seq data in CSV format")297 )298 ),299 300 # Parameters Section301 div(class = "card",302 h3(class = "section-title", "โ๏ธ Analysis Parameters"),303 div(class = "info-box",304 p(style = "margin: 0; color: #1e40af;", 305 "๐ Configure analysis parameters below. Default values are pre-filled.")306 ),307 308 div(class = "param-grid",309 numericInput("refAlleleFreq", "Reference Allele Frequency", 0.20, min = 0, max = 1, step = 0.01),310 numericInput("minTotalDepth", "Min Total Depth", 100, min = 0),311 numericInput("maxTotalDepth", "Max Total Depth", 400, min = 0),312 numericInput("minSampleDepth", "Min Sample Depth", 40, min = 0),313 numericInput("minGQ", "Min Genotype Quality", 99, min = 0, max = 100),314 numericInput("windowSize", "Window Size", 500000, min = 0)315 ),316 317 div(class = "param-grid", style = "margin-top: 20px;",318 selectInput("popStruc", "Population Structure", 319 choices = c("F2" = "F2", "RIL" = "RIL", "BC" = "BC")),320 textInput("bulkSize", "Bulk Sizes (comma-separated)", "20,20"),321 numericInput("replications", "Replications", 10000, min = 1000),322 numericInput("alpha", "Alpha Level", 0.01, min = 0, max = 1, step = 0.01)323 )324 ),325 326 # Run Analysis Button327 div(style = "text-align: center; margin: 30px 0;",328 actionButton("runAnalysis", "๐ Run QTL-seq Analysis", 329 class = "btn-primary",330 style = "font-size: 1.2em; padding: 15px 40px;")331 ),332 333 # Progress Section334 conditionalPanel(335 condition = "input.runAnalysis > 0",336 div(class = "progress-section",337 h4(style = "color: #92400e; margin-top: 0;", "โณ Analysis in Progress..."),338 uiOutput("progressText")339 )340 ),341 342 # Results Section343 conditionalPanel(344 condition = "output.plotReady",345 div(class = "results-section",346 h3(class = "section-title", style = "color: #059669;", "โ
Analysis Complete!"),347 348 div(class = "plot-container",349 h4(style = "color: #4a5568; margin-top: 0;", "Delta SNP-index Plot"),350 plotOutput("deltaPlot", height = "800px")351 ),352 353 div(style = "text-align: center; margin-top: 20px;",354 downloadButton("downloadPlot", "๐ Download Plot", class = "download-btn"),355 downloadButton("downloadQTL", "๐ Download QTL Table", class = "download-btn"),356 downloadButton("downloadResults", "๐พ Download All Results", class = "download-btn")357 ),358 359 div(style = "margin-top: 30px;",360 h4(style = "color: #4a5568;", "๐ QTL Summary Statistics"),361 tableOutput("qtlSummary")362 )363 )364 )365 )366 )367)368 369# Server370server <- function(input, output, session) {371 results <- reactiveValues(data = NULL, plot = NULL)372 373 observeEvent(input$runAnalysis, {374 req(input$csvFile)375 376 withProgress(message = 'Running QTL-seq Analysis', value = 0, {377 tryCatch({378 incProgress(0.2, detail = "Loading data...")379 380 bulkSizes <- as.numeric(strsplit(input$bulkSize, ",")[[1]])381 382 incProgress(0.3, detail = "Filtering SNPs...")383 384 result <- qtlseq(385 input_csv = input$csvFile$datapath,386 refAlleleFreq = input$refAlleleFreq,387 minTotalDepth = input$minTotalDepth,388 maxTotalDepth = input$maxTotalDepth,389 minSampleDepth = input$minSampleDepth,390 minGQ = input$minGQ,391 windowSize = input$windowSize,392 popStruc = input$popStruc,393 bulkSize = bulkSizes,394 replications = input$replications,395 alpha = input$alpha396 )397 398 incProgress(0.8, detail = "Generating plots...")399 400 results$data <- result401 results$plot <- result$plot402 403 incProgress(1, detail = "Complete!")404 405 showNotification("Analysis completed successfully!", type = "message", duration = 5)406 407 }, error = function(e) {408 showNotification(paste("Error:", e$message), type = "error", duration = 10)409 })410 })411 })412 413 output$plotReady <- reactive({414 return(!is.null(results$plot))415 })416 outputOptions(output, "plotReady", suspendWhenHidden = FALSE)417 418 output$deltaPlot <- renderPlot({419 req(results$plot)420 results$plot421 })422 423 output$qtlSummary <- renderTable({424 req(results$data)425 qtl_table <- read.csv("/tmp/BSA_QTLseq.csv")426 head(qtl_table, 10)427 })428 429 output$progressText <- renderUI({430 p(style = "color: #92400e; font-weight: 600;", 431 "Please wait while the analysis is running. This may take several minutes...")432 })433 434 output$downloadPlot <- downloadHandler(435 filename = function() {436 paste("deltaSNPIndex_", Sys.Date(), ".png", sep = "")437 },438 content = function(file) {439 file.copy("/tmp/deltaSNPIndex.png", file)440 }441 )442 443 output$downloadQTL <- downloadHandler(444 filename = function() {445 paste("BSA_QTLseq_", Sys.Date(), ".csv", sep = "")446 },447 content = function(file) {448 file.copy("/tmp/BSA_QTLseq.csv", file)449 }450 )451 452 output$downloadResults <- downloadHandler(453 filename = function() {454 paste("QTLseq_results_", Sys.Date(), ".zip", sep = "")455 },456 content = function(file) {457 files <- c("/tmp/deltaSNPIndex.png", "/tmp/BSA_QTLseq.csv", "/tmp/output_file.table")458 zip(file, files[file.exists(files)])459 }460 )461}462 463# Run the application464shinyApp(ui = ui, server = server)