I want to create a modularized Shiny app where one module, dataUpload
, is used to import a CSV and another module, chart
, is used to
- Create dynamic x and y dropdowns based on the column names within the CSV THIS WORKS
- Create a plot based on the selected input$xaxis, input$yaxis This produces the error invalid type/length (symbol/0) in vector allocation
I think the issue is with my reactive ggplot in chart.R and I'd love any help - I added all the info here but I also have a github repo if that's easier I think this could be a really great demo into the world of interacting modules so I'd really appreciate any help!!
App.R
library(shiny)
library(shinyjs)
library(tidyverse)
source("global.R")
ui <-
tagList(
navbarPage(
"TWO MODULES",
tabPanel(
title = "Data",
dataUploadUI("datafile", "Import CSV")
),
tabPanel(
title = "Charts",
chartUI("my_chart")
)
)
)
server <- function(input, output, session) {
datafile <- callModule(dataUpload, "datafile", stringsAsFactors = FALSE)
output$table <- renderTable({ datafile() })
# PASS datafile WITHOUT () INTO THE MODULE
my_chart <- callModule(chart, "my_chart", datafile = datafile)
output$plot <- renderPlot({ my_chart() })
}
shinyApp(ui, server)
dataUpload.R
dataUpload <- function(input, output, session, stringsAsFactors) {
# The selected file, if any
userFile <- reactive({
# If no file is selected, don't do anything
# input$file == ns("file")
validate(need(input$file, message = FALSE))
input$file
})
# The user's data, parsed into a data frame
dataframe <- reactive({
read.csv(userFile()$datapath,
stringsAsFactors = stringsAsFactors)
})
# We can run observers in here if we want to
observe({
msg <- sprintf("File %s was uploaded", userFile()$name)
cat(msg, "\n")
})
# Return the reactive that yields the data frame
return(dataframe)
}
dataUploadUI.R
# The first argument is the id -- the namespace for the module
dataUploadUI <- function(id, label = "CSV file") {
# Create a namespace function using the provided id
#ALL UI FUNCTION BODIES MUST BEGIN WITH THIS
ns <- NS(id)
# Rather than fluidPage use a taglist
# If you're just returning a div you can skip the taglist
tagList(
sidebarPanel(
fileInput(ns("file"), label)),
mainPanel(tableOutput("table"))
)
}
chart.R
I believe this is the file that needs some minor changing in order to have the plot properly render?
chart <- function(input, output, session, datafile = reactive(NULL)) {
# SINCE DATAFILE IS A REACTIVE WE ADD THE PRERENTHESIS HERE
# WHERE/HOW CAN I ACCESS input$xaxis?
# Do I need to use ns? Can you do that in the server side of a module?
output$XAXIS <- renderUI(selectInput("xaxis", "X Axis", choices = colnames(datafile())))
output$YAXIS <- renderUI(selectInput("yaxis", "Y Axis", choices = colnames(datafile())))
# NOT WORKING
# Use the selectInput x and y to plot
p <- reactive({
req(datafile)
# WORKS: ggplot(datafile(), aes(x = Sepal_Length, y = Sepal_Width))
# DOES NOT WORK:
ggplot(datafile(), aes_(x = as.name(input$xaxis), y = as.name(input$yaxis))) +
geom_point()
})
return(p)
}
chartUI.R
chartUI <- function(id, label = "Create Chart") {
ns <- NS(id)
tagList(
sidebarPanel(
uiOutput(ns("XAXIS")),
uiOutput(ns("YAXIS"))
),
mainPanel(plotOutput("plot"))
)
}