Search code examples
rshinygganimate

How to connect user input with gganimate graph in R shiny?


Is there a way to link user input (x-axis, y-axis, colour etc) to the gganimate graph in R shiny? So that when the user selects a different input (x-axis, y-axis, colour, etc.) from the drop-down list. gganimate graph will be filled with different x-axis, y-axis, colour, etc. so that it can be changed accordingly?

The coding I tried as below. And there is error due to the variable name I saved in UI (xValue, yValue, colorValue etc which are putting in ggplot function) does not apply in the Serve... enter image description here

The idea of UI code come from here: https://shiny.rstudio.com/articles/layout-guide.html And it would display sth like this:

enter image description here

library(shiny)
library(shinythemes)
library(palmerpenguins)
library(gganimate)
library(dplyr)
library(tidyr)
library(ggplot2)
library(gapminder)
data(package = 'palmerpenguins')
ui <- fluidPage(
               
                navbarPage(
                  "Animated penguins data",
                 
                  tabPanel("Navbar 2", 
                           
                           
                           ##########
                           
                           imageOutput('plot'),
                             
                           
                             hr(),
                             
                             fluidRow(
                               column(3,
                                      h4("Diamonds Explorer"),
                                      sliderInput('sampleSize', 'Sample Size', 
                                 min=1, max=nrow(penguins), value=min(1000, nrow(penguins)), 
                                                  step=500, round=0),
                                      br(),
                                      checkboxInput('jitter', 'Jitter'),
                                      checkboxInput('smooth', 'Smooth')
                               ),
                               column(4, offset = 1,
                              xValue -> selectInput('x', 'X', names(penguins)),
                     yValue -> selectInput('y', 'Y', names(penguins), names(penguins)[[2]]),
                  colorValue -> selectInput('color', 'Color', c('None', names(penguins)))
                               ),
                               column(4,
            rowValue -> selectInput('facet_row', 'Facet Row', c(None='.', names(penguins))),
      columnValue -> selectInput('facet_col', 'Facet Column', c(None='.', names(penguins)))
                               )
                             )
                           
                           #########
                           
                           
                          
                           ),
                  
       
                  
                ) # navbarPage
                
) # fluidPage

The idea of serve come from here: How to create and display an animated GIF in Shiny? The server is sth. like this enter image description here

# Define server function  
server <- function(input, output) {
  
  ##########################################
  output$plot <- renderImage({
    # A temp file to save the output.
    # This file will be removed later by renderImage
    outfile <- tempfile(fileext='.gif')
    
    # now make the animation
    p = myPenguins %>%
      ggplot(
        aes(xValue, yValue, color = colorValue)) + 
      geom_point() + 
      #geom_line() +
      facet_grid(rows = vars(rowValue), cols =  vars(columnValue))+
      theme_bw()+
      #theme_minimal() +
      transition_time(year)+
      labs(title = "Year: {frame_time}")+
      
      view_follow()#+
    
    anim_save("outfile.gif", animate(p)) # New
    
    # Return a list containing the filename
    list(src = "outfile.gif",
         contentType = 'image/gif')
    
    }, deleteFile = TRUE)
  
  
  ################################################################
  }

shinyApp(ui = ui, server = server)


Solution

  • Your code is still far from minimal and I don't have many of the packages you reference, but I think the following will illustrate the techniques that will allow you to do what you want. I've based my code on the diamonds dataset, which is part of ggplot2.

    Your problem is due to the fact that Shiny input widgets (generally) return strings, whereas ggplot functions expect symbols as their argument. This is a feature of the tidyverse's use of non-standard evaluation (NSE).

    As a result, the interface between Shiny and the tidyverse can be perplexing when you first come across it. One solution is to use the bang-bang operator (!!) and the sym function.

    The following app displays a faceted scatter plot in which the user has complete control over the variables that

    • are plotted on the x axis
    • are plotted on the y-axis
    • define the colours of the plotted points
    • define the facet rows
    • define the facet columns
    library(shiny)
    library(tidyverse)
    
    ui <- fluidPage(
      selectInput("x", "X variable:", names(diamonds)),
      selectInput("y", "Y variable", names(diamonds), selected="price"),
      selectInput("colour", "Colour: ", names(diamonds), selected="color"),
      selectInput("facetRows", "Facet rows: ", names(diamonds), selected="clarity"),
      selectInput("facetCols", "Facet columns", names(diamonds), selected="cut"),
      plotOutput("plot")
    )
    
    server <- function(input, output) {
      output$plot <- renderPlot({
         diamonds %>% 
          ggplot() +
            geom_point(aes(x=!!sym(input$x), y=!!sym(input$y), colour=!!sym(input$colour)))  +
            facet_grid(rows=vars(!!sym(input$facetRows)), cols=vars(!!sym(input$facetCols)))
      })
    }
    
    shinyApp(ui = ui, server = server)
    

    enter image description here

    Note that the diamonds dataset is quite large and a poor choice of variables for any of the five roles I mention above can lead to lengthy delays!

    I think this provides an answer to your question, but I'm not entirely sure because of the many disparate features in your code (eg saving a GIF file, use of gganimate, reference to gapminder) that do not seem relevant to the question of using UI inputs in a call to renderPlot. If I haven't given you what you want, please refine your question and code so that they reference only the elements that are critical to the fundamental issue.

    This post will help you construct a minimal reproducible example.