coding help shiny

"Hi there, I just started working with R Shiny yesterday. I was able to visualize a histogram for two variables, with a table underneath to summarize some basic statistics. This was done by selecting the names of the two variables from two sidebars. It was a test example to study and build upon for my project. However, I couldn't continue because my data consists of 13 lists, each containing 115 data frames of two variables each. My question is, how can I create a single slider bar that allows selection of one name from the 115 names of the data frames to visualize 5 pairs of histograms and a table of summary statistics for the same name of the data frame, but from all 13 lists?" Shiny reprex

Hi, can you provide a reproducible example? Thanks.

Hi, here an example from chat gpt,
library(shiny)

Assuming you have already defined list_of_lists

list_1 <- list(
df1 = data.frame(name = "df1", x = rnorm(100), y = rnorm(100)),
df2 = data.frame(name = "df2", x = rnorm(100), y = rnorm(100))
)

list_2 <- list(
df1 = data.frame(name = "df1", x = rnorm(100), y = rnorm(100)),
df2 = data.frame(name = "df2", x = rnorm(100), y = rnorm(100))
)

list_of_lists <- list(list_1, list_2)

Extract unique names from both lists combined

df_names <- unique(unlist(lapply(list_of_lists, function(lst) unlist(lapply(lst, [[, "name")))))

UI

ui <- fluidPage(
titlePanel("Basic Data Explorer"),

sidebarLayout(
sidebarPanel(
selectInput("data_frame", "Choose a Data Frame", choices = df_names)
),

mainPanel(
  tableOutput("mean_table")
)

)
)

Server

server <- function(input, output) {

Render mean table

output$mean_table <- renderTable({
req(input$data_frame)

# Extract the selected data frame from both lists
df1 <- list_of_lists[[1]][[which(sapply(list_of_lists[[1]], function(x) x$name == input$data_frame))]]
df2 <- list_of_lists[[2]][[which(sapply(list_of_lists[[2]], function(x) x$name == input$data_frame))]]

# Calculate means for the second column
mean_df1 <- mean(df1[[2]])  # Assuming the second column is the one of interest
mean_df2 <- mean(df2[[2]])  # Assuming the second column is the one of interest

# Create a data frame to display means
mean_data <- data.frame(
  List1_Mean = mean_df1,
  List2_Mean = mean_df2
)

# Add row names
row.names(mean_data) <- "Mean"

return(mean_data)

})
}

shinyApp(ui = ui, server = server)

For this code, as a simple example of what my program should be, the steps should be like this:

  1. Sidebar Selection:
  • Use selectInput in the sidebar layout to allow the user to select a data frame name.
  • Populate the choices with unique names of data frames from both lists.
  1. Data Retrieval:
  • Upon selection, search for the selected data frame name in both lists.
  • Retrieve the corresponding data frames if found.
  1. Mean Calculation:
  • If both data frames are found:
    • Calculate the mean of the second column of each data frame.
  1. Display in Summary Table:
  • Create a summary table to display the mean values.
  • Show each mean value in its own column, labeled appropriately for the list it was calculated from.

Please note that the code provided by ChatGPT is not functioning properly, and I'm unable to find any alternative examples that might perform better than this.

I fixed your chatgpt example

library(shiny)

# Assuming you have already defined list_of_lists
list_1 <- list(
  df1 = data.frame(x = rnorm(100), y = rnorm(100)),
  df2 = data.frame( x = rnorm(100), y = rnorm(100))
)

list_2 <- list(
  df1 = data.frame(x = rnorm(100), y = rnorm(100)),
  df2 = data.frame(x = rnorm(100), y = rnorm(100))
)

list_of_lists <- list(list_1, list_2)

# Extract unique names from both lists combined
df_names <- unique(unlist(lapply(list_of_lists,names)))

# UI
ui <- fluidPage(
  titlePanel("Basic Data Explorer"),
  
  sidebarLayout(
    sidebarPanel(
      selectInput("data_frame", "Choose a Data Frame", choices = df_names)
    ),
    
    mainPanel(
      tableOutput("mean_table")
    )
  )
)

# Server
server <- function(input, output) {
  
  # Render mean table
  output$mean_table <- renderTable({
    req(input$data_frame)
    
    # Extract the selected data frame from both lists
    df1 <- list_of_lists[[1]][[input$data_frame]]
    df2 <- list_of_lists[[2]][[input$data_frame]]
    
    # Calculate means for the second column
    mean_df1 <- mean(df1[[2]])  # Assuming the second column is the one of interest
    mean_df2 <- mean(df2[[2]])  # Assuming the second column is the one of interest
    
    # Create a data frame to display means
    mean_data <- data.frame(
      List1_Mean = mean_df1,
      List2_Mean = mean_df2
    )
    
    # Add row names
    row.names(mean_data) <- "Mean"
    
    return(mean_data)
  })
}

shinyApp(ui = ui, server = server)
1 Like

Thank you very much, I will study it and I will try to build my program aobve the concept of this code.

I have adjusted the code as I wanted it to be, but I am still encountering problems when running it, and I can't figure out why. As I mentioned, I am just starting with R Shiny, so I apologize if the mistakes seem naive.

library(shiny)
library(ggplot2)
library(gridExtra)

obs_15_23 <- list(
  df1 = data.frame(x = rnorm(100), y = rnorm(100)),
  df2 = data.frame( x = rnorm(100), y = rnorm(100)),
 df3 = data.frame( x = rnorm(100), y = rnorm(100)),
.
.
.
df115 = data.frame( x = rnorm(100), y = rnorm(100))
)

mod_245_15_23 <- list(
  df1 = data.frame(x = rnorm(100), y = rnorm(100)),
  df2 = data.frame( x = rnorm(100), y = rnorm(100)),
 df3 = data.frame( x = rnorm(100), y = rnorm(100)),
.
.
.
df115 = data.frame( x = rnorm(100), y = rnorm(100))
)

cas1_245 <- list(
  df1 = data.frame(x = rnorm(100), y = rnorm(100)),
  df2 = data.frame( x = rnorm(100), y = rnorm(100)),
 df3 = data.frame( x = rnorm(100), y = rnorm(100)),
.
.
.
df115 = data.frame( x = rnorm(100), y = rnorm(100))
)

cas2_245 <- list(
  df1 = data.frame(x = rnorm(100), y = rnorm(100)),
  df2 = data.frame( x = rnorm(100), y = rnorm(100)),
 df3 = data.frame( x = rnorm(100), y = rnorm(100)),
.
.
.
df115 = data.frame( x = rnorm(100), y = rnorm(100))
)

cas3_245 <- list(
  df1 = data.frame(x = rnorm(100), y = rnorm(100)),
  df2 = data.frame( x = rnorm(100), y = rnorm(100)),
 df3 = data.frame( x = rnorm(100), y = rnorm(100)),
.
.
.
df115 = data.frame( x = rnorm(100), y = rnorm(100))
)

cas4_245 <- list(
  df1 = data.frame(x = rnorm(100), y = rnorm(100)),
  df2 = data.frame( x = rnorm(100), y = rnorm(100)),
 df3 = data.frame( x = rnorm(100), y = rnorm(100)),
.
.
.
df115 = data.frame( x = rnorm(100), y = rnorm(100))
)

cas5_245 <- list(
  df1 = data.frame(x = rnorm(100), y = rnorm(100)),
  df2 = data.frame( x = rnorm(100), y = rnorm(100)),
 df3 = data.frame( x = rnorm(100), y = rnorm(100)),
.
.
.
df115 = data.frame( x = rnorm(100), y = rnorm(100))
)

list_of_lists <- list(obs_15_23, mod_245_15_23, cas1_245, cas2_245, cas3_245,cas4_245, cas5_245)

# Extract unique names from both lists combined
df_names <- unique(unlist(lapply(list_of_lists,names)))

# UI
ui <- fluidPage(
  titlePanel("Basic Data Explorer"),
  
  sidebarLayout(
    sidebarPanel(
      selectInput("data_frame", "Choose a Data Frame", choices = df_names)
    ),
    
    sliderInput(inputId = "bins", 
                label = "Number of bins:",
                min = 1,
                max = 100,
                value = 30),
    actionButton("submit", "Submit")
  ),
    
    mainPanel(
      plotOutput(outputId = "distPlot"),
      tableOutput("static_table")
    )
  )


# Server
server <- function(input, output) {
  observeEvent(input$submit, {
    output$distPlot <- renderPlot({
      req(input$data_frame)
      
      x_obs = list_of_lists[[1]][[input$data_frame]][[2]]
      x_mod = mod_245_15_23[[2]][[input$data_frame]][[2]]
      x_cas1 = cas1_245[[3]][[input$data_frame]][[2]]
      x_cas2 = cas2_245[[4]][[input$data_frame]][[2]]
      x_cas3 = cas3_245[[5]][[input$data_frame]][[2]]
      x_cas4 = cas4_245[[6]][[input$data_frame]][[2]]
      x_cas5 = cas5_245[[7]][[input$data_frame]][[2]]
      
      histogram_case1 <- generate_histogram(x_obs, x_mod, x_cas1, "Case 1")
      histogram_case2 <- generate_histogram(x_obs, x_mod, x_cas2, "Case 2")
      histogram_case3 <- generate_histogram(x_obs, x_mod, x_cas3, "Case 3")
      histogram_case4 <- generate_histogram(x_obs, x_mod, x_cas4, "Case 4")
      histogram_case5 <- generate_histogram(x_obs, x_mod, x_cas5, "Case 5")
      
      grid.arrange(histogram_case1, histogram_case2, histogram_case3, histogram_case4, histogram_case5, ncol = 3)
      

    })
    static_results <- static_function(obs_15_23, mod_245_15_23, cas1_245, cas2_245, cas3_245,cas4_245, cas5_245 )
    result_summary <- static_results[[input$data_frame]]
    
    output$static_table <- renderTable({
      (result_summary)
    })
    
  })

 
}

shinyApp(ui = ui, server = server)

what you've shared back is not in principle reproducible, you have private functions that we can't run generate_histogram static_function and you've written unexecutable code when you define
example data i.e.

obs_15_23 <- list(
df1 = data.frame(x = rnorm(100), y = rnorm(100)),
df2 = data.frame( x = rnorm(100), y = rnorm(100)),
df3 = data.frame( x = rnorm(100), y = rnorm(100)),
.
.
.
df115 = data.frame( x = rnorm(100), y = rnorm(100))
)

There are ways to produce the desired simulated datasets programatically (to reduce repetative typing) , in base R this would be via *apply family functions like lapply, or map from purrr package. but given that you were content to leave them out, simply leaving them out might be preferred.

I can help you directly in two areas

  1. the UI code was improperly structured. all 3 of selectinput/"data_frame" , sliderInput "bins" and actionbutton("submit") want to be inside sidebarPanel, and they werent. and mainpanel was outside of the sidebar layout. This mean that your code would not start the app when I tried. The corrected UI would be
ui <- fluidPage(
  titlePanel("Basic Data Explorer"),
  
  sidebarLayout(
    sidebarPanel(
      selectInput("data_frame", "Choose a Data Frame", choices = df_names),
      sliderInput(inputId = "bins", 
                  label = "Number of bins:",
                  min = 1,
                  max = 100,
                  value = 30),
      actionButton("submit", "Submit")
    ),
    mainPanel(
      plotOutput(outputId = "distPlot"),
      tableOutput("static_table")
    )
  )
)
  1. its generally not appropriate to have output$-render* definitions triggered by observeEvent's, it can be made to work, but is consiered an antipattern.
    The output$-render* constructions are themselves formulas for generating content based on required inputs being available/changed, so wrapping them inside of larger structures that would restate them is inelegant and prone to issues.

I learnt shiny from the book https://mastering-shiny.org/ ; I would recommend it if you havent come across it yet.

Thank you very much, for the help in coding and for the reference, I am using it now.

I successfully built a prototype that visualizes histograms for two variables with corresponding summary tables, dynamically selected from sidebars. When transitioning to my actual project, I faced a daunting task. My dataset comprises 13 lists, each containing 115 data frames with pairs of variables. Now, I'm grappling with the problem of implementing a single slider input to select one variable name from the 115 available across all lists.

violet had an issue involving 13 and 115, and so does 'CollinFord', what are the odds ? :smiley:
Is this the prelude to a spam campaign ? :thinking: