如何用箭头和最大值注释线图?

How to annotate line plot with arrow and maximum value?

我正在尝试用指向线图中最高点的箭头注释线图,并在图上显示箭头和最大值。我使用 mtcars 数据集作为参考。下面是我的代码。

e <- df$mpg
ggplot(df, aes(x=e, y=df$hp)) + 
  geom_line() + 
  annotate("segment", color="blue", x=max(e), xend = max(e), y=max(df$hp), 
            yend=max(df$hp), arrow=arrow())

提前致谢,

您是否正在寻找这样的东西:

labels <- data.frame(mpg = mtcars[which(mtcars$hp == max(mtcars$hp)), "mpg"]+7, hp = mtcars[which(mtcars$hp == max(mtcars$hp)), "hp"],text = paste0("Max value at mpg = ", mtcars[which(mtcars$hp == max(mtcars$hp)), "mpg"], " and hp = ", max(mtcars$hp)))


ggplot(mtcars, aes(mpg, hp))+
    geom_line()+
    geom_text(data = labels, aes(label = text))+
    annotate("segment", 
        x=mtcars[which(mtcars$hp == max(mtcars$hp)), "mpg"]+2,
        xend=mtcars[which(mtcars$hp == max(mtcars$hp)), "mpg"]+.2, 
        y= mtcars[which(mtcars$hp == max(mtcars$hp)), "hp"],
        yend= mtcars[which(mtcars$hp == max(mtcars$hp)), "hp"], 
        arrow=arrow(), color = "blue")

说明:为了标注max,我们需要找到mpg的位置,即hp的最大值。为此,我们使用 mtcars[which(mtcars$hp == max(mtcars$hp)), "mpg"]which() 语句为我们提供了该最大值的行位置,以便我们可以获得正确的 mpg 值。接下来我们在这个位置上添加一点 space(即 +2 和 +.2)的注释,这样它看起来更漂亮。最后,我们可以构造一个具有相同位置(但偏移量不同)的数据框,并使用 geom_text() 添加数据标签。

这是使用包 'ggpmisc' 的替代方法。下面的代码使用 statistic 而不是 annotate() 使其更通用。由于 stat_peaks() 找到峰值并即时构建标签,此代码可以与面或分组数据一起使用,几乎没有变化。通过更改传递给 span 的值,可以突出显示每组数据的多个峰值。

使用 annotate() 的主要限制是此函数独立于 ggplot data、分组或方面工作。对于小平面,相同的注释被复制到每个面板中。通过设计 annotate() 旨在添加注释,例如与绘制数据相当独立的标签。

突出数据的特征,如在峰值处的观察,不是真正的绘图注释,而是技术上所谓的 数据标签 。使用 geom_text_s()(名称中的“s”代表段)的想法是避免手动定位和将文本标签链接到观察的需要。为了实现链接,我们将标签替换为 position_nudge_keep(),这是 ggplot2::position_nudge() 的变体,它保留原始位置的副本,从而可以绘制标签加上带有 ggpp::geom_text_s() 的线段或箭头或 ggrepel::geom_text_repel().

有一个同伴 statistic stat_valleys() 可用于突出显示最小值。在 'ggpmisc' (>= 0.4.5) 中,这些统计数据支持通过参数 orientation 翻转 xy

注意:我添加了 geom_point() 以突出显示观察结果。

library(ggplot2)
library(ggpmisc)

ggplot(mtcars, aes(mpg, hp)) +
  geom_line() +
  geom_point() +
  stat_peaks(span = NULL,
             geom = "text_s",
             mapping = aes(label = paste(after_stat(y.label), after_stat(x.label))),
             x.label.fmt = "at %.0f mpg",
             y.label.fmt = " Max hp = %.0f",
             segment.colour = "blue",
             arrow = grid::arrow(length = unit(0.1, "inches")),
             position = position_nudge_keep(x = 1, y = 0),
             hjust = 0)

将变量 vs 映射到 color 审美会创建两个组。对于这个例子,我们需要调整微移以避免标签重叠。

ggplot(mtcars, aes(mpg, hp, color = factor(vs))) +
  geom_line() +
  geom_point() +
  stat_peaks(span = NULL,
             geom = "text_s",
             mapping = aes(label = paste(after_stat(y.label), after_stat(x.label))),
             x.label.fmt = "at %.0f mpg ",
             y.label.fmt = " Max hp = %.0f",
             arrow = grid::arrow(length = unit(0.1, "inches")),
             position = position_nudge_keep(x = c(1, -1),  y = 10),
             hjust = c(0, 1))

或者我们可以使用 facet_wrap() 创建面板。

ggplot(mtcars, aes(mpg, hp)) +
  geom_line() +
  geom_point() +
  stat_peaks(span = NULL,
             geom = "text_s",
             mapping = aes(label = paste(after_stat(y.label), after_stat(x.label))),
             x.label.fmt = "at %.0f mpg",
             y.label.fmt = " Max hp = %.0f",
             segment.colour = "blue",
             arrow = grid::arrow(length = unit(0.1, "inches")),
             position = position_nudge_keep(x = 2, y = 10),
             hjust = 0) +
  facet_wrap(~factor(vs))

'ggpmisc' (>= 0.4.6) 和 'ggpp' (>= 0.4.4) 中的错误修复使得可以在同一图中突出显示多个峰和谷。参数 span 描述了 window(连续观察的数量)的宽度,在该范围内搜索峰或谷。

我更改了标签中 mpg 值的格式以包含一位小数。

ggplot(mtcars, aes(mpg, hp)) +
  geom_line() +
  geom_point() +
  stat_valleys(span = 5,
               strict = TRUE,
               geom = "text_s",
               mapping = aes(label = paste(after_stat(y.label), after_stat(x.label))),
               x.label.fmt = "at %.0f mpg ",
               y.label.fmt = "hp = %.0f",
               segment.colour = "blue",
               arrow = grid::arrow(length = unit(0.1, "inches")),
               position = position_nudge_keep(x = -1, y = -20),
               hjust = 1) +
  stat_peaks(span = 5,
             strict = TRUE,
             geom = "text_s",
             mapping = aes(label = paste(after_stat(y.label), after_stat(x.label))),
             x.label.fmt = "at %.0f mpg",
             y.label.fmt = "hp = %.0f\n",
             segment.colour = "red",
             arrow = grid::arrow(length = unit(0.1, "inches")),
             position = position_nudge_keep(x = 1, y = 20),
             hjust = 0) +
 expand_limits(y = 0)

我们可以在参数 orientation 的帮助下翻转第一个示例中的绘图。因为 y 已经成为自变量,我们需要编辑标签格式字符串的文本。

ggplot(mtcars, aes(hp, mpg)) +
  geom_line(orientation = "y") +
  geom_point() +
  stat_peaks(span = NULL,
             strict = TRUE,
             geom = "text_s",
             mapping = aes(label = paste(after_stat(x.label), after_stat(y.label))),
             x.label.fmt = "Max hp = %.0f",
             y.label.fmt = "at %.0f mpg ",
             segment.colour = "red",
             arrow = grid::arrow(length = unit(0.1, "inches")),
             position = position_nudge_keep(x = 0, y = 1),
             hjust = 1,
             angle = -90,
             orientation = "y")