Plotly grouped barchart : how to create buttons to display different x values R

Viewed 54

this is my dataframe :

artists <- c("Black Waitress", "Black Pumas")
tee_x<- c(20, 0)
tee_y <- c(3, 18)
tee_z <- c (30,0)
tee_t <- c(0,35)
data2 <- data.frame(artists, tee_x, tee_y,tee_t)

And this is what I am trying to create :

fig <- plot_ly(data=data2, x = ~artists, y = ~tee_x, type = 'bar', name = 'tee_x')
fig <- fig %>% add_trace(y = ~tee_y, name = 'tee_y')
fig <- fig %>% add_trace(y = ~tee_t, name = 'tee_t')
fig <- fig %>% layout(yaxis = list(title = 'Count'), barmode = 'group',
                      updatemenus = list(
                          list(
                            y = 0.8,
                            buttons = list(
                              list(method = "restyle",
                                   args = list("x", list(data2[c(1),(2:4)])),
                                   label = "Black Waitress"),

                              list(method = "restyle",
                                   args = list("x", list(data2[c(2),(2:4)])),
                                   label = "Black Pumas")))
                            ))

fig

I am trying to create a grouper barplot in plotly which shows, for each artist the number of tees they sold and their type. I am also trying to create buttons so that you can look at individual artists instead of both of them. However it is not working and I have no clue how to solve the problem.

Thank you

EDIT :

I have been also trying this way

    product <- c("tee_X","tee_y","tee_t")
artists <- c("Black Waitress", "Black Pumas")
Black_Waitress<- c(20, 0, 0)
Black_Pumas <- c(3, 18, 0)
tee_z <- c (30,0)
tee_t <- c(0,35)
data2 <- data.frame(product, Black_Waitress, Black_Pumas)
show_vec = c()

for (i in 1:length(artists)){
  show_vec = c(show_vec,FALSE)
}
get_menu_list <- function(artists){
  n_names = length(artists)
  buttons = vector("list",n_names)
  
  for(i in seq_along(buttons)){
    show_vec[i] = TRUE
    buttons[i] = list(list(method = "restyle",
                           args = list("visible", show_vec),
                           label = artists[i]))
    print(list(show_vec))
    show_vec[i] = FALSE
  }
  
  return_list = list(
    list(
      type = 'dropdown',
      active = 0,
      buttons = buttons
    )
  )
  
  return(return_list)
}
print(get_menu_list(artists)) 
fig <- plot_ly(data=data2, x = ~product, y = ~Black_Waitress, type = 'bar')
fig <- fig %>% add_trace(y = ~Black_Pumas)
fig <- fig %>% layout(showlegend = F,yaxis = list(title = 'Count'), barmode = 'group',
                      updatemenus = get_menu_list(artists))
fig

However the problem is that when I choose an artist in the dropdown menu I want to be shown ONLY his/her products (in other words I would like to get rid of the 0 values dynamically) Is this possible?

1 Answers

Without the 0 Values and Initially Blank Plot

Essentially, you need to add a trace with no data. Additionally, since visibility settings were defined, all of that requires updating (because there are more traces now).

This can be further customized, of course. Here's a basic version of what I think you're looking for.

plot_ly(data = data3, x = ~artists, y = 0, type = "bar", color = ~tees,
        visible = c(T, T, T)) %>% 
  add_bars(y = ~values, split = ~artists,      # visibility F for all here
           legendgroup = ~tees, name = ~tees, visible = rep(F, times = 4),
           color = ~tees) %>% 
  layout(
    yaxis = list(title = "Count"), barmode = "group",
    updatemenus = list(
      list(y = .8,
           buttons = list(
             list(method = "restyle",          # there are 7 traces now; 3 blank
                  args = list(list(visible = c(F, F, F, F, T, F, T))),
                  label = "Black Waitress"),
             list(method = "restyle",
                  args = list(list(visible = c(F, F, F, T, F, T, F))),
                  label = "Black Pumas")))))

enter image description here


Without the 0 Values

By your request, here is a version where the zero values are removed. First, I filtered the data for the non-zero values. This changed the number of traces from 6 to 4, so that needed to be accounted for in the areas where visibility is declared.

In this version, I only commented where there was something that changed from my original answer.

library(plotly)
library(tidyverse)

artists <- c("Black Waitress", "Black Pumas")
tee_x <- c(20, 0)
tee_y <- c(3, 18)
# tee_z <- c(30,0)
tee_t <- c(0,35)
data2 <- data.frame(artists, tee_x, tee_y, tee_t)

data3 <- pivot_longer(data2, col = starts_with("tee"),
                      names_to = "tees", values_to = "values") %>% 
  filter(values != 0)                     # <----- filter for non-zeros

plot_ly(data = data3, x = ~artists, y = ~values, split = ~artists, 
        legendgroup = ~tees, name = ~tees, 
        visible = rep(c(F, T), times = 2), # <---- 4 traces
        color = ~tees, type = "bar") %>% 
  layout(
    yaxis = list(title = "Count"), barmode = "group",
    updatemenus = list(
      list(y = .8,
           buttons = list(
             list(method = "restyle",           # 4 traces
                  args = list(list(visible = c(F, T, F, T))),
                  label = "Black Waitress"),
             list(method = "restyle",           # 4 traces
                  args = list(list(visible = c(T, F, T, F))),
                  label = "Black Pumas")))))

enter image description here

enter image description here


With the 0 Values

I think it will be a lot easier to use visibility than trying to change out the data. If you wanted to see one artist at a time and use the dropdown to switch between the groups, this works.

First, I rearranged the data to make this easier. When I plotted it, I used split, so that the traces were split by the values on the x-axis, along with the colors. The traces are ordered artist 1, tee_t, artist 2, tee_t... and so on. When using visibility, you need the method restyle (because it's a trace attribute) and a declaration of true or false for each trace.

library(tidyverse)
library(plotly)

data3 <- pivot_longer(data2, col = starts_with("tee"),
                      names_to = "tees", values_to = "values")


plot_ly(data = data3, x = ~artists, y = ~values, split = ~artists, 
        legendgroup = ~tees, name = ~tees, visible = rep(c(F, T), times = 3),
        color = ~tees, type = "bar") %>% 
  layout(
    yaxis = list(title = "Count"), barmode = "group",
    updatemenus = list(
      list(y = .8,
           buttons = list(
             list(method = "restyle",
                  args = list(list(visible = c(F, T, F, T, F, T))),
                  label = "Black Waitress"),
             list(method = "restyle",
                  args = list(list(visible = c(T, F, T, F, T, F))),
                  label = "Black Pumas"))))) 

enter image description here

enter image description here

Related