1

I'm creating an R Shiny app for data exploration for different runs of an experiment. I have different sliderInput and selectInput to play with the data ranges and variables being plotted. The data is obtained via an API call to a private database.

CODE

ui <- fluidPage(
  sliderInput(inputId = "num",
              label = "Experiment Id",
              value = 5, min = 2, max = 7),
  selectInput("x", "Horizontal Axis", colopts), #colopts is predefined 
  selectInput("y", "Vertical Axis", colopts), #colopts is predefined 
  plotOutput("userPlot")
)

server <- function(input, output){
  output$userPlot <- renderPlot({
    # testdata is a function that makes the API call, performs cleanup, calculations etc. 
    # The output is a list, the first element of which is being called here
    dat <- testdata(input$num)[[1]]
    # "type" is hard-coded for testing - to be changed later
    plt <- ggplot(dat, aes_string(x = input$x, y = input$y)) + 
      geom_point(aes(color = type ,fill = type, shape = type))+ 
      geom_line(aes(color = type)) + 
      ggtitle(paste("Test",input$num, sep = " "))
    return(plt)
  })

}

shinyApp(ui = ui, server = server)

OUTPUT

Current State

It works fine, however, everytime I select a different variable to plot for either axis, the code makes another API call - which is the expected behaviour. Since the dataset being plotted changes only when a different Experiment Id is selected, I would want to make an API call only when I change the Experiment Id.

Short of loading the entire dataset into the memory and then using the app, is there a way to achieve that i.e. if only the axes are changed while keeping the Experiment Id the same, update the plot without making an API call?

Gautam
  • 2,597
  • 1
  • 28
  • 51
  • 1
    Don't put everything in `renderPlot`. Make `dat` a reactive object that depends only on `input$num` and then have your `renderPlot` rely on `dat()`. It would be easier to provide a more concrete answer if you provide a more [reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) – MrFlick Feb 12 '18 at 17:07
  • Thanks, this is helpful. I'm unable to show data since that is from a private server and won't work for anyone not on my work network. – Gautam Feb 12 '18 at 18:05

1 Answers1

2

As MrFlick says in the comments, you can use a reactive which is dependent on input$num, and make your plot dependent on that reactive. In doing so, any time the input$x or input$y changes, only the plot invalidates while the reactive remains unchanged because that is only dependent on input$num. If you change input$num both the reactive and thus the plot will invalidate.

I created a working example based on your code below. New data is only created the input$num changes, as you can see from the mean of the generated data in the plot.

Hope this helps!

library(shiny)
library(ggplot2)
set.seed(1)

ui <- fluidPage(
  sliderInput(inputId = "num",
              label = "Experiment Id",
              value = 5, min = 2, max = 7),
  selectInput("x", "Horizontal Axis", letters[1:3]), #colopts is predefined 
  selectInput("y", "Vertical Axis", letters[1:3]), #colopts is predefined 
  plotOutput("userPlot")
)

server <- function(input, output){

  # API call in here
  dat <- reactive({
    df = data.frame(a=rnorm(200,input$num,0.5),
                    b=rnorm(200,input$num,0.5),
                    c=rnorm(200,input$num,0.5),
                    type=sample(letters[10:15],100,replace = T))
  })

  output$userPlot <- renderPlot({
    # testdata is a function that makes the API call, performs cleanup, calculations etc. 
    # The output is a list, the first element of which is being called here
    # "type" is hard-coded for testing - to be changed later
    plt <- ggplot(dat(), aes_string(x = input$x, y = input$y)) + 
      geom_point(aes(color = type ,fill = type, shape = type)) + 
      geom_line(aes(color = type)) + 
      ggtitle(paste("Test",input$num, sep = " "))
    return(plt)
  })

}

shinyApp(ui = ui, server = server)
Florian
  • 24,425
  • 4
  • 49
  • 80
  • Your code works. But when I change `dat` to a reactive object in the way you've shown above `dat <- reactive({ testdata(input$num)[[1]] })` I get an error: "ggplot2 doesn't know how to deal with data of class reactiveExpr/reactive". – Gautam Feb 12 '18 at 18:17
  • 1
    Don't forget to call it as dat() instead of dat in the plot function to call its value. So `ggplot(dat())` instead of `ggplot(dat)` – Florian Feb 12 '18 at 18:24