如何从给定的 ggplot 对象中提取条形标签及其大小?

这是关于 x 轴标签动态换行的 question (and answer) 的后续。


编辑 - TL;DR 摘要


(A) 总结

  1. 我有一个用 geom_bar()ggfittext::geom_bar_text() 制作的 ggplot 对象。
  2. 我想从该对象中提取条形标签。
  3. 我还想提取这些标签的字体大小。
  4. 我正在尝试对两种图执行上述操作:一个典型的条形图和一个拆分为多面图。

(B) 期望输出

  • 带有条形标签文本的字符向量
  • 带有条形标签大小的数字向量

(C) ggplot 问题对象
1 - object p

library(ggfittext)
library(tidyverse)

my_cats_df <-
  data.frame(breed = c("Domestic Cat","Persian","Siamese","Maine Coon"),weight = c(9,10,7,17),breed_description = c("the only domesticated species in the family Felidae","a long-haired,round face and short muzzle","blue almond-shaped eyes; a triangular head shape","the largest domesticated cat breed") )


p <-
  my_cats_df %>%
  ggplot(aes(x = breed,y = weight,fill = breed)) +
  geom_bar(stat = "identity") +
  geom_bar_text(aes(label = breed_description),min.size = 0,reflow = TRUE)

2 - object p_facets_by_var

my_cats_df_by_sex <- data.frame(breed = rep(c("Domestic Cat",each = 2),sex = rep(c("male","female"),2),weight = c(11,6,12,8,5,20,15),breed_description = rep(c("the only domesticated species in the family Felidae","the largest domesticated cat breed"),each = 2))

p_facets_by_var <- 
  my_cats_df_by_sex %>%
  ggplot(aes(x = breed,reflow = TRUE) +
  facet_wrap(~ sex)

问题背后的故事

如果需要上下文,请阅读,否则请跳过以下所有部分。

问题

x 轴标签重叠。示例:

library(tidyverse)

mtcars[15:20,] %>% 
  rownames_to_column("cars") %>%
  ggplot(aes(x = cars,y = mpg,fill = cars)) + 
  geom_bar(stat = "identity")

如何从给定的 ggplot 对象中提取条形标签及其大小?

reprex package (v0.3.0) 于 2021 年 1 月 31 日创建

背景

我需要在自动化管道中为不同类型的数据生成绘图,因此不能依赖 manual solutions 进行文本换行,例如 stringr::str_wrap()。这是因为它们需要可能对一个数据集有用但不一定对其他数据集有用的参数。此外,此类解决方案对图形设备的变化并不稳健,例如缩小绘图大小可能会扰乱文本格式。

同样,如果我们使用 facet_wrap()/facet_grid() 绘图,这意味着文本空间更少,并且默认样式参数(例如文本大小)使得文本很可能在某处被打乱.

我的想法

我想实现动态文本换行,对绘图尺寸的变化或分割成面时具有鲁棒性。一种方法是使用包 ggfittext,其目的是在框内拟合文本。它的算法计算出文本有多少空间,并相应地包装文本和/或减小文本大小以适应框。

不幸的是,ggfittext 目前仅适用于 geoms,而 does not have an element_text() subclass 可以使其直接与 scale x 标签一起使用。

我想提出以下工作流程,最好将其包装在自定义函数中:

  1. 使用 ggfittext 绘制条形图并在条形中拟合文本。
  2. 将绘图保存到对象 p 中。
  3. p 中提取适合的文本:文本格式和大小。
  4. 重新绘图:
    • 将步骤 (3) 中提取的文本传递给 scale_x_discrete()
    • 将步骤 (3) 中提取的文本大小传递给 theme(axis.text.x = element_text(size = ...)
    • 不要包含任何 ggfittext geom

This answer 使我非常接近最终输出,但我认为它值得单独发表,因此是当前的。

示例

library(ggfittext)
#> Warning: package 'ggfittext' was built under R version 4.0.3
library(tidyverse)

my_cats_df <-
  data.frame(breed = c("Domestic Cat",reflow = TRUE)
#> Warning: Ignoring unknown aesthetics: label

p

如何从给定的 ggplot 对象中提取条形标签及其大小?


## the following is using @teunbrand's solution (https://stackoverflow.com/a/65958754/6105259)
## but I don't understand this at all
grob <- grid::makeContent(layer_grob(p,2)[[1]])$children

grob
#> (fittexttree[GRID.fittexttree.79])

sizes <- vapply(grob,function(x){x$gp$fontsize},numeric(1))
#> Error in vapply(grob,function(x) {: values must be length 1,#>  but FUN(X[[1]]) result is length 0

labels <- unname(vapply(grob,function(x){x$label},character(1)))
#> Error in vapply(grob,#>  but FUN(X[[1]]) result is length 0

reprex package (v0.3.0) 于 2021 年 1 月 31 日创建

示例 (2) -- 分面图

library(tidyverse)
library(ggfittext)
#> Warning: package 'ggfittext' was built under R version 4.0.3

my_cats_df_by_sex <- data.frame(breed = rep(c("Domestic Cat",reflow = TRUE) +
  facet_wrap(~ sex)
#> Warning: Ignoring unknown aesthetics: label

p_facets_by_var

如何从给定的 ggplot 对象中提取条形标签及其大小?

reprex package (v0.3.0) 于 2021 年 1 月 31 日创建


在上述两种情况下(pp_facets_by_var),我想从绘图对象中提取标签文本和大小。应将字符向量传递给 scale_x_discrete() 以重新绘图。

至于轴标签 size,在 ggfittext 为条形呈现各种尺寸的情况下,我们应该取最小的并将其传递给 theme(axis.text.x = element_text(size = ...) 以重新情节。

我希望尽可能地概括这个工作流程,也许是一个函数。不幸的是,我对从给定的 ggplot 对象中提取信息一无所知。我什至不知道怎么读(例如,grid::makeContent(layer_grob(p,2)[[1]])$children 返回(fittexttree[GRID.fittexttree.79])),如何处理?)。

所需的解决方案是获得一些函数/工作流程,以得到一个由 ggfittext 渲染的具有比例 x 标​​签的图。如果有人还可以制定指导方针,如何使用底层机制将此解决方案推广到其他图(例如,我们如何获得 geom_boxplot() 的渲染标签?),这将非常有用。谢谢!

a314913370 回答:如何从给定的 ggplot 对象中提取条形标签及其大小?

暂时没有好的解决方案,如果你有好的解决方案,请发邮件至:iooj@foxmail.com
本文链接:https://www.f2er.com/1008775.html

大家都在问