1

I have asked this question in the RStudio community and didn't get help, so I try it here:

I am trying to add the following functionality to my app: When the user inserts a plot, a remove button should appear that specifically removes the plot that was inserted at the same time. The app is based on insertUI and removeUI.

This would be the example app.

library(shiny)
library(shinydashboard)

# Example data

a<-(letters)
b<-rnorm(length(letters), 4,2)
c<-rnorm(length(letters), 10,15)
d<-c(1:10,20:30,45:49)

data<-data.frame(a,b,c,d)
names(data)<-c("name","v1","v2","v3")

# UI

ui <- dashboardPage(
  dashboardHeader(),
  dashboardSidebar(
    actionButton("add", "Add"),
    radioButtons("add_elements","", c("Element1",   "Element2"))
  ),
  dashboardBody(
    fluidRow( tags$div(id="placeholder")
    )
))

# Server Logic

server <- function(input, output, session) {

 # Initialize empty vector
  inserted<- c()

  # Observer
  observeEvent(input$add, {
    id_add <- paste0(input$add, input$add_elements)

    insertUI(selector = '#placeholder', where = "afterEnd",
             ui= switch(input$add_elements,
                        'Element1'= plotOutput(id_add),
                        'Element2' = plotOutput(id_add))
    )

    output[[id_add]] <- 
      if (input$add_elements == "Element1") 

        renderPlot({
          plot(data[,1],data[,2])

          }) else if (input$add_elements == "Element2") 

          renderPlot({
            plot(data[,1],data[,4])
            })
    inserted <<- c(id_add,inserted)
    insertUI(
      selector = "#placeholder",
      where = "afterEnd",
      ui = tags$div(actionButton("remove_button", "Remove"))
      )})

  ## Remove Elements ###
  observeEvent(input$remove_button, {
    removeUI(
      selector = paste0('#', inserted[length(inserted)])
    )
    inserted <<- inserted[-length(inserted)]
  })
}

shinyApp(ui = ui, server = server)

When a plot is inserted, it gets an ID, such as 1Element1 or 2Element2. I am now wondering how could a remove button only refer to a plot with this exact ID?

So far, I have worked with a single remove button that removes the last inserted plot by defining a vector that stores the IDs.

selector = paste0('#', inserted[length(inserted)])

This is not very useful when a user needs to compare many plots. I have a limited understanding in using these selectors and absolutely no idea how could incorporate a remove button for every plot that only removes the respective plot. Any help would be highly appreciated.

Also, this link may help since it shows a similar functionality (that I was obviously not able to implement).

MKR
  • 1,620
  • 7
  • 20

1 Answers1

3

In this kind of situation I always use 'list' with 'reactiveValues' like below:

library(shiny)
library(shinydashboard)

# Example data

a<-(letters)
b<-rnorm(length(letters), 4,2)
c<-rnorm(length(letters), 10,15)
d<-c(1:10,20:30,45:49)

data<-data.frame(a,b,c,d)
names(data)<-c("name","v1","v2","v3")

# UI

ui <- dashboardPage(
  dashboardHeader(),
  dashboardSidebar(
    actionButton("add", "Add"),
    radioButtons("add_elements","", c("Element1",   "Element2"))
  ),
  dashboardBody(
    uiOutput("myUI")
  ))

# Server Logic

server <- function(input, output, session) {

  alld <- reactiveValues()
  alld$ui <- list()

  output$myUI <- renderUI({
    alld$ui
  })

  # Observer
  observeEvent(input$add, {
    id_add <- length(alld$ui)+1

    alld$ui[[id_add]] <-  list(
      plotOutput(paste0("plt",id_add)),
      actionButton(paste0("remove_button", id_add), "Remove")
    )


      if (input$add_elements == "Element1"){
        output[[paste0("plt",id_add)]] <- renderPlot(plot(data[,1],data[,2]))
      } else {
        output[[paste0("plt",id_add)]] <- renderPlot(plot(data[,1],data[,4]))
      }
    })



  ## Remove Elements (for all plots) ###
observe({
  lapply(seq_len(length(alld$ui)), function(i){
    id_add <- i
    observeEvent(input[[paste0("remove_button", id_add)]], {
      alld$ui[[id_add]][1] <- NULL
    })
  })

})


}

shinyApp(ui = ui, server = server)
Raja Saha
  • 499
  • 5
  • 14
  • Thanks for your solution (and sorry for not getting back to you for a week). The use of `reactiveValues` and `list()` is indeed very nice. I am trying to understand a few things: What exactly does the `ouput[["expression"]] <- renderPlot{...}` do? Does this add a value to a list? – MKR Feb 26 '19 at 17:35