如何在ggplot多子图中为每个子图高亮两条行业曲线?
问题描述
我用ggplot制作了一组多子图,每个子图对应单个行业的曲线。现在希望将行业两两配对,在每个子图中高亮显示两个目标行业的曲线,其余行业曲线以灰色背景呈现,以此将子图数量减少一半(例如把Agriculture与Construction放在同一子图中高亮)。但我无法在ggplot中实现这种分组高亮逻辑,以下是使用的数据集及当前绘图代码:
数据集
dput(df_annual) structure(list(Industry = c("Agriculture", "Mining", "Utilities", "Construction", "Manufacturing", "Wholesale trade", "Retail trade", "Transportation and warehousing", "Information", "FIRE", "Professional and busines sservices", "Education and healthcare", "Entertainment, Accommodation, and food services", "Otherservices", "Petroleum and coal products", "Aggregate Markup (weighted by value added)", "Agriculture", "Mining", "Utilities", "Construction", "Manufacturing", "Wholesale trade", "Retail trade", "Transportation and warehousing", "Information", "FIRE", "Professional and busines sservices", "Education and healthcare", "Entertainment, Accommodation, and food services", "Otherservices", "Petroleum and coal products", "Aggregate Markup (weighted by value added)", "Agriculture", "Mining", "Utilities", "Construction", "Manufacturing", "Wholesale trade", "Retail trade", "Transportation and warehousing", "Information", "FIRE", "Professional and busines sservices", "Education and healthcare", "Entertainment, Accommodation, and food services", "Otherservices", "Petroleum and coal products", "Aggregate Markup (weighted by value added)", "Agriculture", "Mining", "Utilities", "Construction", "Manufacturing", "Wholesale trade", "Retail trade", "Transportation and warehousing", "Information", "FIRE", "Professional and busines sservices", "Education and healthcare", "Entertainment, Accommodation, and food services", "Otherservices", "Petroleum and coal products", "Aggregate Markup (weighted by value added)", "Agriculture", "Mining", "Utilities", "Construction", "Manufacturing", "Wholesale trade", "Retail trade", "Transportation and warehousing", "Information", "FIRE", "Professional and busines sservices", "Education and healthcare", "Entertainment, Accommodation, and food services", "Otherservices", "Petroleum and coal products", "Aggregate Markup (weighted by value added)" ), value = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4.16899022725953, -3.16048739095132, 2.26615125120156, 0.66130884603661, -0.0280915175999513, 2.83955145388273, 1.0360196924704, -1.02176623498684, 3.82132039562726, -0.336373727020167, -0.423101133276901, 0.162838968005144, 0.202636027998032, -0.130655654963285, 0.484757543749409, 0.345797906863748, -6.19581465100466, -7.76170158802538, 9.8323710595107, -0.384612600833956, -0.142319217128792, 5.36608584813379, 2.06086341070106, -3.96206889404121, 2.69441070658506, -0.270586167227105, -1.72408562953159, -1.91182207972596, -3.09849125788884, -2.40236202213844, -10.4483984657011, 0.644164935123387, 5.05288723613821, 7.26564778080908, 6.16490973408088, -1.27550822039797, -0.420179493561609, 1.11895934710035, 1.42772550145728, -0.587421638026028, 0.60164150449748, -0.490330403219696, -1.95109398370057, -0.916492053203161, -1.40945477592939, -1.74435002828741, -1.61195956200604, 0.311268220225386, 7.79558265461643, 8.59069593264387, 5.82758955116995, -1.90794919946671, 0.0574902177623432, 0.646474887329734, 1.01097219864939, 0.888814212065392, 0.529917989609702, 1.77421737752929, -2.58667857085753, -1.39478160549774, -0.392924607564787, -1.37729956885558, -0.724198001834994, 0.890255993161343 ), date = structure(c(17532, 17532, 17532, 17532, 17532, 17532, 17532, 17532, 17532, 17532, 17532, 17532, 17532, 17532, 17532, 17532, 17897, 17897, 17897, 17897, 17897, 17897, 17897, 17897, 17897, 17897, 17897, 17897, 17897, 17897, 17897, 17897, 18262, 18262, 18262, 18262, 18262, 18262, 18262, 18262, 18262, 18262, 18262, 18262, 18262, 18262, 18262, 18262, 18628, 18628, 18628, 18628, 18628, 18628, 18628, 18628, 18628, 18628, 18628, 18628, 18628, 18628, 18628, 18628, 18993, 18993, 18993, 18993, 18993, 18993, 18993, 18993, 18993, 18993, 18993, 18993, 18993, 18993, 18993, 18993), class = "Date")), row.names = c(NA, -80L), class = c("tbl_df", "tbl", "data.frame"))
当前绘图代码
df_annual %>% ggplot() + geom_hline(yintercept = 0,linetype="solid", size=.25) + geom_point(data=df_annual %>% group_by(Industry) %>% slice_max(date), aes(x=date, y=value, color=Industry),shape=16) + geom_line(aes(x=date, y=value, color=Industry), size = 1) + gghighlight(use_direct_label = FALSE, unhighlighted_params = list(linewidth = 0.5, colour = alpha("grey85", 1))) + geom_text(data=df_annual %>% group_by(Industry) %>% slice_max(date), aes(x=date, y=value, color=Industry, label = round(value, digits = 1)), hjust = -.5, vjust = .5, size=4, family=font, fontface="bold") + #scale_color_met_d(name="Redon") + scale_x_date(date_labels = "%Y") + scale_y_continuous(breaks = c(-10,-5,0,5,10), labels = c("","","0","","" )) + facet_wrap(~ Industry) + # facet_wrap(~ factor(Industry, levels=c('Agriculture,forestry,fishing,andhunting','Mining','Utilities','Construction', # 'Manufacturing','Wholesaletrade', 'Retailtrade', 'Transportationandwarehousing', 'Information', # 'Finance,insurance,realestate,rental,andleasing', 'Professionalandbusinessservices', # 'Educationalservices,healthcare,andsocialassistance', 'Arts,entertainment,recreation,accommodation,andfoodservices', # 'Otherservices,exceptgovernment','Aggregate' # ))) + coord_cartesian(clip = "off") + theme( axis.title = element_blank(), axis.text = element_text(color=txt_col, size=10), strip.text.x = element_text(face="bold", size = 15), plot.title = element_text(hjust=.9,size=80, color=txt_col,lineheight=2.8, face="bold", margin=margin(20,0,30,0)), # plot.subtitle = element_markdown(hjust=.5,size=48, color=txt_col,lineheight = 1, margin=margin(10,0,30,0)), # plot.caption = element_markdown(hjust=.5, margin=margin(60,0,0,0), size=8, color=txt_col, lineheight = 1.2), plot.caption.position = "plot", plot.background = element_rect(color=bg, fill=bg), plot.margin = margin(10,10,10,10), legend.position = "none", legend.title = element_text(face="bold") )
解决方案
要实现两两分组高亮的效果,核心是先定义行业配对关系,再通过分层绘图控制背景与高亮曲线的显示,替代原来依赖gghighlight的单组高亮逻辑:
1. 定义行业配对分组
先创建配对映射表,将需要放在同一子图的行业绑定,并给每个配对分配组名(可根据业务需求自由调整配对):
library(tidyverse) # 创建配对分组表 pair_groups <- tibble( Industry = c("Agriculture", "Construction", "Mining", "Utilities", "Manufacturing", "Wholesale trade", "Retail trade", "Transportation and warehousing", "Information", "FIRE", "Professional and business services", "Education and healthcare", "Entertainment, Accommodation, and food services", "Otherservices", "Petroleum and coal products", "Aggregate Markup (weighted by value added)"), Pair = rep(c("Pair 1", "Pair 2", "Pair 3", "Pair 4", "Pair 5", "Pair 6", "Pair 7", "Pair 8"), each = 2) ) # 修正原数据中行业名称的拼写错误("busines sservices" 多了空格) df_annual <- df_annual %>% mutate(Industry = str_replace(Industry, "busines sservices", "business services")) # 将配对信息合并到原数据集 df_annual <- df_annual %>% left_join(pair_groups, by = "Industry")
2. 调整绘图代码
分图层绘制:先画所有行业的灰色背景曲线,再在每个子图上叠加当前配对的高亮曲线、点和文本,最后按配对分组分面:
# 若原代码未定义全局样式变量,先设置默认值 txt_col <- "black" bg <- "white" font <- "sans" ggplot() + # 绘制所有行业的灰色背景曲线(所有子图统一显示) geom_line(data = df_annual, aes(x = date, y = value), color = alpha("grey85", 1), linewidth = 0.5) + # 绘制当前配对组的高亮曲线 geom_line(data = df_annual, aes(x = date, y = value, color = Industry), linewidth = 1) + # 绘制高亮行业的终点圆点 geom_point(data = df_annual %>% group_by(Industry) %>% slice_max(date), aes(x = date, y = value, color = Industry), shape = 16) + # 绘制高亮行业的终点文本标签 geom_text(data = df_annual %>% group_by(Industry) %>% slice_max(date), aes(x = date, y = value, color = Industry, label = round(value, digits = 1)), hjust = -.5, vjust = .5, size = 4, family = font, fontface = "bold") + # 添加水平参考线 geom_hline(yintercept = 0, linetype = "solid", size = .25) + # 坐标轴设置 scale_x_date(date_labels = "%Y") + scale_y_continuous(breaks = c(-10,-5,0,5,10), labels = c("","","0","","")) + # 按配对分组分面 facet_wrap(~ Pair) + # 主题设置(保留原主题样式) coord_cartesian(clip = "off") + theme( axis.title = element_blank(), axis.text = element_text(color = txt_col, size = 10), strip.text.x = element_text(face = "bold", size = 15), plot.title = element_text(hjust = .9, size = 80, color = txt_col, lineheight = 2.8, face = "bold", margin = margin(20,0,30,0)), plot.caption.position = "plot", plot.background = element_rect(color = bg, fill = bg), plot.margin = margin(10,10,10,10),
相关产品推荐
相关产品推荐

