Monday, December 6, 2010

Using a Closure to Make Panel Labels in R

When making plots with several panels, I very often want to label the individual panels with letters of numbers. I like to have a simple function for labeling panels, like this:

# create a plot
plot( x, y )
# assign a unique label to the plot
panel_labeler()

Below the break is a definition for the panel_labeler() function using a closure in R. Shown are some examples of using panel_labeler() assign labels to plots. The plots show different methods for combining mixtures of Normal distributions, but this approach could be used for plotting anything.



make.labeler = function() {
   current_label = 0

   fn = function( location = "topleft" ) {
      current_label <<- current_label + 1
      legend( location, legend = as.character(current_label), bty = 'n' )
   }
   return(fn)
}
panel_labeler = make.labeler()


x = seq( from = 4, to = 20, by = 0.01 )
par( mfrow = c(2,2) ) # four panels
mix1 = 0.7 * dnorm( x, mean = 4, sd = 1.5 ) + 0.3 * dnorm( x, mean = 18.3, sd = 7.3 )
mix2 = 0.7 * dnorm( x, mean = 9, sd = 2.0 ) + 0.3 * dnorm( x, mean = 18.3, sd = 7.3 )
ylim = c(0,max(mix1,mix2))


plot( x, mix1, type = 'l', ylab = "P(d)", col = 2 )
lines( x, mix2, type = 'l', col = 4 )
legend( "topright", legend = c("mix1","mix2"), col = c(2,4), lty = 1 )
panel_labeler() # panel 1


plot ( x, mix1 / 2 + mix2 / 2, type = 'l', ylim = ylim, ylab = "P(d)" )
lines( x, mix1 * mix2, type = 'l', lty = 2 )
legend( "topright", legend = c("sum","product"), lty = c(1,2) )
panel_labeler() # panel 2


plot ( x, mix1 / 2 + mix2 / 2, type = 'l', ylim = ylim, ylab = "P(d)" )
lines( x, 6 * mix1 * mix2, type = 'l', lty = 2 )
legend( "topright", legend = c("sum","6 * product"), lty = c(1,2) )
panel_labeler() # panel 3


plot ( x, -1 * log( mix1 / 2 + mix2 / 2 ), type = 'l', ylab = "-ln(P(d))", ylim = c(0,9) )
lines( x, -1 * log( mix1 * mix2 ), type = 'l', lty = 2 )
lines( x, -1 * log( mix1 ), type = 'l', col = 2 )
lines( x, -1 * log( mix2 ), type = 'l', col = 4 )
legend( "bottomright", legend = c("mix1","mix2","-ln(sum)","-ln(product)"), lty = c(1,1,1,2), cex = 0.8, col = c(2,4,1,1) )
panel_labeler() # panel 4