Search code examples
rshinyplotlyflexdashboard

How to make a plotly chart of variables selected by a user in shiny or flexdahsboard?


I am pretty new to R and I am trying to put together a flexdashboard that takes in an x and y variables from user inputs and returns a graph of those values. So far I am able to generate the desired graphs using ggplotly in the code below.

output$scatter <-renderPlotly({
  
  cat('input$x=',input$x,'\n')
  cat('input$y=',input$y,'\n')
  p <- ggplot(Merged_data_frame_hcat, aes_string(x=input$x, y=input$y)) +
       geom_point()+
       theme_minimal(base_size = 14) 
  g <- ggplotly(p, source = 'source') %>%
       layout(dragmode = 'lasso',
       margin = list(l = 100),
       font = list(family = 'Open Sans', size = 16))
})

Image with code using ggplotly However, I realized with ggplotly my x axis was not as defined as when I used plot_ly to graph the same variables outside of the dashboard. Image with code using plot_ly() Is there a way to use plot_ly iside a flexdashboard. So far I wrote this but that did not work. BTW I am using noquote here because plot_ly did not take well the input names which were strings

output$scatter <-renderPlotly({
  
  cat('input$x=',input$x,'\n')
  cat('input$y=',input$y,'\n')
  if (length(input$y) == 2){
     x1 = noquote(input$x)
     y1 =noquote(input$y[1])
     y2 = noquote(input$y[2])
  
   plot_ly(Merged_data_frame_hcat)%>%
     add_lines(x= ~x1,y =~y1, name = "Red") 
     add_lines(x= ~x1, y =~y2, name = "Green")
   }
})

Before I forget, Here is an example of my data frame that I have reduced for the sake of simplicity

df <-data.frame("Timestamp.Excel_1900."=c("2019-04-01 16:52:51","2019-04-01 16:57:46","2019-04-01 17:02:51","2019-04-01 17:07:46","2019-04-01 17:12:52","2019-04-01 17:17:46"), "Temperature.C."= c(5.2995,5.3155,5.3353,5.3536,5.3770,5.4044), "pH.pH."= c(7.60,7.80,7.96,8.04, 8.09, 8.14))

Solution

  • There are several approaches to make this work. Unfortunaetly your approach using noquote does not work.

    1. Probably the simplest approach would be to extract the columns from your df and pass them to plotly as vectors, e.g. x = df[[input$x]]
    2. As the plotly API works with one-sided formula a second approach would be to pass the variables as formulas, e.g. x = as.formula(paste0("~", input$x))
    3. Following this post you can also make use of base::get, e.g. x = ~get(input$x)
    4. Following this post you can also make use of tidy evaluation

    All four approaches are illustrated in the following example flexdashboard:

    ---
    title: "Plotly"
    output: flexdashboard::flex_dashboard
    runtime: shiny
    ---
    
    ```{r}
    library(plotly)
    library(rlang)
    ```
    
    ```{r global, include=FALSE}
    # load data in 'global' chunk so it can be shared by all users of the dashboard
    df <- data.frame("Timestamp.Excel_1900." = c("2019-04-01 16:52:51","2019-04-01 16:57:46","2019-04-01 17:02:51","2019-04-01 17:07:46","2019-04-01 17:12:52","2019-04-01 17:17:46"), "Temperature.C."= c(5.2995,5.3155,5.3353,5.3536,5.3770,5.4044), "pH.pH."= c(7.60,7.80,7.96,8.04, 8.09, 8.14))
    
    ```
    
    Column {.sidebar}
    -----------------------------------------------------------------------
    
    ```{r}
    selectInput("x",
      "x",
      choices = names(df),
      selected = "Timestamp.Excel_1900."
    )
    selectizeInput("y",
      "y",
      choices = names(df),
      selected = c("Temperature.C.", "pH.pH."),
      multiple = TRUE,
      options = list(maxItems = 2)
    )
    ```
    
    Column
    -----------------------------------------------------------------------
    
    ```{r}
    # Pass the data columns as vectors
    renderPlotly({
      if (length(input$y) == 2) {
        x1 <- df[[input$x]]
        y1 <- df[[input$y[1]]]
        y2 <- df[[input$y[2]]]
    
        plot_ly() %>%
          add_lines(x = x1, y = y1, name = "Red") %>%
          add_lines(x = x1, y = y2, name = "Green")
      }
    })
    ```
    
    ```{r}
    # One-sided formulas
    renderPlotly({
      if (length(input$y) == 2) {
        x1 <- input$x
        y1 <- input$y[1]
        y2 <- input$y[2]
    
        plot_ly(df) %>%
          add_lines(x = as.formula(paste("~", x1)), y = as.formula(paste("~", y1)), name = "Red") %>%
          add_lines(x = as.formula(paste("~", x1)), y = as.formula(paste("~", y2)), name = "Green")
      }
    })
    ```
    
    Column
    -----------------------------------------------------------------------
    
    ```{r}
    # Using base::get
    renderPlotly({
      if (length(input$y) == 2) {
        x1 <- input$x
        y1 <- input$y[1]
        y2 <- input$y[2]
    
        plot_ly(df) %>%
          add_lines(x = ~ get(x1), y = ~ get(y1), name = "Red") %>%
          add_lines(x = ~ get(x1), y = ~ get(y2), name = "Green")
      }
    })
    ```
    
    ```{r}
    # Using tidy evaluation
    renderPlotly({
      if (length(input$y) == 2) {
        x1 <- input$x
        y1 <- input$y[1]
        y2 <- input$y[2]
    
        eval_tidy(
          quo_squash(
            quo({
              plot_ly(df) %>%
                add_lines(x = ~ !!sym(x1), y = ~ !!sym(y1), name = "Red") %>%
                add_lines(x = ~ !!sym(x1), y = ~ !!sym(y2), name = "Green")
            })
          )
        )
      }
    })
    ```
    

    enter image description here