passing variables to ggplot

Dear Group,
I am trying to undrstand the way how to pass variables to ggplot in Shiny. I have a pull down menue for using various data sets, e.g. iris, mtcars or USarrests with

selectInput("data_input", "Choose your data file or example data", *
choices = list("",Upload your *.csv file = 2, "mtcars" = 1, "iris" =3,"Tooth Growth" =4, "USA Arrests" =5 ), selected = NULL)*

the data frame is included with

rf <- reactive({*
req(input$data_input)*
if(input$data_input ==1) {daten <- mtcars}*
else if (input$data_input ==3) {daten <- iris}*
else if (input$data_input ==4) {daten <- ToothGrowth}*
else if (input$data_input ==5) {daten <- USArrests}*

Now if I want to address the variables in the data frames in ggplot in Shiny, i have to do

ggplot(data = rf(), mapping = aes(!!(as.name(input$X_ax)), !!(as.name(input$Y_ax))))

Thus, x and y are addressed by !!(as.name(input$X_ax)) and !!(as.name(input$Y_ax)

If I do an

observe print(!!(as.name(input$X_ax))),
the app crashes.

If I do a

observe(print(rf()$Sepal.Length))
I get the vector of Sepal.Length.

I do not understand the synax one has to use in ggplot. Why is it not possible to use x=input$X_ax from the reactive input value?

Sorry, I am not sure if I made my problem clear. I am just beginning to learn Shiny.

Thanks a lot,
Cyrus

Hi,

The tidyverse evaluation is tricky to understand and I'm still new to it myself, but I found a way to fix it by using the parse_quo() from the 'rlang' package.

library("shiny")
library("ggplot2")
library("rlang")


ui <- fluidPage(
  selectInput("data_input", "data", choices = 1:4),
  selectInput("X_ax", "X_ax", choices = "mpg"),
  selectInput("Y_ax", "y_ax", choices = "mpg"),
  plotOutput("myPlot")
  
)

server <- function(input, output, session) {
  
  rf <- reactive({
      # req(input$data_input)
      if(input$data_input ==1) {daten <- mtcars}
      else if (input$data_input ==2) {daten <- iris}
      else if (input$data_input ==3) {daten <- ToothGrowth}
      else if (input$data_input ==4) {daten <- USArrests}
      updateSelectInput(session, "X_ax", choices = colnames(daten))
      updateSelectInput(session, "Y_ax", choices = colnames(daten))
      daten
  })
  

  output$myPlot = renderPlot({
    x = parse_quo(input$X_ax, env = caller_env())
    y = parse_quo(input$Y_ax, env = caller_env())
    ggplot(data = rf(), aes(x = !!x, y = !!y)) + geom_point()
  })
  
  
}

shinyApp(ui, server)

Once implemented, the code ran, but there were some issues with updating the plots given the inputs for the axes depend on the dataset chosen. If you change the dataset, it would trigger the plot refresh, but then the axes selection hadn't updated yet and you'd get a brief error message before the axes refreshed based on the new dataset. I found a work-around, but I'm still not very happy with is as it looks a bit weird in the code. I had to isolate the dataset in ggplot to prevent triggering update before the axes were set. Unfortunately, this was the only place in the code where the dataset was called, and if isolated, Shiny will ignore the reactive function because there's no code to use it, even if the triggers in the function change. I solved this my adding an empty observeEvent using the reactive function, and now all works well:

library("shiny")
library("ggplot2")
library("rlang")


ui <- fluidPage(
  selectInput("data_input", "data", choices = 1:4),
  selectInput("X_ax", "X_ax", choices = "mpg"),
  selectInput("Y_ax", "y_ax", choices = "mpg"),
  plotOutput("myPlot")
  
)

server <- function(input, output, session) {
  
  rf <- reactive({
      # req(input$data_input)
      if(input$data_input ==1) {daten <- mtcars}
      else if (input$data_input ==2) {daten <- iris}
      else if (input$data_input ==3) {daten <- ToothGrowth}
      else if (input$data_input ==4) {daten <- USArrests}
      updateSelectInput(session, "X_ax", choices = colnames(daten))
      updateSelectInput(session, "Y_ax", choices = colnames(daten))
      daten
  })
  
  observeEvent(rf(),{

  })
  
  
  output$myPlot = renderPlot({
    x = parse_quo(input$X_ax, env = caller_env())
    y = parse_quo(input$Y_ax, env = caller_env())
    ggplot(data = isolate(rf()), aes(x = !!x, y = !!y)) + geom_point()
  })
  
  
}

shinyApp(ui, server)

Let me know if you know a nice way to prevent that refresh issue, because I've been tinkering with it for 2 hours and although it works, I think it's not the right way of coding it. At least I was able to solve your original issue :slight_smile:

Grtz,
PJ

Hi PJ,
thanks for this suggestion. the parse_quo function was not on my mind at all, but it looks much cleaner. I also dont have much experience with using "isolate" either, have to explore your code in more detail.
However, the "issue" is still there, the way ggplot evaluates the x and y values...
thanks a lot,
Cyrus

Hi,

What do you mean by 'the issue the way ggplot evaluates the x and y" ?
I might have interpreted your question wrong then, cause it seemed to be working when I tried...

PJ

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.