Hello!
I am making a shiny app so I can look through my data easily. I have made one and it works, but it's my first and it could definitely be better looking and more efficient.
My objective is to have three dropdown lists with the same markers, allowing me to select three different markers and display the associated box plots and ANOVA results.
Currently, if you run my code, the graphs are stacked vertically. I'd prefer to organize them in a grid, which I find more visually appealing and easier to interpret in conjunction with the ANOVA results. It would also stop me having to scroll up to the menu to change the drop down, and have it all in a single visual page
Also, it would be great to visually distinguish the dropdown lists based on whether the selected prefix is "cat," "dog," or "rabbit."
Lastly, instead of having a line underneath the graph, I'd like to include a subtitle on each graph with the ANOVA results.
Totally open to any and all suggestions, and I know my code is mega repetitive...
Thank you!!
# Load Packages
library(shiny)
library(dplyr)
library(ggplot2)
library(stringr)
library(lme4)
library(lmerTest)
# Create a data frame
fulldf <- data.frame(
ID = rep(1:100, each = 4), # Repeat each ID four times
dog_weight_raw = runif(400, min = 5, max = 30),
dog_size_raw = runif(400, min = 10, max = 50),
dog_width_raw = runif(400, min = 5, max = 20),
cat_whiskers_raw = runif(400, min = 0, max = 10),
cat_length_raw = runif(400, min = 20, max = 60),
cat_weight_raw = runif(400, min = 2, max = 8),
cat_class_raw = runif(400, min = 20, max = 80),
cat_breed_log10 = runif(400, min = 2, max = 8),
cat_size_log10 = runif(400, min = 54, max = 200),
rabbit_height_log10 = runif(400, min = 10, max = 30),
rabbit_length_log10 = runif(400, min = 15, max = 40),
timepoint = rep(1:4, each = 100) # Repeat timepoints 1, 2, 3, 4 for all IDs
)
fulldf$timepoint<-as.factor(fulldf$timepoint)
# make a marker list
markers <- names(df)[grep("log10$|_raw$", names(df))]
# sort markers
markers <- sort(markers)
######################################### UI #############################################
ui <- fluidPage(
titlePanel("Marker Boxplots"), #Sets the title of the Shiny app
sidebarLayout(
sidebarPanel( #Sidebar inputs
selectInput(
inputId = "markerselect1", # ID of the first selectInput
label = "Select a marker:", # Label for the first selectInput
choices = markers, # Choices for the first selectInput
selected = NULL # Initial selected value for the first selectInput
),
selectInput(
inputId = "markerselect2", # ID of the second selectInput
label = "Select a column:", # Label for the second selectInput
choices = markers, # Choices for the second selectInput
selected = NULL # Initial selected value for the second selectInput
),
selectInput(
inputId = "markerselect3", # ID of the third selectInput
label = "Select a column:", # Label for the third selectInput
choices = markers, # Choices for the third selectInput
selected = NULL # Initial selected value for the third selectInput
),
width = 3 #Width of the sidebar panel
),
mainPanel( # Contains the main panel outputs
plotOutput(outputId = "marker1_boxplot"),
textOutput(outputId = "marker1_anova_result"),
plotOutput(outputId = "marker2_boxplot"),
textOutput(outputId = "marker2_anova_result"),
plotOutput(outputId = "marker3_boxplot"),
textOutput(outputId = "marker3_anova_result")
)
)
)
######################################### SERVER #############################################
server <- function(input, output) {
# Function to select and filter data and run an ANOVA
compute_model <- function(df, column_name) {
filtered_df <- df %>%
select(timepoint, ID, !!sym(column_name)) %>%
filter(!is.na(.[[column_name]]) & is.finite(.[[column_name]])) # Filter the data, removing rows with NA or infinite values
# Perform linear mixed-effects regression and calculate ANOVA
lmer_model <- lmer(formula = as.formula(paste(column_name, "~ timepoint + (1 | ID)")), data = filtered_df)
anova_result <- anova(lmer_model, type = "III")
p_value <- formatC(anova_result[["Pr(>F)"]][1], format = "f", digits = 5) # Format the p-value
p_value_display <- ifelse(as.numeric(p_value) < 0.05, paste0(p_value, "*"), p_value) # Add asterisk if p-value is significant
textual_result <- paste("Repeated Measures ANOVA p-value:", p_value_display)
results <- list(
lmer_model = lmer_model,
anova_result = anova_result,
p_value = p_value,
p_value_display = p_value_display,
textual_result = textual_result
)
return(results)
}
# Run the function on marker 1
output$marker1_anova_result <- renderText({
selected_marker <- input$markerselect1
selected_column_name <- paste0(selected_marker)
model_stuff <- compute_model(fulldf, column_name = selected_column_name)
return(model_stuff$textual_result)
})
# Run the function on marker 2
output$marker2_anova_result <- renderText({
selected_marker <- input$markerselect2
selected_column_name <- paste0(selected_marker)
model_stuff <- compute_model(fulldf, column_name = selected_column_name)
return(model_stuff$textual_result)
})
# Run the function on marker 3
output$marker3_anova_result <- renderText({
selected_marker <- input$markerselect3
selected_column_name <- paste0(selected_marker)
model_stuff <- compute_model(fulldf, column_name = selected_column_name)
return(model_stuff$textual_result)
})
# Function to make boxplot
plot_boxplot <- function(df, column_name) {
ggplot(data = df, aes(x = timepoint, y = .data[[column_name]], color = timepoint)) +
geom_boxplot() +
labs(x = "timepoint", y = column_name) +
theme_classic()
}
# Run boxplot function on marker 1
output$marker1_boxplot <- renderPlot({
selected_marker <- input$markerselect1
selected_column_name <- paste0(selected_marker)
plot_stuff <- plot_boxplot(fulldf, column_name = selected_column_name)
print(plot_stuff)
})
# Run boxplot function on marker 2
output$marker2_boxplot <- renderPlot({
selected_marker <- input$markerselect2
selected_column_name <- paste0(selected_marker)
plot_stuff <- plot_boxplot(fulldf, column_name = selected_column_name)
print(plot_stuff)
})
# Run boxplot function on marker 3
output$marker3_boxplot <- renderPlot({
selected_marker <- input$markerselect3
selected_column_name <- paste0(selected_marker)
plot_stuff <- plot_boxplot(fulldf, column_name = selected_column_name)
print(plot_stuff)
})
}
######################################### Run the app! #############################################
shinyApp(ui = ui, server = server)