Search code examples
rggplot2modulerlangfacet-grid

How can you set string argument to NULL with rlang (for use in facet vars)?


I'm trying use selectInput to define facets for ggplot, so the input to facet_grid is a string or the column name. One of the options is "none" (which is not one of the columns) The example below works as long as "none" if not selected. I'm struggling with how I can set define the "none" options as NULL.

I tried the following but get the following error "Error: cols must be NULL or a vars() specification".

v <- ifelse(rfacet() == "none", NULL, vars(!!rlang::sym(rfacet())))  
# Module - facets options-------------------------------------------------------

   #UI
   plotOpt_rowfacet_UI <- function(id){
      ns <- NS(id)
      uiOutput(ns("ui_opt_rowfacet"))
   }

   #SERVER
   plotOpt_rowfacet <- function(input, output, session, facet_choices="none"){

        output$ui_opt_rowfacet <- renderUI({
         ns <- session$ns

         selectInput(inputId = ns("opt_rowfacet"), label = "Y-variable:",
          choices = facet_choices,
          selected = "none",
          multiple = FALSE, selectize = FALSE)
        })

        return(reactive(input$opt_rowfacet))  #returns column name as string
   }


library(shiny)
   library(dplyr)
   library(tidyverse)

ui <- fluidPage(

  plotOpt_rowfacet_UI("test1"),
  h4("facet selected ouput from module"),
  verbatimTextOutput("y_out"),
  plotOutput("plot")

)

server <- function(input, output, session){

  rfacet <- callModule(module=plotOpt_rowfacet, id="test1", facet_choices= c("none", "mpg", "disp"))

  output$y_out <- renderPrint({
    str(rfacet())
  })

  #this works except if none is selected
  #how can set to NULL if input="none"
  output$plot <- renderPlot({

    #v <- ifelse(rfacet() == "none", NULL, vars(!!rlang::sym(rfacet())))  

    p <- ggplot(mtcars, aes(x=wt, y=disp))+
        geom_point()+
        facet_grid(rows=vars(cyl), cols=vars(!!rlang::sym(rfacet())))
    print(p)
  })


}

shinyApp(ui, server)

Solution

  • The v you commented out was pretty close, you can do something like the following to define output$plot:

    output$plot <- renderPlot({
      choice <- rfacet()
      v <- if (choice == "none") NULL else vars(!!rlang::sym(choice))
    
      ggplot(mtcars, aes(x=wt, y=disp)) +
        geom_point() +
        facet_grid(rows=vars(cyl), cols=v)
    })
    

    And do note this remark from renderPlot's documentation:

    With ggplot2 graphics, the code in renderPlot should return a ggplot object; if instead the code prints the ggplot2 object with something like print(p), then the coordinates for interactive graphics will not be properly scaled to the data space.