R/GeneTonic.R

Defines functions GeneTonic

Documented in GeneTonic

#' GeneTonic
#'
#' GeneTonic, main function for the Shiny app
#'
#' @param dds A `DESeqDataSet` object, normally obtained after running your data
#' through the `DESeq2` framework.
#' @param res_de A `DESeqResults` object. As for the `dds` parameter, this is
#' also commonly used in the `DESeq2` framework.
#' @param res_enrich A `data.frame` object, storing the result of the functional
#' enrichment analysis. Required columns for enjoying the full functionality of
#' [GeneTonic()] include:
#' - a gene set identifier (e.g. GeneOntology id, `gs_id`) and its term description
#' (`gs_description`)
#' - a numeric value for the significance of the enrichment (`gs_pvalue`)
#' - a column named `gs_genes` containing a comma separated vector of the gene names
#' associated to the term, one for each term
#' - the number of genes in the geneset of interest detected as differentially
#' expressed (`gs_de_count`), or in the background set of genes (`gs_bg_count`)
#' See [shake_topGOtableResult()] or [shake_enrichResult()] for examples of such
#' formatting helpers
#' @param annotation_obj A `data.frame` object, containing two columns, `gene_id`
#' with a set of unambiguous identifiers (e.g. ENSEMBL ids) and `gene_name`,
#' containing e.g. HGNC-based gene symbols. This object can be constructed via
#' the `org.eg.XX.db` packages, e.g. with convenience functions such as
#' [pcaExplorer::get_annotation_orgdb()].
#' @param project_id  A character string, which can be considered as an identifier
#' for the set/session, and will be e.g. used in the title of the report created
#' via [happy_hour()]
#'
#' @return A Shiny app object is returned, for interactive data exploration
#' @export
#'
#' @author Federico Marini
#'
#' @examples
#' library("macrophage")
#' library("DESeq2")
#' library("org.Hs.eg.db")
#' library("AnnotationDbi")
#'
#' # dds object
#' data("gse", package = "macrophage")
#' dds_macrophage <- DESeqDataSet(gse, design = ~line + condition)
#' rownames(dds_macrophage) <- substr(rownames(dds_macrophage), 1, 15)
#' dds_macrophage <- estimateSizeFactors(dds_macrophage)
#'
#' # annotation object
#' anno_df <- data.frame(
#'   gene_id = rownames(dds_macrophage),
#'   gene_name = mapIds(org.Hs.eg.db,
#'                      keys = rownames(dds_macrophage),
#'                      column = "SYMBOL",
#'                      keytype = "ENSEMBL"),
#'   stringsAsFactors = FALSE,
#'   row.names = rownames(dds_macrophage)
#' )
#'
#' # res object
#' data(res_de_macrophage, package = "GeneTonic")
#' res_de <- res_macrophage_IFNg_vs_naive
#'
#' # res_enrich object
#' data(res_enrich_macrophage, package = "GeneTonic")
#' res_enrich <- shake_topGOtableResult(topgoDE_macrophage_IFNg_vs_naive)
#' res_enrich <- get_aggrscores(res_enrich, res_de, anno_df)
#'
#' # now everything is in place to launch the app
#' if (interactive())
#'   GeneTonic(dds = dds_macrophage,
#'             res_de = res_de,
#'             res_enrich = res_enrich,
#'             annotation_obj = anno_df,
#'             project_id = "myexample")
#'
GeneTonic <- function(dds,
                      res_de,
                      res_enrich,
                      annotation_obj,
                      project_id = "") {
  
  # https://projects.lukehaas.me/css-loaders/
  # or even think of https://cran.r-project.org/web/packages/shinycustomloader/README.html
  oopt <- options(spinner.type = 6, spinner.color = .biocgreen)
  # play nice with other previously chosen options
  on.exit(options(oopt))
  
  usage_mode <- "shiny_mode"
  
  
  # checks on the objects provided
  checkup_GeneTonic(dds,
                    res_de,
                    res_enrich,
                    annotation_obj)
  
  # clean up the result object, e.g. removing the NAs in the relevant columns
  res_de <- res_de[!is.na(res_de$log2FoldChange), ]
  message("Removing ", sum(is.na(res_de$log2FoldChange)), " rows from the result object - logFC detected as NA")
  
  
  # UI definition -----------------------------------------------------------
  
  # dashpage definition -----------------------------------------------------
  genetonic_ui <- bs4Dash::bs4DashPage(
    # enable_preloader = TRUE,
    title = "GeneTonic",
    sidebar_collapsed = TRUE,
    controlbar_collapsed = TRUE,
    
    # navbar definition -------------------------------------------------------
    navbar = bs4Dash::bs4DashNavbar(
      skin = "dark",
      controlbarIcon = "gears",
      fixed = TRUE,
      leftUi = tagList(
        tags$code(tags$h3("GeneTonic")),
        actionButton("bookmarker", label = "Bookmark", icon = icon("heart"),
                     style = "color: #ffffff; background-color: #ac0000; border-color: #ffffff", class = "ml-5")
      ),
      rightUi = tagList(
        shinyWidgets::dropdownButton(
          inputId = "ddbtn_docs",
          circle = FALSE,
          status = "info",
          icon = icon("book"),
          width = "300px",
          size = "xs",
          right = TRUE,
          tooltip = shinyWidgets::tooltipOptions(title = "More documentation"),
          tags$h5("Documentation"),
          actionButton(
            inputId = "btn_docs_vignette",
            icon = icon("book-open"),
            label = "Open GeneTonic Vignette", style = .actionbutton_biocstyle,
            onclick = ifelse(system.file("doc", "GeneTonic_manual.html", package = "GeneTonic") != "",
                             "",
                             "window.open('https://federicomarini.github.io/GeneTonic/articles/GeneTonic_manual.html', '_blank')")
            # sprintf("window.open('http://bioconductor.org/packages/%s/bioc/vignettes/GeneTonic/inst/doc/GeneTonic_manual.html', '_blank')",
            #         ifelse(unlist(packageVersion("GeneTonic"))[2] %% 2L==0L, "release", "devel")
            # )
            # )
          ),
          actionButton(
            inputId = "btn_first_help",
            icon = icon("question-circle"),
            label = "First Help", style = .actionbutton_biocstyle
          )
          
        ),
        shinyWidgets::dropdownButton(
          inputId = "ddbtn_info",
          circle = FALSE,
          status = "info",
          icon = icon("info"),
          width = "300px",
          size = "xs",
          right = TRUE,
          tooltip = shinyWidgets::tooltipOptions(title = "More info!"),
          tags$h5("Additional information"),
          actionButton(
            inputId = "btn_info_session",
            icon = icon("info-circle"),
            label = "About this session", style = .actionbutton_biocstyle
          ),
          actionButton(
            inputId = "btn_info_genetonic",
            icon = icon("heart"),
            label = "About GeneTonic", style = .actionbutton_biocstyle
          )
        )
      )
    ),
    
    # sidebar definition ------------------------------------------------------
    sidebar = bs4Dash::bs4DashSidebar(
      title = HTML("<small>GeneTonic</small>"),
      src = "GeneTonic/GeneTonic.png",
      skin = "dark",
      status = "primary",
      brandColor = NULL,
      url = "https://bioconductor.org/packages/GeneTonic",
      # src = "logos/online-learning.png",
      elevation = 1,
      opacity = 0.8,
      
      bs4SidebarMenu(
        id = "gt_tabs",
        bs4SidebarMenuItem(
          "Welcome!",
          tabName = "tab_welcome",
          icon = "home"
        ),
        bs4SidebarMenuItem(
          "Gene-Geneset",
          tabName = "tab_ggs",
          icon = "share-alt-square"
        ),
        bs4SidebarMenuItem(
          "Enrichment Map",
          tabName = "tab_emap",
          icon = "project-diagram" # hubspot? map?
        ),
        bs4SidebarMenuItem(
          "Overview",
          tabName = "tab_overview",
          icon = "eye"
        ),
        bs4SidebarMenuItem(
          "GSViz",
          tabName = "tab_gsviz",
          icon = "images"
        ),
        bs4SidebarMenuItem(
          "Bookmarks",
          tabName = "tab_bookmarks",
          icon = "bookmark"
        )
      )
    ),
    
    # body definition ---------------------------------------------------------
    body = bs4Dash::bs4DashBody(
      rintrojs::introjsUI(),
      ## Define output size and style of error messages
      ## plus, define the myscrollbox div to prevent y overflow when page fills up
      tags$head(
        tags$style(
          HTML(
            ".shiny-output-error-validation {
            font-size: 15px;
            color: forestgreen;
            text-align: center;
            }

            #myScrollBox{
              overflow-y: scroll;
              .dataTables_wrapper{
                overflow-x: scroll;
              }
            }
            "
          )
        )
      ),
      
      tags$head(
        tags$style(
          ".biocdlbutton{background-color:#0092AC;} .biocdlbutton{color: #ffffff;}"
        )
      ),
      
      tags$script(HTML("$(function(){
      $(document).keyup(function(e) {
      if (e.which == 17) {
        $('#bookmarker').click()
      }
      });
      })")),
      
      # 27: esc, works
      # 60, <, works NOT1
      # 17, ctrl left, works
      
      # see more here:
      # https://stackoverflow.com/questions/41675059/keyboard-shortcuts-to-trigger-reactive-flows-in-r-shiny
      # https://stackoverflow.com/questions/10655202/detect-multiple-keys-on-single-keypress-event-in-jquery
      # http://keycode.info/
      
      bs4TabItems(
        # ui panel welcome -----------------------------------------------------------
        bs4TabItem(
          tabName = "tab_welcome",
          fluidRow(
            column(
              width = 11
            ),
            column(
              width = 1,
              actionButton(
                "tour_firststeps", label = "", icon = icon("question-circle"),
                style = .helpbutton_biocstyle
              )
            )
          ),
          fluidRow(
            h2("Overview on the provided input")
          ),
          fluidRow(
            bs4Dash::bs4Card(
              width = 6,
              inputId = "card_em",
              title = "Expression Matrix",
              status = "danger",
              solidHeader = FALSE,
              collapsible = TRUE,
              collapsed = TRUE,
              closable = FALSE,
              DT::dataTableOutput("overview_dds")
            ),
            bs4Dash::bs4Card(
              width = 6,
              inputId = "card_de",
              title = "DE results",
              status = "warning",
              solidHeader = FALSE,
              collapsible = TRUE,
              collapsed = TRUE,
              closable = FALSE,
              DT::dataTableOutput("overview_res_de")
            ),
            bs4Dash::bs4Card(
              width = 6,
              inputId = "card_enrich",
              title = "Functional analysis results",
              status = "success",
              solidHeader = FALSE,
              collapsible = TRUE,
              collapsed = TRUE,
              closable = FALSE,
              DT::dataTableOutput("overview_res_enrich")
            ),
            bs4Dash::bs4Card(
              width = 6,
              inputId = "card_anno",
              title = "Annotation info",
              status = "info",
              solidHeader = FALSE,
              collapsible = TRUE,
              collapsed = TRUE,
              closable = FALSE,
              DT::dataTableOutput("overview_annotation")
            )
          ),
          uiOutput("ui_infoboxes")
        ),
        
        # ui panel geneset-gene ---------------------------------------------------
        bs4TabItem(
          tabName = "tab_ggs",
          fluidRow(
            column(
              width = 11
            ),
            column(
              width = 1,
              actionButton(
                "tour_ggs", label = "", icon = icon("question-circle"),
                style = .helpbutton_biocstyle
              )
            )
          ),
          fluidRow(
            column(
              width = 8,
              withSpinner(
                visNetworkOutput("ggsnetwork",
                                 height = "700px",
                                 width = "100%")
              )
            ),
            column(
              width = 4,
              bs4Card(
                title = "Geneset Box",
                width = 12,
                closable = FALSE,
                uiOutput("ui_ggs_genesetbox")
              ),
              # box(),
              hr(),
              bs4Card(
                title = "Gene Box",
                width = 12,
                closable = FALSE,
                uiOutput("ui_ggs_genebox")
              )
            )
          )
        ),
        
        # ui panel enrichment map -------------------------------------------------
        bs4TabItem(
          tabName = "tab_emap",
          fluidRow(
            column(
              width = 11
            ),
            column(
              width = 1,
              actionButton(
                "tour_emap", label = "", icon = icon("question-circle"),
                style = .helpbutton_biocstyle
              )
            )
          ),
          fluidRow(
            column(
              width = 8,
              withSpinner(
                tagList(
                  selectInput(
                    inputId = "emap_colorby", 
                    label = "Color emap by",
                    choices = colnames(res_enrich)[unlist(lapply(res_enrich, is.numeric))],
                    selected = "gs_pvalue"),
                  visNetworkOutput("emap_visnet",
                                   height = "700px",
                                   width = "100%")
                )
              )
            ),
            column(
              width = 4,
              bs4Card(
                title = "Geneset Box",
                width = 12,
                closable = FALSE,
                uiOutput("ui_emap_sidecontent")
              )
            )
          ),
          fluidRow(
            bs4Dash::bs4Card(
              width = 12,
              inputId = "card_distillery",
              title = "Geneset distillery",
              status = "info",
              solidHeader = FALSE,
              collapsible = TRUE,
              collapsed = TRUE,
              closable = FALSE,
              fluidRow(
                column(
                  width = 8,
                  withSpinner(
                    DT::dataTableOutput("dt_distill")
                  ),
                  
                  uiOutput("distill_launch"),
                  numericInput(
                    inputId = "n_genesets_distill",
                    label = "Number of genesets",
                    value = min(50, nrow(res_enrich)), min = 1, max = nrow(res_enrich)
                  )
                ),
                column(
                  width = 4,
                  bs4Card(
                    title = "Meta-geneset Box",
                    width = 12,
                    closable = FALSE,
                    uiOutput("ui_metags_sidecontent")
                  )
                )
              )
            )
          )
        ),
        
        # ui panel overview --------------------------------------------------------
        bs4TabItem(
          tabName = "tab_overview",
          fluidRow(
            column(
              width = 11
            ),
            column(
              width = 1,
              actionButton(
                "tour_overview", label = "", icon = icon("question-circle"),
                style = .helpbutton_biocstyle
              )
            )
          ),
          
          fluidRow(
            bs4Dash::column(
              width = 11,
              offset = 0,
              bs4Dash::bs4TabCard(
                id = "tabcard_deview",
                title = "Overview",
                side = "right",
                elevation = 2,
                width = 12,
                closable = FALSE,
                bs4TabPanel(
                  tabName = "Geneset Volcano",
                  active = TRUE,
                  withSpinner(plotOutput("gs_volcano",
                                         height = "650px"))
                ),
                bs4TabPanel(
                  tabName = "Geneset Volcano - simplified",
                  active = FALSE,
                  numericInput(inputId = "gs_overlap",
                               label = "Gene Set overlap",
                               value = 0.6, min = 0, max = 1, step = 0.05),
                  withSpinner(plotOutput("gs_volcano_simplified",
                                         height = "650px"))
                ),
                bs4TabPanel(
                  tabName = "Enhanced Table",
                  active = FALSE,
                  withSpinner(plotOutput("enriched_funcres",
                                         height = "650px"))
                ),
                bs4TabPanel(
                  tabName = "Enhanced Table - interactive",
                  active = FALSE,
                  withSpinner(plotlyOutput("enriched_funcres_plotly",
                                           height = "650px"))
                )
              )
            )
          )
        ),
        
        # ui panel GSViz ------------------------------------------------------
        bs4TabItem(
          tabName = "tab_gsviz",
          fluidRow(
            column(
              width = 11
            ),
            column(
              width = 1,
              actionButton(
                "tour_gsviz", label = "", icon = icon("question-circle"),
                style = .helpbutton_biocstyle
              )
            )
          ),
          
          fluidRow(
            bs4Dash::column(
              width = 11,
              offset = 0,
              bs4Dash::bs4TabCard(
                id = "tabcard_genesets",
                title = "GSViz",
                side = "right",
                elevation = 2,
                width = 12,
                closable = FALSE,
                bs4TabPanel(
                  tabName = "Scores Heatmap",
                  active = TRUE,
                  withSpinner(plotOutput("gsscores_heatmap",
                                         height = "650px"))
                  
                ),
                bs4TabPanel(
                  tabName = "Alluvial Plot",
                  active = FALSE,
                  withSpinner(plotlyOutput("alluvial_genesets",
                                           height = "650px"))
                ),
                bs4TabPanel(
                  tabName = "Summary Heatmap",
                  active = FALSE,
                  withSpinner(plotOutput("gs_summaryheat",
                                         height = "650px"))
                ),
                bs4TabPanel(
                  tabName = "Geneset MDS",
                  active = FALSE,
                  withSpinner(plotOutput("mds_genesets",
                                         height = "650px"))
                ),
                bs4TabPanel(
                  tabName = "Summary Overview",
                  active = FALSE,
                  withSpinner(plotOutput("gs_summaryoverview",
                                         height = "650px"))
                ),
                bs4TabPanel(
                  tabName = "Geneset Radar",
                  active = FALSE,
                  withSpinner(plotlyOutput("gs_summaryradar",
                                           height = "650px"))
                ),
                bs4TabPanel(
                  tabName = "Geneset Dendrogram",
                  active = FALSE,
                  withSpinner(plotOutput("gs_dendro",
                                         height = "650px"))
                )
              )
            )
          )
        ),
        
        # ui panel bookmark ------------------------------------------------------
        bs4TabItem(
          tabName = "tab_bookmarks",
          fluidRow(
            column(
              width = 11
            ),
            column(
              width = 1,
              actionButton(
                "tour_bookmarks", label = "", icon = icon("question-circle"),
                style = .helpbutton_biocstyle
              )
            )
          ),
          fluidRow(
            column(
              width = 12,
              uiOutput("ui_bookmarks")
            )
          ),
          fluidRow(
            bs4Dash::column(
              width = 8,
              offset = 2,
              br(), br(),
              gt_downloadButton(
                "start_happyhour",
                "Start the happy hour!",
                class = "biocdlbutton",
                icon = "cocktail") # magic?
            )
          ),
          hr(),
          br(), br(), br(),
          fluidRow(
            column(
              width = 4, 
              textInput(
                "se_export_name",label = "Choose a filename for the serialized .rds object",
                value = "se_GeneTonic_toiSEE.rds"
              )
            ),
            column(
              width = 4,
              gt_downloadButton(
                "button_iSEEexport",
                label = "Export as serialized SummarizedExperiment",
                class = "biocdlbutton",
                icon = "glasses"
              )
            )
          )
        )
      )
    ),
    # controlbar definition ---------------------------------------------------
    controlbar = bs4Dash::bs4DashControlbar(
      numericInput(inputId = "de_fdr",
                   label = "False Discovery Rate (FDR) for DE",
                   value = 0.05, min = 0.0001, max = 1, step = 0.01),
      numericInput(inputId = "n_genesets",
                   label = "Number of genesets",
                   value = 15, min = 1, max = nrow(res_enrich)),
      selectInput("exp_condition", label = "Group/color by: ",
                  choices = c(NULL, names(colData(dds))), selected = NULL, multiple = TRUE)
    ),
    
    # footer definition -------------------------------------------------------
    footer = bs4DashFooter(
      GeneTonic_footer,
      right_text = NULL
    )
    
  )
  
  options(shiny.maxRequestSize = 15 * 1024^2)
  
  #nocov start
  genetonic_server <- function(input, output, session) {
    
    # reactive objects and setup commands -------------------------------------
    reactive_values <- reactiveValues()
    
    reactive_values$mygenes <- c()
    reactive_values$mygenesets <- c()
    
    myvst <- vst(dds)
    
    res_enhanced <- get_aggrscores(res_enrich = res_enrich,
                                   res_de = res_de,
                                   annotation_obj = annotation_obj)
    
    # output$ui_exp_condition <- renderUI({
    # selectInput("exp_condition", label = "Group/color by: ",
    # choices = c(NULL, poss_covars), selected = NULL, multiple = TRUE)
    # })
    
    
    # panel Welcome -----------------------------------------------------------
    
    output$overview_dds <- DT::renderDataTable({
      DT::datatable(
        counts(dds),
        options = list(scrollX = TRUE, scrollY = "400px")
      )
    })
    output$overview_res_de <- DT::renderDataTable({
      DT::datatable(
        as.data.frame(res_de),
        options = list(
          scrollX = TRUE,
          scrollY = "400px",
          pageLength = 25,
          columnDefs = list(
            list(className = "dt-center", targets = "_all")
          )
        )
      ) %>%
        formatRound(columns = c("log2FoldChange"), digits = 3) %>%
        formatStyle(
          "log2FoldChange",
          background = styleColorBar_divergent(as.data.frame(res_de)$log2FoldChange,
                                               scales::alpha("navyblue", 0.4),
                                               scales::alpha("darkred", 0.4)),
          backgroundSize = "100% 90%",
          backgroundRepeat = "no-repeat",
          backgroundPosition = "center"
        )
    })
    
    output$overview_res_enrich <- DT::renderDataTable({
      DT::datatable(
        res_enrich,
        options = list(scrollX = TRUE, scrollY = "400px")
      )
    })
    output$overview_annotation <- DT::renderDataTable({
      DT::datatable(
        annotation_obj,
        options = list(scrollX = TRUE, scrollY = "400px")
      )
    })
    
    output$ui_infoboxes <- renderUI({
      tagList(
        fluidRow(
          column(
            width = 12,
            bs4ValueBoxOutput("infobox_dds"),
            bs4ValueBoxOutput("infobox_resde"),
            bs4ValueBoxOutput("infobox_resenrich"),
            bs4ValueBoxOutput("infobox_annotation")
          )
          # ,
          # column(
          #   width = 6,
          #   img(src = "GeneTonic/GeneTonic.png", height = "350px")
          # )
        )
      )
    })
    
    output$infobox_dds <- renderbs4ValueBox({
      bs4ValueBox(
        value = paste0(nrow(dds), " genes x ", ncol(dds), " samples"),
        subtitle = "dds object",
        icon = "table",
        status = "danger",
        width = NULL
      )
    })
    
    output$infobox_resde <- renderbs4ValueBox({
      bs4ValueBox(
        value = paste0(
          nrow(deseqresult2df(res_de, FDR = input$de_fdr)),
          " DE genes"
        ),
        subtitle = "res object",
        icon = "vial",
        status = "warning",
        width = NULL
      )
    })
    
    output$infobox_resenrich <- renderbs4ValueBox({
      bs4ValueBox(
        value = paste0(
          nrow(res_enrich),
          " functional categories"
        ),
        subtitle = "func enrich object",
        icon = "share-alt",
        status = "success",
        width = NULL
      )
    })
    
    output$infobox_annotation <- renderbs4ValueBox({
      bs4ValueBox(
        value = paste0(ncol(annotation_obj), " feature identifiers for ", nrow(dds), " features"),
        subtitle = "annotation object",
        icon = "table",
        status = "info",
        width = NULL
      )
    })
    
    # panel GeneSet-Gene ------------------------------------------------------
    reactive_values$ggs_graph <- reactive({
      g <- ggs_graph(
        res_enrich = res_enrich,
        res_de = res_de,
        annotation_obj = annotation_obj,
        n_gs = input$n_genesets,
        prettify = TRUE,
        geneset_graph_color = "gold"
      )
      # rank_gs <- rank(V(g)$name[V(g)$nodetype == "GeneSet"])
      # rank_feats <- rank(V(g)$name[V(g)$nodetype == "Feature"]) +
      #   length(rank_gs) # to keep the GeneSets first
      # g <- permute.vertices(g, c(rank_gs, rank_feats))
      # return(g)
    })
    
    output$ggsnetwork <- renderVisNetwork({
      # minimal example
      
      visNetwork::visIgraph(reactive_values$ggs_graph()) %>%
        visOptions(highlightNearest = list(enabled = TRUE,
                                           degree = 1,
                                           hover = TRUE),
                   nodesIdSelection = TRUE) %>% 
        visExport(name = "ggs_network", 
                  type = "png",
                  label = "Save ggs graph")
      
    })
    
    output$netnode <- renderPrint({
      g <- reactive_values$ggs_graph()
      cur_sel <- input$ggsnetwork_selected
      cur_node <- match(cur_sel, V(g)$name)
      cur_nodetype <- V(g)$nodetype[cur_node]
      
      cur_gsid <- res_enrich$gs_id[match(cur_sel, res_enrich$gs_description)]
      
      paste0("I'm selecting ", input$ggsnetwork_selected, ", which has index ", cur_node, " and is of type ", cur_nodetype, "this is from set", cur_gsid)
    })
    
    output$ui_ggs_genesetbox <- renderUI({
      tagList(
        # verbatimTextOutput("netnode"),
        plotOutput("net_sigheatplot"),
        uiOutput("ggs_geneset_info")
      )
    })
    
    output$net_sigheatplot <- renderPlot({
      g <- reactive_values$ggs_graph()
      cur_sel <- input$ggsnetwork_selected
      cur_node <- match(cur_sel, V(g)$name)
      cur_nodetype <- V(g)$nodetype[cur_node]
      validate(need(cur_nodetype == "GeneSet",
                    message = "Please select a gene set from the Gene-Geneset Graph."
      ))
      cur_gsid <- res_enrich$gs_id[match(input$ggsnetwork_selected, res_enrich$gs_description)]
      
      if (!is.null(input$exp_condition)) {
        gs_heatmap(
          myvst,
          res_de,
          res_enrich,
          annotation_obj = annotation_obj,
          geneset_id = cur_gsid,
          FDR = input$de_fdr,
          de_only = FALSE,
          cluster_rows = TRUE,
          cluster_columns = TRUE,
          center_mean = TRUE,
          scale_row = TRUE,
          anno_col_info = input$exp_condition
        )
      } else {
        gs_heatmap(
          myvst,
          res_de,
          res_enrich,
          annotation_obj = annotation_obj,
          geneset_id = cur_gsid,
          FDR = input$de_fdr,
          de_only = FALSE,
          cluster_rows = TRUE,
          cluster_columns = TRUE,
          center_mean = TRUE,
          scale_row = TRUE
        )
      }
    })
    
    output$ggs_geneset_info <- renderUI({
      g <- reactive_values$ggs_graph()
      cur_sel <- input$ggsnetwork_selected
      cur_node <- match(cur_sel, V(g)$name)
      cur_nodetype <- V(g)$nodetype[cur_node]
      validate(need(cur_nodetype == "GeneSet",
                    message = "" # "Please select a gene set."
      ))
      cur_gsid <- res_enrich$gs_id[match(input$ggsnetwork_selected, res_enrich$gs_description)]
      
      go_2_html(cur_gsid, res_enrich)
    })
    
    output$ui_ggs_genebox <- renderUI({
      tagList(
        uiOutput("ggs_gene_info"),
        plotOutput("ggs_geneplot")
      )
    })
    
    output$ggs_gene_info <- renderUI({
      g <- reactive_values$ggs_graph()
      cur_sel <- input$ggsnetwork_selected
      cur_node <- match(cur_sel, V(g)$name)
      cur_nodetype <- V(g)$nodetype[cur_node]
      validate(need(cur_nodetype == "Feature",
                    message = "Please select a gene/feature."
      ))
      
      cur_geneid <- annotation_obj$gene_id[match(cur_sel, annotation_obj$gene_name)]
      
      # mycontent <- HTML(paste0(
      #   cur_geneid, "<br>", "<b>", cur_sel, "</b>"
      # ))
      
      geneinfo_2_html(cur_sel, res_de)
    })
    
    output$ggs_geneplot <- renderPlot({
      g <- reactive_values$ggs_graph()
      cur_sel <- input$ggsnetwork_selected
      cur_node <- match(cur_sel, V(g)$name)
      cur_nodetype <- V(g)$nodetype[cur_node]
      validate(need(cur_nodetype == "Feature",
                    message = "" # "Please select a gene/feature."
      ))
      validate(need(input$exp_condition != "",
                    message = "Please select a group for the experimental condition."
      ))
      
      cur_geneid <- annotation_obj$gene_id[match(cur_sel, annotation_obj$gene_name)]
      gene_plot(dds,
                gene = cur_geneid,
                intgroup = input$exp_condition,
                annotation_obj = annotation_obj
      )
    })
    
    
    
    # panel EnrichmentMap -----------------------------------------------------
    emap_graph <- reactive({
      emg <- enrichment_map(
        res_enrich = res_enrich,
        res_de = res_de,
        annotation_obj = annotation_obj,
        n_gs = input$n_genesets,
        overlap_threshold = 0.1,
        scale_edges_width = 200,
        color_by = input$emap_colorby
      )
      # rank_gs <- rank(V(emg)$name)
      # emg <- permute.vertices(emg, rank_gs)
      return(emg)
    })
    
    output$emap_visnet <- renderVisNetwork({
      
      visNetwork::visIgraph(emap_graph()) %>%
        visOptions(highlightNearest = list(enabled = TRUE,
                                           degree = 1,
                                           hover = TRUE),
                   nodesIdSelection = TRUE) %>% 
        visExport(name = "emap_network", 
                  type = "png",
                  label = "Save enrichment map")
      
    })
    
    output$ui_emap_sidecontent <- renderUI({
      tagList(
        plotOutput("emap_sigheatplot"),
        uiOutput("emap_geneset_info")
      )
    })
    
    output$emap_geneset_info <- renderUI({
      cur_gsid <- res_enrich$gs_id[match(input$emap_visnet_selected, res_enrich$gs_description)]
      validate(need(!is.na(cur_gsid),
                    message = ""))
      
      # message(cur_gsid)
      # GOTERM[[cur_gsid]]
      go_2_html(cur_gsid, res_enrich)
    })
    
    output$emap_sigheatplot <- renderPlot({
      # g <- reactive_values$emap_graph()
      # cur_sel <- input$emap_visnet_selected
      # cur_node <- match(cur_sel,V(g)$name)
      # cur_nodetype <- V(g)$nodetype[cur_node]
      # validate(need(cur_nodetype == "GeneSet",
      #               message = "Please select a gene set."
      # ))
      cur_gsid <- res_enrich$gs_id[match(input$emap_visnet_selected, res_enrich$gs_description)]
      validate(need(!is.na(cur_gsid),
                    message = "Please select a gene set from the Enrichment Map."
      ))
      
      
      if (!is.null(input$exp_condition)) {
        # message(cur_gsid)
        gs_heatmap(
          myvst,
          res_de,
          res_enrich,
          annotation_obj = annotation_obj,
          geneset_id = cur_gsid,
          FDR = input$de_fdr,
          de_only = FALSE,
          cluster_rows = TRUE,
          cluster_columns = TRUE,
          center_mean = TRUE,
          scale_row = TRUE,
          anno_col_info = input$exp_condition
        )
      } else {
        gs_heatmap(
          myvst,
          res_de,
          res_enrich,
          annotation_obj = annotation_obj,
          geneset_id = cur_gsid,
          FDR = input$de_fdr,
          de_only = FALSE,
          cluster_rows = TRUE,
          cluster_columns = TRUE,
          center_mean = TRUE,
          scale_row = TRUE
        )
      }
    })
    
    
    # geneset distillery
    reactive_values$distillat <- reactive({
      distillat <- distill_enrichment(
        res_enrich = res_enrich,
        res_de = res_de,
        annotation_obj = annotation_obj,
        n_gs = input$n_genesets_distill)
      return(distillat)
    })
    
    output$dt_distill <- DT::renderDataTable({
      dist_table <- reactive_values$distillat()$distilled_table
      
      # TODO: reorder the columns from the distilled table
      
      DT::datatable(
        dist_table[,1:4],
        selection = "single",
        rownames = FALSE,
        options = list(
          pageLength = 50,
          scrollX = TRUE, 
          scrollY = "400px")
      )
    })
    
    output$ui_metags_sidecontent <- renderUI({
      tagList(
        plotOutput("distill_heatmap"),
        uiOutput("distill_info")
      )
    })
    
    output$distill_info <- renderUI({
      "haha"
      # TODO: structure up the content, a la gene2html
    })
    
    output$distill_launch <- renderUI({
      tagList(
        actionButton(
          inputId = "btn_show_emap_distilled",
          icon = icon("hubspot"),
          label = "Distill emap", style = .actionbutton_biocstyle
        )
      )
    })
    
    output$distill_heatmap <- renderPlot({
      dist_table <- reactive_values$distillat()$distilled_table
      s <- input$dt_distill_rows_selected
      
      validate(need(length(s) > 0,
                    message = "Please select a meta-geneset from the table"
      ))
      
      selrow <- dist_table[s,]$metags_msgs
      
      sel_genes <- strsplit(dist_table[s,]$metags_genes, ",")[[1]]
      # message(length(sel_genes))
      sel_genes_id <- annotation_obj$gene_id[match(sel_genes, annotation_obj$gene_name)]
      # message(length(sel_genes_id))
      
      if (!is.null(input$exp_condition)) {
        
        gs_heatmap(
          myvst,
          res_de,
          res_enrich,
          annotation_obj = annotation_obj,
          genelist = sel_genes_id,
          FDR = input$de_fdr,
          de_only = FALSE,
          cluster_rows = TRUE,
          cluster_columns = TRUE,
          center_mean = TRUE,
          scale_row = TRUE,
          anno_col_info = input$exp_condition,
          plot_title = selrow
          
        )
      } else {
        gs_heatmap(
          myvst,
          res_de,
          res_enrich,
          annotation_obj = annotation_obj,
          genelist = sel_genes_id,
          FDR = input$de_fdr,
          de_only = FALSE,
          cluster_rows = TRUE,
          cluster_columns = TRUE,
          center_mean = TRUE,
          scale_row = TRUE,
          plot_title = selrow
        )
      }
    })
    
    # output$distill_graph <- renderPlot({
    #   plot(reactive_values$distillat()$distilled_em)
    # })
    
    output$distill_graph <- renderVisNetwork({
      ig <- reactive_values$distillat()$distilled_em
      # TODO: define color palette
      colpal <- colorspace::rainbow_hcl(length(unique(V(ig)$color)))[V(ig)$color]
      V(ig)$color.background <- scales::alpha(colpal, alpha = 0.8)
      V(ig)$color.highlight <- scales::alpha(colpal, alpha = 1)
      V(ig)$color.hover <- scales::alpha(colpal, alpha = 0.5)
      
      V(ig)$color.border <- "black"
      
      visNetwork::visIgraph(ig) %>%
        visOptions(highlightNearest = list(enabled = TRUE,
                                           degree = 1,
                                           hover = TRUE),
                   nodesIdSelection = TRUE, 
                   selectedBy = "membership")
      
    })
    
    
    
    # panel Overview ------------------------------------------------------------
    
    output$enriched_funcres <- renderPlot({
      enhance_table(res_enrich, res_de,
                    annotation_obj = annotation_obj,
                    n_gs = input$n_genesets)
    })
    
    output$gs_volcano <- renderPlot({
      gs_volcano(
        get_aggrscores(res_enrich,
                       res_de,
                       annotation_obj = annotation_obj),
        volcano_labels = input$n_genesets
      )
    })
    
    output$gs_volcano_simplified <- renderPlot({
      gs_volcano(
        get_aggrscores(gs_simplify(res_enrich, gs_overlap = input$gs_overlap),
                       res_de,
                       annotation_obj = annotation_obj),
        volcano_labels = input$n_genesets
      )
    })
    
    output$enriched_funcres_plotly <- renderPlotly({
      ggplotly(enhance_table(res_enrich,
                             res_de,
                             annotation_obj = annotation_obj,
                             n_gs = input$n_genesets))
    })
    
    
    # panel GSViz -----------------------------------------------------
    
    gss_mat <- reactive({
      gs_scores(se = myvst,
                res_de = res_de,
                res_enrich = res_enrich,
                annotation_obj = annotation_obj)
    })
    output$gsscores_heatmap <- renderPlot({
      gs_scoresheat(
        gss_mat(),
        n_gs = input$n_genesets)
    })
    
    output$alluvial_genesets <- renderPlotly({
      gs_alluvial(res_enrich, res_de, annotation_obj, n_gs = input$n_genesets)
    })
    
    output$mds_genesets <- renderPlot({
      gs_mds(res_enrich, res_de, annotation_obj, mds_colorby = "z_score",
             mds_labels = input$n_genesets)
    })
    
    output$gs_summaryheat <- renderPlot({
      gs_summary_heat(res_enrich, res_de, annotation_obj,
                      n_gs = input$n_genesets)
    })
    
    output$gs_summaryoverview <- renderPlot({
      gs_summary_overview(res_enrich = res_enhanced,
                          n_gs = input$n_genesets)
    })
    
    output$gs_summaryoverview_pair <- renderPlot({
      gs_summary_overview_pair(res_enrich = res_enhanced,
                               n_gs = input$n_genesets)
    })
    
    output$gs_summaryhorizon <- renderPlot({
      gs_horizon(res_enrich = res_enhanced,
                 n_gs = input$n_genesets)
    })
    
    output$gs_summaryradar <- renderPlotly({
      gs_radar(res_enrich = res_enhanced,
               n_gs = input$n_genesets)
    })
    
    output$gs_dendro <- renderPlot({
      gs_dendro(res_enrich = res_enhanced,
                n_gs = input$n_genesets)
    })
    
    
    
    # panel Bookmarks ---------------------------------------------------------
    
    output$ui_bookmarks <- renderUI({
      tagList(
        fluidRow(
          column(
            width = 6,
            bs4InfoBoxOutput("infobox_book_genes"),
            h5("Bookmarked genes"),
            DT::dataTableOutput("bookmarks_genes"),
            downloadButton("btn_export_genes", label = "", class = "biocdlbutton")
            # ideally completed by a function/param to upload them
            
          ),
          column(
            width = 6,
            bs4InfoBoxOutput("infobox_book_genesets"),
            h5("Bookmarked genesets"),
            DT::dataTableOutput("bookmarks_genesets"),
            downloadButton("btn_export_genesets", label = "", class = "biocdlbutton")
            
          )
        )
      )
    })
    
    output$infobox_book_genes <- renderbs4InfoBox({
      bs4InfoBox(
        title = "Bookmarked genes",
        value = length(reactive_values$mygenes),
        icon = "bookmark",
        status = "info",
        width = 12
      )
    })
    
    output$infobox_book_genesets <- renderbs4InfoBox({
      bs4InfoBox(
        title = "Bookmarked genesets",
        value = length(reactive_values$mygenesets),
        icon = "bookmark",
        status = "success",
        width = 12
      )
    })
    
    output$bookmarks_genes <- DT::renderDataTable({
      book_df_genes <- annotation_obj[reactive_values$mygenes, ]
      datatable(book_df_genes, rownames = FALSE)
    })
    output$bookmarks_genesets <- DT::renderDataTable({
      book_df_genesets <- res_enrich[reactive_values$mygenesets, c("gs_id", "gs_description")]
      datatable(book_df_genesets, rownames = FALSE)
    })
    
    output$btn_export_genes <- downloadHandler(
      filename = function() {
        paste0("GeneTonicBookmarks_genes_", project_id, "_", gsub(" ", "_", gsub("-", "", gsub(":", "-", as.character(Sys.time())))), ".txt")
      }, content = function(file) {
        writeLines(text = reactive_values$mygenes,
                   con = file)
      }
    )
    
    output$btn_export_genesets <- downloadHandler(
      filename = function() {
        paste0("GeneTonicBookmarks_genesets_", project_id, "_", gsub(" ", "_", gsub("-", "", gsub(":", "-", as.character(Sys.time())))), ".txt")
      }, content = function(file) {
        writeLines(text = reactive_values$mygenesets,
                   con = file)
      }
    )
    
    output$start_happyhour <- downloadHandler(
      filename = paste0(
        Sys.Date(),
        "_", round(runif(1) * 100), # for not having all w the same name
        "_GeneTonicReport.html"),
      content = function(file) {
        # temporarily switch to the temp dir, in case you do not have write permission to the current working directory
        owd <- setwd(tempdir())
        on.exit(setwd(owd))
        # cat(tmp_content,file="GeneTonic_tempreport.Rmd",sep="\n")
        withProgress(rmarkdown::render(
          input = system.file("extdata", "cocktail_recipe.Rmd", package = "GeneTonic"),
          output_file = file,
          # fragment.only = TRUE,
          quiet = TRUE),
          message = "Generating the html report",
          detail = "This can take some time")
      }
    )
    
    output$button_iSEEexport <- downloadHandler(
      filename = function() {
        input$se_export_name
      }, content = function(file) {
        se <- export_for_iSEE(dds, res_de)
        saveRDS(se, file = file)
      }
    )
    
    output$sessioninfo <- renderPrint({
      sessionInfo()
    })
    
    
    # observers ---------------------------------------------------------------
    
    observeEvent(input$tour_firststeps, {
      tour <- read.delim(system.file("extdata", "tour_welcome.txt", package = "GeneTonic"),
                         sep = ";", stringsAsFactors = FALSE,
                         row.names = NULL, quote = "")
      rintrojs::introjs(session, options = list(steps = tour))
    })
    
    observeEvent(input$tour_ggs, {
      tour <- read.delim(system.file("extdata", "tour_ggs.txt", package = "GeneTonic"),
                         sep = ";", stringsAsFactors = FALSE,
                         row.names = NULL, quote = "")
      rintrojs::introjs(session, options = list(steps = tour))
    })
    
    observeEvent(input$tour_emap, {
      tour <- read.delim(system.file("extdata", "tour_emap.txt", package = "GeneTonic"),
                         sep = ";", stringsAsFactors = FALSE,
                         row.names = NULL, quote = "")
      rintrojs::introjs(session, options = list(steps = tour))
    })
    
    observeEvent(input$tour_overview, {
      tour <- read.delim(system.file("extdata", "tour_overview.txt", package = "GeneTonic"),
                         sep = ";", stringsAsFactors = FALSE,
                         row.names = NULL, quote = "")
      rintrojs::introjs(session, options = list(steps = tour))
    })
    
    observeEvent(input$tour_gsviz, {
      tour <- read.delim(system.file("extdata", "tour_gsviz.txt", package = "GeneTonic"),
                         sep = ";", stringsAsFactors = FALSE,
                         row.names = NULL, quote = "")
      rintrojs::introjs(session, options = list(steps = tour))
    })
    
    observeEvent(input$tour_bookmarks, {
      tour <- read.delim(system.file("extdata", "tour_bookmarks.txt", package = "GeneTonic"),
                         sep = ";", stringsAsFactors = FALSE,
                         row.names = NULL, quote = "")
      rintrojs::introjs(session, options = list(steps = tour))
    })
    
    
    # observe({
    #   print(input$gt_tabs)
    # })
    
    observeEvent(input$btn_first_help, {
      showModal(
        modalDialog(
          title = "First Help Info", size = "l", fade = TRUE,
          footer = NULL, easyClose = TRUE,
          tagList(
            includeMarkdown(system.file("extdata", "GeneTonic101.md", package = "GeneTonic")),
          )
        )
      )
    })
    
    observeEvent(input$btn_docs_vignette, {
      path <- system.file("doc", "GeneTonic_manual.html", package = "GeneTonic")
      if (path == "") {
        showNotification("This vignette has not been built on this system - Opening the online documentation. Please note that the versions might not be coincident!", type = "warning")
      } else {
        browseURL(path)
      }
    })
    
    
    observeEvent(input$btn_info_session, {
      showModal(
        modalDialog(
          title = "Session information", size = "l", fade = TRUE,
          footer = NULL, easyClose = TRUE,
          tagList(
            tags$code("> sessionInfo()"),
            renderPrint({
              sessionInfo()
            })
          )
        )
      )
    })
    
    observeEvent(input$btn_info_genetonic, {
      showModal(
        modalDialog(
          title = "About GeneTonic", size = "l", fade = TRUE,
          footer = NULL, easyClose = TRUE,
          tagList(
            includeMarkdown(system.file("extdata", "about.md", package = "GeneTonic")),
            renderPrint({
              citation("GeneTonic")
            })
          )
        )
      )
    })
    
    
    observeEvent(input$btn_show_emap_distilled, {
      showModal(
        modalDialog(
          title = "distillery", size = "l", fade = TRUE,
          footer = NULL, easyClose = TRUE,
          
          visNetworkOutput("distill_graph")
        )
      )
    })
    
    
    # bookmarker --------------------------------------------------------------
    observeEvent(input$bookmarker, {
      if (input$gt_tabs == "tab_welcome")
        showNotification("Welcome to GeneTonic!")
      else if (input$gt_tabs == "tab_ggs") {
        g <- reactive_values$ggs_graph()
        cur_sel <- input$ggsnetwork_selected
        if (cur_sel == "") {
          showNotification("Select a node in the network to bookmark it", type = "warning")
        } else {
          cur_node <- match(cur_sel, V(g)$name)
          cur_nodetype <- V(g)$nodetype[cur_node]
          
          if (cur_nodetype == "Feature") {
            cur_sel_id <- annotation_obj$gene_id[match(cur_sel, annotation_obj$gene_name)]
            if (cur_sel_id %in% reactive_values$mygenes) {
              showNotification(sprintf("The selected gene %s (%s) is already in the set of the bookmarked genes.", cur_sel, cur_sel_id), type = "default")
            } else {
              reactive_values$mygenes <- unique(c(reactive_values$mygenes, cur_sel_id))
              # message("there go your genes... ", reactive_values$mygenes)
              showNotification(sprintf("Added %s (%s) to the bookmarked genes. The list contains now %d elements", cur_sel, cur_sel_id, length(reactive_values$mygenes)), type = "message")
              
            }
          } else if (cur_nodetype == "GeneSet") {
            cur_sel_id <- res_enrich$gs_id[match(cur_sel, res_enrich$gs_description)]
            if (cur_sel_id %in% reactive_values$mygenesets) {
              showNotification(sprintf("The selected gene set %s (%s) is already in the set of the bookmarked genesets.", cur_sel, cur_sel_id), type = "default")
            } else {
              reactive_values$mygenesets <- unique(c(reactive_values$mygenesets, cur_sel_id))
              # message("here are your genesets... ", reactive_values$mygenesets)
              showNotification(sprintf("Added %s (%s) to the bookmarked genesets. The list contains now %d elements", cur_sel, cur_sel_id, length(reactive_values$mygenesets)), type = "message")
            }
            
          } else {
            message("bleeee")
          }
        }
      }
      else if (input$gt_tabs == "tab_emap") {
        g <- reactive_values$ggs_graph()
        cur_sel <- input$emap_visnet_selected
        cur_sel_id <- res_enrich$gs_id[match(cur_sel, res_enrich$gs_description)]
        
        if (cur_sel == "") {
          showNotification("Select a node in the network to bookmark it", type = "warning")
        } else {
          if (cur_sel_id %in% reactive_values$mygenesets) {
            showNotification(sprintf("The selected gene set %s (%s) is already in the set of the bookmarked genesets.", cur_sel, cur_sel_id), type = "default")
          } else {
            reactive_values$mygenesets <- unique(c(reactive_values$mygenesets, cur_sel_id))
            message("here are your genesets... ", reactive_values$mygenesets)
            showNotification(sprintf("Added %s (%s) to the bookmarked genesets. The list contains now %d elements", cur_sel, cur_sel_id, length(reactive_values$mygenesets)), type = "message")
          }
        }
      }
      else if (input$gt_tabs == "tab_bookmarks")
        showNotification("You are already in the Bookmarks tab...")
    })
    
    
    # observeEvent(input$start_happyhour, {
    # showNotification("The happy hour is on! Please wait for the report to be fully compiled",
    # type = "message")
    # })
    
    
    
  }
  #nocov end
  
  shinyApp(ui = genetonic_ui, server = genetonic_server)
}

Try the GeneTonic package in your browser

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

GeneTonic documentation built on Nov. 8, 2020, 5:27 p.m.