Filtering in Shiny - Error in [: NAs not permitted in row index

shiny
leaflet
shinydashboard

#1

Folks, really simple q about simple Shiny app.

I receive a strange error NAs not permitted in row index

Sample data is here

Shapefile is here

# Load packages
library(shiny)
library(rgdal)
library(raster)
library(leaflet)
library(sp)
library(geojsonio)
library(RColorBrewer)
library(jsonlite)
library(shinythemes)

# Global code

# Read file on a local machine
data_pg <- read.csv("pg.csv", header = TRUE, stringsAsFactors = FALSE)

# Read a shapefile
countries <- readOGR(".","ne_50m_admin_0_countries")

# Merge data
data_pg_df <- merge(countries, data_pg, by.x = "NAME", by.y = "Country", duplicateGeoms = TRUE)

# UI code

ui <- fluidPage(theme = shinytheme("united"),
            titlePanel("PG Map"),
            sidebarLayout(
              sidebarPanel(
                selectInput("regionInput", "Region",
                            choices = c("Choose region", 
                                        "Africa",
                                        "Asia",
                                        "Latin America",
                                        "North America",
                                        "Europe"),
                            selected = "Choose region"),
                selectInput("pgInput", "Select PG",
                            choices = c("Choose PG", 
                                        "PG 1",
                                        "PG 2",
                                        "PG 3"),
                            selected = "Choose PG")
              ),

              mainPanel(

                # Output
                tabsetPanel(type = "tabs",
                            tabPanel("Map", leafletOutput(outputId = 'map', height = 700)) #,
                            # tabPanel("Chart",  plotOutput("chart")),
                            # tabPanel("Table",  tableOutput("table"))
   )
  )
 )
)

#  Server
server <- function(input, output) {

selectedRegion <- reactive({
  data_pg_df[data_pg_df$Region == input$regionInput, ] 
})

output$map <- renderLeaflet({
  leaflet(data_pg_df) %>%
    addProviderTiles(providers$Stamen.Toner) %>%
    addPolygons(stroke = FALSE, 
                fillOpacity = 0.75, 
                color = pal(selectedRegion()), weight = 1) 

})



}

shinyApp(ui = ui, server = server)

I got this advise on SO.

Using View(data_pg_df) you will find data_pg_df is an S4 class and to subset S4 you need to use @ . Also, I think you have a problem with merge as you can see in View(data_pg_df@data) . This will works

data_pg_df@data[data_pg_df@data$Region == input$regionInput, ]

With warning:

Warning in pal(selectedRegion()) : Some values were outside the color scale and will be treated as NA

But it does not resolve my problem, unfortunately. Filter does not work and map still sucks.
Any help is very much appreciated. Thanks!


#2

I updated the code from a working app, but the error continues with NAs

# Global code

# Read file on a local machine
data_pg <- read.csv("pg.csv", header = TRUE, stringsAsFactors = FALSE)

# Read a shapefile
countries <- readOGR(".","ne_50m_admin_0_countries")

# Merge data
data_pg_df <- merge(countries, data_pg, by.x = "name", by.y = "Country", 
duplicateGeoms = TRUE)


# UI code

ui <- fluidPage(theme = shinytheme("united"),
            titlePanel("PG Map"),
            sidebarLayout(
              sidebarPanel(
                selectInput("regionInput", "Region",
                            choices = c("Choose region", 
                                        "Africa",
                                        "Asia",
                                        "Latin America",
                                        "North America",
                                        "Europe"),
                            selected = "Choose region"),
                selectInput("pgInput", "Select PG",
                            choices = c("Choose PG", 
                                        "PG 1",
                                        "PG 2",
                                        "PG 3"),
                            selected = "Choose PG")
              ),

              mainPanel(

                # Output
                tabsetPanel(type = "tabs",
                            tabPanel("Map", leafletOutput(outputId = 'map', height = 700)) #,
                            # tabPanel("Chart",  plotOutput("chart")),
                            # tabPanel("Table",  tableOutput("table"))
  )
  )
  )
  )

#  Server
server <- function(input, output) {

output$map <- renderLeaflet({
leaflet(data_pg_df) %>% 
  addProviderTiles(providers$Stamen.TonerLite) %>% 
  setView(11.0670977,0.912484, zoom = 4) 

})  

selectedRegion <- reactive({
data_pg_df[data_pg_df$Region == input$regionInput, ] 
})

observe({
state_popup <- paste0("<strong>Region: </strong>", 
                      selectedRegion()$Region, 
                      "<br><strong> Client name: </strong>", 
                      selectedRegion()$Client.name,
                      "<br><strong> Country: </strong>", 
                      selectedRegion()$Country,
                      "<br><strong> PG: </strong>", 
                      selectedRegion()$PG)


 leafletProxy("map", data = selectedRegion()) %>%
  clearShapes() %>%
  addPolygons(fillColor =  "blue",
              popup = state_popup,
              color = "#BDBDC3",
              fillOpacity = 0.5,
              weight = 1 
  )
 })

}

shinyApp(ui = ui, server = server)

Also updated shapefiles


#3

If you look at data_pg_df$Region, you'll see it has many NAs:

> data_pg_df$Region
  [1] NA              NA              NA              NA              NA             
  [6] NA              NA              NA              "Latin America" NA             
 [11] NA              NA              NA              NA              NA             
 [16] NA              NA              NA              NA              NA             
 [21] NA              NA              NA              NA              NA             
 [26] NA              NA              NA              NA              NA             
 [31] NA              NA              NA              NA              NA             
 [36] NA              NA              NA              "North America" NA             
 [41] NA              "Asia"          NA              NA              NA             
 [46] NA              NA              NA              NA              NA             
 [51] NA              NA              NA              NA              NA             
 [56] NA              NA              "Europe"        NA              NA             
 [61] NA              NA              NA              NA              NA          
...   

With data_pg_df$Region == input$regionInput, you're comparing it to a value, like "Asia". In R, if you compare a value to NA, you get NA.

> data_pg_df$Region == "Asia"
  [1]    NA    NA    NA    NA    NA    NA    NA    NA FALSE    NA    NA    NA    NA    NA    NA
 [16]    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA
 [31]    NA    NA    NA    NA    NA    NA    NA    NA FALSE    NA    NA  TRUE    NA    NA    NA
 [46]    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA FALSE    NA    NA
 [61]    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA    NA
...

And you can't index into data_pg_df object using NA.

You'll need to handle the NAs somehow. I don't know for sure what's appropriate for your data set, but it looks like you might want to keep only the rows where == resolves to TRUE, and drop the rows which would result in NA and FALSE. To do this, you can add in a check with is.na():

!is.na(data_pg_df$Region) & data_pg_df$Region == "Asia"
  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [16] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [31] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE
 [46] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
 [61] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
...

So then you'd have:

selectedRegion <- reactive({
  data_pg_df[!is.na(data_pg_df$Region) & data_pg_df$Region == input$regionInput, ]
})

#4

@


@winston, fantastic, after fixing NAs works like angel! Kudos!


#5

If your question's been answered (:confetti_ball:), would you mind choosing a solution? It helps other people see which questions still need help, or find solutions if they have similar problems. Here’s how to do it:


#6

I have additional question about the same error, so I think it is legit to ask here.

I did a filter to filter by project ID

Project ID
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012

I use

numericInput("projectInput", label = "Project ID", 0, min = 1, 
                             max = 1000000)

Max is big, but I also tried min as 1001 and max as 1012 - the same error.

So, when I put a number is is beyond 1001-1012, the app breaks, giving the same error

Warning: Error in [: NAs not permitted in row index

How to avoid this, allowing to put wrong numbers without breaking app.

Thanks.


#7

Resolved by myself the second NA problem

 selectedProject <- reactive({
  if (is.na(input$projectInput)) pInputvalue <- 0 else pInputvalue <- input$projectInput
  data_pg_df[!is.na(data_pg_df$Project.ID) & data_pg_df$Project.ID == pInputvalue, ]
  })