如何为ggplot连接散点图的轴线添加颜色渐变
为ggplot2连接散点图添加边缘渐变线条
需求描述
- 为已生成的连接散点图,在图表底部(X轴边缘)和左侧(Y轴边缘)添加颜色渐变效果
- 渐变的可见范围需匹配图表的静态数值范围
- 尝试过用
scale_colour_gradientn()为底部线条添加渐变,但无效果;同时无法获取图表渲染后的X/Y轴实际范围(非数据最值,因标签会超出该范围)
原始示例代码
parent <- c('A','A','A','B','B','B','C','C','C') pd_identifier <- c('2021_10','2022_03','2022_08','2021_10','2022_03','2022_08','2021_10','2022_03','2022_08') PtChg <- c(-15.3,-19.4,-16.0,-9.83,-11.9,-13.4,0.876,2.10 ,2.24) Impact <- c(-0.684 ,-0.860 ,-0.558 ,-1.55 ,-2.00 ,-2.68 ,-0.165 ,-0.0730,-0.0816) label <- c(NA,'A',NA,NA,NA,'B',NA,NA,'C') nudge_x <- c(NA,-0.984,NA,NA,NA,-0.400,NA,NA,0.944) nudge_y <- c(NA,0.0352,NA,NA,NA,-0.183,NA,NA,0.0659) df <- as.data.frame(cbind(parent,pd_identifier,label,PtChg,Impact,nudge_x,nudge_y)) df[, 4:ncol(df)] <- lapply(4:ncol(df), function(x) as.numeric(df[[x]])) ggplot(df, aes(PtChg, Impact)) + theme_bw() + theme(plot.title = element_text(hjust = 0.5), panel.grid = element_line(linetype = "dashed",colour = "#D3D3D3")) + scale_colour_gradientn( colors=c("#C00000","#C00000","#FFFF00","#00B050","#00B050"), values=c(0,0.425,0.5,0.575,1)) + theme(axis.line.x.bottom = element_line(color = (PtChg + 100)/200,size = 4)) + theme(axis.line.y.left = element_line(color = "#D3D3D3",size = 4)) + geom_vline(aes(xintercept = 0),size = 1,colour = "#D3D3D3") + geom_hline(aes(yintercept = 0),size = 1,colour = "#D3D3D3") + geom_path(aes(group=parent), colour="#E20074", arrow = arrow(length=unit(0.3,"cm"), ends="last", type = "closed")) + geom_text_repel(data = df, aes(label = label), min.segment.length = 0.1, nudge_x = df$nudge_x, nudge_y = df$nudge_y, direction = "both", force = 100, force_pull = 1, max.time = 500, max.iter = 1000000, # verbose = TRUE, na.rm = TRUE )
解决步骤与最终代码
- 计算图表轴范围:根据数据最值,计算出适配的X/Y轴显示范围,确保预留足够空间且匹配静态值
- 替换轴线条为渐变线条:使用
ggforce::geom_link2创建渐变线条,替代原有的轴线条 - 独立渐变尺度:用
new_scale_color()实现X/Y轴渐变的独立配色 - 固定轴范围:通过
coord_cartesian锁定轴范围,确保渐变线条与图表区域匹配
最终代码:
x_min = if((floor(min(df$PtChg)/5)*5 - min(df$PtChg)) >= 2.5) {floor(min(df$PtChg)/5)*5} else {floor(min(df$PtChg)/5)*5 - 2.5} x_max = if((ceiling(max(df$PtChg)/5)*5 - max(df$PtChg)) >= 2.5) {ceiling(max(df$PtChg)/5)*5} else {ceiling(max(df$PtChg)/5)*5 + 2.5} y_min = if((floor(min(df$Impact)/.5)*.5 - min(df$Impact)) >= 0.25) {floor(min(df$Impact)/.5)*.5} else {floor(min(df$Impact)/.5)*.5 - 0.25} y_max = if((ceiling(max(df$Impact)/.5)*.5 - max(df$Impact)) >= 2.5) {ceiling(max(df$Impact)/.5)*.5} else {ceiling(max(df$Impact)/.5)*.5 + 0.25} ggplot(df, aes(PtChg, Impact)) + theme_bw() + theme(plot.title = element_text(hjust = 0.5), panel.grid = element_line(linetype = "dashed",colour = "#D3D3D3")) + geom_vline(aes(xintercept = 0),size = 1,colour = "#D3D3D3") + geom_hline(aes(yintercept = 0),size = 1,colour = "#D3D3D3") + geom_path(aes(group=parent), colour="#E20074", arrow = arrow(length=unit(0.3,"cm"), ends="last", type = "closed")) + geom_text_repel(data = df, aes(label = label), min.segment.length = 0.1, nudge_x = df$nudge_x, nudge_y = df$nudge_y, direction = "both", force = 100, force_pull = 1, max.time = 500, max.iter = 1000000, na.rm = TRUE ) + ggforce::geom_link2(data = data.frame(PtChg = seq(-100,100), Impact = y_min), aes(color = (PtChg+100)/200), size = 8) + theme(axis.line.x = element_blank()) + scale_colour_gradientn( colors = c("#C00000","#C00000","#FFFF00","#00B050","#00B050"), values = c(0,0.425,0.5,0.575,1), guide = "none") + new_scale_color() + ggforce::geom_link2(data = data.frame(PtChg = x_min,Impact = seq(-10,10)), aes(color = (Impact+10)/20), size = 8) + theme(axis.line.y = element_blank()) + scale_colour_gradientn( colors = c("#C00000","#C00000","#FFFF00","#00B050","#00B050"), values=c(0,0.45,0,0.55,1), guide = "none") + coord_cartesian(xlim = c(x_min,x_max),ylim = c(y_min,y_max), expand = FALSE)
最终效果
图表底部X轴边缘呈现从红色(#C00000)到黄色(#FFFF00)再到绿色(#00B050)的渐变效果,左侧Y轴边缘也匹配对应渐变;连接散点的路径、中心参考线以及标签均正常显示,渐变范围与图表静态数值范围完全匹配。
内容的提问来源于stack exchange,提问作者JYurkovich
相关产品推荐
相关产品推荐

