如何在R语言径向图中实现柱状顶部文本的精准对齐?
问题描述
我有如下数据:
data_melted <- structure(list(variable = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), levels = c("SJLIFE", "CCSS"), class = "factor"), SN_types = structure(c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 1L, 2L, 3L, 4L, 5L, 6L, 7L), levels = c("Any SN", "SMN", "NMSC", "Breast cancer", "Thyroid cancer", "Meningioma", "Sarcoma" ), class = "factor"), AF_by = c("Combined", "Combined", "Combined", "Combined", "Combined", "Combined", "Combined", "Combined", "Combined", "Combined", "Combined", "Combined", "Combined", "Combined"), value = c(0.536, 0.467, 0.688, 0.704, 0.866, 0.423, 0.316, 0.435, 0.323, 0.577, 0.743, 0.664, 0.444, 0.362 ), new_value = c(54, 47, 69, 70, 87, 42, 32, 44, 32, 58, 74, 66, 44, 36)), row.names = c(6L, 12L, 18L, 24L, 30L, 36L, 42L, 48L, 54L, 60L, 66L, 72L, 78L, 84L), class = "data.frame")
我用以下代码绘制径向图,但柱子上方的文本始终没法正确对齐。我想要文本位于每个柱子顶部,与柱子呈90度夹角,同时保持径向图的角度位置,请问该怎么调整?
原有代码:
angle_increment.AF <- 360 / 14 angle_increment.SN_type <- 360 / 7 ggplot(data_melted, aes(x = SN_types, y = new_value, fill = variable, label = new_value)) + geom_bar(stat = "identity", position = position_dodge(width = 0.9)) + geom_vline(xintercept = seq(1.5, 19.5, by = 3), color = "black", linetype = "dashed") + # If you want to include a vertical line geom_hline(yintercept = 100) + geom_text(aes(angle = 0 + (angle_increment.AF * (as.numeric(as.factor(SN_types)) - 1))), # Adjust angle of text labels position = position_dodge(width = 1), vjust = 0.9, size = 5, color = "black") + # Adjust label position and size scale_fill_manual(values = c(darker_sjlife, darker_ccss), labels = c("SJLIFE", "CCSS")) + # Specify colors for SJLIFE and CCSS bars scale_y_continuous(breaks = seq(0, 100, by = 10)) + # Custom grid lines from 0 to 1 by 0.25 coord_polar() + theme_minimal() + theme(panel.grid.major.y = element_line(color = "gray", linetype = "dotted"), # Adjust major grid lines panel.grid.minor = element_blank(), # Remove minor grid lines axis.line = element_blank(), # Remove axis lines axis.text.x = element_text(hjust = 0.5, angle = angle_increment, color = "black"), # Center SN type labels within grid axis.text = element_text(size = 12, color = "black"), # Adjust axis text size axis.title = element_text(size = 14, color = "black"), # Adjust axis title size legend.title = element_text(size = 14, color = "black"), # Adjust legend title size legend.text = element_text(size = 12, color = "black")) + # Adjust legend text size labs(title = "", x = NULL, y = "(%)", fill = "Cohort")
解决方案
想要实现文本垂直于柱子(90度夹角)且准确定位在柱子顶部,需要从文本角度计算和位置调整两方面修改:
关键调整项
- 为每个柱子单独计算旋转角度:每个
SN_types分组占360/7度,两个柱子分别向左右偏移,保证角度对应柱子的径向方向 - 调整文本的
vjust和hjust参数,让文本贴在柱子顶部,同时避免下半圈文本倒置显示异常 - 修正X轴标签的角度,使其对齐分组中心
- 扩展Y轴上限,防止顶部文本被图表边界截断
完整修改后代码
# 先定义颜色(避免原代码中未定义变量报错) darker_sjlife <- "#2c3e50" darker_ccss <- "#e74c3c" # 为每个柱子计算专属角度:分组基础角度 + 柱子偏移角度 data_melted$angle <- (as.numeric(data_melted$SN_types) - 1) * (360/7) + ifelse(data_melted$variable == "SJLIFE", -180/(7*2), 180/(7*2)) ggplot(data_melted, aes(x = SN_types, y = new_value, fill = variable, label = new_value)) + geom_bar(stat = "identity", position = position_dodge(width = 0.9)) + geom_vline(xintercept = seq(1.5, 7.5, by = 1), color = "black", linetype = "dashed") + geom_hline(yintercept = 100) + geom_text(aes(angle = angle), position = position_dodge(width = 0.9), vjust = -0.2, hjust = ifelse(angle > 90 & angle < 270, 1, 0), size = 5, color = "black") + scale_fill_manual(values = c(darker_sjlife, darker_ccss), labels = c("SJLIFE", "CCSS")) + scale_y_continuous(breaks = seq(0, 100, by = 10), limits = c(0, 110)) + # 扩展Y轴避免文本被截断 coord_polar() + theme_minimal() + theme(panel.grid.major.y = element_line(color = "gray", linetype = "dotted"), panel.grid.minor = element_blank(), axis.line = element_blank(), axis.text.x = element_text(hjust = 0.5, angle = seq(0, 360 - 360/7, length.out = 7)), # X轴标签对应分组中心角度 axis.text = element_text(size = 12, color = "black"), axis.title = element_text(size = 14, color = "black"), legend.title = element_text(size = 14, color = "black"), legend.text = element_text(size = 12, color = "black")) + labs(title = "", x = NULL, y = "(%)", fill = "Cohort")
代码说明
- 角度计算:每个分组的基础角度是
(as.numeric(SN_types)-1)*360/7,两个柱子分别偏移±180/(7*2)度,确保文本旋转后垂直于柱子的径向方向 - 文本位置:
vjust=-0.2把文本放在柱子顶部上方;hjust根据角度切换,下半圈(90-270度)文本右对齐,避免倒置后显示错乱 - Y轴扩展:
limits=c(0,110)给顶部文本留出显示空间,防止被截断 - X轴标签:用
seq(0, 360 - 360/7, length.out=7)生成每个分组的中心角度,让标签精准对齐分组位置
内容的提问来源于stack exchange,提问作者Achal Neupane
相关产品推荐
相关产品推荐

