'data' must be 2-dimensional (e.g. data frame or matrix) RShiny

dt

#1

I am working on a Shiny App and came across an error message saying that the data needs to be 2-dimensional.

The aim of this app is to filter a data set based on a column called region and view and updated data set. Should be simple... Though, the user needs to upload the data set first in order to use the app. I am assuming that all files used within this application will have a column namely "region". I believe the issue is at "# Select regions to print ----".

UI:

 library(shiny)
 library(DT)
 library(tidyverse)

 # Define UI for data upload app ----
 ui <- fluidPage(

   # App title ----
   titlePanel(title = h1("Upload file and select columns", align = "center")),

   # Sidebar layout with input and output definitions ----
   sidebarLayout(

     # Sidebar panel for inputs ----
     sidebarPanel(

       # Input: Select a file ----
       fileInput("uploaded_file", "Choose CSV File",
                 multiple = TRUE,
                 accept = c("text/csv",
                            "text/comma-separated-values,text/plain",
                            ".csv")),

       # Horizontal line ----
       tags$hr(),

       # Input: Checkbox if file has header ----
       checkboxInput("header", "Header", TRUE),

       # Input: Select separator ----
       radioButtons("sep", "Separator",
                    choices = c(Semicolon = ";",
                                Comma = ",",
                                Tab = "\t"),
                    selected = ","),


       # Horizontal line ----
       tags$hr(),

       # Input: Select number of rows to display ----
       radioButtons("disp", "Display",
                    choices = c(All = "all",
                                Head = "head"),
                    selected = "all"),

       # Select variables to display ----
  # uiOutput("variables"),

       # Select variables to display ----
       uiOutput("regions")

     ),

     # Main panel for displaying outputs ----
     mainPanel(

       tabsetPanel(
         id = "dataset",
         tabPanel("Data Explorer", div(style = "overflow-x: scroll",dataTableOutput("rendered_file")))
       )
     )

   )
 )

Server:

# Define server logic to read selected file ----
server <- function(input, output, session) {

  # Read file ----
  df <- reactive({
    req(input$uploaded_file)
    read.csv(input$uploaded_file$datapath,
             header = input$header,
             sep = input$sep)  

  })

  output$regions <- renderUI({
    selectizeInput(inputId = "select_region", 
                   label = "Select region of interest", 
                   choices = unique(df()$region),
                   multiple = T, 
                   options = list(placeholder = 'Select the region of interest'))
  })

  # Select regions to print ----
  df_sel <- reactive({
    req(input$select_region)
    df_sel <- df()$region == input$select_region

  })


  # Print data table ----  
  output$rendered_file <- DT::renderDataTable({
    if(input$disp == "head") {
      head(df_sel())
    }
    else {
      df_sel()
    }
  })

}

#2

Hi! Welcome!

You're right about the source of the error. If you test the line of code that defines df_sel outside of shiny (simulating the shiny conditions as much as possible), you'll see what the problem is:

set.seed(42)

df <- data.frame(
  region = c(NA, sample(c("Region 1", "Region 2", "Region 3", "Region 4"), size = 49, replace = TRUE)), 
  x = c(NA, runif(49, 1, 20)),
  stringsAsFactors = FALSE
)

input <- list(
  select_region = "Region 1"
)

# This produces a 1d vector of logical values, not a filtered data frame
df$region == input$select_region
#>  [1]    NA FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE
#> [12] FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE
#> [23]  TRUE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
#> [34] FALSE FALSE  TRUE FALSE  TRUE  TRUE FALSE FALSE FALSE FALSE  TRUE
#> [45] FALSE FALSE FALSE FALSE FALSE FALSE

Created on 2018-07-05 by the reprex package (v0.2.0).

Here are two ways to do what you want, a base R method and a tidyverse method:

# base R
df[df$region == input$select_region, ]
#>      region         x
#> NA     <NA>        NA
#> 9  Region 1 13.868260
#> 19 Region 1  6.154446
#> 23 Region 1  1.816787
#> 26 Region 1 10.108573
#> 36 Region 1 13.267006
#> 38 Region 1 11.709290
#> 39 Region 1  5.440365
#> 44 Region 1  1.004539

# tidyverse
df %>% dplyr::filter(region == input$select_region)
# without pipe: dplyr::filter(df, region == input$select_region)
#>     region         x
#> 1 Region 1 13.868260
#> 2 Region 1  6.154446
#> 3 Region 1  1.816787
#> 4 Region 1 10.108573
#> 5 Region 1 13.267006
#> 6 Region 1 11.709290
#> 7 Region 1  5.440365
#> 8 Region 1  1.004539

You'll notice that the two methods differ slightly in their handling of row numbers and NA values in the filtering variable, so choose the one that suits your situation and preferences best.