1

I am trying to plot multiple functions using curve(). My example tries to plot multiple normal distributions with different means and the same standard deviation.

png("d:/R/standardnormal-different-means.png",width=600,height=300)
#First normal distribution 
curve(dnorm, 
    from=-2,to=2,ylab="d(x)",
    xlim=c(-5,5))
abline(v=0,lwd=4,col="black")

#Only second normal distribution is plotted
myMean <- -1
curve(dnorm(x,mean=myMean), 
    from=myMean-2,to=myMean+2,
    ylab="d(x)",xlim=c(-5,5), col="blue")
abline(v=-1,lwd=4,col="blue")
dev.off()

As the curve() function creates a new plot each time, only the second normal distribution is plotted.

Plot (shows only second normal distribution)

scs
  • 567
  • 6
  • 22
  • 4
    You need to include `add = TRUE` for the second `curve` – d.b Apr 25 '17 at 19:08
  • or this http://stackoverflow.com/questions/6853204/plotting-multiple-curves-same-graph-and-same-scale – M-- Apr 25 '17 at 19:23
  • The link contains a different problem - the plotting of a point instead of a function – scs Apr 25 '17 at 23:43

1 Answers1

3

I reopened this question because the ostensible duplicates focus on plotting two different functions or two different y-vectors with separate calls to curve. But since we want the same function, dnorm, plotted for different means, we can automate the process (although the answers to the other questions could also be generalized and automated in a similar way).

For example:

my_curve = function(m, col) {
  curve(dnorm(x, mean=m), from=m - 3, to=m + 3, col=col, add=TRUE)
  abline(v=m, lwd=2, col=col)
}

plot(NA, xlim=c(-10,10), ylim=c(0,0.4), xlab="Mean", ylab="d(x)")
mapply(my_curve, seq(-6,6,2), rainbow(7))

enter image description here

Or, to generalize still further, let's allow multiple means and standard deviations and provide an option regarding whether to include a mean line:

my_curve = function(m, sd, col, meanline=TRUE) {
  curve(dnorm(x, mean=m, sd=sd), from=m - 3*sd, to=m + 3*sd, col=col, add=TRUE)
  if(meanline==TRUE) abline(v=m, lwd=2, col=col)
}

plot(NA, xlim=c(-10,10), ylim=c(0,0.4), xlab="Mean", ylab="d(x)")
mapply(my_curve, rep(0,4), 4:1, rainbow(4), MoreArgs=list(meanline=FALSE))

enter image description here

You can also use line segments that start at zero and stop at the top of the density distribution, rather than extending all the way from the bottom to the top of the plot. For a normal distribution the mean is also the point of highest density. However, I've used the which.max approach below as a more general way of identifying the x-value at which the maximum y-value occurs. I've also added arguments for line width (lwd) and line end cap style (lend=1 means flat rather than rounded):

my_curve = function(m, sd, col, meanline=TRUE, lwd=1, lend=1) {
  x=curve(dnorm(x, mean=m, sd=sd), from=m - 3*sd, to=m + 3*sd, col=col, add=TRUE)
  if(meanline==TRUE) segments(m, 0, m, x$y[which.max(x$y)], col=col, lwd=lwd, lend=lend)
}

plot(NA, xlim=c(-10,20), ylim=c(0,0.4), xlab="Mean", ylab="d(x)")
mapply(my_curve, seq(-5,5,5), c(1,3,5), rainbow(3))

enter image description here

eipi10
  • 91,525
  • 24
  • 209
  • 285
  • As far as plotting is concerned, I would like to point out two brilliant solutions in this answer: Create an empty plot with plot(NA, ...) and most importantly the plotting of mean lines adapted to the curve with segments. I will definitely rewrite my own code using these solutions. – scs Apr 25 '17 at 23:57