r - 如何阻止ggrepel标签在R/ggplot2中的gganimate帧之间移动?

标签 r ggplot2 gganimate ggrepel

我想在 ggplot 的行尾添加标签,避免它们重叠,并避免它们在动画过程中移动。

到目前为止,我可以将标签放在正确的位置并使用 geom_text 保持它们静止不动。 ,但标签重叠,或者我可以使用 geom_text_repel 防止它们重叠但是标签不会出现在我希望它们出现的位置,然后在情节动画后跳舞(后一个版本在下面的代码中)。

我认为一个解决方案可能涉及在 ggplot 中有效地创建一个静态层(下面的 p1)然后添加一个动画层(下面的 p2),但似乎不是。

如何在动画 ggplot 中保存绘图常量(即静态)的某些元素? (在这种情况下,行尾的标签。)

此外,还有 geom_text标签显示为我想要的 - 在每行的末尾,在情节之外 - 但带有 geom_text_repel ,标签都在绘图区域内移动。为什么是这样?

以下是一些示例数据:

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

set.seed(99)

# data
static_data <- data.frame(
  hline_label = c("fixed_label_1", "fixed_label_2", "fixed_label_3", "fixed_label_4", 
                  "fixed_label_5", "fixed_label_6", "fixed_label_7", "fixed_label_8", 
                  "fixed_label_9", "fixed_label_10"), 
  fixed_score = c(2.63, 2.45, 2.13, 2.29, 2.26, 2.34, 2.34, 2.11, 2.26, 2.37))

animated_data <- data.frame(condition = c("a", "b")) %>% 
  slice(rep(1:n(), each = 10)) %>% 
  group_by(condition) %>% 
  mutate(time_point = row_number()) %>% 
  ungroup() %>% 
  mutate(score = runif(20, 2, 3))

这是我用于我的动画情节的代码:
# colours for use in plot
condition_colours <- c("red", "blue")

# plot static background layer 
p1 <- ggplot(static_data, aes(x = time_point)) +
  scale_x_continuous(breaks = seq(0, 10, by = 2), expand = c(0, 0)) + 
  scale_y_continuous(breaks = seq(2, 3, by = 0.10), limits = c(2, 3), expand = c(0, 0)) + 
  # add horizontal line to show existing scores
  geom_hline(aes(yintercept = fixed_score), alpha = 0.75) + 
  # add fixed labels to the end of lines (off plot)
  geom_text_repel(aes(x = 11, y = fixed_score, label = hline_label), 
                  hjust = 0, size = 4, direction = "y", box.padding = 1.0) +
  coord_cartesian(clip = 'off') +
  guides(col = F) +
  labs(title = "[Title Here]", x = "Time", y = "Mean score") + 
  theme_minimal() + 
  theme(panel.grid.minor = element_blank(),
        plot.margin = margin(5.5, 120, 5.5, 5.5))

# animated layer
p2 <- p1 + 
  geom_point(data = animated_data, 
             aes(x = time_point, y = score, colour = condition, group = condition)) +
  geom_line(data = animated_data, 
            aes(x = time_point, y = score, colour = condition, group = condition), 
            show.legend = FALSE) +
  scale_color_manual(values = condition_colours) + 
  geom_segment(data = animated_data, 
               aes(xend = time_point, yend = score, y = score, colour = condition),
               linetype = 2) + 
  geom_text(data = animated_data, 
            aes(x = max(time_point) + 1, y = score, label = condition, colour = condition), 
            hjust = 0, size = 4) + 
  transition_reveal(time_point) +
  ease_aes('linear') 

# render animation 
animate(p2, nframes = 50, end_pause = 5, height = 1000, width = 1250, res = 120)

最佳答案

供考虑的建议:

  • geom_text_repel中的具体排斥方向/数量/等由随机种子决定。您可以 套装seed到一个恒定值 为了在动画的每一帧中获得相同的排斥位置。
  • 我认为排斥文本不可能超出绘图区域,即使您关闭剪辑并指定一些超出绘图限制的排斥范围。该软件包的全部意义在于使文本标签彼此远离,同时保持在绘图区域内。但是,您可以扩大地块面积 & 使用 geom_segment而不是 geom_hline绘制水平线,使这些线在到达排斥文本标签之前停止。
  • 由于有更多的几何层使用 animated_data作为他们的数据源,使用 会更干净放animated_data与顶级相关的常见美学映射ggplot()调用 , 而不是 static_data .

  • 这是一个可能的实现。注释中的解释:
    p3 <- ggplot(animated_data,
           aes(x = time_point, y = score, colour = condition, group = condition)) +
    
      # static layers (assuming 11 is the desired ending point)
      geom_segment(data = static_data,
                   aes(x = 0, xend = 11, y = fixed_score, yend = fixed_score), 
                   inherit.aes = FALSE, colour = "grey25") +
      geom_text_repel(data = static_data,
                      aes(x = 11, y = fixed_score, label = hline_label), 
                      hjust = 0, size = 4, direction = "y", box.padding = 1.0, inherit.aes = FALSE, 
                      seed = 123,           # set a constant random seed
                      xlim = c(11, NA)) +   # specify repel range to be from 11 onwards
    
      # animated layers (only specify additional aesthetic mappings not mentioned above)
      geom_point() +
      geom_line() +
      geom_segment(aes(xend = time_point, yend = score), linetype = 2) +
      geom_text(aes(x = max(time_point) + 1, label = condition),
                hjust = 0, size = 4) +
    
      # static aesthetic settings (limits / expand arguments are specified in coordinates
      # rather than scales, margin is no longer specified in theme since it's no longer
      # necessary)
      scale_x_continuous(breaks = seq(0, 10, by = 2)) +
      scale_y_continuous(breaks = seq(2, 3, by = 0.10)) + 
      scale_color_manual(values = condition_colours)  +
      coord_cartesian(xlim = c(0, 13), ylim = c(2, 3), expand = FALSE) +
      guides(col = F) +
      labs(title = "[Title Here]", x = "Time", y = "Mean score") + 
      theme_minimal() + 
      theme(panel.grid.minor = element_blank())  + 
    
      # animation settings (unchanged)
      transition_reveal(time_point) +
      ease_aes('linear') 
    
    animate(p3, nframes = 50, end_pause = 5, height = 1000, width = 1250, res = 120)
    

    result

    关于r - 如何阻止ggrepel标签在R/ggplot2中的gganimate帧之间移动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55723567/

    相关文章:

    r - R 3.6 的 arrayQualityMetrics 包和 GEOquery 的来源是什么

    r - 如何在 R Shiny 中单独更改 renderTable 中列的位数

    RStudio 全局设置(选项)导出/导入

    r - 具有时间序列线图的 tweenr/gganimate

    r - 保持点在gganimate

    r - 使用企业网关时,是否可以在 Power BI Server 中运行 R 脚本?

    r - ggplot2 相对于视口(viewport)的 geom_text 或 geom_label 位置

    r - 如何处理重叠因子水平? (例如,在制作表格和图表时)

    r - 是否可以轻松地降低 ggplot 的饱和度?

    r - gganimate如何订购有序的酒吧时间序列?