Plotting list of functions using for loop in R - r

How can you plot a list of functions in one graph using a for loop in R? The following code does the trick, but requires a separate call of plot for the first function outside of the for loop, which is very clunky. Is there a way to handle all the plotting inside the for loop without creating multiple plots?
vec <- 1:10
funcs <- lapply(vec, function(base){function(exponent){base^exponent}})
x_vals <- seq(0, 10, length.out=100)
plot(x_vals, funcs[[1]](x_vals), type="l", ylim=c(0,100))
for (i in 2:length(vec)) {
lines(x_vals, funcs[[i]](x_vals))
}

You can also do the computations first and plotting after, like this:
vec <- 1:10
funcs <- lapply(vec, function(base) function(exponent){base^exponent})
x_vals <- seq(0, 10, length.out=100)
y_vals <- sapply(funcs, \(f) f(x_vals))
plot(1, xlim=range(x_vals), ylim=range(y_vals), type='n', log='y',
xlab='x', ylab='y')
apply(y_vals, 2, lines, x=x_vals)
This way you know the range of your y values before initiating the plot and can set the y axis limits accordingly (if you would want that). Note that I chose to use logarithmic y axis here.

Based on MrFlick's comment, it looks like something like this would be one way to do what I'm looking for, but is still not great.
vec <- 1:10
funcs <- lapply(vec, function(base){function(exponent){base^exponent}})
x_vals <- seq(0, 10, length.out=100)
plot(NULL, xlim=c(0,10), ylim=c(0,100))
for (i in 1:length(vec)) {
lines(x_vals, funcs[[i]](x_vals))
}

Related

How to create a monomial plot in R?

