如何在R Plotly分组柱状图中对齐散点轨迹
解决Plotly分组柱状图中散点与对应年份柱子对齐的问题
问题核心
制作按年份分组的残疾人收入来源柱状图时,添加非残疾人的散点对比,散点默认落在x轴类别中心,无法和对应年份的柱子对齐。
解决方案思路
Plotly的分组柱状图中,每个x类别下的多组柱子会被分配相对偏移量(比如3组对应-0.2、0、0.2,以保持类别中心对齐)。要让散点和对应年份的柱子对齐,需要给非残疾人数据计算对应的x轴偏移位置,而非直接使用分类标签。
具体步骤
- 为每个年份分配固定偏移量:根据年份数量设置对应偏移值(3个年份可设为
c(-0.2, 0, 0.2))。 - 获取x轴分类标签的数值索引:Plotly将分类x轴转换为0、1、2...的底层索引,通过
match()函数得到每个类别的索引值(需减1适配Plotly的0起始规则)。 - 计算散点实际x位置:类别索引 + 对应年份的偏移量。
修改后的完整代码
先补充模拟的非残疾人数据(原数据仅包含残疾人),再调整代码逻辑:
library(plotly) library(tidyr) # 原始数据 + 模拟非残疾人数据 Figure16 <- structure(list(Disability = c("Disabled", "Disabled", "Disabled", "Non-disabled", "Non-disabled", "Non-disabled"), Year = c("2017/18", "2018/19", "2019/20", "2017/18", "2018/19", "2019/20"), `Wages and salaries` = c(0.32, 0.34, 0.37, 0.45, 0.47, 0.49), `All Pensions` = c(0.34, 0.32, 0.31, 0.28, 0.26, 0.24), `All Social Security benefits` = c(0.37, 0.27, 0.23, 0.30, 0.22, 0.18), `Self employment income` = c(0.03, 0.03, 0.06, 0.08, 0.10, 0.12)), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -6L)) # 数据整理 Figure16 <- pivot_longer(Figure16, cols=c('Wages and salaries','All Pensions','All Social Security benefits','Self employment income'), names_to='Sources', values_to='Rate') Figure16$Rate <- as.numeric(Figure16$Rate) * 100 # 包装x轴标签 Figure16$wrappedy <- sapply(Figure16$Sources, FUN = function(x) {paste(strwrap(x, width = 25), collapse = " <br> ")}) # 为年份分配偏移量:3个年份对应-0.2、0、0.2 year_offsets <- c("2017/18" = -0.2, "2018/19" = 0, "2019/20" = 0.2) Figure16$x_offset <- year_offsets[as.character(Figure16$Year)] # 获取每个x类别的底层数值索引(适配Plotly的0起始规则) Figure16$x_index <- match(Figure16$wrappedy, unique(Figure16$wrappedy)) - 1 # 计算散点的实际x位置:索引 + 偏移 Figure16$scatter_x <- Figure16$x_index + Figure16$x_offset # 绘制图表 Figure_16 <- plot_ly(Figure16[Figure16$Disability =="Disabled",], x = ~wrappedy, y = ~Rate, type = 'bar', color = ~Year, colors = c("#8FAADC","#2F5597","#203864"), name = ~Year, marker = list(color = ifelse(Figure16$Year=="2017/18","#8FAADC", ifelse(Figure16$Year=="2018/19","#2F5597", ifelse(Figure16$Year=="2019/20","#203864", ""))), pattern = list(shape = ifelse(Figure16$Year=="2017/18","x", ifelse(Figure16$Year=="2018/19","/", ""))), line = list(color = ifelse(Figure16$Year=="2017/18","#8FAADC", ifelse(Figure16$Year=="2018/19","#2F5597", ifelse(Figure16$Year=="2019/20","#203864", ""))), width = 1.25)) )%>% # 添加散点:使用计算后的scatter_x作为x值 add_trace(data = Figure16[Figure16$Disability =="Non-disabled",], x = ~scatter_x, y = ~Rate, type = 'scatter', mode = 'markers', name = 'Non-disabled', marker = list(size = 30, symbol ='line-ew-open', color = "#FFC000", line=list(color = "#FFC000"), width = 33))%>% # 配置x轴:保留分类标签显示 layout(xaxis = list(title = "", ticktext = ~unique(wrappedy), tickvals = ~unique(x_index)), yaxis = list(title = "", rangemode='tozero', ticksuffix = "%"))%>% config(displayModeBar = FALSE)
关键说明
year_offsets:偏移量可根据年份数量调整,比如2个年份用-0.15和0.15,保证柱子间距合理。scatter_x:通过数值索引加偏移,让散点精准对应同一年份的柱子位置。layout中的ticktext和tickvals:确保x轴显示原始分类标签,而非底层数值索引。
该方法可复用在你需要制作的7个图表中,仅需根据年份数量调整偏移量即可。
内容的提问来源于stack exchange,提问作者Rory
相关产品推荐
相关产品推荐

