Search code examples
rggplot2gganimate

Problems with geom_text and pausing the animation


I'm trying to replicate the following code (thomasp85/gganimate). I have two problems:

  1. I don't want to show the labels (variable: partidos) of the first geom_point;
  2. I would like that once the animation ends, for a few seconds the labels (variable: partidos) of the last geom_point are shown.

    dput(polls_)
structure(list(week = structure(c(1551571200, 1551571200, 1551571200, 
1551571200, 1551571200, 1550966400, 1550966400, 1550966400, 1550966400, 
1550966400, 1550361600, 1550361600, 1550361600, 1550361600, 1550361600, 
1549756800, 1549756800, 1549756800, 1549756800, 1549756800, 1549152000, 
1549152000, 1549152000, 1549152000, 1549152000, 1548547200, 1548547200, 
1548547200, 1548547200, 1548547200, 1547942400, 1547942400, 1547942400, 
1547942400, 1547942400, 1547337600, 1547337600, 1547337600, 1547337600, 
1547337600, 1546732800, 1546732800, 1546732800, 1546732800, 1546732800, 
1546128000, 1546128000, 1546128000, 1546128000, 1546128000, 1545523200, 
1545523200, 1545523200, 1545523200, 1545523200, 1544918400, 1544918400, 
1544918400, 1544918400, 1544918400, 1544313600, 1544313600, 1544313600, 
1544313600, 1544313600, 1543708800, 1543708800, 1543708800, 1543708800, 
1543708800, 1541894400, 1541894400, 1541894400, 1541894400, 1541894400, 
1541289600, 1541289600, 1541289600, 1541289600, 1541289600, 1540684800, 
1540684800, 1540684800, 1540684800, 1540684800, 1540080000, 1540080000, 
1540080000, 1540080000, 1540080000, 1539475200, 1539475200, 1539475200, 
1539475200, 1539475200, 1538870400, 1538870400, 1538870400, 1538870400, 
1538870400), class = c("POSIXct", "POSIXt"), tzone = "UTC"), 
    partidos = c("PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX", "PPopular", "PSOE", "ahorapodemos", "CiudadanosCs", 
    "VOX"), resultados = c(16.7, 33.3, 14.5, 15.3, 5.9, 21, 27.3, 
    14.2, 16, 11.3, 21.75, 25.85, 14.4, 17.9, 10.9, 20.5, 25.4, 
    13.9, 17, 11.7, 21.3, 23.9, 13.5, 20.9, 11.2, 22.25, 23.65, 
    14.85, 19.15, 10.05, 21.5, 23.2, 14.4, 23, 8.9, 19.2, 23.75, 
    16.7, 18, 8.4, 18.3, 24.1, 16.1, 18.5, 11.5, 20.6, 22.6, 
    15.5, 19.65, 10.75, 21.8, 23.5, 15.2, 22.7, 7.8, 21.4, 24.15, 
    16.15, 20.1, 8.6, 22.8, 24.4, 17.2, 19.8, 5.9, 19.7, 23.2, 
    17.65, 18.2, 10.7, 23.35, 26.4, 17.2, 20.15, 1.8, 22.3, 26.6, 
    16.6, 21.9, 3.4, 22.65, 24.95, 17.15, 21.55, 2.55, 22.6, 
    25.2, 17.7, 19.2, 5.1, 26.7, 26.8, 16.8, 19.5, 1.9, 23, 26.2, 
    18, 20.7, 0)), class = c("grouped_df", "tbl_df", "tbl", "data.frame"
), row.names = c(NA, -100L), vars = "week", indices = list(95:99, 
    90:94, 85:89, 80:84, 75:79, 70:74, 65:69, 60:64, 55:59, 50:54, 
    45:49, 40:44, 35:39, 30:34, 25:29, 20:24, 15:19, 10:14, 5:9, 
    0:4), drop = TRUE, group_sizes = c(5L, 5L, 5L, 5L, 5L, 5L, 
5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 5L), biggest_group_size = 5L, labels = structure(list(
    week = structure(c(1538870400, 1539475200, 1540080000, 1540684800, 
    1541289600, 1541894400, 1543708800, 1544313600, 1544918400, 
    1545523200, 1546128000, 1546732800, 1547337600, 1547942400, 
    1548547200, 1549152000, 1549756800, 1550361600, 1550966400, 
    1551571200), class = c("POSIXct", "POSIXt"), tzone = "UTC")), class = "data.frame", row.names = c(NA, 
-20L), vars = "week", indices = list(315:319, 310:314, 305:309, 
    275:304, 270:274, 240:269, 230:239, 195:229, 155:194, 150:154, 
    140:149, 125:139, 95:124, 90:94, 70:89, 65:69, 50:64, 30:49, 
    5:29, 0:4), drop = TRUE, group_sizes = c(5L, 5L, 5L, 30L, 
5L, 30L, 10L, 35L, 40L, 5L, 10L, 15L, 30L, 5L, 20L, 5L, 15L, 
20L, 25L, 5L), biggest_group_size = 40L, labels = structure(list(
    week = structure(c(1538870400, 1539475200, 1540080000, 1540684800, 
    1541289600, 1541894400, 1543708800, 1544313600, 1544918400, 
    1545523200, 1546128000, 1546732800, 1547337600, 1547942400, 
    1548547200, 1549152000, 1549756800, 1550361600, 1550966400, 
    1551571200), tzone = "UTC", class = c("POSIXct", "POSIXt"
    ))), class = "data.frame", row.names = c(NA, -20L), vars = "week", indices = list(
    c(63L, 127L, 191L, 255L, 319L), c(62L, 126L, 190L, 254L, 
    318L), c(61L, 125L, 189L, 253L, 317L), c(55L, 56L, 57L, 58L, 
    59L, 60L, 119L, 120L, 121L, 122L, 123L, 124L, 183L, 184L, 
    185L, 186L, 187L, 188L, 247L, 248L, 249L, 250L, 251L, 252L, 
    311L, 312L, 313L, 314L, 315L, 316L), c(54L, 118L, 182L, 246L, 
    310L), c(48L, 49L, 50L, 51L, 52L, 53L, 112L, 113L, 114L, 
    115L, 116L, 117L, 176L, 177L, 178L, 179L, 180L, 181L, 240L, 
    241L, 242L, 243L, 244L, 245L, 304L, 305L, 306L, 307L, 308L, 
    309L), c(46L, 47L, 110L, 111L, 174L, 175L, 238L, 239L, 302L, 
    303L), c(39L, 40L, 41L, 42L, 43L, 44L, 45L, 103L, 104L, 105L, 
    106L, 107L, 108L, 109L, 167L, 168L, 169L, 170L, 171L, 172L, 
    173L, 231L, 232L, 233L, 234L, 235L, 236L, 237L, 295L, 296L, 
    297L, 298L, 299L, 300L, 301L), c(31L, 32L, 33L, 34L, 35L, 
    36L, 37L, 38L, 95L, 96L, 97L, 98L, 99L, 100L, 101L, 102L, 
    159L, 160L, 161L, 162L, 163L, 164L, 165L, 166L, 223L, 224L, 
    225L, 226L, 227L, 228L, 229L, 230L, 287L, 288L, 289L, 290L, 
    291L, 292L, 293L, 294L), c(30L, 94L, 158L, 222L, 286L), c(28L, 
    29L, 92L, 93L, 156L, 157L, 220L, 221L, 284L, 285L), c(25L, 
    26L, 27L, 89L, 90L, 91L, 153L, 154L, 155L, 217L, 218L, 219L, 
    281L, 282L, 283L), c(19L, 20L, 21L, 22L, 23L, 24L, 83L, 84L, 
    85L, 86L, 87L, 88L, 147L, 148L, 149L, 150L, 151L, 152L, 211L, 
    212L, 213L, 214L, 215L, 216L, 275L, 276L, 277L, 278L, 279L, 
    280L), c(18L, 82L, 146L, 210L, 274L), c(14L, 15L, 16L, 17L, 
    78L, 79L, 80L, 81L, 142L, 143L, 144L, 145L, 206L, 207L, 208L, 
    209L, 270L, 271L, 272L, 273L), c(13L, 77L, 141L, 205L, 269L
    ), c(10L, 11L, 12L, 74L, 75L, 76L, 138L, 139L, 140L, 202L, 
    203L, 204L, 266L, 267L, 268L), c(6L, 7L, 8L, 9L, 70L, 71L, 
    72L, 73L, 134L, 135L, 136L, 137L, 198L, 199L, 200L, 201L, 
    262L, 263L, 264L, 265L), c(1L, 2L, 3L, 4L, 5L, 65L, 66L, 
    67L, 68L, 69L, 129L, 130L, 131L, 132L, 133L, 193L, 194L, 
    195L, 196L, 197L, 257L, 258L, 259L, 260L, 261L), c(0L, 64L, 
    128L, 192L, 256L)), drop = TRUE, group_sizes = c(5L, 5L, 
5L, 30L, 5L, 30L, 10L, 35L, 40L, 5L, 10L, 15L, 30L, 5L, 20L, 
5L, 15L, 20L, 25L, 5L), biggest_group_size = 40L)))

