Search code examples
rshinyshinydashboardshiny-servershiny-reactivity

Unable to use apply function inside an lapply function in a shiny app


This code returns a number of responses in each column that are not NA.

apply(df, 2, function(x) sum(!is.na(x)))

I also made an app that uses the 'species' column of IRIS dataset to split it into 3 parts. The 3 parts are then displayed. We can use any data really and split it into parts based on some column. However, I also want to calculate the number of responses in each column of each of the 3 datasets and I am not sure how would I do that. I have tried the following and its variations but I failed. I think I also need to subset the species column from data set using subset(x,select=-c(Species)) but I am just really confused now on how would I implement it all. This is the last aspect of the project i am working on and i really need some help with this:-

The following is the code which splits the data in 3 parts and displays it:-

library(shiny) data(iris)
server<- shinyServer(
function(input, output) {
output$data <- renderUI({
  splitDFs<- split(iris, iris$Species)
  lapply(splitDFs, function(x) renderTable(x))
})
} )
ui<- shinyUI(fluidPage( titlePanel(title = h4("Iris Dataset", align="center")), sidebarLayout( sidebarPanel( ),
mainPanel(
  uiOutput("data"),
  
)
)
))
shinyApp(ui = ui, server = server)

The following is what i have tried so far. I have tried various variations of the following code but i have failed:-

output$data <- renderUI({
            splitDFs<- split(iris, iris$Species)
            lapply(splitDFs, function(x) apply(splitDFs, 2, function(x) sum(!is.na(x)))(x) )

        })

Solution

  • VitaminB16's answer delivers what you need, so you need to figure out how you want to represent it.

    For instance, if you use the following code in your server (adapting VitaminB16's answer a bit):

    output$data <- renderUI({
        splitDFs<- split(iris, iris$Species)
        
        sP <- data.frame(t(sapply(splitDFs, function(x) sapply(x, function(y) sum(!is.na(y))))))
        sP <- cbind(data.frame(Metric = rownames(sP)), sP)
        sP2 <- renderTable(sP)
        
        return(list(sP2))
        
      })
    

    You get this:

    enter image description here

    Here, each row is a split in the data, and each column is a column in the original dataset. The cells represent the number of non-missing values in that combination.

    • The split is functioning as before.

    • Then first we use nested apply as Vitamin did to calculate the cross-sectional non-NA count.

      • We use sapply instead of lapply to get a matrix output instead of a list output, so we can easily coerce to a dataframe.
    • Before coercing, we transpose, so columns remain columns (you can play around with this if you like).

    • Then, we add in the row names as an explicit column. We do that through cbind since otherwise the Metric column would be at the end.

    • Then, we put it in a renderTable and pass that back.

      • Note that since this is now just one table, you could use renderTable and tableOutput directly instead of worrying about renderUI and uiOutput.