diff --git a/server.R b/server.R
index b60be192a2760f932269f90ad42fa80e243f3be9..a53d65fb4c942f5019d44fda1799acb2d772e958 100644
--- a/server.R
+++ b/server.R
@@ -1,876 +1,879 @@
-library(shinydashboard)
-
-shinyServer
-(function(input, output, session)
-{
-  checkNull <- function(x) {
-    if (!exists(as.character(substitute(x)))) {
-      return(NULL)
-    } else if (is.null(x)) {
-      return(NULL)
-    } else if (length(x) > 1) {
-      return(x)
-    }
-    else if (x %in% c(0, "", NA, "NULL")) {
-      return(NULL)
-    } else {
-      return(x)
-    }
-  }
-  
-  beautifulTable <- function(data)  {
-    DT::datatable(
-      data = data,
-      rownames = FALSE,
-      filter = "top",
-      extensions = c("Buttons", "ColReorder", "FixedColumns"),
-      options = list(
-        dom = "lBtip",
-        pageLength = 10,
-        lengthMenu = list(c(10, 25, 50, 100, -1), list('10', '25', '50', '100', 'All')),
-        buttons = list(
-          'colvis',
-          list(
-            extend = 'collection',
-            buttons = c('copy', 'csv', 'excel', 'pdf'),
-            text = 'Download'
-          )
-        ),
-        colReorder = TRUE,
-        scrollX = TRUE,
-        fixedColumns = list(leftColumns = 1, rightColumns = 0)
-      ),
-      width = "auto",
-      height = "auto"
-    )
-  }
-  
-  source({
-    "https://raw.githubusercontent.com/mahendra-mariadassou/phyloseq-extended/master/R/load-extra-functions.R"
-  })
-  
-  data16S <- reactive({
-    if (input$dataset == "input")
-    {
-      if (is.null(input$fileBiom))
-      {
-        return()
-      }
-      if (input$biomFormat == "std")
-      {
-        d <- import_biom(
-          BIOMfilename = input$fileBiom$datapath,
-          treefilename = input$fileTree$datapath# ,
-          # refseqfilename = input$fileSeq$datapath
-        )
-      } else if (input$biomFormat == "frogs") {
-        d <- import_frogs(
-          biom = input$fileBiom$datapath,
-          treefilename = input$fileTree$datapath# ,
-          # refseqfilename = input$fileSeq$datapath
-        )
-      }
-      
-      colnames(tax_table(d)) <-
-        c("Kingdom",
-          "Phylum",
-          "Class",
-          "Order",
-          "Family",
-          "Genus",
-          "Species",
-          "Strain")[1:length(rank_names(d))]
-      tax_table(d)[grep("unknown ", tax_table(d))] <- NA
-      #tax_table(d)[grep("Unclassified", tax_table(d))] <- NA
-      if (!is.null(input$fileMeta)) {
-        if (input$CSVsep == "excel") {
-          sample_data(d) <-
-            RcmdrMisc::readXL(input$fileMeta$datapath,
-                              rownames = TRUE,
-                              header = TRUE)
-        } else {
-          sample_data(d) <- read.csv(
-            input$fileMeta$datapath,
-            header = TRUE,
-            sep = input$CSVsep,
-            row.names = 1,
-            na.strings = NA
-          )
-          sample_data(d)$SampleID <- rownames(sample_data(d))
-        }
-      } else {
-        n <- data.frame(sample_names(d) , row.names = sample_names(d))
-        names(n) <- "SampleID"
-        sample_data(d) <- n
-      }
-      if (input$rareData) {
-        d <- rarefy_even_depth(
-          d,
-          replace = FALSE,
-          rngseed = as.integer(Sys.time()),
-          verbose = FALSE
-        )
-      }
-      return(d)
-    } else if (input$dataset == "rdata")
-    {
-      if (is.null(input$fileRData))
-      {
-        return()
-      }
-      load(input$fileRData$datapath)
-      if (exists("data"))
-      {
-        return(data)
-      } else {
-        return()
-      }
-    } else {
-      load("demo/demo.RData")
-      return(get(input$dataset))
-    }
-  })
-  
-  data <- reactiveValues()
-  {
-    observe({
-      if (!is.null(data16S()))
-        isolate(data <<- data16S())
-    })
-  }
-  
-  output$downloadData <- {
-    downloadHandler(
-      filename = function() {
-        paste("Easy16S-data", Sys.Date(), "RData", sep = ".")
-      },
-      content = function(file) {
-        save(data, file = file)
-      }
-    )
-  }
-  
-  output$downloadUI <- renderUI({
-    validate(need(data16S(), ""))
-    tags$div(
-      style = "text-align:center",
-      title = "Download as RData",
-      downloadButton("downloadData", "Download", style = "color: black; background-color: gray90")
-    )
-  })
-  
-  output$rarefactionMin <- renderText({
-    validate(need(input$fileBiom, ""),
-             need(input$dataset == "input", ""))
-    paste("(min sample =", format(min(sample_sums(data16S(
-      
-    ))), big.mark = " "), "reads)")
-  })
-  
-  output$phyloseqPrint <- renderPrint({
-    validate(
-      need(
-        data16S(),
-        "Firstly, you should select a demo dataset or upload an abundance BIOM file.\nFor example, with Galaxy, a BIOM file can be obtained at the end of FROGS workflow with the 'FROGS BIOM to std BIOM' tool"
-      )
-    )
-    data16S()
-  })
-  
-  output$summaryTable <- renderUI({
-    validate(need(data16S(), ""))
-    box(
-      title = "Tables",
-      width = NULL,
-      status = "primary",
-      tabsetPanel(
-        tabPanel("otu_table",
-                 beautifulTable(
-                   data.frame(OTU = taxa_names(data16S()), otu_table(data16S()))
-                 )),
-        tabPanel("tax_table",
-                 beautifulTable(
-                   data.frame(OTU = taxa_names(data16S()), tax_table(data16S()))
-                 )),
-        tabPanel("sample_data",
-                 #as.data.frame(sapply(sample_data(data16S()), class)),
-                 beautifulTable(
-                   data.frame(SAMPLE = sample_names(data16S()), sample_data(data16S()))
-                 ))
-      )
-    )
-  })
-  
-  output$histUI <- renderUI({
-    validate(need(data16S(), ""))
-    box(
-      title = "Setting : ",
-      width = NULL,
-      status = "primary",
-      radioButtons(
-        "barFill",
-        label = "Taxonomic rank : ",
-        choices = rank_names(data16S()),
-        inline = TRUE
-      ),
-      textInput("barTitle",
-                label = "Title : ",
-                value = "OTU abundance barplot"),
-      selectInput(
-        "barGrid",
-        label = "Subplot : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      )
-      ,
-      selectInput(
-        "barX",
-        label = "X : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      )
-    )
-  })
-  
-  output$histo <- renderPlot({
-    validate(need(data16S(),
-                  "Requires an abundance dataset"))
-    p <- plot_bar(
-      physeq = data16S(),
-      fill = input$barFill,
-      x = ifelse(is.null(checkNull(input$barX)), "Sample", input$barX),
-      title = checkNull(input$barTitle)
-    )
-    if (!is.null(checkNull(input$barGrid))) {
-      p <-
-        p + facet_grid(paste(".", "~", input$barGrid), scales = "free_x")
-    }
-    return(p)
-  })
-  
-  output$histFocusUIfocusRank <- renderUI({
-    validate(need(data16S(), ""))
-    radioButtons(
-      "focusRank",
-      label = "Taxonomic rank : ",
-      choices = rank_names(data16S())[-length(rank_names(data16S()))],
-      inline = TRUE
-    )
-  })
-  
-  output$histFocusUIfocusTaxa <- renderUI({
-    validate(need(data16S(), ""))
-    selectInput(
-      "focusTaxa",
-      label = "Selected taxa : ",
-      choices = unique(as.vector(tax_table(data16S(
-        
-      ))[, input$focusRank])),
-      selected = TRUE
-    )
-  })
-  
-  output$histFocusUIfocusNbTaxa <- renderUI({
-    validate(need(data16S(), ""))
-    sliderInput(
-      "focusNbTaxa",
-      label = "Number of sub-taxa : ",
-      min = 0,
-      #max = sum(tax_table(tax_glom(data16S(), rank_names(data16S())[1+as.integer(input$focusRank)]))[, as.integer(input$focusRank)]==input$focusTaxa)
-      max = 30,
-      value = 10
-    )
-  })
-  
-  output$histFocusUIfocusGrid <- renderUI({
-    validate(need(data16S(), ""))
-    selectInput("focusGrid",
-                label = "Subplot : ",
-                choices = c("..." = 0, sample_variables(data16S())))
-  })
-  
-  output$histFocusUIfocusX <- renderUI({
-    validate(need(data16S(), ""))
-    selectInput("focusX",
-                label = "X : ",
-                choices = c("..." = 0, sample_variables(data16S())))
-  })
-  
-  output$histoFocus <- renderPlot({
-    validate(need(data16S(),
-                  "Requires an abundance dataset"))
-    p <- plot_composition(
-      physeq = data16S(),
-      taxaRank1 = input$focusRank,
-      taxaSet1 = input$focusTaxa,
-      taxaRank2 = rank_names(data16S())[which(rank_names(data16S()) == input$focusRank) + 1],
-      numberOfTaxa = input$focusNbTaxa,
-      fill = rank_names(data16S())[which(rank_names(data16S()) == input$focusRank) + 1],
-      x = ifelse(is.null(checkNull(input$focusX)), "Sample", input$focusX)
-    )
-    if (!is.null(checkNull(input$focusGrid))) {
-      p <-
-        p + facet_grid(paste(".", "~", input$focusGrid), scales = "free_x")
-    }
-    return(p)
-  })
-  
-  output$clustUI <- renderUI({
-    validate(need(data16S(), ""))
-    box(
-      title = "Setting : " ,
-      width = NULL,
-      status = "primary",
-      selectInput(
-        "clustDist",
-        label = "Distance : ",
-        choices = list(
-          "bray",
-          "jaccard",
-          "unifrac",
-          "wunifrac",
-          "dpcoa",
-          "jsd",
-          "euclidean"
-        )
-      ),
-      selectInput(
-        "clustMethod",
-        label = "Method : ",
-        choices = list(
-          "ward.D2",
-          "ward.D",
-          "single",
-          "complete",
-          "average",
-          "mcquitty",
-          "median",
-          "centroid"
-        )
-      ),
-      selectInput(
-        "clustCol",
-        label = "Color : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      )
-    )
-  })
-  
-  output$clust <- renderPlot({
-    validate(need(data16S(),
-                  "Requires an abundance dataset"))
-    plot_clust(
-      physeq = data16S(),
-      dist = input$clustDist,
-      method = input$clustMethod,
-      color = checkNull(input$clustCol)
-    )
-  })
-  
-  output$richnessAUI <- renderUI({
-    validate(need(data16S(), ""))
-    box(
-      title = "Setting : " ,
-      width = NULL,
-      status = "primary",
-      checkboxGroupInput(
-        "richnessMeasures",
-        label = "Measures : ",
-        choices = c(
-          "Observed",
-          "Chao1",
-          "ACE",
-          "Shannon",
-          "Simpson",
-          "InvSimpson",
-          "Fisher"
-        ),
-        selected = c(
-          "Observed",
-          "Chao1",
-          "ACE",
-          "Shannon",
-          "Simpson",
-          "InvSimpson",
-          "Fisher"
-        ),
-        inline = TRUE
-      ),
-      radioButtons(
-        "richnessBoxplot",
-        label = "Representation : ",
-        choices = list(
-          "Dots only" = 1,
-          "Dots and boxplot" = 2,
-          "Boxplot only" = 3
-        ),
-        selected = 2,
-        inline = TRUE
-      ),
-      textInput("richnessTitle",
-                label = "Title : ",
-                value = "Alpha diversity graphics"),
-      selectInput(
-        "richnessX",
-        label = "X : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      ),
-      selectInput(
-        "richnessColor",
-        label = "Color : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      ),
-      selectInput(
-        "richnessShape",
-        label = "Shape : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      )
-    )
-  })
-  
-  output$richnessA <- renderPlot({
-    validate(need(data16S(),
-                  "Requires an abundance dataset"))
-    p <- plot_richness(
-      physeq = data16S(),
-      x = ifelse(is.null(checkNull(
-        input$richnessX
-      )), "samples", input$richnessX),
-      color = checkNull(input$richnessColor),
-      shape = checkNull(input$richnessShape),
-      title = checkNull(input$richnessTitle),
-      measures = checkNull(input$richnessMeasures)
-    )
-    if (input$richnessBoxplot >= 2) {
-      p <- p + geom_boxplot()
-    }
-    if (input$richnessBoxplot <= 2) {
-      p <- p + geom_point()
-    }
-    return(p)
-  })
-  
-  output$richnessATable <- renderUI({
-    validate(need(data16S(),
-                  "Requires an abundance dataset"))
-    p(beautifulTable(data.frame(
-      SAMPLE = sample_names(data16S()), round(estimate_richness(data16S()), digits = 2)
-    )))
-  })
-  
-  output$richnessBUI <- renderUI({
-    box(
-      title = "Setting : " ,
-      width = NULL,
-      status = "primary",
-      selectInput(
-        "richnessBOrder",
-        label = "Sorting sample : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      ),
-      textInput("richnessBTitle",
-                label = "Title : ",
-                value = "Beta diversity heatmap")
-    )
-  })
-  
-  output$richnessB <- renderPlot({
-    validate(need(data16S(),
-                  "Requires an abundance dataset"))
-    beta <-
-      melt(as(distance(data16S(), method = input$richnessBDist), "matrix"))
-    colnames(beta) <- c("x", "y", "distance")
-    if (!is.null(checkNull(input$richnessBOrder)))
-    {
-      new_factor = as.factor(get_variable(data16S(), input$richnessBOrder))
-      variable_sort <-
-        as.factor(get_variable(data16S(), input$richnessBOrder)[order(new_factor)])
-      L = levels(reorder(sample_names(data16S()), as.numeric(new_factor)))
-      beta$x <- factor(beta$x, levels = L)
-      beta$y <- factor(beta$y, levels = L)
-      palette <- hue_pal()(length(levels(new_factor)))
-      tipColor <-
-        col_factor(palette, levels = levels(new_factor))(variable_sort)
-    }
-    p <-
-      ggplot(beta, aes(x = x, y = y, fill = distance)) + geom_tile()
-    p <- p + ggtitle(input$richnessBTitle) + theme(
-      axis.text.x = element_text(
-        angle = 90,
-        hjust = 1,
-        color = checkNull(tipColor)
-      ),
-      axis.text.y = element_text(color = checkNull(tipColor)),
-      axis.title.x = element_blank(),
-      axis.title.y = element_blank()
-    )
-    return(p + scale_fill_gradient2())
-  })
-  
-  output$networkBUI <- renderUI({
-    validate(need(data16S(), ""))
-    box(
-      title = "Setting : " ,
-      width = NULL,
-      status = "primary",
-      sliderInput(
-        "netwMax",
-        label = "Threshold : ",
-        min = 0,
-        max = 1,
-        value = 0.7
-      ),
-      checkboxInput("netwOrphan",
-                    label = "Keep orphans",
-                    value = TRUE),
-      textInput("netwTitle",
-                label = "Title : ",
-                value = "Beta diversity network"),
-      selectInput(
-        "netwCol",
-        label = "Color : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      ),
-      selectInput(
-        "netwShape",
-        label = "Shape : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      ),
-      selectInput(
-        "netwLabel",
-        label = "Label : ",
-        choices = c(
-          "..." = 0,
-          "Sample name" = "value",
-          sample_variables(data16S())
-        )
-      )
-    )
-  })
-  
-  output$networkB <- renderPlot({
-    validate(need(data16S(),
-                  "Requires an abundance dataset"))
-    g <- make_network(
-      data16S(),
-      distance = input$richnessBDist,
-      max.dist = input$netwMax,
-      keep.isolates = input$netwOrphan
-    )
-    p <- plot_network(
-      g,
-      physeq = data16S(),
-      color = checkNull(input$netwCol),
-      shape = checkNull(input$netwShape),
-      label = checkNull(input$netwLabel),
-      hjust = 2,
-      title = checkNull(input$netwTitle)
-    )
-    return(p)
-  })
-  
-  output$richnessBTable <- renderUI({
-    validate(need(data16S(),
-                  "Requires an abundance dataset"))
-    p(beautifulTable(data.frame(
-      SAMPLE = sample_names(data16S()), round(as.matrix(
-        distance(data16S(), method = input$richnessBDist)
-      ), digits = 2)
-    )))
-  })
-  
-  output$rarefactionCurve <- renderPlot({
-    validate(need(data16S(),
-                  "Requires an abundance dataset"))
-    p <- ggrare(
-      physeq = data16S(),
-      step = 100,
-      #step = input$rarefactionStep,
-      color = checkNull(input$rarefactionColor),
-      label = checkNull(input$rarefactionLabel),
-      se = FALSE
-    )
-    if (!is.null(checkNull(input$rarefactionGrid))) {
-      p <- p + facet_grid(paste(".", "~", input$rarefactionGrid))
-    }
-    
-    if (input$rarefactionMin) {
-      p <-
-        p + geom_vline(xintercept = min(sample_sums(data16S())),
-                       color = "gray60")
-    }
-    return(p + ggtitle(input$rarefactionTitle))
-    
-  })
-  
-  output$rarefactionCurveUI <- renderUI({
-    validate(need(data16S(), ""))
-    box(
-      title = "Setting : " ,
-      width = NULL,
-      status = "primary",
-      # sliderInput(
-      #   "rarefactionStep",
-      #   label = "Etapes de calcul : ",
-      #   min = 1,
-      #   max = 1000,
-      #   value = 100
-      # ),
-      checkboxInput("rarefactionMin", label = "Show min sample threshold", value = FALSE),
-      textInput("rarefactionTitle",
-                label = "Title : ",
-                value = "Rarefaction curves"),
-      selectInput(
-        "rarefactionColor",
-        label = "Color : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      ),
-      selectInput(
-        "rarefactionLabel",
-        label = "Label : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      ),
-      selectInput(
-        "rarefactionGrid",
-        label = "Subplot : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      )
-    )
-  })
-  
-  output$HeatmapUI <- renderUI({
-    validate(need(data16S(), ""))
-    box(
-      title = "Setting : " ,
-      width = NULL,
-      status = "primary",
-      textInput("heatmapTitle",
-                label = "Title : ",
-                value = "Taxa heatmap by samples"),
-      selectInput(
-        "heatmapGrid",
-        label = "Subplot : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      ),
-      selectInput(
-        "heatmapX",
-        label = "X : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      ),
-      sliderInput(
-        "heatmapTopOtu",
-        label = "Show the n most abundant OTU : ",
-        min = 1,
-        max = ntaxa(data16S()),
-        value = 250
-      ),
-      selectInput(
-        "heatmapDist",
-        label = "Distance : ",
-        selected = "bray",
-        choices = list(
-          "bray",
-          "jaccard",
-          "unifrac",
-          "wunifrac",
-          "dpcoa",
-          "jsd",
-          "euclidean"
-        )
-      ),
-      selectInput(
-        "heatmapMethod",
-        label = "Method : ",
-        selected = "NMDS",
-        choices = list(
-          "NMDS",
-          "ward.D2",
-          "ward.D",
-          "single",
-          "complete",
-          "average",
-          "mcquitty",
-          "median",
-          "centroid"
-        )
-      )
-    )
-  })
-  
-  output$Heatmap <- renderPlot({
-    validate(need(data16S(),
-                  "Requires an abundance dataset"))
-    p <- plot_heatmap(
-      physeq = prune_taxa(names(sort(
-        taxa_sums(data16S()), decreasing = TRUE
-      )[1:input$heatmapTopOtu]), data16S()),
-      distance = input$heatmapDist,
-      method = input$heatmapMethod,
-      title = checkNull(input$heatmapTitle),
-      sample.order = checkNull(input$heatmapX),
-      low = "yellow",
-      high = "red",
-      na.value = "white"
-    )
-    if (!is.null(checkNull(input$heatmapGrid))) {
-      p <-
-        p + facet_grid(paste(".", "~", input$heatmapGrid), scales = "free_x")
-    }
-    return(p)
-  })
-  
-  output$treeUI <- renderUI({
-    validate(need(data16S(), ""))
-    box(
-      title = "Setting : " ,
-      width = NULL,
-      status = "primary",
-      radioButtons(
-        "treeRank",
-        label = "Taxonomic rank captioned : ",
-        choices = c(aucun = "",
-                    rank_names(data16S()),
-                    OTU = "taxa_names"),
-        inline = TRUE
-      ),
-      sliderInput(
-        "treeTopOtu",
-        label = "Show the n most abundant OTU : ",
-        min = 1,
-        max = ntaxa(data16S()),
-        value = 20
-      ),
-      checkboxInput("treeRadial", label = "Radial tree", value = FALSE),
-      checkboxInput("treeSample", label = "Show samples", value = TRUE),
-      textInput("treeTitle",
-                label = "Title : ",
-                value = "Phylogenetic tree"),
-      selectInput(
-        "treeCol",
-        label = "Color : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      ),
-      selectInput(
-        "treeShape",
-        label = "Shape : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      )
-    )
-  })
-  
-  output$tree <- renderPlot({
-    validate(
-      need(data16S(), "Requires an abundance dataset"),
-      need(
-        phy_tree(data16S(), errorIfNULL = FALSE),
-        "Requires a phylogenetic tree"
-      )
-    )
-    p <- plot_tree(
-      physeq = prune_taxa(names(sort(
-        taxa_sums(data16S()), decreasing = TRUE
-      )[1:input$treeTopOtu]), data16S()),
-      method = ifelse(input$treeSample, "sampledodge", "treeonly"),
-      color = checkNull(input$treeCol),
-      shape = checkNull(input$treeShape),
-      size = "abundance",
-      label.tips = checkNull(input$treeRank),
-      sizebase = 5,
-      ladderize = "left",
-      plot.margin = 0,
-      title = checkNull(input$treeTitle)
-    )
-    if (checkNull(input$treeRadial)) {
-      return(p + coord_polar(theta = "y"))
-    } else {
-      return(p)
-    }
-  })
-  
-  output$acpUI <- renderUI({
-    validate(need(data16S(), ""))
-    box(
-      title = "Setting : " ,
-      width = NULL,
-      status = "primary",
-      checkboxGroupInput(
-        "acpAxes",
-        label = "Axes : ",
-        choices = seq(10),
-        selected = c(1, 2),
-        inline = TRUE
-      ),
-      selectInput(
-        "acpDist",
-        label = "Distance : ",
-        selected = "bray",
-        choices = list(
-          "bray",
-          "jaccard",
-          "unifrac",
-          "wunifrac",
-          "dpcoa",
-          "jsd",
-          "euclidean"
-        )
-      ),
-      selectInput(
-        "acpMethod",
-        label = "Method : ",
-        selected = "MDS",
-        choices = list("DCA", "CCA", "RDA", "CAP", "DPCoA", "NMDS", "MDS", "PCoA")
-      ),
-      textInput("acpTitle",
-                label = "Title : ",
-                value = "Samples ordination graphic"),
-      selectInput(
-        "acpLabel",
-        label = "Label : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      ),
-      selectInput(
-        "acpCol",
-        label = "Color : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      ),
-      selectInput(
-        "acpShape",
-        label = "Shape : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      ),
-      selectInput(
-        "acpEllipse",
-        label = "Ellipses : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      ),
-      selectInput(
-        "acpRep",
-        label = "Barycenters : ",
-        choices = c("..." = 0, sample_variables(data16S()))
-      )
-    )
-  })
-  
-  output$acp <- renderPlot({
-    validate(
-      need(data16S(), "Requires an abundance dataset"),
-      need(length(input$acpAxes) == 2, "Requires two projections axes")
-    )
-    p <- plot_samples(
-      data16S(),
-      ordination = ordinate(
-        data16S(),
-        method = input$acpMethod,
-        distance = input$acpDist
-      ),
-      axes = as.numeric(input$acpAxes),
-      title = checkNull(input$acpTitle),
-      color = checkNull(input$acpCol),
-      replicate = checkNull(input$acpRep),
-      shape = checkNull(input$acpShape),
-      label = checkNull(input$acpLabel)
-    )
-    if (!is.null(checkNull(input$acpEllipse))) {
-      p <- p + stat_ellipse(aes_string(group = input$acpEllipse))
-    }
-    return(p + theme_bw())
-  })
+library(shinydashboard)
+
+shinyServer
+(function(input, output, session)
+{
+  checkNull <- function(x) {
+    if (!exists(as.character(substitute(x)))) {
+      return(NULL)
+    } else if (is.null(x)) {
+      return(NULL)
+    } else if (length(x) > 1) {
+      return(x)
+    }
+    else if (x %in% c(0, "", NA, "NULL")) {
+      return(NULL)
+    } else {
+      return(x)
+    }
+  }
+
+  beautifulTable <- function(data)  {
+    DT::datatable(
+      data = data,
+      rownames = FALSE,
+      filter = "top",
+      extensions = c("Buttons", "ColReorder", "FixedColumns"),
+      options = list(
+        dom = "lBtip",
+        pageLength = 10,
+        lengthMenu = list(c(10, 25, 50, 100, -1), list('10', '25', '50', '100', 'All')),
+        buttons = list(
+          'colvis',
+          list(
+            extend = 'collection',
+            buttons = c('copy', 'csv', 'excel', 'pdf'),
+            text = 'Download'
+          )
+        ),
+        colReorder = TRUE,
+        scrollX = TRUE,
+        fixedColumns = list(leftColumns = 1, rightColumns = 0)
+      ),
+      width = "auto",
+      height = "auto"
+    )
+  }
+
+  source({
+    "https://raw.githubusercontent.com/mahendra-mariadassou/phyloseq-extended/master/R/load-extra-functions.R"
+  })
+
+  data16S <- reactive({
+    if (input$dataset == "input")
+    {
+      if (is.null(input$fileBiom))
+      {
+        return()
+      }
+      if (input$biomFormat == "std")
+      {
+        d <- import_biom(
+          BIOMfilename = input$fileBiom$datapath,
+          treefilename = input$fileTree$datapath# ,
+          # refseqfilename = input$fileSeq$datapath
+        )
+      } else if (input$biomFormat == "frogs") {
+        d <- import_frogs(
+          biom = input$fileBiom$datapath,
+          treefilename = input$fileTree$datapath# ,
+          # refseqfilename = input$fileSeq$datapath
+        )
+      }
+
+      colnames(tax_table(d)) <-
+        c("Kingdom",
+          "Phylum",
+          "Class",
+          "Order",
+          "Family",
+          "Genus",
+          "Species",
+          "Strain")[1:length(rank_names(d))]
+      tax_table(d)[grep("unknown ", tax_table(d))] <- NA
+      #tax_table(d)[grep("Unclassified", tax_table(d))] <- NA
+      if (!is.null(input$fileMeta)) {
+        if (input$CSVsep == "excel") {
+          sample_data(d) <-
+            RcmdrMisc::readXL(input$fileMeta$datapath,
+                              rownames = TRUE,
+                              header = TRUE)
+        } else {
+          sample_data(d) <- read.csv(
+            input$fileMeta$datapath,
+            header = TRUE,
+            sep = input$CSVsep,
+            row.names = 1,
+            na.strings = NA
+          )
+          sample_data(d)$SampleID <- rownames(sample_data(d))
+        }
+      } else {
+        n <- data.frame(sample_names(d) , row.names = sample_names(d))
+        names(n) <- "SampleID"
+        sample_data(d) <- n
+      }
+      if (input$rareData) {
+        d <- rarefy_even_depth(
+          d,
+          replace = FALSE,
+          rngseed = as.integer(Sys.time()),
+          verbose = FALSE
+        )
+      }
+      return(d)
+    }
+
+    if (input$dataset == "rdata")
+    {
+      if (is.null(input$fileRData))
+      {
+        return()
+      }
+      load(input$fileRData$datapath)
+      if (exists("data"))
+      {
+        return(data)
+      } else {
+        return()
+      }
+    }
+
+    load("demo/demo.RData")
+    return(get(input$dataset))
+
+  })
+
+  data <- reactiveValues()
+  {
+    observe({
+      if (!is.null(data16S()))
+        isolate(data <<- data16S())
+    })
+  }
+
+  output$downloadData <- {
+    downloadHandler(
+      filename = function() {
+        paste("Easy16S-data", Sys.Date(), "RData", sep = ".")
+      },
+      content = function(file) {
+        save(data, file = file)
+      }
+    )
+  }
+
+  output$downloadUI <- renderUI({
+    validate(need(data16S(), ""))
+    tags$div(
+      style = "text-align:center",
+      title = "Download as RData",
+      downloadButton("downloadData", "Download", style = "color: black; background-color: gray90")
+    )
+  })
+
+  output$rarefactionMin <- renderText({
+    validate(need(input$fileBiom, ""),
+             need(input$dataset == "input", ""))
+    paste("(min sample =", format(min(sample_sums(data16S(
+
+    ))), big.mark = " "), "reads)")
+  })
+
+  output$phyloseqPrint <- renderPrint({
+    validate(
+      need(
+        data16S(),
+        "Firstly, you should select a demo dataset or upload an abundance BIOM file.\nFor example, with Galaxy, a BIOM file can be obtained at the end of FROGS workflow with the 'FROGS BIOM to std BIOM' tool"
+      )
+    )
+    data16S()
+  })
+
+  output$summaryTable <- renderUI({
+    validate(need(data16S(), ""))
+    box(
+      title = "Tables",
+      width = NULL,
+      status = "primary",
+      tabsetPanel(
+        tabPanel("otu_table",
+                 beautifulTable(
+                   data.frame(OTU = taxa_names(data16S()), otu_table(data16S()))
+                 )),
+        tabPanel("tax_table",
+                 beautifulTable(
+                   data.frame(OTU = taxa_names(data16S()), tax_table(data16S()))
+                 )),
+        tabPanel("sample_data",
+                 #as.data.frame(sapply(sample_data(data16S()), class)),
+                 beautifulTable(
+                   data.frame(SAMPLE = sample_names(data16S()), sample_data(data16S()))
+                 ))
+      )
+    )
+  })
+
+  output$histUI <- renderUI({
+    validate(need(data16S(), ""))
+    box(
+      title = "Setting : ",
+      width = NULL,
+      status = "primary",
+      radioButtons(
+        "barFill",
+        label = "Taxonomic rank : ",
+        choices = rank_names(data16S()),
+        inline = TRUE
+      ),
+      textInput("barTitle",
+                label = "Title : ",
+                value = "OTU abundance barplot"),
+      selectInput(
+        "barGrid",
+        label = "Subplot : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      )
+      ,
+      selectInput(
+        "barX",
+        label = "X : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      )
+    )
+  })
+
+  output$histo <- renderPlot({
+    validate(need(data16S(),
+                  "Requires an abundance dataset"))
+    p <- plot_bar(
+      physeq = data16S(),
+      fill = input$barFill,
+      x = ifelse(is.null(checkNull(input$barX)), "Sample", input$barX),
+      title = checkNull(input$barTitle)
+    )
+    if (!is.null(checkNull(input$barGrid))) {
+      p <-
+        p + facet_grid(paste(".", "~", input$barGrid), scales = "free_x")
+    }
+    return(p)
+  })
+
+  output$histFocusUIfocusRank <- renderUI({
+    validate(need(data16S(), ""))
+    radioButtons(
+      "focusRank",
+      label = "Taxonomic rank : ",
+      choices = rank_names(data16S())[-length(rank_names(data16S()))],
+      inline = TRUE
+    )
+  })
+
+  output$histFocusUIfocusTaxa <- renderUI({
+    validate(need(data16S(), ""))
+    selectInput(
+      "focusTaxa",
+      label = "Selected taxa : ",
+      choices = unique(as.vector(tax_table(data16S(
+
+      ))[, input$focusRank])),
+      selected = TRUE
+    )
+  })
+
+  output$histFocusUIfocusNbTaxa <- renderUI({
+    validate(need(data16S(), ""))
+    sliderInput(
+      "focusNbTaxa",
+      label = "Number of sub-taxa : ",
+      min = 0,
+      #max = sum(tax_table(tax_glom(data16S(), rank_names(data16S())[1+as.integer(input$focusRank)]))[, as.integer(input$focusRank)]==input$focusTaxa)
+      max = 30,
+      value = 10
+    )
+  })
+
+  output$histFocusUIfocusGrid <- renderUI({
+    validate(need(data16S(), ""))
+    selectInput("focusGrid",
+                label = "Subplot : ",
+                choices = c("..." = 0, sample_variables(data16S())))
+  })
+
+  output$histFocusUIfocusX <- renderUI({
+    validate(need(data16S(), ""))
+    selectInput("focusX",
+                label = "X : ",
+                choices = c("..." = 0, sample_variables(data16S())))
+  })
+
+  output$histoFocus <- renderPlot({
+    validate(need(data16S(),
+                  "Requires an abundance dataset"))
+    p <- plot_composition(
+      physeq = data16S(),
+      taxaRank1 = input$focusRank,
+      taxaSet1 = input$focusTaxa,
+      taxaRank2 = rank_names(data16S())[which(rank_names(data16S()) == input$focusRank) + 1],
+      numberOfTaxa = input$focusNbTaxa,
+      fill = rank_names(data16S())[which(rank_names(data16S()) == input$focusRank) + 1],
+      x = ifelse(is.null(checkNull(input$focusX)), "Sample", input$focusX)
+    )
+    if (!is.null(checkNull(input$focusGrid))) {
+      p <-
+        p + facet_grid(paste(".", "~", input$focusGrid), scales = "free_x")
+    }
+    return(p)
+  })
+
+  output$clustUI <- renderUI({
+    validate(need(data16S(), ""))
+    box(
+      title = "Setting : " ,
+      width = NULL,
+      status = "primary",
+      selectInput(
+        "clustDist",
+        label = "Distance : ",
+        choices = list(
+          "bray",
+          "jaccard",
+          "unifrac",
+          "wunifrac",
+          "dpcoa",
+          "jsd",
+          "euclidean"
+        )
+      ),
+      selectInput(
+        "clustMethod",
+        label = "Method : ",
+        choices = list(
+          "ward.D2",
+          "ward.D",
+          "single",
+          "complete",
+          "average",
+          "mcquitty",
+          "median",
+          "centroid"
+        )
+      ),
+      selectInput(
+        "clustCol",
+        label = "Color : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      )
+    )
+  })
+
+  output$clust <- renderPlot({
+    validate(need(data16S(),
+                  "Requires an abundance dataset"))
+    plot_clust(
+      physeq = data16S(),
+      dist = input$clustDist,
+      method = input$clustMethod,
+      color = checkNull(input$clustCol)
+    )
+  })
+
+  output$richnessAUI <- renderUI({
+    validate(need(data16S(), ""))
+    box(
+      title = "Setting : " ,
+      width = NULL,
+      status = "primary",
+      checkboxGroupInput(
+        "richnessMeasures",
+        label = "Measures : ",
+        choices = c(
+          "Observed",
+          "Chao1",
+          "ACE",
+          "Shannon",
+          "Simpson",
+          "InvSimpson",
+          "Fisher"
+        ),
+        selected = c(
+          "Observed",
+          "Chao1",
+          "ACE",
+          "Shannon",
+          "Simpson",
+          "InvSimpson",
+          "Fisher"
+        ),
+        inline = TRUE
+      ),
+      radioButtons(
+        "richnessBoxplot",
+        label = "Representation : ",
+        choices = list(
+          "Dots only" = 1,
+          "Dots and boxplot" = 2,
+          "Boxplot only" = 3
+        ),
+        selected = 2,
+        inline = TRUE
+      ),
+      textInput("richnessTitle",
+                label = "Title : ",
+                value = "Alpha diversity graphics"),
+      selectInput(
+        "richnessX",
+        label = "X : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      ),
+      selectInput(
+        "richnessColor",
+        label = "Color : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      ),
+      selectInput(
+        "richnessShape",
+        label = "Shape : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      )
+    )
+  })
+
+  output$richnessA <- renderPlot({
+    validate(need(data16S(),
+                  "Requires an abundance dataset"))
+    p <- plot_richness(
+      physeq = data16S(),
+      x = ifelse(is.null(checkNull(
+        input$richnessX
+      )), "samples", input$richnessX),
+      color = checkNull(input$richnessColor),
+      shape = checkNull(input$richnessShape),
+      title = checkNull(input$richnessTitle),
+      measures = checkNull(input$richnessMeasures)
+    )
+    if (input$richnessBoxplot >= 2) {
+      p <- p + geom_boxplot()
+    }
+    if (input$richnessBoxplot <= 2) {
+      p <- p + geom_point()
+    }
+    return(p)
+  })
+
+  output$richnessATable <- renderUI({
+    validate(need(data16S(),
+                  "Requires an abundance dataset"))
+    p(beautifulTable(data.frame(
+      SAMPLE = sample_names(data16S()), round(estimate_richness(data16S()), digits = 2)
+    )))
+  })
+
+  output$richnessBUI <- renderUI({
+    box(
+      title = "Setting : " ,
+      width = NULL,
+      status = "primary",
+      selectInput(
+        "richnessBOrder",
+        label = "Sorting sample : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      ),
+      textInput("richnessBTitle",
+                label = "Title : ",
+                value = "Beta diversity heatmap")
+    )
+  })
+
+  output$richnessB <- renderPlot({
+    validate(need(data16S(),
+                  "Requires an abundance dataset"))
+    beta <-
+      melt(as(distance(data16S(), method = input$richnessBDist), "matrix"))
+    colnames(beta) <- c("x", "y", "distance")
+    if (!is.null(checkNull(input$richnessBOrder)))
+    {
+      new_factor = as.factor(get_variable(data16S(), input$richnessBOrder))
+      variable_sort <-
+        as.factor(get_variable(data16S(), input$richnessBOrder)[order(new_factor)])
+      L = levels(reorder(sample_names(data16S()), as.numeric(new_factor)))
+      beta$x <- factor(beta$x, levels = L)
+      beta$y <- factor(beta$y, levels = L)
+      palette <- hue_pal()(length(levels(new_factor)))
+      tipColor <-
+        col_factor(palette, levels = levels(new_factor))(variable_sort)
+    }
+    p <-
+      ggplot(beta, aes(x = x, y = y, fill = distance)) + geom_tile()
+    p <- p + ggtitle(input$richnessBTitle) + theme(
+      axis.text.x = element_text(
+        angle = 90,
+        hjust = 1,
+        color = checkNull(tipColor)
+      ),
+      axis.text.y = element_text(color = checkNull(tipColor)),
+      axis.title.x = element_blank(),
+      axis.title.y = element_blank()
+    )
+    return(p + scale_fill_gradient2())
+  })
+
+  output$networkBUI <- renderUI({
+    validate(need(data16S(), ""))
+    box(
+      title = "Setting : " ,
+      width = NULL,
+      status = "primary",
+      sliderInput(
+        "netwMax",
+        label = "Threshold : ",
+        min = 0,
+        max = 1,
+        value = 0.7
+      ),
+      checkboxInput("netwOrphan",
+                    label = "Keep orphans",
+                    value = TRUE),
+      textInput("netwTitle",
+                label = "Title : ",
+                value = "Beta diversity network"),
+      selectInput(
+        "netwCol",
+        label = "Color : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      ),
+      selectInput(
+        "netwShape",
+        label = "Shape : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      ),
+      selectInput(
+        "netwLabel",
+        label = "Label : ",
+        choices = c(
+          "..." = 0,
+          "Sample name" = "value",
+          sample_variables(data16S())
+        )
+      )
+    )
+  })
+
+  output$networkB <- renderPlot({
+    validate(need(data16S(),
+                  "Requires an abundance dataset"))
+    g <- make_network(
+      data16S(),
+      distance = input$richnessBDist,
+      max.dist = input$netwMax,
+      keep.isolates = input$netwOrphan
+    )
+    p <- plot_network(
+      g,
+      physeq = data16S(),
+      color = checkNull(input$netwCol),
+      shape = checkNull(input$netwShape),
+      label = checkNull(input$netwLabel),
+      hjust = 2,
+      title = checkNull(input$netwTitle)
+    )
+    return(p)
+  })
+
+  output$richnessBTable <- renderUI({
+    validate(need(data16S(),
+                  "Requires an abundance dataset"))
+    p(beautifulTable(data.frame(
+      SAMPLE = sample_names(data16S()), round(as.matrix(
+        distance(data16S(), method = input$richnessBDist)
+      ), digits = 2)
+    )))
+  })
+
+  output$rarefactionCurve <- renderPlot({
+    validate(need(data16S(),
+                  "Requires an abundance dataset"))
+    p <- ggrare(
+      physeq = data16S(),
+      step = 100,
+      #step = input$rarefactionStep,
+      color = checkNull(input$rarefactionColor),
+      label = checkNull(input$rarefactionLabel),
+      se = FALSE
+    )
+    if (!is.null(checkNull(input$rarefactionGrid))) {
+      p <- p + facet_grid(paste(".", "~", input$rarefactionGrid))
+    }
+
+    if (input$rarefactionMin) {
+      p <-
+        p + geom_vline(xintercept = min(sample_sums(data16S())),
+                       color = "gray60")
+    }
+    return(p + ggtitle(input$rarefactionTitle))
+
+  })
+
+  output$rarefactionCurveUI <- renderUI({
+    validate(need(data16S(), ""))
+    box(
+      title = "Setting : " ,
+      width = NULL,
+      status = "primary",
+      # sliderInput(
+      #   "rarefactionStep",
+      #   label = "Etapes de calcul : ",
+      #   min = 1,
+      #   max = 1000,
+      #   value = 100
+      # ),
+      checkboxInput("rarefactionMin", label = "Show min sample threshold", value = FALSE),
+      textInput("rarefactionTitle",
+                label = "Title : ",
+                value = "Rarefaction curves"),
+      selectInput(
+        "rarefactionColor",
+        label = "Color : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      ),
+      selectInput(
+        "rarefactionLabel",
+        label = "Label : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      ),
+      selectInput(
+        "rarefactionGrid",
+        label = "Subplot : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      )
+    )
+  })
+
+  output$HeatmapUI <- renderUI({
+    validate(need(data16S(), ""))
+    box(
+      title = "Setting : " ,
+      width = NULL,
+      status = "primary",
+      textInput("heatmapTitle",
+                label = "Title : ",
+                value = "Taxa heatmap by samples"),
+      selectInput(
+        "heatmapGrid",
+        label = "Subplot : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      ),
+      selectInput(
+        "heatmapX",
+        label = "X : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      ),
+      sliderInput(
+        "heatmapTopOtu",
+        label = "Show the n most abundant OTU : ",
+        min = 1,
+        max = ntaxa(data16S()),
+        value = 250
+      ),
+      selectInput(
+        "heatmapDist",
+        label = "Distance : ",
+        selected = "bray",
+        choices = list(
+          "bray",
+          "jaccard",
+          "unifrac",
+          "wunifrac",
+          "dpcoa",
+          "jsd",
+          "euclidean"
+        )
+      ),
+      selectInput(
+        "heatmapMethod",
+        label = "Method : ",
+        selected = "NMDS",
+        choices = list(
+          "NMDS",
+          "ward.D2",
+          "ward.D",
+          "single",
+          "complete",
+          "average",
+          "mcquitty",
+          "median",
+          "centroid"
+        )
+      )
+    )
+  })
+
+  output$Heatmap <- renderPlot({
+    validate(need(data16S(),
+                  "Requires an abundance dataset"))
+    p <- plot_heatmap(
+      physeq = prune_taxa(names(sort(
+        taxa_sums(data16S()), decreasing = TRUE
+      )[1:input$heatmapTopOtu]), data16S()),
+      distance = input$heatmapDist,
+      method = input$heatmapMethod,
+      title = checkNull(input$heatmapTitle),
+      sample.order = checkNull(input$heatmapX),
+      low = "yellow",
+      high = "red",
+      na.value = "white"
+    )
+    if (!is.null(checkNull(input$heatmapGrid))) {
+      p <-
+        p + facet_grid(paste(".", "~", input$heatmapGrid), scales = "free_x")
+    }
+    return(p)
+  })
+
+  output$treeUI <- renderUI({
+    validate(need(data16S(), ""))
+    box(
+      title = "Setting : " ,
+      width = NULL,
+      status = "primary",
+      radioButtons(
+        "treeRank",
+        label = "Taxonomic rank captioned : ",
+        choices = c(aucun = "",
+                    rank_names(data16S()),
+                    OTU = "taxa_names"),
+        inline = TRUE
+      ),
+      sliderInput(
+        "treeTopOtu",
+        label = "Show the n most abundant OTU : ",
+        min = 1,
+        max = ntaxa(data16S()),
+        value = 20
+      ),
+      checkboxInput("treeRadial", label = "Radial tree", value = FALSE),
+      checkboxInput("treeSample", label = "Show samples", value = TRUE),
+      textInput("treeTitle",
+                label = "Title : ",
+                value = "Phylogenetic tree"),
+      selectInput(
+        "treeCol",
+        label = "Color : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      ),
+      selectInput(
+        "treeShape",
+        label = "Shape : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      )
+    )
+  })
+
+  output$tree <- renderPlot({
+    validate(
+      need(data16S(), "Requires an abundance dataset"),
+      need(
+        phy_tree(data16S(), errorIfNULL = FALSE),
+        "Requires a phylogenetic tree"
+      )
+    )
+    p <- plot_tree(
+      physeq = prune_taxa(names(sort(
+        taxa_sums(data16S()), decreasing = TRUE
+      )[1:input$treeTopOtu]), data16S()),
+      method = ifelse(input$treeSample, "sampledodge", "treeonly"),
+      color = checkNull(input$treeCol),
+      shape = checkNull(input$treeShape),
+      size = "abundance",
+      label.tips = checkNull(input$treeRank),
+      sizebase = 5,
+      ladderize = "left",
+      plot.margin = 0,
+      title = checkNull(input$treeTitle)
+    )
+    if (checkNull(input$treeRadial)) {
+      return(p + coord_polar(theta = "y"))
+    } else {
+      return(p)
+    }
+  })
+
+  output$acpUI <- renderUI({
+    validate(need(data16S(), ""))
+    box(
+      title = "Setting : " ,
+      width = NULL,
+      status = "primary",
+      checkboxGroupInput(
+        "acpAxes",
+        label = "Axes : ",
+        choices = seq(10),
+        selected = c(1, 2),
+        inline = TRUE
+      ),
+      selectInput(
+        "acpDist",
+        label = "Distance : ",
+        selected = "bray",
+        choices = list(
+          "bray",
+          "jaccard",
+          "unifrac",
+          "wunifrac",
+          "dpcoa",
+          "jsd",
+          "euclidean"
+        )
+      ),
+      selectInput(
+        "acpMethod",
+        label = "Method : ",
+        selected = "MDS",
+        choices = list("DCA", "CCA", "RDA", "CAP", "DPCoA", "NMDS", "MDS", "PCoA")
+      ),
+      textInput("acpTitle",
+                label = "Title : ",
+                value = "Samples ordination graphic"),
+      selectInput(
+        "acpLabel",
+        label = "Label : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      ),
+      selectInput(
+        "acpCol",
+        label = "Color : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      ),
+      selectInput(
+        "acpShape",
+        label = "Shape : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      ),
+      selectInput(
+        "acpEllipse",
+        label = "Ellipses : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      ),
+      selectInput(
+        "acpRep",
+        label = "Barycenters : ",
+        choices = c("..." = 0, sample_variables(data16S()))
+      )
+    )
+  })
+
+  output$acp <- renderPlot({
+    validate(
+      need(data16S(), "Requires an abundance dataset"),
+      need(length(input$acpAxes) == 2, "Requires two projections axes")
+    )
+    p <- plot_samples(
+      data16S(),
+      ordination = ordinate(
+        data16S(),
+        method = input$acpMethod,
+        distance = input$acpDist
+      ),
+      axes = as.numeric(input$acpAxes),
+      title = checkNull(input$acpTitle),
+      color = checkNull(input$acpCol),
+      replicate = checkNull(input$acpRep),
+      shape = checkNull(input$acpShape),
+      label = checkNull(input$acpLabel)
+    )
+    if (!is.null(checkNull(input$acpEllipse))) {
+      p <- p + stat_ellipse(aes_string(group = input$acpEllipse))
+    }
+    return(p + theme_bw())
+  })
 })
\ No newline at end of file
diff --git a/ui.R b/ui.R
index 05da260adf702061ee53d42167b8454b159ce5ea..6d405dec8f10939f4cce4efb43d3ae65a97831b0 100644
--- a/ui.R
+++ b/ui.R
@@ -1,208 +1,208 @@
-library(shinydashboard)
-library(shinycustomloader)
-shinyUI(dashboardPage(
-  dashboardHeader(title = "Easy16S"),
-  dashboardSidebar(
-    tags$div(
-      title = "Select dataset for demonstration",
-      selectInput(
-        "dataset",
-        label = "Select dataset : ",
-        choices = list(
-          "Input data" = "input",
-          "Rdata" = "rdata",
-          "Demo : Chaillou et al., 2015" = "food"
-        ),
-        # "Mach et al., 2015" = "kinetic", "Morton et al., 2017" = "soil", "Ravel et al., 2011" = "ravel", "biorare" = "biorare", "GlobalPatterns" = "GlobalPatterns"
-        selected = 1
-      )
-    ),
-    hr(),
-    tags$div(
-      title = "RData where 'data' is a phyloseq object.",
-      fileInput("fileRData",
-                label = "RData : ",
-                placeholder = "data.RData")
-    ),
-    hr(),
-    tags$div(
-      title = "Abundance BIOM file come from FROGS with 'FROGS BIOM to std BIOM', Qiime or another metagenomic tool.",
-      fileInput("fileBiom",
-                label = "Abundance BIOM file : ",
-                placeholder = "data.biom"),
-      radioButtons(
-        "biomFormat",
-        label = NULL,
-        inline = TRUE,
-        choices = list(`STD BIOM` = "std",
-                       `FROGS BIOM` = "frogs"),
-        selected = "std"
-      )
-    ),
-    tags$div(
-      style = "text-align:center",
-      title = "Resample dataset such that all samples have the same library size. \nIt's using an random sampling without replacement.",
-      checkboxInput("rareData", label = "Rarefy dataset", value = TRUE),
-      textOutput("rarefactionMin")
-    ),
-    tags$div(
-      title = "Metadata table with variables (in columns) and samples (in rows). \nMake sure you follow the exact spelling of the sample names (1st column). \nThe import of an excel table is possible but not recommended.",
-      fileInput("fileMeta",
-                label = "Metadata table : ",
-                placeholder = "data.csv")
-    ),
-    radioButtons(
-      "CSVsep",
-      label = "CSV separator : ",
-      inline = TRUE,
-      choices = list(
-        `<tab>` = "\t",
-        `,` = ",",
-        `;` = ";",
-        excel = "excel"
-      )
-    ),
-    tags$div(
-      title = "Phylogenetic tree",
-      fileInput("fileTree",
-                label = "Phylogenetic tree : ",
-                placeholder = "data.nwk")
-    ),
-    # tags$div(
-    #   title = "Representative FASTA sequences of OTU",
-    #   fileInput(
-    #     "fileSeq",
-    #     label = "FASTA sequences : "),
-    #     placeholder = "data.fasta"
-    #   )
-    # ),
-    uiOutput("downloadUI")
-  ),
-  dashboardBody(
-    tabsetPanel(
-      tabPanel(
-        "Summary",
-        verbatimTextOutput("phyloseqPrint"),
-        withLoader(uiOutput("summaryTable")),
-        tags$footer(
-          "Questions, problems or comments regarding this application should be sent to ",
-          a(href = "mailto:cedric.midoux@irstea.fr?subject=[Easy16S]", "cedric.midoux@irstea.fr"),
-          align = "center",
-          style = "position:absolute;
-          bottom: 0;
-          width: 100%;
-          color: grey;
-          padding: 10px;
-          # background-color: white;
-          z-index: 1000;
-          "
-        )
-        ),
-      tabPanel("Global barplot",
-               withLoader(plotOutput("histo", height = 700)),
-               uiOutput("histUI")),
-      tabPanel(
-        "Filtered barplot",
-        withLoader(plotOutput("histoFocus", height = 700)),
-        box(
-          title = "Paramètres",
-          width = NULL,
-          status = "primary",
-          uiOutput("histFocusUIfocusRank"),
-          uiOutput("histFocusUIfocusTaxa"),
-          uiOutput("histFocusUIfocusNbTaxa"),
-          uiOutput("histFocusUIfocusGrid"),
-          uiOutput("histFocusUIfocusX")
-        )
-      ),
-      tabPanel("Heatmap",
-               withLoader(plotOutput("Heatmap", height = 700)),
-               uiOutput("HeatmapUI")),
-      tabPanel(
-        "Rarefaction curves",
-        withLoader(plotOutput("rarefactionCurve", height = 700)),
-        uiOutput("rarefactionCurveUI")
-      ),
-      tabPanel(HTML("&alpha;-diversity"),
-               box(
-                 width = NULL, tabsetPanel(
-                   tabPanel("Plots",
-                            withLoader(plotOutput(
-                              "richnessA", height = 700
-                            )),
-                            uiOutput("richnessAUI")),
-                   tabPanel("Tables", withLoader(uiOutput("richnessATable")))
-                 )
-               )),
-      tabPanel(
-        HTML("&beta;-diversity"),
-        selectInput(
-          "richnessBDist",
-          label = "Distance : ",
-          choices = list(
-            "bray",
-            "jaccard",
-            "unifrac",
-            "wunifrac",
-            "dpcoa",
-            "jsd",
-            "euclidean"
-          )
-        ),
-        box(width = NULL, tabsetPanel(
-          tabPanel("Heatmap",
-                   withLoader(plotOutput(
-                     "richnessB", height = 700
-                   )),
-                   uiOutput("richnessBUI")),
-          tabPanel("Networks",
-                   withLoader(plotOutput("networkB", height = 700)),
-                   uiOutput("networkBUI")),
-          tabPanel("Tables", withLoader(uiOutput("richnessBTable")))
-        ))
-      ),
-      tabPanel(
-        "MultiDimensional Scaling",
-        withLoader(plotOutput("acp", height = 700)),
-        uiOutput("acpUI")
-      ),
-      tabPanel(
-        "Phylogenetic tree",
-        withLoader(plotOutput("tree", height = 700)),
-        uiOutput("treeUI")
-      ),
-      tabPanel("Clustering",
-               withLoader(plotOutput("clust", height = 700)),
-               uiOutput("clustUI")),
-      tabPanel("Help",
-               div(
-                 HTML(
-                   "<p>
-                   Questions, problems or comments regarding this application should be sent to
-                   <a href = \"mailto:cedric.midoux@irstea.fr?subject=[Easy16S]\">cedric.midoux@irstea.fr</a>
-                   </p>
-                   
-                   <p>
-                   For more information about this tool, you can refer to
-                   <a href = \"http://migale.jouy.inra.fr/sites/migale.jouy.inra.fr.drupal7.migale.jouy.inra.fr/files/JOBIM2018_poster.pdf\">this poster</a>.
-                   </p>
-                   
-                   <p>
-                   <u>The demo dataset :</u> Chaillou, S., et al. \"
-                   <a href = \"https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4409155/\">
-                   Origin and ecological selection of core and food-specific bacterial communities associated with meat and seafood spoilage.</a>\"
-                   <i>The ISME journal</i> 9.5 (2015): 1105.
-                   <br>
-                   16S survey of bacterial communities from 8 different food products, distributed as 4 meat products and 4 seafoods. Used to find core microbiota of food products.
-                   </p>
-                   <br>
-                   <p align=\"center\" position=\"absolute\" bottom\"80px\">
-                   <img src=\"migale.png\" width=\"100\"/>
-                   <img src=\"Irstea.png\" width=\"100\"/>
-                   </p>
-                   "
-                 )
-                 ))
-                 )
-               )
-        ))
+library(shinydashboard)
+library(shinycustomloader)
+shinyUI(dashboardPage(
+  dashboardHeader(title = "Easy16S"),
+  dashboardSidebar(
+    tags$div(
+      title = "Select a dataset for demonstration purpose",
+      selectInput(
+        "dataset",
+        label = "Select dataset : ",
+        choices = list(
+          "Input data" = "input",
+          "Rdata" = "rdata",
+          "Demo : Chaillou et al., 2015" = "food"
+        ),
+        # "Mach et al., 2015" = "kinetic", "Morton et al., 2017" = "soil", "Ravel et al., 2011" = "ravel", "biorare" = "biorare", "GlobalPatterns" = "GlobalPatterns"
+        selected = 1
+      )
+    ),
+    hr(),
+    tags$div(
+      title = "RData where 'data' is a phyloseq object.",
+      fileInput("fileRData",
+                label = "RData : ",
+                placeholder = "data.RData")
+    ),
+    hr(),
+    tags$div(
+      title = "Abundance BIOM file come from FROGS with 'FROGS BIOM to std BIOM', Qiime or another metagenomic tool.",
+      fileInput("fileBiom",
+                label = "Abundance BIOM file : ",
+                placeholder = "data.biom"),
+      radioButtons(
+        "biomFormat",
+        label = NULL,
+        inline = TRUE,
+        choices = list(`STD BIOM` = "std",
+                       `FROGS BIOM` = "frogs"),
+        selected = "std"
+      )
+    ),
+    tags$div(
+      style = "text-align:center",
+      title = "Resample dataset such that all samples have the same library size. \nIt's using an random sampling without replacement.",
+      checkboxInput("rareData", label = "Rarefy dataset", value = TRUE),
+      textOutput("rarefactionMin")
+    ),
+    tags$div(
+      title = "Metadata table with variables (in columns) and samples (in rows). \nMake sure you follow the exact spelling of the sample names (1st column). \nThe import of an excel table is possible but not recommended.",
+      fileInput("fileMeta",
+                label = "Metadata table : ",
+                placeholder = "data.csv")
+    ),
+    radioButtons(
+      "CSVsep",
+      label = "CSV separator : ",
+      inline = TRUE,
+      choices = list(
+        `<tab>` = "\t",
+        `,` = ",",
+        `;` = ";",
+        excel = "excel"
+      )
+    ),
+    tags$div(
+      title = "Phylogenetic tree",
+      fileInput("fileTree",
+                label = "Phylogenetic tree : ",
+                placeholder = "data.nwk")
+    ),
+    # tags$div(
+    #   title = "Representative FASTA sequences of OTU",
+    #   fileInput(
+    #     "fileSeq",
+    #     label = "FASTA sequences : "),
+    #     placeholder = "data.fasta"
+    #   )
+    # ),
+    uiOutput("downloadUI")
+  ),
+  dashboardBody(
+    tabsetPanel(
+      tabPanel(
+        "Summary",
+        verbatimTextOutput("phyloseqPrint"),
+        withLoader(uiOutput("summaryTable")),
+        tags$footer(
+          "Questions, problems or comments regarding this application should be sent to ",
+          a(href = "mailto:cedric.midoux@irstea.fr?subject=[Easy16S]", "cedric.midoux@irstea.fr"),
+          align = "center",
+          style = "position:absolute;
+          bottom: 0;
+          width: 100%;
+          color: grey;
+          padding: 10px;
+          # background-color: white;
+          z-index: 1000;
+          "
+        )
+        ),
+      tabPanel("Global barplot",
+               withLoader(plotOutput("histo", height = 700)),
+               uiOutput("histUI")),
+      tabPanel(
+        "Filtered barplot",
+        withLoader(plotOutput("histoFocus", height = 700)),
+        box(
+          title = "Paramètres",
+          width = NULL,
+          status = "primary",
+          uiOutput("histFocusUIfocusRank"),
+          uiOutput("histFocusUIfocusTaxa"),
+          uiOutput("histFocusUIfocusNbTaxa"),
+          uiOutput("histFocusUIfocusGrid"),
+          uiOutput("histFocusUIfocusX")
+        )
+      ),
+      tabPanel("Heatmap",
+               withLoader(plotOutput("Heatmap", height = 700)),
+               uiOutput("HeatmapUI")),
+      tabPanel(
+        "Rarefaction curves",
+        withLoader(plotOutput("rarefactionCurve", height = 700)),
+        uiOutput("rarefactionCurveUI")
+      ),
+      tabPanel(HTML("&alpha;-diversity"),
+               box(
+                 width = NULL, tabsetPanel(
+                   tabPanel("Plots",
+                            withLoader(plotOutput(
+                              "richnessA", height = 700
+                            )),
+                            uiOutput("richnessAUI")),
+                   tabPanel("Tables", withLoader(uiOutput("richnessATable")))
+                 )
+               )),
+      tabPanel(
+        HTML("&beta;-diversity"),
+        selectInput(
+          "richnessBDist",
+          label = "Distance : ",
+          choices = list(
+            "bray",
+            "jaccard",
+            "unifrac",
+            "wunifrac",
+            "dpcoa",
+            "jsd",
+            "euclidean"
+          )
+        ),
+        box(width = NULL, tabsetPanel(
+          tabPanel("Heatmap",
+                   withLoader(plotOutput(
+                     "richnessB", height = 700
+                   )),
+                   uiOutput("richnessBUI")),
+          tabPanel("Networks",
+                   withLoader(plotOutput("networkB", height = 700)),
+                   uiOutput("networkBUI")),
+          tabPanel("Tables", withLoader(uiOutput("richnessBTable")))
+        ))
+      ),
+      tabPanel(
+        "MultiDimensional Scaling",
+        withLoader(plotOutput("acp", height = 700)),
+        uiOutput("acpUI")
+      ),
+      tabPanel(
+        "Phylogenetic tree",
+        withLoader(plotOutput("tree", height = 700)),
+        uiOutput("treeUI")
+      ),
+      tabPanel("Clustering",
+               withLoader(plotOutput("clust", height = 700)),
+               uiOutput("clustUI")),
+      tabPanel("Help",
+               div(
+                 HTML(
+                   "<p>
+                   Questions, problems or comments regarding this application should be sent to
+                   <a href = \"mailto:cedric.midoux@irstea.fr?subject=[Easy16S]\">cedric.midoux@irstea.fr</a>
+                   </p>
+
+                   <p>
+                   For more information about this tool, you can refer to
+                   <a href = \"http://migale.jouy.inra.fr/sites/migale.jouy.inra.fr.drupal7.migale.jouy.inra.fr/files/JOBIM2018_poster.pdf\">this poster</a>.
+                   </p>
+
+                   <p>
+                   <u>The demo dataset :</u> Chaillou, S., et al. \"
+                   <a href = \"https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4409155/\">
+                   Origin and ecological selection of core and food-specific bacterial communities associated with meat and seafood spoilage.</a>\"
+                   <i>The ISME journal</i> 9.5 (2015): 1105.
+                   <br>
+                   16S survey of bacterial communities from 8 different food products, distributed as 4 meat products and 4 seafoods. Used to find core microbiota of food products.
+                   </p>
+                   <br>
+                   <p align=\"center\" position=\"absolute\" bottom\"80px\">
+                   <img src=\"migale.png\" width=\"100\"/>
+                   <img src=\"Irstea.png\" width=\"100\"/>
+                   </p>
+                   "
+                 )
+                 ))
+                 )
+               )
+        ))