anim <- ggplot(polls_, aes(semana, resultados, group = partidos)) + 
  geom_line() + 
  geom_segment(aes(xend = as.POSIXct("2019-03-08 00:00:00", tz="UTC"), yend = resultados), 
               linetype = 2, colour = 'grey') + 
  geom_point(size = 2) + 
  geom_text(aes(x = as.POSIXct("2019-03-15 00:00:00", tz="UTC"), label = partidos),
            hjust = 0) + 
  transition_reveal(semana) + 
  coord_cartesian(clip = 'off') + 
  labs(title = 'Opinion polling for the 2019 Spanish general election', 
       y = 'Estimated results', x = 'week') + 
  theme_minimal() + 
  theme(plot.margin = margin(5.5, 40, 5.5, 5.5))

animate(anim, width = 900, height = 600, fps = 10, rewind = FALSE, duration = 15)

Here I include the animation:

animation


Solution

  • Here are two steps to address your two problems:

    1. Sort your data frame before passing it to ggplot():
    polls_ <- arrange(polls_, week)
    
    1. Include end_pause = <some positive integer> in animate(anim, ...).

    Note: the column name in your sample data frame is week, while your code used semana. I'm going with the former here.

    Explanation:

    Your data frame is arranged with the latest week values on top, and the earliest below. This does not work well with the default parameters for transition_reveal.

    From ?transition_reveal:

    transition_reveal(along, range = NULL, keep_last = TRUE, id)
    

    where keep_last is a TRUE / FALSE value for whether the last row of the data should be kept for subsequent frames.

    When the earliest week rows are in this position, they are scheduled to appear first due to their week values, & are kept visible till the end due to keep_last = TRUE.

    When we sort rows by week, on the other hand, the latest week values get sorted to the bottom rows instead. Now keep_last = TRUE work in our favour, because we want these values to be kept for all subsequent frames--most importantly, the last frame, which is where end_pause becomes useful.

    Demonstration:

    library(dplyr)
    
    anim <- polls_ %>% 
      arrange(week) %>% 
      ggplot(aes(week, resultados, group = partidos)) + 
      geom_line() + 
      geom_segment(aes(xend = as.POSIXct("2019-03-08 00:00:00", tz="UTC"), yend = resultados), 
                   linetype = 2, colour = 'grey') + 
      geom_point(size = 2) + 
      geom_text(aes(x = as.POSIXct("2019-03-15 00:00:00", tz="UTC"), label = partidos),
                hjust = 0) + 
      transition_reveal(week) + 
      coord_cartesian(clip = 'off') + 
      labs(title = 'Opinion polling for the 2019 Spanish general election', 
           y = 'Estimated results', x = 'week') + 
      theme_minimal() + 
      theme(plot.margin = margin(5.5, 40, 5.5, 5.5))
    
    animate(anim, width = 900, height = 600, 
            end_pause = 10,
            fps = 10, rewind = FALSE, duration = 15)
    

    result