0

I'm using a function from the ClusterProfiler package, which takes 0.1-10 min to complete. I'd like to keep shiny responsive during the computation, and also give a possibility to terminate the execution. This is the computation only:

library(org.Mm.eg.db)
library(clusterProfiler)
d <-
  data.frame(
    ENTREZ = c(
      "26394",
      "16765",
      "19143",
      "54214",
      "620695",
      "14232",
      "20262",
      "100732",
      "99681"
    ),
    Cell_Type = c(rep("A", 5), rep("B", 4)),
    Timepoint = rep("C", 9)
  )

r <- compareCluster(
  ENTREZ ~ Cell_Type + Timepoint,
  data = d,
  fun = "enrichGO",
  pvalueCutoff = 0.5,
  qvalueCutoff = 0.5,
  ont           = "MF",
  pAdjustMethod = "BH",
  readable = T,
  OrgDb         = org.Mm.eg.db,
  keyType       = 'ENTREZID'
)

  rp <- dotplot(r, showCategory=10, x = ~Cell_Type) +
    facet_wrap(~Timepoint)
rp

The best solution I found for that was a neat script from the user fxi (https://stackoverflow.com/a/34517844/9950389). However, I run into a problem. The function analyze executed in the script as a parallel process, seems to return an improper object type for the downstream function, in this case dotplot (unable to find an inherited method for function ‘dotplot’ for signature ‘"list"’). Below there is a minimal example of the problem (shamelessly based on the script written by the user fxi). Do you see any solution to this?

library(shiny)
library(parallel)
library(org.Mm.eg.db)
library(clusterProfiler)

#
# reactive variables
# 
rVal <- reactiveValues()
rVal$process <- NULL
rVal$msg <- NULL
rVal$obs <- NULL
counter <- 0
results <- list()
dfEmpty <- data.frame(results = numeric(0))


#
# Long computation
#
analyze <- function() {
  d <-
    data.frame(
      ENTREZ = c(
        "26394",
        "16765",
        "19143",
        "54214",
        "620695",
        "14232",
        "20262",
        "100732",
        "99681"
      ),
      Cell_Type = c(rep("A", 5), rep("B", 4)),
      Timepoint = rep("C", 9)
    )

  r <- compareCluster(
    ENTREZ ~ Cell_Type + Timepoint,
    data = d,
    fun = "enrichGO",
    pvalueCutoff = 0.5,
    qvalueCutoff = 0.5,
    ont           = "MF",
    pAdjustMethod = "BH",
    readable = T,
    OrgDb         = org.Mm.eg.db,
    keyType       = 'ENTREZID'
  )
}

#
# Shiny app
#
shinyApp(
  ui = fluidPage(
    column(6,
           wellPanel(
             tags$label("Press start and wait 5 seconds for the process to finish"),
             actionButton("start", "Start", class = "btn-primary"),
             actionButton("stop", "Stop", class = "btn-danger"),
             textOutput('msg'),
             plotOutput('myplot', width = 200)
           )
    ),
    column(6,
           wellPanel(
             sliderInput(
               "inputTest",
               "Shiny is responsive during computation",
               min = 10,
               max = 100,
               value = 40
             ),
             plotOutput("testPlot")
           ))),
  server = function(input, output, session)
  {
    #
    # Add something to play with during waiting
    #
    output$testPlot <- renderPlot({
      plot(rnorm(input$inputTest))
    })

    #
    # Render messages
    #
    output$msg <- renderText({
      rVal$msg
    })

    #
    # Render results
    #
    # output$result <- renderTable({
    #   print(rVal$result)
    #   rVal$result
    # })

    output$myplot <-renderPlot({
      r <- rVal$result
      rp <- dotplot(r, showCategory=10, x = ~Cell_Type) +
        facet_wrap(~Timepoint) +
        scale_color_gradient(low = "lawngreen", high = "black") +
        guides(color=guide_colorbar(title = "Adj. P-value")) +
        theme(title = element_text(size = 16, face = "plain", lineheight = .8),
              panel.grid.major.x = element_blank(),
              panel.grid.major.y = element_line(size = 0.1),
              axis.title = element_text(size = 16),
              text = element_text(size = 14),
              strip.text.x = element_text(size = 18, face = "plain"),
              axis.text = element_text(size = 14, face = "plain"),
              legend.text = element_text(angle = 0, hjust=0, size = 16),
              legend.title.align = 0.5,
              legend.title = element_text(angle = 0, hjust=0, size = 18)) +
        coord_fixed(ratio = 0.4)
      rp
    })


    #
    # Start the process
    #
    observeEvent(input$start, {
      if (!is.null(rVal$process))
        return(NULL)
      rVal$result <- NULL
      rVal$process <- mcparallel({
        analyze()
      })

      rVal$msg <- sprintf("%1$s started", rVal$process$pid)

    })


    #
    # Stop the process
    #
    observeEvent(input$stop, {
      rVal$result <- NULL
      if (!is.null(rVal$process)) {
        tools::pskill(rVal$process$pid)
        rVal$msg <- sprintf("%1$s killed", rVal$process$pid)
        rVal$process <- NULL

        if (!is.null(rVal$obs)) {
          rVal$obs$destroy()
        }
      }
    })


    #
    # Handle process event
    #
    observeEvent(rVal$process, {
      rVal$obs <- observe({
        invalidateLater(500, session)
        isolate({
          result <- mccollect(rVal$process, wait = FALSE)
          if (!is.null(result)) {
            rVal$result <- result
            rVal$obs$destroy()
            rVal$process <- NULL
          }
        })
      })
    }) # observe
  }
)

I also tried using the async approach, but both attempts failed:

library(promises)
library(future)

future(
    compareCluster(
      ENTREZ ~ Cell_Type + Timepoint,
      data = d,
      fun = "enrichGO",
      pvalueCutoff = 0.5,
      qvalueCutoff = 0.5,
      ont           = "MF",
      pAdjustMethod = "BH",
      readable = T,
      OrgDb         = org.Mm.eg.db,
      keyType       = 'ENTREZID'
    )
  ) %...>% dotplot(., showCategory=10, x = ~Cell_Type) +
    facet_wrap(~Timepoint)


future(
  compareCluster(
    ENTREZ ~ Cell_Type + Timepoint,
    data = d,
    fun = "enrichGO",
    pvalueCutoff = 0.5,
    qvalueCutoff = 0.5,
    ont           = "MF",
    pAdjustMethod = "BH",
    readable = T,
    OrgDb         = org.Mm.eg.db,
    keyType       = 'ENTREZID'
  )
) %...>% {
  dotplot(., showCategory=10, x = ~Cell_Type) +
  facet_wrap(~Timepoint)
  }
Lechu
  • 149
  • 1
  • 7
  • For keeping shiny responsive you can check https://blog.rstudio.com/2018/06/26/shiny-1-1-0/ – A. Suliman Jul 08 '18 at 10:47
  • Thanks. Wasn't aware of that, should solve at least the responsiveness problem. However, couldn't make it to work with the compareCluster() function, even though it seems like it should be a single promise. I edited the question. – Lechu Jul 08 '18 at 14:26
  • Unfortunately, It looks like **future** does not support `(‘org.Mm.eg.db’ of class ‘OrgDb’)`. You can find another unsuported classes [here](https://cran.r-project.org/web/packages/future/vignettes/future-2-issues.html). To reproduce the error run `plan(multisession)` and `options(future.globals.onReference = "error") #To get infromative error msg` after `library(future)` then the future code. – A. Suliman Jul 09 '18 at 08:19

0 Answers0