Search code examples
shinyrstudioggvis

Error in match.arg(position) : 'arg' must be NULL or a character vector


I am trying to develop a shiny app where there are data inputs on multiple tabs. The content under each tab works fine on its own however when i attempt to combine them into one app I continue to get this error. Error in match.arg(position) : 'arg' must be NULL or a character vector. My code is as follows:

library(shiny)
library(shinydashboard)
library(ggvis)
sidebar <- dashboardSidebar(
  hr(),
  sidebarMenu(id="tabs",
              menuItem("Import Data", tabName = "Import", icon=icon("list-alt")),
              menuItem("Bivariate Regression", tabName="Bivariate Regression", icon=icon("line-chart")),
              menuItem("Contingency", tabName = "Contingency", icon = icon("table"))
  ))

  body <- dashboardBody(
    tabItems(      
      tabItem(tabName= "Import",
              sidebarLayout(
                sidebarPanel(
                  fileInput("file","Upload the file"), 
                  tags$hr(),
                  h5(helpText("Select the table parameters below")),
                  checkboxInput(inputId = 'header', label= 'Header', value= TRUE),
                  checkboxInput(inputId = "stringsAsFactors", "stringsAsFactors", FALSE),
                  br(),
                  radioButtons(inputId = 'sep', label = 'Seperator', choices = c(Comma=',', Semicolon=';', Tab='\t', Space= ' '), selected= ',')
                ),
                mainPanel(
                  uiOutput("tb")
                )
              )),

      tabItem(tabName= "Bivariate Regression",
              sidebarLayout(
                div(),
                sidebarPanel(
                  fileInput('datfile', ''),
                  selectInput('x', 'x:' ,'x'),
                  selectInput('y', 'y:', 'y'),
                  uiOutput("plot_ui")
                ),
                mainPanel(
                  titlePanel("Plot Output"),
                  ggvisOutput("plot")
                )
              ))
    ))


dashboardPage(
 dashboardHeader(title = "COBE Dashboard"),
  sidebar,
  body)

and server

library(shiny)
library(dplyr)
library(ggvis)
shinyServer(function(input, output){   
  #read the data and give import prefrences  
  data <- reactive({
    file1 <- input$file
    if(is.null(file1)){return()}
    read.table(file=file1$datapath, sep= input$sep, header= input$header, stringsAsFactors= input$stringsAsFactors)
  })

  # display summary of table output
  output$filledf <-renderTable({
    if(is.null(data())){return ()}
    input$file
  })

  output$sum <- renderTable({
    if(is.null(data())){return ()}
    summary(data())

  })
  output$table <- renderTable({
    if(is.null(data())){return ()}
    data()

  })

  #generate tabsets when the file is loaded. 
  output$tb <- renderUI({
    if(is.null(data()))
      h2("App powered by", tags$img(src='Blue.png', height= 100, width=250))
    else
      tabsetPanel(tabPanel("About file", tableOutput("filledf")), tabPanel("Data", tableOutput("table")), tabPanel("Summary", tableOutput("sum")))
  })
########## Data import end #########

    ########## Bivariate regression begin ###########
    #load the data when the user inputs a file
  theData <- reactive({
    infile <- input$datfile        
    if(is.null(infile))
      return(NULL)        
    d <- read.csv(infile$datapath, header = T)
    d        
  })

  # dynamic variable names
  observe({
    data<-theData()
    updateSelectInput(session, 'x', choices = names(data))
    updateSelectInput(session, 'y', choices = names(data))

  }) # end observe

  #gets the y variable name, will be used to change the plot legends
  yVarName<-reactive({
    input$y
  })

  #gets the x variable name, will be used to change the plot legends
  xVarName<-reactive({
    input$x
  })

  #make the filteredData frame

  filteredData<-reactive({
    data<-isolate(theData())
    #if there is no input, make a dummy dataframe
    if(input$x=="x" && input$y=="y"){
      if(is.null(data)){
        data<-data.frame(x=0,y=0)
      }
    }else{
      data<-data[,c(input$x,input$y)]
      names(data)<-c("x","y")
    }
    data
  })

  #plot the ggvis plot in a reactive block so that it changes with filteredData
  vis<-reactive({
    plotData<-filteredData()
    plotData %>%
      ggvis(~x, ~y) %>%
      layer_points() %>%
      add_axis("y", title = yVarName()) %>%
      add_axis("x", title = xVarName()) %>%
      add_tooltip(function(df) format(sqrt(df$x),digits=2))
  })
  vis%>%bind_shiny("plot", "plot_ui")

 ##### add contingency table ########
  # display contingcy table output
  output$foo <- renderTable({
    if(is.null(data())){return ()}
    as.data.frame.matrix(table((data())))
  })

})

