How to cumulate/preserve old frames using the Animation package? - r

The code below plots 10 dots on the x-axis, one at a time. At any one point in time, the animation displays only one dot. I am looking to end up with a plot with all 10 dots. I would like the second dot to be added to the plot showing the first dot; the third to be added to the plot showing the first two dots, etc. I looked at the documentation for saveGIF for a parameter that would somehow cumulate the frames, but could not find a relevant parameter there. It looks like it should be possible. Yihui Xie, the creator of the animation package, did exactly that in the top right plot of this example https://yihui.org/animation/example/buffon-needle/
library(animation)
saveGIF({
for (i in 1:10) {
x <- rnorm(1,0,1)
plot(x,0,xlim=c(0,1),ylim=c(-1,1))
}
})

You can generate the 10 numbers in advance, and plot them incrementally, e.g.,
library(animation)
saveGIF({
n <- 10
x <- rnorm(n, 0, 1)
for (i in seq_len(n)) {
plot(head(x, i), 0, xlim = c(1, n), ylim = c(-1, 1))
}
})

Related

In R, how can I tell if the scales on a ggplot object are log or linear?

I have many ggplot objects where I wish to print some text (varies from plot to plot) in the same relative position on each plot, regardless of scale. What I have come up with to make it simple is to
define a rescale function (call it sx) to take the relative position I want and return that position on the plot's x axis.
sx <- function(pct, range=xr){
position <- range[1] + pct*(range[2]-range[1])
}
make the plot without the text (call it plt)
Use the ggplot_build function to find the x scale's range
xr <- ggplot_build(plt)$layout$panel_params[[1]]$x.range
Then add the text to the plot
plt <- plt + annotate("text", x=sx(0.95), ....)
This works well for me, though I'm sure there are other solutions folks have derived. I like the solution because I only need to add one step (step 3) to each plot. And it's a simple modification to the annotate command (x goes to sx(x)).
If someone has a suggestion for a better method I'd like to hear about it. There is one thing about my solution though that gives me a little trouble and I'm asking for a little help:
My problem is that I need a separate function for log scales, (call it lx). It's a bit of a pain because every time I want to change the scale I need to modify the annotate commands (change sx to lx) and occasionally there are many. This could easily be solved in the sx function if there was a way to tell what the type of scale was. For instance, is there a parameter in ggplot_build objects that describe the log/lin nature of the scale? That seems to be the best place to find it (that's where I'm pulling the scale's range) but I've looked and can not figure it out. If there was, then I could add a command to step 3 above to define the scale type, and add a tag to the sx function in step 1. That would save me some tedious work.
So, just to reiterate: does anyone know how to tell the scaling (type of scale: log or linear) of a ggplot object? such as using the ggplot_build command's object?
Suppose we have a list of pre-build plots:
linear <- ggplot(iris, aes(Sepal.Width, Sepal.Length, colour = Species)) +
geom_point()
log <- linear + scale_y_log10()
linear <- ggplot_build(linear)
log <- ggplot_build(log)
plotlist <- list(a = linear, b = log)
We can grab information about their position scales in the following way:
out <- lapply(names(plotlist), function(i) {
# Grab plot, panel parameters and scales
plot <- plotlist[[i]]
params <- plot$layout$panel_params[[1]]
scales <- plot$plot$scales$scales
# Only keep (continuous) position scales
keep <- vapply(scales, function(x) {
inherits(x, "ScaleContinuousPosition")
}, logical(1))
scales <- scales[keep]
# Grab relevant transformations
out <- lapply(scales, function(scale) {
data.frame(position = scale$aesthetics[1],
# And now for the actual question:
transformation = scale$trans$name,
plot = i)
})
out <- do.call(rbind, out)
# Grab relevant ranges
ranges <- params[paste0(out$position, ".range")]
out$min <- sapply(ranges, `[`, 1)
out$max <- sapply(ranges, `[`, 2)
out
})
out <- do.call(rbind, out)
Which will give us:
out
position transformation plot min max
1 x identity a 1.8800000 4.520000
2 y identity a 4.1200000 8.080000
3 y log-10 b 0.6202605 0.910835
4 x identity b 1.8800000 4.520000
Or if you prefer a straightforward answer:
log$plot$scales$scales[[1]]$trans$name
[1] "log-10"

Way to progressively overlap line plots in R

I have a for loop from which I call a function grapher() which extracts certain columns from a dataframe (position and w, both continuous variables) and plots them. My code changes the Y variable (called w here) each time it runs and so I'd like to plot it as an overlay progressively. If I run the grapher() function 4 times for example, I'd like to have 4 plots where the first plot has only 1 line, and the 4th has all 4 overlain on each other (as different colours).
I've already tried points() as suggested in other posts, but for some reason it only generates a new graph.
grapher <- function(){
position.2L <- data[data$V1=='2L', 'V2']
w.2L <- data[data$V1=='2L', 'w']
plot(position.2L, w.2L)
points(position.2L, w.2L, col='green')
}
# example of my for loop #
for (t in 1:200){
#code here changes the 'w' variable each iteration of 't'
if (t%%50==0){
grapher()
}
}
Not knowing any details about your situation I can only assume something like this might be applicable.
# Example data set
d <- data.frame(V1=rep(1:2, each=6), V2=rep(1:6, 2), w=rep(1:6, each=2))
# Prepare the matrix we will write to.
n <- 200
m <- matrix(d$w, nrow(d), n)
# Loop progressively adding more noise to the data
set.seed(1)
for (i in 2:n) {
m[,i] <- m[,i-1] + rnorm(nrow(d), 0, 0.05)
}
# We can now plot the matrix, selecting the relevant rows and columns
matplot(m[d$V1 == 1, seq(1, n, by=50)], type="o", pch=16, lty=1)

