dcomtois / summarytools

R Package to Quickly and Neatly Summarize Data
522 stars 78 forks source link

Name of Group variable is not updated when using descr() with by() in Shiny app #32

Closed Payamdel closed 6 years ago

Payamdel commented 6 years ago

I found that the Name of Group variable (and group level) is not retrieved or re-updated on UI when selecting a new Group variable in the app. It should be noted that the corresponding table (calculations) updates upon selection a new group variable. Moreover, the group variable is also displayed in a static manner. Using the Shiny App below, the issue could be exemplified to some extent. For example, the Group variable is displayed on UI, as shown below:

Group: _(pData(eset_object)[, esetgroups]) = B


# Install packages
source("https://bioconductor.org/biocLite.R")
biocLite("ALL")
biocLite("Biobase")
install.packages('devtools')
devtools::install_github('dcomtois/summarytools')

# Load packages
library(summarytools)
library(Biobase)
library(ALL) 

# Shiny Server
server <- function(input, output, session) {
  output$summaryTable <- renderUI({
    #-- Load the ALL data
    data(ALL)  
    #-- Subset
    eset_object <- ALL [1:3,] # choose only 3 variables 
    #-- The group of interest 
    eset_groups <-"BT"
    # print(rownames (eset_object)) # print variable names
    ALL_stats_by_BT <- by(data = as.data.frame(t(exprs(eset_object))), 
                          INDICES = (pData(eset_object)[,eset_groups]), 
                          FUN = descr, stats ="all", 
                          transpose = TRUE)

    view(ALL_stats_by_BT,
         method = 'render',
         omit.headings = FALSE,
         bootstrap.css = FALSE)
  })
}

# Shiny UI
ui <- fluidPage(theme = "dfSummary.css",
                fluidRow(
                  uiOutput("summaryTable")
                )
)

# Lauch
shinyApp(ui, server)

Of note, if you replace eSet_object <- relevant_est() to eSet_object <<- relevant_est() (that is Global Env) the option Data Frame will be retrieved and displayed on UI, as presented below:

Data Frame: as.data.frame(t(exprs(eSet_object))) Group: (pData(eSet_object)[, eSet_groups]) = B

dcomtois commented 6 years ago

When you say "when selecting a new Group variable in the app", do you mean that you have a Shiny app allowing the specification of the grouping variable?

Payamdel commented 6 years ago

Exactly! The app allows to pick any of the groups that contains in the data. Thus, I can switch between different group variables to explore the data.

The issue with group variables reminds me of the previously described issue with Feature variables, that you have just addressed!

dcomtois commented 6 years ago

And is the app publicly available? Without seeing it, and how it's built, I can't do much I'm afraid.

