I am having some trouble getting a ggplot2 facet_grid
plot working for an evaluation system. The plot renders well but I get the following error in the browser and console:
Error in : Faceting variables must have at least one value
This occurs every time I switch the brand entry based on the input input$brand
. The application doesn't crash but the error message is annoying.
I have prepared this reproducible example:
---
title: "Power ranking for mtcars"
runtime: shiny
output:
flexdashboard::flex_dashboard:
orientation: rows
source_code: embed
---
```{r rows.print = 25}
library(dplyr)
library(ggplot2)
mtcars_tidy <- mtcars %>%
tibble::rownames_to_column() %>%
rename(model = rowname) %>%
mutate(brand = gsub( " .*$", "", model )) %>%
mutate(model = model) %>%
select(brand, model, everything()) %>%
tidyr::gather(key = 'measure', value = "value", mpg:carb) %>%
mutate(ranking = as.factor(sample(x = c(1, 2, 3), size = n(), replace = TRUE))) %>%
mutate(power = case_when(
.$measure == "hp" & value > 200 | (.$measure == "cyl" & value == 8) ~ "high",
.$measure == "hp" & value < 200 | (.$measure == "cyl" & value == 8) ~ "medium",
.$measure == "hp" & value > 100 | (.$measure == "cyl" & value == 6) ~ "high",
.$measure == "hp" & value < 100 | (.$measure == "cyl" & value == 6) ~ "medium",
.$measure == "hp" & value > 50 | (.$measure == "cyl" & value == 6) ~ "high",
.$measure == "hp" & value < 50 | (.$measure == "cyl" & value == 6) ~ "medium",
.$measure == "hp" & value > 200 | (.$measure == "carb" & value > 4) ~ "high",
.$measure == "hp" & value < 200 | (.$measure == "carb" & value <= 4) ~ "medium",
.$measure == "hp" & value > 100 | (.$measure == "carb" & value > 2.8) ~ "high",
.$measure == "hp" & value < 100 | (.$measure == "carb" & value <= 2.8) ~ "medium",
.$measure == "hp" & value > 50 | (.$measure == "carb" & value > 2) ~ "high",
.$measure == "hp" & value < 50 | (.$measure == "carb" & value <= 2) ~ "medium",
TRUE ~ "low"
))
```
# Sidebar {.sidebar data-width="350"}
```{r}
selectInput("brand", "Brand of the car",
choices = unique(mtcars_tidy$brand))
renderUI({
selectInput("model", "Car model",
choices = mtcars_tidy$model[mtcars_tidy$brand == levels(mtcars_tidy$brand)[1]])
})
br()
observe({
brand <- input$brand
updateSelectInput(session, "model",
choices = mtcars_tidy$model[mtcars_tidy$brand == brand])
})
# when switching the brand of the car, input$brand this error pops up:
# Error in : Faceting variables must have at least one value
```
# Main
##
### Plot power ranking for each measure
```{r}
nameorder <- make.unique(mtcars_tidy$measure[order(mtcars_tidy$power, mtcars_tidy$ranking)])
mtcars_tidy$measure <- factor(mtcars_tidy$measure, levels=nameorder,
ordered = TRUE)
dataset <- reactive({
subset(mtcars_tidy, brand == input$brand & model == input$model)
})
renderPlot({
ggplot(dataset(), aes(x = ranking, y = measure)) +
geom_segment(aes(yend = measure), xend=0, color = "grey50") +
geom_point(size = 3, aes(colour = power)) +
scale_colour_brewer(palette="Set1", limits = c("high","medium", "low")) +
theme_bw() +
theme(panel.grid.major.y = element_blank()) + # No horizontal grid lines
facet_grid(power ~ ., scales="free_y", space="free_y") +
ggtitle(paste0("Brand: ", input$brand, ", Model: " , input$model))
})
```
EDIT 1: I changed facet_grid
to facet_wrap
but the error still there.
EDIT 2: As per suggestion, I switched to facet_wrap
with this formula: p <- p + facet_wrap(power ~ .)
. Still same error. I also tried this other formula
p <- p + facet_wrap(power ~ ranking)
. Error still there.
EDIT 3: On the facet_wrap
function I also tried with these formulas as well:
facet_wrap(~power )
facet_wrap(vars(power ))
facet_wrap(vars(power , ranking))
.
The error is still the same (identical). No change (Error in : Faceting variables must have at least one value
).
EDIT 4: If I try with facet_wrap(power)
, the error is even worse because crashes Shiny with this mouthful:
Error: Column `function (lambda = 1) \n{\n if (!is.numeric(lambda) || is.na(lambda)) \n stop("invalid argument 'lambda'")\n if (lambda <= 0) \n return(make.link("log"))\n if (lambda == 1) \n return(make.link("identity"))\n linkfun <- function(mu) mu^lambda\n linkinv <- function(eta) pmax(eta^(1/lambda), .Machine$double.eps)\n mu.eta <- function(eta) pmax((1/lambda) * eta^(1/lambda - \n 1), .Machine$double.eps)\n valideta <- function(eta) all(is.finite(eta)) && all(eta > \n 0)\n link <- paste0("mu^", round(lambda, 3))\n structure(list(linkfun = linkfun, linkinv = linkinv, mu.eta = mu.eta, \n valideta = valideta, name = link), class = "link-glm")\n}` must be a 1d atomic vector or a list
This error is occuring when
dataset()
has no rows in it. When I run your code (the current version with thefacet_grid(power ~ .,
), it actually works fine. When I choose a new brand, there is a short gap where it displays this error while theinput$model
list updates. Once it does, and the combination ofbrand
andmodel
return rows, the plot displays nicely.You can prevent this gap by using
req
to hold off rendering the plot until certain requirements are met. Just insert the following code at the top of yourrenderPlot
This will prevent the
renderPlot
from running ifdataset()
doesn't contain at least one row. In that case, the plot will just be blank (removing the scary error message) until the data is ready to use. With that line added, your app seems to be running fine (and looks quite nice, by the way).You can see the source of that error message by testing your code outside the
shiny
context. Here's a minimal example of your plot:when I make
dataset
using this call:The plot renders correctly. When I use a
subset
that doesn't return any rows:I get your same error: