ggplot2:如何有条件地更改 geom_text 的 vjust 当低栏使文本超过栏的底部时
ggplot2: How to conditionally change geom_text's vjust when low bars make text exceed bar's bottom
绘制条形图时,我经常给条形图添加标签以表示每个条形图的 y 值。然而,我 运行 遇到了麻烦,当标准变得太低时,标签变得不可读或简直丑陋。
例子
library(ggplot2)
df_blood <- data.frame(blood_type = c("O-", "O+", "A-", "A+", "B-", "B+", "AB-", "AB+"),
frequency = c(0.13, 0.35, 0.08, 0.3, 0.02, 0.08, 0.01, 0.02))
ggplot(df_blood, aes(x = blood_type, y = frequency, fill = blood_type)) +
geom_bar(stat = "identity") +
geom_text(aes(label = frequency), color = "blue", vjust = 1, size = 7)
由 reprex package (v0.3.0) 于 2021-01-25 创建
查看 AB-
的栏,我们可以看到 0.01
文本超过了栏的高度(在栏的底部)。在这种情况下,我想将 geom_text()
的 vjust
更改为 0
。
具有不同 y 比例的另一个例子
这里我使用与上面相同的 size = 7
geom_text()
:
library(ggplot2)
df_something <- data.frame(something = c("a", "b", "c"),
quantity = c(10000, 7800, 500))
ggplot(df_something, aes(x = something, y = quantity)) +
geom_bar(stat = "identity", fill = "black") +
geom_text(aes(label = quantity), color = "red", vjust = 1, size = 7)
由 reprex package (v0.3.0) 于 2021-01-25 创建
在这里,我们看到 c
栏的 500
文本超出了栏的底部。因此,在这种情况下,我还想将 geom_text()
的 vjust
更改为 0
,仅适用于小节 c
。
总结
尽管有一些解决方案可以根据 y 值使用简单的 ifelse
(请参阅 )有条件地更改 vjust
,但我正在尝试弄清楚如何设置条件vjust
这样无论 y 尺度上的值如何,它都可以工作。相反,规则应该是,如果栏的高度低于 geom_text()
的大小,文本位置将移动到顶部。谢谢!
编辑
根据下面与@Paul 的讨论,我想知道根据 geom_text()
位置是否覆盖 y = 0
来确定 vjust
是否更容易,如果覆盖,则更改 vjust
到 0
.
编辑 2
(credit to 寻找)似乎足够接近我的要求。它动态更改 geom_text()
的 size
以适合条形宽度,并且即使在调整绘图大小时也能正常工作。所以我认为这为我所追求的提供了基础,而不是调整 size
我需要调整 vjust
,而不是根据条宽度调节它我需要根据条高度调节它。不幸的是,它对于我对 ggproto
等的理解来说太复杂了,所以我不知道如何使它适应我的情况。
您可以不将标签放在列中,而是将它们放在最上面就可以解决您的问题吗?它适用于所有列,您无需担心选择个别列。将所有标签都放在上面可能更干净,而不是在内部和上面放置一些标签。
library(ggplot2)
df_something <- data.frame(something = c("a", "b", "c"),
quantity = c(10000, 7800, 500))
ggplot(data = df_something, aes(x = something, y = quantity)) +
geom_col(position = "dodge", fill = "black") +
geom_text(
aes(label = quantity, y = quantity + 50),
position = position_dodge(0.9),
vjust = 0,
color = "red",
size = 7
)
vjust 也可以采用等于 x 轴大小的输入向量。
vjust(我放 0 的地方)的顺序基于数据集的顺序,而不是 ggplot 中显示的顺序。您可以考虑 blood_type 以非常具体地确定每个条形图的位置,并更好地控制 v。
library(ggplot2)
df_blood <- data.frame(blood_type = c("O-", "O+", "A-", "A+", "B-", "B+", "AB-", "AB+"),
frequency = c(0.13, 0.35, 0.08, 0.3, 0.02, 0.08, 0.01, 0.02))
ggplot(df_blood, aes(x = blood_type, y = frequency, fill = blood_type)) +
geom_bar(stat = "identity") +
geom_text(aes(label = frequency), color = "blue", vjust = c(1,1,1,1,1,1,0,1), size = 7)
刚在 googling around 时发现:
尝试使用 vjust = "inward"
。然而,这可能会导致其他问题(如前所述 )...
ggplot(df_something, aes(x = something, y = quantity)) +
geom_bar(stat = "identity", fill = "black") +
geom_text(aes(label = quantity), color = "red", vjust = "inward", size = 7)
[旧 post]
我post这是一个“答案”,只是为了说明我的意思。将通过反馈进行改进。
如 here 所述,“文本的大小以毫米为单位”。然后无论你的情节的最终大小是什么,它总是有相同的大小。
我想我们需要知道您是否必须为情节保留最终维度。
例如:
ggsave(filename = "test_small.png", height = 5, units = "cm")
ggsave(filename = "test_big.png", height = 20, units = "cm")
作为一个开箱即用的选项来达到你想要的结果,我建议看看 ggfittext
包,它有一些选项可以将标签放在条形之外,如果他们不'适合内部或缩小标签。此外,还有一些选项可以在标签周围添加一些填充。但是,它使用非默认大小调整策略,因此您必须将默认单位乘以 ggplot2::.pt
:
library(ggplot2)
library(ggfittext)
df_something <- data.frame(something = c("a", "b", "c"),
quantity = c(10000, 7800, 500))
ggplot(df_something, aes(x = something, y = quantity)) +
geom_bar(stat = "identity", fill = "black") +
geom_bar_text(aes(label = quantity),
color = "red",
vjust = 1,
size = 7 * ggplot2::.pt,
min.size = 7 * ggplot2::.pt,
padding.x = grid::unit(0, "pt"),
padding.y = grid::unit(0, "pt"),
outside = TRUE)
#> Warning: Ignoring unknown aesthetics: label
df_blood <- data.frame(blood_type = c("O-", "O+", "A-", "A+", "B-", "B+", "AB-", "AB+"),
frequency = c(0.13, 0.35, 0.08, 0.3, 0.02, 0.08, 0.01, 0.02))
ggplot(df_blood, aes(x = blood_type, y = frequency, fill = blood_type)) +
geom_bar(stat = "identity") +
geom_bar_text(aes(label = frequency),
color = "blue",
vjust = 1,
size = 7 * ggplot2::.pt,
min.size = 7 * ggplot2::.pt,
padding.x = grid::unit(0, "pt"),
padding.y = grid::unit(0, "pt"),
outside = TRUE)
#> Warning: Ignoring unknown aesthetics: label
绘制条形图时,我经常给条形图添加标签以表示每个条形图的 y 值。然而,我 运行 遇到了麻烦,当标准变得太低时,标签变得不可读或简直丑陋。
例子
library(ggplot2)
df_blood <- data.frame(blood_type = c("O-", "O+", "A-", "A+", "B-", "B+", "AB-", "AB+"),
frequency = c(0.13, 0.35, 0.08, 0.3, 0.02, 0.08, 0.01, 0.02))
ggplot(df_blood, aes(x = blood_type, y = frequency, fill = blood_type)) +
geom_bar(stat = "identity") +
geom_text(aes(label = frequency), color = "blue", vjust = 1, size = 7)
由 reprex package (v0.3.0) 于 2021-01-25 创建
查看 AB-
的栏,我们可以看到 0.01
文本超过了栏的高度(在栏的底部)。在这种情况下,我想将 geom_text()
的 vjust
更改为 0
。
具有不同 y 比例的另一个例子
这里我使用与上面相同的 size = 7
geom_text()
:
library(ggplot2)
df_something <- data.frame(something = c("a", "b", "c"),
quantity = c(10000, 7800, 500))
ggplot(df_something, aes(x = something, y = quantity)) +
geom_bar(stat = "identity", fill = "black") +
geom_text(aes(label = quantity), color = "red", vjust = 1, size = 7)
由 reprex package (v0.3.0) 于 2021-01-25 创建
在这里,我们看到 c
栏的 500
文本超出了栏的底部。因此,在这种情况下,我还想将 geom_text()
的 vjust
更改为 0
,仅适用于小节 c
。
总结
尽管有一些解决方案可以根据 y 值使用简单的 ifelse
(请参阅 vjust
,但我正在尝试弄清楚如何设置条件vjust
这样无论 y 尺度上的值如何,它都可以工作。相反,规则应该是,如果栏的高度低于 geom_text()
的大小,文本位置将移动到顶部。谢谢!
编辑
根据下面与@Paul 的讨论,我想知道根据 geom_text()
位置是否覆盖 y = 0
来确定 vjust
是否更容易,如果覆盖,则更改 vjust
到 0
.
编辑 2
geom_text()
的 size
以适合条形宽度,并且即使在调整绘图大小时也能正常工作。所以我认为这为我所追求的提供了基础,而不是调整 size
我需要调整 vjust
,而不是根据条宽度调节它我需要根据条高度调节它。不幸的是,它对于我对 ggproto
等的理解来说太复杂了,所以我不知道如何使它适应我的情况。
您可以不将标签放在列中,而是将它们放在最上面就可以解决您的问题吗?它适用于所有列,您无需担心选择个别列。将所有标签都放在上面可能更干净,而不是在内部和上面放置一些标签。
library(ggplot2)
df_something <- data.frame(something = c("a", "b", "c"),
quantity = c(10000, 7800, 500))
ggplot(data = df_something, aes(x = something, y = quantity)) +
geom_col(position = "dodge", fill = "black") +
geom_text(
aes(label = quantity, y = quantity + 50),
position = position_dodge(0.9),
vjust = 0,
color = "red",
size = 7
)
vjust 也可以采用等于 x 轴大小的输入向量。 vjust(我放 0 的地方)的顺序基于数据集的顺序,而不是 ggplot 中显示的顺序。您可以考虑 blood_type 以非常具体地确定每个条形图的位置,并更好地控制 v。
library(ggplot2)
df_blood <- data.frame(blood_type = c("O-", "O+", "A-", "A+", "B-", "B+", "AB-", "AB+"),
frequency = c(0.13, 0.35, 0.08, 0.3, 0.02, 0.08, 0.01, 0.02))
ggplot(df_blood, aes(x = blood_type, y = frequency, fill = blood_type)) +
geom_bar(stat = "identity") +
geom_text(aes(label = frequency), color = "blue", vjust = c(1,1,1,1,1,1,0,1), size = 7)
刚在 googling around 时发现:
尝试使用 vjust = "inward"
。然而,这可能会导致其他问题(如前所述
ggplot(df_something, aes(x = something, y = quantity)) +
geom_bar(stat = "identity", fill = "black") +
geom_text(aes(label = quantity), color = "red", vjust = "inward", size = 7)
[旧 post]
我post这是一个“答案”,只是为了说明我的意思。将通过反馈进行改进。
如 here 所述,“文本的大小以毫米为单位”。然后无论你的情节的最终大小是什么,它总是有相同的大小。
我想我们需要知道您是否必须为情节保留最终维度。 例如:
ggsave(filename = "test_small.png", height = 5, units = "cm")
ggsave(filename = "test_big.png", height = 20, units = "cm")
作为一个开箱即用的选项来达到你想要的结果,我建议看看 ggfittext
包,它有一些选项可以将标签放在条形之外,如果他们不'适合内部或缩小标签。此外,还有一些选项可以在标签周围添加一些填充。但是,它使用非默认大小调整策略,因此您必须将默认单位乘以 ggplot2::.pt
:
library(ggplot2)
library(ggfittext)
df_something <- data.frame(something = c("a", "b", "c"),
quantity = c(10000, 7800, 500))
ggplot(df_something, aes(x = something, y = quantity)) +
geom_bar(stat = "identity", fill = "black") +
geom_bar_text(aes(label = quantity),
color = "red",
vjust = 1,
size = 7 * ggplot2::.pt,
min.size = 7 * ggplot2::.pt,
padding.x = grid::unit(0, "pt"),
padding.y = grid::unit(0, "pt"),
outside = TRUE)
#> Warning: Ignoring unknown aesthetics: label
df_blood <- data.frame(blood_type = c("O-", "O+", "A-", "A+", "B-", "B+", "AB-", "AB+"),
frequency = c(0.13, 0.35, 0.08, 0.3, 0.02, 0.08, 0.01, 0.02))
ggplot(df_blood, aes(x = blood_type, y = frequency, fill = blood_type)) +
geom_bar(stat = "identity") +
geom_bar_text(aes(label = frequency),
color = "blue",
vjust = 1,
size = 7 * ggplot2::.pt,
min.size = 7 * ggplot2::.pt,
padding.x = grid::unit(0, "pt"),
padding.y = grid::unit(0, "pt"),
outside = TRUE)
#> Warning: Ignoring unknown aesthetics: label