(Although I do have a few workarounds in mind, but first I'll wait for your answer)

Payamdel commented 6 years ago

See below for a very simple version of my app. The only difference is that in this example you do not upload the data via your browser.

------------------------------------------------------------------

Define Server

------------------------------------------------------------------

# Install packages
# source("https://bioconductor.org/biocLite.R")
# biocLite("ALL")
# biocLite("Biobase")
# install.packages('devtools')
# devtools::install_github('dcomtois/summarytools')

# Load packages
library(summarytools)
library(Biobase)
library(ALL) 
data(ALL)

# Shiny Server
server <- function(input, output, session) {

   ExpressionSet <-reactive({
          ExpressionSet <- ALL [1:3,] # choose only 3 features  
        })
 #  Pheno data Selection  
   NamesPdataEset <-reactive({
          ExpressionSet <- ExpressionSet()

          if(length(ExpressionSet)!=0){
           prChoices <- names(pData(ExpressionSet))
            names(prChoices) <- prChoices

          }
          else{
            return(NULL)
          }
        })

        output$choose_Covariate <- renderUI({

           prChoices<-NamesPdataEset()
            selectInput("Covariate", "Pick a group (Covariate)", prChoices)

        })

  output$summaryTable <- renderUI({

  eSet_object  <- ExpressionSet() 
  eSet_groups <-input$Covariate#  #Group of interest 

    ALL_stats_by_BT <- by(data = as.data.frame(t(exprs(eSet_object))), 
                          INDICES = (pData(eSet_object)[,eSet_groups]), 
                          FUN = descr, stats ="all", 
                          transpose = TRUE)

    view(ALL_stats_by_BT,
         method = 'render',
         omit.headings = FALSE,
         bootstrap.css = FALSE)
  })
}

------------------------------------------------------------------

Define UI

------------------------------------------------------------------

ui <- fluidPage(theme = "dfSummary.css",
                fluidRow(
                  uiOutput("choose_Covariate"),
                                  uiOutput("summaryTable")
                )
)

I think this example can to some extent show you how the name of group variable displays on UI!

dcomtois commented 6 years ago

That's real nice! Now for a solution... There are several layers of complexities involved (Shiny, BIOBASE data which is a bit peculiar at first glancec, and the use of by() to sugar coat it all. If I could do this full-time, then maaaaybe I'd come up with a one-size-fits-all solution. Unfortunately my time is quite limited nowadays. But don't despair, I have a workaround solution that may well be totally acceptable for your needs.

I set a default value for the covariate to avoid having a warning/error upon loading. For the rest, I did a little tweaking, nothing too complicated... (yeah, from the package developer's perspective, I'm aware of that nuance).

Try it out and let me know your thoughts!

library(shiny)
library(summarytools)
library(Biobase)
library(ALL) 
data(ALL)

# Shiny Server
server <- function(input, output, session) {

  ExpressionSet <-reactive({
    ExpressionSet <- ALL [1:3,] # choose only 3 features  
  })
  #  Pheno data Selection  
  NamesPdataEset <-reactive({
    ExpressionSet <- ExpressionSet()

    if(length(ExpressionSet)!=0){
      prChoices <- names(pData(ExpressionSet))
      names(prChoices) <- prChoices

    }
    else{
      return(NULL)
    }
  })

  output$choose_Covariate <- renderUI({

    prChoices <- NamesPdataEset()
    selectInput("Covariate", "Pick a group (Covariate)", prChoices, selected = "sex")
  })

  output$summaryTable <- renderUI({

    eSet_object  <- ExpressionSet() 
    eSet_groups <-input$Covariate  #Group of interest
    #browser()
    assign(input$Covariate, pData(eSet_object)[,eSet_groups])

    ALL_stats_by_BT <- by(data = as.data.frame(t(exprs(eSet_object))), 
                          INDICES = get(input$Covariate), 
                          FUN = descr, stats ="all", 
                          transpose = TRUE)

    attr(ALL_stats_by_BT[[1]], "data_info")$Dataframe <- "Your dataframe's name goes here"

    for (i in seq_along(ALL_stats_by_BT)) { 
      attr(ALL_stats_by_BT[[i]], "data_info")$Group <- sub(pattern = "get(inputCovariate)", 
                                                           replacement = input$Covariate,
                                                           fixed = TRUE,
                                                           x = attr(ALL_stats_by_BT[[i]], "data_info")$Group)
    }

    view(ALL_stats_by_BT,
         method = 'render',
         omit.headings = FALSE,
         bootstrap.css = FALSE)
  })
}

ui <- fluidPage(theme = "dfSummary.css",
                fluidRow(
                  uiOutput("choose_Covariate"),
                  uiOutput("summaryTable")
                )
)

shinyApp(ui, server)
Payamdel commented 6 years ago

It's a very effective solution! Using this modification you introduced into the code, I can now see the name Group variable is displayed correctly upon selecting a Group. So thank you very much for that!

However, the name of Group LEVEL variable is static and does not updates accordingly. Any workarounds for that?

dcomtois commented 6 years ago

Hmm ok, on my side things seems pretty up-to-date when I change the grouping variable... could you give a specific example of what is expected vs what is shown?

Thx

Payamdel commented 6 years ago

You are right! Using the current exmaple data in the app, everything seems as it should! But I coducted the same analysis using other types of data and noticed that the utilized functions (descr() with by()) do not return the updated group level as expected, in some cases. I'm not sure whether it is due to the problem with the overwrite on a (permanent) variable in the environment that the function by() utilizes or not.

So I am wondering whether there is any other function that we could use instead of by() to do the same analysis by descr().

dcomtois commented 6 years ago

Ok I may have found the issue... Could you pls reinstall the dev-current version and try again, but changing the line: attr(ALL_stats_by_BT[[i]], "data_info")$Group <- sub(pattern = "get(inputCovariate)", for: attr(ALL_stats_by_BT[[i]], "data_info")$Group <- sub(pattern = "get(input$Covariate)",

Payamdel commented 6 years ago

I did as you instructed but the outcome is the same! BUT, I further used the function print() instead of view() to see if there is any difference between the outcomes. Indeed, there is a difference:

When i used the function print(), I got the following results in R console: get(input$Covariate): TBD Descriptive Statistics
Data Frame: net_sig
Group: status = 20180509
N: 112

So, as you can see, the code returns two different names for Group levels. These are: TBD and 20180509 This is exactly the problem, what we should expect is: Group: status = TBD Because I used the Group variable Status in the analysis which has only 1 level (i.e. TBD). What we see here, instead, is the group level "20180509" which actually belongs to the first Group variable that I selected when I started the App, which never overwrites upon choosing a new group!!

Do you see what I mean?

dcomtois commented 6 years ago

Yes, thank you for the precise description. I have an idea why this happens, will look into it!

dcomtois commented 6 years ago

I think it should work now... Can you test after re-installing the dev-current version pls? Thx!

Payamdel commented 6 years ago

It works like a charm now!!!! Great job!! Thank you very much for all the efforts you put into it!

Payamdel commented 6 years ago

I'm wondering whether it is possible to control which Stats to be shown in the case of numerical variables when using dfSummary(). This is almost necessary to be able to control which Stats to be used for numerical variables, particularity in the case of CV. This is because CV values should not be calculated for a data on a logarithmic scale!

dcomtois commented 6 years ago

I understand. Could you pls open another issue for this? I'll think about a solution!