ggplot2:如何动态包装/调整大小/重新缩放 x 轴标签,使它们不会重叠

Posted

技术标签:

【中文标题】ggplot2:如何动态包装/调整大小/重新缩放 x 轴标签,使它们不会重叠【英文标题】:ggplot2: How to dynamically wrap/resize/rescale x axis labels so they won't overlap 【发布时间】:2021-05-03 12:17:36 【问题描述】:

我正在尝试实现一种包装 x 轴标签的解决方案,这样它们就不会重叠。我知道这个问题已经被问过好几次了,还有some good answers。但是,我所见过的解决方案没有解决如何在情节得到调整大小时重新包装标签。

SO 的三个不同答案让我相信这是可以实现的。

    This solution 写了一个定制的geom 用于调整条形 的标签size 以适应条形的宽度,在您调整绘图大小时动态调整。

    This solution 依赖于名为ggtextggplot2扩展 包。该解决方案允许在您根据创建element_textbox() 调整绘图大小时动态换行绘图的标题

    This solution 依赖于另一个名为 ggfittext 的扩展。它显示了在调整绘图大小时,条形内标签的size 如何动态变化以适应条形的尺寸。本质上,它解决了与上述解决方案 (1) 相同的问题,但功能更强大。事实上,这是让我充满希望的功能,它依赖于通用解决方案 geom_fit_text() 来将文本放入矩形内,而不仅仅是 geom_bar()s。

一些可使用的演示数据

1.只是为了显示 x 轴标签重叠时的典型输出

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

由reprex package (v0.3.0) 于 2021-01-29 创建


2。当我们使用ggfittext 时,我们可以看到条形内的标签如何缩小以适应条形

  library(tidyverse)
  library(ggfittext)
#> Warning: package 'ggfittext' was built under R version 4.0.3
  
  my_mtcars <-
    mtcars[15:20,] %>% 
    rownames_to_column("cars")
  
  my_mtcars %>%
    ggplot(aes(x = cars, y = mpg, fill = cars)) + 
    geom_bar(stat = "identity") +
    geom_bar_text(aes(label = cars), 
      color = "blue", 
      vjust = 1, 
      size = 7 * ggplot2::.pt, 
      min.size = 0,
      padding.x = grid::unit(0, "pt"),
      padding.y = grid::unit(0, "pt"))
#> Warning: Ignoring unknown aesthetics: label

由reprex package (v0.3.0) 于 2021-01-29 创建


3。 ggfittext 具有促进文本换行的 reflow 参数

  library(tidyverse)
  library(ggfittext)
#> Warning: package 'ggfittext' was built under R version 4.0.3
  
  my_mtcars <-
    mtcars[15:20,] %>% 
    rownames_to_column("cars")
  
  my_mtcars %>%
    ggplot(aes(x = cars, y = mpg, fill = cars)) + 
    geom_bar(stat = "identity") +
    geom_bar_text(aes(label = cars), 
      color = "blue", 
      vjust = 1, 
      size = 7 * ggplot2::.pt, 
      min.size = 0,
      padding.x = grid::unit(0, "pt"),
      padding.y = grid::unit(0, "pt"),
      reflow = TRUE ## <--------------- added this
      )
#> Warning: Ignoring unknown aesthetics: label

由reprex package (v0.3.0) 于 2021-01-29 创建


我的问题

我不知道该怎么做,但是我们能否通过某种方式让ggfittext 为我们完成繁重的工作,从而动态地包装/调整大小/重新调整 x 轴标签?以天真的方式,我看到这个,条内的文本已经以正确的方式呈现,我们可以以某种方式将这个呈现“复制”到轴标签吗?

【问题讨论】:

可能在 ggfittext 的 github 上的相关问题:github.com/wilkox/ggfittext/issues/14 【参考方案1】:

我们将ggfittext 文本放在y 轴下方怎么样?我们关闭剪辑并设置ooblimits 以适合我们的数据。可能应该调整 axis.text.x 的大小以更好地与 x 轴标题对齐。

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

my_mtcars <-
  mtcars[15:20,] %>% 
  rownames_to_column("cars")

