首页 > 解决方案 > 使用多个geom时如何添加带有directlabels的标签?

问题描述

当我使用多个几何图形时,我正在努力在带有直接标签的线图的右端创建标签。这是一个例子:

#load packages
library(dplyr)
library(ggplot2)
library(tidyr)
library(directlabels)

#create data
set.seed(1)
test <- tibble(year = as.factor(rep(1990:2000, 4)), 
     label = rep(replicate(4, paste0(sample(letters, 20), collapse = "")), each =11), #create long random labels
     value = rnorm(44))
test[which(test$year==2000),]$value <- seq(0,0.1, length.out = 4) # make final values very similar

average <- test %>% 
     group_by(year) %>% 
     summarize(value = mean(value)) %>% 
     bind_cols(label = "average")

#draw plot
ggplot(test, aes(x = year, y = value, group = label, color = label)) +
  geom_line() +
  geom_smooth(data = average,
              mapping = aes(x = year, y = value, group = label, color = label),
              inherit.aes = F, col = "black") +
  geom_dl(aes(label = label,
              color = label), 
          method = list(dl.combine("last.bumpup"))) +
  theme(legend.position = "none")

这给出了这个情节:

线图示例

现在我想在 geom_smooth 线的右侧添加一个黑色标签,上面写着“平均”。我在尝试过的一些方法中发现的一个问题是,当我单独创建它时它与其他标签重叠并且它不会以黑色显示。

例如:

ggplot(test, aes(x = year, y = value, group = label, color = label)) +
  geom_line() +
  geom_smooth(data = average,
              mapping = aes(x = year, y = value, group = label, color = label),
              inherit.aes = F, col = "black") +
  geom_dl(aes(label = label,
              color = label), 
          method = list(dl.combine("last.bumpup"))) +
  geom_dl(data = average,
          mapping = aes(label = label,
              color = label), 
          method = list(dl.combine("last.bumpup"))) +
  theme(legend.position = "none")

给出了这个情节:

线图示例 2

总而言之,我希望为 geom_smooth 创建一个与 geom_smooth 线颜色相同且不与其他标签冲突的标签。

一个警告:我不能使用 stat_summary (如其他地方所建议的那样),因为在我的实际数据中,平均值是加权的,由于我不知道权重,我不能从单个数据点到平均值。所以我需要取数据框中提供的平均值。

更新

在我的实际数据中,标签要长得多(10-30 个字符),其中一些在最高年份的 y 值非常相似。这就是为什么我使用带有碰撞参数的直接标签。如果标签不相互排斥,可能会有重叠。

标签: rggplot2direct-labels

解决方案


尝试ggrepel使用directlabels.

(修改问题后的更新方法)

test请注意,在适用于标签的数据中包含平均数据行和标签可能更优雅。这种方法需要对“平均”标签进行一些手动调整。还有其他geom_text_repel()未使用的参数可能允许改进定位。

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

set.seed(1)
test <- tibble(year = as.factor(rep(1990:2000, 4)), 
               label = rep(replicate(4, paste0(sample(letters, 20), collapse = "")), each =11), #create long random labels
               value = rnorm(44))
test[which(test$year==2000),]$value <- seq(0,0.1, length.out = 4) # make final values very similar

average <- test %>% 
  group_by(year) %>% 
  summarize(value = mean(value)) %>% 
  bind_cols(label = "average")


# initial plot with labels for lines
# For fuller description of possible arguments to repel function, see:
# https://ggrepel.slowkow.com/articles/examples.html
p <- 
  ggplot(test, aes(x = year, y = value, group = label, color = label)) +
  geom_line() +
  geom_smooth(data = average,
              mapping = aes(x = year, y = value, group = label, color = label),
              inherit.aes = F, col = "black") +
  geom_text_repel(data = filter(test, year == 2000), 
                  aes(label = label,
                      color = label),
                  direction = "y",
                  vjust = 1.6,
                  hjust = 0.5,
                  segment.size = 0.5,
                  segment.linetype = "solid",
                  box.padding = 0.4,
                  seed = 123) +
  coord_cartesian(clip = 'off')+
  scale_x_discrete(expand = expansion(mult = c(0.06, 0.0)))+
  theme(legend.position = "none",
        plot.margin = unit(c(5, 50, 5, 5), "mm"))
  
# find coordinates for last point of geom_smooth line, by inspection of ggplot_buildt

lab_avg <- 
  slice_tail(ggplot_build(p)$data[[2]], n = 1) %>% 
  mutate(label = "Average")

# plot with label for geom_smooth line
# positioning of the Average label achieved manually varying vjust and hjust,
# there is probably a better way of doing this

p1 <- 
  p + 
  geom_text_repel(data = lab_avg,
          aes(x = x, y = y, label = label),
          colour = "black",
          direction = "y",
          vjust = 3.5,
          hjust = -7,
          segment.size = 0.5,
          segment.linetype = "solid",
          segment.angle = 10,
          box.padding = 0.4,
          seed = 123)
p1

reprex 包于 2021-08-22 创建 (v2.0.0 )

原始问题的初步答案。

您可以尝试geom_text()使用数据集中的数据并使用和average调整“平均”的位置。hjustvjust

用于scale_x_discrete(expand...)为文本标签创建一些额外的空间。


ggplot(test, aes(x = year, y = value, group = label, color = label)) +
  geom_line() +
  geom_smooth(data = average,
              mapping = aes(x = year, y = value, group = label, color = label),
              inherit.aes = F, col = "black") +
  geom_dl(aes(label = label,
              color = label), 
          method = list(dl.combine("last.bumpup"))) +
  scale_x_discrete(expand = expansion(mult = c(0.06, 0.2)))+
  geom_text(data = slice_tail(average, n = 1),
            aes(x = year, y = value, label = "Average"),
            colour = "black",
            hjust = -0.2,
            vjust = 1.5)+
  theme(legend.position = "none")

reprex 包于 2021-08-21 创建 (v2.0.0 )


推荐阅读