Commit 7f7ba4a5 authored by svolant's avatar svolant
Browse files

modif masque integration

parent 8e65da7d
options(download.file.method = 'wget')
if (!require("backports")){
install.packages("backports")
library(backports)
if (!require("sendmailR")){
install.packages("sendmailR")
library(sendmailR)
}
if (!require("shinyBS")){
install.packages("shinyBS")
library(shinyBS)
}
library(tools)
if (!require("flexdashboard")){
install.packages("flexdashboard")
library(flexdashboard)
}
if (!require("backports")){
install.packages("backports")
library(backports)
}
if (!require("readr")){
install.packages("readr")
library(readr)
......
......@@ -236,16 +236,32 @@ CheckMasque <- function(input,values)
Error = NULL
HowTo = NULL
## Check password
if(is.null(Error) && input$password == ""){
Error = "<h6><strong>Empty key field </strong></h6>"
HowTo = "<h6><strong>Make sure that you have click the &laquo Get key &raquo button and that you have pasted the key sent by mail </strong></h6>"
}
if(is.null(Error) && input$password != ""){
pass = toupper(gsub(" ","",input$password))
if(!identical(pass,toupper(values$pass))){
Error = "<h6><strong>Invalid key </strong></h6>";
HowTo = "<h6><strong>Make sure that you have click the &laquo Get key &raquo button and that you have pasted the key sent by mail</strong></h6>"
}
}
## At least one fastq is detected
if(is.null(Error) && input$LoadFiles>0 && length(values$fastq_names_only)==0){
Error = "The selected directory must contain at least one file in the following format : fastq, fastq.gz, or fq."
HowTo = "Change the working directory and check the format of the files"
Error = "<h6><strong>The selected directory must contain at least one file in the following format : fastq, fastq.gz, or fq.</strong></h6>"
HowTo = "<h6><strong>Change the working directory and check the format of the files</strong></h6>"
}
if(is.null(Error) && input$PairedOrNot=='y' && input$MatchFiles_button>0){
if(length(values$R2fastQ) !=length(values$R2fastQ)){
Error = "The number of fastq files for R1 and R2 must be the same"
HowTo = "Add/Remove some files or change the suffix to identify the pairs"
Error = "<h6><strong>The number of fastq files for R1 and R2 must be the same</strong></h6>"
HowTo = "<h6><strong>Add/Remove some files or change the suffix to identify the pairs</strong></h6>"
}
if(length(values$R2fastQ)>0 && length(values$R2fastQ)>0){
......@@ -254,27 +270,30 @@ CheckMasque <- function(input,values)
dup_files = c(values$R1fastQ[duplicated(tmpR1)],values$R2fastQ[duplicated(tmpR2)])
if(length(dup_files)>0){
Error = paste("These fastq files corresponds to the same sample names:" ,dup_files)
HowTo = "Change the suffix to identify the pairs"
Error = paste("<h6><strong>These fastq files corresponds to the same sample names:</strong></h6>" ,dup_files)
HowTo = "<h6><strong>Change the suffix to identify the pairs</strong></h6>"
}
if(!isValidPrimer(input$R1primer)){ Error = "The primer (forward) must only contain letters from A to Z" }
if(!isValidPrimer(input$R2primer)){ Error = "The primer (reverse) must only contain letters from A to Z" }
if(!isValidPrimer(input$R1primer)){ Error = "<h6><strong>The primer (forward) must only contain letters from A to Z</strong></h6>" }
if(!isValidPrimer(input$R2primer)){ Error = "<h6><strong>The primer (reverse) must only contain letters from A to Z</strong></h6>" }
}
}
if(is.null(Error) && !isValidEmail(input$to)) Error = "The email address is not valid"
if(is.null(Error) && !isValidEmail(input$to)) Error = "<h6><strong>The email address is not valid</strong></h6>"
if(is.null(Error) && !isValidPrimer(input$primerSingle)){ Error = "The primer must only contain letters from A to Z" }
if(is.null(Error) && !isValidPrimer(input$primerSingle)){ Error = "<h6><strong>The primer must only contain letters from A to Z</strong></h6>" }
if(is.null(Error)) {
res = SamplesMasque(input,values)
if(length(res$samples)==0) {
Error = "0 sample detected"
if(input$PairedOrNot=='y') HowTo = "Change the working directory and/or verify the pairs matching"
if(input$PairedOrNot=='n') HowTo = "Change the working directory and load fastq files"
Error = "<h6><strong>0 sample detected</strong></h6>"
if(input$PairedOrNot=='y') HowTo = '<h6><strong>Make sur that you click the &laquo Load &raquo button. <br /> Change the working directory and/or verify the pairs matching.</strong></h6>'
if(input$PairedOrNot=='n') HowTo = '<h6><strong>Make sur that you click the &laquo Load &raquo button. <br /> Change the working directory.</strong></h6>'
}
}
......@@ -316,9 +335,8 @@ SamplesMasque <- function(input,values)
CreateJSON <- function(input){
curdir <- getwd()
tmpjson = tempfile(pattern = "file", tmpdir = paste(curdir,"www","masque","todo",sep= .Platform$file.sep), fileext = ".json")
CreateJSON <- function(input,values){
if(input$PairedOrNot=='n')
{
......@@ -327,11 +345,11 @@ CreateJSON <- function(input){
"path"=path_fastq,
"host"=input$HostName,
"type"=input$DataTypeMasque,
"mail"=input$to,
"mail"=values$login_email,
"contaminant"= "/home/aghozlan/workspace/shaman_bioblend/alienTrimmerPF8contaminants.fasta"
)
df %>% jsonlite::toJSON() %>% write_lines(tmpjson)
df %>% jsonlite::toJSON() %>% write_lines(values$json_name)
}
if(input$PairedOrNot=='y')
{
......@@ -343,10 +361,10 @@ CreateJSON <- function(input){
"path_R2"=path_fastq_R2,
"host"=input$HostName,
"type"=input$DataTypeMasque,
"mail"=input$to,
"mail"=values$login_email,
"contaminant"= "/home/aghozlan/workspace/shaman_bioblend/alienTrimmerPF8contaminants.fasta"
)
df %>% jsonlite::toJSON() %>% write_lines(tmpjson)
df %>% jsonlite::toJSON() %>% write_lines(values$json_name)
}
}
......
......@@ -50,3 +50,12 @@ text-align: center;
color: #FFFFFF;
}
"
gaugeCSS <- "
.html-widget.gauge svg {
height: 100%;
margin-top: -10px;
margin-bottom: -40px;
}
"
......@@ -21,11 +21,16 @@ shinyServer(function(input, output,session) {
curdir = getwd()
json_name = tempfile(pattern = "file", tmpdir = paste(curdir,"www","masque","todo",sep= .Platform$file.sep), fileext = ".json")
## Pass for MASQUE
pass = gsub("file","",basename(file_path_sans_ext(json_name)))
## Popup messages
observe(if(input$AddRegScatter) info("By adding the regression line, you will lose interactivity."))
## Reactive target
values <- reactiveValues(TargetWorking = target,labeled=NULL,fastq_names_only=NULL,R1fastQ=NULL,R2fastQ=NULL,json_name=json_name)
values <- reactiveValues(TargetWorking = target,labeled=NULL,fastq_names_only=NULL,R1fastQ=NULL,R2fastQ=NULL,
json_name=json_name,num=0,pass=pass,login_email = NULL,is.valid =NULL,
biom_masque = NULL,tree_masque=NULL)
## Counts file
dataInputCounts <-reactive({
......@@ -93,13 +98,19 @@ shinyServer(function(input, output,session) {
data = NULL
inFile <- input$fileBiom
if (is.null(inFile)) return(NULL)
if (!is.null(inFile) && is.null(values$biom_masque)) {
try(read_biom(inFile$datapath)->data,silent=T)
}
if (!is.null(values$biom_masque) && file.exists(values$biom_masque)) try(read_biom(values$biom_masque)->data,silent=T)
return(data)
})
observeEvent(input$fileBiom,{
values$biom_masque=NULL;
})
## Unifrac File (tree)
dataInputTree <-reactive({
......@@ -107,12 +118,27 @@ shinyServer(function(input, output,session) {
data = NULL
inFile <- input$fileTree
if (is.null(inFile)) return(NULL)
if (!is.null(inFile) && is.null(values$tree_masque)) {
try(read.tree(inFile$datapath)->data, silent=T)
CheckTree = CheckTreeFile(data)
data = CheckTree$tree
try(readLines(inFile$datapath)->treeseq, silent=T)
return(list(data=data, Error=CheckTree$Error, Warning=CheckTree$Warning, treeseq=treeseq))
}
if (!is.null(values$tree_masque) && file.exists(values$tree_masque)) {
try(read.tree(values$tree_masque)->data, silent=T)
CheckTree = CheckTreeFile(data)
data = CheckTree$tree
try(readLines(values$tree_masque)->treeseq, silent=T)
return(list(data=data, Error=CheckTree$Error, Warning=CheckTree$Warning, treeseq=treeseq))
}
})
observeEvent(input$fileTree,{
values$tree_masque=NULL;
})
......@@ -672,6 +698,7 @@ shinyServer(function(input, output,session) {
observeEvent(input$submit,{
CMP = CheckMasque(input, values)
Error = CMP$Error
values$num = 0
if(is.null(Error))
{
......@@ -712,10 +739,12 @@ shinyServer(function(input, output,session) {
}
## Create JSON file
withProgress(message = 'Creating JSON file...',{CreateJSON(input,values$json_name)})
withProgress(message = 'Creating JSON file...',{CreateJSON(input,values)})
if(file.exists(values$json_name)) values$num = 1
info("Your data have been submitted. You will receive an e-mail once the computation over.\nThis can take few hours")
}
})
},priority = 1)
......@@ -862,7 +891,7 @@ shinyServer(function(input, output,session) {
if(!is.null(CMP$Error) && input$submit>0) {
box(title = "Error", status = "danger",width = 12,
h6(strong(CMP$Error))
HTML(CMP$Error)
)
} else return(NULL)
......@@ -875,18 +904,183 @@ shinyServer(function(input, output,session) {
if(!is.null(CMP$HowTo) && input$submit>0) {
box(title = "How To", status = "success",width = 12,
h6(strong(CMP$HowTo))
HTML(CMP$HowTo)
)
} else return(NULL)
})
## plot gauge
output$gaugeMasque <-renderGauge({
input$submit
res = NULL;
num = as.numeric(values$num)
CMP = isolate(CheckMasque(input, values))
Error = CMP$Error
if(is.null(Error) || num!=0) res = gauge(min(num,100), 0,100,symbol = '%',label= "Progress...")
return(res)
})
## Timer for the gauge
Timer <- reactiveTimer(5000)
## Check masque progress
observe({
Timer()
# values$num = isolate(values$num)*5
progress_file = paste(curdir,"www","masque","doing",paste(basename(file_path_sans_ext(json_name)),".txt",sep=""),sep= .Platform$file.sep)
if(file.exists(progress_file))
{
pf = read_lines(progress_file)
pf = as.numeric(pf)
if(!is.na(pf)){
pf = min(pf,100); pf = max(pf,0)
if(isolate(values$num)<pf) {values$num = pf}
}
}
})
observe({
toggleState("checkMail",condition = isValidEmail(input$to))
})
output$pass_Arg <- renderUI({
pass = toupper(gsub(" ","",input$password))
passOK = identical(pass,toupper(values$pass))
if(!is.null(input$password) && input$password!="" && !passOK){
removeCssClass(class = 'pwdGREEN', selector = '#password')
addCssClass(class = 'pwdRED', selector = '#password')
}
if(!is.null(input$password) && input$password!="" && passOK){
removeCssClass(class = 'pwdRED', selector = '#password')
addCssClass(class = 'pwdGREEN', selector = '#password')
}
if(is.null(input$password) || input$password==""){
removeCssClass(class = 'pwdRED', selector = '#password')
removeCssClass(class = 'pwdGREEN', selector = '#password')
}
})
textMASQUE <- reactive({
values$json_name
num = 0
gauge(num, 0,100,symbol = '%')
samp = SamplesMasque(input,values)
home <- normalizePath("~")
path_glob = file.path(home, paste(unlist(dir()$path[-1]), collapse = .Platform$file.sep))
text = paste("<b>Type of data:</b>",input$DataTypeMasque,"<br /> <br /> ",
"<b>Paired-end sequencing:</b>",input$PairedOrNot)
text = paste(text,"<br /> <br /> ","<b>Number of samples:</b>",length(samp$samples))
text = paste(text,"<br /> <br /> ","<b>Removed samples:</b>",length(samp$samples_removed))
text = paste(text,"<br /> <br /> ","<b>Working directory:</b>",path_glob)
if(isValidEmail(input$to)) text = paste(text,"<br /> <br /> ","<b>Email:</b>",input$to)
if(input$HostName!="") text = paste(text,"<br /> <br /> ","<b>Host:</b>",input$HostName)
if(input$primer && input$PairedOrNot=="n") {text = paste(text,"<br /> <br /> ","<b>Primer:</b>",input$primerSingle)}
if(input$primer && input$PairedOrNot=="y") {text = paste(text,"<br /> <br /> ","<b>Primer forward:</b>",input$R1primer,
"<br /> <br /> ","<b>Primer reverse:</b>",input$R2primer)}
return(text)
})
output$summary_box_masque <- renderUI({
text = textMASQUE()
res = div(style = "word-wrap: break-word;",box(
title = strong("Summary of your analysis"), width = 12, background = "light-blue",
HTML(text),
div(style = "text-align:right;",
downloadButton("printMasque_summary", "Save"),
tags$style(type='text/css', "#printMasque_summary {margin-top: 15px;}")
)
)
)
return(res)
})
## Export MASQUE summary in .txt
output$printMasque_summary <- downloadHandler(
filename = function() { 'Summary.txt' },
content = function(file){
txt = textMASQUE()
txt = gsub("<br />",replacement = "\n",txt)
txt = gsub("</b>",replacement = "",txt)
txt = gsub("<b>",replacement = "",txt)
write(paste("Summary of your analysis \n \n ",txt), file)
}
)
## Send mail with the password
observeEvent(input$checkMail,{
observe( info(paste("You will received a password by email at :",isolate(input$to), '\nThis can take few seconds.')))
to <- isolate(input$to)
subject <- "SHAMAN Analysis"
body <- paste("Hello, \n You are using SHAMAN to run a quantitative metagenomic analysis. Hereafter is the key you need in SHAMAN :
\n",values$pass," \n \n Best regards, \n SHAMAN team")
mailControl=list(smtpServer="smtp.pasteur.fr")
from="<shaman@pasteur.fr>"
## Send mail
sendmail(from=from,to=to,subject=subject,msg=body,control=mailControl)
## Store the email
values$login_email = to
})
## Create button once MASQUE computation is over
output$MasqueToShaman_button <- renderUI({
input$submit
res = NULL
CMP = isolate(CheckMasque(input, values))
Error = CMP$Error
if(is.null(Error) && values$num<1){
res = box(id="load-masque-res",title="Upload the results",width = 12, status = "success",
selectInput("masque_database","Select the database",choices=c("Silva" = "silva","Greengenes" = "greengenes")),
tags$style(type='text/css', "#masque-database { width:100%; margin-top: 5px;}"),
actionButton("RunResMasque",label = "Upload the results",icon=icon('upload')),
tags$style(type='text/css', "#RunResMasque { width:100%; margin-top: 15px;}")
)
}
return(res)
})
observe({
if(values$num<100) disable("RunResMasque")
if(values$num<100) disable("masque_database")
if(values$num<100){ addPopover(session,"load-masque-res",
title= "Waiting for the results",
content = paste("Once the computation is over, you will received a password by email at:",values$login_email)
)
} else removePopover(session, "load-masque-res")
})
observeEvent(input$RunResMasque,{
updateSelectInput(session, "FileFormat","",selected = "fileBiom")
reset("fileBiom"); reset("fileTree")
values$biom_masque = paste(curdir,"www","masque","done",basename(file_path_sans_ext(json_name)),paste("shaman_",input$masque_database,".biom",sep=""),sep= .Platform$file.sep)
values$tree_masque = paste(curdir,"www","masque","done",basename(file_path_sans_ext(json_name)),paste("shaman_tree_",input$masque_database,".nhx",sep=""),sep= .Platform$file.sep)
})
......@@ -895,6 +1089,11 @@ shinyServer(function(input, output,session) {
######################## END MASQUE #################################
observeEvent(input$deleteRows,{
if (!is.null(input$DataTarget_rows_selected)) {
......@@ -1670,7 +1869,7 @@ shinyServer(function(input, output,session) {
tmpBIOM = dataInputBiom()
if(!is.null(inFile) && is.null(tmpBIOM)) {
box(title = "Error", status = "danger",width = 3,
box(title = "Error", status = "danger",width = 12,
h5(strong("This file can not be loaded.")),br(),
em("The loaded file is not in the biom format or its format is not currently supported by SHAMAN software")
)
......@@ -1687,7 +1886,7 @@ shinyServer(function(input, output,session) {
Counts = dataInputCounts()
if(!is.null(inFile) && is.null(Counts)) {
box(title = "Error", status = "danger",width = 3,
box(title = "Error", status = "danger",width = 12,
h5(strong("This file can not be loaded.")),br(),
em("The count table file is not in the correct format for SHAMAN software")
)
......@@ -1704,7 +1903,7 @@ shinyServer(function(input, output,session) {
Taxo = dataInputTaxo()
if(!is.null(inFile) && !input$NoTaxoFile && is.null(Taxo)) {
box(title = "Error", status = "danger",width = 3,
box(title = "Error", status = "danger",width = 12,
h5(strong("This file can not be loaded.")),br(),
em("The taxonomy table file is not in the correct format for SHAMAN software")
)
......
......@@ -222,67 +222,91 @@ body <- dashboardBody(
),
tabItem(tabName = "RawData",
tags$style(type='text/css', ".well { max-width: 20em; }"),
fluidRow(
# fluidRow(
HTML('<center><h1>MASQUE : Metagenomic Analysis with a Quantitative pipeline</h1></center>'),
column(width=8,
div(style="background-color: white; padding-left:20px;",
HTML('
<h2>Introduction</h2>
<p>The aim of this part is to provide an easy cluster interface to perform <b>targeted metagenomic analysis</b>. This analysis will be done using the MASQUE pipeline which allows :</p>
<ul>
<li>to analyse 16S/18S/23S/28S/ITS data. It builds a count matrix, an annotation table and a phylogeny of the OTU.</li>
<li>to perform to use a set of parameters already tested on serveral projects for the numerous software used to perform the clustering and the annotation.</li>
<li>to perform an "uptodate" analysis considering the scientific litterature.</li>
</ul>
<hr></hr>
<h2>Process</h2>
<p>We follow the recommandation described by Robert C. Edgar in <a href="http://www.nature.com/nmeth/journal/v10/n10/full/nmeth.2604.html" target="_blank" >Uparse</a> supplementary paper.<br>
The clustering process in MASQUE is performed as the following :<br>
1. Read quality control<br>
2. Dereplication<br>
3. Chimera filtering<br>
4. Clustering<br>
5. Realignment/mapping<br>
6. Taxonomical annotation of the OTU<br>
7. Quality check of every step </p>
<p>You can find more information in the presentation <a href="/aghozlane/masque/blob/master/tp/Targeted_metagenomics.pdf">here</a>. We try to describe the idea behind each step and a complete TP to do it on your own.</p>'
)
hr(),
# column(width=8,
# div(style="background-color: white; padding-left:20px;",
# HTML('
# <h2>Introduction</h2>
#
# <p>The aim of this part is to provide an easy cluster interface to perform <b>targeted metagenomic analysis</b>. This analysis will be done using the MASQUE pipeline which allows :</p>
#
# <\ui> to analyse 16S/18S/23S/28S/ITS data. It builds a count matrix, an annotation table and a phylogeny of the OTU.
# to perform to use a set of parameters already tested on serveral projects for the numerous software used to perform the clustering and the annotation.
# to perform an uptodate analysis considering the scientific litterature."
)),
column(width=4,
gaugeOutput("gaugeMasque", width = "100%", height = "100%")
)
# <ul>
# <li>to analyse 16S/18S/23S/28S/ITS data. It builds a count matrix, an annotation table and a phylogeny of the OTU.</li>
# <li>to perform to use a set of parameters already tested on serveral projects for the numerous software used to perform the clustering and the annotation.</li>
# <li>to perform an "uptodate" analysis considering the scientific litterature.</li>
# </ul>
#
# <hr></hr>
# <h2>Process</h2>
#
# <p>We follow the recommandation described by Robert C. Edgar in <a href="http://www.nature.com/nmeth/journal/v10/n10/full/nmeth.2604.html" target="_blank" >Uparse</a> supplementary paper.<br>
# The clustering process in MASQUE is performed as the following :<br>
# 1. Read quality control<br>
# 2. Dereplication<br>
# 3. Chimera filtering<br>
# 4. Clustering<br>
# 5. Realignment/mapping<br>
# 6. Taxonomical annotation of the OTU<br>
# 7. Quality check of every step </p>
#
# <p>You can find more information in the presentation <a href="/aghozlane/masque/blob/master/tp/Targeted_metagenomics.pdf">here</a>. We try to describe the idea behind each step and a complete TP to do it on your own.</p>'
# )
# #
# #
# # <\ui> to analyse 16S/18S/23S/28S/ITS data. It builds a count matrix, an annotation table and a phylogeny of the OTU.
# # to perform to use a set of parameters already tested on serveral projects for the numerous software used to perform the clustering and the annotation.
# # to perform an uptodate analysis considering the scientific litterature."
# )),
# column(width=4)
# # column(width=4,
# # inlineCSS(gaugeCSS),
# # gaugeOutput("gaugeMasque", width = "100%", height = "100%")
# # )
# ),
# hr(),
# HTML('<center><h2 style="color:#053383;"><b>Start your analysis</b></h2></center>'),
# hr(),
fluidRow(
column(width=3,
box(title = "Enter the key",width=12,status="danger",
inlineCSS(list(.pwdGREEN = "background-color: #DDF0B3",.pwdRED = "background-color: #F0B2AD")),
uiOutput("pass_Arg"),
textInput("password","",value = NULL),
bsTooltip("password", 'Fill in the email field and click the "Get key" button',"bottom",trigger = "hover", options = list(container = "body")),
tags$style(type='text/css', "#password { width:100%; margin-top: 10px;}")
),
uiOutput("summary_box_masque")
),
hr(),
HTML('<center><h2 style="color:#053383;"><b>Start your analysis</b></h2></center>'),
hr(),
fluidRow(
column(width=2),
column(width=8,
# column(width=3,
# inlineCSS(gaugeCSS),
# gaugeOutput("gaugeMasque", width = "100%", height = "100%")
#
# ),
column(width=6,