Skip to content

Commit fc238a9

Browse files
authored
Add files via upload
1 parent ffd46dc commit fc238a9

36 files changed

+9815
-0
lines changed

scripts/02_garden_animation.r

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
# animate garden of forking data
2+
3+
library(rethinking)
4+
library(animation)
5+
6+
#######
7+
# library functions
8+
9+
10+
polar2screen <- function( dist, origin, theta ) {
11+
## takes dist, angle and origin and returns x and y of destination point
12+
vx <- cos(theta) * dist;
13+
vy <- sin(theta) * dist;
14+
c( origin[1]+vx , origin[2]+vy );
15+
}
16+
17+
screen2polar <- function( origin, dest ) {
18+
## takes two points and returns distance and angle, from origin to dest
19+
vx <- dest[1] - origin[1];
20+
vy <- dest[2] - origin[2];
21+
dist <- sqrt( vx*vx + vy*vy );
22+
theta <- asin( abs(vy) / dist );
23+
## correct for quadrant
24+
if( vx < 0 && vy < 0 ) theta <- pi + theta; # lower-left
25+
if( vx < 0 && vy > 0 ) theta <- pi - theta; # upper-left
26+
if( vx > 0 && vy < 0 ) theta <- 2*pi - theta; # lower-right
27+
if( vx < 0 && vy==0 ) theta <- pi;
28+
if( vx==0 && vy < 0 ) theta <- 3*pi/2;
29+
## return angle and dist
30+
c( theta, dist );
31+
}
32+
33+
point.polar <- function(dist,theta,origin=c(0,0),draw=TRUE,...) {
34+
# angle theta is in radians
35+
pt <- polar2screen(dist,origin,theta)
36+
if ( draw==TRUE ) points( pt[1] , pt[2] , ... )
37+
invisible( pt )
38+
}
39+
40+
line.polar <- function(dist,theta,origin=c(0,0),...) {
41+
# dist should be vector of length 2 with start and end points
42+
# theta is angle
43+
pt1 <- polar2screen(dist[1],origin,theta)
44+
pt2 <- polar2screen(dist[2],origin,theta)
45+
lines( c(pt1[1],pt2[1]), c(pt1[2],pt2[2]) , ... )
46+
}
47+
48+
line.short <- function(x,y,short=0.1,...) {
49+
# shortens the line segment, but retains angle and placement
50+
pt1 <- c(x[1],y[1])
51+
pt2 <- c(x[2],y[2])
52+
theta <- screen2polar( pt1 , pt2 )[1]
53+
dist <- screen2polar( pt1 , pt2 )[2]
54+
q1 <- polar2screen( short , pt1 , theta )
55+
q2 <- polar2screen( dist-short , pt1 , theta )
56+
lines( c(q1[1],q2[1]) , c(q1[2],q2[2]) , ... )
57+
}
58+
59+
wedge <- function(dist,start,end,pt,hedge=0.1,alpha,lwd=2,draw=TRUE,hit,...) {
60+
# start: start angle of wedge
61+
# end: end angle of wedge
62+
# pt: vector of point bg colors
63+
n <- length(pt)
64+
points.save <- matrix(NA,nrow=n,ncol=2) # x,y columns
65+
span <- abs(end-start)
66+
span2 <- span*(1 - 2*hedge)
67+
origin <- start + span*hedge
68+
gap <- span2/n
69+
theta <- origin + gap/2
70+
border <- rep("black",length(pt))
71+
if ( !missing(hit) ) border <- ifelse( hit==1 , 2 , 1 )
72+
if ( !missing(alpha) ) {
73+
pt <- sapply( 1:length(pt) , function(i) col.alpha(pt[i],alpha[i]) )
74+
border <- sapply( 1:length(pt) , function(i) col.alpha(border[i],alpha[i]) )
75+
}
76+
for ( i in 1:n ) {
77+
points.save[i,] <- point.polar( dist , theta , pch=21 , lwd=lwd , bg=pt[i] , col=border[i] , draw=draw, ... )
78+
theta <- theta + gap
79+
}
80+
points.save
81+
}
82+
83+
point_on_line <- function( x , y , p ) {
84+
X <- x[1]*(1-p) + x[2]*p
85+
Y <- y[1]*(1-p) + y[2]*p
86+
c(X,Y)
87+
}
88+
89+
######
90+
# garden draw with progression
91+
# the progression argument is a vector of how deep to draw each layer in garden
92+
93+
garden <- function( arc , possibilities , data , alpha.fade = 0.25 , col.open=2 , col.closed=1 , hedge=0.1 , hedge1=0 , newplot=TRUE , plot.origin=FALSE , cex=1.5 , lwd=2 , adj.cex , adj.lwd , lwd.dat=1 , ring_dist , progression , prog_dat , xlim=c(-1,1) , ylim=c(-1,1) , thresh=0.2 , ... ) {
94+
95+
poss.cols <- ifelse( possibilities==1 , rangi2 , "white" )
96+
97+
if ( missing(adj.cex) ) adj.cex=rep(1,length(data))
98+
if ( missing(adj.lwd) ) adj.lwd=rep(1,length(data))
99+
100+
if ( newplot==TRUE ) {
101+
# empty plot
102+
par(mgp = c(1.5, 0.5, 0), mar = c(1, 1, 1, 1) + 0.1, tck = -0.02)
103+
plot( NULL , xlim=xlim , ylim=ylim , bty="n" , xaxt="n" , yaxt="n" , xlab="" , ylab="" )
104+
}
105+
106+
if ( plot.origin==TRUE ) point.polar( 0 , 0 , pch=16 )
107+
108+
N <- length(data)
109+
n_poss <- length(possibilities)
110+
111+
# draw rings
112+
113+
# compute distance out for each ring
114+
# use golden ratio 1.618 for each successive ring
115+
goldrat <- 1.618
116+
if ( missing(ring_dist) ) {
117+
ring_dist <- rep(1,N)
118+
if ( N>1 )
119+
for ( i in 2:N ) ring_dist[i] <- ring_dist[i-1]*goldrat
120+
ring_dist <- ring_dist / sum(ring_dist)
121+
#ring_dist <- cumsum(ring_dist)
122+
}
123+
124+
if ( length(alpha.fade)==1 ) alpha.fade <- rep(alpha.fade,N)
125+
if ( length(col.open)==1 ) col.open <- rep(col.open,N)
126+
if ( length(col.closed)==1 ) col.closed <- rep(col.closed,N)
127+
128+
draw_wedge <- function(r,hit_prior,arc2,hedge=0.1,hedge1=0,lines_to) {
129+
130+
# is each path clear?
131+
hit <- hit_prior * ifelse( possibilities==data[r] , 1 , 0 )
132+
133+
# transparency for blocked paths
134+
alpha <- ifelse( hit==1 , 1 , alpha.fade[r] )
135+
the_col <- ifelse( hit==1 , col.open , col.closed )
136+
137+
# draw wedge
138+
hedge_use <- ifelse( r==1 , hedge1 , hedge )
139+
140+
do_draw <- TRUE
141+
if ( progression[r] < 1 ) do_draw <- FALSE
142+
143+
rd <- 0
144+
for ( rdi in 1:r ) rd <- rd + ring_dist[rdi]
145+
if ( prog_dat[r] == 1 )
146+
pts <- wedge( rd , arc2[1] , arc2[2] , poss.cols , hedge=hedge_use , alpha=alpha , cex=cex*adj.cex[r] , lwd=lwd*adj.lwd[r] , draw=do_draw , hit=hit )
147+
else
148+
pts <- wedge( rd , arc2[1] , arc2[2] , poss.cols , hedge=hedge_use , alpha=alpha , cex=cex*adj.cex[r] , lwd=lwd*adj.lwd[r] , draw=do_draw )
149+
150+
if ( N > r ) {
151+
# draw next layer
152+
span <- abs( arc2[1] - arc2[2] ) / n_poss
153+
for ( j in 1:n_poss ) {
154+
# for each possibility, draw the next wedge
155+
# recursion handles deeper wedges
156+
new_arc <- c( arc2[1]+span*(j-1) , arc2[1]+span*j )
157+
pts2 <- draw_wedge(r+1,hit[j],new_arc,hedge,lines_to=pts[j,])
158+
}#j
159+
}# N>r
160+
161+
# draw lines back to parent point
162+
if ( !missing(lines_to) ) {
163+
for ( k in 1:n_poss ) {
164+
#alpha_l <- ifelse( hit==1 , 1 , alpha.fade[r] )
165+
# path line
166+
167+
if ( progression[r] > thresh ) {
168+
ptend <- point_on_line( c(lines_to[1],pts[k,1]) , c(lines_to[2],pts[k,2]) , progression[r] )
169+
line.short( c(lines_to[1],ptend[1]) , c(lines_to[2],ptend[2]) , lwd=lwd*adj.lwd[r] , short=0.04 , col=col.closed[1] )
170+
}
171+
if ( prog_dat[r] > thresh && hit[k]==1 ) {
172+
ptend <- point_on_line( c(lines_to[1],pts[k,1]) , c(lines_to[2],pts[k,2]) , prog_dat[r] )
173+
line.short( c(lines_to[1],ptend[1]) , c(lines_to[2],ptend[2]) , lwd=lwd*adj.lwd[r]+lwd.dat , short=0.04 , col=col.open[1] )
174+
}
175+
}
176+
} # lines_to
177+
178+
return(pts)
179+
180+
}
181+
182+
pts1 <- draw_wedge(1,1,arc=arc,hedge=hedge,lines_to=c(0,0))
183+
184+
invisible(pts1)
185+
186+
}
187+
188+
189+
goldrat <- 1.618
190+
ring_dist <- rep(1,3)
191+
for ( i in 2:3 ) ring_dist[i] <- ring_dist[i-1]*goldrat
192+
ring_dist <- ring_dist / sum(ring_dist)
193+
#ring_dist <- cumsum(ring_dist)
194+
195+
dat <- c(1,0,1)
196+
dat <- c(-1,-1,-1)
197+
198+
arc <- c( 0 , pi )
199+
garden(
200+
arc = arc,
201+
possibilities = c(0,0,0,1),
202+
data = dat,
203+
hedge = 0.05,
204+
ring_dist=ring_dist,
205+
alpha.fade=1,
206+
progression=c(1,1,0.1)
207+
)
208+
209+
####
210+
# grow garden animation
211+
212+
ani.record(reset = TRUE)
213+
214+
poss <- c(0,1,1,1)
215+
nsteps <- 20
216+
prog_seq <- seq( from=0 , to=1 , length=nsteps )
217+
prog <- c(0,0,0)
218+
for ( rr in 1:3 ) {
219+
for ( p in prog_seq ) {
220+
prog[rr] <- p
221+
garden(
222+
arc = arc,
223+
possibilities = poss,
224+
data = c(1,0,0),
225+
hedge = 0.05,
226+
ring_dist=ring_dist,
227+
alpha.fade=1,
228+
progression=prog,
229+
prog_dat=c(0,0,0),
230+
ylim=c(0,1),
231+
thresh=0.3
232+
)
233+
ani.record()
234+
}
235+
}
236+
237+
oopts = ani.options(interval = 0.1)
238+
ani.replay()
239+
240+
# convert -alpha remove -background white -delay 10 -loop 0 frame*.png globe_tossing.gif
241+
# convert -delay 0 animated.gif animated2.gif
242+
243+
####
244+
# data path animation
245+
246+
#ani.record(reset = TRUE)
247+
prog_seq <- seq( from=0 , to=1 , length=nsteps )
248+
prog <- c(1,1,1)
249+
prog2 <- c(0,0,0)
250+
for ( rr in 1:3 ) {
251+
for ( p in prog_seq ) {
252+
prog2[rr] <- p
253+
garden(
254+
arc = arc,
255+
possibilities = poss,
256+
data = c(1,0,1),
257+
hedge = 0.05,
258+
ring_dist=ring_dist,
259+
alpha.fade=1,
260+
progression=prog,
261+
prog_dat=prog2,
262+
ylim=c(0,1),
263+
lwd.dat=2,
264+
thresh=0.3
265+
)
266+
ani.record()
267+
}
268+
}
269+
270+
oopts = ani.options(interval = 0.1)
271+
ani.replay()
272+
273+
# ani.saveqz(dpi=150)
274+
# convert -alpha remove -background white -delay 10 -loop 0 frame*.png garden.gif
275+

0 commit comments

Comments
 (0)