Before I decided to learn R in a serious way, I thought about learning Flash/Actionscript instead. Most of my work involves evolutionary models that take place over time. I need visual representations of change. It’s certainly possible to represent change and tell an evolving story with a single plot (see for example Tufte’s favorite infographic), but there are a lot more options when you can use animations. Flash is also object oriented, well documented with hundreds of books and websites, and has a powerful (albeit challenging to learn) IDE which helps for large coding projects.
The drawbacks to Flash are that it is way behind R in terms of statistical tools, is a closed, expensive language to work with, and dispute widespread use it might be so weak that a Apple’s iPhone might kill it.
So I picked R, with the idea that when I needed animations, I would find a way to build them. The code below is my first test of using R to generate animations. It’s a variant of Conway’s Game of Life (not to be confused with the Milton Bradley version), where single celled lifeforms live or die based on how many living neighbors they have. In my version, the rules for each cell are determined randomly, in advance of the game. The board size is fixed (see the configuration options at the beginning), whereas Conway’s version was played on a theoretically infinite grid. Green cells are “alive”, black ones are “dead”. I tried for nearly an hour to match the Black=living, White=dead scheme of Conway but couldn’t get that to work, maybe you can figure out how to do it. I re-sized the resulting animated GIF with an external program, that’s another thing I still need to figure out in R.
par(mar=c(0,0,0,0))
library(abind)
library(gdata)
library(fields)
library(grDevices)
library(caTools)
#
times = 50
myWidth = 10
myHeight = 10
#
# Set the 3D array of rules to determine transitions for each cell.
rulesArray = NULL
for(i in 1:9) {
toBind <- matrix(sample(c(0,1),replace=T,(myWidth*myHeight)),ncol=myWidth)
rulesArray <- abind(rulesArray, toBind, along=3)
}
#
first = T
frames = array(0, c(myWidth, myHeight, times))
for(i in 1:times) {
if(first) {
forFrame <- sample(c(0,1),replace=T,(myWidth*myHeight))
first = F
} else {
# Convert last frame data to matrix to make comparing adjacent cells easier
forFrame <- matrix(forFrame, ncol=myWidth)
newFrame <- forFrame
#
for(m in 1:myHeight) {
for(n in 1:myWidth) {
adjLiving = 1 # cuz we start with array index 1
#
# Find out how many adjacent are living
if(m > 1 && n > 1) {
# Look at top left
adjLiving = adjLiving + forFrame[(m-1),(n-1)]
}
if(m > 1) {
# Look at top center
adjLiving = adjLiving + forFrame[(m-1),(n)]
}
if(m > 1 && n < myWidth) {
# Look at top right
adjLiving = adjLiving + forFrame[(m-1),(n+1)]
}
if(n > 1) {
# Look at left
adjLiving = adjLiving + forFrame[(m),(n-1)]
}
if(n < myWidth) {
# Look at right
adjLiving = adjLiving + forFrame[(m),(n+1)]
}
if(m < myHeight && n > 1) {
# Look at bottom left
adjLiving = adjLiving + forFrame[(m+1),(n-1)]
}
if(m < myHeight) {
# Look at bottom center
adjLiving = adjLiving + forFrame[(m+1),(n)]
}
if(m < myHeight && n < myWidth) {
# Look at bottom right
adjLiving = adjLiving + forFrame[(m+1),(n+1)]
}
#
# Find the corresponding rule for this cell
newStatus = rulesArray[m,n,adjLiving]
#
# Update the status of this cell depending on the rule and number of living adjacent
newFrame[m,n] = newStatus
}
}
#
# Pull it out of a matrix
forFrame = unmatrix(newFrame)
}
frames[,,i] <- forFrame
}
write.gif(frames, "gameOfLifeRevisited.gif", col=c("#FFFF00", "#000000") , delay=150)