I am new to shinymodule and trying to modulize this reproducible shiny framework, with no success. I am trying to have 3 different modules, that communicate with each other. Here is the reproducible app without the modules.
library(shiny)
library(datasets)
ui <- shinyUI(fluidPage(
titlePanel("Column Plot"),
tabsetPanel(
tabPanel("Upload File",
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Choose CSV File',
accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv')),
tags$br(),
checkboxInput('header', 'Header', TRUE),
radioButtons('sep', 'Separator',
c(Comma=',',
Semicolon=';',
Tab='\t'),
','),
radioButtons('quote', 'Quote',
c(None='',
'Double Quote'='"',
'Single Quote'="'"),
'"')
),
mainPanel(
tableOutput('contents')
)
)
),
tabPanel("First Tab",
pageWithSidebar(
headerPanel('My First Plot'),
sidebarPanel(
selectInput('xcol', 'X Variable', ""),
selectInput('ycol', 'Y Variable', "", selected = "")
),
mainPanel(
plotOutput('MyPlot')
)
)
),
tabPanel("second Tab",
sidebarLayout(
sidebarPanel(
fluidRow(
selectInput(
"disp",
"Display",
choices = c(
Summary = "summary",
Structure = "str",
dimension = "dimension"
),
selected = " "
)
)
),
mainPanel(
verbatimTextOutput("summaryy")
)
)
)
)
)
)
server <- shinyServer(function(input, output, session) {
data <- reactive({
req(input$file1)
inFile <- input$file1
df <- read.csv(inFile$datapath, header = input$header, sep = input$sep,
quote = input$quote)
updateSelectInput(session, inputId = 'xcol', label = 'X Variable',
choices = names(df), selected = names(df))
updateSelectInput(session, inputId = 'ycol', label = 'Y Variable',
choices = names(df), selected = names(df)[2])
return(df)
})
output$contents <- renderTable({
data()
})
output$MyPlot <- renderPlot({
x <- data()[, c(input$xcol, input$ycol)]
plot(x)
})
output$summaryy <- renderPrint({
if (input$disp == "summary"){
return(summary(data()))
} else if (input$disp == "str"){
return(str(data()))
} else if (input$disp == "dimension"){
return(dim(data()))
}
else{
return()
}
})
})
shinyApp(ui, server)
And here is my attempt at modulizing the app, with three different modules, with no success. What should I do so that the modules communicate with each other and also regarding the updateselectInput() function, since, I will have more tabset/other modules that will be dependent to the uploaded data and its variables.
data_upload_Ui <- function(id){
ns <- NS(id)
tabPanel("Upload File",
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput(ns('file1'), 'Choose CSV File',
accept=c('text/csv',
'text/comma-separated-values,text/plain',
'.csv')),
tags$br(),
checkboxInput(ns('header'), 'Header', TRUE),
radioButtons(ns('sep'), 'Separator',
c(Comma=',',
Semicolon=';',
Tab='\t'),
','),
radioButtons(ns('quote'), 'Quote',
c(None='',
'Double Quote'='"',
'Single Quote'="'"),
'"')
),
mainPanel(
tableOutput(ns('contents'))
)
)
)
}
data_upload_Server <- function(id){
moduleServer(id, function(input, output, session){
data <- reactive({
req(input$file1)
inFile <- input$file1
df <- read.csv(inFile$datapath, header = input$header, sep = input$sep,
quote = input$quote)
updateSelectInput(session, inputId = 'xcol', label = 'X Variable',
choices = names(df), selected = names(df))
updateSelectInput(session, inputId = 'ycol', label = 'Y Variable',
choices = names(df), selected = names(df)[2])
return(df)
})
output$contents <- renderTable({
data()
})
}
)
}
#########################
plot_UI <- function(id){
ns <- NS(id)
tabPanel("First Tab",
pageWithSidebar(
headerPanel('My First Plot'),
sidebarPanel(
# "Empty inputs" - they will be updated after the data is uploaded
selectInput(ns('xcol'), 'X Variable', ""),
selectInput(ns('ycol'), 'Y Variable', "", selected = "")
),
mainPanel(
plotOutput(ns('MyPlot'))
)
)
)
}
plot_Server <- function(id){
moduleServer(id, function(input, output, session){
output$MyPlot <- renderPlot({
x <- data()[, c(input$xcol, input$ycol)]
plot(x)
})
}
)
}
###############################################
info_Ui <- function(id){
ns <- NS(id)
tabPanel("second Tab",
sidebarLayout(
sidebarPanel(
fluidRow(
selectInput(ns(
"disp"),
"Display",
choices = c(
Summary = "summary",
Structure = "str",
dimension = "dimension"
),
selected = " "
)
)
),
mainPanel(
verbatimTextOutput(ns("summaryy"))
)
)
)
}
info_Server <- function(id){
moduleServer(id, function(input, output, session){
output$summaryy <- renderPrint({
if (input$disp == "summary"){
return(summary(data()))
} else if (input$disp == "str"){
return(str(data()))
} else if (input$disp == "dimension"){
return(dim(data()))
}
else{
return()
}
})
}
)
}
I wrote this simple function to run the modules, but only the first modules is working. Grateful for all the help.
####################################
run_App <- function(){
ui <- shinyUI(fluidPage(
titlePanel("Column Plot"),
tabsetPanel(
data_upload_Ui("data"),
plot_UI("plot_1"),
info_Ui("info")
)
)
)
server <- function(input, output, session){
data_upload_Server("data")
plot_Server("plot_1")
info_Server("info")
}
shinyApp(ui, server)
}
run_App()
CodePudding user response:
From what I can see you're trying to create one module per tab. The first module will be used to upload a file and will need to "return" that file into de server in order to use it for the remaining two modules.
file upload module:
file_upload_UI <- function(id) {
ns <- NS(id)
tabPanel(
"Upload File",
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput(ns("file1"), "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv"
)
),
tags$br(),
checkboxInput(ns("header"), "Header", TRUE),
radioButtons(
ns("sep"),
"Separator",
c(
Comma = ",",
Semicolon = ";",
Tab = "\t"
),
","
),
radioButtons(
ns("quote"),
"Quote",
c(
None = "",
"Double Quote" = '"',
"Single Quote" = "'"
),
'"'
)
),
mainPanel(
tableOutput(ns("contents"))
)
)
)
}
file_upload_Server <- function(id) {
moduleServer(
id,
function(input, output, session) {
data <- reactive({
req(input$file1)
inFile <- input$file1
df <- read.csv(inFile$datapath,
header = input$header, sep = input$sep,
quote = input$quote
)
return(df)
})
output$contents <- renderTable({
data()
})
# return data
data
}
)
}
Second Page module:
first_page_UI <- function(id) {
ns <- NS(id)
tabPanel(
"First Tab",
titlePanel("My First Plot"),
sidebarPanel(
selectInput(ns("xcol"), "X Variable", ""),
selectInput(ns("ycol"), "Y Variable", "", selected = "")
),
mainPanel(
plotOutput(ns("MyPlot"))
)
)
}
first_page_Server <- function(id, df) {
stopifnot(is.reactive(df))
moduleServer(
id,
function(input, output, session) {
observeEvent(df(), {
updateSelectInput(session,
inputId = "xcol", label = "X Variable",
choices = names(df()), selected = names(df())
)
updateSelectInput(session,
inputId = "ycol", label = "Y Variable",
choices = names(df()), selected = names(df())[2]
)
})
output$MyPlot <- renderPlot({
x <- df()[, c(input$xcol, input$ycol)]
plot(x)
})
}
)
}
Third page module:
second_page_UI <- function(id) {
ns <- NS(id)
tabPanel(
"second Tab",
sidebarLayout(
sidebarPanel(
fluidRow(
selectInput(
ns("disp"),
"Display",
choices = c(
Summary = "summary",
Structure = "str",
dimension = "dimension"
),
selected = " "
)
)
),
mainPanel(
verbatimTextOutput(ns("summaryy"))
)
)
)
}
second_page_Server <- function(id, df) {
moduleServer(
id,
function(input, output, session) {
output$summaryy <- renderPrint({
if (input$disp == "summary") {
return(summary(df()))
} else if (input$disp == "str") {
return(str(df()))
} else if (input$disp == "dimension") {
return(dim(df()))
} else {
return()
}
})
}
)
}
APP:
Notice that file_upload_server
is returning a reactive dataset that will later be used as an argument for the subsequent modules.
library(shiny)
library(datasets)
ui <- shinyUI(fluidPage(
titlePanel("Column Plot"),
tabsetPanel(
file_upload_UI("upload_file"),
first_page_UI("first_page"),
second_page_UI("second_page")
)
))
server <- shinyServer(function(input, output, session) {
upload_data <- file_upload_Server("upload_file")
first_page_Server("first_page", upload_data)
second_page_Server("second_page", upload_data)
})
shinyApp(ui, server)
Example: