如何在R的Plotly分组柱状图中添加按钮切换X轴数据
问题描述
我想用Plotly创建分组柱状图,展示每位艺人的T恤销量及类型,同时添加按钮实现单个艺人数据的切换查看,但初始代码无法正常运行。调整数据结构后,新问题是:选择下拉菜单中的艺人时,希望只展示该艺人有销量的产品(动态移除0值),请问是否可行?
初始数据与代码
数据框
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)
尝试的初始代码
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
补充尝试的数据与代码
调整后的数据框
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
解决方案
完全可以实现切换艺人时只显示非0销量的产品,核心是通过长格式数据整理+独立trace控制+动态更新x轴来实现。以下是完整可运行的代码:
library(plotly) library(tidyr) # 1. 整理为长格式数据(过滤掉0销量记录) product <- c("tee_x","tee_y","tee_t") Black_Waitress <- c(20, 0, 0) Black_Pumas <- c(3, 18, 35) # 修正原数据中tee_t的数值,匹配初始数据 data_long <- data.frame(product, Black_Waitress, Black_Pumas) %>% pivot_longer(cols = -product, names_to = "artist", values_to = "sales") %>% filter(sales > 0) # 2. 为每个艺人创建独立的trace fig <- plot_ly() # 添加Black Waitress的trace(默认显示) fig <- fig %>% add_trace( data = data_long %>% filter(artist == "Black_Waitress"), x = ~product, y = ~sales, type = "bar", name = "Black Waitress", visible = TRUE ) # 添加Black Pumas的trace(默认隐藏) fig <- fig %>% add_trace( data = data_long %>% filter(artist == "Black_Pumas"), x = ~product, y = ~sales, type = "bar", name = "Black Pumas", visible = FALSE ) # 3. 定义下拉菜单按钮:同时控制trace可见性和x轴内容 updatemenus <- list( list( type = "dropdown", active = 0, buttons = list( list( label = "Black Waitress", method = "restyle", args = list( "visible", list(TRUE, FALSE), "x", list(data_long %>% filter(artist == "Black_Waitress") %>% pull(product)) ) ), list( label = "Black Pumas", method = "restyle", args = list( "visible", list(FALSE, TRUE), "x", list(data_long %>% filter(artist == "Black_Pumas") %>% pull(product)) ) ) ) ) ) # 4. 布局设置 fig <- fig %>% layout( yaxis = list(title = "Count"), updatemenus = updatemenus, showlegend = FALSE ) fig
关键细节说明
- 长格式数据:用
pivot_longer将宽格式转为长格式,再过滤掉0销量记录,方便按艺人筛选有效数据 - 独立trace:每个艺人对应一个独立的trace,通过
visible参数控制显示/隐藏 - 动态x轴:在按钮的
args中同时指定x轴的产品列表,确保切换艺人时x轴只显示该艺人有销量的产品 - 数据修正:原补充代码中
Black_Pumas的tee_t数值为0,和初始数据的35不符,已修正保证数据一致性
如果需要保留所有产品的x轴(仅隐藏0销量的柱子),可以基于宽格式数据为每个产品-艺人组合创建trace,再通过按钮控制对应艺人的所有trace显示。
内容的提问来源于stack exchange,提问作者Fras
相关产品推荐
相关产品推荐

