You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 15:35:40