简体   繁体   English

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

[英]How to stop ggrepel labels moving between gganimate frames in R/ggplot2?

I would like to add labels to the end of lines in ggplot, avoid them overlapping, and avoid them moving around during animation.我想在 ggplot 的行尾添加标签,避免它们重叠,并避免它们在动画过程中移动。

So far I can put the labels in the right place and hold them static using geom_text , but the labels overlap, or I can prevent them overlapping using geom_text_repel but the labels do not appear where I want them to and then dance about once the plot is animated (this latter version is in the code below).到目前为止,我可以将标签放在正确的位置并使用geom_text将它们保持静态,但标签重叠,或者我可以使用geom_text_repel防止它们重叠,但标签不会出现在我希望它们出现的位置,然后在情节结束后跳舞动画(后一个版本在下面的代码中)。

I thought a solution might involve effectively creating a static layer in ggplot ( p1 below) then adding an animated layer ( p2 below), but it seems not.我认为一个解决方案可能涉及在 ggplot(下面的p1 )中有效地创建一个静态层,然后添加一个动画层(下面的p2 ),但似乎不是。

How do I hold some elements of a plot constant (ie static) in an animated ggplot?如何在动画 ggplot 中保存绘图常量(即静态)的某些元素? (In this case, the labels at the end of lines.) (在这种情况下,行尾的标签。)

Additionally, with geom_text the labels appear as I want them - at the end of each line, outside of the plot - but with geom_text_repel , the labels all move inside the plotting area.此外,使用geom_text标签显示为我想要的 - 在每行的末尾,在绘图之外 - 但使用geom_text_repel ,标签都在绘图区域内移动。 Why is this?为什么是这样?

Here is some example data:以下是一些示例数据:

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))

and this is the code I am using for my animated plot:这是我用于我的动画情节的代码:

# 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)

Suggestions for consideration:供考虑的建议:

  1. The specific repelling direction / amount / etc. in geom_text_repel is determined by a random seed. geom_text_repel具体的排斥方向/数量/等由随机种子决定。 You can set seed to a constant value in order to get the same repelled positions in each frame of animation.您可以seed设置为常量值,以便在动画的每一帧中获得相同的排斥位置。

  2. I don't think it's possible for repelled text to go beyond the plot area, even if you turn off clipping & specify some repel range outside plot limits.我认为排斥文本不可能超出绘图区域,即使您关闭剪辑并指定一些超出绘图限制的排斥范围。 The whole point of that package is to keep text labels away from one another while remaining within the plot area.该软件包的全部意义在于使文本标签彼此远离,同时保持在绘图区域内。 However, you can extend the plot area & use geom_segment instead of geom_hline to plot the horizontal lines, such that these lines stop before they reach the repelled text labels.但是,您可以扩展绘图区域并使用geom_segment而不是geom_hline来绘制水平线,以便这些线在到达排斥文本标签之前停止。

  3. Since there are more geom layers using animated_data as their data source, it would be cleaner to put animated_data & associated common aesthetic mappings in the top level ggplot() call , rather than static_data .由于有更多的几何层使用animated_data数据作为数据源,将animated_data和相关的通用美学映射放在顶级ggplot()调用中会更static_data ,而不是static_data

Here's a possible implementation.这是一个可能的实现。 Explanation in annotations:注释中的解释:

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)

结果

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM