1

I am trying to update multiple data attributes in a figure generated via plotly.

This is my script based on this post:

library(plotly)
library(magrittr)
library(data.table)

X <- data.table(x = c(1, 2, 1, 2), y = c(1, 1, 2, 2), z = rep(c("a", "b"), each = 2))

gg <- ggplot() + geom_point(data = X, aes(x = x, y = y, color = z))

ggplotly(gg) %>% 
  layout(
    updatemenus = list(
      list(
        buttons = list(
          list(method = "restyle",
               args = list(
                 list(x = list(X[z == "a", x])),
                 list(y = list(X[z == "a", y]))
               ),
               label = "a"),
          list(method = "restyle",
               args = list(
                 list(x = list(X[z == "b", x])),
                 list(y = list(X[z == "b", y]))
               ),
               label = "b")
        )
      )
    )
  )

enter image description here

However, as can be seen, the update menu does not work as intended. Not sure what the problem is.

mat
  • 2,412
  • 5
  • 31
  • 69
  • Can you please elaborate on the expected behaviour? Do you want to hide/show the traces? If so why don't you click on the legenditems? – ismirsehregal Apr 07 '22 at 20:28

1 Answers1

2

There are too many lists in your above args parameter.

Furthermore, when calling restyle without specifying the trace number you are restyling all traces.

If you want to restyle a single trace you need to provide its trace index:

library(plotly)
library(magrittr)
library(data.table)

DT <- data.table(x = c(1, 2, 10, 20), y = c(1, 1, 20, 20), z = rep(c("a", "b"), each = 2))

gg <- ggplot() + geom_point(data = DT, aes(x = x, y = y, color = z))

ggplotly(gg) %>% 
  layout(
    updatemenus = list(
      list(
        buttons = list(
          list(method = "restyle",
               args = list(list(x = DT[z == "a", x], y = DT[z == "a", y]), 0L),
               label = "a"),
          list(method = "restyle",
               args = list(list(x = DT[z == "b", x], y = DT[z == "b", y]), 1L),
               label = "b")
        )
      )
    )
  )

I'm not sure what you are trying to achive.

If you want to show trace "a" when "a" is selected and trace "b" when "b" is selected this filter approach is problematic, as it completly removes traces (reduces the dataset) from the plot and once the trace is removed you can no longer restyle it.

If you just want to toggle the trace visibility you should use the visible parameter instead of modifying the data:

DT <- data.table(x = c(1, 2, 10, 20), y = c(1, 1, 20, 20), z = rep(c("a", "b"), each = 2))

gg <- ggplot() + geom_point(data = DT, aes(x = x, y = y, color = z))

ggplotly(gg) %>% style(visible = FALSE, traces = 2) %>% 
  layout(
    updatemenus = list(
      list(
        buttons = list(
          list(method = "restyle",
               args = list(list(visible = c(TRUE, FALSE)), c(0, 1)),
               label = "a"),
          list(method = "restyle",
               args = list(list(visible = c(FALSE, TRUE)), c(0, 1)),
               label = "b")
        )
      )
    )
  )

result

PS: Plotly.restyle expects the trace count starting from 0 (JS) and style() from 1 (R)

Using addTraces/deleteTraces as done here would be another approach. However, if the data stays the same I guess toggling the visibility is less computationally intensive.

ismirsehregal
  • 30,045
  • 5
  • 31
  • 78
  • 1
    Works like a charm, thanks! Wish we could use the same indexing system for `plotly.restyle` and `style()`. – mat Apr 08 '22 at 08:07
  • I have another question that builds on the top of this one. Maybe you have the answer: https://stackoverflow.com/questions/71807698/plotly-independent-updatemenus – mat Apr 09 '22 at 11:34