ggplot2文本自定义问题求助:图例与轴标题重叠等问题
解决ggplot2图表的三个常见问题
问题1:图例标题与x轴标题意外相邻
原因
coord_flip() 交换坐标轴后,设置在顶部的图例与交换后的x轴标题(原y轴标题)间距不足,再加上legend.justification = c(0, 0)让图例靠左下对齐,进一步挤压了元素间的空间,导致两者相邻。
解决方案
- 给图例添加底部外边距,拉开与轴标题的距离;
- 调整图例对齐方式为左上,避免向下挤占轴标题空间;
- 增加整体绘图的外边距,避免元素过度拥挤。
问题2:geom_texthline文本间距过宽、linewidth参数无效
原因
linewidth是控制虚线宽度的参数,并非文本行间距;文本行间距由lineheight控制,但showtext对该参数的处理与原生ggplot有差异,加上过大的size值放大了行间距问题;- 所选字体的默认行高较大,加重了间距过宽的情况;
coord_flip()后,hjust和vjust参数的作用逻辑变化,导致文本位置异常。
解决方案
- 调小
lineheight值,同时降低文本size,缩小行间距; - 明确设置
linewidth参数控制虚线宽度; - 调整
vjust值让文本更贴近虚线,减少不必要的空白; - 优先使用单行文本,避免换行带来的间距问题。
问题3:字体相关的潜在问题
原因
- 使用
showtext加载字体时,部分字体的粗体权重未正确绑定,导致face="bold"渲染异常; - 缺失对应粗体字重的字体,会间接影响文本布局和间距。
解决方案
- 加载字体时明确指定粗体权重,确保字体支持粗体渲染;
- 优先选择支持多字重的字体;
- 可临时关闭
showtext测试是否为字体加载导致的问题。
修改后的完整代码
library(tidyverse) library(ggbeeswarm) library(ggtext) library(showtext) library(showtextdb) library(glue) # 加载字体并明确粗体权重 font_add_google("Lora", bold.wt = 700, family = "plottitle") font_add_google("Roboto Slab", family = "title", bold.wt = 700) font_add_google("Ubuntu", family = "caption", bold.wt = 700) font_add('fa-reg', 'fonts/Font Awesome 6 Free-Regular-400.otf') font_add('fa-brands', 'fonts/Font Awesome 6 Brands-Regular-400.otf') font_add('fa-solid', 'fonts/Font Awesome 6 Free-Solid-900.otf') showtext_auto() safi_data <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2023/2023-06-13/safi_data.csv') summary_data <- safi_data %>% group_by(village) %>% mutate(mean = mean(years_liv, na.rm = TRUE)) %>% # 处理缺失值 select(village, mean) %>% distinct() plot <- ggplot(safi_data, aes(y = years_liv, x = village)) + geom_point(aes(fill = respondent_wall_type), color="white", shape=21, position = position_beeswarm(cex = 4.5), size = 6) + geom_point(data = summary_data, aes(x = village, y = mean), size=4.5, shape=23, fill = "#F79327", color="white") + coord_flip() + theme_minimal() + labs(title = "哪个村庄的受访者居住时间更长?", subtitle = "该图展示了SAFI项目受访者在Ruaca、God和Chirodzo三个村庄的居住年限分布。", y = "居住年限", x = "") + scale_y_continuous(breaks = c(0, 25, 50, 75, 100), limits = c(0, 100), labels = as.character(c(0, 25, 50, 75, 100))) + scale_x_discrete(labels=c("**Ruaca**<br>(n=49)", "**God**<br>(n=43)", "**Chirodzo**<br>(n=39)")) + scale_fill_manual(values = c("#884A39", "#EA906C", "#B31312", "#2B2A4C"), labels = c("烧砖", "水泥", "泥灰", "晒砖"), name = "受访者房屋墙体类型") + geom_hline(yintercept = c(0, 25, 50, 75, 100), color = "grey", linewidth = 0.5, alpha = 0.5) + geomtextpath::geom_texthline(yintercept = mean(safi_data$years_liv, na.rm = TRUE), color="grey20", linetype="dashed", linewidth = 0.8, # 明确虚线宽度 label = glue("平均: {round(mean(safi_data$years_liv, na.rm = TRUE),0)}年"), # 单行文本避免行间距问题 hjust = 0.75, vjust = 0.5, family = 'caption', size = 6, fontface = "bold") + geom_segment(aes(y = 26, yend = 31.2, x = 2.95, xend = 2.35), linewidth=0.15) + geom_segment(aes(y = 21.8, yend = 31.2, x = 2, xend = 2.25), linewidth=0.15) + geom_segment(aes(y = 25.3, yend = 33, x = 1, xend = 2.2), linewidth=0.15) + geom_text(label = "平均居住年限", x = 2.3, y = 37, family = "title", size = 12, lineheight = 0.15) + theme(panel.grid = element_blank(), panel.background = element_rect(fill = "white", color = "white"), plot.background = element_rect(fill = "white", color = "white"), plot.title = element_markdown(size = 28, hjust = 0, family = "plottitle"), plot.subtitle = element_markdown(size = 18, hjust = 0, family = "title", lineheight = 0.2), plot.margin = margin(t = 10, r = 10, b = 10, l = 10, unit = "mm"), # 调整绘图外边距 axis.text.y = element_markdown(size = 16, family = "caption", color = "grey60", face = "bold", lineheight = 0.1, hjust = 0), axis.title.x = element_markdown(size = 16, family = "caption", face = "bold"), axis.text.x = element_markdown(size = 16, family = "caption", face = "bold", lineheight = 0.1), axis.line.x = element_line(linewidth = 0.5, color="black"), panel.border = element_blank(), legend.position="top", legend.spacing.x = unit(0.2, 'cm'), legend.justification = c(0, 1), # 图例左上对齐 legend.box.margin = margin(b = 5, unit = "mm"), # 图例底部添加外边距 legend.title = element_markdown(face="bold", size = 14), legend.text = element_markdown(size = 12, hjust = 0, family = "title"), legend.key = element_blank()) ggsave("plot.png", dpi = 300, height = 6, width = 8)
内容的提问来源于stack exchange,提问作者mzkrc
相关产品推荐
相关产品推荐

