2

I am new to shiny and plotly. What I'm trying to do is to add a trace first and then I want it to be replaced by a new one every time I click on a button.

here is my minimal example:

library(shiny)
library(plotly)

ui <- fluidPage(plotlyOutput("fig1"),
                
                numericInput("A",
                             label = h5("A"),
                             value = "",
                             width = "100px"),
                numericInput("B",
                             label = h5("B"),
                             value = "",
                             width = "100px"),
                actionButton("action3", label = "Add to plot"),
                actionButton("action4", label = "Remove point")
                
                
                )
server <- function(input, output) {
  
  
  A <- 1:5
  B <- c(115, 406, 1320, 179, 440)
  data <- data.frame(A, B)
  
  fig <- plot_ly(data, x = A, y = B, type = 'scatter', mode = 'markers')
  
  output$fig1 <- renderPlotly(fig)
  
  observeEvent(input$action3, {
    vals <- reactiveValues(A = input$A, B = input$B)
    plotlyProxy("fig1") %>%
      plotlyProxyInvoke("addTraces", 
                        list(x = c(vals$A,vals$A),
                             y = c(vals$B,vals$B),
                             type = "scatter",
                             mode = "markers"
                             
                        )
      )
  })
  observeEvent(input$action4, {
    vals <- reactiveValues(A = input$A, B = input$B)
    plotlyProxy("fig1") %>%
      plotlyProxyInvoke("deleteTraces")
  })
}

shinyApp(ui,server)

I can add a new trace easily but they all remain on the plot. My solution was to add a new button to delete the trace but it did not work. I have already read this but I couldn't make it work.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214

1 Answers1

1

Based on what you described, it sounds like you want to add a trace and remove the most recent trace added at the same time when the button is pressed. This would still leave the original plot/trace that you started with.

I tried simplifying a bit. The first plotlyProxyInvoke will remove the most recently added trace (it is zero-indexed, leaving the first plotly trace in place).

The second plotlyProxyInvoke will add the new trace. Note that the (x, y) pair is included twice based on this answer.

library(shiny)
library(plotly)

A <- 1:5
B <- c(115, 406, 1320, 179, 440)
data <- data.frame(A, B)

ui <- fluidPage(plotlyOutput("fig1"),
                numericInput("A",
                             label = h5("A"),
                             value = "",
                             width = "100px"),
                numericInput("B",
                             label = h5("B"),
                             value = "",
                             width = "100px"),
                actionButton("action3", label = "Add to plot"),
)

server <- function(input, output, session) {
  
  fig <- plot_ly(data, x = A, y = B, type = 'scatter', mode = 'markers')
  
  output$fig1 <- renderPlotly(fig)
  
  observeEvent(input$action3, {
    plotlyProxy("fig1", session) %>%
      plotlyProxyInvoke("deleteTraces", list(as.integer(1)))
    plotlyProxy("fig1", session) %>%
      plotlyProxyInvoke("addTraces", 
                        list(x = c(input$A, input$A),
                             y = c(input$B, input$B),
                             type = 'scatter',
                             mode = 'markers')
      )
  })
  
}

shinyApp(ui,server)
Ben
  • 28,684
  • 5
  • 23
  • 45
  • Thank you that was exactly what I wanted to do although I did not understand the list(as.integer(1) or the "zero- index" as you said. – Reza Khayami Sep 08 '21 at 08:06
  • 1
    "zero-indexed" refers to the numbering system used with `plotly`, starting 0, 1, 2...instead of with R which is one-indexed or 1, 2, 3...etc. So in this case, you include which trace to delete, since it is zero-indexed, the first trace is trace 0, second trace is trace 1, etc. Since you already have your first trace with 5 points, the second trace is the single point added, or trace 1, which is removed. I noticed that the other examples used `as.integer()` so I assumed that an integer was needed for the index (technically 1 is `double` not `integer`)...and structure needed is `list`... – Ben Sep 08 '21 at 12:53