Solution

  • There is an extra div() element in the second tabItem in tabItems in ui.R. Either provide an argument you implied to or remove that div() element. Also, I have added session argument to the shinyServer() function in server.R. After these changes app is running without any errors.

    EDIT :

    You forgot to add one more tabItem for Contingency in tabItems() function. Also, it is always better to differentiate between tabName and the title for that tab. And there should be no spaces in the tab name as per my experience, that is the reason why Bivariate Regression tab was not working before. It should work fine now.

    Updated code:

    ui.R

    library(shiny)
    library(shinydashboard)
    library(ggvis)
    sidebar <- dashboardSidebar(
      br(),
      sidebarMenu(id="tabs",
                  menuItem("Import Data", tabName = "import", icon=icon("list-alt")),
                  menuItem("Bivariate Regression", tabName="bivariate_regression", icon=icon("line-chart")),
                  menuItem("Contingency", tabName = "contingency", icon = icon("table"))
      ))
    
    body <- dashboardBody(
      tabItems(      
        tabItem(tabName= "import",
                sidebarLayout(
                  sidebarPanel(
                    fileInput("file","Upload the file"), 
                    tags$hr(),
                    h5(helpText("Select the table parameters below")),
                    checkboxInput(inputId = 'header', label= 'Header', value= TRUE),
                    checkboxInput(inputId = "stringsAsFactors", "stringsAsFactors", FALSE),
                    br(),
                    radioButtons(inputId = 'sep', label = 'Seperator', choices = c(Comma=',', Semicolon=';', Tab='\t', Space= ' '), selected= ',')
                  ),
                  mainPanel(
                    uiOutput("tb")
                  )
                )),
    
        tabItem(tabName= "bivariate_regression",
                sidebarLayout(
                  #div(),
                  sidebarPanel(
                    fileInput('datfile', ''),
                    selectInput('x', 'x:' ,'x'),
                    selectInput('y', 'y:', 'y'),
                    uiOutput("plot_ui")
                  ),
                  mainPanel(
                    titlePanel("Plot Output"),
                    ggvisOutput("plot")
                  )
                )),
        tabItem(tabName="contingency", h2("Contigency Tab content"))
      ))
    
    
    dashboardPage(
      dashboardHeader(title = "COBE Dashboard"),
      sidebar,
      body)
    

    server.R

    library(shiny)
    library(dplyr)
    library(ggvis)
    shinyServer(function(input, output,session){   
      #read the data and give import prefrences  
      data <- reactive({
        file1 <- input$file
        if(is.null(file1)){return()}
        read.table(file=file1$datapath, sep= input$sep, header= input$header, stringsAsFactors= input$stringsAsFactors)
      })
    
      # display summary of table output
      output$filledf <-renderTable({
        if(is.null(data())){return ()}
        input$file
      })
    
      output$sum <- renderTable({
        if(is.null(data())){return ()}
        summary(data())
    
      })
      output$table <- renderTable({
        if(is.null(data())){return ()}
        data()
    
      })
    
      #generate tabsets when the file is loaded. 
      output$tb <- renderUI({
        if(is.null(data()))
          h2("App powered by", tags$img(src='Blue.png', height= 100, width=250))
        else
          tabsetPanel(tabPanel("About file", tableOutput("filledf")), tabPanel("Data", tableOutput("table")), tabPanel("Summary", tableOutput("sum")))
      })
      ########## Data import end #########
    
      ########## Bivariate regression begin ###########
      #load the data when the user inputs a file
      theData <- reactive({
        infile <- input$datfile        
        if(is.null(infile))
          return(NULL)        
        d <- read.csv(infile$datapath, header = T)
        d        
      })
    
      # dynamic variable names
      observe({
        data<-theData()
        updateSelectInput(session, 'x', choices = names(data))
        updateSelectInput(session, 'y', choices = names(data))
    
      }) # end observe
    
      #gets the y variable name, will be used to change the plot legends
      yVarName<-reactive({
        input$y
      })
    
      #gets the x variable name, will be used to change the plot legends
      xVarName<-reactive({
        input$x
      })
    
      #make the filteredData frame
    
      filteredData<-reactive({
        data<-isolate(theData())
        #if there is no input, make a dummy dataframe
        if(input$x=="x" && input$y=="y"){
          if(is.null(data)){
            data<-data.frame(x=0,y=0)
          }
        }else{
          data<-data[,c(input$x,input$y)]
          names(data)<-c("x","y")
        }
        data
      })
    
      #plot the ggvis plot in a reactive block so that it changes with filteredData
      vis<-reactive({
        plotData<-filteredData()
        plotData %>%
          ggvis(~x, ~y) %>%
          layer_points() %>%
          add_axis("y", title = yVarName()) %>%
          add_axis("x", title = xVarName()) %>%
          add_tooltip(function(df) format(sqrt(df$x),digits=2))
      })
      vis%>%bind_shiny("plot", "plot_ui")
    
      ##### add contingency table ########
      # display contingcy table output
      output$foo <- renderTable({
        if(is.null(data())){return ()}
        as.data.frame.matrix(table((data())))
      })
    
    })