如何在ggplot2渐变图例中添加平均线?
在ggplot2渐变图例色条中添加平均线
你之前用annotate的问题在于,这个函数是在主绘图区添加元素,而非图例内部,所以会破坏原有布局。下面是两种可行的实现方案:
方案1:自定义图例向导(推荐)
通过重写guide_colorbar的绘制逻辑,直接在色条上添加平均线,代码可复用性高:
1. 计算目标均值
mean_np <- mean(parties_ger_plz$np, na.rm = TRUE)
2. 自定义带平均线的颜色条向导
guide_colorbar_with_mean <- function(mean_val, ...) { guide <- guide_colorbar(...) # 重写图例绘制函数 guide$draw <- function(self, theme, x, y, width, height, ...) { # 先绘制默认的颜色条 base_bar <- NextMethod() # 将均值归一化到色条的0-1高度范围 val_limits <- self$scale$get_limits() y_normalized <- (mean_val - val_limits[1]) / (val_limits[2] - val_limits[1]) # 创建平均线元素 mean_line <- grid::segmentsGrob( x0 = x, x1 = x + width, y0 = y + height * y_normalized, y1 = y + height * y_normalized, gp = grid::gpar(col = "blue", lwd = 1.5, lty = "dashed") ) # 合并颜色条与平均线 grid::grobTree(base_bar, mean_line) } guide }
3. 应用到你的绘图中
修改scale_fill_gradientn的guide参数,替换为自定义向导:
main_map <- ggplot() + geom_sf(data = parties_ger_plz, aes(fill = np), color = "white", linewidth = 0.045) + scale_fill_gradientn( name = "Klagequote (%)", na.value = "#9DBF9E", labels = scales::label_number(scale = 1, suffix = " %", accuracy = 1), colors = c("#9DBF9E", "#FCB97D", "#A84268"), # 使用自定义图例 guide = guide_colorbar_with_mean( mean_val = mean_np, frame.colour = "black", frame.linewidth = 0.3, ticks = TRUE, ticks.colour = "black", barwidth = 0.5, barheight = 10, title.position = "top" ) ) + geom_sf(data = geo_data_ger_adm_states, linewidth = 0.25, color = "black", fill = "transparent") + coord_sf(expand = FALSE) + theme_minimal() + theme( legend.text = element_text(size = 6), legend.title = element_text(size = 7), legend.key.size = unit(0.3, "cm") )
之后继续按照你原有的代码逻辑构建big_map、noth_west_germany和final_map即可,此时图例色条上会显示蓝色虚线的平均线。
方案2:修改已生成的图例gtable
如果你不想自定义向导,可以先绘制好图,再提取图例并手动添加线段:
1. 先绘制基础地图(用默认图例)
main_map <- ggplot() + geom_sf(data = parties_ger_plz, aes(fill = np), color = "white", linewidth = 0.045) + scale_fill_gradientn( name = "Klagequote (%)", na.value = "#9DBF9E", labels = scales::label_number(scale = 1, suffix = " %", accuracy = 1), colors = c("#9DBF9E", "#FCB97D", "#A84268"), guide = guide_colorbar( frame.colour = "black", frame.linewidth = 0.3, ticks = TRUE, ticks.colour = "black", barwidth = 0.5, barheight = 10, title.position = "top" ) ) + geom_sf(data = geo_data_ger_adm_states, linewidth = 0.25, color = "black", fill = "transparent") + coord_sf(expand = FALSE) + theme_minimal() + theme( legend.text = element_text(size = 6), legend.title = element_text(size = 7), legend.key.size = unit(0.3, "cm") )
2. 提取并修改图例
library(gtable) library(grid) # 将ggplot对象转为gtable gt <- ggplotGrob(main_map) # 定位图例所在的grob legend_pos <- which(grepl("guide-box", gt$layout$name)) legend_grob <- gt$grobs[[legend_pos]] # 找到色条元素 bar_pos <- which(sapply(legend_grob$grobs, function(x) x$name == "bar")) color_bar <- legend_grob$grobs[[bar_pos]] # 计算均值对应的色条位置 val_range <- range(parties_ger_plz$np, na.rm = TRUE) y_norm <- (mean_np - val_range[1]) / (val_range[2] - val_range[1]) line_y <- color_bar$y + color_bar$height * y_norm # 添加平均线 mean_line <- segmentsGrob( x0 = color_bar$x, x1 = color_bar$x + color_bar$width, y0 = line_y, y1 = line_y, gp = gpar(col = "blue", lwd = 1.5, lty = "dashed") ) # 合并色条与平均线 legend_grob$grobs[[bar_pos]] <- grobTree(color_bar, mean_line) gt$grobs[[legend_pos]] <- legend_grob
3. 绘制或组合修改后的图
# 直接绘制修改后的图 grid.draw(gt) # 或者继续组合到你的final_map中 final_map <- ggdraw(gt) + draw_plot(big_map, x = 0.635, y = 0.05, width = 0.4, height = 0.4) + coord_fixed() + theme_minimal() + theme( plot.background = element_blank(), plot.margin = unit(c(0, 0, 0, 0), "cm") )
内容的提问来源于stack exchange,提问作者Niklas H.
相关产品推荐
相关产品推荐

