R语言 如何(最低限度地)调整geom_text()标签以避免堆叠geom_col()上的重叠

zdwk9cvp  于 2023-02-06  发布在  其他
关注(0)|答案(2)|浏览(555)

如何在堆积柱形图上放置不重叠的直接标签?
geom_text_repel()正在移动不需要移动的标签,从而导致可读性问题。

library(tibble)
library(tidyr)
library(ggplot2)
library(ggrepel)
library(dplyr)
library(scales)

set.seed(23)
n <- 4
mu <- 4E6

sales <- tibble(
  year=as.factor(seq(2019, length.out=n)),
  A = rnorm(n=n, mean=mu, sd=mu/4),
  B = rnorm(n=n, mean=6*mu, sd=mu),
  C = rnorm(n=n, mean=mu/5, sd=mu/40),
  D = rnorm(n=n, mean=mu/10, sd=mu/40),
  E = rnorm(n=n, mean=4*mu, sd=mu)
) %>% pivot_longer(!year, names_to="product", values_to="sales")
  
p <- sales %>%
  group_by(year, product) %>%
  summarise(sales=sum(sales)) %>%
  mutate(pct_of_year_sales = sales/sum(sales),
         label=paste(
    scales::label_dollar(scale=1/1E6, suffix="M", accuracy=0.1)(sales),
    scales::label_percent(accuracy=0.1)(pct_of_year_sales),
    sep=", ")) %>%
  ggplot(aes(x=year, y=sales, fill=product, label=label)) + 
  geom_col() +
  scale_y_continuous(labels = scales::label_dollar(scale=1/1E6, suffix="M"),
                     expand = expansion(mult = c(0, .05)))

p + geom_text(position=position_stack(vjust=0.5)) +
  labs(title="geom_text()",
       subtitle="overlapping labels")

p + geom_text_repel(position=position_stack(vjust = 0.5), 
                    direction="y") + 
  labs(title="geom_text_repel()", 
       subtitle="text for series A moves needlessly")

reprex package(v2.0.1)于2023年2月2日创建

deyfvvtc

deyfvvtc1#

我完全同意@tjebo的评论,有时候添加这么多文本并不是最好的方法。但有时候这是强制性的(我们无法控制),所以我建议解决你的一个抱怨:
geom_text_repel()正在移动不需要移动的标注
我们可以在大多数情况下使用geom_text(按销售百分比过滤),在少数情况下使用geom_text_repel
通常,我会使用data = ~ filter(., pct_of_year_sales <= 0.015))>用于main),但是当列的数量和值被打乱时,堆叠也会被打乱。相反,我们可以创建两组标签,其中一些是空的(""NA),这取决于它们的pct_of_year_sales值。这样,geom_text_repel可以看到所有列/值,并将它们放置在适当的位置。

dat <- sales %>%
  group_by(year, product) %>%
  summarise(sales=sum(sales), .groups="drop") %>%
  mutate(pct_of_year_sales = sales/sum(sales),
         label = paste(
           scales::label_dollar(scale=1/1E6, suffix="M", accuracy=0.1)(sales),
           scales::label_percent(accuracy=0.1)(pct_of_year_sales),
           sep=", ")) %>%
  mutate(
    label1 = if_else(pct_of_year_sales > 0.015, label, NA_character_),
    label2 = if_else(pct_of_year_sales <= 0.015, label, NA_character_)
  )

p <- ggplot(dat, aes(x=year, y=sales, fill=product, label=label1)) + 
  geom_col() +
  scale_y_continuous(labels = scales::label_dollar(scale=1/1E6, suffix="M"),
                     expand = expansion(mult = c(0, .05))) +
  geom_text(position=position_stack(vjust=0.5), na.rm = TRUE) +
  labs(title="geom_text()",
       subtitle="overlapping labels")
p

p +
  ggrepel::geom_text_repel(
    min.segment.length = 0, force = 10,
    aes(label = label2),
    position=position_stack(vjust = 0.5), hjust = 0.25,
    direction="y", na.rm=TRUE)

我添加了hjust=来稍微移动它们,这也有助于澄清线段线(如果没有hjust,它们倾向于与逗号连接,这是一个视觉上分散注意力的人工产物)。您可能希望使用force=或其他线段美学来更清楚地将它们分开。(例如,为了控制每年的水平对齐,可以在框架本身内定义hjust,而在aes(..)内指定美学,这只是一个想法。)

hvvq6cgz

hvvq6cgz2#

我想我更喜欢@r2evans的答案,因为它利用了工具,因为他们是用来。我走了一条不同的路线。
开始了解电网永远不会太早...
它使用库gridgridExtra
首先,我将打印保存到对象,并调查标签的位置和应用的设置(使用geom_text,而不是...repel)。
grid中,你可以设置每个标签的对齐方式。所以我把C中的值的垂直对齐方式设置为0,D中的值的垂直对齐方式设置为1。这在我的绘图窗格中已经足够了......然而,根据图形的大小,你可能需要选择距离更远的值。只要记住.5是中间,而不是0。
有关更深入的解释,请参见我的代码注解。

library(grid)
library(gridExtra)

pp <- p + geom_text(position=position_stack(vjust=0.5)) +
  labs(title="geom_text()",
       subtitle="overlapping labels")
pg <- ggplotGrob(pp)        # create grid (gtable) of graph

# the labels in geom_text
pg$grobs[[6]]$children$GRID.text.246$label # use this to see the label order

# lbls top to btm then left to right
# get vjust to modify
gimme <- pg$grobs[[6]]$children$GRID.text.246$vjust

# which indices need to change (C and D labels)
ttxt <- seq(from = 3, by = 5, length.out = 4) # 5 labels in column
btxt <- seq(from = 4, by = 5, length.out = 4) # 4 columns

gimme[ttxt] <- 0 # set C to top of vspace
gimme[btxt] <- 1 # set D to bottom of vspace

# replace existing vjust
pg$grobs[[6]]$children$GRID.text.246$vjust <- gimme

你可以查看带有网格的绘图,或者将它改回ggplot对象。要将它改回ggplot对象,你可以使用ggplotify::as.ggplotggpubr::as_ggplot,它们做同样的事情。

plot.new()
grid.draw(pg)

# back to ggplot obj
ggpubr::as_ggplot(pg)

相关问题