Reputation: 725
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
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
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
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")
Upvotes: 2
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)
Upvotes: 0