5

我正在制作一个类似于坡度图的图表,我想在一侧或两侧放置标签,并留有足够的空白空间以使其适合两侧。在标签很长的情况下,我将它们包裹起来stringr::str_wrap用于放置换行符。为了防止标签重叠,我使用ggrepel::geom_text_repelwithdirection = "y"所以 x 位置是稳定的,但 y 位置相互排斥。我还必须hjust = "outward"在其右端对齐左侧文本,反之亦然。

但是,似乎排斥定位将标签的边界框放置在 中hjust = "outward",但该标签中的文本具有,即文本在其边界内居中hjust = 0.5直到现在,我从未注意到这一点,但是使用包裹标签,第二行居中尴尬,而我希望看到两行左对齐或右对齐。

这是一个基于数据集构建的示例mpg

library(ggplot2)
library(dplyr)
library(ggrepel)

df <- structure(list(long_lbl = c("chevrolet, k1500 tahoe 4wd, auto(l4)", 
                                  "chevrolet, k1500 tahoe 4wd, auto(l4)", "subaru, forester awd, manual(m5)", 
                                  "subaru, forester awd, manual(m5)", "toyota, camry, manual(m5)", 
                                  "toyota, camry, manual(m5)", "toyota, toyota tacoma 4wd, manual(m5)", 
                                  "toyota, toyota tacoma 4wd, manual(m5)", "volkswagen, jetta, manual(m5)", 
                                  "volkswagen, jetta, manual(m5)"), year = c(1999L, 2008L, 1999L, 
                                                                             2008L, 1999L, 2008L, 1999L, 2008L, 1999L, 2008L), mean_cty = c(11, 
                                                                                                                                            14, 18, 20, 21, 21, 15, 17, 33, 21)), class = c("tbl_df", "tbl", 
                                                                                                                                                                                            "data.frame"), row.names = c(NA, -10L))

df_wrap <- df %>%  
  mutate(wrap_lbl = stringr::str_wrap(long_lbl, width = 25))

ggplot(df_wrap, aes(x = year, y = mean_cty, group = long_lbl)) +
  geom_line() +
  geom_text_repel(aes(label = wrap_lbl),
                  direction = "y", hjust = "outward", seed = 57, min.segment.length = 100) +
  scale_x_continuous(expand = expand_scale(add = 10))

的其他值也会发生同样的情况hjust。查看函数的source,我看到一条指向此问题的行:

hjust = x$data$hjust %||% 0.5,

如果为空,%||%则分配 0.5 。x$data$hjust据我所知,但似乎hjust我设置的并没有被转移到这个位置,而是变成了空值。

我错过了什么吗?谁能在不重新实现整个算法的情况下看到我可以在哪里覆盖它?还是这里有一个错误会导致我的hjust?

4

2 回答 2

8

TL;DR:可能是一个错误

长答案:

我认为这可能是代码中的错误。我检查了您制作的绘图的 gtable,其中以hjust数字方式正确指定了:

# Assume 'g' is the plot saved under the variable 'g'
gt <- ggplotGrob(g)
# Your number at the end of the geom may vary
textgrob <- gt$grobs[[6]]$children$geom_text_repel.textrepeltree.1578
head(textgrob$data$hjust)
[1] 1 0 1 0 1 0

这让我想到(1)不能通过在 gtable 中乱搞来修复情节,(2)grobstextrepeltree类的绘制时间代码可能包含一些错误。这是有道理的,因为在调整绘图设备大小时会重新定位标签。因此,当我们查看makeContent.textrepeltree()您提供的链接中的代码时,我们可以看到hjust参数被传递到makeTextRepelGrobs(). 我们来看看相关的形式:

makeTextRepelGrobs <- function(
  ...other_arguments...,
  just = "center",
  ...other_arguments...,
  hjust = 0.5,
  vjust = 0.5
) { ...body...}

我们可以看到这hjust是一个有效的参数,但也存在一个just参数,它是一个不从 传递的参数makeContent.textrepeltree()

当我们查看函数体时,有这两行:

  hj <- resolveHJust(just, NULL)
  vj <- resolveVJust(just, NULL)

从哪里resolveH/VJust导入网格包。resolveHJust()本质上检查第二个参数是否为NULL真,如果为真,则默认为第一个参数,否则返回第二个参数。您可以看到hjust传递给的makeTextRepelGrobs()没有被传递给resolveHJust(),这似乎是您的hjust参数被意外删除的地方。

再往下,代码是实际文本 grobs 的生成位置:

  t <- textGrob(
    ...other_arguments...
    just = c(hj, vj),
    ...other_arguments...
  )

我想修复会相对简单:您只需hjust将第二个参数提供给resolveHJust(). 但是,由于它makeTextRepelGrobs()是 ggrepel 内部的并且不会被导出,因此您必须复制大量额外的代码才能使其正常工作。(不确定是否只复制makeTextRepelGrob()就足够了,还没有测试过)

所有这一切让我得出结论,hjust您在中指定的内容在geom_text_repel()绘制时间的最后一刻被makeTextRepelGrobs()内部函数丢失了。

于 2019-05-07T20:09:24.410 回答
3

更新(2019 年 12 月 12 日):

仅供参考,现在在 的开发版本中解决了这个问题ggrepel,并且该修复也适用于geom_label_repel. 请参阅GitHub 上的问题 #137 。

library(ggplot2)
library(dplyr)
devtools::install_github("slowkow/ggrepel")


df <- structure(list(long_lbl = c("chevrolet, k1500 tahoe 4wd, auto(l4)", 
                                  "chevrolet, k1500 tahoe 4wd, auto(l4)", "subaru, forester awd, manual(m5)", 
                                  "subaru, forester awd, manual(m5)", "toyota, camry, manual(m5)", 
                                  "toyota, camry, manual(m5)", "toyota, toyota tacoma 4wd, manual(m5)", 
                                  "toyota, toyota tacoma 4wd, manual(m5)", "volkswagen, jetta, manual(m5)", 
                                  "volkswagen, jetta, manual(m5)"), year = c(1999L, 2008L, 1999L, 
                                                                             2008L, 1999L, 2008L, 1999L, 2008L, 1999L, 2008L), mean_cty = c(11, 
                                                                                                                                            14, 18, 20, 21, 21, 15, 17, 33, 21)), class = c("tbl_df", "tbl", 
                                                                                                                                                                                            "data.frame"), row.names = c(NA, -10L))

df_wrap <- df %>%  
  mutate(wrap_lbl = stringr::str_wrap(long_lbl, width = 25))

# With geom_text_repel
ggplot(df_wrap, aes(x = year, y = mean_cty, group = long_lbl)) +
  geom_line() +
  geom_text_repel(aes(label = wrap_lbl),
                  hjust = "outward",
                  direction = "y",
                  seed = 57,
                  min.segment.length = 100) +
  scale_x_continuous(expand = expansion(add = 10))

# With geom_label_repel
ggplot(df_wrap, aes(x = year, y = mean_cty, group = long_lbl)) +
  geom_line() +
  geom_label_repel(aes(label = wrap_lbl),
                  hjust = "outward",
                  direction = "y",
                  seed = 57,
                  min.segment.length = 100) +
  scale_x_continuous(expand = expansion(add = 10))

在此处输入图像描述

于 2019-12-12T18:53:12.333 回答