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.

1
  • 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? Commented Apr 7, 2022 at 20:28

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Works like a charm, thanks! Wish we could use the same indexing system for plotly.restyle and style().
I have another question that builds on the top of this one. Maybe you have the answer: stackoverflow.com/questions/71807698/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.