Producing an animated comet plot in R
How about this with animation
# required librariesrequire(animation) # NB you must install ImageMagickrequire(ggplot2)require(grid) # for arrow()# create a path with variable speed (1 point per time unit)path<-data.frame(time=1:100,x=1:100,y=c((1:50)^2,(50:1)^2))# plot it, just to seeggplot(path)+geom_point(aes(x,y))
# work out the path and previous points of each observation# average of previous 2 steps, but could be any numbersteps<-2path$prevx<-c(rep(0,steps),path$x[1:(nrow(path)-steps)])path$prevy<-c(rep(0,steps),path$y[1:(nrow(path)-steps)])path$prevtime<-c(rep(0,steps),path$time[1:(nrow(path)-steps)])# then calculate the velocity at each point, and the angle (for the arrow)# note we could just plot point to point, but that assumes the time units are regularpath$v<-((((path$x-path$prevx)^2)+((path$y-path$prevy)^2))^0.5)/(path$time-path$prevtime)path$atan2<-atan2((path$x-path$prevx),(path$y-path$prevy))# OK, we now have all the data; let's plot first without animationggplot(path)+geom_segment(aes(x = x-(v*sin(atan2)), y = y-(v*cos(atan2)), xend = x, yend = y), arrow=arrow(length = unit(0.5, "cm")) , alpha=0.5, size=2, color="blue")
# create function which takes a vector of rows (to plot a subset of arrows)plot_arrow<-function(vec){ alphas<-rev(1/(1:length(vec))^1.5) # this create an alpha scale g<-ggplot(path[vec,])+geom_segment(aes(x = x-(v*sin(atan2)), y = y-(v*cos(atan2)), xend = x, yend = y), arrow=arrow(length = unit(0.5, "cm")) , # create arrow alpha=alphas, size=2, color="blue")+ coord_cartesian(xlim=c(min(path$x),max(path$x)),ylim=c(min(path$y),max(path$y))) # fix width print(g)}# then create the animated GIF with 5 arrows per framesaveGIF({ lapply(1:nrow(path),function(x)plot_arrow(max(1,x-5):x))},movie.name="comet.gif",interval=0.2)
PS: you can also remove the trailing arrowheads, by changing the plot_arrow()
function call as follows [the arrow()
call in 'geom_segment']:
arrow=arrow(length = unit(c(rep(0,length(vec)-1),0.5), "cm"))
You can play with the excellent animation
package.
Maybe you should change the points
call to segments ( or call them together) , but this should be a good start.
library(animation)saveGIF({ ani.options(interval = 0.2, nmax = 10) t = seq(0,2*pi,.01) x = cos(2*t)*(cos(t)^2) y = sin(2*t)*(sin(t)^2) idx = seq(1,length(x),10) for (i in seq_along(idx)) { plot(x,y,type='n') points(x[seq(idx[i])],y[seq(idx[i])],pch=20,col='red') ani.pause() ## pause for a while ('interval') }}, interval = 0.05, movie.name = "comet_demo.gif", outdir = "/usr/temp",ani.width = 600, ani.height = 600)