Contour plot x-labeling

My question is very similar to this question but I wish to write special values on the x-axis.
I have the following code:
x <- c(1:12)
y <- c(1:12)
filled.contour(c(2,4,7,10,14,21,30,60,90,120,180,365), y, outer(x,y))
Gives the following plot :
My problem is that I don't want the plot to be squeezed on the left but want all values in c(2,4,7,10,14,21,30,60,90,120,180,365) to be equally spaced on the x-axis.
How can I do this?
As an extension, how can I put characters "two", "four", ... instead of 2, 4, ... on the x-axis?
Thanks
This is a start:
x <- 1:12
y <- 1:12
xvals <- c(2,4,7,10,14,21,30,60,90,120,180,365)
fx <- as.numeric(as.factor(xvals))
filled.contour(fx, y, outer(x,y),
plot.axes= {
axis(2) ## plain
axis(1,at=fx,labels=xvals)
})
However, you can see that the '180' label is already getting omitted, which means that things are going to be even worse if you translate the x-axis labels into words (do you really want the last tick label to read "three hundred sixty-five")? (You can use par(las=3) to turn the labels vertical, but that's ugly too.)
This question points us to qdap::replace_number(), but it doesn't seem to work for single-digit numbers ...
library(qdap)
filled.contour(fx, y, outer(x,y),
plot.axes= {
axis(2) ## plain
axis(1,at=fx,labels=replace_number(xvals))
})
update: the qdap maintainer has already fixed this bug; if you need the latest version you could try devtools::install_github("qdap","trinker")
If you're in a big hurry you could just fix the result by hand.

How to plot and animate coordinates (latitude/longitude) data in R?

I have 10 lat and long points. With the code below, I can plot the coordinates, draw arrows in the order of their sequence and out-put a gif file that shows navigation order.
So far I was able to do this only with plot {graphics} function. because arrow {graphics} and saveGIF{animation} only seems to work with the plot function. I am wondering if its possible to this a more appropriate library such as ggmap (edit: I had mistakenly said ggplot), googleVis and etc.
library(graphics)
library(animation)
lat <- c(34.083398,34.072467,34.030237,34.597334,34.587142,34.488386,33.443484,33.946902,33.062739,32.273711,32.272611)
lon <- c(-107.907107,-106.893156,-107.971542,-105.225107,-105.13397,-103.196355,-104.52479,-103.655698,-106.0156,-107.71744,-107.713977)
coords = data.frame(lat,lon)
x <- coords$lat ; y <- coords$lon
s <- seq(length(x)-1) # one shorter than data
saveGIF({
for(s in 1:length(x)){
plot(x,y)
arrows(x[s], y[s], x[s+1], y[s+1], col = 1:s)
}
})
Yes, just remember to wrap your ggplot calls in print so they produce output. Toy example:
data=data.frame(i=1:100,x=runif(100),y=runif(100))
saveGIF({for(i in 2:100){print(ggplot(data[1:i,],aes(x=x,y=y))+geom_point())}})
Just write your code to produce each frame with ggplot2 functions and wrap in print. What did you try?

plotting specific points within a spreadsheet in r

currently I am plotting 2000 some lines on a single plot in r. I am using the data from a spreadsheet which i cannot disclose due to sensitive information, but I'll try to illistrate how it is arranged.
x1/x1/x1/x1/x1/x1/etc.
y1/y1/y1/y1/y1/y1/etc.
x2/x2/x2/x2/x2/x2/etc.
y2/y2/y2/y2/y2/y2/etc.
...
x4436/x4436/x4436/etc.
y4436/y4436/y4436/etc.
where each x1,y1 is a point on a separate line. I need to plot a point on the endpoint of each line and I cannot seem to get my code to work. Currently I am using this to generate the points:
for (k in (1:2218)*2) {
q <- unlist(e_web_clear[2*k])
w <- unlist(e_web_clear[716])
points(w, q, col = "lightblue")
}
the way I imagined it, it would loop back to each point in every other row, to get only the y value for each line, and it would take the values from only the last column of my data (column 716).
needless to say, it did not work as intended, any suggestions?
EDIT:
spreadsheet with just a small portion of values here
and the code used to generate the lines:
for (j in (1:2218)*2) {
x <- unlist(e_web_clear[2*j-1,])
y <- unlist(e_web_clear[2*j,])
lines(x,y,'l',lwd=.00000000001, col="black")
}
data was imported as text file
Edit2:
this is the graph i am getting.
the graph i want to get would have the endpoint of each line highlighted in light blue. i believe it should look something like this. http: / /imgur.com/13b9MZL
figured it out.
I edited my line loop to place a point on the last vector point of each line.
for (j in (1:2218)*2) {
x <- unlist(e_web_clear[2*j-1,])
y <- unlist(e_web_clear[2*j,])
lines(x,y,'l',lwd=.00000000001, col="black")
points(x[358], y[358], lwd = 1.5, cex = .1, col = "lightblue")
}

Resources