19

When programming in Stata I often find myself using the loop index in the programming. For example, I'll loop over a list of the variables nominalprice and realprice:

local list = "nominalprice realprice"
foreach i of local list {
  summarize `i'
  twoway (scatter `i' time)
  graph export "C:\TimePlot-`i'.png"
}

This will plot the time series of nominal and real prices and export one graph called TimePlot-nominalprice.png and another called TimePlot-realprice.png.

In R the method I've come up with to do the same thing would be:

clist <- c("nominalprice", "realprice")
for (i in clist) {
  e <- paste("png(\"c:/TimePlot-",i,".png\")", sep="")
  eval(parse(text=e))
  plot(time, eval(parse(text=i)))
  dev.off() 
}

This R code looks unintuitive and messy to me and I haven't found a good way to do this sort of thing in R yet. Maybe I'm just not thinking about the problem the right way? Can you suggest a better way to loop using strings?

4 Answers 4

24

As other people have intimated, this would be easier if you had a dataframe with columns named nominalprice and realprice. If you do not, you could always use get. You shouldn't need parse at all here.

clist <- c("nominalprice", "realprice")
for (i in clist) {
   png(paste("c:/TimePlot-",i,".png"), sep="")
   plot(time, get(i))
   dev.off() 
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Jonathon. I like the get(i) option and I'll try working with that. The data I was using is dummy data so could be structured in a dataframe. What would be different if using a dataframe?
Because then it's easy to access by string. Say you have a data frame df with a column named nominalprice. Then you can just write df[,"nominalprice"] to obtain that column.
2

If your main issue is the need to type eval(parse(text=i)) instead of ``i'`, you could create a simpler-to-use functions for evaluating expressions from strings:

e = function(expr) eval(parse(text=expr))

Then the R example could be simplified to:

clist <- c("nominalprice", "realprice")
for (i in clist) {
  png(paste("c:/TimePlot-", i, ".png", sep=""))
  plot(time, e(i))
  dev.off() 
}

1 Comment

I think you should use get() as shown by Jonathan Chang instead.
1

Using ggplot2 and reshape:

library(ggplot2)
library(reshape)
df <- data.frame(nominalprice=rexp(10), time=1:10)
df <- transform(df, realprice=nominalprice*runif(10,.9,1.1))
dfm <- melt(df, id.var=c("time"))
qplot(time, value, facets=~variable, data=dfm)

Comments

1

I don't see what's especially wrong with your original solution, except that I don't know why you're using the eval() function. That doesn't seem necessary to me.

You can also use an apply function, such as lapply. Here's a working example. I created dummy data as a zoo() time series (this isn't necessary, but since you're working with time series data anyway):

# x <- some time series data
time <- as.Date("2003-02-01") + c(1, 3, 7, 9, 14) - 1
x <- zoo(data.frame(nominalprice=rnorm(5),realprice=rnorm(5)), time)
lapply(c("nominalprice", "realprice"), function(c.name, x) { 
  png(paste("c:/TimePlot-", c.name, ".png", sep=""))
  plot(x[,c.name], main=c.name)
  dev.off()
}, x=x)

2 Comments

In the function above what does c.name refer to? I'm trying to understand how I could apply this technique to other situations.
c.name is a variable name that I'm assigning to what get's passed by lapply (lapply, in this instance, is just passing each element of that vector, one at a time). Try playing with this to see how it works: lapply(c(1,2,3), function(x) print(x)). Also look at ?lapply.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.