How to retain the curves after plotting in R Shiny?

Hi! I am building a Shiny app, where the user can add different curves to the plot, but I can't make the plot to retain the already added curves. How can I make that happen?

In the simplified reproducible code below are altogether 8 curve possibilities, based on 3 radiobuttons selections which have 2 options each. I would like to keep these as radiobuttons and not use checkboxes, as in my real app that I am working on there will be about 300 combinations that would be too confusing to use with checkboxes. Please see the code below:

library(shiny)
library(plotly)
library(dplyr)

data111 <-data.frame("x"=1:10, "y"=c(99,98,97,96,95,94,93,92,91,90))
data112 <-data.frame("x"=5:14, "y"=c(79,78,77,76,75,74,73,72,71,70))
data121 <-data.frame("x"=9:18, "y"=c(59,58,57,56,55,54,53,52,51,50))
data122 <-data.frame("x"=3:12, "y"=c(49,48,47,46,45,44,43,42,41,40))
data211 <-data.frame("x"=7:16, "y"=c(29,28,27,26,25,24,23,22,21,20))
data212 <-data.frame("x"=11:20, "y"=c(19,18,17,16,15,14,13,12,11,10))
data221 <-data.frame("x"=2:11, "y"=c(95,94,93,92,91,90,89,88,87,86))
data222 <-data.frame("x"=1:10, "y"=c(45,44,43,42,41,40,39,38,37,36))

ui <- fluidPage(
titlePanel("Curve selection"),
sidebarLayout(
  sidebarPanel(

     radioButtons(inputId = "option",
                 label="Choose the option",
                 choices=c("option1"=1,
                           "option2"=2),
                 selected = 1),

     radioButtons(inputId = "type",
                  label="Choose the type",
                  choices=c("type1"=1,
                            "type2"=2),
                  selected = 1),

     radioButtons(inputId = "group",
                  label="Choose the group",
                  choices=c("group1"=1,
                            "group2"=2),
                  selected = 1),

     actionButton("add","Add curve to the plot")
  ),

  mainPanel(
    plotlyOutput("plot")
  )
  )
)

server <- function(input, output) {

data <- eventReactive(input$add,{
 get(paste0("data",input$option,input$type, input$group))

})

output$plot <- renderPlotly({

 data <- data()

 p <-plot_ly(type = "scatter", mode="lines")
 p<-add_data(p, data) %>% add_trace(p, x= ~x, y = ~y)
 p

})
}

shinyApp(ui = ui, server = server)

I expect that the user can choose the option, type and group in the radiobutton selections, then add the curve. After that, make a new selection of option, type and group and add the new curve to the already existing one in the plot. The user should be able to do this several times. Do you know how this can be achived?

Thanks!

There are two general approaches you could try to take. If you're not working with a ton of data, I'd recommend this first approach that accumulates event data and does a full redraw everytime:


server <- function(input, output, session) {
  
  selections <- reactiveValues()
  
  observeEvent(input$add, {
    selections[[as.character(input$add)]] <- list(
      option = input$option,
      type = input$type,
      group = input$group
    )
  })
  
  output$plot <- renderPlotly({
    req(input$add)
    
    dats <- lapply(selections, function(x) {
      get(paste0("data", x$option, x$type, x$group))
    })
  
    dplyr::bind_rows(dats, .id = "selection") %>%
      dplyr::mutate(selection = paste("Selection", selection)) %>%
      plot_ly(x = ~x, y = ~y, color = ~selection, colors = "Set2") %>%
      add_lines()
  })
  
}

The other approach is less work computationally, but it requires intimate knowledge of plotly.js. The idea is to only add the new data on every button press:


server <- function(input, output, session) {
  
  output$plot <- renderPlotly(plotly_empty())
  
  observeEvent(input$add, {
    
    d <- get(paste0("data",input$option,input$type, input$group))
    
    # make sure data is sorted by x
    d <- dplyr::arrange(d, x)
    payload <- list(list(
      x = d$x,
      y = d$y,
      type = "scatter",
      mode = "lines",
      name = paste("Selection", input$add)
    ))
    
    p <- plotlyProxy("plot", session)
    
    if (input$add == 1) {
      plotlyProxyInvoke(p, "newPlot", list(data = payload))
    } else {
      plotlyProxyInvoke(p, "addTraces", payload)
    }
    
  })
}

2 Likes

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