Naveen Mathew
Naveen Mathew

Reputation: 372

Combination of reactive and eventReactive for generating a plot

Overview: I'm using a reactive component to update the data set dynamically based on user input. This works without any issue.

Additional requirement: I want to color the plot only on click of a button. Current setting: After I click 'Color' button, the color remains even if I change the data set.

I defined the same output element inside an observeEvent block to override the default element defined in server. However, this override is permanent.

library(shiny)
shinyApp(ui = fluidPage(
  sidebarPanel(
    selectInput(inputId = "dropdown", label = "Select data set:",
                choices = c("iris", "mtcars"), selected = "iris")
  ),

  mainPanel(fluidPage(
    fluidRow(plotOutput("plot"),
             actionButton("color", "Color"))
  ))
), server = function(input, output) {
  get_data <- reactive({
    if(input$dropdown == "iris") {
      return(list(dat = iris, x = "Sepal.Length", color = "Species"))
    } else {
      return(list(dat = mtcars, x = "mpg", color = "cyl"))
    }
  })
  output$plot <- renderPlot({
    dat <- get_data()
    return(plot(dat$dat[, dat$x]))
  })

  observeEvent(input$color, {
    output$plot <- renderPlot({
      dat <- get_data()
      return(plot(dat$dat[, dat$x], col = dat$dat[, dat$color]))
    })
  })
})

Actual result: Color appears every time clicking "Color" button even if I change the data set. Expected result: Color should appear after clicking "Color" for the current data set. It should not appear once I change the data set. It should reappear only when I click "Color" button again.

Upvotes: 2

Views: 769

Answers (2)

alko989
alko989

Reputation: 7908

You can explicitly observe the event that is triggered by input$dropdown:

function(input, output) {
  get_data <- reactive({
    if(input$dropdown == "iris") {
      return(list(dat = iris, x = "Sepal.Length", color = "Species"))
    } else {
      return(list(dat = mtcars, x = "mpg", color = "cyl"))
    }
  })
  observeEvent(input$dropdown, {
    output$plot <- renderPlot({
      dat <- get_data()
      return(plot(dat$dat[, dat$x]))
    })  
  })

  observeEvent(input$color, {
    output$plot <- renderPlot({
      dat <- get_data()
      return(plot(dat$dat[, dat$x], col = dat$dat[, dat$color]))
    })
  })
}

Upvotes: 1

MrFlick
MrFlick

Reputation: 206242

It seems like you want to be tracking state. You can't really "un-click" a button so it would be better just to store a reactive value to indicate whether or not you want colors and you can reset that when the dataset changes. Here's such a server function

function(input, output) {

  showColor <- reactiveVal(FALSE)

  get_data <- reactive({
    if(input$dropdown == "iris") {
      return(list(dat = iris, x = "Sepal.Length", color = "Species"))
    } else {
      return(list(dat = mtcars, x = "mpg", color = "cyl"))
    }
  })
  output$plot <- renderPlot({
    dat <- get_data()
    if (showColor()) {
      plot(dat$dat[, dat$x], col = dat$dat[, dat$color])
    } else {
      plot(dat$dat[, dat$x])
    }
  })
  observeEvent(input$dropdown, {
    showColor(FALSE)
  })
  observeEvent(input$color, {
    showColor(TRUE)
  })
}

You see we added the showColor <- reactiveVal(FALSE) part so it won't show colors by default and reset it to FALSE when the dropdown changes. We set it to TRUE when you press the "color" button.

Upvotes: 2

Related Questions