-
Notifications
You must be signed in to change notification settings - Fork 310
Object permanence: Which data points describe the same object?
submitted by Felix Golcher
This little collection is supposed to explore the rules determining which data points are seen by gganimate
as representing the same object across the animation and which are not. The code is very basic. It was not made for fancy looks but in order to understand the working of gganimate. It's what I had to understand, maybe it helps others to understand faster.
library(tidyverse)
library(gganimate)
We start with the animation of two states a
and b
, a
consisting of one point, b
consisting of two.
myps <- 10
dta <- data.frame(y = c(1, 1.3, 0.7),
x = c(1, 2, 2),
tstep = c("a", "b", "b"))
(gg1 <- ggplot(dta,
aes(x,y))+geom_point(size=myps)+
theme_void()+
coord_equal()+
labs(title="state: {closest_state}")+
transition_states(states=tstep,
transition_length = 1,
state_length = 1)+
ease_aes('linear')+
enter_fade()+
exit_fade())
Two of the points are identified as belonging to the same object: the point on the left (state a
) morphs into the upper point of state b
.
but why this one? What determines, what points are identified?
Distance doesn't play a role as the next animation shows:
dtb <- dta
dtb$x[3] <- 1.1
dtb$y[3] <- 1
gg1 %+% dtb
Though the lower point of state b
is now much closer to the point of state a
, the state a point still morphs into the upper point of state b
.
There is only one option left: We conclude it should be determined by the ordering of points:
gg1 %+% dta[c(1,3,2),]
If we introduce color, we see another detail: Only points of the exact same quality are identified: If the two states have different colours, no points are identified, no morphing occurs.
(gg2 <- ggplot(dta,
aes(x,y,col=tstep))+
geom_point(size=myps,show.legend = F)+
theme_void()+
coord_equal()+
transition_states(states=tstep,
transition_length = 1,
state_length = 1)+
labs(title="state: {closest_state}")+
ease_aes('linear')+
enter_fade()+
exit_fade())
If we color more sensibly across states, only points with the same color are identified:
dta$id <- c("A","B","A")
(gg3 <- ggplot(dta,
aes(x,y,col=id))+
geom_point(size=myps,show.legend = F)+
theme_void()+
coord_equal()+
labs(title="state: {closest_state}")+
transition_states(states=tstep,
transition_length = 1,
state_length = 1)+
ease_aes('linear')+
enter_fade()+
exit_fade())
If we add new points, ordering is again used for identifying points as describing the same object:
dtd <- rbind(dta, data.frame(x=1.5,y=1,tstep="b",id="A"))
gg3 %+% dtd
If you want to avoid identification of object across states without using color, the states can be assigned to different groups:
ggplot(dta,
aes(x,y,group=tstep))+geom_point(size=myps)+
theme_void()+
coord_equal()+
transition_states(states=tstep,
transition_length = 1,
state_length = 1)+
ease_aes('linear')+
enter_fade()+
exit_fade()
In summary: data points which match in all aesthetics, including group, describe the same object. If ambiguities remain, the ordering of the data is used for matching up objects.
Our last animation in this series repeats the first. But now we add a fourth data point, which is now connected with the orphaned data point. There are two objects on the move:
dtg <- rbind(dta, data.frame(x=1,y=1.1,tstep="a",id=NA))
gg1 %+% dtg
If you want to identify data points across different qualities, you can explicitly identify them by using transition_components
.
dtc <- data.frame(x = c(1, 2, 2, 1),
y = c(1.4, 1, 1.4, 1),
id = c("a", "a", "b", "b"),
time = c(1, 2, 2.1, 3.1),
element = paste0("e",1:4))
(gg4 <- ggplot(dtc, aes(x,y,label=element,col=element, group = id)) +
geom_point(size=20, show.legend = F) +
geom_text(size=10, show.legend = F, col="black") +
theme_void()+
coord_equal()+
labs(title="Time {round(frame_time,2)}")+
transition_components(time=time,
enter_length = .2,
exit_length = .2,
range=c(0,6))+
enter_fade())
If there are more elements with a specific ID at some time than at others, the old rules apply and ordering comes into play again: The Element e5
, added at the end of the data frame, appears from nowhere.
dte <- rbind(dtc, data.frame(x=2,y=1.2,id="a",time=2.0,element="e5"))
gg4 %+% dte
If we pull it to the top of the data frame, e1
now morphs into the new element and e2
, now further down in the data, appears only later:
gg4 %+% dte[c(5,1:4),]
There are transitions which do not seem to allow movement of objects at all, as the following examples show.
homo <- data.frame(from=c(-2.3e5, -2e5, -7e5, -3e5),
to=c(-3e4, 0, -3e5, -2e5),
spec=c("Neanderthalensis","Sapiens","Heidelbergensis","(archaic) Sapiens"),
x=c(1,1,1,1),
y=c(1,2,2,2))
ggplot(homo, aes(x,y,label=spec))+
geom_text(size=10)+
theme_void()+
coord_equal()+
xlim(c(-2,4))+
ylim(c(.5,2.5))+
transition_events(start=from,
end=to,
exit_length = 1e4)+
labs(title="{-round(frame_time/1000)*1000} BCE")+
exit_fade()+
ease_aes('linear')
dtf <- data.frame(x=rnorm(100),
y=rnorm(100))
ggplot(dtf, aes(x,y))+
geom_point()+
transition_filter(transition_length = 1,
filter_length = 1,
x>y,x<y,x>-y,x< -y)
Install gganimate using devtools::install_github('thomasp85/gganimate')
The Grammar
Misc
Examples