Quarto仪表板Plotly分组条形图Crosstalk过滤间距问题求助
问题:Crosstalk筛选后分组条形图组内间距异常
在Quarto仪表板中使用crosstalk为分组条形图实现Indicator筛选功能,每组展示对应Indicator的First/Second两个数值(通过透明度区分)。筛选功能可返回正确条形,但筛选后组内的两个条形仍保留所有Indicator同时显示时的间距,无法填满组内空间,调整数据排序也无法解决该问题。
问题原因
ggplot默认的position_dodge()是基于原始完整数据的分组数量计算条形间距,crosstalk筛选仅隐藏了不符合条件的数据,并未更新ggplot的底层布局参数,导致筛选后间距仍按多Indicator的情况保留,无法适配当前仅显示2个条形的组。
解决方案
使用position_dodge2(preserve = "single")替代默认的position_dodge(),该参数会根据当前每组实际显示的条形数量动态调整间距,确保条形填满组内空间;同时需将FirstSecond映射到group美学,让ggplot正确识别每组内的子分组。
修改后的完整代码
library(plotly) library(ggplot2) library(crosstalk) library(htmltools) df <- data.frame(FirstSecond = c("First", "Second", "First", "Second", "First", "Second", "First", "Second", "First", "Second", "First", "Second", "First", "Second", "First", "Second", "First", "Second", "First", "Second", "First", "Second", "First", "Second"), Group = c("Group 1", "Group 1", "Group 1", "Group 1", "Group 1", "Group 1", "Group 1", "Group 1", "Group 2", "Group 2", "Group 2", "Group 2", "Group 2", "Group 2", "Group 2", "Group 2", "Group 3", "Group 3", "Group 3", "Group 3", "Group 3", "Group 3", "Group 3", "Group 3"), Indicator = c("Indicator 1","Indicator 1","Indicator 2","Indicator 2", "Indicator 3","Indicator 3","Indicator 4","Indicator 4", "Indicator 1","Indicator 1","Indicator 2","Indicator 2", "Indicator 3","Indicator 3","Indicator 4","Indicator 4", "Indicator 1","Indicator 1","Indicator 2","Indicator 2", "Indicator 3","Indicator 3","Indicator 4","Indicator 4"), value = c(3, 5, 2.5, 3, 1.3, 2, 4, 4.5, 3, 5, 2.5, 3, 1.3, 2, 4, 4.5, 3, 5, 2.5, 3, 1.3, 2, 4, 4.5)) shared_df <- crosstalk::SharedData$new(df) div( filter_select( id = "indicator_selector", label = HTML("<span style='font-size: 15px;'>Select Indicator</span>"), sharedData = shared_df, group = ~ Indicator, multiple = F ), br(), plotly::ggplotly(tooltip = c("text"), ggplot(data = shared_df, aes(x = Group, y = value, group = FirstSecond)) + # 添加group映射 geom_bar(aes(fill = Group, alpha = factor(FirstSecond)), position = position_dodge2(preserve = "single"), # 替换为position_dodge2 stat = "identity", color = "black") + scale_alpha_manual(values = c(1, 0.6)) + ylim(0,7)+ scale_fill_viridis_d() + scale_y_continuous(breaks = c(1,2,3,4,5,6,7), limits = c(0,7)) + scale_x_discrete(guide = guide_axis(n.dodge=2)) + labs(x = "Group") + guides(fill="none") + ggplot2::theme( axis.line = element_line(color = 'black'), panel.background = element_rect(fill = "white"), panel.grid.major.y = element_blank(), panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank(), legend.key.size = unit(0.2, 'cm'), legend.key.height = unit(0.2, 'cm'), legend.key.width = unit(0.2, 'cm'), legend.title = element_text(size = 8), legend.text = element_text(size = 5), axis.title.x = element_text(size = 12), axis.title.y = element_text(size = 12), plot.title = element_text(size = 16), plot.subtitle = element_text(size = 12), legend.position = "none", plot.caption = element_text(size =13), axis.text.x = element_text(vjust = 0.55, size = 10), axis.text.y = element_text(size = 10) ) ) %>% plotly::config(modeBarButtonsToRemove = c( "zoom2d","pan2d","select2d","lasso2d", "zoomIn2d", "zoomOut2d", "autoScale2d", "resetScale2d", "hoverClosestCartesian", "hoverCompareCartesian", "zoom3d", "pan3d", "resetCameraDefault3d", "resetCameraLastSave3d", "hoverClosest3d", "orbitRotation", "tableRotation", "zoomInGeo", "zoomOutGeo", "resetGeo", "hoverClosestGeo", "sendDataToCloud", "hoverClosestGl2d", "hoverClosestPie", "toggleHover", "resetViews", "toggleSpikelines", "resetViewMapbox" ), displayLogo = F) %>% plotly::layout(xaxis = list(title = list(standoff = 10, font = list(family = "Arial", size = 10)), tickfont = list(family = "Arial", size = 9), tickangle = 12), yaxis = list(title = list(standoff = 20, text = "Average Score", font = list(family = "Arial", size = 12), tickfont = list(size = 12)), tickfont = list(size = 12, family = "Arial"), ticks = "outside", tickcolor='white', ticklen=10, range = c(0,7), showline = T ), showlegend = F, hoverlabel = list(font=list(size=8)), autosize = T, height = 350 ) ) %>% browsable()
内容的提问来源于stack exchange,提问作者Ben_Kimpton
相关产品推荐
相关产品推荐

