Some notes on extending ggplot2 using custom grid grobs
For the directlabels package, since there is not a lot of documentation on extending ggplot2, I had to look through the code quite a bit to understand how it works. This document tries to summarize a few things I learned in this process that can be applicable to writing geoms in the future.
First, download the most recent version of the ggplot2 source from github:
cd mkdir R cd R git clone git://github.com/hadley/ggplot2.git
Then you can look at how the geoms are implemented, in ggplot2/R/geom-*.r
. For directlabels, I basically modified GeomText in geom-text.r
.
The most important method is draw
(from directlabels/R/ggplot2.R):
GeomDirectLabel <- proto(Geom, { draw <- function(., data, scales, coordinates, method=NULL,debug=FALSE, ...) { data$rot <- as.integer(data$angle) data$groups <- data$label dlgrob(subset(coordinates$transform(data, scales),select=-group), method,debug=debug, axes2native=function(data){ coordinates$transform(data, scales) }) } })
- The ggplot2 system works by calling
draw
for the data in every facet when youprint
a ggplot object. Thedraw
function must return some grid grobs that will be plotted later. - Standard grobs can be created using functions like
textGrob
,rectGrob
, orlinesGrob
. - I made a custom grob with
grob(cl="dlgrob",...)
inside thedlgrob
function. For making custom grobs, all you have to know is that a grob is basically a list, and you can stick whatever you want inside that list using named arguments togrob
that will be intercepted by the...
argument and stored in that list. - When you call
grid.draw
on a grob, grid will plot the grob in the current viewport, callingdrawDetails
on the grob for doing the actual plotting. - The directlabels package calculates the size of text labels before they are drawn by exploiting the fact that
drawDetails
is called in the plotting viewport. I wrote adrawDetails.dlgrob
function that is called to plot dlgrobs. - One tricky part about plotting using ggplot2 is that the native plotting coordinates do not match the coordinates of the data, or the axes labels. So you have to make sure to call
coordinates$transform(data,scales)
to convert axes units to native units, that you can plot in grobs asunit(x,"native")
. - If you define more arguments to
draw
, i.e.method
anddebug
above, these arguments can be specified when you instantiate the geom. For example,GeomDirectLabel$new(aes(Petal.Length,Sepal.Length,label=Species),method=smart.grid)
means that insidedraw
,data=data.frame(x=Petal.Length,y=Sepal.Length,label=Species)
andmethod=smart.grid
Org version 7.5 with Emacs version 22
Validate XHTML 1.0