As a follow-up to my last post about how to render a normal distribution curve with R, here’s how you can render two on the same plot:
setClass( Class = "Distribution", representation = representation( name = "character", mean = "numeric", sd = "numeric", color = "character", x = "vector", y = "vector" ) ) # We rewrite the initialize method for Distribution objects so that we can # set the x and y values which are used throughout the plotting process setMethod( f = "initialize", signature = "Distribution", definition = function( .Object, name, mean, sd, color ) { .Object@name = name .Object@mean = mean .Object@sd = sd .Object@color = color .Object@x = seq( -4, 4, length = 1000 ) * sd + mean .Object@y = dnorm( .Object@x, mean, sd ) return ( .Object ) } ) # Given a list of distributions, this returns a list of the x and y axis range get_axis_ranges = function( distributions ) { x_all = vector() y_all = vector() for ( distribution in distributions ) { x_all = c( x_all, distribution@x ) y_all = c( y_all, distribution@y ) } xlim = c( min( x_all ), max( x_all ) ) ylim = c( min( y_all ), max( y_all ) ) # Note that by forming a list of the vectors, the vectors get converted to lists # which we then have to convert back to vectors in order to use them for plotting return ( list( xlim, ylim ) ) } # Define the distributions that we want to plot distributions = list( new( Class = "Distribution", name = "women", mean = 63.6, sd = 2.5, color = "pink" ), new( Class = "Distribution", name = "men", mean = 69, sd = 2.8, color = "blue" ) ) # Determine the range to use for each axis axis_range = get_axis_ranges( distributions ) xlim = unlist( axis_range[ 1 ] ) ylim = unlist( axis_range[ 2 ] ) # Create the plot plot( NULL, NULL, type = "n", xlim = xlim, ylim = ylim, xlab = "Height (inches)", ylab = "", main = "Distribution of Heights", axes = FALSE ) # Render each of the curves line_width = 3 for( distribution in distributions ) { lines( distribution@x, distribution@y, col = distribution@color, lwd = line_width ) } # Render the x axis axis_bounds <- seq( min( xlim ), max( xlim ) ) axis( side = 1, at = axis_bounds, pos = 0, col = "#aaaaaa", col.axis = "#444444" ) # Finally, render a legend legend_text = vector() legend_colors = vector() for ( distribution in distributions ) { legend_text = c( legend_text, distribution@name ) legend_colors = c( legend_colors, distribution@color ) } legend('right', legend_text, lty = 1, lwd = line_width, col = legend_colors, bty = 'n' )