my_mtcars %>%
  ggplot(aes(x = cars, y = mpg, fill = cars)) + 
  geom_bar(stat = "identity") +
  geom_fit_text(aes(label = cars, y = -4),
                reflow = TRUE, height = 50,
                show.legend = FALSE) +
  scale_y_continuous(oob = scales::oob_keep,
                     limits = c(0, NA)) +
  coord_cartesian(clip = "off") +
  theme(axis.text.x = element_text(colour = "transparent", size = 18))

由reprex package (v0.3.0) 于 2021-01-29 创建

编辑:从 grob 中取出标签

library(tidyverse)
library(ggfittext)

my_mtcars <-
  mtcars[15:20,] %>% 
  rownames_to_column("cars")

p <- my_mtcars %>%
  ggplot(aes(x = cars, y = mpg, fill = cars)) + 
  geom_bar(stat = "identity") +
  geom_fit_text(aes(label = cars, y = -1),
                reflow = TRUE, height = 50,
                show.legend = FALSE) +
  scale_y_continuous(oob = scales::oob_keep,
                     limits = c(0, NA)) +
  coord_cartesian(clip = "off") +
  theme(axis.text.x = element_text(colour = "transparent", size = 18))

grob <- grid::makeContent(layer_grob(p, 2)[[1]])$children

sizes <- vapply(grob, function(x)x$gp$fontsize, numeric(1))
labels <- unname(vapply(grob, function(x)x$label, character(1)))
print(labels)
#> [1] "Cadillac\nFleetwood"  "Lincoln\nContinental" "Chrysler\nImperial"  
#> [4] "Fiat 128"             "Honda Civic"          "Toyota\nCorolla"

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

【讨论】:

这真是太好了,谢谢。但是,y = -4 提出了一个限制。虽然 -4 适用于此图,但不同的图可以有任何 y 比例,而 -4 将不起作用。有没有办法独立于 y 值设置垂直位置? 我有另一个想法......是否有可能破解呈现的标签,并提取自动换行(例如,"Fiat 128""Honda\nCivic"和 i> 文本大小,然后将其传递给scale_x_discrete()? 是的,我同意这是这种方法的一个限制,这就是为什么我在他们的 github 上为 ggtfittext 作者留下了一些建议,以便在 theme() 级别实现它。 我喜欢这个想法,但限制是 ggfittext 在实际渲染时间和所有绝对尺寸已知之前不会渲染。您必须以某种方式拦截他们的 makeContent.fittexttree 方法,您可以使用调试器执行此操作,但这比手动设置 y 位置更难通用。此外,如果您调整设备窗口的大小,您截取的值将不再正确。 我们不能先将渲染图保存到对象p,然后从p中提取信息并添加scale_x_discrete()吗?最后将其全部封装在一个函数中......这将是一个半动态的解决方案,但足够了。【参考方案2】:

改变文字的角度或大小怎么样?

角度:

my_mtcars %>%
  ggplot(aes(x = cars, y = mpg, fill = cars)) + 
  geom_bar(stat = "identity")+
  theme(axis.text.x = element_text(angle = 45, vjust = 0.5, hjust=1))

尺寸:

my_mtcars %>%
  ggplot(aes(x = cars, y = mpg, fill = cars)) + 
  geom_bar(stat = "identity")+
  theme(axis.text.x = element_text(size = 4)) 

【讨论】:

当然可以,而且我知道这样的解决方案。我通过在本文开头引用此rundown 来承认这一点。但我的问题不同。 啊,抱歉,我没有进入参考文献。

以上是关于ggplot2:如何动态包装/调整大小/重新缩放 x 轴标签,使它们不会重叠的主要内容,如果未能解决你的问题,请参考以下文章

Numpy 调整大小/重新缩放图像

如何在ggplot2中分别缩放线和点的大小

如何在网站中动态裁剪/缩放图像

如何在android中根据谷歌地图不同的缩放级别调整谷歌地图标记的大小

当系统范围的字体缩放时,Android TextView不会包装内容

Qt QGraphicsSvgItem 缩放和调整大小