Jim
Jim

Reputation: 725

R nested for loop to write multiple functions and plot them

Here is my data:

color   a   b
red     3   1.3
blue    9   1.8
purple  13  1.2
green   4   1.1
orange  7   0.9
yellow  6   2.1
brown   7   1.8

For each row, I'd like to write a function called "fun_color" by the following format: y = a*(x^b)

(a and b are the values of the data$a and data$b column for each row. x is the domain of the function.)

I assumed I should write a nested for loop along the following:

for (i in dt$color) 
  {(paste("fun_",i, sep = "")) = function(x)
    for (a in dt$a) 
      {a*x}
    }

However, I, a relative R newbie, can't quite get this for loop to work.

I'd then like to plot each of these 10 equations on the same plot. I assume I should write another for loop here, something like:

plot(fun_red)
for (i in function_list) {
  plot(i, add=TRUE)}

Any help? Thanks!

Upvotes: 0

Views: 1122

Answers (4)

Choubi
Choubi

Reputation: 680

The following does not use a for loop to create the functions but rather uses a function that returns a different function depending on the color given as argument. This has the advantage of not using assign and get.

fun_col <- function(col) {
  a <- dt$a[dt$color == col]
  b <- dt$b[dt$color == col]
  function(x) a*x^b
}

for (col in dt$color) {

  plot(fun_col(col), add = TRUE)

}

Upvotes: 0

nya
nya

Reputation: 2250

Alternatively, we can plot the functions with apply rather than the for loop. First, let's read in data and the range of the values to plot.

dt <- read.table(text="color   a   b
red     3   1.3
blue    9   1.8
purple  13  1.2
green   4   1.1
orange  7   0.9
yellow  6   2.1
brown   7   1.8", header=T)

# vector for x values
x1 <- 0
x2 <- 1
n <- 100
x <- seq(x1, x2, by = ((x2-x1)/n))

Then, we plot an empty space into which the function curves will be plotted. Note, that we calculate the maximum needed for the y axis in the max.y variable.

max.y <- dt[which.max(rowSums(dt[,2:3])),2] * (x2 ^ dt[which.max(rowSums(dt[,2:3])),3])

plot(x1, type="n", xlim=c(x1,x2), ylim=c(x1, max.y), xlab="x", ylab="a*(x^b)")

And finally, we plot the lines according to the specifications in the data.

apply(dt, 1, FUN=function(dt.row) 
    lines(x, as.numeric(dt.row[2]) * (x ^ as.numeric(dt.row[3])), col=dt.row[1]))

Benchmarking

As per Roland's and shayaa's comments, here is the performance comparison. The whole answers from Roland and shayaa were fed into the respective functions, and everything from here starting from the x1 variable definition into the nya() function.

library(microbenchmark)
microbenchmark(roland(dt))
Unit: milliseconds
       expr      min      lq    mean   median       uq      max neval
 roland(dt) 18.09634 18.4124 19.2258 18.67313 19.17735 35.42943   100
microbenchmark(shayaa(dt=dt))
Unit: milliseconds
            expr      min       lq     mean   median       uq      max neval
 shayaa(dt = dt) 10.85788 11.04311 11.44358 11.22057 11.51216 18.19182   100
 microbenchmark(nya(dt=dt))
 Unit: milliseconds
          expr      min       lq     mean  median       uq      max neval
  nya(dt = dt) 18.26883 18.61892 19.02823 18.8229 19.18054 25.41353   100

I would conclude that in this case, performance is not a critical issue. The user might choose an approach based on personal preference and amend it with dynamic options for plot size (x1, x2, max.y).

Upvotes: 0

shayaa
shayaa

Reputation: 2797

Choose a sequence of x values, and iterate over them with sapply. No need to call the plotting functions many times, just use matplot.

s <- seq(.2,5,by =.2)
matplot(s,t(sapply(s, function(x) dt$a*(x)^dt$b)),
        type = "l", lty = "solid", lwd = 2, col = dt$color, ylab = "y", xlab = "x")

enter image description here

Upvotes: 2

Roland
Roland

Reputation: 132706

Yes, use a for loop. However, use curve for plotting functions.

plot.new()
plot.window(xlim = c(0, 5), ylim = c(0, 200))
for (i in seq_len(nrow(DF))) curve(DF$a[i] * (x ^ DF$b[i]), 
                                   add = TRUE, col = as.character(DF$color[i]),
                                   lwd = 2)
axis(1)  
axis(2)

resulting plot

Upvotes: 0

Related Questions