I'm creating a small shiny app to look at survival analysis for insect mortality. It's aim is to produce a model selection table for the analysis and then a Kaplan-Meier plot with fitted survival curves. I've attached here a pared-down version of the app with simple data upload, model selection and plot generation but I continually get the message 'Error: object 'input' not found'.
I'm new to shiny and struggling with the reactive elements but I've managed to produce the wrong sort of plot elsewhere so it's clearly an issue with the packages I'm using, how I'm using them or what's being called where.
Please help!
Edit: I should mention that the app takes a .csv file with 'Individual', 'Treatment', 'Dose', 'Time', 'Status'. Treatment and Dose are both factorised and status is binary - 1 (when fate known), 0 for unknown at that time point. The plot works in the regular R script!
# Load necessary libraries
library(shiny)
library(survival)
library(AICcmodavg)
library(tidyr)
library(survminer)
# Define the User Interface
ui <- fluidPage(
# Application title
titlePanel("Survival Analysis Plot"),
# Layout with sidebar and main panel
sidebarLayout(
sidebarPanel(
# File input for uploading CSV file
fileInput("file", "Upload CSV File", accept = c(".csv")),
# Dropdown to select the model
selectInput("model_select", "Select Model:", choices = NULL)
),
mainPanel(
# Output plot for survival analysis
plotOutput("survivalPlot")
)
)
)
# Define the server logic
server <- function(input, output, session) {
# Reactive expression to read and process the uploaded CSV file
surv_data <- reactive({
req(input$file) # Ensure file is uploaded
data <- read.csv(input$file$datapath) # Read the CSV file
data$Group <- paste(data$Treatment, data$Dose, sep = "_") # Create a new 'Group' variable
return(data) # Return the processed data
})
# Observe changes in surv_data and update model choices
observe({
req(surv_data()) # Ensure surv_data is available
updateSelectInput(session, "model_select", choices = c("Treatment x Dose", "Treatment + Dose", "Treatment", "Dose"))
})
# Reactive expression to get the selected model
selected_model <- reactive({
req(surv_data()) # Ensure surv_data is available
surv <- surv_data() # Get the survival data
# Fit different models based on the input selection
surv_T_x_D <- survreg(Surv(Time, Status) ~ Treatment * Dose, data = surv)
surv_T_D <- survreg(Surv(Time, Status) ~ Treatment + Dose, data = surv)
surv_T <- survreg(Surv(Time, Status) ~ Treatment, data = surv)
surv_D <- survreg(Surv(Time, Status) ~ Dose, data = surv)
# Store models in a list with names
models <- list(surv_T_x_D, surv_T_D, surv_T, surv_D)
names(models) <- c("Treatment x Dose", "Treatment + Dose", "Treatment", "Dose")
# Return the selected model
models[[input$model_select]]
})
# Render the survival plot
output$survivalPlot <- renderPlot({
surv <- surv_data() # Get the survival data
model <- selected_model() # Get the selected model
# Predict quantiles from the model
pred <- data.frame(predict(model, type = "quantile", p = seq(0.01, 0.99, by = 0.01)))
pred$Group <- surv$Group # Add Group variable to predictions
pred$Treatment <- surv$Treatment # Add Treatment variable to predictions
pred$Dose <- surv$Dose # Add Dose variable to predictions
# Initialize an array for predicted values
pred2 <- array(dim = c(nlevels(as.factor(surv$Treatment)) * nlevels(as.factor(surv$Dose)), ncol(pred)))
for (i in 1:ncol(pred2)) {
pred2[, i] <- tapply(pred[, i], pred$Group, unique) # Apply tapply to group predictions
}
y_val <- seq(0.99, 0.01, by = -0.01) # Define y values
pred2 <- data.frame(t(pred2[, 1:length(y_val)]), y_val) # Transform predictions to dataframe
pred2_long <- gather(pred2, key = "Group", value = "time", -y_val) # Gather predictions into long format
pred2_long$time <- as.numeric(pred2_long$time) # Convert time to numeric
pred2_long$Group <- rep(levels(as.factor(surv$Group)), each = length(y_val)) # Repeat Group levels
pred2_long$Treatment <- rep(rep(levels(as.factor(surv$Treatment)), each = length(y_val)), nlevels(as.factor(surv$Dose))) # Repeat Treatment levels
pred2_long$Dose <- rep(rep(levels(as.factor(surv$Dose)), each = length(y_val) * nlevels(as.factor(surv$Treatment)))) # Repeat Dose levels
pred2_long <- na.omit(pred2_long) # Remove NA values
# Plot the survival analysis using survminer
plot_surv <- ggsurvplot(fit = survfit(Surv(Time, Status) ~ Treatment + Dose, data = surv), conf.int = FALSE, col = "Dose")
# Add predicted lines to the plot
plot_surv$plot +
geom_line(data = pred2_long, aes(x = time, y = y_val, group = Group, colour = Dose), size = 0.75, alpha = 0.8) +
xlab("Time (hours)") +
facet_grid(~Treatment) +
theme_bw()
}, {
surv_data() # Pass the reactive object to renderPlot
})
}
# Run the Shiny application
shinyApp(ui = ui, server = server)