Search code examples
rplotlyr-plotlyggplotly

Plotly multiple updatemenus


Building on this post, I am trying to create two updatemenus in R plotly that would allow to select every possible combination of two factors.

This is what I have done so far:

library(plotly)

X <- data.frame(x = 1:6,
                y = 1:6,
                z = 1:6,
                gender = rep(c("M", "F"), each = 3),
                eyes = rep(c("B", "G"), 3))

gg <- ggplot(data = X, aes(x = x, y = y)) + 
  geom_point(aes(color = z, alpha = interaction(gender, eyes))) +
  scale_alpha_manual(values = rep(1, 4))


ggplotly(gg) %>% 
  layout(
    updatemenus = list(
      list(y = 1,
           buttons = list(
             list(method = "restyle",
                  args = list(list(visible = c(TRUE, TRUE, TRUE, TRUE)), 0:3),
                  label = "F&M"),
             list(method = "restyle",
                  args = list(list(visible = c(TRUE, TRUE)), c(0, 2)),
                  label = "F"),
             list(method = "restyle",
                  args = list(list(visible = c(TRUE, TRUE)), c(1, 3)),
                  label = "M"))),
      list(y = .8,
           buttons = list(
             list(method = "restyle",
                  args = list(list(visible = c(TRUE, TRUE, TRUE, TRUE)), 0:3),
                  label = "B&G"),
             list(method = "restyle",
                  args = list(list(visible = c(TRUE, TRUE)), 0:1),
                  label = "B"),
             list(method = "restyle",
                  args = list(list(visible = c(TRUE, TRUE)), 2:3),
                  label = "G")))
    )
  )
)

The data:

#  x y z gender eyes
#  1 1 1      M    B
#  2 2 2      M    G
#  3 3 3      M    B
#  4 4 4      F    G
#  5 5 5      F    B
#  6 6 6      F    G

This is the output, which does not work at all: enter image description here


Edit
For instance, if F and B are selected, I would expect only a single data point to be displayed, namely (5, 5).


Solution

  • When you created this plotly object, plotly divided it into five traces. So when you wanted to use visibility, you needed to address each of these traces. If you have any questions, let me know!

    I used gg1 to find five traces and what was in each of these traces. You could look at gg1 in the source pane or plotly_json().

    Typically (not always!), you'll find the traces at gg1$x$data where gg1 is the plotly object.

    There are five traces. For each args, each trace needs a T or F for visibility.

    • The first trace only contains (5, 5), that's F B
    • The second trace contains (1, 1) and (3, 3); those are both M B
    • The third trace contains (4, 4) and (6, 6); those are both F G
    • The fourth trace contains (2, 2); that's M G
    • The fifth trace contains the color gradient that all traces use

    Here's the code:

    gg1 = plotly_build(gg) 
    
    ggplotly(gg) %>% 
      layout(
        updatemenus = list(
    
          list(y = 1,
               buttons = list(
                 list(method = "restyle",
                      args = list("visible", as.list(unlist(rep(T, 5)))),
                      label = "F&M"),
                 list(method = "restyle",
                      args = list("visible", list(T, F, T, F, T)),
                      label = "F"),
                 list(method = "restyle",
                      args = list("visible", list(F, T, F, T, T)),
                      label = "M")
                 ) # end button
               ),  # end first button list
          list(y = .8,
               buttons = list(
                 list(method = "restyle",
                      args = list("visible", as.list(unlist(rep(T, 5)))),
                      label = "B&G"),
                 list(method = "restyle",
                      args = list("visible", list(T, T, F, F, T)),
                      label = "B"),
                 list(method = "restyle",
                      args = list("visible", list(F, F, T, T, T)),
                      label = "G")
                 ) # end button
               ) # end second menu list
        ) # end updatemenus
      ) # end layout
    


    Update

    From our comments, I do not believe that it's possible at this time to use updatemenus style buttons that interact with each other.