'geom_errorbar transitions strangely with gganimate
I am trying to animate a scatterplot with bars representing standard deviation. My data are measurements taken over the course of several days. Using gganimate, I'm 99% of the way there, but the way the error bars are transitioning is not how I want.
You can see that while the SD bars for the egg measurements transition smoothly, fading in and out, the SD bars for the larval measurements pop in and out of existence abruptly at both the beginning and end.
My data and code are below:
library(plyr)
library(tidyverse)
library(broom)
library(cowplot)
library(scales)
library(ggpubr)
library(rlang)
library(gganimate)
library(ggrepel)
library(MetBrewer)
library(gifski)
# Data:
longitudinalMeasurements <- data.frame(
stringsAsFactors = FALSE,
specimen = c("chunk1_L1","chunk1_L1",
"chunk1_E1","chunk1_E1","chunk1_E2","chunk1_E2",
"chunk1_E3","chunk1_E3","chunk2_E1","chunk2_E1","chunk2_E2",
"chunk2_E2","chunk2_E3","chunk2_E3","chunk2_E4",
"chunk2_E4","chunk2_E5","chunk2_E5","chunk2_E6","chunk2_E6",
"chunk3_L1","chunk3_L1","chunk3_E1","chunk3_E1",
"chunk3_E2","chunk3_E2","chunk3_E3","chunk3_E3",
"chunk3_E4","chunk3_E4","chunk3_E5","chunk3_E5","chunk3_E6",
"chunk3_E6","chunk4_L1","chunk4_L1","chunk4_L2",
"chunk4_L2","chunk4_E1","chunk4_E1","chunk4_E2","chunk4_E2",
"chunk4_E3","chunk4_E3","chunk4_E4","chunk4_E4",
"chunk4_E5","chunk4_E5","chunk4_E6","chunk4_E6",
"chunk4_E7","chunk4_E7","chunk4_E8","chunk4_E8","chunk4_E9",
"chunk4_E9","chunk4_E10","chunk4_E10",
"CSC02FK01H9M9C9_L1","CSC02FK01H9M9C9_L1","330_eggs_chunk1_L1",
"330_eggs_chunk1_L1","330_eggs_chunk1_L2","330_eggs_chunk1_L2",
"330_eggs_chunk1_E3","330_eggs_chunk1_E3",
"330_eggs_chunk1_E4","330_eggs_chunk1_E4","330_eggs_chunk1_E5",
"330_eggs_chunk1_E5","330_eggs_chunk1_E6",
"330_eggs_chunk1_E6","330_eggs_chunk1_E7","330_eggs_chunk1_E7",
"330_eggs_chunk1_E8","330_eggs_chunk1_E8",
"330_eggs_chunk1_E9","330_eggs_chunk1_E9","330_eggs_chunk1_E10",
"330_eggs_chunk1_E10","330_eggs_chunk3_L1","330_eggs_chunk3_L1",
"330_eggs_chunk3_E1","330_eggs_chunk3_E1",
"330_eggs_chunk3_E2","330_eggs_chunk3_E2","330_eggs_chunk3_E3",
"330_eggs_chunk3_E3","330_eggs_chunk3_E4",
"330_eggs_chunk3_E4","330_eggs_chunk3_E5","330_eggs_chunk3_E5",
"330_eggs_chunk3_E6","330_eggs_chunk3_E6","330_eggs_chunk3_E7",
"330_eggs_chunk3_E7","330_eggs_chunk3_E8",
"330_eggs_chunk3_E8","330_eggs_chunk3_E9","330_eggs_chunk3_E9",
"330_eggs_chunk3_E10","330_eggs_chunk3_E10",
"330_eggs_chunk2_E1","330_eggs_chunk2_E1","330_eggs_chunk2_E2",
"330_eggs_chunk2_E2","330_eggs_chunk2_E3",
"330_eggs_chunk2_E3","330_eggs_chunk2_E4","330_eggs_chunk2_E4",
"330_eggs_chunk2_E5","330_eggs_chunk2_E5"),
measurement = c("body","head","body","head",
"body","head","body","head","body","head","body",
"head","body","head","body","head","body","head",
"body","head","body","head","body","head","body",
"head","body","head","body","head","body","head",
"body","head","body","head","body","head","body",
"head","body","head","body","head","body","head",
"body","head","body","head","body","head","body","head",
"body","head","body","head","body","head","body",
"head","body","head","body","head","body","head",
"body","head","body","head","body","head","body",
"head","body","head","body","head","body","head",
"body","head","body","head","body","head","body",
"head","body","head","body","head","body","head",
"body","head","body","head","body","head","body",
"head","body","head","body","head","body","head","body",
"head"),
Length = c(1.01,0.304,0.97,0.308,0.99,
0.299,0.94,0.342,0.832,0.291,0.949,0.27,0.914,
0.338,0.875,0.353,0.855,0.319,0.824,0.347,0.987,
0.159,0.92,0.283,0.923,0.327,0.92,0.272,0.825,0.286,
0.918,0.31,0.989,0.303,0.958,0.234,0.773,0.296,
1.003,0.299,0.891,0.334,0.963,0.322,0.83,0.29,
0.998,0.312,0.935,0.349,0.807,0.232,0.883,0.274,0.9,
0.336,0.955,0.314,1.065,0.161,1.098,0.292,1.104,
0.285,0.832,0.368,0.91,0.332,1.005,0.315,0.837,
0.364,0.912,0.257,0.889,0.366,0.891,0.332,0.968,
0.299,0.847,0.277,1.009,0.325,0.922,0.356,0.893,0.328,
0.947,0.336,0.877,0.379,0.932,0.304,0.936,0.319,
0.868,0.374,0.943,0.336,0.988,0.317,0.891,0.33,
0.899,0.305,0.882,0.328,0.963,0.295,0.965,0.308),
observations = c("larva","larva","egg","egg",
"egg","egg","egg","egg","egg","egg","egg","egg",
"egg","egg","egg","egg","egg","egg","egg","egg",
"larva","larva","egg","egg","egg","egg","egg","egg",
"egg","egg","egg","egg","egg","egg","larva",
"larva","larva","larva","egg","egg","egg","egg","egg",
"egg","egg","egg","egg","egg","egg","egg","egg",
"egg","egg","egg","egg","egg","egg","egg","larva",
"larva","larva","larva","larva","larva","egg",
"egg","egg","egg","egg","egg","egg","egg","egg","egg",
"egg","egg","egg","egg","egg","egg","larva",
"larva","egg","egg","egg","egg","egg","egg","egg",
"egg","egg","egg","egg","egg","egg","egg","egg",
"egg","egg","egg","egg","egg","egg","egg","egg","egg",
"egg","egg","egg","egg","egg","egg"),
date = c("3/29/22","3/29/22","3/29/22",
"3/29/22","3/29/22","3/29/22","3/29/22","3/29/22",
"3/29/22","3/29/22","3/29/22","3/29/22","3/29/22",
"3/29/22","3/29/22","3/29/22","3/29/22","3/29/22",
"3/29/22","3/29/22","3/29/22","3/29/22","3/29/22",
"3/29/22","3/29/22","3/29/22","3/29/22","3/29/22",
"3/29/22","3/29/22","3/29/22","3/29/22","3/29/22","3/29/22",
"3/29/22","3/29/22","3/29/22","3/29/22","3/29/22",
"3/29/22","3/29/22","3/29/22","3/29/22","3/29/22",
"3/29/22","3/29/22","3/29/22","3/29/22","3/29/22",
"3/29/22","3/29/22","3/29/22","3/29/22","3/29/22",
"3/29/22","3/29/22","3/29/22","3/29/22","3/28/22","3/28/22",
"3/30/22","3/30/22","3/30/22","3/30/22","3/30/22",
"3/30/22","3/30/22","3/30/22","3/30/22","3/30/22",
"3/30/22","3/30/22","3/30/22","3/30/22","3/30/22",
"3/30/22","3/30/22","3/30/22","3/30/22","3/30/22",
"3/30/22","3/30/22","3/30/22","3/30/22","3/30/22",
"3/30/22","3/30/22","3/30/22","3/30/22","3/30/22","3/30/22",
"3/30/22","3/30/22","3/30/22","3/30/22","3/30/22",
"3/30/22","3/30/22","3/30/22","3/30/22","3/30/22",
"3/30/22","3/30/22","3/30/22","3/30/22","3/30/22",
"3/30/22","3/30/22","3/30/22","3/30/22","3/30/22",
"3/30/22")
)
# Pivoting to wider format:
longitudinalMeasurementsWider <- select(longitudinalMeasurements,
c(measurement, Length, specimen, observations, date)) %>%
pivot_wider(names_from = c(measurement),
values_from = c(Length))
longitudinalMeasurementsWider$date <- as.Date(longitudinalMeasurementsWider$date,
format = "%m/%d/%y")
# Getting SDs:
longitudinalSD <- plyr::ddply(longitudinalMeasurementsWider,
.(observations, date),
summarise,
bodySD = sd(body),
headSD = sd(head),
bodyMean = mean(body),
headMean = mean(head))
# Plotting:
longitudinalPlot <- ggplot(data = longitudinalMeasurementsWider) +
geom_point(mapping = aes(x = body,
y = head,
colour = observations,
group = date),
size = 3) +
geom_errorbarh(data = longitudinalSD,
aes(xmin = bodyMean - bodySD,
xmax = bodyMean + bodySD,
y = headMean,
colour = observations,
height = 0.01)) +
geom_errorbar(data = longitudinalSD,
aes(ymin = headMean - headSD,
ymax = headMean + headSD,
x = bodyMean,
colour = observations)) +
scale_color_manual(values=met.brewer("Redon", 7)) +
coord_trans(x="log10",
y="log10") +
ggtitle("Head width to body length") +
xlab("Body length (log10, mm)") +
ylab("Head width (log10, mm)") +
transition_states(date,
transition_length = 1,
state_length = 1,
wrap = TRUE) +
enter_fade() +
exit_shrink() +
ease_aes('sine-in-out')
longitudinalPlot
I'm particularly stumped by the fact that one set of SD bars behaves, while the other does not. Any help is hugely appreciated!
Solution 1:[1]
I figured out the reason for the behavior- it is because in my first time point for the larvae, I have only one observation, and so no calculated standard deviations. A hacky solution is to replace those NA values in longitudinalSD with 0, like so:
longitudinalSD[is.na(longitudinalSD)] <- 0
I'd be interested if anyone has a more elegant solution, however!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | meganbarkdull |

