R/DEGsUserInterface.R

Defines functions DEGsUserInterface

Documented in DEGsUserInterface

#' UI function for DEGs module in Shiny application
#' @param id Shiny module identifier
DEGsUserInterface <- function(id) {
  # Sidebar for filtering operations
  bslib::layout_sidebar(

      htmltools::tags$head(
        htmltools::tags$style(htmltools::HTML("
        .tooltip-inner {
          max-width: 400px;  /* Adjust the width */
          white-space: normal;  /* Allow text to wrap */
          text-align: left;  /* Optional: aligns text to the left */
          border-radius: 4px !important;  /* Less curvature */
          background-color: #202020;      /* Optional: lighter background */
          color: #FFFFFF;                 /* Optional: darker text for readability */
          border: 1px solid #ccc;         /* Optional: subtle border */
        }
      "))
      ),
      htmltools::tags$style(".selectize-dropdown {position: static}"),
      shinyjs::useShinyjs(), # Enables JavaScript for more interactive features
      rintrojs::introjsUI(), # Allows the use of intro.js for creating interactive onboarding tours
      bslib::input_dark_mode(id = "dark_mode"), # Toggle for dark mode

      # sidebar DEG User Interface
      sidebar = bslib::sidebar(
        width = "23%",


        # 1 step - import matrices obtained from summarization step
          shiny::fluidRow(shiny::column(
            12, align = "left", htmltools::h5("Step 1 - Import count matrices"), htmltools::br()
          )),

          shiny::fluidRow(shiny::column(
            width = 12,
            shiny::splitLayout(
              cellWidths = c("90%", "10%"),
              shinyFiles::shinyDirButton(shiny::NS(id, "directory_raw_count"),
                "Select_input_folder",
                "Please select the folder containing the raw count data for the samples."
                ,
                icon = shiny::icon("upload")
              ),
              bslib::tooltip(
                bsicons::bs_icon("question-circle"),
                "This folder contains the count matrices for each sample in tab-separated format (e.g., <sampleName>.tab). Each file uses tab delimiters and is generated from the summarization step. Ensure the folder contains only count matrix files.
File names will serve as sample identifiers, with the .tab extension removed. If you upload files not generated by the inDAGO summarization module, you must manually select the columns corresponding to genes and counts after loading. The first column (col1) should contain gene names, while the second column (col2) should hold quantification data. Additionally, remove any initial accessory rows before proceeding.",
                placement = "right"
              )
            ),
            # Displays the selected input directory path
            shiny::verbatimTextOutput(shiny::NS(id, "directory_raw_count_path"))

          )),

        # 2 step - Assigns groups by loading or creating matrix with 'Samples' and 'Groups'
          shiny::fluidRow(shiny::column(12, align = "left", htmltools::tags$hr(
            htmltools::h5("Step 2 - Group assignment")
          ), htmltools::br())),

          shiny::fluidRow(shiny::column(
            width = 12, shiny::splitLayout(
              cellWidths = c("90%", "10%"),
              shiny::radioButtons(shiny::NS(id, "Import_table_exp"),
                label = "How to assign groups",
                choices = c("Load the matrix" = "Loading", "Generate the matrix" = "Create"),
                selected = "Loading"
              ),
              bslib::tooltip(
                bsicons::bs_icon("question-circle"),
                "Upload a CSV or TAB-separated file containing 'Samples' and 'Groups' metadata, or generate the table interactively. Completing either task is sufficient; if both are done, only the uploaded file will be used. For more details, click the 'Info' button.",
                placement = "right"
              )
            )
          )),

          # Conditional panel that appears if Import_table_exp == 'Loading'
          shiny::conditionalPanel(
            condition = sprintf("input['%s'] == 'Loading'", shiny::NS(id, "Import_table_exp")),
            shiny::fluidRow(shiny::column(
              width = 12,
              shiny::splitLayout(
                cellWidths = c("90%", "10%"),
                shinyFiles::shinyFilesButton(shiny::NS(id, id = "assignGroupByTable"),
                  label = "Select_input_table",
                  title = "Please select the input table"
                  ,
                  icon = shiny::icon("upload"),
                  multiple = FALSE
                ),
                bslib::tooltip(
                  bsicons::bs_icon("question-circle"),
                  "This input table must contain two columns: 'Samples' and 'Groups'. The 'Samples' column should list sample names (e.g., A1, A2, A3, B1, B2, B3, C1, C2, C3), while the 'Groups' column should indicate the corresponding group names (e.g., A, A, A, B, B, B, C, C, C).",
                  placement = "right"
                )
              ),
              # Displays the selected file
              shiny::verbatimTextOutput(shiny::NS(id, "AssignGroupByTablePath"))

            )
          )),
          # Conditional panel that appears if Import_table_exp == 'Create'
          shiny::conditionalPanel(
            condition = sprintf("input['%s'] == 'Create'", shiny::NS(id, "Import_table_exp")),
            shiny::fluidRow(shiny::column(
            width = 12, shiny::splitLayout(
              cellWidths = c("90%", "10%"),
              shiny::actionButton(shiny::NS(id, "assign_group"),
                label = "View_matrix",
                shiny::icon("table"),
                class = "btn-primary"
              ),
              bslib::tooltip(
                bsicons::bs_icon("question-circle"),
                "View the table for group assignments",
                placement = "right"
              )
            )
          )), htmltools::br()),


        # 3 step - set contrast groups for identification of DEGs
          shiny::fluidRow(shiny::column(12, align = "center", htmltools::tags$hr(
            htmltools::h5("Step 3 - Defining contrasts")
          ), htmltools::br())),

          #input : set the minimum count required for at least some samples


          shiny::fluidRow(shiny::column(
            width = 12,
            shiny::splitLayout(
              cellWidths = c("90%", "10%"),
              #  The button to trigger the preparation of necessary input for plot generation
              shiny::actionButton(shiny::NS(id, "SetContrast"),
                label = "Show contrast",
                shiny::icon("table"),
                class = "btn-primary"

              ),
              bslib::tooltip(
                bsicons::bs_icon("question-circle"),
                "Verify and display all possible contrast variations in the corresponding result panel (i.e., Step 3 Result - Defining contrasts).",
                placement = "right"
              )
            ),

            shiny::verbatimTextOutput(shiny::NS(id, "SetContrastNote"))

          )),



        # Running DEG analysis

        # 4 step - set options used to process data, generate edger DGEList object and make contrast
          shiny::fluidRow(shiny::column(12, align = "center", htmltools::tags$hr(
            htmltools::h5("Step 4 - Identifying DEGs")
          ), htmltools::br())),



          shiny::fluidRow(
            shiny::column(width = 12, shiny::splitLayout(
              cellWidths = c("90%", "10%"),
              shinyFiles::shinyDirButton(shiny::NS(id, "directory_deg"),
                "Select_output_folder",
                "Please choose the folder where the DEG list will be saved."
                ,
                icon = shiny::icon("download")
              ),
              bslib::tooltip(
                bsicons::bs_icon("question-circle"),
                "This is the output folder where the result of differential expression analysis will be saved",
                placement = "right"
              )
            )),

            shiny::verbatimTextOutput(shiny::NS(id, "directory_deg_path"))

          ),


          # input: Set the filtering method
          shiny::fluidRow(shiny::column(
            width = 12, shiny::splitLayout(
              cellWidths = c("90%", "10%"),
              shiny::radioButtons(shiny::NS(id, "filterDEG"),
                "Filter_mode",
                choices = c("filterByExpr", "HTSFilter"),
                selected = "filterByExpr"
              ),
              bslib::tooltip(
                bsicons::bs_icon("question-circle"),
                "Choose a filter to apply. The filterByExpr function, the default in edgeR, retains rows with sufficient counts in a minimum number of samples. Alternatively, the HTSFilter function, available in the HTSFilter package, uses a global Jaccard similarity index to filter genes with low and consistent expression across one or more experimental conditions. The default parameters for HTSFilter are s.min = 1, s.max = 200, and s.len = 100. Please refer to the package documentation for additional details. Note that to use the HTSFilter function, each experimental condition must have more than one biological replicate. 'filterByExpr' by deafult",
                placement = "right"
              )
            )
          )),

          shiny::conditionalPanel(
            condition = sprintf("input['%s'] == 'filterByExpr'", shiny::NS(id, "filterDEG")),
            #input : set the minimum count required for at least some samples
            shiny::fluidRow(shiny::column(
              width = 12, shiny::splitLayout(
                cellWidths = c("90%", "10%"),
                shiny::numericInput(shiny::NS(id, "DEGsmin_count"),
                  label = "min_count",
                  min = 1,
                  value = 10
                ),
                bslib::tooltip(
                  bsicons::bs_icon("question-circle"),
                  "Minimum count required for at least N samples. '10' by default",
                  placement = "right"
                )
              )
            )),

            # input: set the minimum total count required
            shiny::fluidRow(shiny::column(
              width = 12, shiny::splitLayout(
                cellWidths = c("90%", "10%"),
                shiny::numericInput(shiny::NS(id, "DEGsmin_total_count"),
                  label = "min_total_count",
                  min = 1,
                  value = 15
                ),
                bslib::tooltip(
                  bsicons::bs_icon("question-circle"),
                  "Minimum total count required. '15' by default",
                  placement = "right"
                )
              )
            )),

            # input: set number of samples per group that is considered to be 'large'
            shiny::fluidRow(shiny::column(
              width = 12, shiny::splitLayout(
                cellWidths = c("90%", "10%"),
                shiny::numericInput(shiny::NS(id, "DEGslarge_n"),
                  label = "large_n",
                  min = 1,
                  value = 10
                ),
                bslib::tooltip(
                  bsicons::bs_icon("question-circle"),
                  "Number of samples per group considered 'large'. '10' by default",
                  placement = "right"
                )
              )
            )),



            # input: In large sample situations, the minimum percentage of samples within a group in which a gene must be expressed
            shiny::fluidRow(shiny::column(
              width = 12, shiny::splitLayout(
                cellWidths = c("90%", "10%"),
                shiny::numericInput(shiny::NS(id, "DEGsmin_prop"),
                  label = "min_prop",
                  min = 0.1,
                  value = 0.7,
                  step = 0.1
                ),
                bslib::tooltip(
                  bsicons::bs_icon("question-circle"),
                  "In large sample cases, minimum percentage of samples in which a gene must be expressed. '0.7' by default",
                  placement = "right"
                )
              )
            ))

          ),
          # close condition panel filterDEG == 'filterByExpr'


          # Input: Choose normalization method for DEG analysis (e.g., TMM, RLE)
          shiny::fluidRow(shiny::column(
            width = 12, shiny::splitLayout(
              cellWidths = c("90%", "10%"),
              shiny::radioButtons(shiny::NS(id, "normMethod"),
                "Normalization_method",
                choices = c("TMM", "RLE", "none"),
                selected = "TMM"
              ),
              bslib::tooltip(
                bsicons::bs_icon("question-circle"),
                "The normalization method is used to adjust library sizes in a way that minimizes log-fold changes between samples for most genes. The Trimmed Mean of M-values (TMM) is a scaling normalization method introduced by Robinson and Oshlack (2010). Alternatively, Relative Log Expression (RLE), a scaling factor method proposed by Anders and Huber (2010), can be used. 'TMM' by deafult",
                placement = "right"
              )
            )
          )),

          # Input: Select method for testing DEGs (e.g., exactTest, glmQLFTest)
          shiny::fluidRow(shiny::column(
            width = 12, shiny::splitLayout(
              cellWidths = c("90%", "10%"),
              shiny::radioButtons(shiny::NS(id, "modelDEG"),
                "Model_test",
                choices = c("exactTest", "glmLRT", "glmQLFTest"),
                selected = "glmQLFTest"
              ),
              bslib::tooltip(
                bsicons::bs_icon("question-circle"),
                "Choose the EdgeR function to test for differentially expressed genes. The 'exactTest' function is part of the classical edgeR pipeline and uses the qCML methods. It applies the negative binomial distribution and has strong parallels with exact test of Fisher. The 'glmLRT' function performs a likelihood ratio test, which is useful in specific cases, such as datasets with no replicates. The 'glmQLFTest' function uses the quasi-likelihood (QL) F-test, offering more conservative and rigorous control of type I error rates. The QL method is highly recommended for differential expression analysis of dual/bulk RNA-seq. 'glmQLFTest' by deafult",
                placement = "right"
              )
            )
          )),


          # Input: Select method for adjusting p-values after DEG analysis (e.g., Holm, FDR)
          shiny::fluidRow(shiny::column(
            width = 12, shiny::splitLayout(
              cellWidths = c("90%", "10%"),
              shiny::radioButtons(shiny::NS(id, "adjustPvalue"),
                "adjusted_PValue",
                choices = c("holm", "hochberg", "hommel", "bonferroni", "fdr", "none"),
                selected = "fdr"
              ),
              bslib::tooltip(
                bsicons::bs_icon("question-circle"),
                "The available adjustment methods include Holm (1979) ('holm'), Hochberg (1988) ('hochberg'), Hommel (1988) ('hommel'), Bonferroni correction (1936) ('bonferroni'), Benjamini & Hochberg (1995) ('fdr'), and Benjamini & Yekutieli (2001) ('BY'). 'fdr' by default",
                placement = "right"
              )
            )
          )),
          # Input: Threshold for absolute log fold change (logFC) to filter DEGs
          shiny::fluidRow(shiny::column(
            width = 12, shiny::splitLayout(
              cellWidths = c("90%", "10%"),
              shiny::numericInput(shiny::NS(id, "Th_logFC"),
                "logFC",
                min = 0,
                step = 0.01,
                value = 0.58

              ),
              bslib::tooltip(
                bsicons::bs_icon("question-circle"),
                "Set the logFC threshold for labeling a gene as differentially expressed (e.g., a logFC >= 0.58 indicates the gene is considered UP, while a logFC <= -0.58 indicates it is considered DOWN). The p-value threshold ('PValue' parameter) will also be evaluated. '0.58' by default",
                placement = "right"
              )
            )
          )),
          # Input: Threshold for adjusted PValue to filter DEGs
          shiny::fluidRow(shiny::column(
            width = 12, shiny::splitLayout(
              cellWidths = c("90%", "10%"),
              shiny::numericInput(shiny::NS(id, "Th_Pvalue"),
                "PValue",
                step = 0.01,
                value = 0.05
              ),
              bslib::tooltip(
                bsicons::bs_icon("question-circle"),
                "Set the p-value threshold (adjusted if the 'adjusted_p-value method' parameter is specified) for labeling a gene as differentially expressed. The logFC threshold ('logFC' parameter) will also be considered. '0.05' by default)",
                placement = "right"
              )
            )
          )),

          # Button to trigger DEG analysis

          shiny::fluidRow(shiny::column(
            width = 12,
            shiny::splitLayout(
              cellWidths = c("60%", "30%", "10%"),
              #  The button to trigger the preparation of necessary input for plot generation
              shiny::actionButton(shiny::NS(id, "RunDEGs"),
                           label = "Run analysis",
                           shiny::icon("table"),
                           class = "btn-primary"),
              shinyjs::disabled(
                shiny::actionButton(shiny::NS(id, "KillRunDEGs"),
                  label = "Kill",
                  class = "btn-warning",
                  icon = shiny::icon("fire")
                )
              ),
              bslib::tooltip(bsicons::bs_icon("question-circle"), "Run the test to identify differentially expressed genes between the selected contrasts.", placement = "right")
            ),

            shiny::verbatimTextOutput(shiny::NS(id, "RunDEGsNote"))

          )),

        # Section for optional operations related to merging DEG matrices
        accordion(
          open = FALSE,
            bslib::accordion_panel(
              "OPTIONAL OPERATIONS",
              icon = shiny::icon("plus-sign", lib = "glyphicon"),

              # Optional operations section heading

              shiny::fluidRow(shiny::column(12, align = "center", htmltools::tags$hr(
                htmltools::h5("Optional - Merge DEG")
              ), htmltools::br())),


              # Input: Select DEGs matrices for merging
              shiny::fluidRow(shiny::column(
                width = 12,
                shiny::splitLayout(
                  cellWidths = c("90%", "10%"),
                  shinyFiles::shinyDirButton(shiny::NS(id, "MergeDegsDir"),
                    label = "Select_input_DEG_folder",
                    title = "Please select the folder containing the input DEG files.",
                    icon = shiny::icon("upload"),
                    multiple = FALSE
                  ),
                  bslib::tooltip(
                    bsicons::bs_icon("question-circle"),
                    "Select the folder containing the DEG matrices in 'CSV' format (resulting from the 'Step 4 - Identifying DEGs') you want to merge",
                    placement = "right"
                  )
                ),
                shiny::verbatimTextOutput(shiny::NS(id, "MergeDegsPath"))

              )),
              # Input: Select GTF file for merging DEGs
              shiny::fluidRow(shiny::column(
                width = 12,
                shiny::splitLayout(
                  cellWidths = c("90%", "10%"),
                  shinyFiles::shinyFilesButton(shiny::NS(id, "MergeDegsgtf"),
                    label = "Select_input_GTF",
                    title = "Please select the input GTF file. It can be either uncompressed or gzip-compressed.",
                    icon = shiny::icon("upload"),
                    multiple = FALSE
                  ),
                  bslib::tooltip(
                    bsicons::bs_icon("question-circle"),
                    "Select the 'GTF' annotation file",
                    placement = "right"
                  )
                ),
                shiny::verbatimTextOutput(shiny::NS(id, "MergeDegsgtfPath"))

              )),

              # Input: Select columns in GTF for merging DEGs
              shiny::fluidRow(shiny::column(
                width = 12,
                shiny::splitLayout(
                  cellWidths = c("70%", "20%", "10%"),

                  shiny::checkboxGroupInput(shiny::NS(id, "ColumnsMergeDegs"),
                    "Select columns from GTF",
                    choices = c(
                      "seqnames",
                      "start",
                      "end",
                      "width",
                      "strand",
                      "source",
                      "type",
                      "gene_id",
                      "transcript_id",
                      "db_xref",
                      "gbkey",
                      "gene",
                      "gene_biotype",
                      "partial",
                      "pseudo",
                      "description",
                      "gene_synonym"
                    )
                  ),
                  # Button to check empty columns in GTF
                  shiny::actionButton(shiny::NS(id, "CheckEmptyGTFcol"),
                    label = "",
                    class = "btn-primary",
                    icon = shiny::icon("refresh")
                  ),
                  bslib::tooltip(
                    bsicons::bs_icon("question-circle"),
                    "Set the information to retain from the 9th column of the 'GTF' file. To avoid having empty attributes, you can update the list by using the corresponding refresh button, which will ensure that only attributes with at least one available annotation are selected.",
                    placement = "right"
                  )
                )
              )),

              # Input: Select type attribute in GTF for merging DEGs
              shiny::fluidRow(shiny::column(
                width = 12, shiny::splitLayout(
                  cellWidths = c("90%", "10%"),
                  shiny::radioButtons(shiny::NS(id, "typeFilterDegs"),
                    "Select the type attribute in 'GTF",
                    choices = c("gene", "transcript", "exon", "CDS"),
                    selected = "gene"
                  ),
                  bslib::tooltip(
                    bsicons::bs_icon("question-circle"),
                    "Select the type of attribute to retrieve from the annotation. The table will be integrated with the information extracted from the 'GTF' file based on the 'Choose columns from GTF' and 'Select the type attribute in GTF' settings. 'gene' by default",
                    placement = "right"
                  )
                )
              )),
              # Input: Select if merge just UP and DOWN
              shiny::fluidRow(shiny::column(
                width = 12, shiny::splitLayout(
                  cellWidths = c("90%", "10%"),
                  shiny::radioButtons(shiny::NS(id, "selectUpDownDegs"),
                    "Select only 'UP' and 'DOWN' labels",
                    choices = c("TRUE", "FALSE"),
                    selected = "TRUE"
                  ),
                  bslib::tooltip(
                    bsicons::bs_icon("question-circle"),
                    "Choose whether to select only the biological units labeled as 'UP' and 'DOWN'. 'TRUE' by default",
                    placement = "right"
                  )
                )
              )),
              # Input: Select if collapse name of matrices DEGs
              shiny::fluidRow(shiny::column(
                width = 12, shiny::splitLayout(
                  cellWidths = c("90%", "10%"),
                  shiny::radioButtons(shiny::NS(id, "collapseNameDegs"),
                    "Select whether to collapse names",
                    choices = c("TRUE", "FALSE"),
                    selected = "TRUE"
                  ),
                  bslib::tooltip(
                    bsicons::bs_icon("question-circle"),
                    "Select whether to collapse the names of each file by removing the prefixes <filterByExpr_, <HTSFilter_, <exactTest_, <glmQLFTest_, and <glmLRT_>.",
                    placement = "right"
                  )
                )
              )),
              # Input: Action button to run DEG merging process
              shiny::fluidRow(shiny::column(
                width = 12,
                shiny::splitLayout(
                  cellWidths = c("60%", "30%", "10%"),
                  #  The button to trigger the preparation of necessary input for plot generation
                  shiny::actionButton(shiny::NS(id, "RunMergeDegs"),
                    label = "Merge DEG tables",
                    shiny::icon("rocket"),
                    class = "btn-primary"
                  ),
                  shinyjs::disabled(
                    shiny::actionButton(shiny::NS(id, "killRunMergeDegs"),
                      label = "Kill",
                      class = "btn-warning",
                      icon = shiny::icon("fire")
                    )
                  ),
                  bslib::tooltip(
                    bsicons::bs_icon("question-circle"),
                    "Run the merging process to generate the resulting unified matrix.",
                    placement = "right"
                  )
                ),

                shiny::verbatimTextOutput(shiny::NS(id, "RunMergeDegsNote"))

              )),


              shiny::fluidRow(shiny::column(12, align = "center", htmltools::tags$hr(
                htmltools::h5("Optional - plots")
              ), htmltools::br())),

              shiny::fluidRow(shiny::column(12, align = "center", htmltools::h6("Volcano Plot")), htmltools::br()),
              # Input: Button to upload the DEG matrix for Volcano Plot
              shiny::fluidRow(shiny::column(
                width = 12,
                shiny::splitLayout(
                  cellWidths = c("90%", "10%"),
                  shinyFiles::shinyFilesButton(shiny::NS(id, "VolcanoDEGmatrix"),
                    label = "Select_input_DEG_matrix",
                    title = "Please select the input DEG matrix file"
                    ,
                    icon = shiny::icon("upload"),
                    multiple = FALSE
                  ),
                  bslib::tooltip(
                    bsicons::bs_icon("question-circle"),
                    "Select a single 'CSV' file (resulting from 'Step 4 - Identifying DEGs') to use for generating the volcano plot.",
                    placement = "right"
                  )
                ),
                shiny::verbatimTextOutput(shiny::NS(id, "VolcanoDEGmatrixPath"))

              )),
              # Input: Action button to run Volcano plot analysis
              shiny::fluidRow(shiny::column(
                width = 12,
                shiny::splitLayout(
                  cellWidths = c("60%", "30%", "10%"),
                  # Button to trigger the box plot analysis
                  shiny::actionButton(shiny::NS(id, "RunVolcano"),
                    label =  "Volcano plot",
                    shiny::icon("rocket"),
                    class = "btn-primary"
                  ),
                  shinyjs::disabled(
                    # Button to enable deletion of box chart analysis
                    shiny::actionButton(shiny::NS(id, "killRunVolcano"),
                      label = "Kill",
                      class = "btn-warning",
                      icon = shiny::icon("fire")
                    )
                  ),
                  bslib::tooltip(bsicons::bs_icon("question-circle"), "Generate Volcano plot", placement = "right")
                ),

                shiny::verbatimTextOutput(shiny::NS(id, "RunVolcanoNote"))

              )),

              htmltools::br(),

              shiny::fluidRow(shiny::column(12, align = "center", htmltools::h6("UpSet Plot")), htmltools::br()),

              # Input: Button to upload the DEGs matrices for Upset Plot
              shiny::fluidRow(shiny::column(
                width = 12,
                shiny::splitLayout(
                  cellWidths = c("90%", "10%"),
                  shinyFiles::shinyDirButton(shiny::NS(id, "UpsetDEGfolder"),
                    label = "Select_input_DEGs_folder",
                    title = "Please select input DEGs folder"
                    ,
                    icon = shiny::icon("upload"),
                    multiple = FALSE
                  ),
                  bslib::tooltip(
                    bsicons::bs_icon("question-circle"),
                    "Select a folder (containing the results of 'Step 4 - Identifying DEGs') you want to consider for generating UpSet plot. At least two contrasts should be taken into account.",
                    placement = "right"
                  )
                ),
                shiny::verbatimTextOutput(shiny::NS(id, "UpsetDEGfolderPath"))

              )),
              # Input: Action button to run Upset plot analysis
              shiny::fluidRow(shiny::column(
                width = 12,
                shiny::splitLayout(
                  cellWidths = c("60%", "30%", "10%"),
                  # Button to trigger the box plot analysis
                  shiny::actionButton(shiny::NS(id,  "RunUpSet"),
                    label =  "Upset plot",
                    shiny::icon("rocket"),
                    class = "btn-primary"
                  ),
                  shinyjs::disabled(
                    # Button to enable deletion of box chart analysis
                    shiny::actionButton(shiny::NS(id, "killRunUpSet"),
                      label = "Kill",
                      class = "btn-warning",
                      icon = shiny::icon("fire")
                    )
                  ),
                  bslib::tooltip(bsicons::bs_icon("question-circle"), "Generate UpSet plot", placement = "right")
                ),

                shiny::verbatimTextOutput(shiny::NS(id, "RunUpSetNote"))

              ))

            ))


      ),

      # MAIN PANEL ________________________________________________________________

      bslib::accordion(
        # Dropdown button for information about the summarization process
        shinyWidgets::dropdownButton(inputId = shiny::NS(id, "InfoDEGs"),
          status = "info",
          label = "Info",
          size = "sm",
          circle = FALSE,
          # Detailed description of the data exploration process
          htmltools::h3(shiny::strong("Identification of Differentially Expressed Genes (DEGs)")),
          htmltools::br(),
          htmltools::h5(htmltools::strong("WHEN TO PERFORM")),
          htmltools::h5(
            "The identification of differentially expressed genes should be conducted after the summarization or data exploration step."
          ),
          htmltools::br(),
          htmltools::br(),
          htmltools::h6(htmltools::strong("WHAT IT DOES")),
          htmltools::h6(
            "This module detects genes that exhibit significant differential expression between selected groups or conditions. Statistically significant variations in gene expression are identified, requiring the application of appropriate statistical methods. To derive meaningful biological insights, results must be carefully interpreted within the context of the research question."
          ),
          htmltools::br(),
          htmltools::h6(
            "Starting with raw count data, this process applies rigorous filtering methods, normalizes the dataset, and employs statistical models to estimate differential gene expression accurately. It also generates key visualizations, including Biological Coefficient of Variation (BCV) and Quasi-Likelihood (QL) dispersion plots. The final results are systematically saved in CSV format based on the specified contrasts."
          ),
          htmltools::br(),
          htmltools::br(),
          htmltools::h6("The input data includes:"),
          htmltools::br(),
          htmltools::h6("-	count matrices: results from the summarization step, with filenames (excluding extensions) serving as sample names."),
          htmltools::h6("- metadata table: A CSV or TAB file assigning samples to groups, structured in two columns:"),
          htmltools::br(),
          htmltools::h6("Example:"),
          htmltools::h6("Samples,Groups"),
          htmltools::h6("A1,A"),
          htmltools::h6("A2,A"),
          htmltools::h6("A3,A"),
          htmltools::h6("B1,B"),
          htmltools::h6("B2,B"),
          htmltools::h6("B3,B"),
          htmltools::h6("C1,C"),
          htmltools::h6("C2,C"),
          htmltools::h6("C3,C"),
          htmltools::br(),
          htmltools::h6("Users can generate this table interactively using the 'Generate the Matrix' button."),
          htmltools::br(),
          htmltools::br(),
          htmltools::h6(htmltools::strong("OPERATIONAL INSTRUCTIONS")),
          htmltools::br(),
          htmltools::h6(htmltools::strong("Step 1 - Import count matrices")),
          htmltools::h6("-	Select the folder containing count matrix files in .tab format (e.g., <sampleName>.tab)."),
          htmltools::br(),
          htmltools::h6(htmltools::strong("Step 2 - Group assignment")),
          htmltools::h6("- Choose the metadata file in CSV or TAB format, or generate it interactively."),
          htmltools::br(),
          htmltools::h6(htmltools::strong("Step 3 - Defining contrasts")),
          htmltools::h6("- Specify the contrast of interest. A 'Test' vs. 'Baseline' comparison means genes with a positive log-fold change are up-regulated in the 'Test' group relative to the 'Baseline' group, while those with a negative log-fold change are down-regulated."),
          htmltools::br(),
          htmltools::h6(htmltools::strong("Step 4 - Identifying DEGs")),
          htmltools::h6("- Perform DEG calling by selecting:"),
          htmltools::h6("filtering methods (e.g., filterByExpr or HTSFilter)"),
          htmltools::h6("normalization techniques;"),
          htmltools::h6("test models (e.g., Negative Binomial (NB) dispersion, Quasi-Likelihood (QL), or likelihood ratio methods)."),
          htmltools::br(),
          htmltools::br(),
          htmltools::h6(htmltools::strong("RESULT")),
          htmltools::br(),
          htmltools::h6("For each contrast, differential expression results are saved in CSV format as <Filter_mode>_<Model_test>_<Baseline>vs<Test>.csv. Genes are classified as UP, DOWN, or NO based on log fold-change (Th_logFC) and adjusted p-values (Th_Pvalue)."),
          htmltools::br(),
          htmltools::h6("The generated CSV file contains the following columns:"),
          htmltools::h6("- ID: identifier of the functional unit;"),
          htmltools::h6("- logFC: log2-fold change of expression between conditions;"),
          htmltools::h6("- logCPM: average log2-counts per million across all libraries;"),
          htmltools::h6("- LR or F: likelihood ratio test statistic (for glmLRT) or quasi-likelihood F-statistic (for glmQLFTest);"),
          htmltools::h6("- PValue: statistical measure for hypothesis validation;"),
          htmltools::h6("- FDR or FWER: False discovery rate or family-wise error rate (if adjustPvalue is selected);"),
          htmltools::h6("- diffExp: differential expression label (UP, DOWN, NO)"),
          htmltools::br(),
          htmltools::br(),
          htmltools::h6(htmltools::strong("ADDITIONALLY NOTES")),
          htmltools::br(),
          htmltools::h6("Optionally, users can merge the DEGs tables by incorporating the information from the 'GTF' file in addition to generate additional plots, such as the Volcano plot and UpSet plot."),
          htmltools::br()
        ),
        htmltools::br(),

        # Section to view count matrices imported
          bslib::accordion_panel(
            title = "Step 1 Result - Import count matrices",
            bslib::tooltip(
              bsicons::bs_icon("question-circle"),
              "Here, we present the count matrices for each sample. Ensure that the first column lists the gene names and the second column contains the corresponding count values. You can select the relevant columns and remove any rows without count values using the control window on the right. The default settings assume the files are in the format generated by the inDAGO summarization process.",
              placement = "right"
            ),
            # Card to display the count matrix and sidebar controls for adjusting the view
             bslib::card(
              full_screen = TRUE,
               bslib::layout_sidebar(
                sidebar = bslib::sidebar(
                  title = "Local controls",
                  position = "right",

                  # Sidebar control to set the number of lines to skip in the matrix
                  shiny::fluidRow(shiny::column(12, align = "center", htmltools::h5("Check the matrices"), htmltools::br())),

                  # Numeric input for skipping rows in the matrix
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::numericInput(shiny::NS(id, "skip_preN"),
                        label = "Number of lines to skip",
                        min = 0,
                        value = 0
                      ),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Remove any rows that lack count values, such as those containing statistical summaries or total quantification results.",
                        placement = "right"
                      )
                    )
                  )),

                  # Numeric input to specify the column containing gene IDs
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::numericInput(shiny::NS(id, "colIDgene"),
                        label = "Column of genes",
                        min = 1,
                        value = 1
                      ),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Select the column containing the gene names",
                        placement = "right"
                      )
                    )
                  )),
                  # Numeric input to specify the column containing counts
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::numericInput(shiny::NS(id,  "colCounts"),
                        label = "Count column",
                        min = 1,
                        value = 2
                      ),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Select the column containing the count values for each gene.",
                        placement = "right"
                      )
                    )
                  )),
                  # Select which sample matrix to view
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::selectizeInput(shiny::NS(id, "selectpn"),
                                     label = "Number of imported matrices: 0",
                                     choices = ""),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Select a sample to view.",
                        placement = "right"
                      )
                    )
                  )),
                  # Display either the full matrix or just the first few rows
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::radioButtons(shiny::NS(id,  "disp"),
                        label = "Display",
                        choices = c("Head" = "head", "All" = "all"),
                        selected = "head"
                      ),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Choose whether to display all rows or just the first 20.",
                        placement = "right"
                      )
                    )
                  ))


                ),
                # print message if table is not loaded
                shinycssloaders::withSpinner(shiny::tableOutput(shiny::NS(id, "ShowTable")))

              )
            )
          ),

        # Section to view the matrix to assign group to each samples
          # Conditional panel if input.Import_table_exp == 'Loading'
          shiny::conditionalPanel(
            condition = sprintf("input['%s'] == 'Loading'", shiny::NS(id, "Import_table_exp")),
            bslib::accordion_panel(
              title = "Step 2 Result - Load the Matrix",
              bslib::tooltip(
                bsicons::bs_icon("question-circle"),
                "Here, we present the loaded matrix containing metadata, including 'Samples' and 'Groups'.",
                placement = "right"
              ),

              shinycssloaders::withSpinner(shiny::tableOutput(shiny::NS(id, "ImportedTable")))
            )
          ),


          # Conditional panel if input.Import_table_exp == 'Create'
          shiny::conditionalPanel(
            condition = sprintf("input['%s'] == 'Create'", shiny::NS(id, "Import_table_exp")),
            bslib::accordion_panel(
              title = "Step 2 Result - Generate the Matrix",
              bslib::tooltip(
                bsicons::bs_icon("question-circle"),
                "Here, you can create the matrix containing metadata ('Samples' and 'Groups') interactively. Be sure to save it once you've made your selections!",
                placement = "right"
              ),
              # Card containing the controls and layout for creating the matrix
               bslib::card(
                full_screen = TRUE,
                 bslib::layout_sidebar(
                  sidebar = bslib::sidebar(
                    title = "Local controls",
                    position = "right",

                    # Display a reminder to save the created matrix
                    shiny::fluidRow(shiny::column(
                      12, align = "center", htmltools::h5("Remember to save it!"), htmltools::br()
                    )),
                    # Button to save the matrix, with a tooltip explaining its function
                    shiny::fluidRow(shiny::column(
                      width = 12, shiny::splitLayout(
                        cellWidths = c("90%", "10%"),
                        shiny::actionButton(shiny::NS(id,  "save_group"),
                          label =
                            "Save_matrix",
                          shiny::icon("table"),
                          class = "btn-primary"
                        ),
                        bslib::tooltip(
                          bsicons::bs_icon("question-circle"),
                          "Save the assigned groups",
                          placement = "right"
                        )
                      )
                    ))
                  ),

                  # Conditional panel that displays interactive group assignment options if the group assignment option is selected
                  shiny::conditionalPanel(
                    condition = sprintf("input['%s'] == true", shiny::NS(id, "assign_group")), # Tabset panel with two tabs for group assignment and saved groups
                                   shiny::tabsetPanel(
                                     shiny::tabPanel(
                                       "Interactive group assignment",
                                       DT::DTOutput(shiny::NS(id, "grouping"))
                                     ),


                                     shiny::tabPanel("Groups saved", shiny::tableOutput(shiny::NS(id, "groups_assigned")))


                                   )),
                  #Show message
                  shiny::tableOutput(shiny::NS(id, "groupingMessage"))
                )
              )

            )
          ),

        # SetContrast: This section handles the contrast setup for differentially expressed gene analysis.
          bslib::accordion_panel(
            title = "Step 3 Result - Defining contrasts",
            bslib::tooltip(
              bsicons::bs_icon("question-circle"),
              "This tab allows you to select which groups to compare in order to identify differentially expressed genes. 'Test' versus 'Baseline' indicates that genes with a positive log-fold change are up-regulated in the 'Test' group compared to the 'Baseline' group (and vice versa for genes with a negative log-fold change).",
              placement = "right"
            ),
             bslib::card(
              full_screen = TRUE,
              # Conditional display for setting contrast options
              shiny::conditionalPanel(
                condition = paste0("output['", shiny::NS(id,"ShowpanelContrast"), "'] == 'Running'"),
                 bslib::layout_sidebar(
                sidebar = bslib::sidebar(
                  title = "Local controls",
                  position = "right",

                  shiny::fluidRow(shiny::column(
                    12, align = "center", htmltools::h5("Be sure to save the contrasts before proceeding!"), htmltools::br()
                  )),
                  # Add row action button
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::actionButton(shiny::NS(id, "add_row_contrast"), "Add row", class = "btn-primary")
                      ,
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Choose whether to add a new contrast.",
                        placement = "right"
                      )
                    )
                  )),
                  # Remove last row action button
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::actionButton(shiny::NS(id, "remove_last_row_contrast"), "Delete the last row", class = "btn-primary")
                      ,
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Choose whether to remove the last contrast.",
                        placement = "right"
                      )
                    )
                  )),
                  # Save data action button
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::actionButton(shiny::NS(id, "save_data_contrast"), "Save the contrasts", class = "btn-primary")
                      ,
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Save the chosen contrasts to proceed to the next step.",
                        placement = "right"
                      )
                    )
                  ))

                ),
                # Dynamic interface displaying the contrast results and saved data
                shiny::fluidRow(shiny::column(
                  width = 12,
                  shiny::splitLayout(
                    cellWidths = c("50%", "50%"),
                    shiny::uiOutput(shiny::NS(id, "Resultcontrast")),
                    # dinamic interface
                    DT::DTOutput(shiny::NS(id, "saved_data_table"))
                  )
                ))

              )),
              # Output when previous steps are not yet completed
              shinycssloaders::withSpinner(shiny::tableOutput(shiny::NS(id, "ContrastMessage")))


            )


          ),

        # Set DEGs Result: This section shows the progress of differential expression analysis.
          bslib::accordion_panel(
            title = "Step 4 Result - Identifying DEGs",
            bslib::tooltip(
              bsicons::bs_icon("question-circle"),
              "This section displays the progress of the analysis related to the identification of differentially expressed genes.",
              placement = "right"
            ),
             bslib::card(
              full_screen = TRUE,

              # Conditional panel for running DEGs analysis
              shiny::conditionalPanel(
                condition = paste0("output['", shiny::NS(id,"ShowpanelDEGs"), "'] == 'Running'"),

                  shiny::verbatimTextOutput(shiny::NS(id, "RunDEGsoutput")),
                  htmltools::br(),
                  # Plotting BCV (Biological Coefficient of Variation)
                  shiny::fluidRow(shiny::column(12, align = "center", htmltools::h5("plotBCV"))),

                  shiny::fluidRow(shiny::column(
                    width = 12,
                    shiny::splitLayout(
                      cellWidths = c("90%", "10%"),


                      shinycssloaders::withSpinner(shiny::plotOutput(shiny::NS(id, "plotBCV")))
                      ,
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Plot the gene-wise biological coefficient of variation (BCV) against gene abundance expressed in log2 counts per million. BCV is calculated as the standard deviation of gene expression across replicates divided by the mean expression level. It reflects the degree of variability in gene expression due to biological differences rather than technical noise. A low BCV indicates that a gene has relatively consistent expression across samples, while a high BCV suggests greater variability in gene expression across replicates.
Black dots represent the tagwise (gene-specific) dispersions for individual genes. The blue line displays the fitted mean-dispersion trend (common dispersion as a function of expression). If many genes show BCVs far from the trend, it may indicate potential issues with the data, such as batch effects or poor normalization.",
                        placement = "right"
                      )
                    )
                  )),
                  # Plotting QL Dispersion
                  shiny::fluidRow(shiny::column(12, align = "center", htmltools::h5("plotQLDisp"))),
                  shiny::fluidRow(shiny::column(
                    width = 12,
                    shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shinycssloaders::withSpinner(shiny::plotOutput(shiny::NS(id, "plotQLDisp")))
                      ,
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Plot the gene-wise quasi-likelihood (QL) dispersion against gene abundance expressed in log2 counts per million. Genes with low mean expression (on the left side of the plot) are typically more variable (higher dispersion) because low-count genes are more susceptible to random fluctuations in RNA-seq data. In contrast, genes with high mean expression (on the right side of the plot) tend to have more stable expression (lower dispersion), as their higher expression levels are less affected by noise.
The dispersion values on the y-axis represent the degree of variation in expression across the replicates. Genes with higher dispersion values show greater variability in expression, while those with lower dispersion values exhibit more consistent expression. High-dispersion genes are often those that may show differential expression across conditions. The red line represents the trend of QL dispersions (mean-QL trend), and the black dots indicate the QL dispersions for individual genes.
By visualizing the QL dispersion estimates, you can gain insight into the variability captured in the data and assess the quality of the model fit, ensuring the robustness of downstream differential expression analysis. A well-fitting model will show the individual QL dispersions (dots) clustering reasonably around the trend line.",
                        placement = "right"
                      )
                    )
                  ))

              ),
              # Output when previous steps are not yet completed
              shinycssloaders::withSpinner(shiny::tableOutput(shiny::NS(id, "DEGsMessage")))

            )
          ),
        # Merged DEGs Table: This section displays the results of merging all DEGs matrices.
        shiny::conditionalPanel(
          condition = sprintf("input['%s']  == true", shiny::NS(id, "RunMergeDegs")),

          bslib::accordion_panel(
            title = "Merge DEG",
            bslib::tooltip(
              bsicons::bs_icon("question-circle"),
              "Here, we present the result of merging all DEG matrices.",
              placement = "right"
            ),
             bslib::card(
              full_screen = TRUE,

              shinycssloaders::withSpinner(DT::DTOutput(shiny::NS(id, "Merged_DEGs_out")))
            )

          )


        ),


        # plot

        shiny::conditionalPanel(
          condition = sprintf("input['%s']  == true", shiny::NS(id, "RunVolcano")), # Accordion panel with Volcano-related settings
                         bslib::accordion_panel(
                           title = "Volcano plot",
                           bslib::tooltip(
                             bsicons::bs_icon("question-circle"),
                             "A volcano plot is used to visualize two key metrics: statistical significance (p-value) on the y-axis and the magnitude of change (fold change) on the x-axis. It enables the quick identification of genes that exhibit both large fold changes and statistical significance, which are often the most biologically relevant. In a volcano plot, genes with the highest upregulation appear on the right, the most downregulated genes on the left, and the most statistically significant genes are located at the top.",
                             placement = "right"
                           ),
                            bslib::card(
                             full_screen = TRUE,
                              bslib::layout_sidebar(
                               sidebar = bslib::sidebar(
                                 width = "30%",
                                 title = "Local controls",
                                 position = "right",



                                 shiny::fluidRow(shiny::column(
                                   width = 12, shiny::splitLayout(
                                     cellWidths = c("90%", "10%"),
                                     shinyWidgets::switchInput(shiny::NS(id, "Volcano_interactively"),
                                       label = "Interactive",
                                       labelWidth = "120px",
                                       onStatus = "primary",
                                       offStatus = "default"
                                     ),
                                     bslib::tooltip(
                                       bsicons::bs_icon("question-circle"),
                                       "Generate interactive plot",
                                       placement = "right"
                                     )
                                   )
                                 )),




                                 # Accordion panel for Plot Settings
                                 bslib::accordion_panel(
                                   "Plot settings",



                                   # selectizeInput for selecting desired color palette
                                   shiny::fluidRow(shiny::column(
                                     width = 12, shiny::splitLayout(
                                       cellWidths = c("90%", "10%"),

                                       shiny::selectizeInput(shiny::NS(id, "VolcanoPalettePoint"),
                                         label = "Preferred color scheme",
                                         choices = paste(
                                           dplyr::filter(paletteer::palettes_d_names, length == 3, type == "qualitative")$package,
                                           dplyr::filter(paletteer::palettes_d_names, length == 3, type == "qualitative")$palette,
                                           sep = "::"
                                         )
                                       ),
                                       bslib::tooltip(
                                         bsicons::bs_icon("question-circle"),
                                         "Select the color palette you prefer to use. If you are using the app in a browser, you can visit the following link to explore available palettes: https://pmassicotte.github.io/paletteer_gallery/" ,
                                         htmltools::tags$a("The paletteer gallery", href = "https://pmassicotte.github.io/paletteer_gallery/", target = "_blank"),
                                         placement = "right"
                                       )
                                     )
                                   )),
                                   # selectInput for setting maximum overlaps
                                   shiny::fluidRow(shiny::column(
                                     width = 12, shiny::splitLayout(
                                       cellWidths = c("90%", "10%"),
                                       shiny::selectInput(shiny::NS(id, "VolcanoMaxOverlaps"),
                                         label = "maxOverlaps",
                                         choices = c(1:20),
                                         selected = 5
                                       ),
                                       bslib::tooltip(
                                         bsicons::bs_icon("question-circle"),
                                         "Adjust the maximum overlap threshold to exclude labels that overlap with too many other elements. '5' by default",
                                         placement = "right"
                                       )
                                     )
                                   )),
                                   # selectInput for adjusting label size
                                   shiny::fluidRow(shiny::column(
                                     width = 12, shiny::splitLayout(
                                       cellWidths = c("90%", "10%"),
                                       shiny::selectInput(shiny::NS(id, "VolcanoSizeLabel"),
                                         label = "sizeLabel",
                                         choices = c(1:20),
                                         selected = 2),
                                       bslib::tooltip(
                                         bsicons::bs_icon("question-circle"),
                                         "Adjust the label size. '2' by default",
                                         placement = "right"
                                       )
                                     )
                                   )),
                                   # Numeric input for threshold logFC
                                   shiny::fluidRow(shiny::column(
                                     width = 12, shiny::splitLayout(
                                       cellWidths = c("90%", "10%"),
                                       shiny::numericInput(shiny::NS(id, "VolcanoTh_logFC"),
                                         label = "Th_logFC",
                                         min = 0,
                                         step = 0.001,
                                         value = 0.58
                                       ),
                                       bslib::tooltip(
                                         bsicons::bs_icon("question-circle"),
                                         "Set the threshold of 'logFC' value used to label the genes as 'UP' or 'DOWN'. '0.58' by default",
                                         placement = "right"
                                       )
                                     )
                                   )),
                                   # Numeric input for threshold p-value
                                   shiny::fluidRow(shiny::column(
                                     width = 12, shiny::splitLayout(
                                       cellWidths = c("90%", "10%"),
                                       shiny::numericInput(shiny::NS(id, "VolcanoTh_Pvalue"),
                                         label = "Th_Pvalue",
                                         min = 0,
                                         max = 1,
                                         step = 0.001,
                                         value = 0.05
                                       ),
                                       bslib::tooltip(
                                         bsicons::bs_icon("question-circle"),
                                         "Set the threshold of p-value used to label the genes as 'UP' or 'DOWN'. '0.05' by default",
                                         placement = "right"
                                       )
                                     )
                                   )),
                                   # selectInput for selecting subset of genes
                                   shiny::fluidRow(shiny::column(
                                     width = 12, shiny::splitLayout(
                                       cellWidths = c("90%", "10%"),
                                       shiny::selectInput(shiny::NS(id, "VolcanoSubsetGenes"),
                                         label = "subsetGenes",
                                         choices = c(seq(
                                           from = 1000, to = 100000, by = 1000
                                         ), Inf),
                                         selected  = 1000
                                       ),
                                       bslib::tooltip(
                                         bsicons::bs_icon("question-circle"),
                                         "Select the number of genes (ranked by 'adjustPvalue' or 'PValue' parameters) used to generate the plot. '1000' by default ",
                                         placement = "right"
                                       )
                                     )
                                   )),
                                   # Radio buttons for significance type (PValue or adjusted p-value)
                                   shiny::fluidRow(shiny::column(
                                     width = 12, shiny::splitLayout(
                                       cellWidths = c("90%", "10%"),
                                       shiny::radioButtons(shiny::NS(id, "Volcano_st_significance"),
                                         label = "st_significance",
                                         choices = c("PValue", "adjustPvalue"),
                                         selected  = "PValue"
                                       ),
                                       bslib::tooltip(
                                         bsicons::bs_icon("question-circle"),
                                         "Set if significance should be based on 'PValue' or 'adjustPvalue' (e.g., FDR or FWER). If 'PValue' is selected, the 'PValue' column should be present in the table. If 'adjustPvalue' is selected, the 'FDR' or 'FWER' columns should be included. 'PValue' by default",
                                         placement = "right"
                                       )
                                     )
                                   )),


                                   # Button to refresh the plot
                                   shiny::fluidRow(shiny::column(
                                     width = 12, shiny::splitLayout(
                                       cellWidths = c("90%", "10%"),
                                       shiny::actionButton(shiny::NS(id, "RefreshRunVolcano"),
                                         label =  "Refresh",
                                         shiny::icon("refresh"),
                                         class = "btn-primary"
                                       ),
                                       bslib::tooltip(
                                         bsicons::bs_icon("question-circle"),
                                         "Refresh the plot to apply and view the changes",
                                         placement = "right"
                                       )
                                     )
                                   ))

                                 ),

                                 # Accordion panel for download settings
                                 bslib::accordion_panel(
                                   "Download settings",
                                   # radioButtons for selecting plot export format
                                   shiny::fluidRow(shiny::column(
                                     width = 12, shiny::splitLayout(
                                       cellWidths = c("90%", "10%"),
                                       shiny::radioButtons(shiny::NS(id, "Volcanoformat"),
                                         label = "Desired format",
                                         choices = c("jpeg", "png", "tiff", "eps", "svg", "pdf"),
                                         selected = "jpeg"
                                       ),
                                       bslib::tooltip(
                                         bsicons::bs_icon("question-circle"),
                                         "Select the format to save the plot. 'jpeg' by default",
                                         placement = "right"
                                       )
                                     )
                                   )),
                                   # radioButtons for selecting plot units (in, cm, mm, px)
                                   shiny::fluidRow(shiny::column(
                                     width = 12, shiny::splitLayout(
                                       cellWidths = c("90%", "10%"),
                                       shiny::radioButtons(shiny::NS(id, "unitsVolcano"),
                                         label = "units",
                                         choices = c("in", "cm", "mm", "px"),
                                         selected = "cm"
                                       ),
                                       bslib::tooltip(
                                         bsicons::bs_icon("question-circle"),
                                         "Choose the unit for defining the dimensions ('width' and 'height). 'cm' by default",
                                         placement = "right"
                                       )
                                     )
                                   )),
                                   # Numeric input for resolution of the plot
                                   shiny::fluidRow(shiny::column(
                                     width = 12, shiny::splitLayout(
                                       cellWidths = c("90%", "10%"),
                                       shiny::numericInput(shiny::NS(id, "resVolcano"),
                                         label = "resolution",
                                         step = 1,
                                         min = 1,
                                         value = 200
                                       ),
                                       bslib::tooltip(
                                         bsicons::bs_icon("question-circle"),
                                         "Select the resolution (applies only to raster output types). '200' by default",
                                         placement = "right"
                                       )
                                     )
                                   )),
                                   # Numeric input for setting width of the plot
                                   shiny::fluidRow(shiny::column(
                                     width = 12, shiny::splitLayout(
                                       cellWidths = c("90%", "10%"),
                                       shiny::numericInput(shiny::NS(id, "widthVolcano"),
                                         label = "width",
                                         step = 1,
                                         min = 1,
                                         value = 10
                                       ),
                                       bslib::tooltip(
                                         bsicons::bs_icon("question-circle"),
                                         "Select the plot width. '10' by default",
                                         placement = "right"
                                       )
                                     )
                                   )),
                                   # Numeric input for setting height of the plot
                                   shiny::fluidRow(shiny::column(
                                     width = 12, shiny::splitLayout(
                                       cellWidths = c("90%", "10%"),
                                       shiny::numericInput(shiny::NS(id, "heightVolcano"),
                                         label = "height",
                                         step = 1,
                                         min = 1,
                                         value = 10
                                       ),
                                       bslib::tooltip(
                                         bsicons::bs_icon("question-circle"),
                                         "Select the plot height. '10' by default",
                                         placement = "right"
                                       )
                                     )
                                   )),

                                   # Button to trigger download of the plot
                                   shiny::fluidRow(shiny::column(
                                     width = 12, shiny::splitLayout(
                                       cellWidths = c("90%", "10%"),
                                       shiny::downloadButton(shiny::NS(id, "VolcanoLink"), label = "Download plot"),
                                       bslib::tooltip(bsicons::bs_icon("question-circle"), "Download the plot", placement = "right")
                                     )
                                   ))



                                 )
                               ),
                               # Conditional panel for interactive/non-interactive plot
                               shiny::conditionalPanel(
                                 condition = sprintf("input['%s']  == '0'", shiny::NS(id, "Volcano_interactively")),
                                                shinycssloaders::withSpinner(shiny::plotOutput(shiny::NS(id, "VolcanoPlot")))),
                               shiny::conditionalPanel(
                                 condition = sprintf("input['%s']  == '1'", shiny::NS(id, "Volcano_interactively")),
                                                shinycssloaders::withSpinner(plotly::plotlyOutput(shiny::NS(id, "VolcanoPlottly"))))
                             )
                           )
                         )),

        # Accordion panel for UpSet plot settings
        shiny::conditionalPanel(
          condition = sprintf("input['%s']  == true", shiny::NS(id, "RunUpSet")),
                         bslib::accordion_panel(
          title = "UpSet plot",
          bslib::tooltip(
            bsicons::bs_icon("question-circle"),
            "The UpSet plot is especially useful in RNA-seq studies for analyzing and comparing gene expression patterns across multiple conditions or time points. The horizontal bars show the number of genes in each individual set, while the vertical bars represent the overlap between sets, highlighting shared genes.",
            placement = "right"
          ),
           bslib::card(
            full_screen = TRUE,
             bslib::layout_sidebar(
              sidebar = bslib::sidebar(
                width = "30%",
                title = "Local controls",
                position = "right",



                shiny::fluidRow(shiny::column(
                  width = 12, shiny::splitLayout(
                    cellWidths = c("90%", "10%"),
                    shinyWidgets::switchInput(shiny::NS(id, "UpSet_interactively"),
                      label = "Interactive",
                      labelWidth = "120px",
                      onStatus = "primary",
                      offStatus = "default"
                    ),
                    bslib::tooltip(
                      bsicons::bs_icon("question-circle"),
                      "Generate interactive plot",
                      placement = "right"
                    )
                  )
                )),

                # Accordion panel for plot settings
                bslib::accordion_panel(
                  "Plot settings",

                  # Numeric input for threshold logFC (fold-change)
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::numericInput(shiny::NS(id, "UpSetTh_logFC"),
                        label = "Th_logFC",
                        min = 0,
                        step = 0.001,
                        value = 0.58
                      ),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Filter the data frame to include only genes that meet the logFC threshold. '0.58' by default",
                        placement = "right"
                      )
                    )
                  )),
                  # Numeric input for threshold p-value
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::numericInput(shiny::NS(id, "UpSetTh_Pvalue"),
                        label = "Th_Pvalue",
                        min = 0,
                        max = 1,
                        step = 0.001,
                        value = 0.05
                      ),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Filter the data frame for genes that meet the 'adjustPvalue' or 'PValue' thresholds, based on the 'st_significance' parameter. '0.05' by default",
                        placement = "right"
                      )
                    )
                  )),
                  # Numeric input for number of intersections to display
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::numericInput(shiny::NS(id, "UpSet_nintersects"),
                        label = "nintersects",
                        min = 2,
                        step = 1,
                        value = 20
                      ),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Set the limit of the intersection number displayed. '20' by deafult",
                        placement = "right"
                      )
                    )
                  )),

                  # Numeric input for label size
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::numericInput(shiny::NS(id, "UpSet_scale"),
                        label = "LabelSize",
                        min = 0,
                        step = 0.5,
                        value = 1
                      ),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Adjust the size of the labels and annotations.",
                        placement = "right"
                      )
                    )
                  )),
                  # Radio buttons for significance type (PValue or adjusted p-value)
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::radioButtons(shiny::NS(id, "UpSet_st_significance"),
                        label =
                          "st_significance",
                        choices = c("PValue", "adjustPvalue"),
                        selected = "PValue"
                      ),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Set if significance should be based on 'PValue' or 'adjustPvalue' (e.g., FDR or FWER). If 'PValue' is selected, the 'PValue' column should be present in the table. If 'adjustPvalue' is selected, the 'FDR' or 'FWER' columns should be included. 'PValue' by default",
                        placement = "right"
                      )
                    )
                  )),
                  # Radio buttons for collapsing group names
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::radioButtons(shiny::NS(id, "UpSet_collapseName"),
                        label =
                          "collapseName",
                        choices = c("TRUE", "FALSE"),
                        selected = "TRUE"
                      ),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Select whether to collapse the names of each file by removing the prefixes <filterByExpr_|HTSFilter_|exactTest_|glmQLFTest_|glmLRT_>. 'TRUE' by default",
                        placement = "right"
                      )
                    )
                  )),
                  # Button to refresh the plot
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::actionButton(shiny::NS(id, "RefreshRunUpSet"),
                        label =  "Refresh",
                        shiny::icon("refresh"),
                        class = "btn-primary"
                      ),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Refresh the plot to apply and view the changes",
                        placement = "right"
                      )
                    )
                  ))
                ),
                # Accordion panel for download settings
                bslib::accordion_panel(
                  "Download settings",
                  # Radio buttons for selecting the download format
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::radioButtons(shiny::NS(id, "UpSetformat"),
                        label =
                          "Desired format",
                        choices = c("jpeg", "png", "tiff", "eps", "svg", "pdf"),
                        selected = "jpeg"
                      ),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Select the format to save the plot. 'jpeg' by default",
                        placement = "right"
                      )
                    )
                  )),
                  # Radio buttons for selecting the units (inches, cm, mm, pixels)
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::radioButtons(shiny::NS(id, "unitsUpSet"),
                        label = "units",
                        choices = c("in", "cm", "mm", "px"),
                        selected = "cm"
                      ),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Choose the unit for defining the dimensions ('width' and 'height). 'cm' by default",
                        placement = "right"
                      )
                    )
                  )),
                  # Numeric input for setting resolution
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::numericInput(shiny::NS(id, "resUpSet"),
                        label = "resolution",
                        step = 1,
                        min = 1,
                        value = 200
                      ),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Select the resolution (applies only to raster output types). '200' by default",
                        placement = "right"
                      )
                    )
                  )),
                  # Numeric input for setting width of the plot
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::numericInput(shiny::NS(id, "widthUpSet"),
                        label = "width",
                        step = 1,
                        min = 1,
                        value = 10
                      ),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Select the plot width. '10' by default",
                        placement = "right"
                      )
                    )
                  )),
                  # Numeric input for setting height of the plot
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::numericInput(shiny::NS(id, "heightUpSet"),
                        label = "height",
                        step = 1,
                        min = 1,
                        value = 10
                      ),
                      bslib::tooltip(
                        bsicons::bs_icon("question-circle"),
                        "Select the plot height. '10' by default",
                        placement = "right"
                      )
                    )
                  )),
                  # Button to download the UpSet plot
                  shiny::fluidRow(shiny::column(
                    width = 12, shiny::splitLayout(
                      cellWidths = c("90%", "10%"),
                      shiny::downloadButton(shiny::NS(id, "UpSetLink"),
                                     label = "Download UpSet"),
                      bslib::tooltip(bsicons::bs_icon("question-circle"),
                              "Download the plot", placement = "right")
                    )
                  ))
                )
              ),

              # Conditional panel for non-interactive plot display
              shiny::conditionalPanel(
                condition = sprintf("input['%s']  == '0'", shiny::NS(id, "UpSet_interactively")),
                               shinycssloaders::withSpinner(shiny::plotOutput(shiny::NS(id, "UpSetPlot")))),
              # Conditional panel for interactive plot display
              shiny::conditionalPanel(
                condition = sprintf("input['%s']  == '1'", shiny::NS(id, "UpSet_interactively")),
                               shinycssloaders::withSpinner(upsetjs::upsetjsOutput(shiny::NS(id, "UpSetjsPlot"))))
            )
          )
        ))
      )
    ) # end of main
} # End of Ui

Try the inDAGO package in your browser

Any scripts or data that you put into this service are public.

inDAGO documentation built on Aug. 8, 2025, 7:47 p.m.