I am working on a shiny app that has a reactive df which I am using to render a dt data table. My issue is that on my sidebar pickerInput filters I am using:
choices = unique(COLUMN_NAME)
When there is NA values in the column that gets turned into "NA" on the filter so when I use:
filter(COLUMN_NAME %in% input$column_name)
In the reactive df the NA values do not filter correctly. What is the best way around this? Should I recode any NA values to a string or should I work around fixing the sidebar filter so that NA filters to truly NA values?
Welcome to the community @para239! I believe the answer to your question is a matter of personal preference. Below is an example app that illustrates three different ways of handling an NA in the pickerInput. The app produces a count of species from the starwars data set based on the selection (defaulted to "Droid" and NA).
In the first case, the data and filter are left as-is, which results in no count for NA.
The second cased recodes NA values in the reactive data frame to "NA".
The final case does not recode NAs, rather checks for "NA" in the selection and, if present, updates the filter statement to include NAs via filter(... | is.na(species))
library(shiny)
library(tidyverse)
library(shinyWidgets)
mydata = starwars
ui <- fluidPage(
br(),
pickerInput('selection',
'Select Species',
choices = unique(mydata$species),
selected = c('Droid', NA),
multiple = T
),
br(),
HTML('<h4>Use data as-is with "regular" filter (NAs overlooked)</h4>'),
tableOutput('mytable'),
br(),
br(),
HTML('<h4>Recoded NA to "NA" string</h4>'),
tableOutput('mytable_recode'),
br(),
br(),
HTML('<h4>NA not recoded but included via logic</h4>'),
tableOutput('mytable_no_recode')
)
server <- function(input, output, session) {
# use the data as-is with a regular filter
df = reactive({
req(input$selection)
count(mydata, species) %>%
filter(species %in% input$selection)
})
output$mytable = renderTable({
df()
})
# handle NA by recoding NA values to "NA"
df_recode = reactive({
req(input$selection)
count(mydata, species) %>%
mutate(species = ifelse(is.na(species), 'NA', species)) |>
filter(species %in% input$selection)
})
output$mytable_recode = renderTable({
df_recode()
})
# how to include NA without recoding
df_no_recode = reactive({
req(input$selection)
out = count(mydata, species)
# if NA in selection, include an OR (|) in the filter
if('NA' %in% input$selection) {
out = out %>%
filter(species %in% input$selection | is.na(species))
} else {
out = out %>%
filter(species %in% input$selection)
}
out
})
output$mytable_no_recode = renderTable({
df_no_recode()
})
}
shinyApp(ui, server)