在R的ggiraph中如何为图例与图表设置相同data_id实现联动高亮?
问题:实现堆叠条形图与图例的悬停联动
我需要实现鼠标悬停在图表分段上时,对应图例标签和填充色同步高亮;悬停图例时,对应图表分段也高亮。按要求图例和图表需设置相同的data_id,但操作中遇到问题:
向scale_fill_manual_interactive()添加data_id=groupID时,触发错误:
Error in scale_interactive(scale_fill_manual, ...) :
object 'groupID' not found
改用data_id = function(breaks) { as.character(breaks) }能运行,但无法实现图表与图例的联动,找不到原因。
以下是我的代码:
library(ggplot2) library(ggiraph) library(ggrepel) library(scales) Area <- c("location1", "location2", "location3", "location4") very_good <- c(14, 7, 17, 16) good <- c(33, 31, 35, 31) quite_bad <- c(33, 36, 30, 1) very_bad <- c(17, 2, 14, 10) #Custom labels for the legend Labels <- c("Very good", "Good", "Quite bad", "Very bad, wont return") df1 <- data.frame( Area, very_good, good, quite_bad, very_bad ) df1_subset <- df1 %>% mutate_at(vars(2:5), funs(./100)) %>% pivot_longer( cols = c(2:5), names_to = "Question", values_to = "Result" ) df1_subset <- transform( df1_subset,groupID=as.numeric(forcats::fct_inorder(Question)) ) set.seed(1) stacked_chart <- ggplot( data = df1_subset, aes( x = Result, y = Area, group = Question, fill = Question, data_id = groupID ) ) + geom_col_interactive( position = position_fill(reverse = TRUE) ) + geom_text_repel_interactive( aes( color = ifelse(Result > 0.06, "#FFFFFF", "transparent"), label = percent(Result) ), fontface = "bold", position = position_fill( reverse = TRUE ), box.padding = 0.05, segment.color = "transparent", size = 5, direction = "x", hjust = 1.5 ) + scale_y_discrete( limits = rev(Area) ) + scale_x_continuous( labels = scales::percent, expand = c(0, 0), limits = c(0, 1) ) + scale_color_identity() + scale_fill_manual_interactive( data_id = lapply(Labels, function(breaks) { as.character(breaks) }), labels = function(breaks) { lapply(Labels, function(breaks) { label_interactive( breaks, data_id = as.character(breaks) ) }) }, values = c( "#000000", "#333333", "#666666", "#999999" ) ) + theme_minimal() + theme( legend.position = "top", legend.justification = "left", legend.title = element_blank() ) stacked_chart_ggiraph <- girafe( ggobj = stacked_chart, width_svg = 9, height_svg = 6, options = list( opts_sizing(rescale = TRUE), opts_toolbar(saveaspng = FALSE), opts_hover_inv(css = girafe_css( css = "opacity:0.3;" )), opts_hover(css = girafe_css( css = "cursor:pointer;fill:red;", text = "cursor:pointer;fill:#222222;" )), opts_hover_key(css = girafe_css( css = "cursor:pointer;fill:red;" )) ) ) stacked_chart_ggiraph
解决方案
问题核心是scale层无法直接访问数据框中的groupID列,scale的参数是基于图例的breaks(即Question的原始取值)进行映射的,而非直接引用数据列。要实现联动,必须让图表元素和图例元素的data_id完全匹配。
修改步骤:
- 图表的
data_id改用Question(与图例breaks的取值一致),替代原来的groupID - 在
scale_fill_manual_interactive()中,data_id直接设置为function(breaks) breaks,让每个图例项的data_id等于Question的原始值 - 调整标签部分的
data_id,确保与图表的data_id保持一致
修改后的完整代码
library(ggplot2) library(ggiraph) library(ggrepel) library(scales) library(dplyr) library(tidyr) Area <- c("location1", "location2", "location3", "location4") very_good <- c(14, 7, 17, 16) good <- c(33, 31, 35, 31) quite_bad <- c(33, 36, 30, 1) very_bad <- c(17, 2, 14, 10) # 自定义图例标签 Labels <- c("Very good", "Good", "Quite bad", "Very bad, wont return") df1 <- data.frame( Area, very_good, good, quite_bad, very_bad ) df1_subset <- df1 %>% mutate(across(2:5, ~./100)) %>% pivot_longer( cols = 2:5, names_to = "Question", values_to = "Result" ) set.seed(1) stacked_chart <- ggplot( data = df1_subset, aes( x = Result, y = Area, group = Question, fill = Question, data_id = Question # 改用Question作为data_id,与图例breaks匹配 ) ) + geom_col_interactive( position = position_fill(reverse = TRUE) ) + geom_text_repel_interactive( aes( color = ifelse(Result > 0.06, "#FFFFFF", "transparent"), label = percent(Result), data_id = Question # 文本层也设置相同的data_id ), fontface = "bold", position = position_fill(reverse = TRUE), box.padding = 0.05, segment.color = "transparent", size = 5, direction = "x", hjust = 1.5 ) + scale_y_discrete(limits = rev(Area)) + scale_x_continuous( labels = scales::percent, expand = c(0, 0), limits = c(0, 1) ) + scale_color_identity() + scale_fill_manual_interactive( data_id = function(breaks) breaks, # 图例项的data_id与Question取值一致 labels = function(breaks) { # 给每个标签设置对应Question的data_id Map(function(label, q) { label_interactive(label, data_id = q) }, Labels, breaks) }, values = c("#000000", "#333333", "#666666", "#999999") ) + theme_minimal() + theme( legend.position = "top", legend.justification = "left", legend.title = element_blank() ) stacked_chart_ggiraph <- girafe( ggobj = stacked_chart, width_svg = 9, height_svg = 6, options = list( opts_sizing(rescale = TRUE), opts_toolbar(saveaspng = FALSE), opts_hover_inv(css = girafe_css(css = "opacity:0.3;")), opts_hover(css = girafe_css( css = "cursor:pointer;fill:red;", text = "cursor:pointer;fill:#222222;" )), opts_hover_key(css = girafe_css(css = "cursor:pointer;fill:red;")) ) ) stacked_chart_ggiraph
说明:
- 图表元素(条形、文本)的
data_id统一使用Question,确保与图例项的data_id一一对应 scale_fill_manual_interactive()中通过function(breaks) breaks让图例项的data_id等于Question的原始值- 标签部分用
Map将自定义标签与对应的Question绑定,保证标签的data_id也匹配
内容的提问来源于stack exchange,提问作者Techie
相关产品推荐
相关产品推荐