I want to create a function, that result will be a plot of moniomals ( degree less than "n").
I wrote the simple code.
Monomial=function(m){
x=1:100
y=1:100
for(i in m) x2=x^m
plot(y,x2,type="l",col="red",xlab="Arguments",ylab="Values",
main=expression("Monomials"))
But for example: Monomial(3) I getting plot x^3. I need yet x^1 and x^2. How to name each line?
Here is what you need:
Monomial <- function(m){
x <- 1:100
cols <- palette(rainbow(m))
plot(x,x,type="l",col = cols[1],xlab="Arguments",ylab="Values",
main=expression("Monomials"))
for (d in 2:m){
lines(x, x^d, type="l", col=cols[d])
}
legend(90, 60, legend=c(as.character(paste0("x",1:m))),
col=cols, lty=1, cex=0.6)
}
You need to generate colors. This is what the cols variable achieves. lines adds a new curve to existing axes. Finally, ledend adds a legend to the plot.

Plot multiple fitdist objects in same the plot with different colors?

I have a list of fitdist objects, which I have stored using this piece of code.
norm_dist_res <- list()
for(i in 1:10)
{
x <- 1+(8000*(i-1))
y <- 8000*i
print (x)
print(y)
norm_dist_res[[i]] = norm_dist_res[[i]] <- fitdist(data=as.vector(g_all_p$data[x:y,]), distr="norm")
}
Is there a way to plot all the normal distributions extracted from fittest with a different color to show how the data is distributed?
Or in general how to visualize multiple normal distributions?
You are estimating the parameters of a normal distribution, so just plot the densities.
## Don't no what g_all_p is, so simplifying the data
library(fitdistrplus)
norm_dist_res <- list()
for(i in 1:10)
{
norm_dist_res[[i]] = norm_dist_res[[i]] <- fitdist(data=rnorm(10), distr="norm")
}
Then just plot using lines and changing the colour
x = seq(-5, 5, length.out=100)
plot(x, type="n", ylim=c(0, 1), xlim=range(x))
for(i in 1:10) {
est = norm_dist_res[[i]]$estimate
lines(x, dnorm(x, est[1], est[2]), col="grey90")
}
To get

Adding lines to graph created using plotrix library

I have created a stacked histogram using the multhist function in the plotrix library, but I am unable to add a straight line to this histogram. Code that I would normally use doesn't seem to work in this setting.
Here's an example. I am trying to add the mean and standard errors of the overall distribution as simple vertical lines on the histogram, but these do not work properly. What am I doing wrong?
library(plotrix)
test1<-rnorm(30,0)
test2<-rnorm(30,0)
test3<-rnorm(30,0)
forstats<-c(test1,test2,test3)
mn<-mean(forstats)
se<-std.error(forstats)
together<-list(test1,test2,test3)
multhist(together, col=c(7,4,2), space=c(0,0), beside=FALSE,right=FALSE)
abline(v=mn)
abline(v=mn+se)
abline(v=mn-se)
multhist uses barplot, so, as #BenBolker mentions here, the x-axis corresponds to bin index. It's a bit tricky to convert between native coordinates and bin index units, so I've put together another function for stacked histograms (for frequencies, anyway):
histstack <- function(x, breaks, col=rainbow(length(x)), ...) {
col <- rev(col)
if (length(breaks)==1) {
rng <- range(pretty(range(x)))
breaks <- seq(rng[1], rng[2], length.out=breaks)
}
h <- lapply(x, hist, plot=FALSE, breaks=breaks)
cumcounts <- apply(sapply(h, '[[', 'counts'), 1, cumsum)
for(i in seq_along(h)) {
h[[i]]$counts <- cumcounts[nrow(cumcounts) - i + 1, ]
}
max_cnt <- max(sapply(h, '[[', 'counts'))
plot(h[[1]], xlim=range(sapply(h, '[', 'breaks')), yaxt='n',
ylim=c(0, max(pretty(max_cnt))), col=col[1], ...)
sapply(seq_along(h)[-1], function(i) plot(h[[i]], col=col[i], add=TRUE, ...))
axis(2, at=pretty(c(0, max_cnt)), labels=pretty(c(0, max_cnt)), ...)
}
And here it is:
histstack(together, seq(-3, 3, 0.5), col=c(7, 4, 2), main='',
las=1, xlab='', ylab='')
abline(v=c(mn, mn+se, mn-se), lwd=2, )
IMO the x-axis labelling is probably more appropriate than that of multhist, since multhist implies that counts relate to the mid-bin values, whereas above it's clear that the x-axis ticks delineate the bins.

R plotting frequency distribution

I know that we normally do in this way:
x=c(rep(0.3,100),rep(0.5,700))
plot(table(x))
However, we can only get a few dots or vertical lines in the graph.
What should I do if I want 100 dots above 0.3 and 700 dots above 0.5?
Something like this?
x <- c(rep(.3,100), rep(.5, 700))
y <- c(seq(0,1, length.out=100), seq(0,1,length.out=700))
plot(x,y)
edit: (following OP's comment)
In that case, something like this should work.
x <- rep(seq(1, 10)/10, seq(100, 1000, by=100))
x.t <- as.matrix(table(x))
y <- unlist(apply(x.t, 1, function(x) seq(1,x)))
plot(x,y)
You can lay with the linetype and linewidth settings...
plot(table(x),lty=3,lwd=0.5)
For smaller numbers (counts) you can use stripchart with method="stack" like this:
stripchart(c(rep(0.3,10),rep(0.5,70)), pch=19, method="stack", ylim=c(0,100))
But stripchart does not work for 700 dots.
Edit:
The dots() function from the package TeachingDemos is probably what you want:
require(TeachingDemos)
dots(x)

superpose a histogram and an xyplot

I'd like to superpose a histogram and an xyplot representing the cumulative distribution function using r's lattice package.
I've tried to accomplish this with custom panel functions, but can't seem to get it right--I'm getting hung up on one plot being univariate and one being bivariate I think.
Here's an example with the two plots I want stacked vertically:
set.seed(1)
x <- rnorm(100, 0, 1)
discrete.cdf <- function(x, decreasing=FALSE){
x <- x[order(x,decreasing=FALSE)]
result <- data.frame(rank=1:length(x),x=x)
result$cdf <- result$rank/nrow(result)
return(result)
}
my.df <- discrete.cdf(x)
chart.hist <- histogram(~x, data=my.df, xlab="")
chart.cdf <- xyplot(100*cdf~x, data=my.df, type="s",
ylab="Cumulative Percent of Total")
graphics.off()
trellis.device(width = 6, height = 8)
print(chart.hist, split = c(1,1,1,2), more = TRUE)
print(chart.cdf, split = c(1,2,1,2))
I'd like these superposed in the same frame, rather than stacked.
The following code doesn't work, nor do any of the simple variations of it that I have tried:
xyplot(cdf~x,data=cdf,
panel=function(...){
panel.xyplot(...)
panel.histogram(~x)
})
You were on the right track with your custom panel function. The trick is passing the correct arguments to the panel.- functions. For panel.histogram, this means not passing a formula and supplying an appropriate value to the breaks argument:
EDIT Proper percent values on y-axis and type of plots
xyplot(100*cdf~x,data=my.df,
panel=function(...){
panel.histogram(..., breaks = do.breaks(range(x), nint = 8),
type = "percent")
panel.xyplot(..., type = "s")
})
This answer is just a placeholder until a better answer comes.
The hist() function from the graphics package has an option called add. The following does what you want in the "classical" way:
plot( my.df$x, my.df$cdf * 100, type= "l" )
hist( my.df$x, add= T )

Resources