Eric Green
Eric Green

Reputation: 7735

filtering on shiny selectizeInput and showing blank plot when there are no observations in the dataset that meet the input

In my flexdashboard shiny app, I'm using selectizeInput() with three options: "english", "spanish", and "other". In my toy dataset, there are no observations of the variable lang that take the value "other". Therefore, when only "other" is selected in the input bar, R returns an evaluation error:

missing value where TRUE/FALSE needed.

This is caused by the following line of the pipe in the "Page 1" section:

filter(if(is.null(input$foo)) (new==1) else (lang %in% input$foo)) %>%

What is the right approach to show a blank plot when there are no observations in the dataset that take the value of the input?

---
title: "test"
output: 
  flexdashboard::flex_dashboard:
    theme: bootstrap
runtime: shiny
---

```{r setup, include=FALSE}
  library(flexdashboard)
  library(tidyverse)
  library(tibbletime)
  library(dygraphs)
  library(magrittr)
  library(xts)
```

```{r global, include=FALSE}
# generate data
  set.seed(1)
  dat <- data.frame(date = seq(as.Date("2018-01-01"), 
                               as.Date("2018-06-30"), 
                               "days"),
                    sex = sample(c("male", "female"), 181, replace=TRUE),
                    lang = sample(c("english", "spanish"), 181, replace=TRUE),
                    age = sample(20:35, 181, replace=TRUE))
  dat <- sample_n(dat, 80)

```

Sidebar {.sidebar}
=====================================

```{r}
selectizeInput(
  'foo', label = NULL, 
  choices = c("english", "spanish", "other"),
  multiple = TRUE
)
```

Page 1
=====================================

```{r}
# all
  totals <- reactive({
  dat %>%
    mutate(new = 1) %>%
    arrange(date) %>%
    filter(if(is.null(input$foo)) (new==1) else (lang %in% input$foo)) %>%
  # time series analysis
  tibbletime::as_tbl_time(index = date) %>% # convert to tibble time object
    select(date, new) %>%
    tibbletime::collapse_by("1 week", side = "start", clean = TRUE) %>%
    group_by(date) %>%
    mutate(total = sum(new, na.rm = TRUE)) %>%
    distinct(date, .keep_all = TRUE) %>%
    ungroup() %>%
    # expand matrix to include weeks without data
    complete(
      date = seq(date[1], date[length(date)], by = "1 week"),
      fill = list(total = 0)
    )
  })

# convert to xts
  totals_ <- reactive({
    totals <- totals()
    xts(totals, order.by = totals$date)
  })

# plot
  renderDygraph({

  totals_ <- totals_()
  dygraph(totals_[, "total"]) %>%
    dyRangeSelector() %>%
    dyOptions(useDataTimezone = FALSE,
              stepPlot = TRUE,
              drawGrid = FALSE,
              fillGraph = TRUE) 
  })
```

Upvotes: 0

Views: 654

Answers (1)

divibisan
divibisan

Reputation: 12165

One way to do this is to use the shiny::req function to check the requirements before running the code block.

If you add:

req(dat$lang %in% input$foo)

to the top of your totals <- reactive({ expression, then it will check that the value of input$foo is in dat$lang before running the rest of that expression. If it's not found, then the operation will be stopped silently. No error will be displayed and the plot will remain blank.

Upvotes: 2

Related Questions