R语言ggplot2:geom_rect中换行文本的对齐与居中问题
问题描述
数据准备代码
Channel <- c("Episode", "Episode", "Episode", "Episode", "Episode", "Episode", "Episode", "Episode") start.time <- c(0.000, 25.458, 48.712, 152.419, 179.055, 196.274, 212.693, 232.861) stop.time <- c(25.458, 48.712, 152.419, 179.055, 196.274, 212.693, 232.861, 266.370) Episode <- c("Prologue", "An episode title", "A longer episode title", "An really, incredibly long episode title", "I wish I knew how to make hjust work with wrapped text", "A sample title", "No one likes making reproducible examples", "Epilogue") ep_df <- data.frame(Channel, start.time, stop.time, Episode) #wrap text for episode titles ep_df$Episode <- stringr::str_wrap(ep_df$Episode, 15)
绘图代码
library(ggplot2) ggplot(ep_df, aes(fill = Episode, color = Episode)) + geom_rect(color = "black", aes(xmin = start.time, xmax = stop.time, ymin = -0.5, ymax = 0.5), show.legend = FALSE) + scale_x_continuous(breaks = scales::pretty_breaks(n = 15)) + facet_grid(Channel ~ .) + theme(axis.text.y=element_blank(), axis.ticks.y=element_blank()) + coord_fixed(40)+ scale_fill_manual(values=c("#F8F8F8", "#F5F5F5", "#F0F0F0", "#E8E8E8", "#E0E0E0", "#DCDCDC", "#D8D8D8", "#D3D3D3", "#D0D0D0", "#C8C8C8")) + theme(legend.position="bottom") + geom_text(hjust = -0.5, vjust = 0.5, size = 2, aes(x = pmin(start.time, (start.time+stop.time)/2), y = 0, label = Episode), inherit.aes = FALSE) + theme(plot.margin = margin(t = 0)) + labs(x = "Time (sec)") + ylab(NULL)
遇到的问题
- 使用
hjust对齐矩形内的文本时,仅第一行生效,后续行错位,希望换行文本的每行都能对齐同一左边缘(不紧贴矩形左边界); - 无法实现文本在矩形块内居中,
hjust似乎不起作用,能否实现文本随矩形大小自动居中?(第二个问题无法解决也可接受)
解决方案
解决换行文本左对齐问题
要让换行后的每行文本保持同一左边缘对齐,只需调整geom_text的对齐参数与锚点位置:
- 将
hjust设为0(左对齐模式),所有换行行都会以指定的x坐标为左基准对齐; - 把x坐标设为
start.time + 1(1为偏移量,可根据需求调整),避免文本紧贴矩形左边界; - 保持
vjust=0.5确保文本在垂直方向居中,添加lineheight参数优化行间距。
修改后的完整绘图代码:
library(ggplot2) library(stringr) ggplot(ep_df, aes(fill = Episode, color = Episode)) + geom_rect(color = "black", aes(xmin = start.time, xmax = stop.time, ymin = -0.5, ymax = 0.5), show.legend = FALSE) + scale_x_continuous(breaks = scales::pretty_breaks(n = 15)) + facet_grid(Channel ~ .) + theme(axis.text.y=element_blank(), axis.ticks.y=element_blank()) + coord_fixed(40)+ scale_fill_manual(values=c("#F8F8F8", "#F5F5F5", "#F0F0F0", "#E8E8E8", "#E0E0E0", "#DCDCDC", "#D8D8D8", "#D3D3D3", "#D0D0D0", "#C8C8C8")) + theme(legend.position="bottom") + geom_text(hjust = 0, vjust = 0.5, size = 2, lineheight = 0.8, aes(x = start.time + 1, y = 0, label = Episode), inherit.aes = FALSE) + theme(plot.margin = margin(t = 0)) + labs(x = "Time (sec)") + ylab(NULL)
可选:实现文本在矩形内自动居中
如果需要让文本随矩形大小自动居中,需要结合矩形宽度动态调整文本换行宽度,并设置居中对齐:
- 根据每个矩形的宽度(
stop.time - start.time)估算合适的换行宽度,让文本适配矩形空间; - 将
geom_text的hjust设为0.5,x坐标设为矩形中点(start.time + stop.time)/2。
示例代码:
library(ggplot2) library(stringr) # 按矩形宽度动态调整换行宽度(比例可按需微调) ep_df$Episode <- mapply(function(txt, width) { str_wrap(txt, width = round(width / 1.5)) }, ep_df$Episode, ep_df$stop.time - ep_df$start.time) ggplot(ep_df, aes(fill = Episode, color = Episode)) + geom_rect(color = "black", aes(xmin = start.time, xmax = stop.time, ymin = -0.5, ymax = 0.5), show.legend = FALSE) + scale_x_continuous(breaks = scales::pretty_breaks(n = 15)) + facet_grid(Channel ~ .) + theme(axis.text.y=element_blank(), axis.ticks.y=element_blank()) + coord_fixed(40)+ scale_fill_manual(values=c("#F8F8F8", "#F5F5F5", "#F0F0F0", "#E8E8E8", "#E0E0E0", "#DCDCDC", "#D8D8D8", "#D3D3D3", "#D0D0D0", "#C8C8C8")) + theme(legend.position="bottom") + geom_text(hjust = 0.5, vjust = 0.5, size = 2, lineheight = 0.8, aes(x = (start.time + stop.time)/2, y = 0, label = Episode), inherit.aes = FALSE) + theme(plot.margin = margin(t = 0)) + labs(x = "Time (sec)") + ylab(NULL)
内容的提问来源于stack exchange,提问作者Wangana
相关产品推荐
相关产品推荐

