ggplot2:如何动态 wrap/resize/rescale x 轴标签,这样它们就不会重叠

ggplot2: How to dynamically wrap/resize/rescale x axis labels so they won't overlap

我正在尝试实现一种包装 x 轴标签的解决方案,这样它们就不会重叠。我知道这个问题已经被问过好几次了,而且有 。但是,我所见过的解决方案都没有回答如何在绘图 resized.

时重新包装标签

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

  1. 写了一个定制的 geom 来适应 bar 的标签 size条形的宽度,在您调整绘图大小时动态显示。

  2. relies on an extension package for ggplot2 called ggtext. The solution allows dynamic word wrapping of the plot's title, as you resize the plot, based on creating a element_textbox().

  3. relies on another extension called 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 轴标签 wrapped/resized/rescaled 吗?以我幼稚的方式来看,条形内的文本已经以正确的方式呈现,我们能否以某种方式将此呈现“复制”到轴标签?

仅更改文本的角度或大小怎么样?

角度:

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)) 

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

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-01-29 创建