## Animated paths in R: toy example

Recently I have shared examples of animations made using **R** which feature traversal of pathways, specifically grid cell borders and great circle arcs. Here I provide the basic code required to generate a path sequence from a path.

The fundamental ideas are as follows:

- Pathways are represented by lines.
- Lines are represented by a series of points.
- You already have your path defined in an
**R**object, stored as a typical two-column matrix of`x`

and`y`

coordinates, e.g., longitude and latitude. - The goal is to break the line into a sequence of line segments to be plotted in some iterative manner, so your matrix must have enough coordinate pairs to suit your needs.
- The sequence is of spatially overlapping line segments generally, whereas perfect end to end segments are a special case.
**Most importantly**, to a achieve a realistic appearance of travel between two end points, the sequence of segments should be defined such that a moving segment appears to*emerge from*and*disappear into*a point.

That last part about emergence and disappearance is what the code below achieves. Here is an example function which offers some nominal randomization to your path construction.

get_segs_list <- function(d, seg.size="uniform", seg.frac.max=1/3){ n <- nrow(d) if(n < 3) stop("Data not appropriate for this operation.") if(is.numeric(seg.size)){ stopifnot(seg.size >= 2) z <- round(runif(2, 2, seg.size)) z[z > n] <- n } else { if(n*seg.frac.max < 3) stop("seg.frac.max is too small.") if(seg.size=="uniform"){ z <- round(runif(2, 2, n*seg.frac.max)) } else if(seg.size=="normal") { mn <- mean(1:n) stddev <- mn/6 z <- round(rnorm(2, mn, stddev)) } } n1 <- ceiling(diff(c((z[1] - z[2]), n))/z[1]) f <- function(k, d, n, z){ ind2 <- z[1]*k ind1 <- max(ind2 - z[2], 1) if(ind2 > n) ind2 <- n ind <- ind1:ind2 d[ind,] } lapply(1:n1, f, d=d, n=n, z=z) }

Note that this will **NOT** magically allow you to make awesome visualizations. That can take a lot of work, which is highly nuanced and specific to the visualization desired, the computing environment you are coding within, and the constraints of the computing resources available to you. This is a toy example. However, it shows precisely the ways in which I have generated path sequences for my animations. How you use pathways generated for your own data is up to you. This approach may or may not scale well to your specific needs, depending on the complexity of your task, computing resources required, organization of your data, etc.

The function above returns a list object where the *i*th element in the list is a matrix object representing the subset of the original matrix which defines the *i*th segment along the path. Using the code below, note the way in which emergence and disappearance at the endpoints manifest in the output list and in the plot below. In the example, I have a two-column matrix describing a straight line with `x`

varying and `y`

constant because the result remains easy to visualize in a static plot. I ran it six times with varying segment sizes.

n <- 50 m <- cbind(1:n, 1) set.seed(1) win.graph(12,8) layout(matrix(1:6, nrow=2)) for(i in 1:6){ l <- get_segs_list(m) plot(0, 0, type="n", xlab="", ylab="", xlim=c(1,n), ylim=c(1, length(l))) lapply(1:length(l), function(i, x) lines(x[[i]][,1], rep(i, nrow(x[[i]]))), x=l) }

The bottom line is that this is simply an exercise in breaking a line into line segments, but with some nominal enhancements, namely, random variation and endpoint/boundary behavior. It is also helpful to think of combinations of segment length, number of segments, and degree of segment overlap (these are not independent) as crude ways to control the “speed” of path traversal or the amount of data generated. For example, more overlap and more segments, with segment length held constant, means more iterations required to traverse a path.