Search code examples
rggplot2plotlyr-plotlymle

Adding a static element across slider steps in a R plotly graph


I am giving a tutorial on MLE and am trying to figure out how to add a static grouping of points to a plotly graph. Obviously the idea is that as I slide the normal distributions over you can see that the points correspond to a lower or higher likeihood. However, I can only get the points to appear on the first frame.

x <- seq(0, 10, length.out = 1000)

aval <- list()
for (step in 1:6) {
  aval[[step]] <- list(
    visible = FALSE,
    name = paste0('v = ', step),
    x = x,
    y = dnorm(x, step+1)
  )
  
}

aval[3][[1]]$visible = TRUE

steps <- list()
fig <- plot_ly()

for (i in 1:6) {
  fig <-
    add_lines(
      fig,
      x = aval[i][[1]]$x,
      y = aval[i][[1]]$y,
      visible = aval[i][[1]]$visible,
      
      name = aval[i][[1]]$name,
      type = 'scatter',
      mode = 'lines',
      hoverinfo = 'name',
      
      line = list(color = '00CED1'),
      showlegend = FALSE
    )

step <- list(args = list('visible', rep(FALSE, length(aval))),method = 'restyle')
  step$args[[2]][i] = TRUE
  steps[[i]] = step
  
}


fig <- fig %>% add_markers(x = c(4.5,5,5.5), y = c(0,0,0))
# add slider control to plot

fig <- fig %>%
  layout(sliders = list(list(
    active = 0,
    currentvalue = list(prefix = "Frequency: "),
    steps = steps
  )))


fig

Solution

  • Why don't you use plotly's animation capabilities?

    But regardless of whether you define custom steps or you use the frame parameter, you'll have to provide the "static" points for each step:

    library(plotly)
    library(data.table)
    
    f <- 1:6
    x <- seq(0, 10, length.out = 1000)
    y <- unlist(lapply(f+1, dnorm, x = x))
    
    DT <- CJ(f, x) # like expand.grid()
    DT[, y := y]
    DT[, step := paste0("step-", f)]
    
    staticDT <- CJ(f, x = c(4.5,5,5.5), y = 0)
    staticDT[, step := paste0("step-", f)]
    
    fig <- plot_ly(
      data = DT,
      x = ~x,
      y = ~y,
      frame = ~step,
      type = 'scatter',
      mode = 'lines',
      showlegend = FALSE,
      color = I('#00CED1')
    )
    
    fig <- add_trace(
      fig,
      data = staticDT,
      x = ~x,
      y = ~y,
      frame = ~step,
      type = 'scatter',
      mode = 'markers',
      showlegend = FALSE,
      color = I('red'),
      inherit = FALSE
    )
    
    fig <- animation_opts(
      fig, transition = 0, redraw = FALSE
    )
    
    fig <- animation_slider(
      fig, currentvalue = list(prefix = "Frequency: ")
    )
    
    fig
    

    result