如何在ggplot2中让柱状图标签字号自动适配柱子大小?
问题:ggplot2循环绘图中让柱状图标签字号自动适配柱子大小
我在循环中用ggplot2绘制柱状图,每次循环柱子高度会变化,代码如下:
ggplot(draft, aes(x=draft[,2], y=draft[,i])) + geom_bar(stat="identity",fill="navyblue") + geom_text(label=draft[,i],size=4, vjust=1.2, colour = "white",fontface=2) + labs(title = paste("Session trends for",colnames(draft)[i],"-",player))+ theme(axis.text.x = element_text(angle = 0,color="black",size=8), axis.title.x = element_blank(), axis.title.y = element_blank(), plot.title = element_text(color="black", size=10, face="bold",hjust = 0.5), legend.position = "none",panel.grid.major = element_blank(), panel.grid.minor = element_blank(),panel.background = element_blank(), axis.line = element_line(colour = "black"))
现在geom_text里固定了size=4,这个字号只适配部分图表,其他图表里要么太大要么太小。想知道有没有方法让标签字号自动适配柱子的大小?
可复现示例
数据框
draft <- structure(list(Player = c("Shaquil Delos", "Shaquil Delos", "Shaquil Delos", "Shaquil Delos", "Shaquil Delos", "Shaquil Delos", "Shaquil Delos", "Shaquil Delos", "Shaquil Delos", "Shaquil Delos", "Shaquil Delos", "Shaquil Delos", "Shaquil Delos", "Shaquil Delos", "Shaquil Delos", "Shaquil Delos"), Date = structure(c(19371, 19370, 19369, 19368, 19367, 19364, 19363, 19362, 19361, 19360, 19359, 19356, 19355, 19354, 19353, 19349), class = "Date"), week = c(29, 29, 29, 29, 29, 28, 28, 28, 28, 28, 28, 27, 27, 27, 27, 26), TD = c(6638, 2660, 4761, 4956, 3984, 4001, 3688, 4476, 4616, 4666, 4120, 3782, 3701, 4398, 4275, 3222), Time = c(96, 67, 70, 75, 38, 33, 55, 68, 59, 57, 56, 35, 45, 56, 46, 21), Vmax = c(9.4, 4.7, 8.3, 8.8, 6.9, 9.5, 6.5, 6, 9.2, 7.1, 7.3, 9, 6.5, 6.8, 6.2, 4.6), Amax = c(4.5, 3.1, 4.1, 4.9, 3.8, 3.8, 4.4, 3.9, 4.5, 4.4, 4, 3.4, 4.3, 3.5, 3.2, 1.5), Dmax = c(-5.9, -2.8, -4.2, -6.2, -3.9, -2.7, -4.9, -3.5, -2.7, -4.6, -3.5, -2.7, -4.5, -3.7, -3.8, -1.4), Aerobic = c(462, 44, 589, 280, 175, 546, 333, 831, 303, 959, 225, 125, 194, 188, 534, 665), HSD = c(177, 0, 475, 86, 59, 463, 56, 14, 384, 92, 119, 393, 54, 262, 24, 0), SD = c(100, 0, 78, 39, 0, 149, 0, 0, 125, 3, 6, 141, 0, 0, 0, 0), Nsprints = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), DEC3 = c(7, 0, 2, 5, 0, 0, 8, 0, 0, 3, 0, 0, 3, 0, 0, 0), ACC3 = c(4, 0, 1, 4, 0, 0, 9, 0, 3, 4, 0, 0, 9, 0, 0, 0), RHIE = c(15, 3, 19, 10, 5, 5, 17, 6, 6, 10, 10, 3, 10, 5, 5, 2), MIP1 = c(161, 112, 169, 147, 184, 285, 162, 266, 170, 248, 197, 222, 167, 177, 232, 254), MIP3 = c(359, 309, 375, 345, 535, 738, 431, 688, 479, 709, 531, 549, 476, 461, 662, 724), MIP5 = c(565, 473, 560, 537, 868, 1049, 589, 851, 673, 1152, 845, 875, 682, 619, 983, 1166), ACC = c(78, 14, 64, 46, 27, 20, 51, 32, 29, 56, 40, 12, 45, 26, 21, 0), ACC2 = c(18, 1, 14, 15, 3, 9, 24, 9, 16, 12, 9, 6, 25, 4, 3, 0), DEC = c(67, 11, 42, 48, 23, 14, 36, 22, 14, 49, 32, 7, 30, 20, 15, 0), DEC2 = c(21, 0, 12, 14, 5, 0, 20, 4, 0, 11, 4, 0, 16, 1, 2, 0), Explosive = c(12, 9, 15, 13, 5, 1, 45, 11, 3, 8, 16, 0, 14, 11, 6, 0), TRIMP = c(107, 0, 78, 51, 105, 60, 85, 93, 55, 93, 102, 44, 89, 110, 109, 47), TRIMP4 = c(0, 0, 3, 12, 20, 8, 0, 0, 0, 13, 1, 2, 2, 15, 17, 15), TRIMP5 = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), TD.min = c(69.3, 39.9, 68.1, 66, 103.6, 121.4, 67.2, 65.7, 78.7, 82.1, 77.5, 109.3, 82.5, 78.8, 92.8, 151 ), HRavg = c(66, 0, 65, 65, 79, 69, 67, 65, 60, 67, 74, 70, 71, 71, 75, 73), Vmax.perc = c(100, 50, 88, 93, 73, 101, 69, 64, 98, 75, 78, 95, 70, 72, 66, 49), Amax.perc = c(88, 62, 80, 96, 74, 75, 86, 77, 89, 87, 78, 67, 85, 68, 63, 30 ), Dmax.perc = c(104, 50, 74, 109, 69, 48, 85, 61, 47, 81, 61, 47, 79, 65, 66, 25)), row.names = c("21", "211", "22", "19", "191", "2", "20", "212", "201", "213", "221", "1", "11", "202", "203", "18"), class = "data.frame")
循环绘图代码
ggplot(draft, aes(x=draft[,2], y=draft[,i])) + geom_bar(stat="identity",fill="navyblue") + geom_text(label=draft[,i],size=4, vjust=1.2, colour = "white",fontface=2) + labs(title = paste("Session trends for",colnames(draft)[i],"-",player))+ theme(axis.text.x = element_text(angle = 0,color="black",size=8), axis.title.x = element_blank(), axis.title.y = element_blank(), plot.title = element_text(color="black", size=10, face="bold",hjust = 0.5), legend.position = "none",panel.grid.major = element_blank(), panel.grid.minor = element_blank(),panel.background = element_blank(), axis.line = element_line(colour = "black"))
解决方案
有两种实用方法可以实现标签字号自动适配柱子大小:
方法1:基于柱子高度动态调整字号
直接将geom_text的size参数与柱子的y值关联,通过缩放系数控制字号范围,避免极端值导致字号失控:
# 循环中修改geom_text部分 geom_text(aes(label = draft[,i], size = draft[,i]), vjust = 1.2, colour = "white", fontface = 2) + # 限定字号范围,可根据需求调整 scale_size(range = c(2, 6))
方法2:使用ggfittext包自动适配
ggfittext包专门用于让文本适配容器,能自动根据柱子的高度和宽度调整字号,确保标签完全显示在柱子内部:
- 先安装包:
install.packages("ggfittext")
- 替换
geom_text为geom_fit_text:
library(ggfittext) ggplot(draft, aes(x = draft[,2], y = draft[,i])) + geom_bar(stat = "identity", fill = "navyblue") + geom_fit_text(aes(label = draft[,i]), colour = "white", fontface = 2, place = "bottom", # 可选top/middle/bottom设置标签位置 reflow = FALSE) + # 不需要换行则设为FALSE labs(title = paste("Session trends for", colnames(draft)[i], "-", player)) + theme(...) # 保留原主题设置
内容的提问来源于stack exchange,提问作者Jesús Olivares-Jabalera
相关产品推荐
相关产品推荐

