1

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()
EnriqueGG
  • 179
  • 1
  • 12
  • 1
    Modules are (or should be) self contained. They only know about other parts of the main app if you tell the module what’s going on elsewhere. Similarly, the main app only knows what’s happening inside a module if the module tells the app what it has done via its return value. You’ve done neither. I will vote to close and point you to an answer which shows you what you need to do in a MWE. You should also read the pages on modules on the RStudio website. – Limey Jul 30 '22 at 14:31
  • 1
    Does this answer your question? [How to update shiny module with reactive dataframe from another module](https://stackoverflow.com/questions/68584478/how-to-update-shiny-module-with-reactive-dataframe-from-another-module) – Limey Jul 30 '22 at 14:31

1 Answers1

1

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:

enter image description here

jpdugo17
  • 6,816
  • 2
  • 11
  • 23