[med-svn] [r-cran-ggplot2] 01/05: Imported Upstream version 2.0.0

Andreas Tille tille at debian.org
Sat Dec 19 22:26:16 UTC 2015


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository r-cran-ggplot2.

commit 7cbb6b88f251f2962a1b7b8697859cf4ac7a92f9
Author: Andreas Tille <tille at debian.org>
Date:   Sat Dec 19 19:10:12 2015 +0100

    Imported Upstream version 2.0.0
---
 DESCRIPTION                                        |  141 +-
 MD5                                                |  806 ++++----
 NAMESPACE                                          |  274 +--
 NEWS                                               | 2052 --------------------
 R/aaa-.r                                           |   70 +-
 R/aaa-constants.r                                  |    1 -
 R/aes-calculated.r                                 |    9 +-
 R/aes-colour-fill-alpha.r                          |   15 +-
 R/aes-group-order.r                                |   25 +-
 R/aes-linetype-size-shape.r                        |   24 +-
 R/aes-position.r                                   |   13 +-
 R/aes.r                                            |  190 +-
 R/annotation-custom.r                              |   66 +-
 R/annotation-logticks.r                            |  167 +-
 R/annotation-map.r                                 |   39 +-
 R/annotation-raster.r                              |   65 +-
 R/annotation.r                                     |   25 +-
 R/autoplot.r                                       |    4 +-
 R/bench.r                                          |    6 +-
 R/coord-.r                                         |  156 +-
 R/coord-cartesian-.r                               |  118 +-
 R/coord-fixed.r                                    |   39 +-
 R/coord-flip.r                                     |   78 +-
 R/coord-map.r                                      |  308 +--
 R/coord-munch.r                                    |   51 +-
 R/coord-polar.r                                    |  410 ++--
 R/coord-quickmap.R                                 |   87 +-
 R/coord-transform.r                                |  131 +-
 R/{ggplot2.r => data.R}                            |  182 +-
 R/facet-grid-.r                                    |  288 ++-
 R/facet-labels.r                                   |  637 ++++--
 R/facet-layout.r                                   |   49 +-
 R/facet-locate.r                                   |   20 +-
 R/facet-null.r                                     |   20 +-
 R/facet-viewports.r                                |   12 +-
 R/facet-wrap.r                                     |  338 +++-
 R/fortify-lm.r                                     |   50 +-
 R/fortify-map.r                                    |   45 +-
 R/fortify-multcomp.r                               |   10 +-
 R/fortify-spatial.r                                |   33 +-
 R/fortify.r                                        |    6 +-
 R/geom-.r                                          |  185 +-
 R/geom-abline.r                                    |  164 +-
 R/geom-bar-.r                                      |  149 --
 R/geom-bar-histogram.r                             |  123 --
 R/geom-bar.r                                       |  125 ++
 R/geom-bin2d.r                                     |   52 +-
 R/geom-blank.r                                     |   36 +-
 R/geom-boxplot.r                                   |  256 ++-
 R/geom-contour.r                                   |   67 +
 R/geom-count.r                                     |   59 +
 R/geom-crossbar.r                                  |  118 +-
 R/geom-curve.r                                     |   54 +
 R/geom-defaults.r                                  |   37 +-
 R/geom-density.r                                   |   77 +
 R/geom-density2d.r                                 |   72 +
 R/geom-dotplot.r                                   |  229 ++-
 R/geom-error.r                                     |   81 -
 R/geom-errorbar.r                                  |   55 +
 R/geom-errorbarh.r                                 |   77 +
 R/geom-errorh.r                                    |   59 -
 R/geom-freqpoly.r                                  |   45 +-
 R/geom-hex.r                                       |   72 +-
 R/geom-histogram.r                                 |   95 +
 R/geom-hline.r                                     |  104 +-
 R/geom-jitter.r                                    |   57 +
 R/geom-label.R                                     |  141 ++
 R/geom-linerange.r                                 |  106 +-
 R/geom-map.r                                       |   46 +-
 R/geom-path-.r                                     |  207 --
 R/geom-path-contour.r                              |   25 -
 R/geom-path-density2d.r                            |   29 -
 R/geom-path-line.r                                 |   77 -
 R/geom-path-step.r                                 |   73 -
 R/geom-path.r                                      |  306 +++
 R/geom-point-.r                                    |  143 --
 R/geom-point-jitter.r                              |   46 -
 R/geom-point.r                                     |  164 ++
 R/geom-pointrange.r                                |   72 +-
 R/geom-polygon.r                                   |   67 +-
 R/geom-quantile.r                                  |   63 +-
 R/geom-raster.r                                    |  128 +-
 R/geom-rect.r                                      |   93 +-
 R/geom-ribbon-.r                                   |  131 --
 R/geom-ribbon-density.r                            |   27 -
 R/geom-ribbon.r                                    |  135 ++
 R/geom-rug.r                                       |   60 +-
 R/geom-segment.r                                   |  122 +-
 R/geom-smooth.r                                    |  155 +-
 R/geom-spoke.r                                     |   61 +
 R/geom-text.r                                      |  227 ++-
 R/geom-tile.r                                      |  148 +-
 R/geom-violin.r                                    |  152 +-
 R/geom-vline.r                                     |  119 +-
 R/ggplot2.r                                        |  222 +--
 R/ggproto.r                                        |  280 +++
 R/grob-absolute.r                                  |    4 +-
 R/grob-dotstack.r                                  |   20 +-
 R/grob-null.r                                      |    1 +
 R/grouping.r                                       |   39 +
 R/guide-colorbar.r                                 |  104 +-
 R/guide-legend.r                                   |  444 ++---
 R/guides-.r                                        |   68 +-
 R/guides-axis.r                                    |   65 +-
 R/guides-grid.r                                    |   16 +-
 R/labels.r                                         |    8 +-
 R/layer.r                                          |  376 ++--
 R/legend-draw.r                                    |  201 ++
 R/limits.r                                         |   58 +-
 R/margins.R                                        |  168 ++
 R/panel.r                                          |   55 +-
 R/plot-build.r                                     |  231 ++-
 R/plot-construction.r                              |   57 +-
 R/plot-render.r                                    |  210 --
 R/plot.r                                           |  108 +-
 R/position-.r                                      |  100 +-
 R/position-collide.r                               |   42 +-
 R/position-dodge.r                                 |   58 +-
 R/position-fill.r                                  |   49 +-
 R/position-identity.r                              |   20 +-
 R/position-jitter.r                                |   71 +-
 R/position-jitterdodge.R                           |   94 +-
 R/position-nudge.R                                 |   46 +
 R/position-stack.r                                 |   54 +-
 R/quick-plot.r                                     |  126 +-
 R/range.r                                          |   33 +
 R/save.r                                           |  212 +-
 R/scale-.r                                         | 1022 +++++-----
 R/scale-alpha.r                                    |    8 +-
 R/scale-area.r                                     |   18 -
 R/scale-brewer.r                                   |   69 +-
 R/scale-continuous.r                               |  140 +-
 R/scale-date.r                                     |  232 ++-
 R/scale-datetime.r                                 |   92 -
 R/scale-discrete-.r                                |  132 +-
 R/scale-gradient.r                                 |  119 +-
 R/scale-gradient2.r                                |   72 -
 R/scale-gradientn.r                                |   45 -
 R/scale-grey.r                                     |   18 +-
 R/scale-hue.r                                      |   14 +-
 R/scale-identity.r                                 |  127 +-
 R/scale-linetype.r                                 |   12 +-
 R/scale-manual.r                                   |    3 +-
 R/scale-shape.r                                    |    8 +-
 R/scale-size.r                                     |   77 +-
 R/scales-.r                                        |   82 +-
 R/stat-.r                                          |  160 +-
 R/stat-bin.r                                       |  169 +-
 R/stat-bin2d.r                                     |  223 ++-
 R/stat-bindot.r                                    |  144 +-
 R/stat-binhex.r                                    |  100 +-
 R/stat-boxplot.r                                   |  128 +-
 R/stat-contour.r                                   |  111 +-
 R/stat-count.r                                     |   67 +
 R/stat-density-2d.r                                |  117 +-
 R/stat-density.r                                   |  180 +-
 R/stat-ecdf.r                                      |   46 +-
 R/stat-ellipse.R                                   |  111 +-
 R/stat-function.r                                  |   69 +-
 R/stat-identity.r                                  |   56 +-
 R/stat-qq.r                                        |   89 +-
 R/stat-quantile.r                                  |  111 +-
 R/stat-smooth-methods.r                            |   14 +-
 R/stat-smooth.r                                    |  199 +-
 R/stat-spoke.r                                     |   39 -
 R/stat-sum.r                                       |   88 +-
 R/stat-summary-2d.r                                |  174 +-
 R/stat-summary-bin.R                               |   83 +
 R/stat-summary-hex.r                               |  104 +-
 R/stat-summary.r                                   |  171 +-
 R/stat-unique.r                                    |   35 +-
 R/stat-vline.r                                     |  135 --
 R/stat-ydensity.r                                  |  149 +-
 R/summary.r                                        |   25 +-
 R/templates.r                                      |   46 -
 R/theme-defaults.r                                 |  135 +-
 R/theme-elements.r                                 |  125 +-
 R/theme.r                                          |  178 +-
 R/translate-qplot-gpl.r                            |   56 -
 R/translate-qplot-lattice.r                        |    8 +-
 R/utilities-break.r                                |   95 +-
 R/utilities-grid.r                                 |    6 +
 R/utilities-help.r                                 |   19 +-
 R/utilities-layer.r                                |   33 -
 R/utilities-matrix.r                               |   81 +-
 R/utilities.r                                      |  232 ++-
 R/xxx-digest.r                                     |   96 -
 R/zxx.r                                            |   19 +-
 R/zzz.r                                            |   11 +-
 README.md                                          |   32 +-
 build/partial.rdb                                  |  Bin 147581 -> 175862 bytes
 build/vignette.rds                                 |  Bin 249 -> 245 bytes
 data/datalist                                      |    8 -
 data/diamonds.rda                                  |  Bin 513648 -> 343422 bytes
 data/economics.rda                                 |  Bin 7282 -> 8082 bytes
 data/economics_long.rda                            |  Bin 0 -> 30979 bytes
 data/faithfuld.rda                                 |  Bin 0 -> 48762 bytes
 data/luv_colours.rda                               |  Bin 0 -> 15083 bytes
 data/midwest.rda                                   |  Bin 61233 -> 62081 bytes
 data/movies.rda                                    |  Bin 1411851 -> 0 bytes
 data/mpg.rda                                       |  Bin 1834 -> 2059 bytes
 data/msleep.rda                                    |  Bin 3489 -> 3466 bytes
 data/presidential.rda                              |  Bin 329 -> 375 bytes
 data/seals.rda                                     |  Bin 16348 -> 19330 bytes
 data/txhousing.rda                                 |  Bin 0 -> 83137 bytes
 inst/CITATION                                      |    6 +-
 inst/doc/development.R                             |   14 -
 inst/doc/development.Rmd                           |  263 ---
 inst/doc/development.html                          |  446 -----
 inst/doc/extending-ggplot2.R                       |  328 ++++
 inst/doc/extending-ggplot2.Rmd                     |  547 ++++++
 inst/doc/extending-ggplot2.html                    |  556 ++++++
 inst/doc/ggplot2-specs.R                           |   52 +
 inst/doc/ggplot2-specs.Rmd                         |  168 ++
 inst/doc/ggplot2-specs.html                        |  191 ++
 inst/doc/release.R                                 |    8 -
 inst/doc/release.Rmd                               |  107 -
 inst/doc/release.html                              |  257 ---
 inst/staticdocs/icons.R                            |  434 +++--
 inst/staticdocs/index.r                            |   46 +-
 inst/test_ns/DESCRIPTION                           |   12 -
 inst/test_ns/NAMESPACE                             |    2 -
 inst/test_ns/R/my-plot.r                           |   12 -
 inst/test_ns/man/my_plot.Rd                        |   13 -
 inst/tests/test-aes-grouping.r                     |   71 -
 inst/tests/test-aes-setting.r                      |   23 -
 inst/tests/test-aes.r                              |   62 -
 inst/tests/test-boxplot.r                          |   13 -
 inst/tests/test-build.r                            |   42 -
 inst/tests/test-empty-data.r                       |  131 --
 inst/tests/test-layer.r                            |   18 -
 inst/tests/test-scales-breaks-labels.r             |  238 ---
 inst/tests/test-stats.r                            |  136 --
 inst/tests/test-utilities.r                        |   22 -
 man/absoluteGrob.Rd                                |    4 +-
 man/add_theme.Rd                                   |    4 +-
 man/aes.Rd                                         |   39 +-
 man/aes_.Rd                                        |   58 +
 man/aes_all.Rd                                     |    3 +-
 man/aes_auto.Rd                                    |   16 +-
 man/aes_colour_fill_alpha.Rd                       |   16 +-
 man/aes_group_order.Rd                             |   28 +-
 man/aes_linetype_size_shape.Rd                     |   26 +-
 man/aes_position.Rd                                |   16 +-
 man/aes_string.Rd                                  |   42 -
 man/annotate.Rd                                    |   14 +-
 man/annotation_custom.Rd                           |   19 +-
 man/annotation_logticks.Rd                         |   66 +-
 man/annotation_map.Rd                              |    5 +-
 man/annotation_raster.Rd                           |   21 +-
 man/as.list.ggproto.Rd                             |   20 +
 man/as_labeller.Rd                                 |   46 +
 man/autoplot.Rd                                    |    2 +-
 man/benchplot.Rd                                   |    6 +-
 man/borders.Rd                                     |   19 +-
 man/calc_element.Rd                                |    3 +-
 man/continuous_scale.Rd                            |   93 +-
 man/coord.Rd                                       |   16 -
 man/coord_cartesian.Rd                             |   45 +-
 man/coord_expand_defaults.Rd                       |   13 -
 man/coord_fixed.Rd                                 |   19 +-
 man/coord_flip.Rd                                  |   30 +-
 man/coord_map.Rd                                   |   58 +-
 man/coord_munch.Rd                                 |   25 +
 man/coord_polar.Rd                                 |   21 +-
 man/coord_quickmap.Rd                              |   52 -
 man/coord_trans.Rd                                 |   58 +-
 man/cut_interval.Rd                                |   44 +-
 man/cut_number.Rd                                  |   25 -
 man/cweave.Rd                                      |   19 -
 man/diamonds.Rd                                    |   35 +-
 man/discrete_scale.Rd                              |   13 +-
 man/draw_key.Rd                                    |   68 +
 man/economics.Rd                                   |   38 +-
 man/element_blank.Rd                               |    2 +-
 man/element_grob.Rd                                |   19 +
 man/element_line.Rd                                |    2 +-
 man/element_rect.Rd                                |    2 +-
 man/element_text.Rd                                |   12 +-
 man/expand_limits.Rd                               |   14 +-
 man/facet.Rd                                       |    2 +-
 man/facet_grid.Rd                                  |   94 +-
 man/facet_null.Rd                                  |    3 +-
 man/facet_wrap.Rd                                  |  134 +-
 man/faithfuld.Rd                                   |   16 +
 man/format.ggproto.Rd                              |   21 +
 man/fortify-multcomp.Rd                            |    4 +-
 man/fortify.Rd                                     |    8 +-
 man/fortify.lm.Rd                                  |   40 +-
 man/fortify.map.Rd                                 |    9 +-
 man/fortify.sp.Rd                                  |    2 +-
 man/geom_abline.Rd                                 |  145 +-
 man/geom_area.Rd                                   |   46 -
 man/geom_bar.Rd                                    |  247 ++-
 man/geom_bin2d.Rd                                  |   82 +-
 man/geom_blank.Rd                                  |   46 +-
 man/geom_boxplot.Rd                                |  187 +-
 man/geom_contour.Rd                                |   88 +-
 man/geom_count.Rd                                  |  103 +
 man/geom_crossbar.Rd                               |   46 -
 man/geom_density.Rd                                |  118 +-
 man/geom_density2d.Rd                              |   56 -
 man/geom_density_2d.Rd                             |  111 ++
 man/geom_dotplot.Rd                                |  100 +-
 man/geom_errorbar.Rd                               |   77 -
 man/geom_errorbarh.Rd                              |   50 +-
 man/geom_freqpoly.Rd                               |   49 -
 man/geom_hex.Rd                                    |   85 +-
 man/geom_histogram.Rd                              |  212 +-
 man/geom_hline.Rd                                  |   70 -
 man/geom_jitter.Rd                                 |   97 +-
 man/geom_line.Rd                                   |   93 -
 man/geom_linerange.Rd                              |  137 +-
 man/geom_map.Rd                                    |   47 +-
 man/geom_path.Rd                                   |  172 +-
 man/geom_point.Rd                                  |   97 +-
 man/geom_pointrange.Rd                             |   45 -
 man/geom_polygon.Rd                                |   48 +-
 man/geom_quantile.Rd                               |   92 +-
 man/geom_raster.Rd                                 |   82 -
 man/geom_rect.Rd                                   |   43 -
 man/geom_ribbon.Rd                                 |   95 +-
 man/geom_rug.Rd                                    |   50 +-
 man/geom_segment.Rd                                |  122 +-
 man/geom_smooth.Rd                                 |  177 +-
 man/geom_spoke.Rd                                  |   71 +
 man/geom_step.Rd                                   |   57 -
 man/geom_text.Rd                                   |  190 +-
 man/geom_tile.Rd                                   |  170 +-
 man/geom_violin.Rd                                 |  111 +-
 man/geom_vline.Rd                                  |   73 -
 man/gg-add.Rd                                      |   21 +-
 man/gg_dep.Rd                                      |    4 +-
 man/ggplot.Rd                                      |   32 +-
 man/ggplot.data.frame.Rd                           |   26 -
 man/ggplot2-ggproto.Rd                             |  290 +++
 man/ggplot2.Rd                                     |   11 -
 man/ggplotGrob.Rd                                  |    4 +-
 man/ggplot_build.Rd                                |   24 +-
 man/ggplot_gtable.Rd                               |    4 +-
 man/ggproto.Rd                                     |   49 +
 man/ggsave.Rd                                      |   76 +-
 man/ggscale.Rd                                     |   32 -
 man/ggtheme.Rd                                     |   20 +-
 man/graphical-units.Rd                             |   20 +
 man/guide_colourbar.Rd                             |   39 +-
 man/guide_legend.Rd                                |   50 +-
 man/guides.Rd                                      |   22 +-
 man/hmisc.Rd                                       |    2 +-
 man/interleave.Rd                                  |   16 -
 man/{is.coord.Rd => is.Coord.Rd}                   |    8 +-
 man/is.facet.Rd                                    |    2 +-
 man/is.ggplot.Rd                                   |    3 +-
 man/is.ggproto.Rd                                  |   15 +
 man/is.rel.Rd                                      |    2 +-
 man/is.theme.Rd                                    |    2 +-
 man/label_both.Rd                                  |   26 -
 man/label_bquote.Rd                                |   32 +-
 man/label_parsed.Rd                                |   29 -
 man/label_value.Rd                                 |   28 -
 man/label_wrap_gen.Rd                              |   18 -
 man/labeller.Rd                                    |  129 +-
 man/labellers.Rd                                   |  118 ++
 man/labs.Rd                                        |    8 +-
 man/last_plot.Rd                                   |    2 +-
 man/layer.Rd                                       |   44 +-
 man/limits.Rd                                      |    4 +-
 man/{xylim.Rd => lims.Rd}                          |   34 +-
 man/luv_colours.Rd                                 |   19 +
 man/map_data.Rd                                    |   13 +-
 man/margin.Rd                                      |   24 +
 man/mean_se.Rd                                     |    2 +-
 man/midwest.Rd                                     |   20 +-
 man/movies.Rd                                      |   39 -
 man/mpg.Rd                                         |   24 +-
 man/msleep.Rd                                      |   33 +-
 man/opts.Rd                                        |   15 -
 man/plot-templates.Rd                              |   32 -
 man/position_dodge.Rd                              |   46 +-
 man/position_fill.Rd                               |   45 -
 man/position_identity.Rd                           |   21 +-
 man/position_jitter.Rd                             |   41 +-
 man/position_jitterdodge.Rd                        |   16 +-
 man/position_nudge.Rd                              |   37 +
 man/position_stack.Rd                              |   53 +-
 man/presidential.Rd                                |    6 +-
 man/print.ggplot.Rd                                |    9 +-
 man/print.ggproto.Rd                               |   23 +
 man/qplot.Rd                                       |   86 +-
 man/reexports.Rd                                   |   27 +
 man/rel.Rd                                         |    7 +-
 man/remove_missing.Rd                              |   29 +
 man/resolution.Rd                                  |    2 +-
 man/rweave.Rd                                      |   19 -
 man/scale_alpha.Rd                                 |    8 +-
 man/scale_area.Rd                                  |   21 -
 man/scale_brewer.Rd                                |  103 +-
 man/scale_continuous.Rd                            |  146 +-
 man/scale_date.Rd                                  |  171 +-
 man/scale_datetime.Rd                              |   88 -
 man/scale_discrete.Rd                              |   31 +-
 man/scale_gradient.Rd                              |  145 +-
 man/scale_gradient2.Rd                             |  114 --
 man/scale_gradientn.Rd                             |   93 -
 man/scale_grey.Rd                                  |   41 +-
 man/scale_hue.Rd                                   |   47 +-
 man/scale_identity.Rd                              |   35 +-
 man/scale_linetype.Rd                              |   14 +-
 man/scale_manual.Rd                                |    7 +-
 man/scale_shape.Rd                                 |   10 +-
 man/scale_size.Rd                                  |   94 +-
 man/scale_size_area.Rd                             |   24 -
 man/seals.Rd                                       |    8 +-
 man/should_stop.Rd                                 |    2 +-
 man/stat_abline.Rd                                 |   37 -
 man/stat_bin.Rd                                    |   81 -
 man/stat_bin2d.Rd                                  |   69 -
 man/stat_bindot.Rd                                 |   82 -
 man/stat_binhex.Rd                                 |   64 -
 man/stat_boxplot.Rd                                |   56 -
 man/stat_contour.Rd                                |   85 -
 man/stat_density.Rd                                |  126 --
 man/stat_density2d.Rd                              |   84 -
 man/stat_ecdf.Rd                                   |   32 +-
 man/stat_ellipse.Rd                                |   51 +-
 man/stat_function.Rd                               |   50 +-
 man/stat_hline.Rd                                  |   37 -
 man/stat_identity.Rd                               |   24 +-
 man/stat_qq.Rd                                     |   71 +-
 man/stat_quantile.Rd                               |   80 -
 man/stat_smooth.Rd                                 |  136 --
 man/stat_spoke.Rd                                  |   49 -
 man/stat_sum.Rd                                    |   79 -
 man/stat_summary.Rd                                |  159 +-
 man/stat_summary2d.Rd                              |   62 -
 man/stat_summary_2d.Rd                             |   92 +
 man/stat_summary_hex.Rd                            |   60 -
 man/stat_unique.Rd                                 |   19 +-
 man/stat_vline.Rd                                  |   37 -
 man/stat_ydensity.Rd                               |   68 -
 man/summary.ggplot.Rd                              |    6 +-
 man/theme.Rd                                       |   65 +-
 man/theme_blank.Rd                                 |   29 -
 man/theme_update.Rd                                |   18 +-
 man/transform_position.Rd                          |   19 +
 man/translate_qplot_base.Rd                        |    2 +-
 man/translate_qplot_ggplot.Rd                      |    3 +-
 man/translate_qplot_gpl.Rd                         |   59 -
 man/translate_qplot_lattice.Rd                     |   10 +-
 man/txhousing.Rd                                   |   26 +
 man/update_defaults.Rd                             |   10 +-
 man/update_element.Rd                              |   46 -
 man/update_labels.Rd                               |    4 +-
 man/waiver.Rd                                      |    2 +-
 man/zeroGrob.Rd                                    |    2 +-
 tests/{test-all.R => testthat.R}                   |    2 +-
 {inst/tests => tests/testthat}/helper-plot-data.r  |   14 +-
 tests/testthat/test-aes-grouping.r                 |   44 +
 tests/testthat/test-aes-setting.r                  |   17 +
 tests/testthat/test-aes.r                          |   60 +
 tests/testthat/test-annotate.r                     |   28 +
 tests/testthat/test-boxplot.r                      |   40 +
 tests/testthat/test-build.r                        |   51 +
 {inst/tests => tests/testthat}/test-coord-polar.r  |   11 +-
 {inst/tests => tests/testthat}/test-coord-train.r  |   20 +-
 {inst/tests => tests/testthat}/test-data.r         |   14 +-
 {inst/tests => tests/testthat}/test-dotplot.r      |   33 +-
 tests/testthat/test-empty-data.r                   |   97 +
 {inst/tests => tests/testthat}/test-facet-.r       |   40 +-
 tests/testthat/test-facet-labels.r                 |  149 ++
 {inst/tests => tests/testthat}/test-facet-layout.r |   62 +-
 {inst/tests => tests/testthat}/test-facet-locate.r |   46 +-
 {inst/tests => tests/testthat}/test-fortify.r      |    2 +-
 tests/testthat/test-function-args.r                |   71 +
 tests/testthat/test-geom-rule.R                    |   34 +
 tests/testthat/test-geom-text.R                    |   33 +
 tests/testthat/test-geom-violin.R                  |   27 +
 tests/testthat/test-ggsave.R                       |   59 +
 tests/testthat/test-guides.R                       |   10 +
 {inst/tests => tests/testthat}/test-labels.r       |    0
 tests/testthat/test-layer.r                        |   34 +
 tests/testthat/test-munch.r                        |   51 +
 {inst/tests => tests/testthat}/test-qplot.r        |    0
 tests/testthat/test-range.r                        |   24 +
 tests/testthat/test-sanitise-dim.r                 |   34 +
 {inst/tests => tests/testthat}/test-scale-manual.r |   15 +-
 tests/testthat/test-scales-breaks-labels.r         |  257 +++
 {inst/tests => tests/testthat}/test-scales.r       |   51 +-
 tests/testthat/test-stat-bin.R                     |   41 +
 tests/testthat/test-stat-bin2d.R                   |   31 +
 tests/testthat/test-stat-density.R                 |   13 +
 tests/testthat/test-stat-density2d.R               |   17 +
 tests/testthat/test-stat-sum.R                     |   43 +
 tests/testthat/test-stats-function.r               |   25 +
 tests/testthat/test-stats.r                        |   13 +
 {inst/tests => tests/testthat}/test-theme.r        |   75 +-
 tests/testthat/test-utilities.r                    |   29 +
 vignettes/car.png                                  |  Bin 0 -> 1987 bytes
 vignettes/development.Rmd                          |  263 ---
 vignettes/extending-ggplot2.Rmd                    |  547 ++++++
 vignettes/ggplot2-specs.Rmd                        |  168 ++
 vignettes/release.Rmd                              |  107 -
 502 files changed, 21149 insertions(+), 19452 deletions(-)

diff --git a/DESCRIPTION b/DESCRIPTION
index 9840f4c..40b5cf6 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,88 +1,85 @@
 Package: ggplot2
-Type: Package
-Title: An Implementation of the Grammar of Graphics
-Version: 1.0.1
+Version: 2.0.0
 Authors at R: c(
-    person("Hadley", "Wickham", role = c("aut", "cre"), email = "h.wickham at gmail.com"),
-    person("Winston", "Chang", role = "aut", email = "winston at stdout.org")
+    person("Hadley", "Wickham", , "hadley at rstudio.com", c("aut", "cre")),
+    person("Winston", "Chang", , "winston at rstudio.com", "aut"),
+    person("RStudio", role = "cph")
     )
-Description: An implementation of the grammar of graphics
-    in R. It combines the advantages of both base and
-    lattice graphics: conditioning and shared axes are
-    handled automatically, and you can still build up a
-    plot step by step from multiple data sources. It also
-    implements a sophisticated multidimensional
-    conditioning system and a consistent interface to map
-    data to aesthetic attributes. See http://ggplot2.org
-    for more information, documentation and examples.
-Depends: R (>= 2.14), stats, methods
-Imports: plyr (>= 1.7.1), digest, grid, gtable (>= 0.1.1), reshape2,
-        scales (>= 0.2.3), proto, MASS
-Suggests: quantreg, Hmisc, mapproj, maps, hexbin, maptools, multcomp,
-        nlme, testthat, knitr, mgcv
-VignetteBuilder: knitr
+Title: An Implementation of the Grammar of Graphics
+Description: An implementation of the grammar of graphics in R. It combines the
+    advantages of both base and lattice graphics: conditioning and shared axes
+    are handled automatically, and you can still build up a plot step by step
+    from multiple data sources. It also implements a sophisticated
+    multidimensional conditioning system and a consistent interface to map
+    data to aesthetic attributes. See http://ggplot2.org for more information,
+    documentation and examples.
+Depends: R (>= 2.14)
+Imports: digest, grid, gtable (>= 0.1.1), MASS, plyr (>= 1.7.1),
+        reshape2, scales (>= 0.3.0), stats
+Suggests: ggplot2movies, hexbin, Hmisc, mapproj, maps, maptools, mgcv,
+        multcomp, nlme, testthat, quantreg, knitr
 Enhances: sp
 License: GPL-2
 URL: http://ggplot2.org, https://github.com/hadley/ggplot2
 BugReports: https://github.com/hadley/ggplot2/issues
 LazyData: true
-Collate: 'aaa-.r' 'aaa-constants.r' 'aes-calculated.r'
+Collate: 'ggproto.r' 'aaa-.r' 'aes-calculated.r'
         'aes-colour-fill-alpha.r' 'aes-group-order.r'
-        'aes-linetype-size-shape.r' 'aes-position.r' 'aes.r' 'geom-.r'
-        'annotation-custom.r' 'annotation-logticks.r' 'geom-polygon.r'
-        'geom-map.r' 'annotation-map.r' 'geom-raster.r'
-        'annotation-raster.r' 'annotation.r' 'autoplot.r' 'bench.r'
-        'coord-.r' 'coord-cartesian-.r' 'coord-fixed.r' 'coord-flip.r'
+        'aes-linetype-size-shape.r' 'aes-position.r' 'utilities.r'
+        'aes.r' 'legend-draw.r' 'geom-.r' 'annotation-custom.r'
+        'annotation-logticks.r' 'geom-polygon.r' 'geom-map.r'
+        'annotation-map.r' 'geom-raster.r' 'annotation-raster.r'
+        'annotation.r' 'autoplot.r' 'bench.r' 'coord-.r'
+        'coord-cartesian-.r' 'coord-fixed.r' 'coord-flip.r'
         'coord-map.r' 'coord-munch.r' 'coord-polar.r'
-        'coord-quickmap.R' 'coord-transform.r' 'facet-.r'
+        'coord-quickmap.R' 'coord-transform.r' 'data.R' 'facet-.r'
         'facet-grid-.r' 'facet-labels.r' 'facet-layout.r'
         'facet-locate.r' 'facet-null.r' 'facet-viewports.r'
         'facet-wrap.r' 'fortify-lm.r' 'fortify-map.r'
-        'fortify-multcomp.r' 'fortify-spatial.r' 'fortify.r'
-        'geom-abline.r' 'geom-bar-.r' 'geom-bar-histogram.r'
-        'geom-bin2d.r' 'geom-blank.r' 'geom-boxplot.r'
-        'geom-crossbar.r' 'geom-defaults.r' 'geom-dotplot.r'
-        'geom-error.r' 'geom-errorh.r' 'geom-freqpoly.r' 'geom-hex.r'
-        'geom-hline.r' 'geom-linerange.r' 'geom-path-.r'
-        'geom-path-contour.r' 'geom-path-density2d.r'
-        'geom-path-line.r' 'geom-path-step.r' 'geom-point-.r'
-        'geom-point-jitter.r' 'geom-pointrange.r' 'geom-quantile.r'
-        'geom-rect.r' 'geom-ribbon-.r' 'geom-ribbon-density.r'
-        'geom-rug.r' 'geom-segment.r' 'geom-smooth.r' 'geom-text.r'
-        'geom-tile.r' 'geom-violin.r' 'geom-vline.r' 'ggplot2.r'
-        'grob-absolute.r' 'grob-dotstack.r' 'grob-null.r'
-        'guide-colorbar.r' 'guide-legend.r' 'guides-.r' 'guides-axis.r'
-        'guides-grid.r' 'labels.r' 'layer.r' 'limits.r' 'panel.r'
-        'plot-build.r' 'plot-construction.r' 'plot-last.r'
-        'plot-render.r' 'plot.r' 'position-.r' 'position-collide.r'
-        'position-dodge.r' 'position-fill.r' 'position-identity.r'
-        'position-jitter.r' 'position-jitterdodge.R' 'position-stack.r'
-        'quick-plot.r' 'save.r' 'scale-.r' 'scale-alpha.r'
-        'scale-area.r' 'scale-brewer.r' 'scale-continuous.r'
-        'scale-date.r' 'scale-datetime.r' 'scale-discrete-.r'
-        'scale-gradient.r' 'scale-gradient2.r' 'scale-gradientn.r'
-        'scale-grey.r' 'scale-hue.r' 'scale-identity.r'
-        'scale-linetype.r' 'scale-manual.r' 'scale-shape.r'
-        'scale-size.r' 'scales-.r' 'stat-.r' 'stat-bin.r'
-        'stat-bin2d.r' 'stat-bindot.r' 'stat-binhex.r' 'stat-boxplot.r'
-        'stat-contour.r' 'stat-density-2d.r' 'stat-density.r'
-        'stat-ecdf.r' 'stat-ellipse.R' 'stat-function.r'
-        'stat-identity.r' 'stat-qq.r' 'stat-quantile.r'
-        'stat-smooth-methods.r' 'stat-smooth.r' 'stat-spoke.r'
-        'stat-sum.r' 'stat-summary-2d.r' 'stat-summary-hex.r'
-        'stat-summary.r' 'stat-unique.r' 'stat-vline.r'
-        'stat-ydensity.r' 'summary.r' 'templates.r' 'theme-defaults.r'
-        'theme-elements.r' 'theme.r' 'translate-qplot-base.r'
-        'translate-qplot-ggplot.r' 'translate-qplot-gpl.r'
+        'fortify-multcomp.r' 'fortify-spatial.r' 'fortify.r' 'stat-.r'
+        'geom-abline.r' 'geom-rect.r' 'geom-bar.r' 'geom-bin2d.r'
+        'geom-blank.r' 'geom-boxplot.r' 'geom-path.r' 'geom-contour.r'
+        'geom-count.r' 'geom-crossbar.r' 'geom-segment.r'
+        'geom-curve.r' 'geom-defaults.r' 'geom-ribbon.r'
+        'geom-density.r' 'geom-density2d.r' 'geom-dotplot.r'
+        'geom-errorbar.r' 'geom-errorbarh.r' 'geom-freqpoly.r'
+        'geom-hex.r' 'geom-histogram.r' 'geom-hline.r' 'geom-jitter.r'
+        'geom-label.R' 'geom-linerange.r' 'geom-point.r'
+        'geom-pointrange.r' 'geom-quantile.r' 'geom-rug.r'
+        'geom-smooth.r' 'geom-spoke.r' 'geom-text.r' 'geom-tile.r'
+        'geom-violin.r' 'geom-vline.r' 'ggplot2.r' 'grob-absolute.r'
+        'grob-dotstack.r' 'grob-null.r' 'grouping.r' 'guide-colorbar.r'
+        'guide-legend.r' 'guides-.r' 'guides-axis.r' 'guides-grid.r'
+        'labels.r' 'layer.r' 'limits.r' 'margins.R' 'panel.r'
+        'plot-build.r' 'plot-construction.r' 'plot-last.r' 'plot.r'
+        'position-.r' 'position-collide.r' 'position-dodge.r'
+        'position-fill.r' 'position-identity.r' 'position-jitter.r'
+        'position-jitterdodge.R' 'position-nudge.R' 'position-stack.r'
+        'quick-plot.r' 'range.r' 'save.r' 'scale-.r' 'scale-alpha.r'
+        'scale-brewer.r' 'scale-continuous.r' 'scale-date.r'
+        'scale-discrete-.r' 'scale-gradient.r' 'scale-grey.r'
+        'scale-hue.r' 'scale-identity.r' 'scale-linetype.r'
+        'scale-manual.r' 'scale-shape.r' 'scale-size.r' 'scales-.r'
+        'stat-bin.r' 'stat-bin2d.r' 'stat-bindot.r' 'stat-binhex.r'
+        'stat-boxplot.r' 'stat-contour.r' 'stat-count.r'
+        'stat-density-2d.r' 'stat-density.r' 'stat-ecdf.r'
+        'stat-ellipse.R' 'stat-function.r' 'stat-identity.r'
+        'stat-qq.r' 'stat-quantile.r' 'stat-smooth-methods.r'
+        'stat-smooth.r' 'stat-sum.r' 'stat-summary-2d.r'
+        'stat-summary-bin.R' 'stat-summary-hex.r' 'stat-summary.r'
+        'stat-unique.r' 'stat-ydensity.r' 'summary.r'
+        'theme-defaults.r' 'theme-elements.r' 'theme.r'
+        'translate-qplot-base.r' 'translate-qplot-ggplot.r'
         'translate-qplot-lattice.r' 'utilities-break.r'
-        'utilities-grid.r' 'utilities-help.r' 'utilities-layer.r'
-        'utilities-matrix.r' 'utilities-resolution.r'
-        'utilities-table.r' 'utilities.r' 'xxx-digest.r' 'zxx.r'
-        'zzz.r'
-Packaged: 2015-03-16 20:29:42 UTC; winston
-Author: Hadley Wickham [aut, cre],
-  Winston Chang [aut]
-Maintainer: Hadley Wickham <h.wickham at gmail.com>
+        'utilities-grid.r' 'utilities-help.r' 'utilities-matrix.r'
+        'utilities-resolution.r' 'utilities-table.r' 'zxx.r' 'zzz.r'
+VignetteBuilder: knitr
+RoxygenNote: 5.0.0
 NeedsCompilation: no
+Packaged: 2015-12-15 13:04:37 UTC; hadley
+Author: Hadley Wickham [aut, cre],
+  Winston Chang [aut],
+  RStudio [cph]
+Maintainer: Hadley Wickham <hadley at rstudio.com>
 Repository: CRAN
-Date/Publication: 2015-03-17 17:49:38
+Date/Publication: 2015-12-18 10:45:15
diff --git a/MD5 b/MD5
index 21309b7..162ed7d 100644
--- a/MD5
+++ b/MD5
@@ -1,421 +1,403 @@
-f2a2e096c4a77dedf8be1d4ebd4aeffc *DESCRIPTION
-a547378bfa6653abc57990e2cc948a5a *NAMESPACE
-56c6bbf3282171cec48a64032d434e4c *NEWS
-f619b0ed74903b4c2418c5c6e46e370c *R/aaa-.r
-dc3d3aab5c3802286ba7ad449eb6645d *R/aaa-constants.r
-437908a74682d578f7eb223c8ed863ba *R/aes-calculated.r
-334f021337c8c344810d57a74b0be07a *R/aes-colour-fill-alpha.r
-173e513577570948eb00a5ac883358f6 *R/aes-group-order.r
-cd3be935c62fff91d804b5de7b617082 *R/aes-linetype-size-shape.r
-db5b22d2da805d40e1b3d3314d259f22 *R/aes-position.r
-418cbbe4cd2fa4705ea9f19dd230e310 *R/aes.r
-8f0bc9fb0ea389b093b66dd29ea3eae6 *R/annotation-custom.r
-466f11d4b6932c2743166c594db6eae6 *R/annotation-logticks.r
-0cd85d549020a22ff0e356fc9c52294c *R/annotation-map.r
-c09a4fd2a87dc99b85fe56a03e230f28 *R/annotation-raster.r
-28be5bf186120cf1cf4f54e763e4c7e3 *R/annotation.r
-2e7da6e309c0d9a583c19e034f8439bc *R/autoplot.r
-002d571b02b862da365019e5ad665947 *R/bench.r
-b4b4e57c494cb5f702594197864adf0b *R/coord-.r
-4683128fa78f31064204ded093ff2766 *R/coord-cartesian-.r
-3138096ebcab95e7367f19bc5b03b436 *R/coord-fixed.r
-6b31f68b65f0b819995a1e98f99cdc94 *R/coord-flip.r
-07a80006b5cc63201bdd9faa76e5d748 *R/coord-map.r
-3cae8e956b77a36e051830619960f7cb *R/coord-munch.r
-d95e60b9e7640efec0339a193552daf9 *R/coord-polar.r
-5303b40f6b4ac06b0000e038abb47dfc *R/coord-quickmap.R
-56c4dee9e75c15c297b484a0d91b46eb *R/coord-transform.r
+128c13758924244b835c69aed44c94a7 *DESCRIPTION
+c6f6758c306983417f8c23f0d038525a *NAMESPACE
+7171046778fbb6a06b96a48bb9c6cb75 *R/aaa-.r
+41c9ba0c55c5b2dac5c2ba80a9e6f0f0 *R/aes-calculated.r
+a744d7b67886c9a66068cffb5e71699a *R/aes-colour-fill-alpha.r
+d901c095dc98fd19f788ed7814152f8d *R/aes-group-order.r
+53f129179804c8dbeb9a5fba52d5b056 *R/aes-linetype-size-shape.r
+9b2ae79db47a3528738807199529ff3c *R/aes-position.r
+fa764c0f3d99ed90d728bbf57c41e186 *R/aes.r
+7197b034fc85230edffc479af5cd1f5d *R/annotation-custom.r
+1c56152690873e5cb80a9ede93222a45 *R/annotation-logticks.r
+23a65ca6c3e4ce2ffa1d11b94171e524 *R/annotation-map.r
+39f637bb6e438cfbe001e2f86eedc1f2 *R/annotation-raster.r
+61cd6012d06c8f01a7574f7bf48bfc31 *R/annotation.r
+eb4a7f643fd1a9c47fb64ed576a10e87 *R/autoplot.r
+57939239ee7146de73a2aba6de11f5a0 *R/bench.r
+8081549496f51360a79570c233a1929f *R/coord-.r
+7f06acc0754ed9be0e8499cf393c1d25 *R/coord-cartesian-.r
+09cadc86b4cc436f073d468b5024b7bc *R/coord-fixed.r
+c7a07694ef7c686f232fe3c0ba4e673a *R/coord-flip.r
+0dd48578dbceafa78fc2e170032790a2 *R/coord-map.r
+3cd117fab4fb175c188202dc7078b951 *R/coord-munch.r
+5a85a120c7c97d7528035e105a76a24b *R/coord-polar.r
+e042de925de133ab9978221438997b4e *R/coord-quickmap.R
+5b7efc37f850dba08b4dffb964122000 *R/coord-transform.r
+d38997c46c827930f845c5f239aff407 *R/data.R
 1cc34cbdb97662693545d1f09f53c080 *R/facet-.r
-580691f36d9eeff2389ba8846b5939b4 *R/facet-grid-.r
-9b12151f5570c6425ef26b61817bf9a5 *R/facet-labels.r
-ee052f06a431f3d7398363e7e3e95d99 *R/facet-layout.r
-3237a0155df325b5f839c2aa77ebb8c8 *R/facet-locate.r
-0fccaf52ac692a2536b9a5d7a04618fb *R/facet-null.r
-7c2d0996eee3e6b0b592f190086e05ed *R/facet-viewports.r
-5e7ef96ae8241158c87545ec18c21067 *R/facet-wrap.r
-aaa3fc7bb671c4b504f4a00e50640e98 *R/fortify-lm.r
-dc79c0352642bbea357b7640fb91933d *R/fortify-map.r
-74311415c2f72fbd804da74a7e0f97b4 *R/fortify-multcomp.r
-0db845f2fd75d6f4c723bce803cac463 *R/fortify-spatial.r
-b16daaa3a96ef6da619b3a27db789504 *R/fortify.r
-2eba55e1d2236ca737f662d8aae4d729 *R/geom-.r
-89029b74dfe36d80f6660e58d0a8f43c *R/geom-abline.r
-73ee231468fd5419e5c3a812e52aea6d *R/geom-bar-.r
-c4191294aba5be8a2950401c74b05b8b *R/geom-bar-histogram.r
-7ac893cece36513f1f68d5af9bce6407 *R/geom-bin2d.r
-797a0761fcd2b4150b6d3a959f78137a *R/geom-blank.r
-0dad76ee22dd7dc122938cd9a32c1d45 *R/geom-boxplot.r
-838b60d4df9e0b9cb254f0bfcabee6b3 *R/geom-crossbar.r
-6f76afb959cf4de6c5393ab30007b4e6 *R/geom-defaults.r
-5aa9371ced151ed66d3526fa846108c8 *R/geom-dotplot.r
-9b015b902ec0cdbd7183c05213ec1f4f *R/geom-error.r
-32b5c79d2f1631552a0aeda040e74a2b *R/geom-errorh.r
-de9028d2868412479685ab1a56dcd520 *R/geom-freqpoly.r
-116ecbafcedc284ce078ce906b86b7d5 *R/geom-hex.r
-e2e5efc4758fc52183b0521e9715d2ad *R/geom-hline.r
-dfa8fd5027a398a6bfdc95420c471ad8 *R/geom-linerange.r
-532eb327b4c056506b6649df9cb04682 *R/geom-map.r
-854bd32e6cb03241278ac9619f81cffa *R/geom-path-.r
-8cd868ce8b0403868e3f48dbb6e6925e *R/geom-path-contour.r
-3498d5f68d59a4314d2d5ee7444ee55d *R/geom-path-density2d.r
-4d88e896ed0324a7c81a65039f709f26 *R/geom-path-line.r
-eafcf3374d4169c1f13a57fbb4fc21bb *R/geom-path-step.r
-aaee5da813a00b7c289148d021779116 *R/geom-point-.r
-0a22af9812a4dfebc0592035b3e2a8a8 *R/geom-point-jitter.r
-daf31eae92cdb40077ba12c7ed8bcf5b *R/geom-pointrange.r
-c69833ed42949f88ceff97f23b262c82 *R/geom-polygon.r
-328eb9f974aa1cc45bd2adccc1f672e1 *R/geom-quantile.r
-e9c122841a2b04ea88d927ac9142fecc *R/geom-raster.r
-25aa195ff8d6fae219db9afa3dc9958a *R/geom-rect.r
-f80372ab7b9b0c779dae329e4b6e9c47 *R/geom-ribbon-.r
-d5a97849e493fe2e4c2f3a324b374b56 *R/geom-ribbon-density.r
-177470afc369a077d12a87587d121cad *R/geom-rug.r
-fec5c5228d49615ef159fd3c2c4f3a49 *R/geom-segment.r
-aefdb484bdc794d89197bd1e92b1d5b0 *R/geom-smooth.r
-97e73dd29928a218132dcefa6fd38d0b *R/geom-text.r
-b7798c5d38d9b51a119e17f7178d5487 *R/geom-tile.r
-adb729cebdfe71e1cb0ee93e2c825248 *R/geom-violin.r
-ed7e61ce71f1d2c676d459f2eb48819c *R/geom-vline.r
-93380c43b85735ebfb3c8a558b164d94 *R/ggplot2.r
-9ecf3ee0f58c470cff0b94b4b2b4c483 *R/grob-absolute.r
-a92d5cd7213cc67efd8d5eb261da363c *R/grob-dotstack.r
-1df573f9a098435be0d8a5f4bd1139db *R/grob-null.r
-ea8d7bba70a3843d781419db4fb14b0f *R/guide-colorbar.r
-30717872bb105da8e2c71ce08c4e4555 *R/guide-legend.r
-df9873781cc0c4017ac0672e51ed7011 *R/guides-.r
-8b21d8b40e32e982429a6817db86f17d *R/guides-axis.r
-49c53870378098a3523f3ac48df86b43 *R/guides-grid.r
-18ba5f8c124934c35b9fcb471212477e *R/labels.r
-27ab5d6c1b82bd9ea682260d05a9f739 *R/layer.r
-e40ae7451b7eb711ca65bfb2e6b289dc *R/limits.r
-40fb5a4aa9d14ecf34f219c570520004 *R/panel.r
-a880b6457f54f07c749458de66e99005 *R/plot-build.r
-eac13dd299a1a608f0e02024a5e2deb8 *R/plot-construction.r
+3f8b216d933c934fea5407033678b5e6 *R/facet-grid-.r
+455f53f8eeafdb025e1923f8fafc1105 *R/facet-labels.r
+bf8ddb7258fdc55f31454b5f6b82ab1e *R/facet-layout.r
+10fead8ab5f75e313766eef213ca175d *R/facet-locate.r
+9fabb1104100303c97d6132cf7aceb64 *R/facet-null.r
+97efe28b15c4317698b0ec49e5c2b279 *R/facet-viewports.r
+d2e160b5c7f9037554062df1ce3a274b *R/facet-wrap.r
+185ec0bbe6e5fb2900d3bcb8b3a98947 *R/fortify-lm.r
+5ab10594c4dae94d6118c0a2655d5736 *R/fortify-map.r
+1e6a486f18bfe39121a436f47922f67c *R/fortify-multcomp.r
+c48d8fa6657357fbaaca6335107e0fc9 *R/fortify-spatial.r
+4f2c97115990bc2a207aa4cb1d54ae45 *R/fortify.r
+045b781a9d085ecbd8f6fbd6fc14ce8c *R/geom-.r
+af5f4983deed90c750742a47190d4bc4 *R/geom-abline.r
+87f066dc91ba0cce9b707a412380bd4c *R/geom-bar.r
+5acd1dfba0920f7bc074c3b97a9a49c3 *R/geom-bin2d.r
+32e1513b9e272076f40db4989a0124c1 *R/geom-blank.r
+807f7c8a54d5cb65ba518ad6abd2a579 *R/geom-boxplot.r
+e647994ca5e70887fca98af44e0082e1 *R/geom-contour.r
+5e0493d8775001ac459c2d6efb6b0821 *R/geom-count.r
+842f2e7f5d39d180dd3d9a7a51914ed3 *R/geom-crossbar.r
+60b7162c3ab48cee151496229a820b32 *R/geom-curve.r
+55172848e9beb54df54b8d6d2d2f91ae *R/geom-defaults.r
+f1298f9045e22ac4799c23205c62440a *R/geom-density.r
+a349028790f849972489c2d65f3f9ce8 *R/geom-density2d.r
+dfa78318176fbc810488bda4231b0856 *R/geom-dotplot.r
+f06b64fc0383b9b48ff468d0325a5438 *R/geom-errorbar.r
+2593f86192e79334bc9e29ebb3ae1674 *R/geom-errorbarh.r
+36d7c7bee86501f609fc799081852f0a *R/geom-freqpoly.r
+1deee106b67853189207fb765d388376 *R/geom-hex.r
+cdfe6e9751445c5e20f51aad0f909796 *R/geom-histogram.r
+fd337aca62b5bc57c6cdb9463a22d22b *R/geom-hline.r
+b7855c6dd4d98aecd805621a9e65f49c *R/geom-jitter.r
+29b89a9cdb090bd89a4bcd1d042f3d2e *R/geom-label.R
+74e854863fe5d088782bf0fb828a3d92 *R/geom-linerange.r
+d70b6e894ae2eb0161de5b5cb3986c65 *R/geom-map.r
+f2fcfe75931bb242a205d2a1f4630e24 *R/geom-path.r
+8cc237ce23b928aa87b1e58c74f5d607 *R/geom-point.r
+62eeb8af6b42aec1b772d3fcf63f2fd0 *R/geom-pointrange.r
+09143a1f81d3422e5ead8a6ef39db9eb *R/geom-polygon.r
+d3eb045bf5cf536cee2d68428b365451 *R/geom-quantile.r
+7ea959a7d466659333a8c1398edf624b *R/geom-raster.r
+3117863095c2652d0c61609c47e304e8 *R/geom-rect.r
+c1d8b2f823b4c5c6c2bdad80768e61e2 *R/geom-ribbon.r
+19bc5cc0f8b3c8bf49a65039bf9d6fb2 *R/geom-rug.r
+f6d8792e03c246a5398c5e623237c221 *R/geom-segment.r
+616550b16de176986b8d76d56ff7bb83 *R/geom-smooth.r
+2b93a744cc60d182de6554aebc2f2a94 *R/geom-spoke.r
+ee049b1fa8922d3492401cc7554c71ba *R/geom-text.r
+945dadbab75c776e940086f27ac49ec6 *R/geom-tile.r
+c078dd69473252fcf572d48eda009b2e *R/geom-violin.r
+6aaa2cb92cda27382ff4b613a8f646cc *R/geom-vline.r
+7fbb4a1b3a36deea08d5990dc9b82bb6 *R/ggplot2.r
+070781ab73a3e2cf5ea10abe2dd044fd *R/ggproto.r
+abe3e869859c7f73fa4a9721df2ef29e *R/grob-absolute.r
+57c5dee7337f17082fde9a43d071cc2c *R/grob-dotstack.r
+95d44bd0d180dca5892db5674bec6362 *R/grob-null.r
+a432566834bd4321476e8c8e1a5993f6 *R/grouping.r
+a81c889fb0d614d49262f7f627c6d314 *R/guide-colorbar.r
+791c3a32f35493bf109ecd6264d39acb *R/guide-legend.r
+4ffffa04a45a0fdc98d0b4a86b3964fd *R/guides-.r
+a6a7662bace821f91da3ababf1f42c11 *R/guides-axis.r
+91319825178764869b02d5ed527637e8 *R/guides-grid.r
+09651c30b88b748c5b7da7a41efbcd49 *R/labels.r
+ba4a38bde128d1edf27891aba63596a9 *R/layer.r
+cb041a872c511f7508ccf9e0b7a2b68e *R/legend-draw.r
+22ac4e1d41ee5809fd19a21347000af6 *R/limits.r
+7a443f2662cd5ad7545d6fed891e2dd6 *R/margins.R
+3e7952b15074bc30956d1e77c286d724 *R/panel.r
+0b477c5a9747234a69c00ba335675e05 *R/plot-build.r
+929aa868d774ed75060e6d45fc5c1ea3 *R/plot-construction.r
 e7d2e29ecfc09bffcf8518894eec414b *R/plot-last.r
-c98775ee91cac1e88e2bf526529ea79e *R/plot-render.r
-2fc63b9c8af17e00d71d183117483833 *R/plot.r
-d1d036c42de52bd227e173e536a8117d *R/position-.r
-7c712c4a10f5e82b89cb25813940e725 *R/position-collide.r
-9122c08241b1d6a6dc6acc97d43fa55f *R/position-dodge.r
-dd3d6309b06152f9e0f109bb596fb5b6 *R/position-fill.r
-adefea880e0fdcd381d48eb397dacbaf *R/position-identity.r
-7eca3412b594ecdbb6fd157d5c37dd39 *R/position-jitter.r
-9bbaa6b648c2241e5956dca5e2a6d250 *R/position-jitterdodge.R
-d23f824339cb7cb1dead47c71cc68aa8 *R/position-stack.r
-34b96125d8448a5f5b46f1246dd6dcc6 *R/quick-plot.r
-bbc3613dbfe61c759ad95f891dcb155c *R/save.r
-2390cffcbacd27b4f738c3dda829db9a *R/scale-.r
-3cf8ae7ae428a496151ac12c00246c35 *R/scale-alpha.r
-2af0ecc1ad18ed8b8074d259835d2767 *R/scale-area.r
-3aa82d13974ee266d63d88f1eb170f8a *R/scale-brewer.r
-71ddaadd63f1a81132f1d7cfd97388c1 *R/scale-continuous.r
-f73a89c5213beab09846a7958f8850c0 *R/scale-date.r
-165796cac80658af2524b9f7118c0507 *R/scale-datetime.r
-b8010c01da84c6e434cd3bb8a0c0dd03 *R/scale-discrete-.r
-c8f38cac586662e423824a5f8de4e80e *R/scale-gradient.r
-0fee5d5e99888e66b7b74428abcf615b *R/scale-gradient2.r
-7b70d88e128f6c707e619dafb6637641 *R/scale-gradientn.r
-44e0d7b7b33f43a4ce5b172a0d45a3c6 *R/scale-grey.r
-4684519e905cc620580296d3b4bd4620 *R/scale-hue.r
-2ce4d8bf820d32f331e2a00b7f232c86 *R/scale-identity.r
-5518b49ebaef372bf32bba55771fc4ab *R/scale-linetype.r
-7efacd05dceb31b0cc7bb6e78347fdfa *R/scale-manual.r
-1f31154c84baeafffdefda6101df6e8f *R/scale-shape.r
-21cd9e75546deacf869ae68654d21641 *R/scale-size.r
-c986df3b9231146a05c3548c1bf665ea *R/scales-.r
-91503213da0b0a4fba4fd80650783f71 *R/stat-.r
-f9bd6fb941a19c25d7ac748c87fcd820 *R/stat-bin.r
-a747eae385ccf605a6572a549bb3b272 *R/stat-bin2d.r
-3b15d2033f30c902ae8282733dad7433 *R/stat-bindot.r
-7d398fa1b6d3352101bb5539cfb2f784 *R/stat-binhex.r
-47e9cce7592903970fe666470497ffaa *R/stat-boxplot.r
-35ea3c58d577163cc70120abc29abd19 *R/stat-contour.r
-4d9fde8e9b9f145b3723a7fc5d145af2 *R/stat-density-2d.r
-1aa16c6faa97d62cf39915c0bd70be4c *R/stat-density.r
-8eb465733148a29108da357c691b75dc *R/stat-ecdf.r
-fed06a28a53b3294c3470adb691b96d7 *R/stat-ellipse.R
-adccc25e424f422bbd1ac4cfb44e44bc *R/stat-function.r
-c66776fb2e2d75dade61ab65988bd442 *R/stat-identity.r
-843729a267306bed15774602b7da1df0 *R/stat-qq.r
-f67e69db4d9761022835b61fed1a49c7 *R/stat-quantile.r
-7fa079e08b611c22763856d1977c7237 *R/stat-smooth-methods.r
-280a616cba1c28a66282399b7ec628bc *R/stat-smooth.r
-f2c556e4fed9ee698ca0cda10e4877b2 *R/stat-spoke.r
-20911610c78693674e865668226bdf2e *R/stat-sum.r
-aec239677a41aec83e5daa5495bd7e7d *R/stat-summary-2d.r
-0b057fd945dae31f50caff6716935c40 *R/stat-summary-hex.r
-45f9667778980b11ed71a60a1e85ba02 *R/stat-summary.r
-4e5d8cd311dcba7608c2c585990b85c6 *R/stat-unique.r
-f6f71512cecc01fdbb0e04fa16ff2bfe *R/stat-vline.r
-7f0ac525d2df22013edfd5fcfd5b3591 *R/stat-ydensity.r
-7eaa6b3f8b149eef3f4c663e59761ca4 *R/summary.r
-5104c1968d419c4dd5642c0c70db4027 *R/templates.r
-d4a52d63d9e4287dae9ccf701242f7c0 *R/theme-defaults.r
-10131db0cf56dd48fcccd1a2ccefb41d *R/theme-elements.r
-1b173e669c5d449e2d2eeaf9fc460d1d *R/theme.r
+c8d0ebe260e3701226750c0e8d8707a6 *R/plot.r
+636580e38110490dd2f38b09bba0152c *R/position-.r
+9bb9cfaa59dd9d64dfcf2388f4ba0cdf *R/position-collide.r
+29baf4dc9462147822635b22109fb527 *R/position-dodge.r
+d30ffc9364ffa8b08256f601b7d67fcd *R/position-fill.r
+8d8c6f5432e9f61de2fe222922b93142 *R/position-identity.r
+fe1e1022e11f937a360352a26255e8ac *R/position-jitter.r
+47c7143f55eb5b16ceaaa97b12c583f5 *R/position-jitterdodge.R
+21b4b44525017a08e41efa0888724c01 *R/position-nudge.R
+3bf43bb214de063904c603ce4f4909d2 *R/position-stack.r
+d88b979e879b28ea83929c9d410fb1bf *R/quick-plot.r
+42d7a80d2fdd0e3b2a53b58a0cbf9be9 *R/range.r
+cd3cc7621245ed40b84344a36f554435 *R/save.r
+f73c05f4e123121f6d83ee20bca85176 *R/scale-.r
+1b99c2f65e2b210e26f686a379629341 *R/scale-alpha.r
+a9d9dad9fd80dd209ebe50d8ea1d5558 *R/scale-brewer.r
+04a1eb6b2c8144a6528882dc64f95934 *R/scale-continuous.r
+61e114a0c99a03328d6dabcacc0ec9ad *R/scale-date.r
+a1aa9f1df3072a478c84df63f5aa3478 *R/scale-discrete-.r
+d577e4befed18b3306ff53f9c2a917e7 *R/scale-gradient.r
+bf1d0a9a8698b092799af1c0f966034a *R/scale-grey.r
+d0248ff685ce6bda7eba6fb9272e13dd *R/scale-hue.r
+e96f1acf5f333a0e2d3fb94ba0ac1682 *R/scale-identity.r
+7501deaed0c692d084705890995952df *R/scale-linetype.r
+6bf98c26a2f17a42134941151ef25af9 *R/scale-manual.r
+8b1c96c7b6214e45adbb96b805d2789b *R/scale-shape.r
+a10109b9f412ee7beb43bb7f607e00cb *R/scale-size.r
+ad8afa0ba9fb2fcfe7ec5f4852611d21 *R/scales-.r
+002772e3a128c3074f4d3100c9f63d9d *R/stat-.r
+97d6ba417371a436a14709de57c24d99 *R/stat-bin.r
+aff0b85ad8b4b5d75005e3d67dbe97f3 *R/stat-bin2d.r
+ee8c8631bed750cf47fe15b282174d4b *R/stat-bindot.r
+dac71107f1eda06b162b49e0f74294b4 *R/stat-binhex.r
+5b8996c2cb08ff36d428fcdeeabee8ea *R/stat-boxplot.r
+e2c5d5c372c6604ce7ed781e1b56dc69 *R/stat-contour.r
+5d0a381bf3c61f5cad1adf30c75aaa72 *R/stat-count.r
+341a44248958c77541327a07b383dd4b *R/stat-density-2d.r
+29a474e17d850a9cd5021e2ad4cbd783 *R/stat-density.r
+cfcc728918f7cdcd01959d85da3b2fba *R/stat-ecdf.r
+5c659828ce50d18248b77519e86ad8ee *R/stat-ellipse.R
+b4d52166558a1233a8e81f6df67b4dd7 *R/stat-function.r
+e2d0ceaf1188627706972441d8b1ec60 *R/stat-identity.r
+0b302a713eaa4b767f8fc8efc4e0d2c8 *R/stat-qq.r
+8a7f4804dc21330353cb541ba994ed94 *R/stat-quantile.r
+72ebe9d0bb085a8be73b6eb41c7a2752 *R/stat-smooth-methods.r
+efc5b7b102d6682b620765f0aa21eb4b *R/stat-smooth.r
+52c51464a86d459f00cd3c077f9ee627 *R/stat-sum.r
+f0f02eab3acaa7c1f3d4ca9a3ce9178b *R/stat-summary-2d.r
+4ac747a8b5be7b8bc44b166363ee8567 *R/stat-summary-bin.R
+d8b6fe46eb82f9bd01ace95823e03ec0 *R/stat-summary-hex.r
+423506c429776259467a670e78d21e56 *R/stat-summary.r
+9f3e890e1164da8732d13283e43389bc *R/stat-unique.r
+5714d97e361067084f41c4620545d714 *R/stat-ydensity.r
+c92420a879310b86c1bcbb1e6fb45425 *R/summary.r
+ab69c1ba381733ebf620dcf10b227445 *R/theme-defaults.r
+7beceb23e6e35270cdf25d7df940fedd *R/theme-elements.r
+df5cd14fbf8b04c0ff12bda88c247317 *R/theme.r
 1239cf068ccaa1a1c58d38793e91caf3 *R/translate-qplot-base.r
 b97bd5e0d2c69643142fb2b4529a0cad *R/translate-qplot-ggplot.r
-1bd070722cc8df670a421f418332430f *R/translate-qplot-gpl.r
-fc1aac2cb829de6311c21ddff4eb4b5b *R/translate-qplot-lattice.r
-feb283c70f8bcc6347beebc0b03a169e *R/utilities-break.r
-aac51c69462f8ba3a39324092ca86992 *R/utilities-grid.r
-7d2253be1f20087c6d0316d0443b73b7 *R/utilities-help.r
-08517a0c6322429c9555c3d6aba1d02e *R/utilities-layer.r
-5410fb5e04e464764ed86dc00bffc4a6 *R/utilities-matrix.r
+ad2f08f76dac34814872123de6a2654a *R/translate-qplot-lattice.r
+31fad80a907f5ec247287296b5ffa4a4 *R/utilities-break.r
+462f0313976c787cd44700fe5346439b *R/utilities-grid.r
+6f55c444360fe627ccd3669b74f122da *R/utilities-help.r
+3bef847b27dc1a7182eff846527f6fc6 *R/utilities-matrix.r
 a2f6c224351ced0c10b6f55dcd941fd3 *R/utilities-resolution.r
 e72a2689dc0d2076b7492a6ebd165b62 *R/utilities-table.r
-4df100d2cd3585c7daea8ffd9341bdd2 *R/utilities.r
-5e3565930d6b2543aa0772d2611fb34e *R/xxx-digest.r
-f93fe51f34d83c7e9736eef199216b47 *R/zxx.r
-62b43ab5691752c5156baadc1fbefa27 *R/zzz.r
-92cf5ffe3de9a67d9994ef6ab9797a6d *README.md
-a1e1772c4ea8f86d01ae2338ae541230 *build/partial.rdb
-222261e911560f229e5b947c3c93a0ca *build/vignette.rds
-9cb6a35588a5dd6989b03aece1b60e03 *data/datalist
-4096c2eeb1224845fc5f0e25e9974c25 *data/diamonds.rda
-8985076e2ad3bed814a263e66cda6536 *data/economics.rda
-3ae982c0a646d089158019dd7cff7270 *data/midwest.rda
-9d8747e779836d5c6e49034c45cf8b98 *data/movies.rda
-d4a17298bd70c76813a5413330c1cd23 *data/mpg.rda
-1617a2dd8416c15f6d258ae6cfe2baf5 *data/msleep.rda
-f11e86b50338713740fae032ed3d32bc *data/presidential.rda
-401d0becb289a0ca4b041bb64e3b8aa0 *data/seals.rda
-d5d8dadfa9a1796813880c6dd466051b *inst/CITATION
-9714b4f3166fc0b63ad1be34175febbb *inst/doc/development.R
-ca9a9bfa8225e85a1400d060568ada6a *inst/doc/development.Rmd
-4207976c1831f697eee8988da1716f9f *inst/doc/development.html
-df1ad550422fec942e9709b6a671a318 *inst/doc/release.R
-031c78a8fbe505a4ee120726f622d005 *inst/doc/release.Rmd
-99cefe067cf8f69908e640c546bd21d7 *inst/doc/release.html
+ae40757394892074687c9d11a7744f20 *R/utilities.r
+b2fdc194c563ec6312f20e74382951c6 *R/zxx.r
+9ba24b6237d2e367c3f4c30d8cd968d1 *R/zzz.r
+0eb9195324e6152acd04d0e853a8b455 *README.md
+45b569636a7954e0fe2bf7f8c9fcad99 *build/partial.rdb
+854144184597775f66eeacd20d7b0552 *build/vignette.rds
+7fd28ad1feab3e3c773313672cd1b3be *data/diamonds.rda
+1c883c4bb873c21cd428435264c456d7 *data/economics.rda
+3cc1cdb7f53ac95b7346683e44e225d1 *data/economics_long.rda
+27720de2f50f4a1fbac825226021806e *data/faithfuld.rda
+cf670e82bef3beba32bb2b4197276036 *data/luv_colours.rda
+507bdb348d1d5cf1f8a162a46055f1d7 *data/midwest.rda
+0aa41f897a20f3f952c11335d73da1a2 *data/mpg.rda
+c6d2b711873dc702d39de601f683ebdd *data/msleep.rda
+e1ef68be302f256fe79e1e2833f5f50f *data/presidential.rda
+d419c85de9cb971b7ebec959a836f72c *data/seals.rda
+2012af9687f6f5813b8aa6aa86773c67 *data/txhousing.rda
+8c412b9bcc5ff77ba07b0488ea29a79d *inst/CITATION
+3cd9eb0fa04c028287aecdac2bf95cdd *inst/doc/extending-ggplot2.R
+3ea1eef97dfdacc7cd6703ae5e1bb2ed *inst/doc/extending-ggplot2.Rmd
+cc4415dc48f5a5b6ab6701d431b5aa6e *inst/doc/extending-ggplot2.html
+fd4fffee04dfb833e03497c4701be1b4 *inst/doc/ggplot2-specs.R
+580964d5ac3b6030ddbfeb79f5123db3 *inst/doc/ggplot2-specs.Rmd
+50e57550b42bbc72e7d8be3f67dbe851 *inst/doc/ggplot2-specs.html
 d41d8cd98f00b204e9800998ecf8427e *inst/staticdocs/README.md
 7a09459ca2898424c3714a03f20665fd *inst/staticdocs/footer.html
 923198a65466326dfb62fec20e793e3c *inst/staticdocs/head.html
-a24a2d726dd6a2fa5e49c58626272d89 *inst/staticdocs/icons.R
-650e05ef6010bc7ca18e7c543c8b551e *inst/staticdocs/index.r
-866901e6be1bdbaba1c9c2d7b879e8dc *inst/test_ns/DESCRIPTION
-b21b353b8831ab5ccca59122881140d3 *inst/test_ns/NAMESPACE
-e2f433ef982d4a7577a9364adfb6c952 *inst/test_ns/R/my-plot.r
-06a9f7ef332826077bd8e50b13121112 *inst/test_ns/man/my_plot.Rd
-77945a46a6b20d19e78bf208dd8032cd *inst/tests/helper-plot-data.r
-93ddf3d657ca72d8f55339560a53ec7f *inst/tests/test-aes-grouping.r
-cc9e57a09518a730a765c21e45b5e04b *inst/tests/test-aes-setting.r
-61f07cdbec3e2551558fbe5c8a379d34 *inst/tests/test-aes.r
-196e9a7accdbb9fb1f2e13f4aece3918 *inst/tests/test-boxplot.r
-6dc1254d98d2934283c5841d0d4e7d8a *inst/tests/test-build.r
-0465e5e3f7e11018338ea4bdf774ad20 *inst/tests/test-coord-polar.r
-70db5dd20f4b1a8a0164cf522feec0fd *inst/tests/test-coord-train.r
-e1f64293358ced2a79f18dc1b336cc51 *inst/tests/test-data.r
-c4ec1dc18f683b9afdefb6ee82b4f5d2 *inst/tests/test-dotplot.r
-1b12e4284c255e898648b3e81edee1d4 *inst/tests/test-empty-data.r
-54d9d6f682eb8574e28a03ac1fef1cc6 *inst/tests/test-facet-.r
-747e7df23151f233e6c2b574a5942af6 *inst/tests/test-facet-layout.r
-8f34247aa95dfa5f50a5a0189f87bece *inst/tests/test-facet-locate.r
-38e013c546215e5d1d1d4809be98219c *inst/tests/test-fortify.r
-6318ef949123e4e13c938ffc0e3d4010 *inst/tests/test-labels.r
-a172b0ff15b8c249e0c69af0c014007c *inst/tests/test-layer.r
-972abcb47b4a68ac9f086af1c8198da9 *inst/tests/test-qplot.r
-ef9d5bdaf6d1f4560a86d7841c9d1e85 *inst/tests/test-scale-manual.r
-447ee9f3231c9fbb114dcfc888dae316 *inst/tests/test-scales-breaks-labels.r
-724df5b5fbd7cb01740cf7467e50cae9 *inst/tests/test-scales.r
-1ea4b0add6ed2f15724d58441483c1a8 *inst/tests/test-stats.r
-640dc2d0eb7ef9a9c47129a70f1ae465 *inst/tests/test-theme.r
-f3cbac27a85b4d7022031b7dfbe80e2d *inst/tests/test-utilities.r
-88e86413a6672048475b6d33c1e1cd07 *man/absoluteGrob.Rd
-70b91afd582c966da70282d1dad778c9 *man/add_theme.Rd
-9dd0b3892b27e13035b56c8aae0f1c52 *man/aes.Rd
-b2ee7a1d243ec33827bf6d34d0081228 *man/aes_all.Rd
-843313ead83e34faea79e75bf739d0cb *man/aes_auto.Rd
-d81c77deefca02ae6b6eca5be26e878b *man/aes_colour_fill_alpha.Rd
-1aa9545d7185104f937e2c7ebae90992 *man/aes_group_order.Rd
-559b416776a7e29623dec8326f7a11b4 *man/aes_linetype_size_shape.Rd
-4d8634a5e08bb56949bc6ae566e91761 *man/aes_position.Rd
-393b1023a83f6f6b394ed11ea0ee5523 *man/aes_string.Rd
-b836e0853423c2efb8451270445d7c4d *man/annotate.Rd
-bddebbbbc61b190d059032bd3d6fa78e *man/annotation_custom.Rd
-66db8cb02b4fb2a0a3c6b70f0f8334e0 *man/annotation_logticks.Rd
-0184945a1805a8bd4c020e6d143aa597 *man/annotation_map.Rd
-aff58e38e9fbab339a7d590373260aad *man/annotation_raster.Rd
-2e66b1c5a16ceb76093cfc0625cef3cb *man/autoplot.Rd
-15f13f90d81e86c61f1fa069c719ee31 *man/benchplot.Rd
-73a4ef07adaf087c67f271f8bdbfd03c *man/borders.Rd
-7a201c8f48ce5f700a04ba40c64c7c00 *man/calc_element.Rd
-14a686c4751d41b649966d77f53d8a6e *man/continuous_scale.Rd
-1fe8251da91d285c4b384b1c182b1a7b *man/coord.Rd
-8ad3faa579da548f77e49d66ddd30e5d *man/coord_cartesian.Rd
-2c6179aecb180a2bea9e305351d07eb8 *man/coord_expand_defaults.Rd
-845e33709a349738acb3379cf109b7ea *man/coord_fixed.Rd
-c60894884d6b3c1406940c0e4abadf39 *man/coord_flip.Rd
-8c9c0bc18019bb0c8c5f470849ee2bf4 *man/coord_map.Rd
-dfe9c8c352d5d00808204e1af8840475 *man/coord_polar.Rd
-d1d46a048d7288ce57eb95077c29654e *man/coord_quickmap.Rd
-835f477b5b9e0c8f4fc70d843ad236af *man/coord_trans.Rd
-d11213e6f9d1393449ec7990c6fe9add *man/cut_interval.Rd
-92b3df33df9a0f94fba3b979729cdff6 *man/cut_number.Rd
-085059f21c257eb24b8c208f15cf7b5a *man/cweave.Rd
-a68ca34f29823be17c909ff3a42ec82f *man/diamonds.Rd
-dd2dc771d129c2da9ccdb77819840c3c *man/discrete_scale.Rd
-212b750d1d89ffc6cc81beac0634beba *man/economics.Rd
-70c387994e9c5300295013a1928d518b *man/element_blank.Rd
-5f9893928c1a82d1e175394878301542 *man/element_line.Rd
-b7129991a8483b90a45b019a6f97219c *man/element_rect.Rd
-cc737228d4235a9ad80f7a3886da24ee *man/element_text.Rd
-f23b5900e4c9f958952a341d565f4896 *man/expand_limits.Rd
-2747c6bd2961a76a8f9b702d7f4bc32b *man/facet.Rd
-4178f9e7f765cc7ff347e8ad694cb2e1 *man/facet_grid.Rd
-4eb2aa80308bc4cf3e470447cdd9f5b0 *man/facet_null.Rd
-aca63f9edc909eb37494d5de028a9157 *man/facet_wrap.Rd
-db3eadb0b7a25a0571ada0366f69305e *man/fortify-multcomp.Rd
-9e6931b7f675d844633c5a27f897701e *man/fortify.Rd
-d55933118aa8ee06c965645763d05089 *man/fortify.lm.Rd
-e5f155af6b67a01f4fa58082d089997b *man/fortify.map.Rd
-eeb833308f4b80d4474f2bd5f539da1c *man/fortify.sp.Rd
-22b225fab51eccbf457120365f8fc538 *man/geom_abline.Rd
-7618dc781f96bbb46de3373da577e6e2 *man/geom_area.Rd
-9c0a343f0917ddcdf184a4299f6d6dba *man/geom_bar.Rd
-b457e611971e745f73d00cddb7a8d51c *man/geom_bin2d.Rd
-a02ff775a1473b5141cf5aea0301e4e4 *man/geom_blank.Rd
-69555513052791e20e76859b8ea07ec8 *man/geom_boxplot.Rd
-e6c4fd1583a8118057a5683db2db08c1 *man/geom_contour.Rd
-575de2e3107730e538be0f68b4cfa9b5 *man/geom_crossbar.Rd
-c6c6eb604674434fb5e71bd98a98615e *man/geom_density.Rd
-d6c27d08451a4428a1fb58ba40f885b2 *man/geom_density2d.Rd
-82692e992b59d38c092ba6cdce1814c7 *man/geom_dotplot.Rd
-4e2638ba162d0b18a6319fb4f11219a0 *man/geom_errorbar.Rd
-4e85c4cb69105b40eb536f22fefd80ab *man/geom_errorbarh.Rd
-3b8c87b62f23fa5e1bff4a91b77b8fb8 *man/geom_freqpoly.Rd
-44f5c5d6befe729678714ff103b6b663 *man/geom_hex.Rd
-4468cf23b8576ab87378a0d9bd600bdd *man/geom_histogram.Rd
-0f230a21047054d5e1021b6baf184427 *man/geom_hline.Rd
-82b332d515c4da512366aa1e584096c1 *man/geom_jitter.Rd
-738f3392c62f3504cbb1a7e3abac210e *man/geom_line.Rd
-d2cd2a3e4730fb9e09c75e8445e2c2b0 *man/geom_linerange.Rd
-503d2e4f6c4f44982dfaf5c96f52fd3a *man/geom_map.Rd
-56cfbbd21b65d6f5f334f72470f8fc73 *man/geom_path.Rd
-216ca40b3117921ebf2b0e25ce7bd28a *man/geom_point.Rd
-f8688cdcd66af2e5818290e3dd350d9d *man/geom_pointrange.Rd
-6d3284f22eb86e836f7d1c05ddc0ca9d *man/geom_polygon.Rd
-b72efb8d5bf2a67343372f1140c51d04 *man/geom_quantile.Rd
-95d1878f261557cd336a47487adebe2c *man/geom_raster.Rd
-c3b5ecbf1f70a411259963f386a2c026 *man/geom_rect.Rd
-8842c660de5628a9493cd280e5bcc225 *man/geom_ribbon.Rd
-0cd50707daf1c259aa9c33c5f397ce36 *man/geom_rug.Rd
-7b752d18e4707fdafb992d8e06acbca5 *man/geom_segment.Rd
-d89105e9639378f60be203ce0130314a *man/geom_smooth.Rd
-02432505ced8af2836239024a5ee47c0 *man/geom_step.Rd
-692e6e0def392066168d62fffcff24d6 *man/geom_text.Rd
-14d9b2504f007b74be2c189c717d4e45 *man/geom_tile.Rd
-7d2832b1beb34386ca7bfb3aaa54483d *man/geom_violin.Rd
-c539b93cb99871b7ebcf6d82f6527b10 *man/geom_vline.Rd
-f5515b7ce17e654bfdaeafc512c51a90 *man/gg-add.Rd
-37dd03ea6adbd281d447c38c59fc111d *man/gg_dep.Rd
-5a7316e35e41283cb90542ceee05cb3c *man/ggplot.Rd
-0025cf1b1f8b6b93982122d486663ce0 *man/ggplot.data.frame.Rd
-3289a6e395c7fdb780ffeed58a528a23 *man/ggplot2.Rd
-21ed5b2c57d02d5a3261ac3e8109c1d3 *man/ggplotGrob.Rd
-f9b674162fc11ee71004fbd00fe7c3d4 *man/ggplot_build.Rd
-58ebc78a5c6a7f7ac27016ccdef48c1b *man/ggplot_gtable.Rd
-dc7d997e06824ebfbc53e65a2b7a524b *man/ggsave.Rd
-f6fa2d77a8ae9ff17d584c39c5d24d40 *man/ggscale.Rd
-8d69f4c51e492465eb4bd292d71091e3 *man/ggtheme.Rd
-f6638223f5f070e1ec8bba7bbe6adc54 *man/guide_colourbar.Rd
-7bff7488f2a6c8672a422a0df57e6cd5 *man/guide_legend.Rd
-ce1566351de8eda1e0cdb7edbdf78845 *man/guides.Rd
-07c9249170e38ba37134fa2938f53360 *man/hmisc.Rd
-9a6042278406f88db2b646a6737b3597 *man/interleave.Rd
-112cbe677b0fbe023bd3f8ed4e2892e0 *man/is.coord.Rd
-5b4359b1c4398ed1305e68653762f352 *man/is.facet.Rd
-d7f4156c0c9457b77c9185104221e28b *man/is.ggplot.Rd
-e524b2dc66cb7a2d3374ae298d8090d5 *man/is.rel.Rd
-41f135d50950de515903c630260bbfbe *man/is.theme.Rd
-bc1389cd4b64884880235d8d9e4c59c5 *man/label_both.Rd
-e98098ee9ba5106e88bd8a83e00c258b *man/label_bquote.Rd
-8357025661d03ee84066f0a509ac8fcb *man/label_parsed.Rd
-668c3db4113a86e8bb15236dedac7afd *man/label_value.Rd
-839cefdff2cc922174e53da515569f04 *man/label_wrap_gen.Rd
-7be8f6f748a2f10d255cbfbdbe73eaf4 *man/labeller.Rd
-fde417ac38367298132e25087a9cf5f8 *man/labs.Rd
-f2833d7ebd491eaec27ec1926b8aee37 *man/last_plot.Rd
-25109207a7d912538f92bb6b1f9ce1ac *man/layer.Rd
-3a61b4c9327bd1374b90477ece26f9f9 *man/limits.Rd
-c6f6c701faec9eb0397cfb53d553743d *man/map_data.Rd
-fe38d0d928e915f0f2370964991d4678 *man/mean_se.Rd
-09ce11b1c896c49c65bef48c47299185 *man/midwest.Rd
-123e04881d499854a32a71dc9ca54c61 *man/movies.Rd
-e97500ec9a396436bbe3cd87c75bbe72 *man/mpg.Rd
-8d7c926b77c05e43590971cef79631dc *man/msleep.Rd
-b36c10c2e0474755b684e199a0e3fbe5 *man/opts.Rd
-3044bf0a1980297dce635331bfad4a79 *man/plot-templates.Rd
-9b0290e93402850bc3be2a915ff36034 *man/position_dodge.Rd
-d91cc4da2a96e778a7b9674fc30ec12d *man/position_fill.Rd
-1f53ed825489aa4ec16090e834484f9d *man/position_identity.Rd
-eae1a5427f476e61945d96f89757658f *man/position_jitter.Rd
-17fb643eda5930e50003b9838028b5b8 *man/position_jitterdodge.Rd
-91a5839a048a81c5180442eb54519be2 *man/position_stack.Rd
-70afa8ce687c0f2a51ef78320442005d *man/presidential.Rd
-bc1c24de8f970a6a9d7a6831f22f685e *man/print.ggplot.Rd
-4653e3e54464b0170b4284f4482e36b7 *man/qplot.Rd
-8be989550fa23071982fc8e609f20770 *man/rel.Rd
-9c9afa898c06984590c1fe06322bcce0 *man/resolution.Rd
-8210b82f45ba9f87572241aacc8ce9a7 *man/rweave.Rd
-9386e3c0693d799b87c75b6418613927 *man/scale_alpha.Rd
-6b7bb4ff624cfa4ad26a2afcd9c0526c *man/scale_area.Rd
-95bc93520413fdf55d2d77267f382eb9 *man/scale_brewer.Rd
-a4982707a1010ce40ec59fca78900bcb *man/scale_continuous.Rd
-a0532d9ed33fd197d08276003ddb6367 *man/scale_date.Rd
-0c0b671da03e9fcb4da71a6497431523 *man/scale_datetime.Rd
-afa0c69428122953da25689dd47c25bb *man/scale_discrete.Rd
-3189f6b92d7a808d9859ffc0db36381b *man/scale_gradient.Rd
-d0cfe255778f49fdce6bdf610923ad32 *man/scale_gradient2.Rd
-ff11a332511540026bb348e3495c34dd *man/scale_gradientn.Rd
-4f35d6e90893bcb9528ecd5272dad1e9 *man/scale_grey.Rd
-306f8cd98e552961320c927b6f407ceb *man/scale_hue.Rd
-dd8f4da65318686fbb2049d4b622bed1 *man/scale_identity.Rd
-ffa0b2b57b5cef00f9d54691394933fd *man/scale_linetype.Rd
-1f2281dbe5429afc99ad6e496d1230b1 *man/scale_manual.Rd
-058b2cdbe6b5ae8f2f54d322075499b5 *man/scale_shape.Rd
-eee6cd51c6917f91bd9d77acd8615729 *man/scale_size.Rd
-d487f598e6fb229a8312f05e704fb548 *man/scale_size_area.Rd
-ca64d5ea098ab71978ea274fa6caddbd *man/seals.Rd
-b46dc34fb4bacb15b08a0a8a9eeb284b *man/should_stop.Rd
-c439cc858f0a553c983bf8de3bb4e190 *man/stat_abline.Rd
-391099f905df69f3b798b921b665c38a *man/stat_bin.Rd
-1ce3d843435a1fe4167e71de9e343386 *man/stat_bin2d.Rd
-5b9b5b8401da13c9f980d5b90b5cb422 *man/stat_bindot.Rd
-3b63ed56797fb241fba367dab3fb5348 *man/stat_binhex.Rd
-d8a88951d37130991296924bd588d9fd *man/stat_boxplot.Rd
-b159e26fb2024c4bfcdfb7e77220c604 *man/stat_contour.Rd
-d2941676cc0c751cce9acf8754f698aa *man/stat_density.Rd
-31fc8adcf0e4de533883afe239eef686 *man/stat_density2d.Rd
-7828aee915d3bf49d1bca3a3e86ce8e3 *man/stat_ecdf.Rd
-bbf0a31c1273fb665b873a8ae4320b98 *man/stat_ellipse.Rd
-410519ce65ef26e5e416ca0b9be54208 *man/stat_function.Rd
-2d0715b0ba198f7b6a249d42f297ccbd *man/stat_hline.Rd
-837426bb4432c22cfeea4891613fe1e5 *man/stat_identity.Rd
-ac457fa80c0eb5449fe1be91d75170f2 *man/stat_qq.Rd
-0894015e7313deffd5fa0799eca03d80 *man/stat_quantile.Rd
-97dfe9027e477d0910d9f0ffcd1e383a *man/stat_smooth.Rd
-475d390dd116a5eb56eaed2e9695bcc5 *man/stat_spoke.Rd
-58c066cd09a94ea706e65ef2b241e101 *man/stat_sum.Rd
-7bdb590091360d6157c5c5e12fb6e09b *man/stat_summary.Rd
-4b8700e63551aefe7f2ed1ffbdc9a9b3 *man/stat_summary2d.Rd
-fcc03dbba2dd58d7fa395cc02c0e598d *man/stat_summary_hex.Rd
-832e6b61e2c15faad64cb0286f0158d5 *man/stat_unique.Rd
-6cf7c1cd65b09b83165e18c0fd9c0b05 *man/stat_vline.Rd
-ef58ede141bd49c5585cbfc5aa33d512 *man/stat_ydensity.Rd
-929158e1e54c880581f8b7894d7e2a9f *man/summary.ggplot.Rd
-50aa6896903055bf64ed4a8aca0a084b *man/theme.Rd
-1b2ac07ae066f84de2a9ad19df8c8aee *man/theme_blank.Rd
-af45808871a6ccc67820945b37f68c84 *man/theme_update.Rd
-1f4127776fa8f6e79ce9c1de0a69c78a *man/translate_qplot_base.Rd
-bc0f33b484f9949d1ab4ad072dd697db *man/translate_qplot_ggplot.Rd
-7fbf80c8266ba6f0bc67841f244a856e *man/translate_qplot_gpl.Rd
-5bb768a0f46c5ced49bd9873d1966e9a *man/translate_qplot_lattice.Rd
-2a08b034c41f850d43eb73e5f7159663 *man/update_defaults.Rd
-320e4bd31a72c9aedac8063ab850d4f9 *man/update_element.Rd
-254a9d75f5c1a72f473d1cb18c694144 *man/update_labels.Rd
-aa47820f0d7513cd882190e0f47cd399 *man/waiver.Rd
-0bccf2d22a4398f005f3adee1d314c29 *man/xylim.Rd
-36fb02bfdac80561d3d13cfae32149ba *man/zeroGrob.Rd
-18ce871dfe61dcdd288c02929f1b55d7 *tests/test-all.R
-ca9a9bfa8225e85a1400d060568ada6a *vignettes/development.Rmd
-031c78a8fbe505a4ee120726f622d005 *vignettes/release.Rmd
+8a0e4eb3cf19379924a78bc3f6fd3d7d *inst/staticdocs/icons.R
+4add1191e76ffb056578dbe4272159e7 *inst/staticdocs/index.r
+56c75450069dc75bc81998ee2ec1e689 *man/absoluteGrob.Rd
+ff67ba09d9d3541a10c519c3ed0d055c *man/add_theme.Rd
+20f0528eb3688034fab93fc721b65409 *man/aes.Rd
+f77426680c2a929cb9ad19f8aa7613d4 *man/aes_.Rd
+7712e3e5b0ab03a32404a8f034aa10f0 *man/aes_all.Rd
+ef8ce354cb3b609f4c33f53cd26821cc *man/aes_auto.Rd
+03b05c2b533b5a88d81a6ac37cd5de77 *man/aes_colour_fill_alpha.Rd
+48368f5dea136a4ec910b3c2e77cbf11 *man/aes_group_order.Rd
+d7a853f2e395f95617f5b6da138cec65 *man/aes_linetype_size_shape.Rd
+a99dcba86e888d8d6641653c7a5b972d *man/aes_position.Rd
+da7b4f468468cab96bb8573443141fb3 *man/annotate.Rd
+c6f56de489e678ee0c1e9ffa8603a618 *man/annotation_custom.Rd
+e3f138140bdadb64a8aa2038218f4e25 *man/annotation_logticks.Rd
+8c8c2ba1b4e343fb916b354a6560fcb5 *man/annotation_map.Rd
+9a00f65c63148ff18f9fd46067bbdb4e *man/annotation_raster.Rd
+f428bf30bcd593b2b6940df5e04b7f58 *man/as.list.ggproto.Rd
+a01a9827585d5254017ca6ce9fbbb599 *man/as_labeller.Rd
+43589aa720efd687662e0de7354eb4b0 *man/autoplot.Rd
+9f6abc675b3e32de763c9d53fa9f77d0 *man/benchplot.Rd
+1a343455cf735e38d3fabfa499221ad5 *man/borders.Rd
+63c959e3e092bcf3a6fcc2366d3f1430 *man/calc_element.Rd
+3e26b171206c01912b6d838c222eb49f *man/continuous_scale.Rd
+f6d9adf026157a00fd92df166ac675fa *man/coord_cartesian.Rd
+61af3e0c70d351e48110df56657ca13e *man/coord_fixed.Rd
+ede8ed39297e89fe4dc8d9bb0eeb422a *man/coord_flip.Rd
+79cd96819a42d0185ce072d5ca853dfa *man/coord_map.Rd
+03ea1bbb888bb836e26d1d04ce859a76 *man/coord_munch.Rd
+3af68f29c13c188fc422415813089498 *man/coord_polar.Rd
+1025087210f72dabf5ef6308790b2c6e *man/coord_trans.Rd
+b3087f2c77e447cd21e6898615bfbf81 *man/cut_interval.Rd
+b3ce84b7cf66c2930d2a6ee63873f72d *man/diamonds.Rd
+a2b6fbd168d4e755310000b7cc1fb60d *man/discrete_scale.Rd
+6be3e22abc22f2b478bbf7bf6f79e10c *man/draw_key.Rd
+4e7e5a544d058f424a52f3c2dba4cd91 *man/economics.Rd
+c4df9291f631ea3cd24f69c97f02f1e2 *man/element_blank.Rd
+1296c043ef8b9ed396cf6d0103f6f7ba *man/element_grob.Rd
+0e777f87e5497e22240fcc4febf0edda *man/element_line.Rd
+325bd1005487d98b4e7a39e2878c22ac *man/element_rect.Rd
+f5778a7dbfad57f255816ee8c590abfb *man/element_text.Rd
+5d9d25976953ec27acfc6428556eb3aa *man/expand_limits.Rd
+df0176ef30dbfdde4cce9cea8381d99d *man/facet.Rd
+70e412fc004ef63b4dd13987fa69e2f5 *man/facet_grid.Rd
+b79ffe497fda049f9f7718a4efa86867 *man/facet_null.Rd
+772a5f2d18d65842decf6d7fce27df91 *man/facet_wrap.Rd
+49314a7e941068d810878ceee132c904 *man/faithfuld.Rd
+294388d79ebc5fef1db58f4c06d12523 *man/format.ggproto.Rd
+84300d3fcdd22030ca8d1ac5d9f1df62 *man/fortify-multcomp.Rd
+60662763b7a08678979a92f218c9537c *man/fortify.Rd
+72f9d74ebc7f9b4354a702a02ac8acd4 *man/fortify.lm.Rd
+720abd47d0d039c70334c93b327f3141 *man/fortify.map.Rd
+7602d9d65104b9bc4e204bcb7894f445 *man/fortify.sp.Rd
+dcb5d4f5abb536b72f9350c8ff5c1a44 *man/geom_abline.Rd
+d5ffd3b3b476392c0de7e59fcc0d4cae *man/geom_bar.Rd
+86fd822c0dab391d0b021c8a04c39759 *man/geom_bin2d.Rd
+e07433ef36f68faf0a09d6cbc0093a35 *man/geom_blank.Rd
+0ad31ca2d92be8b02a38e825fa8e1d87 *man/geom_boxplot.Rd
+ebeac9abd59706401c4c0f8e07b3dc66 *man/geom_contour.Rd
+a431a225e971088a4ebcee99b346f904 *man/geom_count.Rd
+9debbf163e919ac9c0a4f4fad2162e7d *man/geom_density.Rd
+051c3ceff3b1f29d4605d6eae4960034 *man/geom_density_2d.Rd
+ff5676a104f025f5e14b0c14ad3ffe45 *man/geom_dotplot.Rd
+f617666ccea672d3ac7f7383b5030ae6 *man/geom_errorbarh.Rd
+c564a6814ccd3fe39d2d909ef5e79035 *man/geom_hex.Rd
+0ee3581c134ee72ee0b1645c47938685 *man/geom_histogram.Rd
+43e59c75d324f75f2d3602d1a8c0b088 *man/geom_jitter.Rd
+4206d8f6928e9c26277795dfd0a8b59b *man/geom_linerange.Rd
+900fc042ac2ccd6e686603b9b3de0b2f *man/geom_map.Rd
+e68a78e087c71b276e3645c2ded6cead *man/geom_path.Rd
+b2a28c9173a63654d78522dc0862ede8 *man/geom_point.Rd
+9b54eb991ed2bf0ce3cf8167a4cf466b *man/geom_polygon.Rd
+f57ff34cf79711d370e6a48e6ce30801 *man/geom_quantile.Rd
+4d3be4002eeaa64bc9103713e17bda4b *man/geom_ribbon.Rd
+a3e976f4161a198988ad8fb95365c3e8 *man/geom_rug.Rd
+17121dc9468c91ae1b2566446cb8a591 *man/geom_segment.Rd
+6ff1ac4aefc1cd657955b72d2c535005 *man/geom_smooth.Rd
+b6cdad5c6952b9dff9c2bd67ba30d295 *man/geom_spoke.Rd
+36a08621b671333882290a948773c57c *man/geom_text.Rd
+6fc616f1a1e28f726f7a895cbeb73031 *man/geom_tile.Rd
+a6bbbf06590523bff5f0389b15496cc2 *man/geom_violin.Rd
+dab0412cf340913187b9383bd173b4aa *man/gg-add.Rd
+f1075176114c6b91fdbf223719cd981a *man/gg_dep.Rd
+c63db10ccb04b87aedfdda2119ef9b5c *man/ggplot.Rd
+238ef3805c533dc74575a0853d06c636 *man/ggplot2-ggproto.Rd
+a4bef608dde830e27ac03f259c102cef *man/ggplotGrob.Rd
+449d55cacfef6d03d889df009992894e *man/ggplot_build.Rd
+7aedf2453e47d8d2bebd38923501c60b *man/ggplot_gtable.Rd
+db86dd2f3896ef6a5950d64b0a4d2766 *man/ggproto.Rd
+7fadc3359fc39669f9e3b3bd59dea9a0 *man/ggsave.Rd
+f30de9d8e16cc683c280267dc54db4e0 *man/ggtheme.Rd
+7a6498b8983bc96328ce0846ce0e877c *man/graphical-units.Rd
+6759e461416f3ce513ad249dd15fa106 *man/guide_colourbar.Rd
+2bd2c77d6ef8806705a2b378cf4bad0a *man/guide_legend.Rd
+81243640ba87fee316373900d47bd170 *man/guides.Rd
+7e0bd3d61fe1df07da190c3ced288fdf *man/hmisc.Rd
+630598fb99d0a7a34bbb146074dfacc0 *man/is.Coord.Rd
+15366e61452b09ab99fe3c4d76402aad *man/is.facet.Rd
+8656337fbb445f7df31749f916df4879 *man/is.ggplot.Rd
+b6171db99a23771ff09509040977439c *man/is.ggproto.Rd
+9d8a05937e7e0b8637eded383b367400 *man/is.rel.Rd
+9dd92b4dd7a88320e6d1486625f7f018 *man/is.theme.Rd
+6d35b6f8b4fef5a3757a999d2294cadb *man/label_bquote.Rd
+489c778eadaba0fc2ea1779450e723d1 *man/labeller.Rd
+86f29d63e2e2434a227e2de707b8f54e *man/labellers.Rd
+b5821e641bcc949b92d3b27871ff5ff3 *man/labs.Rd
+ec27029cac6b31ea9157ef0feb154b07 *man/last_plot.Rd
+d70cf02322cd705691c803fbcd1f9695 *man/layer.Rd
+115cedc87e2e5383505475fe2cf63054 *man/limits.Rd
+377da418fcc446ccf31c060c52bc0d7a *man/lims.Rd
+3ed091075707aa13724a9043b3ed2aa1 *man/luv_colours.Rd
+21a16a89724a7fb35b1e4a83497bef74 *man/map_data.Rd
+653ed592603548727d9ba6210fb4f448 *man/margin.Rd
+95ceb14a8b8d499aa1e3a13318fc2b98 *man/mean_se.Rd
+230020b63a1ed18e271efbb407269e64 *man/midwest.Rd
+ed26f5ff992715b558e465f84f9a5ee6 *man/mpg.Rd
+1db47d6001687f68ad3ae1cb53cb1c0a *man/msleep.Rd
+a2e7c0d524aa4ddb36a5c3800adc00b2 *man/position_dodge.Rd
+ae3e6c3a943617e4d58eb0954a0c76e0 *man/position_identity.Rd
+a6e474584d501fccbc8f44c7b5cfc477 *man/position_jitter.Rd
+17959133179918180ec83f11c4cbc621 *man/position_jitterdodge.Rd
+605df25d4d57fa0117b5247aa1c15205 *man/position_nudge.Rd
+bec4dbb370a26eb76d196c9208f95e94 *man/position_stack.Rd
+c41b9d71182dd3680692b2de56254408 *man/presidential.Rd
+3214de68f499011f976c396ae519e6de *man/print.ggplot.Rd
+f130ffe874ab878cfba9e43a145df148 *man/print.ggproto.Rd
+2618d742cecc1748f77cd870aade6839 *man/qplot.Rd
+774af14fcd1baed19c001ae81a31f2aa *man/reexports.Rd
+2a3d7cca6cadd2c1c919f77f97fa118e *man/rel.Rd
+d7f87c2dfc2d156fb61cba090a620299 *man/remove_missing.Rd
+0945809c10e67d31c5337b7300d14d42 *man/resolution.Rd
+7646f1860ccfcfdef643a36a96838422 *man/scale_alpha.Rd
+89d50c11d76e3222056ca9bef1eee95c *man/scale_brewer.Rd
+1d97e27509e6d0ac39fc87e598d337a9 *man/scale_continuous.Rd
+445d9ce9a48c7656f7e0e196a76edc29 *man/scale_date.Rd
+1ce0563c5f4297d788925a7298e1a83d *man/scale_discrete.Rd
+82457894e9d32c0b19792dde26efdec4 *man/scale_gradient.Rd
+cf572e09e6ec62dc446f6ee845713751 *man/scale_grey.Rd
+2315b109bc3814b19fe1eca32d71fc45 *man/scale_hue.Rd
+f6a2295e5df163391b3759359def22cb *man/scale_identity.Rd
+cdf000a350d3bc9df114f5d73889becb *man/scale_linetype.Rd
+7b1d99d5983f282fd910e9b53378f0c6 *man/scale_manual.Rd
+e421384c765694757e3a2676f6d44fa0 *man/scale_shape.Rd
+6443a0c5dfb9614e648721ae343609a1 *man/scale_size.Rd
+b59ea5ba748f6cff46c84679997afc9b *man/seals.Rd
+1056d55d33485453dd04e35394dddbac *man/should_stop.Rd
+ce238a515ba75aaa73ab63f3f7de53cd *man/stat_ecdf.Rd
+a2e10d53569214aa5a85a1ce54acddd2 *man/stat_ellipse.Rd
+bc1b38dfbfd9f629ec5d575a27e2d6a9 *man/stat_function.Rd
+c488178bbf7011597fadf82333a53262 *man/stat_identity.Rd
+c8327ec1ecf7807bc836c554c6259e99 *man/stat_qq.Rd
+29e597040e07a445416d688995bf48a2 *man/stat_summary.Rd
+a3362e1e10d662c578157a0a05d90326 *man/stat_summary_2d.Rd
+6e346ef82bfa85da9c0179c309ce7711 *man/stat_unique.Rd
+ab1fa2e5b12d61345c6df1c55d057290 *man/summary.ggplot.Rd
+ddb990cb82eceb1692278ab09a7771ec *man/theme.Rd
+0b1a77dc069162e990936c72515fcbf8 *man/theme_update.Rd
+ec58a310165674abab536ca72c129ac5 *man/transform_position.Rd
+ca96d351fe279c59980265de693fe286 *man/translate_qplot_base.Rd
+8feeb91c8e5d9077dc5a37ed1808af46 *man/translate_qplot_ggplot.Rd
+8eba2685b5b409df90036b2251587bcd *man/translate_qplot_lattice.Rd
+d8ce22b7718402206269b27a8f954b22 *man/txhousing.Rd
+efdbab8bf593c178c64d6e1fc22205cb *man/update_defaults.Rd
+df4c14b5a8d448e6bab888cab8831378 *man/update_labels.Rd
+00df4f81231118534f870304920f88db *man/waiver.Rd
+9ef186947b49d31af9fec818c266e4ce *man/zeroGrob.Rd
+d61ade7569d3176888310444bed0e4ef *tests/testthat.R
+d3a921ea3008eada9d101257f4f15594 *tests/testthat/helper-plot-data.r
+1076ad0ef6acd3a78dd8db456f9bba04 *tests/testthat/test-aes-grouping.r
+3495ad6baee576d4dba787926e739f01 *tests/testthat/test-aes-setting.r
+56417865028605cba1c09e3a5f39663a *tests/testthat/test-aes.r
+1093aca9aab9868183b5357b945ed379 *tests/testthat/test-annotate.r
+9245ba261a33250b76c72466bcbb1ebe *tests/testthat/test-boxplot.r
+dfb45a5e2f1c12d8ac1c5021a7d642af *tests/testthat/test-build.r
+a61803e15d2625dc599faa8f3f6b1fb2 *tests/testthat/test-coord-polar.r
+6e70a3a306f7272bb7391af0af9cb84e *tests/testthat/test-coord-train.r
+9ec3f36295915b84878da970f38610cc *tests/testthat/test-data.r
+d0b20527ddaca6ab1f99c1cfc449e15d *tests/testthat/test-dotplot.r
+2a70f0d37abe08e7f7b4e2746ff5f846 *tests/testthat/test-empty-data.r
+6728e5c8edd8d12a05308e12b82197b6 *tests/testthat/test-facet-.r
+fafcc66255d651a5d3c8819fb0d069fd *tests/testthat/test-facet-labels.r
+32772170a1a135a200a9748c63ddfbcc *tests/testthat/test-facet-layout.r
+14ad2ef393e2b8c42ed26caae00faf1a *tests/testthat/test-facet-locate.r
+24307e570b5c3a261fbac843622f6dfb *tests/testthat/test-fortify.r
+77262eb0c26b03cdcb6a7a610d584ccf *tests/testthat/test-function-args.r
+3a8b464d19174e4eece703c99839174c *tests/testthat/test-geom-rule.R
+b7060e5ccf4c447b38e855310bfd140c *tests/testthat/test-geom-text.R
+11b564057fd03011bca4861fbf2c4798 *tests/testthat/test-geom-violin.R
+f7de4f656b033dab01630f1ed918c7b5 *tests/testthat/test-ggsave.R
+cb855e4c0ec9892813c5f86f838b3f52 *tests/testthat/test-guides.R
+6318ef949123e4e13c938ffc0e3d4010 *tests/testthat/test-labels.r
+83d926bc18cbc8a2a138f73009cb169c *tests/testthat/test-layer.r
+c2b1f4b1d448df295563ae1ed9dc1886 *tests/testthat/test-munch.r
+972abcb47b4a68ac9f086af1c8198da9 *tests/testthat/test-qplot.r
+99ee168c3f25007fca5e93c76453038c *tests/testthat/test-range.r
+d2f2d93cd9cfda4de1268614593e15f9 *tests/testthat/test-sanitise-dim.r
+926a7d6e1dd028761c51e1926c605c82 *tests/testthat/test-scale-manual.r
+11af33c3989010aec22c5c5ebb34108f *tests/testthat/test-scales-breaks-labels.r
+cc078e4e9973263342f51212c2ecb71f *tests/testthat/test-scales.r
+e2e2f29a35ad159d12dae8517ab28794 *tests/testthat/test-stat-bin.R
+7a2de7d35f8f4e2a9a38596b8caedffd *tests/testthat/test-stat-bin2d.R
+264a54ed95553c9d2bef6fa83a8245c9 *tests/testthat/test-stat-density.R
+10744c4e51dd7cd19728e845f4171880 *tests/testthat/test-stat-density2d.R
+547fbe507cc42321b6257125ba33f1c3 *tests/testthat/test-stat-sum.R
+99fdfeb1c824e9ab041f78075a0b1f50 *tests/testthat/test-stats-function.r
+4b6d4c25b74a97b1e27a0e169126e37f *tests/testthat/test-stats.r
+03ac3fdccc2a146db16f700f1b657cb6 *tests/testthat/test-theme.r
+ce26fb5635464c1ddc29cd992f03108f *tests/testthat/test-utilities.r
+ac880a6aa04fc8644fed280c88b5d674 *vignettes/car.png
+3ea1eef97dfdacc7cd6703ae5e1bb2ed *vignettes/extending-ggplot2.Rmd
+580964d5ac3b6030ddbfeb79f5123db3 *vignettes/ggplot2-specs.Rmd
diff --git a/NAMESPACE b/NAMESPACE
index f44b35b..1c6da18 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -1,50 +1,13 @@
-# Generated by roxygen2 (4.1.0): do not edit by hand
+# Generated by roxygen2: do not edit by hand
 
+S3method("$",ggproto)
+S3method("$",ggproto_parent)
 S3method("+",gg)
 S3method("[",uneval)
+S3method("[[",ggproto)
 S3method(as.character,uneval)
+S3method(as.list,ggproto)
 S3method(autoplot,default)
-S3method(coord_aspect,default)
-S3method(coord_aspect,fixed)
-S3method(coord_aspect,map)
-S3method(coord_aspect,polar)
-S3method(coord_aspect,quickmap)
-S3method(coord_distance,cartesian)
-S3method(coord_distance,map)
-S3method(coord_distance,polar)
-S3method(coord_distance,trans)
-S3method(coord_expand_defaults,default)
-S3method(coord_expand_defaults,polar)
-S3method(coord_labels,default)
-S3method(coord_labels,flip)
-S3method(coord_labels,polar)
-S3method(coord_range,default)
-S3method(coord_range,flip)
-S3method(coord_range,polar)
-S3method(coord_render_axis_h,default)
-S3method(coord_render_axis_h,map)
-S3method(coord_render_axis_h,polar)
-S3method(coord_render_axis_v,default)
-S3method(coord_render_axis_v,map)
-S3method(coord_render_axis_v,polar)
-S3method(coord_render_bg,default)
-S3method(coord_render_bg,map)
-S3method(coord_render_bg,polar)
-S3method(coord_render_fg,default)
-S3method(coord_render_fg,polar)
-S3method(coord_train,cartesian)
-S3method(coord_train,flip)
-S3method(coord_train,map)
-S3method(coord_train,polar)
-S3method(coord_train,trans)
-S3method(coord_transform,cartesian)
-S3method(coord_transform,flip)
-S3method(coord_transform,map)
-S3method(coord_transform,polar)
-S3method(coord_transform,trans)
-S3method(cweave,list)
-S3method(cweave,matrix)
-S3method(drawDetails,dotstackGrob)
 S3method(drawDetails,zeroGrob)
 S3method(element_grob,element_blank)
 S3method(element_grob,element_line)
@@ -70,6 +33,8 @@ S3method(facet_vars,null)
 S3method(facet_vars,wrap)
 S3method(finite.cases,data.frame)
 S3method(format,facet)
+S3method(format,ggproto)
+S3method(format,ggproto_method)
 S3method(fortify,"NULL")
 S3method(fortify,Line)
 S3method(fortify,Lines)
@@ -89,6 +54,7 @@ S3method(fortify,summary.glht)
 S3method(ggplot,data.frame)
 S3method(ggplot,default)
 S3method(grid.draw,absoluteGrob)
+S3method(grid.draw,ggplot)
 S3method(grobHeight,absoluteGrob)
 S3method(grobHeight,zeroGrob)
 S3method(grobWidth,absoluteGrob)
@@ -103,19 +69,19 @@ S3method(guide_merge,colorbar)
 S3method(guide_merge,legend)
 S3method(guide_train,colorbar)
 S3method(guide_train,legend)
+S3method(heightDetails,stripGrob)
+S3method(heightDetails,titleGrob)
 S3method(heightDetails,zeroGrob)
 S3method(interleave,default)
-S3method(interleave,list)
 S3method(interleave,unit)
-S3method(is.linear,cartesian)
-S3method(is.linear,default)
-S3method(is.linear,flip)
 S3method(limits,Date)
 S3method(limits,POSIXct)
 S3method(limits,POSIXlt)
 S3method(limits,character)
 S3method(limits,factor)
 S3method(limits,numeric)
+S3method(makeContent,labelgrob)
+S3method(makeContext,dotstackGrob)
 S3method(plot,ggplot)
 S3method(predictdf,default)
 S3method(predictdf,glm)
@@ -124,47 +90,11 @@ S3method(predictdf,loess)
 S3method(print,element)
 S3method(print,facet)
 S3method(print,ggplot)
-S3method(print,proto)
+S3method(print,ggproto)
+S3method(print,ggproto_method)
 S3method(print,rel)
-S3method(print,scale)
 S3method(print,theme)
 S3method(print,uneval)
-S3method(rweave,list)
-S3method(rweave,matrix)
-S3method(scale_break_info,continuous)
-S3method(scale_break_info,discrete)
-S3method(scale_breaks,continuous)
-S3method(scale_breaks,discrete)
-S3method(scale_breaks_minor,continuous)
-S3method(scale_breaks_minor,discrete)
-S3method(scale_clone,continuous)
-S3method(scale_clone,discrete)
-S3method(scale_clone,position_d)
-S3method(scale_dimension,continuous)
-S3method(scale_dimension,discrete)
-S3method(scale_dimension,position_d)
-S3method(scale_expand,default)
-S3method(scale_is_empty,default)
-S3method(scale_is_empty,position_d)
-S3method(scale_labels,continuous)
-S3method(scale_labels,discrete)
-S3method(scale_limits,default)
-S3method(scale_limits,position_d)
-S3method(scale_map,continuous)
-S3method(scale_map,date)
-S3method(scale_map,datetime)
-S3method(scale_map,discrete)
-S3method(scale_map,identity)
-S3method(scale_map,position_c)
-S3method(scale_map,position_d)
-S3method(scale_reset,default)
-S3method(scale_reset,position_d)
-S3method(scale_train,continuous)
-S3method(scale_train,discrete)
-S3method(scale_train,identity)
-S3method(scale_train,position_d)
-S3method(scale_transform,continuous)
-S3method(scale_transform,discrete)
 S3method(scale_type,Date)
 S3method(scale_type,POSIXt)
 S3method(scale_type,character)
@@ -174,37 +104,152 @@ S3method(scale_type,logical)
 S3method(scale_type,numeric)
 S3method(str,uneval)
 S3method(summary,ggplot)
+S3method(widthDetails,stripGrob)
+S3method(widthDetails,titleGrob)
 S3method(widthDetails,zeroGrob)
 export("%+%")
 export("%+replace%")
+export(.pt)
+export(.stroke)
+export(Coord)
+export(CoordCartesian)
+export(CoordFixed)
+export(CoordFlip)
+export(CoordMap)
+export(CoordPolar)
+export(CoordQuickmap)
+export(CoordTrans)
+export(Geom)
+export(GeomAbline)
+export(GeomAnnotationMap)
+export(GeomArea)
+export(GeomBar)
+export(GeomBlank)
+export(GeomBoxplot)
+export(GeomContour)
+export(GeomCrossbar)
+export(GeomCurve)
+export(GeomCustomAnn)
+export(GeomDensity)
+export(GeomDensity2d)
+export(GeomDotplot)
+export(GeomErrorbar)
+export(GeomErrorbarh)
+export(GeomHex)
+export(GeomHline)
+export(GeomLabel)
+export(GeomLine)
+export(GeomLinerange)
+export(GeomLogticks)
+export(GeomMap)
+export(GeomPath)
+export(GeomPoint)
+export(GeomPointrange)
+export(GeomPolygon)
+export(GeomQuantile)
+export(GeomRaster)
+export(GeomRasterAnn)
+export(GeomRect)
+export(GeomRibbon)
+export(GeomRug)
+export(GeomSegment)
+export(GeomSmooth)
+export(GeomSpoke)
+export(GeomStep)
+export(GeomText)
+export(GeomTile)
+export(GeomViolin)
+export(GeomVline)
+export(Position)
+export(PositionDodge)
+export(PositionFill)
+export(PositionIdentity)
+export(PositionJitter)
+export(PositionJitterdodge)
+export(PositionNudge)
+export(PositionStack)
+export(Scale)
+export(ScaleContinuous)
+export(ScaleContinuousDate)
+export(ScaleContinuousDatetime)
+export(ScaleContinuousIdentity)
+export(ScaleContinuousPosition)
+export(ScaleDiscrete)
+export(ScaleDiscreteIdentity)
+export(ScaleDiscretePosition)
+export(Stat)
+export(StatBin)
+export(StatBin2d)
+export(StatBindot)
+export(StatBinhex)
+export(StatBoxplot)
+export(StatContour)
+export(StatCount)
+export(StatDensity)
+export(StatDensity2d)
+export(StatEcdf)
+export(StatEllipse)
+export(StatFunction)
+export(StatIdentity)
+export(StatQq)
+export(StatQuantile)
+export(StatSmooth)
+export(StatSum)
+export(StatSummary)
+export(StatSummary2d)
+export(StatSummaryBin)
+export(StatSummaryHex)
+export(StatUnique)
+export(StatYdensity)
 export(aes)
+export(aes_)
 export(aes_all)
 export(aes_auto)
 export(aes_q)
 export(aes_string)
+export(alpha)
 export(annotate)
 export(annotation_custom)
 export(annotation_logticks)
 export(annotation_map)
 export(annotation_raster)
+export(arrow)
+export(as_labeller)
 export(autoplot)
 export(benchplot)
 export(borders)
 export(calc_element)
 export(continuous_scale)
-export(coord)
 export(coord_cartesian)
 export(coord_equal)
 export(coord_fixed)
 export(coord_flip)
 export(coord_map)
+export(coord_munch)
 export(coord_polar)
 export(coord_quickmap)
 export(coord_trans)
 export(cut_interval)
 export(cut_number)
+export(cut_width)
 export(discrete_scale)
+export(draw_key_abline)
+export(draw_key_blank)
+export(draw_key_boxplot)
+export(draw_key_crossbar)
+export(draw_key_dotplot)
+export(draw_key_label)
+export(draw_key_path)
+export(draw_key_point)
+export(draw_key_pointrange)
+export(draw_key_polygon)
+export(draw_key_rect)
+export(draw_key_smooth)
+export(draw_key_text)
+export(draw_key_vline)
+export(draw_key_vpath)
 export(element_blank)
+export(element_grob)
 export(element_line)
 export(element_rect)
 export(element_text)
@@ -221,9 +266,12 @@ export(geom_bin2d)
 export(geom_blank)
 export(geom_boxplot)
 export(geom_contour)
+export(geom_count)
 export(geom_crossbar)
+export(geom_curve)
 export(geom_density)
 export(geom_density2d)
+export(geom_density_2d)
 export(geom_dotplot)
 export(geom_errorbar)
 export(geom_errorbarh)
@@ -232,6 +280,7 @@ export(geom_hex)
 export(geom_histogram)
 export(geom_hline)
 export(geom_jitter)
+export(geom_label)
 export(geom_line)
 export(geom_linerange)
 export(geom_map)
@@ -239,6 +288,7 @@ export(geom_path)
 export(geom_point)
 export(geom_pointrange)
 export(geom_polygon)
+export(geom_qq)
 export(geom_quantile)
 export(geom_raster)
 export(geom_rect)
@@ -246,33 +296,33 @@ export(geom_ribbon)
 export(geom_rug)
 export(geom_segment)
 export(geom_smooth)
+export(geom_spoke)
 export(geom_step)
 export(geom_text)
 export(geom_tile)
 export(geom_violin)
 export(geom_vline)
 export(gg_dep)
-export(ggfluctuation)
-export(ggmissing)
-export(ggorder)
-export(ggpcp)
 export(ggplot)
 export(ggplotGrob)
 export(ggplot_build)
 export(ggplot_gtable)
+export(ggproto)
+export(ggproto_parent)
 export(ggsave)
-export(ggstructure)
 export(ggtitle)
 export(guide_colorbar)
 export(guide_colourbar)
 export(guide_legend)
 export(guides)
-export(is.coord)
+export(is.Coord)
 export(is.facet)
 export(is.ggplot)
+export(is.ggproto)
 export(is.theme)
 export(label_both)
 export(label_bquote)
+export(label_context)
 export(label_parsed)
 export(label_value)
 export(label_wrap_gen)
@@ -280,30 +330,34 @@ export(labeller)
 export(labs)
 export(last_plot)
 export(layer)
+export(layer_data)
+export(layer_grob)
+export(layer_scales)
+export(lims)
 export(map_data)
+export(margin)
 export(mean_cl_boot)
 export(mean_cl_normal)
 export(mean_sdl)
 export(mean_se)
 export(median_hilow)
-export(opts)
-export(plotmatrix)
 export(position_dodge)
 export(position_fill)
 export(position_identity)
 export(position_jitter)
 export(position_jitterdodge)
+export(position_nudge)
 export(position_stack)
 export(qplot)
 export(quickplot)
 export(rel)
+export(remove_missing)
 export(resolution)
 export(scale_alpha)
 export(scale_alpha_continuous)
 export(scale_alpha_discrete)
 export(scale_alpha_identity)
 export(scale_alpha_manual)
-export(scale_area)
 export(scale_color_brewer)
 export(scale_color_continuous)
 export(scale_color_discrete)
@@ -342,6 +396,7 @@ export(scale_linetype_continuous)
 export(scale_linetype_discrete)
 export(scale_linetype_identity)
 export(scale_linetype_manual)
+export(scale_radius)
 export(scale_shape)
 export(scale_shape_continuous)
 export(scale_shape_discrete)
@@ -368,19 +423,20 @@ export(scale_y_log10)
 export(scale_y_reverse)
 export(scale_y_sqrt)
 export(should_stop)
-export(stat_abline)
 export(stat_bin)
 export(stat_bin2d)
-export(stat_bindot)
+export(stat_bin_2d)
+export(stat_bin_hex)
 export(stat_binhex)
 export(stat_boxplot)
 export(stat_contour)
+export(stat_count)
 export(stat_density)
 export(stat_density2d)
+export(stat_density_2d)
 export(stat_ecdf)
 export(stat_ellipse)
 export(stat_function)
-export(stat_hline)
 export(stat_identity)
 export(stat_qq)
 export(stat_quantile)
@@ -389,27 +445,26 @@ export(stat_spoke)
 export(stat_sum)
 export(stat_summary)
 export(stat_summary2d)
+export(stat_summary_2d)
+export(stat_summary_bin)
 export(stat_summary_hex)
 export(stat_unique)
-export(stat_vline)
 export(stat_ydensity)
 export(theme)
-export(theme_blank)
 export(theme_bw)
 export(theme_classic)
+export(theme_dark)
 export(theme_get)
 export(theme_gray)
 export(theme_grey)
 export(theme_light)
-export(theme_line)
 export(theme_linedraw)
 export(theme_minimal)
-export(theme_rect)
-export(theme_segment)
 export(theme_set)
-export(theme_text)
 export(theme_update)
-export(update_element)
+export(theme_void)
+export(transform_position)
+export(unit)
 export(update_geom_defaults)
 export(update_labels)
 export(update_stat_defaults)
@@ -418,13 +473,10 @@ export(xlab)
 export(xlim)
 export(ylab)
 export(ylim)
-import(digest)
+export(zeroGrob)
 import(grid)
 import(gtable)
-import(plyr)
-import(proto)
-import(reshape2)
 import(scales)
-importFrom(MASS,cov.trob)
-importFrom(MASS,kde2d)
-importFrom(methods,setRefClass)
+importFrom(plyr,as.quoted)
+importFrom(plyr,defaults)
+importFrom(stats,setNames)
diff --git a/NEWS b/NEWS
deleted file mode 100644
index 2bf3300..0000000
--- a/NEWS
+++ /dev/null
@@ -1,2052 +0,0 @@
-ggplot2 1.0.1
-----------------------------------------------------------------
-
-* Fixes to pass `R CMD check --run-donttest` in R-devel.
-
-ggplot2 1.0.0
-----------------------------------------------------------------
-
-NEW FEATURES
-
-* New coordinate system for small scale maps. `coord_quickmap()` computes and
-  sets the correct aspect ratio between one degree of latitude and one degree
-  of longitude at the centre of the plotted region. It does not perform full
-  fledged mapping projection as `coord_map()` does and therefore is much
-  faster. Yet, it gives a correct approximation for small scale maps (a few
-  degrees in either direction) at medium to low latitudes (@jiho, #922).
-
-* `geom_boxplot` gain new `varwidth` argument for controlling whether or not
-  the width of boxplots should be proportional to the size of the groups
-  (@tsieger, #927).
-
-* `position_jitterdodge()` combines `position_jitter()` and `position_dodge()`,
-  allowing the user to plot and align points generated by e.g. `geom_point()`
-  with those generated by a dodged `geom_boxplot()`. See
-  `example(position_jitterdodge)` for a potential usage. (@kevinushey, #932)
-
-* Allow specifying only one of the limits in a scale and use the automatic
-  calculation of the other limit by passing NA to to the limit function,
-  `xlim()` or `ylim()` (@jimhester, #557).
-
-* Allow to use brewer palettes for continuous scales, through the new
-  `scale_fill/colour_distiller()` functions (@jiho, #925).
-
-* `stat_ellipse()` adds data ellipses. It supports bivariate normal and t distributions,
-  as well as a euclidian distance circle. (@jofrhwld, #926)
-
-* Add new themes: `theme_linedraw()` is similar to `theme_bw()` but with
-  truly only white and black elements and spacing between elements identical
-  to `theme_gray`. `theme_light` is similar but with light gray box and axes
-  around the plot, to emphasise content more (@jiho, #923)
-
-* new theme settings panel.margin.x and panel.margin.y (units) allow
-  specifying horizontal and vertical gap between panels in facetted plots (for
-  both grid and wrap).  (Kirill Müller. Fixes #839)
-
-* Fix vertical justification for rotated text.  This will change the appearance
-  of plots that use textual elements that are rotated by 90° or 270° and have a
-  `vjust` parameter other than the default 0.5; the interpretation of `vjust`
-  and `hjust` is now the same for both rotated and non-rotated text elements
-  (0 = top/left, 1 = bottom/right, 0.5 = centered).  (@krlmlr, #883)
-
-* Added helper function `labeller()` for formatting faceting values.
-  (@stefanedwards, #910). Added `label_wrap_gen` based on
-  https://github.com/hadley/ggplot2/wiki/labeller#writing-new-labellers
-  (@stefanedwards, #910)
-
-BUG FIXES AND MINOR IMPROVEMENTS
-
-* `aes()` no more treats variables like `a..x..b` as a calculated aesthetic.
-  (@krlmlr, #834.)
-
-* New `aes_q()` function to generate aesthetic specifications from
-  quoted calls/names. `aes_string()` uses names `x` and `y` for first
-  two unnamed arguments.
-
-* `fortify.SpatialPolygonsDataFrame()` now calls `polygons` without
-  requiring the `sp` to be loaded first (@seancarmody, #879).
-
-* The outliers of `geom_boxplot()` use the default colour, size and shape from
-  `geom_point()`. Changing the defaults of `geom_point()` with
-  `update_geom_defaults()` will apply the same changes to the outliers of
-  `geom_boxplot()`. Changing the defaults for the outliers was previously not
-  possible. (@ThierryO, #757)
-
-* `geom_dotplot()` now works with `qplot()`. (@rasmusab. Fixes #825)
-
-* Marginal improvements to `theme_bw()` and `theme_classic()` (@jiho, #934)
-
-* `stat_smooth()` checks for `method = "auto"` and `method = "glm"` in
-  a safer way.
-
-* Add `"none"` to documentation of `theme()` for parameter `legend.position`
-  (@krlmlr, #829).
-
-REMOVED FUNCTIONALITY
-
-* `ggpcp()`, `ggfluctuation()`, `ggmissing()`, `ggstructure()`, and
-  `ggorder()` are now defunct and have been removed.
-
-ggplot2 0.9.3.1
-----------------------------------------------------------------
-
-BUG FIXES
-
-* The theme element `legend.box.just` now can be set. It was not properly
-  recognized before.
-
-* `stat_density2d` previously resulted in errors when geom="polygon". This
-  is fixed. (Fixes #741 and #749)
-
-* `annotation_logticks` previously drew one set of logticks for each group,
-  and inherited aesthetic mappings like colour. It no longer does this. (Fixes
-  #767)
-
-* Plots with geom_crossbar not display correct symbol in legend. (Fixes #768)
-
-* Grouping is no longer set automatically by `stat_summary()`, allowing for
-  summary paths. This reverts a change made for 0.9.3. (Fixes #732 and #739)
-
-ggplot2 0.9.3
-----------------------------------------------------------------
-
-* The `plotmatrix` function has been deprecated and prints a warning
-  message.
-
-* `stat_bin` now produces warning messages when it is used with set or
-  mapped y values. Previously, it was possible to use `stat_bin` and
-  also set/map y values; if there was one y value per group, it would
-  display the y values from the data, instead of the counts of cases for
-  each group. This usage is deprecated and will be removed in a future
-  version of ggplot2. (Winston Chang. Fixes #632)
-
-* Several small changes were made so that ggplot2 is compatible with
-  plyr <= 1.7.1 as well as plyr > 1.7.1.
-
-* `geom_polygon` draws multiple polygons as a single grob instead of as
-  separate grobs. This results in much better performance. For example,
-  drawing a world map is about 12 times faster. (Winston Chang. Fixes #666)
-
-MINOR FEATURES
-
-* A new theme `theme_minimal` has been added. This theme is based on
-  `theme_bw`, but does not have outlines around many of the rectangular
-  elements. (Baptiste Auguie)
-
-* A new theme `theme_classic` has been added. This theme has is based on
-  `theme_bw`. It has x and y axis lines, but no box around the plotting area
-  and no grid lines. (Thanks to David Kahle)
-
-* `geom_segment` allows setting `lineend`. (Jean-Olivier Irisson)
-
-* `ggsave` raises an error when making images larger than 50x50 inches.
-  This prevents accidentally creating extremely large bitmap images that
-  hang R and eat up memory. (Winston Chang. Fixes #517)
-
-* `train_cartesian` and `train_trans` are no longer memoized. Previously
-  the results of these functions were saved and so they would not
-  respond changes in the operating environment, such as a change in
-  locale. (Winston Chang. Fixes #592)
-
-* In `stat_ydensity` and `geom_violin`, the `scale` argument now accepts
-  the value "width", for equal widths. Additionally `scale="equal"` has
-  been deprecated, in favor of "area". (Jean-Olivier Irisson)
-
-* `stat_quantile` now supports `rqss`.
-
-* `scale_size_area` has been added as a replacement for `scale_area`. This
-  makes the naming more consistent. The new scale also by default makes the
-  area of points proportional to the value, which is different from what
-  `scale_area` does. (Fixes #635)
-
-* Functions now have gradual deprecation behavior with the `gg_dep` function.
-
-* Scales for required but missing aesthetics (x and y) are now automatically
-  added. (Fixes #676)
-
-* `geom_crossbar` previous raised a warning when notches were used and the
-  notches went outside the hinges. This has been changed to a message.
-
-BUG FIXES
-
-* With `geom_segment`, when a variable mapped to `linetype` had an NA
-  value, it would raise an error. This is now fixed. (Winston Chang.
-  Fixes #623)
-
-* When using `coord_map` with some projections, latitude lines wrapped
-  around the globe and added extra lines. (Winston Chang. Fixes #562)
-
-* `stat_summary` now calculates a unique value at each x. (Winston
-  Chang. Fixes #622)
-
-* Colorbar guides now supports language objects returned from functions
-  like `math_format()`, and will render them as expressions. (Kohske
-  Takahashi)
-
-* When using `coord_polar`, NA or NaN values caused errors. They are now
-  ignored instead. (Winston Chang)
-
-* Text theme elements used in `guide_legend`, such as `label.theme`, caused
-  confusing errors when the angle wasn't set. Now it produces a more
-  informative error message.
-
-* Theme elements now have their subclass listed first, before the `element`
-  class. (Thanks to Jeffrey Arnold)
-
-* Previously when free scales were used with non-cartesian coords, they just
-  wouldn't work. Now ggplot throws an error with an informative message.
-  (Fixes #673)
-
-* `geom_dotplot` previously worked with `position="dodge", but did not work
-  when using `position=position_dodge()`. It now works with both. (Fixes
-  #709)
-
-* For linetype scales, NA values previously caused errors. Now `na.value`
-  for linetype scales defaults to "blank". (Fixes #711)
-
-ggplot2 0.9.2.1
-----------------------------------------------------------------
-
-BUG FIXES
-
-* find_global now searches for objects in the namespace environment
-  instead of the package environment. This fixes problems when ggplot2
-  is imported to another package but not attached.
-
-ggplot2 0.9.2
-----------------------------------------------------------------
-
-THEME SYSTEM
-
-* The theme system has been completely rewritten. (Winston Chang)
-
-* The functions `theme_text`, `theme_line`, and so on have been renamed to
-  `element_text`, `element_line`, and so on.
-
-* The `opts()` function has been renamed to `theme()`.
-
-* To set the plot title, use `labs(title = "...")` or `ggtitle("...")
-  instead of `opts(title = "...")`.
-
-* Elements are now just lists of properties, instead of functions that
-  return grobs.
-
-* Theme elements now can inherit properties. For example, `axis.title.x`
-  inherits properties from `axis.title`, which in turn inherits from
-  `text`. The inheritance tree is stored in ggplot2::.element_tree.
-
-* Theme objects can now be added to each other with `+`, without a ggplot
-  object. There is also a new `%replace%` operator for adding theme
-  objects together.
-
-* Vertical and horizontal grid lines can now be controlled independently,
-  with `axis.grid.major.x`, `axis.grid.major.y` (and the same for minor);
-  `axis.ticks.x` and `axis.ticks.y`; and `axis.line.x` and `axis.line.y`.
-
-* The `size` property of theme elements can be defined relative to the
-  parent objects, using the `rel()` function.
-
-MINOR FEATURES
-
-* ggplot2 now uses the external gtable package instead of internal gtable
-  functions.
-
-* The condition that set parameters (e.g. `colour = "red"`) could only be of
-  length one has been relaxed - they may now be of length one, or exactly the
-  same length as the data. Recycling is not done because it makes it harder to
-  spot problems. This makes `annotate` considerably more flexible. (Fixes
-  #489)
-
-* `stat_contour` is now somewhat faster
-
-* new stat class `stat_ecdf` that shows empirical cumulative distribution
-  function. (Kohske Takahashi)
-
-* Dependency on `gpclib` removed, and `fortify.SpatialPolygonsDataFrame` will
-  now use `rgeos` if available - this is particularly useful if you're not
-  able to use the non-free `gpclib`.
-
-* `ggsave` now supports emf output files.
-
-* all "template" plots (`plotmatrix`, `ggorder` etc) have been deprecated and
-  will be removed in a future version. These plots are poorly tested and
-  poorly supported and really belong in a separate package.
-
-* The default guide for continuous color/fill scale is now colourbar.
-  (Kohske Takahashi. Fixes #555)
-
-* The arrowhead of geom-path and geom-segment with `arrow = TRUE` is
-  now filled with the same colour as the path.
-
-* The algorithm for calculating breaks locations has been changed from
-  `pretty_breaks()` to `extended_breaks()` from the 'labeling' package
-  by Justin Talbot. (Winston Chang. Fixes #580)
-
-* `scale_type`, the function used to pick which type of scale should be
-   used for a given type of input variable is now an S3 generic. That
-   means that if you want to add a new default type of scale you can
-   provide a method - it should return a string giving the name of the
-   scale to use (e.g. "continuous", "discrete", "date")
-
-* When there are multiple guides (legends), the order that they are
-  displayed can now be controlled manually. (Kohske Takahashi. Fixes
-  #470)
-
-* When a scale for a given aesthetic is added to a plot more than once,
-  display a message indicating that the first scale will be replaced.
-  (Winston Chang. Fixes #518)
-
-DOCUMENTATION
-
-* All geoms and stats now document their aesthetics. (Thanks to joranE.
-  Fixes #447)
-
-BUG FIXES
-
-* `scale_x_continuous` now respects `na.value` (Fixes #522)
-
-* `geom_map` now correctly uses set aesthetics (e.g. `colour = "green"`)
-
-* Setting breaks outside the limits of the x or y axis no longer causes
-  errors. (Kohske Takahashi. Fixes #552)
-
-* `facet_locate` no longer evaluates unneeded expressions. (Winston
-  Chang. Fixes #565)
-
-* `annotation_map` now gets group id from munched data. (Winston Chang.
-  Fixes #568)
-
-* `geom_raster` now supports alpha. (Kohske Takahashi. Fixes #596)
-
-* Both axis lines are now drawn above the plotting area panel.
-  (Winston Chang. Fixes #585)
-
-* The jitter resolution is now correctly calculated when the data
-  does _not_ include zero. (Thanks to Karl Ove Hufthammer. Fixes #572)
-
-* Legend icons for `geom_boxplot` now display linetype. (Kohske
-  Takahashi. Fixes #608)
-
-* Facets now appear in the correct order when layers with different
-  factor levels are added. (Winston Chang. Fixes #543)
-
-* Distances in polar coordinates are calculated along spiral arcs,
-  instead of straight-line distance. (Winston Chang. Fixes #471)
-
-* `fortify.SpatialPolygonsDataFrame` now uses the correct ordering.
-  (Charlotte Wickham. Fixes #434)
-
-* `stat_vline` and `stat_hline` no longer throw errors when
-  `xintercept` and `yintercept` are passed to them. (Winston Chang.
-  Fixes #624)
-
-ggplot2 0.9.1
-----------------------------------------------------------------
-
-MINOR FEATURES
-
-* `ggstructure` and `ggorder`, which call `ggpcp`, no longer have a
-  `scale` argument since `ggpcp` does not have one.
-
-* built in datasets have been checked to make sure they use characters,
-  factors and ordered factors appropriately
-
-* `geom_raster` and `annotation_raster` gain new `interpolate` argument for
-  controlling whether or not rasters are interpolated
-
-* Added `plot` as an alias for `print` for ggplot objects.
-
-* Visual tests have been moved to /visual_test and modified to work with the
-  vtest package. (Thanks to Winston Chang)
-
-* `geom_dotplot`: now supports stacking. It uses `stackgroups = TRUE` instead
-  of the usual position="stack", for technical reasons. It also will stack in
-  the x direction when binning along the y axis. (Thanks to Winston Chang)
-
-* `geom_rug` now allows control over which sides to put the rug lines, with
-  the `sides` argument. (Thanks to Winston Chang)
-
-* `annotation_logticks`: a new geom that adds tick marks on the inside of the
-  plotting rectangle that have diminishing spacing for log-10 axes. (Thanks
-  to Winston Chang)
-
-* Coordinate expansion is now handled by an interaction of the scale and
-  coord, rather than by the scale only. Also, the `wise` argument is no
-  longer needed. (Thanks to Winston Chang and Kohske Takahashi)
-
-BUG FIXES
-
-* `facet_grid` no longer drops duplicate cases (Fixes #443)
-
-* `munch_range` properly reports the x and y range. (Thanks to Winston Chang)
-
-* `stat_bin2d` handles data with NA in the position variables. Error was
-  triggered when scale was limited to a range smaller than the range of
-  the data. (Bug reported by Tao Gao; diagnosed and fixed by Brian Diggs)
-
-* `scale_*_identity` will now produce a legend when `guide = "legend"` and no
-  breaks or labels are supplied (Fixes #453)
-
-* `geom_map` now works with `coord_map` (Fixes #480)
-
-* discrete scales now accept named vectors of labels again (Fixes #427)
-
-* `geom_raster` works better with categorical input (Fixes #463)
-
-* `qplot` no longer uses non-standard evaluation for geom/stat arguments - it
-  doesn't seem to be needed and was causing problems when qplot was used in
-  special environments (e.g. in knitr) (Fixes #377)
-
-* `coord_train.polar` and `coord_train.trans` remove NAs from breaks.
-  (Thanks to Winston Chang. Fixes #422)
-
-* Theta breaks with `coord_polar` have equal angular spacing. (Thanks to
-  Winston Chang and Kohske Takahashi. Fixes #288)
-
-* Empty data frames are now handled correctly: layers with empty data are
-  dropped silently, instead of inheriting data from the plot. (Thanks to
-  Winston Chang. Fixes #31, #332, #506 and #507)
-
-* The alpha value of set colours is now preserved by default. To return to the
-  old behaviour, set `alpha = 1`. (Fixes #475)
-
-* `scale_*_manual` will throw an error if you have too few values. (Fixes
-  #512)
-
-* `facet_wrap` gets the `as.table` argument back. (Fixes #497)
-
-* `resolution` now returns 1 when range is zero. (Fixes #526)
-
-* Titles are displayed above legend when legend is on top. (Thanks to
-  Kohske Takahashi. Fixes #432)
-
-* Specifying breaks outside coord limits works. (Thanks to Kohske Takahashi.
-  Fixes #430)
-
-* `renames_aes` now uses exact matching instead of partial matching. (Thanks
-  to Winston Chang. Fixes #529)
-
-* `labs()` now works with American spellings. (Thanks to Winston Chang.
-  Fixes #521)
-
-* `stat_density2d` sets the limits for `kde2d` from the limits of the x and
-  y scales. (Thanks to Winston Chang)
-
-ggplot2 0.9.0
-----------------------------------------------------------------
-
-NEW FEATURES
-
-* `annotation_custom`: a new geom intended for use as static annnotations that
-  are the same in every panel. Can be used to add inset plots, tables, and
-  other grid-based decorations inside the plot area (Contributed by Baptiste
-  Auguié).
-
-* `geom_map`: a new special case of `geom_polygon` useful when you are drawing
-  maps, particularly choropleth maps. It is matched with `annotation_map`, an
-  even faster special case when you want the same map drawn in each panel.
-
-* `geom_raster` is a special case of `geom_tile` for equally sized rectangular
-  tiles. It uses the raster functionality of R graphics devices for massively
-  increased speed and much decreased file sizes. It is matched with
-  `annotation_raster`, an even faster special case, for when you want to draw
-  the same raster in each panel.
-
-* `geom_violin`: an implementation of violin plots, which are a way of
-  visualizing kernel density estimates. (Thanks to Winston Chang)
-
-* `geom_dotplot`: dot plots, as described in Wilkinson (1999). To bin the
-  data, it uses `stat_bindot` to bin the data, which has two methods: histodot
-  and dot-density. Histodot binning uses fixed-width bins just like
-  `stat_bin`, while dot-density binning uses variable-width bins. A new grob,
-  `grob_dotstack` is used to render the dots. (Thanks to Winston Chang)
-
-* New fortify methods have been added for objects produced by the `multcomp`
-  package.
-
-* `stat_summary2d` and `stat_summary_hex`. These are work like `stat_bin2d`
-  and stat_binhex but allow any summarisation function (instead of just
-  count). They are 2d analogs of `stat_summary`
-
-* `facet_grid`: The space argument now supports `free_x` and `free_y` next to
-  `free` and `fixed, this allows the user to adjust the spatial scaling of the
-  facets in either the x or y direction. This is especially useful when the
-  scales are very different. In this case space = `free` could make some
-  facets very small. (Thanks to Willem Ligtenberg)
-
-DOCUMENTATION
-
-* Thorough clean up and checking, including documenting all arguments, adding
-  systematic cross-references, and adding commonly requested examples. Thanks
-  to Jake Russ and Dennis Murphy for the help.
-
-* Complete series of aesthetics pages (grouped subsets of aesthetics) with
-  examples of how to use the major ones, see e.g. `?fill`, `?shape`, `?x`,
-
-* Added a complete list of theme opts with usage examples in `?opts`
-
-* Added "translate" pages to demonstrate usage between qplot and ggplot, GPL,
-  base and lattice graphics: `?translate_qplot_base`, `?translate_qplot_gpl`,
-  `?translate_qplot_lattice`, `?translate_qplot_ggplot`,
-
-SCALES
-
-* Scales have been rewritten to use the new `scales` package, which does a
-  much better job at defining what a scale is and making it easier for you to
-  create your own scales. Scales should now behave much more consistently, and
-  it should be easier for me to add new features in the future.
-
-* `breaks` parameter can now be a function, which will be passed the scale
-  limits and expected to return a character vector of breaks
-
-* `labels` parameter can now be a function - this replaces the previous
-  formatter function that only some scales possessed, and the `major` argument
-  to the data time scales. This function should take a vector of breaks as
-  input, and return a character vector or list of expressions as output. See
-  `comma_format`, `dollar_format`, `percent_format`, `scientific_format`,
-  `parse_format` and `math_format` for examples
-
-* Transformations are now provided by the scales package - see `?trans_new`
-  for list of available transformations, and how to create your own. The
-  transformations in this package should do a better job at computing default
-  breaks.
-
-* Transformations for continuous scales are now detected automatically when
-  the default scales are added. This ensures that dates and date times will
-  display correctly when used for any aesthetic - previously they only worked
-  with position scales. The system is now also easier to extend to new types
-  of continuous data that you might want to plot.  (Fixes #48)
-
-* All scales now accept a `na.value` parameter which provides an aesthetic
-  value to be used for `NA` values in the data. Colour/fill scales default to
-  grey, which should stand out as different from non-missing values.
-
-* The new `oob` (out of bounds) parameter controls how scales deals with
-  values outside the limits. The default action is `censor` - see `clip` for
-  another option.
-
-* Only `scale_x_log10`, `scale_x_sqrt` and `scale_x_reverse` provided as
-  convenience functions for x and y scales. Use e.g. `scale_x_continuous(trans
-  = "log")` to access others
-
-* `set_default_scale` has been removed. If you want to change the default
-  scale for an aesthetic, just create a function called
-  `scale_aesthetic_continuous` or `scale_aesthetic_discrete` that returns the
-  scale that you want.  For example:
-
-      p <- qplot(mpg, wt, data = mtcars, colour = factor(cyl))
-      p
-      scale_colour_discrete <- scale_colour_brewer
-      p
-
-* Scales now automatically shrink to what is actually displayed on the plot,
-  not the underlying data used for statistical transformation. If you want the
-  old behaviour, supply `shrink = FALSE` to the facetting specification.
-  (Fixes #125)
-
-* `scale_colour_gradient` and `scale_fill_gradient` now use a colour scheme
-  with constant hue but varying chroma and luminance. This is better because
-  it creates a natural ordering inline with the order of the colour values.
-
-FACETS
-
-* Converted from proto to S3 objects, and class methods (somewhat) documented
-  in `facet.r`. This should make it easier to develop new types of facetting
-  specifications.
-
-* The new `facet_null` specification is applied in the default case of no
-  faceting. This special case is implemented more efficiently and results in
-  substantial performance improvements for non-facetted plots.
-
-* Facetting variables will no longer interfere with aesthetic mappings -
-  `facet_wrap(~ colour)` will no longer affect the colour of points.
-
-DEVELOPMENT
-
-* ggplot2 has moved away from the two (!!) homegrown documentation systems
-  that it previously relied on, and now uses roxygen extensively. The current
-  downside is that this means that ggplot2 website can no longer be updated,
-  but I hope work with the `helpr` package will resolve that shortly.
-
-* ggplot2 now uses a `NAMESPACE`, and only exports functions that should be
-  user visible - this should make it play considerably more nicely with other
-  packages in the R ecosystem. Note that this means you now need to explicitly
-  load `plyr` (and other packages) if you are using them elsewhere in your
-  code.
-
-* ggplot2 now has a start on a set of automated tests. As this test suite
-  expands it will help me ensure that bugs stay fixed, and that old bugs don't
-  come back in new versions. A test suite also gives me more confidence when
-  I'm modifying code, which should help with general code quality.
-
-COORDS
-
-* Converted from proto to S3 objects, and class methods (somewhat) documented
-  in `coord.r`. This should make it easier to develop new types of coordinate
-  systems.
-
-* Added a new method `coord_range` for finding the x and y range even after
-  coordinates have been transformed to other names (eg., theta and r). (Thanks
-  to Winston Chang)
-
-RENDERING
-
-* When printing a ggplot2 object, the rendered plot information is returned
-  invisibly. You can capture this with (e.g.) `x <- print(qplot(mpg, wt, data
-  = mtcars))` and in the future will be able to use it to get information
-  about the plot computations, such as the range of all the scales, and the
-  exact data that is plotted.
-
-* Drawing a plot takes place in three documented steps: `ggplot_build` which
-  creates a list of data frames ready for rendering builds, `ggplot_gtable`
-  which creates a `gtable` of grobs, and `grid.draw` which renders the grobs
-  on screen. Each of these returns a data structure which should be useful for
-  understanding and modifying the rendered plot. This is still a work in
-  progress, so please ask questions if anything is confusing.
-
-* The `drop` and `keep` parameters to `ggsave` and `print.ggplot` have been
-  dropped, as the data structure returned by `ggplot_gtable` is sufficiently
-  rich enough to remove the need for them.
-
-* Axis labels are now centred underneath the panels (not the whole plot), and
-  stick close to the panels regardless of the aspect ratio.
-
-GUIDES
-
-* Guides (particularly legends) have been rewritten by Kohske Takahashi to
-  provide considerably more layout flexibility.
-
-* `guide_legend` now supports multi-row/column legend and reversed order,
-  gives more flexible positioning of title and label, and can override
-  aesthetics settings. This is useful, for example, when alpha value in a
-  panel is very low but you want to show vivid legend.
-
-* `guide_colorbar` is a guide specially for continuous colour scales as
-  produced by colour and fill scales.
-
-MINOR CHANGES
-
-* `geom_text` now supports `fontfamily`, `fontface`, and `lineheight`
-  aesthetics for finer control over text display. (Thanks to Kohske Takahashi
-  for the patch. Fixes #60)
-
-* `collide`, which powers `position_dodge` and `position_stack`, now does not
-  error on single x values (Thanks to Brian Diggs for a fix. #157)
-
-* `...` in `ggplot` now passed on to `fortify` method when used with an object
-  other than a data frame
-
-* `geom_boxplot`: outlier colour and shape now default to values set by the
-  aesthetic mapping (thanks to suggestion by Ben Bolker), the width of the
-  median line is now `fatten` times the width of the other lines (thanks to
-  suggestion by Di Cook), and the line type can now be set. Notched box
-  plots are now supported by setting `notch = TRUE` (thanks to Winston Chang
-  for the patch).
-
-* `ggsave` can work with cm and mm `units` (Thanks to patch from Jean-Olivier
-  Irisson)
-
-* `scale_shape` finally returns an error when you try and use it with a
-  continuous variable
-
-* `stat_contour` no longer errors if all breaks outside z range (fixes #195).
-
-* `geom_text` remove rows with missing values with warning (fixes #191)
-
-* New generic function `autoplot` for the creation of complete plots
-  specific to a given data structure. Default implementation throws
-  an error. It is designed to have implementations provided by other
-  packages.  (Thanks to suggestion by Brian Diggs)
-
-* `ggpcp` loses the `scale` argument because it relied on reshape(1) code
-
-* `map_data` passes `...` on to `maps::map` (Fixes #223)
-
-* `coord_fixed` accepts `xlim` and `ylim` parameters to zoom in on x and y
-  scales (Fixes #91)
-
-* ggplot2 will occasionally display a useful hint or tip on startup.  Use
-  `suppressPackageStartupMessages` to eliminate
-
-* `stat_binhex` uses correct bin width for computing y axis bounds. (Fixes
-  #299, thanks to Dave Henderson for bug report and fix.)
-
-* `stat_smooth` now adjusts confidence intervals from `loess` using a
-  t-based approximation
-
-* `stat_smooth` reports what method is used when method is "auto". It also
-  picks the method based on the size of the largest group, not individually by
-  group. (Thanks to Winston Chang)
-
-* `stat_bin` and `geom_histogram` now use right-open, left-closed intervals by
-  default. Use `right = TRUE` to return to previous behaviour.
-
-* `geom_vline`, `geom_hline`, and `geom_abline` now work with non-Cartesian
-  coordinate systems. (Thanks to Winston Chang)
-
-ggplot2 0.8.9
-----------------------------------------------------------------
-
-A big thanks to Koshke Takahashi, who supplied the majority of improvements
-in this release!
-
-GUIDE IMPROVEMENTS
-
-* key size: can specify width and height separately
-
-* axis: can partially handle text rotation (issue #149)
-
-* legend: now can specify the direction of element by opts(legend.direction =
-  "vertical") or opts(legend.direction = "horizontal"), and legend box is
-  center aligned if horizontal
-
-* legend: now can override the alignment of legend box by
-  opts(legend.box = "vertical") or opts(legend.box = "horizontal")
-
-* legend: now can override legend title alignment with opts(legend.title.align
-  = 0) or opts(legend.title.align = 1)
-
-* legend: can override legend text alignment with opts(legend.text.align = 0)
-  or opts(legend.text.align = 1)
-
-BUG FIXES
-
-* theme_*: can specify font-family for all text elements other than geom_text
-
-* facet_grid: fixed hirozontal spacing when nrow of horizontal strip >= 2
-
-* facet_grid: now can manually specify the relative size of each row and column
-
-* is.zero: now correctly works
-
-* +: adding NULL to a plot returns the plot (idempotent under addition)
-  (thanks to suggestion by Matthew O'Meara)
-
-* +: meaningful error message if + doesn't know how to deal with an object
-  type
-
-* coord_cartesian and coord_flip: now can wisely zoom when wise = TRUE
-
-* coord_polar: fix point division bugs
-
-* facet_grid: now labels in facet_grid are correctly aligned when the number
-  of factors is more then one (fixes #87 and #65)
-
-* geom_hex: now correctly applies alpha to fill colour not outline colour
-  (thanks to bug report from Ian Fellows)
-
-* geom_polygon: specifying linetype now works (thanks to fix from Kohske
-  Takahashi)
-
-* hcl: can now set c and l, and preserves names (thanks to suggestion by
-  Richard Cotton)
-
-* mean_se: a new summary function to work with stat_summary that calculates
-  mean and one standard error on either side (thanks to contribution from
-  Kohske Takahashi)
-
-* pos_stack: now works with NAs in x
-
-* scale_alpha: setting limits to a range inside the data now works (thanks to
-  report by Dr Proteome)
-
-* scale_colour_continuous: works correctly with single continuous value (fixes
-  #73)
-
-* scale_identity: now show legends (fix #119)
-
-* stat_function: now works without y values
-
-* stat_smooth: draw line if only 2 unique x values, not three as previously
-
-* guides: fixed #126
-
-* stat_smooth: once again works if n > 1000 and SE = F (thanks to bug report
-  from Theiry Onkelinx and fix from Kohske Takahashi)
-
-* stat_smooth: works with locfit (fix #129)
-
-* theme_text handles alignment better when angle = 90
-
-ggplot2 0.8.8
-----------------------------------------------------------------
-
-Bug fixes:
-
-* coord_equal finally works as expected (thanks to continued prompting from
-  Jean-Olivier Irisson)
-
-* coord_equal renamed to coord_fixed to better represent capabilities
-
-* coord_polar and coord_polar: new munching system that uses distances (as
-  defined by the coordinate system) to figure out how many pieces each segment
-  should be broken in to (thanks to prompting from Jean-Olivier Irisson)
-
-* fix ordering bug in facet_wrap (thanks to bug report by Frank Davenport)
-
-* geom_errorh correctly responds to height parameter outside of aes
-
-* geom_hline and geom_vline will not impact legend when used for fixed
-  intercepts
-
-* geom_hline/geom_vline: intercept values not set quite correctly which
-  caused a problem in conjunction with transformed scales (reported by Seth
-  Finnegan)
-
-* geom_line: can now stack lines again with position = "stack" (fixes #74)
-
-* geom_segment: arrows now preserved in non-Cartesian coordinate system (fixes
-  #117)
-
-* geom_smooth now deals with missing values in the same way as geom_line
-  (thanks to patch from Karsten Loesing)
-
-* guides: check all axis labels for expressions (reported by Benji Oswald)
-
-* guides: extra 0.5 line margin around legend (fixes #71)
-
-* guides: non-left legend positions now work once more (thanks to patch from
-  Karsten Loesing)
-
-* label_bquote works with more expressions (factors now cast to characters,
-  thanks to Baptiste Auguie for bug report)
-
-* scale_color: add missing US spellings
-
-* stat: panels with no non-missing values trigged errors with some statistics.
-  (reported by Giovanni Dall'Olio)
-
-* stat: statistics now also respect layer parameter inherit.aes (thanks to bug
-  report by Lorenzo Isella and investigation by Brian Diggs)
-
-* stat_bin no longer drops 0-count bins by default
-
-* stat_bin: fix small bug when dealing with single bin with NA position
-  (reported by John Rauser)
-
-* stat_binhex: uses range of data from scales when computing binwidth so hexes
-  are the same size in all facets (thanks to Nicholas Lewin-Koh for the bug
-  report)
-
-* stat_qq has new dparam parameter for specifying distribution parameters
-  (thanks to Yunfeng Zhang for the bug report)
-
-* stat_smooth now uses built-in confidence interval (with small sample
-  correction) for linear models (thanks to suggestion by Ian Fellows)
-
-* stat_spoke: correctly calculate stat_spoke (cos and sin were flipped, thanks
-  to Jean-Olivier Irisson for bug report and fix)
-
-ggplot2 0.8.7
-----------------------------------------------------------------
-
-* coord_map gains xlim and ylim arguments to control region of projection
-
-* corrected label generation for computed aesthetics (..x..) and special
-  names (`x x`)
-
-* fullseq: now always returns vector of length two, even when range is 0
-
-* geom_point legend takes more care to ensure that fill colours will be shown
-
-* legend: fixed scale merging bug when labels were set manually
-
-* scale_area: gains a legend argument like all other scales
-
-* scale_colour_brewer: gains na.colour argument to set colour of missing
-  values
-
-* stat_bin2d: fix typo in breaks calculation
-
-* stat_bin: deals with floating point rounding issues using the same
-  algorithm as base::hist
-
-* stat_density2d: fixed bug when contour = FALSE (Thanks to Takahashi Kohske)
-
-
-ggplot2 0.8.6
-----------------------------------------------------------------
-
-NEW FEATURES
-
-* trans_log1p: new log + 1 transformer contributed by Jean-Olivier Irisson
-
-BUG FIXES
-
-* aesthetics: fixed bug when overriding aesthetics with NULL
-
-* annotate: adds layers with legend = FALSE
-
-* coord_equal: correctly place tick marks (Fixes #61)
-
-* documentation: usage statements should now be spread over multiple lines
-
-* fortify.SpatialPolygonsDataFrame: fixed bug when region variable had missing values
-
-* legend: don't try and display legend when unnecessary scale added
-
-* legend: text labels now correctly left-aligned when non-numeric
-
-* order aesthetic now correctly affects position adjustments  (Fixes #70)
-
-* qplot loads facetting variables from global environment more correctly
-
-* scale_date and scale_date_time now work with infinite positions
-
-* scale_date and scale_date_time now take expand argument
-
-* scales were not getting automatically added in many situations (Fixes #69)
-
-* scale_manual was not returning labels in the correct format and so legends
-  were not getting merged correctly
-
-* stat_contour: fix error if x or y coordinates were negative
-
-* stat_bin: now copes with bars of zero height (Fixes #72)
-
-* stat_qq: always use sorted data (rather than interpolated quantiles) on
-  sample axis.  This makes it behave more like qqnorm
-
-* stat_quantile: correctly group results
-
-* xlim now works with datetimes
-
-* all plyr functions prefixed with their namespace to avoid clashes with other
-  packages (thanks to Steve Lianoglou)
-
-
-ggplot2 0.8.5
-----------------------------------------------------------------
-
-NEW FEATURES
-
-* geom_text gains parse argument which makes it possible to display
-  expressions. (Implements #50)
-
-* all scales now have legend parameter, which defaults to TRUE. Setting to
-  false will prevent that scale from contributing to the legend (Implements
-  #27)
-
-* default axis labels and legend titles are now stored in the options, instead
-  of in each scale. This fixes a long standing bug where it was not easy to
-  set the label for computed variable, such as the y axis on a histogram.
-  Additionally, it means default scales are only added to the plot until just
-  prior to plotting, instead of the previous behaviour where scales where
-  added as layers were added - this could cause problems if you later modified
-  the underlying data. (Implements #28)
-
-* coord_equal: when ratio = NULL (the default), it will adjust the aspect
-  ratio of the plot, rather than trying to extend the shortest axis.
-
-* x and y positions can be set to Inf or -Inf to refer to the top/right and
-  bottom/left extents of the panel. (Implements #18)
-
-* expand_limits(): a new function to make it easy to force the inclusion of
-  any set of values in the limits of any aesthetic.
-
-NEW FEATURES (MINOR)
-
-* aesthetics: when _setting_ an aesthetic, you may only set it to a single
-  value.  This was always a good idea, but now it is enforced with an
-  informative error message.
-
-* stat_contour bump up default number of contours
-
-* stat_density2d: make number of grid points used for density estimation
-  user controllable (implements #9)
-
-* geom_bin now allows you to set whether bins used intervals of the form
-  (a, b] or [a, b) with the "right" parameter (implements #20)
-
-* geom_path: linejoin, lineend and linemitre are now user controllable
-  (implements #24)
-
-* scales: all scales check that breaks are supplied if labels are, and
-  that breaks and labels are the same length (implements #40)
-
-* scales: if breaks are a named vector, the names will be used as labels
-  (thanks to suggestion by David Kahle)
-
-* scale_colour_gradient, scale_colour_gradient2 & scale_colour_gradientn now
-  have formatter argument to match scale_continuous
-
-* updated citation to refer to the ggplot2 book
-
-BUG FIXES
-
-* coord_cartesian now correctly sets limits when one or both of the position
-  scales are non-linear.  (fixes #17)
-
-* coord_equal: now works with non-linear scales (fixes #13)
-
-* coord_map sets aspect ratio correctly (fixes #4)
-
-* coord_polar correctly combines labels on end of axis if expressions
-  (fixes #39)
-
-* coord_trans now respects scale expand parameter (expansion occurs after
-  transformation) (fixes #14)
-
-* facet_grid with scales = "free" and space = "free" now calculates space
-  correctly if the range of the scale is < 1 (fixes #1)
-
-* facet_grid works once more when facetting with multiple variables in one
-  direction (fixes #11)
-
-* facet_wrap now sets aspect ratio correctly
-
-* facet_wrap now maintains original order of data
-
-* geom_hline and geom_vline now work with coord_flip (fixes #30)
-
-* geom_path drops missing values at start and end of each line (fixes #41)
-
-* scale_shape_discrete, scale_size_continuous, scale_alpha and
-  scale_linetype_discrete added to scales to match naming convention of all
-  other scales (fixes #47)
-
-* legends now correctly calculate label widths (fixes #38)
-
-* legends will only merge if both the title and all labels are the same.
-  (fixes #16)
-
-* legends: fix for bug #19: Legend with three constraints doesn't work
-
-* stat_contour & stat_density2d: fix grouping bugs (issue #7)
-
-* xlim, ylim: fix bug when setting limits of discrete scales
-
-
-ggplot2 0.8.4
-----------------------------------------------------------------
-
-* aes and aes_string both convert prefixes to full names
-* aesthetics: corrected list of aesthetics to include american spelling of
-  colour as well as base R abbreviations
-* aesthetics: fix bug in detecting which aesthetics are calculated
-* aes_string treats NULL as "NULL"
-* annotate now works with missing x and y (e.g. for geom_rect)
-* continuous scale limits now automatically sorted
-* coord_polar: fix bug if breaks not all inside limits
-* facet_wrap: can now specify both ncol and nrow without getting an error
-* facet_wrap: now works with statistics that produce both x and y values (e.g.
-  stat_qq)
-* fullseq now adds additional break on bottom if necessary, so that the
-  include.lowest argument in cut never comes into play (this the source of a
-  potential bug in histograms)
-* geom_boxplot: alpha now affects fill colour of boxes only
-* geom_path correctly switches to segments if varying alpha used (thanks to
-  Karl Ove Hufthammer for the report and Baptiste Auguie for the fix)
-* geom_point: the alpha aesthetic now also affects the fill.
-* geom_ribbon always sorts input to avoid problems with certain pathological
-  inputs
-* geom_smooth was incorrectly applying alpha to line colour in the legend
-* nullGrob renamed to zeroGrob to avoid name conflict with grid
-* position_collide now works with missing values
-* position_stack: fixed bug in detection of overlap for negative values
-* scale_discrete_position now uses drop argument to force dropping of unused
-  levels
-* scale_gradient, scale_gradient2 and scale_gradientn now uses label
-  parameters, if supplied
-* scale_x_inverse, scale_y_inverse now actually work, and added recip as alias
-* stat_qq now correctly groups results
-* stat_smooth will not try and fit a line to 2 or fewer points (previously
-  didn't try for only 1 point)
-* stat_spoke now works with reversed scales
-* grouping: now consistent between different geoms (Issue #33)
-
-ggplot2 0.8.3
-----------------------------------------------------------------
-
-New features
-
-* alpha: new aesthetic, with scale alpha.  Where a geom has both fill and colour, alpha affects the fill.
-
-* annotate: new annotate function to make it easier to add annotations to plots
-
-* facet_grid now takes strip label function from parameter labeller, not theme setting
-
-* facet_grid: gains as.table argument to control direction of horizontal facets
-
-* fortify: full set of methods for turning data from the sp package into data frames that can be plotted with ggplot2
-
-* geom_errorbarh: new geom for horizontal error bars
-
-* labels_parsed and labels_bquote functions to make it easier to display expressions on facet labels
-
-* scale_manual now supports breaks and limits
-
-* subset: experimental new feature.  Layers now have a subset argument, which takes subsets formatted like .(var1 < 5, var2 == 3) etc.
-
-* xlim and ylim now work recognise Date and POSIXct classes to create date and date_time scales respectively
-
-Dealing with missing values
-
-* facet_wrap: add drop argument to control whether or not panels for non-existent combinations of facetting variables should be dropped or not.  Defaults to TRUE
-
-* scale_discrete: empty factor levels will be preserved, unless drop = TRUE
-
-Bug fixes
-
-* added presidents dataset from book to package
-
-* American spelling of color accepted in as geom parameter, and all colour
-  scales have alias spelled color (e.g. scale_color_hue)
-
-* facet_wrap: contents guaranteed to be clipped to panel
-
-* facet_wrap: corrected labelling when facetting by multiple variables (thank
-  to Charlotte Wickham for a clear test case)
-
-* geom_histogram now works with negative weights (provided position =
-  "identity").  This is useful for creating back to back histograms.
-
-* geom_step: improve legend
-
-* geom_text: better legend
-
-* geom_vline, geom_hline, geom_abline: should work in yet more situations
-
-* resolution: fixed bug in computation of resolution that lead to (e.g.)
-  incorrect boxplot widths when there was only a single x value in a group.
-
-* position_stack: fixed bug in detection of overlap for very large bins
-
-* scale_discrete: factor levels no longer mistakenly reordered
-
-* scale_hue: now spans full range of hue if it less than 360 degrees
-
-* scale_hue: rotated default hue range by 15 degrees to avoid unfortunate
-  red-green contrast in two colour case
-
-* show now works with ggplot objects
-
-* stat_sum: fixed bug which resulted in dropped aesthetics
-
-* stat_summary: now warns when dropping records with missing values
-
-* stat_summary: should be a little faster
-
-* stat_summary: correctly passes ... arguments on fun.data
-
-* theme_bw: corrected justification of axis.text.y
-
-* trans: bug fixes to logistic transformation
-
-* order aesthetic should work again
-
-ggplot2 0.8.2
-----------------------------------------------------------------
-
-New features
-
-* borders, fortify.map and map_data to make it easier to draw map borders and
-  choropleth maps
-
-* cut_interval and cut_number utility functions to discretise continuous
-  variables
-
-* stat_summary has reparameterised to make it easier to specify different
-  summary functions.  It now has four parameters: fun.y, fun.ymin and
-  fun.ymax; and fun.data.  See the documentation for stat_summary for more
-  details
-
-Minor improvements
-
-* ggfluctuation: default to aspect ratio that produces squares
-
-* ggsave: filename now first parameter, not second
-
-* qplot: if sample aesthetic is used, stat automatically set to qq
-
-* scale_datetime: improved breaks calculation
-
-* scale_gradient: better default colour scheme from red to blue (thanks to
-  Charlotte Wickham for providing the Munsell colours)
-
-* scale_size and scale_area: increased default size range
-
-* stats: all give useful error message if missing a required aesthetic
-
-* theme_set warns if missing needed theme elements
-
-* theme_text: now possible to right and left align text with hjust=0 and hjust=1 respectively
-
-Bug fixes
-
-* be explicit about is.discrete to avoid clash with Hmisc
-
-* facet_wrap: work around R bug so no longer crashers when ncol = 1
-
-* geom_errorbar now works correctly with dashed lines
-
-* geom_path will now silently ignore lines with less than 2 points (instead of
-  throwing a mysterious error as before)
-
-* geom_path now responds to the size aesthetic once more
-
-* geom_polygon etc now correctly displays linetype on legends
-
-* geom_step now works with multiple groups
-
-* geom_vline and geom_hline: fix bug when mapping intercept to variable in
-  data frame
-
-* ggsave: path parameter correctly sets path
-
-* guides: fix broken legend from default stat aesthetics (e.g. for stat_sum)
-
-* scale_manual now works better with missing values
-
-* scale_manual: labels now correctly sets legend labels.
-
-* stat_density_2d: no longer passes unnecessary parameters to kde2d causing an
-  error message (seen when setting aesthetics with qplot)
-
-* stat_pointrange: better relationship between point and line widths
-
-* stat_sum now correctly preserves other aesthetic columns (should be a bit faster too)
-
-
-ggplot2 0.8.1
-----------------------------------------------------------------
-
-New features
-
-* new labs, xlab & ylab functions for easily modifying axis labels and legend titles
-
-* qplot now guesses what geom you want based on the position aesthetics that you provide:
-
-  * both x & y: scatterplot
-
-  * only x: histogram
-
-  * only y: scatterplot of seq_along(y) vs y
-
-* scale_datetime: a first attempt at a scale for date time objects of class POSIXt
-
-Aesthetic improvements
-
-* legends should now work in cases where you have multiple layers the use the
-  same geom and have different aesthetic mappings
-
-* theme: new theme setting legend.key.size determines size of keys in legend
-
-* theme: new theme setting plot.margins to control the plot margins
-
-* tweaks to plot and legend layout
-
-Other minor improvements
-
-* geom_point warns if missing values present in data and not displayed on plot
-
-* geom_smooth gives a more accurate warning when you have incorrectly specified the grouping
-
-* geom_smooth will switch to an alternative smoothing method (mgcv::gam(y ~
-  s(x, bs = "cr"))), when there are more than 1000 observations
-
-* layers gain a legend argument, which allow you to force the layer either
-  into (TRUE) or out of (FALSE) the legend
-
-Bug fixes
-
-* coord_equal now calculates scales correctly again
-
-* coord_flip: flips axes labels again too
-
-* coord_trans fix bug where transformation incorrect
-
-* facet_grid: fix bug where tick labels where being produced outside the range of the axes
-
-* facet_wrap: fixed bug with ncol = 1 or nrow = 1
-
-* facet_wrap: labels correctly clipped to axis ranges
-
-* facet_wrap: labels will match panels even when factor levels are not in alphabetical order
-
-* facet_wrap: now works when a layer doesn't contain every level of the faceting variables
-
-* geom_abline should now work in a wider variety of situations
-
-* geom_smooth now gives correct asymmetric standard errors with generalised
-  linear models (thanks to Thierry Onkelinx)
-
-* geom_vline and geom_hline now correctly transform their intercepts if the
-  scale is transformed
-
-* geom_vline and geom_hline: now use xintercept and yintercept instead of intercept
-
-* legend.position and legend.justification work again
-
-* position_dodge now works for any number of elements with smaller widths, not just 2!
-
-* scale_discrete_position: does a better job of calculating axis limits when
-  plotting a mixture of continuous and discrete values (e.g. with geom_jitter)
-
-* summary: tweaks to improve output
-
-
-ggplot2 0.8  (2008-11-18)
-----------------------------------------
-
-* The two biggest new features in this release are the (long awaited) ability
-  to have scales that vary between facets, and a faceting system that works
-  like lattice (facet_wrap). From qplot, you can use facet_wrap by specifying
-  one sided formula (~ colour, as opposed to . ~ color). To see some potential
-  uses for these new features, see the "Positioning" chapter of the book.
-  Implementing these changes has required a rewrite of large parts of the
-  coordinate systems code, so if anything seems strange with non-Cartesian
-  coordinate systems, please get in touch.
-
-* I've also made another round of tweaks to make the plots more aesthetically
-  pleasing.This includes using a bright blue colour for geoms used to add
-  statistical summaries to plots (contour, smooth, and quantiles), and
-  tweaking the default colour scheme for the continuous colour scale.Please
-  let me know what you think.Remember that most of these options are
-  controllable with the theming system - see the book chapter "Polishing your
-  plots for publication".
-
-* Accompanying this new release of the package is an updated and expanded
-  version of the book. The content of the book is now largely complete (~170
-  pages), and over the coming months I will be working on make it polished and
-  easy to understand.See http://had.co.nz/ggplot2/book.I love to hear your
-  feedback about the book, but at this point please don't bother reporting
-  minor typos, I would much rather hear about what you want to do, but can't
-  figure out from the book.
-
-Other new features:
-
-* geom_bin2d/stat_bin2d & geom_hex/stat_binhex: for 2d square and hexagon binning, particularly useful for alleviating overplotting in scatterplots
-
-* geom_freqpoly: draws frequency polygons (= stat_bin + geom_line)
-
-* scale_position: both discrete and continuous gain a new formatter argument
-  to control the default formatting of the axis labels.  See also the handy
-  numeric formatters: dollar, comma and percent
-
-* the xlim and ylim functions now produce discrete scales when appropriate,
-  and generate a reverse scale if the minimum is greater than the maximum
-
-Improvements
-
-* coord_map gains experimental axis labels
-
-* facet_grid: new support for varying scales in rows and columns
-
-* facet_wrap: new faceter which wraps a 1d ribbon of panels into 2d, in a
-  similar way to lattice
-
-* geom_bin: gains a drop argument to control whether or not 0 count bins
-  should be removed
-
-* geom_path and geom_line gain arrows argument to match geom_segment
-
-* ggsave now checks that you are using it with a ggplot plot
-
-* ggsave now produces postscript files that are suitable for embedding in
-  another document
-
-* ggsave now recognises the .svg extension and will produce svg files, if
-  possible
-
-* ggsave: default dpi changed to 300, on the assumption that you are saving
-  the plot for printing
-
-* qplot: uses facet_wrap if formula looks like ~ a + b (as opposed to a ~ b)
-
-Aesthetic tweaks
-
-* geom_bar, geom_polygon, geom_rect, ...: default fill colour is now much
-  closer to black to match the defaults in other geoms (point, line, etc)
-
-* geom_line, geom_path, geom_segment: lines have squared ends
-
-* geom_point, geom_pointrange and geom_boxplot: now use shape = 16 instead of
-  19.  This shape does not have a border from R 2.8 on, and so will look
-  better when displayed transparently.
-
-* geom_contour, geom_density2d, geom_quantile and geom_smooth use a bright
-  blue colour for lines, to make them stand out when used with black points
-
-* scale_gradient: tweaked default colours to make more aesthetically pleasing
-
-* theme: new theme setting panel.margin (a unit) controls gap between panels
-  in facetted plots (for both grid and wrap)
-
-* theme_gray: removed black border around strips
-
-* theme_bw: tweaks to make black and white theme look a little nicer
-
-Bug fixes
-
-* coord_cartesian now correctly clips instead of dropping points outside of its limits
-
-* facet_grid: margins now grouped correctly in default case (non-aesthetic
-  variables ignored when generating default group value)
-
-* facet_grid: fix long standing bug when combining datasets with different
-  levels of facetting variable
-
-* geom_smooth calls stat::predict explicitly to avoid conflicts with packages
-  that override predict for S4 model classes
-
-* grid: correctly expose subcomponents of strips and axes
-
-* mapping aesthetics to functions of stat output now works in a much wider
-  variety of cases
-
-* order aesthetic should now work with bars (and in general more geoms)
-
-* position_dodge now works with points and other geoms that lack xmin and xmax
-
-* scale_area works once more
-
-* scale_discrete_position: empty levels are no longer displayed by default, if
-  you want them, use breaks = levels(myfactor)
-
-* scale_discrete_position: fixed bug when limits were set
-
-* scale_discrete_position: more aesthetically pleasing expansion for a wider
-  ranges of plots (picks expansion based on whether or not geom with width
-  used, e.g. bars)
-
-* scale_gradient*: axes are correctly labelled when a transformation is used
-
-* scale_x_log10, scale_y_sqrt etc now correctly transform output from
-  statistics as well as raw data
-
-* scale_z_* now removed because no longer used by anything
-
-* stat_bin: correctly returns 0 when no observations in a bin (was previously
-  returning NA)
-
-* stat_quantreg: deal with yet another new output format from quantreg
-
-* stat_contour now has arguments to control the position of the contours,
-  rather than relying on the z scale
-
-* theme: panel.empty setting removed as it is no longer used
-
-* theme_grey now aliased to theme_gray
-
-* theme_line: setting size works correctly
-
-* theme_rect, theme_segment: size now measured in mm, to be consistent with
-  the rest of ggplot
-
-ggplot2 0.7
-----------------------------------------------------------------
-
-* ggplot2 0.7 introduces a new theming system which allows you to control
-  (almost) every aspect of the appearance of the plot.  This system is
-  documented in the book chapter "Polishing your plots for publication",
-  available from http://had.co.nz/ggplot2/book/polishing.pdf.
-
-Bugs fixed
-
-* geom_boxplot: now displays outliers even if only one present
-
-* geom_jitter: setting one jitter direction to 0 now works
-
-* geom_segment: should now work correctly in all coordinate systems (note that
-  arrows only work in Cartesian coordinates)
-
-* ggsave: correctly uses dpi for raster devices and default dpi changed to 72
-  (thanks to Brian Ripley for pointing this out)
-
-* ggsave: current device no longer closes if error occurs
-
-* position_jitter: now works correctly with 0 jitter
-
-* remove_missing: some statistics were calculated incorrectly when missing
-  values were present
-
-* scales: extra scales ignored (again)
-
-* scales: legends respect fixed parameters of the layer
-
-* scales: legends won't appear when aesthetics are mapped to NULL, or set to fixed value
-
-* scales: xend and yend now transformed correctly
-
-* scale_date: breaks are now rounded to correct position
-
-New functionality
-
-* geom_point: can now control colour and fill separately for point glyphs with
-  borders
-
-* geom_step: now has parameter direction which can take values vh (vertical
-then horizontal)  or hv (horizontal then vertical) describing the shape of the
-stairs
-
-* qplot: new asp argument to set aspect ratio
-
-* qplot: now captures the environment in which it was run, which should make
-  it much more robust at finding the variables you expect it to find
-
-* qplot: now treats any arguments wrapped in I() as parameters, not
-  aesthetics, e.g. qplot(mpg, wt, data=mtcars, colour = I("red")) or
-  qplot(mpg, wt, data=mtcars, size = I(5))
-
-* scale_continuous: new minor_breaks argument to controls position of minor
-  breaks
-
-* scale_discrete: new discrete position scales which make it possible to
-  manually position elements
-
-* scale_gradientn: new colour scale which creates gradient between any list of
-  colours
-
-More consistent interfaces
-
-* can use color instead of colour, and old R names throughout ggplot2
-
-* geom_jitter: Arguments changed to height and width to match other position
-  adjustments
-
-* scales: any point outside of limits is dropped (this was previously the
-  behaviour for discrete scales, but not continuous scales)
-
-* scales: limits are consistent across discrete and continuous scales (limits
-  c(1, NA) form no longer works for continuous scales)
-
-* scales: order of legends reversed to match order of x axis (and to be
-  consistent with previous versions)
-
-* scale_date: new limits argument to set axis limits
-
-* scale_discrete: all discrete scales accept breaks argument
-
-* scale_discrete: all discrete scales have limits and labels argument to
-  better control legends
-
-* scale_discrete: character and logical vectors now reliably treated as
-  discrete scales
-
-* stat_density2d, geom_density2d: density2d used consistently (instead of
-  density_2d in some places)
-
-Improved aesthetics
-
-* coord_polar: more tweaks to grid lines to enhance appearance
-
-* coord_polar: new expand argument to control whether axes should be expanded
-  outside the range of the data
-
-* geom_contour, geom_smooth, geom_quantile: now use blue lines
-
-* position_stack, position_dodge: should be more informative if conditions for
-  stacking/dodging not met
-
-* position_jitter: default amount of jittering tweaked to align with boxplots
-  etc.
-
-* scales: background colour of legends key matches plot
-
-* themes: Complete rewrite of theming system, see new book chapter for details
-
-* themes: direct access to plot options via $ is now disabled
-
-Improved documentation and error messages
-
-* facet_grid: documentation improved
-
-* qplot: Better error messages when needed variables are missing
-
-* scale_discrete: improved error message for too many values in domain
-
-* scale_size: improved documentation for discrete variables
-
-* online documentation generally tweaked and primped to work a little better
- and look a little nicer
-
-* website now includes a search box
-
-* links from rdoc now point to correct pages
-
-
-ggplot2 0.6
-----------------------------------------------------------------
-
-The two big changes in this release are improved documentation and legends.
-
-* all major ggplot2 components now have their own built in documentation, so
-  that (e.g.) ?stat_smooth or ?geom_point now give you useful information
-
-* the legend code is now considerably more sophisticated and will attempt to
-  merge together legends for the same variable
-
-* also, legends are drawn based on the geoms used (instead of the scales
-  used, as previously) so should match the plot much better (e.g. for
-  geom_smooth, geom_boxplot, geom_vline, geom_abline, geom_pointrange).
-
-These features are new, so there are likely to be a few bugs that I haven't discovered.  Please me know if you discover any.
-
-Other additions and corrections
-
-* coord_equal: should now work correctly in all situations
-
-* coord_polar: add start and direction parameters, giving more control over
-  the layout of the polar coords
-
-* coord_polar: added my favourite pie chart example
-
-* coord_trans now deals with groups appropriately, at the cost of decreased
-  speed
-
-* geom_abline, geom_vline, geom_hline: should now behave better in a wider
-  variety of settings
-
-* geom_boxplot: deals with continuous x-axis and grouping much better
-
-* geom_boxplot: now has it's own legend which actually looks like a boxplot
-
-* geom_boxplot: reports if missing values removed
-
-* geom_crossbar: the middle line is now display thicker than the other lines,
-  controlled by the parameter fatten (thanks to Heike Hofmann for the
-  suggestion)
-
-* geom_density: fix scale adjustment bug in geom_density
-
-* geom_line, geom_text: all size measurements (now lines and text as well) are
-  measured in mm, lines/paths default to paths 0.5mm wide
-
-* geom_rug: new to add marginal rug plots
-
-* geom_smooth: added example showing how to use geom_smooth with your own
-  models
-
-* geom_smooth: fixed bug where if se=FALSE x axis always includes 0
-
-* geom_vline, geom_hline: yet another rewrite which should make them more
-  powerful and less error prone.
-
-* ggsave reports width and height of saved image
-
-* position_stack: fixed bug when data was empty
-
-* qplot: allow qplot to use computed aesthetics too
-
-* scale_continuous: tweaks to minor breaks to make appearance better on wider
-  range of coordinate systems
-
-* scale_discrete: all discrete scales now have labels argument which you can
-  use to override the factor levels
-
-* scale_discrete: now works correctly with character vectors
-
-* scale_size: changed default range to [0.5, 3] to better reflect new sizing
-  decisions
-
-* scale_size: legends resize to avoid overlaps
-
-* scale_x_continuous, scale_y_continuous: new convenience functions xlim and
-  ylim (and zlim) that make it even easier to adjust the limits of the x, y,
-  and z axes
-
-* stat_bin, geom_area: fixed bug in combination of stat_bin and geom_area that
-  made it difficult to draw frequency polygons
-
-* stat_bin: fixed bug which resulted in increased counts when the x axis was a
-  categorical variable with a single level (thanks to Bob Muenchen for
-  pointing this out!)
-
-* stat_bin: no longer incorrectly warns that binwidth is unspecified when
-  breaks are set
-
-* stat_bin: now takes origin argument to manually specify origin of first bin
-  (default is round_any(min(range), bin_width, floor))
-
-* stat_boxplot, stat_contour, stat_density_2d, stat_qq, stat_density: na.rm
-  parameter added to the following statistics (thanks to Leena Choi for
-  suggesting this)
-
-* stat_function: new, makes it easy to superimpose a function on the plot
-
-* stat_qq: axes flipped to agree with base R
-
-* stat_qq: now uses sample aesthetic to select variable for summary
-
-* stat_quantile: updated to work with latest version of quantreg
-
-* stat_spoke: new, to make it possible to use geom_segment parameterised by
-  angle and radius (thanks to Jiho for the suggestion)
-
-* stat_summary: better documentation
-
-* stat_summary: convenient auto wrapping of simple summary functions
-
-Miscellaneous changes:
-
-* it's now easy to change the default scales (and their arguments) with the
-  set_default_scale function, see ?set_default_scale for more details (thanks
-  to Bob Muenchen for the suggestion)
-
-* new order aesthetic which controls the order in which elements are plotted
-
-* min and max are now scaled the same way as y
-
-* functions are silently dropped (e.g. aes(colour=col))
-
-* scales do not try and map variables that don't exist (fixes some rather
-  obscure bugs)
-
-* aes(mpg, wt) is now equivalent to aes(x = mpg, y = wt)
-
-
-ggplot2 0.5.7
-----------------------------------------------------------------
-
-New geoms, scales and aesthetics
-
-* stat_step and geom_step to draw staircase plots (like plot(type="s"))
-
-* order aesthetic (currently only for lines/paths) allows you to control the
-  drawing order within a group
-
-* scale_manual makes it easier to let ggplot uses the exact
-  colours/sizes/linetypes that you want
-
-* scale_reverse allows you to reverse the scale of x and y axes
-
-* scale_grey is a new black and white scale for categorical data (colour and
-  fill)
-
-
-Improved options handling
-
-* new function opts() to allow modification of plot options by addition
-
-* update(p, theme_bw) and p + theme_bw now work
-
-These changes mean that you can modify plot options in the same way that you modify all other aspects of the plot, e.g.  qplot(mpg, wt, data=mptcars) + opts(title = "Fuel economy vs weight")
-
-Improved documentation
-
-* many tweaks to the online documentation, particular including the actual
-  code you need to run for each object!
-
-* every page now has a link to a form where you can submit feedback on exactly
-  you do or don't like about a page
-
-* required aesthetics now listed in documentation
-
-* geom_polygon now has a decent example
-
-* numerous minor corrections suggested by Jörg Beyer
-
-* separated plotting advice from details of plot construction (what vs how),
-  thanks to Bert Gunter for this suggestion
-
-
-Improved map projections (with coord_map)
-
-* coord_map defaults to orientation = c(90, 0, mean(range(y))) - this ensures
-  that multiple layers line up correctly, but means you will have to specify
-  the orientation yourself for many projections
-
-* coord_map now respects limits set by scales
-
-* removed useless ticks from coord_map
-
-If you're using ggplot to draw maps and have thought of other features that would make your life easier, please let me know.
-
-
-Bug fixes
-
-* adding data and aesthetics in separate steps should now work
-
-* layers with set parameters will not use mapped aesthetics
-
-* use LazyLoad: false instead of SaveData: true for better future
-  compatability
-
-* coord_cartesian: fixed bug that prevented you from overriding the default
-  axis expansion
-
-* coord_equal: now scales correctly if ratio < 1
-
-* geom_abline: fix bug where slope was ignored
-
-* geom_jitter now works correctly with groups and categorical values (was
-  actually a bug in how scale_discrete deals with continuous values)
-
-* geom_path: automatically switch between polylineGrob and segmentsGrob when
-  drawing paths so that setting line type now works properly
-
-* geom_segment now uses both ends of segments to calculate axis limits
-
-* plotmatrix: fix bug in scatterplot matrix where all scatterplots were
-  transposed!
-
-* qplot: should now work better within functions
-
-* quickplot added as an alias of qplot, to avoid confusion with qunif, etc
-
-* scale_*: better error message if you add a scale without a matching
-  aesthetic mapping in the plot
-
-* scale_identity no longer converts everything to character
-
-* scale_identity: grob argument renamed to guide
-
-* stat_*: made all statistics more robust to errors
-
-* stat_quantile: fixed bug when only drawing a single quantile
-
-* stat_smooth: returns silently if <2 non-missing data points
-
-
-Minor aesthetic improvements
-
-* coord_polar now specifies aspect.ratio by default, and I've made a few other
-  tweaks to make polar coordinates plot look nicer
-
-* geom_bar no longer draws gray borders by default, but instead uses the same
-  colour as fill (this eliminates a tiny gap between neighbouring bars)
-
-* plotmatrix: tweaks to improve display of scatterplot matrix
-
-* scale_brewer: added option to reverse palette
-
-* scale_colour: colour and fill legends now look exactly the same (previously
-  colour was missing a grey border)
-
-* scale_discrete has slightly larger expansion (0.75 vs 0.5)
-
-* stat_bar: only output bars with > 0 count
-
-
-ggplot2 0.5.6
-----------------------------------------------------------------
-
-Improved error messages and other notifications:
-
-* all geoms and position adjustments should now give an informative error
-  message when required aesthetics are missing
-
-* better error messages if data not a data frame, or mapping not created by
-  aes or aes_string
-
-* better errors for qplot when variables missing or data invalid
-
-* better error if somehow you are missing necessary scales
-
-* stat_bin informs you of the default choice of binwidth
-
-* stat_smooth gives helpful error messages for common problems
-
-* printing a geom now displays the data set that it uses (if not the default)
-
-Other improvements:
-
-* colour and fill legends now surround by background plot colour
-
-* can now draw arrow heads with geom_segment, and have added an example
-  demonstrating drawing a vector field
-
-* density plots should always include 0 on y axis
-
-* default boxplot outlier changed colour to black
-
-* stat_smooth supports categorical variables a little better
-
-* implemented hash methods for all ggplot objects.  This is the first step in
-  making it easier for me to compare all examples between versions for quality
-  control purposes
-
-New data:
-
-* seals, contributed by David Brillinger and Charlotte Wickham, used for
-  vector field example
-
-Bug fixes:
-
-* geoms hline, vline and abline now all work correctly when a grouping variable is used
-
-* block histograms (where individuals are identifiable) now work correctly
-
-* all ggplot objects should now print properly from the command line
-
-* fixed bug in geom_path when only 1 point
-
-* segments geom now works correctly for more coordinate systems
-
-* order variables in scatterplot matrix by order of variables in data.frame
-
-* geom_density deals with missing values correctly when displaying scaled densities
-
-* fixed bug in calculating categorical ranges
-
-* fixed bug in drawing error bars
-
-Subtractions
-
-* now relies on R 2.6
-
-* removed grid.gedit and grid.gremove, and code replaced by grid.ls
-
-ggplot2 0.5.5
-----------------------------------------------------------------
-
-Improvements:
-
-* ggplot now gives rather more helpful errors if you have misspecified a
-  variable name in the aesthetic mapping
-
-* changed default hline and vline intercepts to 0
-
-* added "count" output variable from stat_density for creating
-  stacked/conditional density plots
-
-* added parameters to geom_boxplot to control appearance of outlying points
-
-* overriding aesthetics with fixed values that have already been set with
-  aesthetics now actually works
-
-* slightly better names for xaxis and yaxis grobs
-
-* added aes_string function to make it easier to construction aesthetic
-  mapping specifications in functions
-
-* continuous scales now have labels argument so that you can manually specify
-  labels if desired
-
-* stat_density now calculates densities on a common grid across groups.  This
-  means that position_fill and position_stack now work properly
-
-* if numeric, legend labels right aligned
-
-* polar coordinates much improved, and with better examples
-
-Documentation:
-
-* fixed argument documentation for qplot
-
-* added (very) rudimentary documentation about what functions return
-
-* documentation now lists extra variables created by statistics
-
-Bug fixes:
-
-* coord_flip now works with segment and all interval geoms
-
-* geom_errorbar now works in all coordinate systems
-
-* derived y axes (eg. on histogram) are now labelled correctly
-
-* fixed bug in stat_quantile caused by new output format from predict.rq
-
-* fixed bug if x or y are constant
-
-* fixed bug in histogram where sometimes lowest bar was omitted
-
-* fixed bug in stat_qq which prevent setting aesthetics
-
-* fixed bug in qplot(..., geom="density", position="identity")
-
-* fixed stat_qq so that unnecessary arguments are no longer passed to the
-  distribution function
-
-Subtractions:
-
-* removed grid argument from ggsave, replaced by ggtheme(theme_bw)
-
-* removed add argument from qplot
-
-
-ggplot2 0.5.4
-----------------------------------------------------------------
-
-* border now drawn on top of geoms, instead of below - this results in better
-  appearance when adjusting scale limits
-
-* ggplot() + aes() now modifies existing default aesthetic mapping, rather
-  than overwriting
-
-* polish examples in facet_grid
-
-ggplot2 0.5.3
-----------------------------------------------------------------
-
-* added experimental scatterplot matrix, see ?plotmatrix
-
-* added new border.colour and grid.minor.colour options for better control
-  over plot apperance
-
-* updated theme_bw to do better when drawing a plot with white background
-
-* better default colour choices for gradients (and more discussion in examples)
-
-* fixed bug in ScaleGradient2 where scales with different positive and
-  negative ranges were not scaled correctly
-
-* allow expressions as result from strip.text
-
-* fixed rare bug in geom_vline and geom_hline
-
-* fixed example in geom_abline
-
-* tweaked display of multiline axis labels
-
-ggplot2 0.5.2
-----------------------------------------------------------------
-
-* add argument to position dodge so it's now possible to accurately dodge things with different widths to their physical widths
-
-* added median summary
-
-New examples:
-
-* logistic regression example in stat_smooth
-
-Bugs fixed:
-
-* evaluation of arguments to layer is no longer delayed
-
-* can use categorical xseq with stat_smooth
-
-* x and y axes named incorrectly (thanks to Dieter Menne for spotting this)
-
-* can now pass position objects to qplot
-
-* y jitter calculated correctly, and jittered data rescales axis now
-
-* removed silly legend from quantile plot
-
-* extra arguments not being passed on to geoms/stats
-
-* fixed bug in stat_summary when summarising a factor
-
-* fixed bugs in stat_summary, geom_ribbon, and coord_trans examples
-
-ggplot2 0.5.1
-----------------------------------------------------------------
-
-* renamed scale_manual to scale_identity to map position_identity and
-  stat_identity
-
-* ensured all grob consistently named
-
-* renamed aesthetics argument to mapping to be consistent with description in
-  book
-
-* added useful utilities for modifying grobs
-
-* bug fixes to x axis range with interval geoms
-
-* added ability to turn legend off for single scale (currently undocumented)
-
-* added economics data set and matching examples
-
-ggplot2 0.5
-----------------------------------------------------------------
-
-* complete rewrite of ggplot code base
-
-* id/grouping completely rewritten so that automatically grouped when any of
-  the aesthetics is a categorical variable.This behaviour is defined in the
-  Grammar of Graphics, and makes things like qplot(wt, data=mtcars,
-  geom="density", colour=factor(cyl)) work nicely
diff --git a/R/aaa-.r b/R/aaa-.r
index 56f5a1b..c40a3a2 100644
--- a/R/aaa-.r
+++ b/R/aaa-.r
@@ -1,57 +1,13 @@
-# INCLUDES <- "web/graphics"
-# FILETYPE <- "html"
-
-# Upper case first letter of string
-# This comes from the examples of some R function.
-#
-# @keyword internal
-firstUpper <- function(s) {
-  paste(toupper(substring(s, 1,1)), substring(s, 2), sep="")
-}
-
-TopLevel <- proto(expr = {
-  find_all <- function(., only.documented = FALSE) {
-    names <- ls(pattern=paste("^", firstUpper(.$class()), "[A-Z].+", sep=""), parent.env(TopLevel))
-    objs <- structure(lapply(names, get), names=names)
-
-    if (only.documented) objs <- objs[sapply(objs, function(x) get("doc", x))]
-    objs
-  }
-  find <- function(., name) {
-    fullname <- paste(firstUpper(.$class()), firstUpper(name), sep="")
-    if (!exists(fullname)) {
-      stop("No ", .$class(), " called ", name, call.=FALSE)
-    }
-    get(fullname)
-  }
-
-  my_name <- function(., prefix=TRUE) {
-    if (!prefix) return(.$objname)
-    paste(.$class(), .$objname, sep="_")
-  }
-  my_names <- function(.) .$my_name()
-
-  myName <- function(.) {
-    ps(firstUpper(.$class()), ps(firstUpper(strsplit(.$objname, "_")[[1]])))
-  }
-
-  params <- function(.) {
-    param <- .$parameters()
-    if (length(param) == 0) return()
-
-    if(!exists("required_aes", .)) return(param)
-
-    aesthetics <- c(.$required_aes, names(.$default_aes()))
-    param[setdiff(names(param), aesthetics)]
-  }
-
-})
-
-#' @export
-print.proto <- function(x, ...) x$pprint(...)
-pprint <- function(x, ...) print(as.list(x), ...)
-# name.proto <- function (...) {
-#        proto(print.proto = print.default, f = proto::name.proto)$f(...)
-# }
-
-
+#' @include ggproto.r
+NULL
+
+#' Base ggproto classes for ggplot2
+#'
+#' If you are creating a new geom, stat, position, or scale in another package,
+#' you'll need to extend from \code{ggplot2::Geom}, \code{ggplot2::Stat},
+#' \code{ggplot2::Position}, or \code{ggplot2::Scale}.
+#'
+#' @seealso ggproto
+#' @keywords internal
+#' @name ggplot2-ggproto
+NULL
diff --git a/R/aaa-constants.r b/R/aaa-constants.r
deleted file mode 100644
index 35016ac..0000000
--- a/R/aaa-constants.r
+++ /dev/null
@@ -1 +0,0 @@
-.pt <- 1 / 0.352777778
diff --git a/R/aes-calculated.r b/R/aes-calculated.r
index 139ba37..d8a14b6 100644
--- a/R/aes-calculated.r
+++ b/R/aes-calculated.r
@@ -28,13 +28,18 @@ strip_dots <- function(expr) {
   if (is.atomic(expr)) {
     expr
   } else if (is.name(expr)) {
-    as.name(gsub(match_calculated_aes, "\\1", as.character(expr)))
+    expr_ch <- as.character(expr)
+    if (nchar(expr_ch) > 0) {
+      as.name(gsub(match_calculated_aes, "\\1", expr_ch))
+    } else {
+      expr
+    }
   } else if (is.call(expr)) {
     expr[-1] <- lapply(expr[-1], strip_dots)
     expr
   } else if (is.pairlist(expr)) {
     # In the unlikely event of an anonymous function
-    as.pairlist(lapply(expr, expr))
+    as.pairlist(lapply(expr, strip_dots))
   } else if (is.list(expr)) {
     # For list of aesthetics
     lapply(expr, strip_dots)
diff --git a/R/aes-colour-fill-alpha.r b/R/aes-colour-fill-alpha.r
index ff60ec6..3b24a30 100644
--- a/R/aes-colour-fill-alpha.r
+++ b/R/aes-colour-fill-alpha.r
@@ -4,7 +4,7 @@
 #' of aesthetics; colour, fill and alpha.
 #'
 #' @name aes_colour_fill_alpha
-#' @aliases colour color fill alpha
+#' @aliases colour color fill
 #' @examples
 #' \donttest{
 #'
@@ -20,14 +20,14 @@
 #' c + geom_bar(fill = "white", colour = "red")
 #'
 #' # The aesthetic fill also takes different colouring scales
-#' # setting fill equal to a factor varible uses a discrete colour scale
+#' # setting fill equal to a factor variable uses a discrete colour scale
 #' k <- ggplot(mtcars, aes(factor(cyl), fill = factor(vs)))
 #' k + geom_bar()
 #'
 #' # Fill aesthetic can also be used with a continuous variable
-#' m <- ggplot(movies, aes(x = rating))
-#' m + geom_histogram()
-#' m + geom_histogram(aes(fill = ..count..))
+#' m <- ggplot(faithfuld, aes(waiting, eruptions))
+#' m + geom_raster()
+#' m + geom_raster(aes(fill = density))
 #'
 #' # Some geoms don't use both aesthetics (i.e. geom_point or geom_line)
 #' b <- ggplot(economics, aes(x = date, y = unemploy))
@@ -44,10 +44,6 @@
 #' h + geom_point(alpha = 0.5)
 #' h + geom_point(alpha = 1/10)
 #'
-#' #If a geom uses both fill and colour, alpha will only modify the fill colour
-#' c + geom_bar(fill = "dark grey", colour = "black")
-#' c + geom_bar(fill = "dark grey", colour = "black", alpha = 1/3)
-#'
 #' # Alpha can also be used to add shading
 #' j <- b + geom_line()
 #' j
@@ -55,7 +51,6 @@
 #' j <- j + geom_rect(aes(NULL, NULL, xmin = start, xmax = end, fill = party),
 #' ymin = yrng[1], ymax = yrng[2], data = presidential)
 #' j
-#' library(scales) # to access the alpha function
 #' j + scale_fill_manual(values = alpha(c("blue", "red"), .3))
 #' }
 NULL
diff --git a/R/aes-group-order.r b/R/aes-group-order.r
index 662497c..a97956a 100644
--- a/R/aes-group-order.r
+++ b/R/aes-group-order.r
@@ -1,7 +1,7 @@
-#' Aesthetics: group, order
+#' Aesthetics: group
 #'
 #' @name aes_group_order
-#' @aliases group order
+#' @aliases group
 #'
 #' @examples
 #' \donttest{
@@ -30,13 +30,11 @@
 #' a + geom_bar(aes(fill = factor(vs)))
 #'
 #' # Using linetypes
-#' library(reshape2) # for melt
-#' library(plyr) # for colwise
 #' rescale01 <- function(x) (x - min(x)) / diff(range(x))
 #' ec_scaled <- data.frame(
 #'   date = economics$date,
-#'   colwise(rescale01)(economics[, -(1:2)]))
-#' ecm <- melt(ec_scaled, id = "date")
+#'   plyr::colwise(rescale01)(economics[, -(1:2)]))
+#' ecm <- reshape2::melt(ec_scaled, id.vars = "date")
 #' f <- ggplot(ecm, aes(date, value))
 #' f + geom_line(aes(linetype = variable))
 #'
@@ -51,8 +49,7 @@
 #' # occasions (Occasion).
 #'
 #' # Multiple groups with one aesthetic
-#' library(nlme)
-#' h <- ggplot(Oxboys, aes(age, height))
+#' h <- ggplot(nlme::Oxboys, aes(age, height))
 #' # A single line tries to connect all the observations
 #' h + geom_line()
 #' # The group aesthetic maps a different line for each subject
@@ -72,22 +69,12 @@
 #' # groups. This is the strategy used in interaction plots, profile plots, and parallel
 #' # coordinate plots, among others. For example, we draw boxplots of height at
 #' # each measurement occasion
-#' boysbox <- ggplot(Oxboys, aes(Occasion, height))
+#' boysbox <- ggplot(nlme::Oxboys, aes(Occasion, height))
 #' boysbox + geom_boxplot()
 #' # There is no need to specify the group aesthetic here; the default grouping
 #' # works because occasion is a discrete variable. To overlay individual trajectories
 #' # we again need to override the default grouping for that layer with aes(group = Subject)
 #' boysbox <- boysbox + geom_boxplot()
 #' boysbox + geom_line(aes(group = Subject), colour = "blue")
-#'
-#' # Use the order aesthetic to change stacking order of bar charts
-#' w <- ggplot(diamonds, aes(clarity, fill = cut))
-#' w + geom_bar()
-#' w + geom_bar(aes(order = desc(cut)))
-#'
-#' # Can also be used to change plot order of scatter plots
-#' d <- ggplot(diamonds, aes(carat, price, colour = cut))
-#' d + geom_point()
-#' d + geom_point(aes(order = sample(seq_along(carat))))
 #' }
 NULL
diff --git a/R/aes-linetype-size-shape.r b/R/aes-linetype-size-shape.r
index e9c6a29..41ea078 100644
--- a/R/aes-linetype-size-shape.r
+++ b/R/aes-linetype-size-shape.r
@@ -8,30 +8,24 @@
 #' @examples
 #'
 #' # Line types should be specified with either an integer, a name, or with a string of
-#' # an even number (up to eight) of hexidecimal digits which give the lengths in
+#' # an even number (up to eight) of hexadecimal digits which give the lengths in
 #' # consecutive positions in the string.
 #' # 0 = blank, 1 = solid, 2 = dashed, 3 = dotted, 4 = dotdash, 5 = longdash, 6 = twodash
 #'
 #' # Data
 #' df <- data.frame(x = 1:10 , y = 1:10)
-#' f <- ggplot(df, aes(x = x, y = y))
+#' f <- ggplot(df, aes(x, y))
 #' f + geom_line(linetype = 2)
 #' f + geom_line(linetype = "dotdash")
-#
+#'
 #' # An example with hex strings, the string "33" specifies three units on followed
 #' # by three off and "3313" specifies three units on followed by three off followed
 #' # by one on and finally three off.
 #' f + geom_line(linetype = "3313")
 #'
 #' # Mapping line type from a variable
-#' library(plyr)
-#' library(reshape2)
-#' rescale01 <- function(x) (x - min(x)) / diff(range(x))
-#' ec_scaled <- data.frame(
-#'   date = economics$date,
-#'   colwise(rescale01)(economics[, -(1:2)]))
-#' ecm <- melt(ec_scaled, id = "date")
-#' qplot(date, value, data = ecm, geom = "line", linetype = variable)
+#' ggplot(economics_long, aes(date, value01)) +
+#'   geom_line(aes(linetype = variable))
 #'
 #' # Size examples
 #' # Should be specified with a numerical value (in millimetres),
@@ -39,7 +33,8 @@
 #' p <- ggplot(mtcars, aes(wt, mpg))
 #' p + geom_point(size = 4)
 #' p + geom_point(aes(size = qsec))
-#' p + geom_point(size = 2.5) + geom_hline(yintercept = 25, size = 3.5)
+#' p + geom_point(size = 2.5) +
+#'   geom_hline(yintercept = 25, size = 3.5)
 #'
 #' # Shape examples
 #' # Shape takes four types of values: an integer in [0, 25],
@@ -57,8 +52,9 @@
 #'
 #' # A look at all 25 symbols
 #' df2 <- data.frame(x = 1:5 , y = 1:25, z = 1:25)
-#' s <- ggplot(df2, aes(x = x, y = y))
-#' s + geom_point(aes(shape = z), size = 4) + scale_shape_identity()
+#' s <- ggplot(df2, aes(x, y))
+#' s + geom_point(aes(shape = z), size = 4) +
+#'   scale_shape_identity()
 #' # While all symbols have a foreground colour, symbols 19-25 also take a
 #' # background colour (fill)
 #' s + geom_point(aes(shape = z), size = 4, colour = "Red") +
diff --git a/R/aes-position.r b/R/aes-position.r
index 22e4965..2feeb3a 100644
--- a/R/aes-position.r
+++ b/R/aes-position.r
@@ -16,21 +16,12 @@
 #' ymax = fit + se.fit, colour = cut))
 #' se + geom_pointrange()
 #'
-#' # Boxplot with precomputed statistics
-#' # generate sample data
-#' library(plyr)
-#' abc <- adply(matrix(rnorm(100), ncol = 5), 2, quantile, c(0, .25, .5, .75, 1))
-#' b <- ggplot(abc, aes(x = X1, ymin = "0%", lower = "25%",
-#'   middle = "50%", upper = "75%", ymax = "100%"))
-#' b + geom_boxplot(stat = "identity")
-#'
 #' # Using annotate
 #' p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
 #' p + annotate("rect", xmin = 2, xmax = 3.5, ymin = 2, ymax = 25,
 #'   fill = "dark grey", alpha = .5)
 #'
 #' # Geom_segment examples
-#' library(grid)
 #' p + geom_segment(aes(x = 2, y = 15, xend = 2, yend = 25),
 #'   arrow = arrow(length = unit(0.5, "cm")))
 #' p + geom_segment(aes(x = 2, y = 15, xend = 3, yend = 15),
@@ -43,6 +34,6 @@
 #' counts$x <- as.numeric(as.character(counts$x))
 #' with(counts, plot(x, Freq, type = "h", lwd = 10))
 #'
-#' qplot(x, Freq, data = counts, geom = "segment", yend = 0, xend = x,
-#'   size = I(10))
+#' ggplot(counts, aes(x, Freq)) +
+#'   geom_segment(aes(yend = 0, xend = x), size = 10)
 NULL
diff --git a/R/aes.r b/R/aes.r
index c89339e..fe72c2c 100644
--- a/R/aes.r
+++ b/R/aes.r
@@ -1,11 +1,11 @@
-# all_aes <- function(y) c(names(y$default_aes()), y$required_aes)
-# geom_aes <- unlist(lapply(Geom$find_all(), all_aes))
-# stat_aes <- unlist(lapply(Stat$find_all(), all_aes))
-# all <- sort(unique(c(names(.base_to_ggplot), geom_aes, stat_aes)))
-# dput(all)
-
-.all_aesthetics <- c("adj", "alpha", "angle", "bg", "cex", "col", "color", "colour", "fg", "fill", "group", "hjust", "label", "linetype", "lower", "lty", "lwd", "max", "middle", "min", "order", "pch", "radius", "sample", "shape", "size", "srt", "upper", "vjust", "weight", "width", "x", "xend", "xmax", "xmin", "xintercept", "y", "yend", "ymax", "ymin", "yintercept", "z")
+#' @include utilities.r
+NULL
 
+.all_aesthetics <- c("adj", "alpha", "angle", "bg", "cex", "col", "color",
+  "colour", "fg", "fill", "group", "hjust", "label", "linetype", "lower",
+  "lty", "lwd", "max", "middle", "min", "pch", "radius", "sample", "shape",
+  "size", "srt", "upper", "vjust", "weight", "width", "x", "xend", "xmax",
+  "xmin", "xintercept", "y", "yend", "ymax", "ymin", "yintercept", "z")
 
 .base_to_ggplot <- c(
   "col"   = "colour",
@@ -22,15 +22,19 @@
   "max"   = "ymax"
 )
 
-#' Generate aesthetic mappings that describe how variables in the data are
-#' mapped to visual properties (aesthetics) of geoms.
+#' Define aesthetic mappings.
 #'
-#' \code{aes} creates a list of unevaluated expressions.  This function also
-#' performs partial name matching, converts color to colour, and old style R
-#' names to ggplot names (eg. pch to shape, cex to size)
+#' Generate aesthetic mappings that describe how variables in the data are
+#' mapped to visual properties (aesthetics) of geoms. This function also
+#' standardise aesthetic names by performs partial name matching, converting
+#' color to colour, and old style R names to ggplot names (eg. pch to shape,
+#' cex to size)
 #'
-#' @param x,y,... List of name value pairs giving aesthetics to map.
-#' @family aesthetic generators
+#' @param x,y,... List of name value pairs giving aesthetics to map to
+#'   variables. The names for x and y aesthetics can be omitted (because
+#'   they are so common); all other aesthetics must be named.
+#' @seealso See \code{\link{aes_q}}/\code{\link{aes_string}} for standard
+#'   evaluation versions of \code{aes}.
 #' @seealso See
 #'    \code{\link{aes_colour_fill_alpha}}, \code{\link{aes_group_order}},
 #'    \code{\link{aes_linetype_size_shape}} and \code{\link{aes_position}}
@@ -38,15 +42,37 @@
 #' @export
 #' @examples
 #' aes(x = mpg, y = wt)
+#' aes(mpg, wt)
+#'
+#' # You can also map aesthetics to functions of variables
 #' aes(x = mpg ^ 2, y = wt / cyl)
+#'
+#' # Aesthetic names are automatically standardised
+#' aes(col = x)
+#' aes(fg = x)
+#' aes(color = x)
+#' aes(colour = x)
+#'
+#' # aes is almost always used with ggplot() or a layer
+#' ggplot(mpg, aes(displ, hwy)) + geom_point()
+#' ggplot(mpg) + geom_point(aes(displ, hwy))
+#'
+#' # Aesthetics supplied to ggplot() are used as defaults for every layer
+#' # you can override them, or supply different aesthetics for each layer
 aes <- function(x, y, ...) {
-  aes <- structure(as.list(match.call()[-1]), class="uneval")
+  aes <- structure(as.list(match.call()[-1]), class = "uneval")
   rename_aes(aes)
 }
 #' @export
-print.uneval <- function(x, ...) str(unclass(x))
+print.uneval <- function(x, ...) {
+  values <- vapply(x, deparse2, character(1))
+  bullets <- paste0("* ", format(names(x)), " -> ", values, "\n")
+
+  cat(bullets, sep = "")
+}
+
 #' @export
-str.uneval <- function(object, ...) str(unclass(object), ...)
+str.uneval <- function(object, ...) utils::str(unclass(object), ...)
 #' @export
 "[.uneval" <- function(x, i, ...) structure(unclass(x)[i], class = "uneval")
 
@@ -63,7 +89,7 @@ rename_aes <- function(x) {
   full <- match(names(x), .all_aesthetics)
   names(x)[!is.na(full)] <- .all_aesthetics[full[!is.na(full)]]
 
-  rename(x, .base_to_ggplot, warn_missing = FALSE)
+  plyr::rename(x, .base_to_ggplot, warn_missing = FALSE)
 }
 
 # Look up the scale that should be used for a given aesthetic
@@ -79,49 +105,89 @@ is_position_aes <- function(vars) {
   aes_to_scale(vars) %in% c("x", "y")
 }
 
-#' Generate aesthetic mappings from a string/quoted objects
+#' Define aesthetic mappings from strings, or quoted calls and formulas.
 #'
 #' Aesthetic mappings describe how variables in the data are mapped to visual
 #' properties (aesthetics) of geoms. \code{\link{aes}} uses non-standard
-#' evaluation to capture the variable names. These two variants use
-#' regular evaluation, which is easier to use inside functions.
+#' evaluation to capture the variable names. \code{aes_} and \code{aes_string}
+#' require you to explicitly quote the inputs either with \code{""} for
+#' \code{aes_string()}, or with \code{quote} or \code{~} for \code{aes_()}.
+#' (\code{aes_q} is an alias to \code{aeq_})
+#'
+#' It's better to use \code{aes_q()}, because there's no easy way to create the
+#' equivalent to \code{aes(colour = "my colour")} or \code{aes{x = `X$1`}}
+#' with \code{aes_string()}.
 #'
-#' \code{aes_string} and \code{aes_q} are particularly useful when writing
+#' \code{aes_string} and \code{aes_} are particularly useful when writing
 #' functions that create plots because you can use strings or quoted
 #' names/calls to define the aesthetic mappings, rather than having to use
 #' \code{\link{substitute}} to generate a call to \code{aes()}.
 #'
-#' @param x,y,... List of name value pairs
-#' @family aesthetic generators
+#' @param x,y,... List of name value pairs. Elements must be either
+#'   quoted calls, strings, one-sided formulas or constants.
 #' @seealso \code{\link{aes}}
 #' @export
 #' @examples
-#' # Threee ways of generating the same aesthetics
-#' aes(mpg, wt, col = cyl, fill = NULL)
-#' aes_string("mpg", "wt", col = "cyl", fill = NULL)
-#' aes_q(quote(mpg), quote(wt), col = quote(cyl), fill = NULL)
+#' # Three ways of generating the same aesthetics
+#' aes(mpg, wt, col = cyl)
+#' aes_(quote(mpg), quote(wt), col = quote(cyl))
+#' aes_(~mpg, ~wt, col = ~cyl)
+#' aes_string("mpg", "wt", col = "cyl")
 #'
-#' aes(col = cyl, fill = NULL)
-#' aes_string(col = "cyl", fill = NULL)
-#' aes_q(col = quote(cyl), fill = NULL)
-aes_string <- function(x = NULL, y = NULL, ...) {
-  mapping <- c(compact(list(x = x, y = y)), list(...))
-  mapping[vapply(mapping, is.null, logical(1))] <- "NULL"
-
-  parsed <- lapply(mapping, function(x) parse(text = x)[[1]])
-  structure(rename_aes(parsed), class = "uneval")
+#' # You can't easily mimic these calls with aes_string
+#' aes(`$100`, colour = "smooth")
+#' aes_(~ `$100`, colour = "smooth")
+#' # Ok, you can, but it requires a _lot_ of quotes
+#' aes_string("`$100`", colour = '"smooth"')
+#'
+#' # Convert strings to names with as.name
+#' var <- "cyl"
+#' aes(col = x)
+#' aes_(col = as.name(var))
+aes_ <- function(x, y, ...) {
+  mapping <- list(...)
+  if (!missing(x)) mapping["x"] <- list(x)
+  if (!missing(y)) mapping["y"] <- list(y)
+
+  as_call <- function(x) {
+    if (is.formula(x) && length(x) == 2) {
+      x[[2]]
+    } else if (is.call(x) || is.name(x) || is.atomic(x)) {
+      x
+    } else {
+      stop("Aesthetic must be a one-sided formula, call, name, or constant.",
+        call. = FALSE)
+    }
+  }
+  mapping <- lapply(mapping, as_call)
+  structure(rename_aes(mapping), class = "uneval")
 }
 
-#' @rdname aes_string
+#' @rdname aes_
 #' @export
-aes_q <- function(x = NULL, y = NULL, ...) {
-  mapping <- c(compact(list(x = x, y = y)), list(...))
+aes_string <- function(x, y, ...) {
+  mapping <- list(...)
+  if (!missing(x)) mapping["x"] <- list(x)
+  if (!missing(y)) mapping["y"] <- list(y)
+
+  mapping <- lapply(mapping, function(x) {
+    if (is.character(x)) {
+      parse(text = x)[[1]]
+    } else {
+      x
+    }
+  })
   structure(rename_aes(mapping), class = "uneval")
 }
 
+#' @export
+#' @rdname aes_
+aes_q <- aes_
+
 #' Given a character vector, create a set of identity mappings
 #'
 #' @param vars vector of variable names
+#' @keywords internal
 #' @export
 #' @examples
 #' aes_all(names(mtcars))
@@ -131,7 +197,7 @@ aes_all <- function(vars) {
   vars <- rename_aes(vars)
 
   structure(
-    lapply(vars, function(x) parse(text=x)[[1]]),
+    lapply(vars, as.name),
     class = "uneval"
   )
 }
@@ -140,20 +206,11 @@ aes_all <- function(vars) {
 #'
 #' @param data data.frame or names of variables
 #' @param ... aesthetics that need to be explicitly mapped.
+#' @keywords internal
 #' @export
-#' @examples
-#' df <- data.frame(x = 1, y = 1, colour = 1, label = 1, pch = 1)
-#' aes_auto(df)
-#' aes_auto(names(df))
-#'
-#' df <- data.frame(xp = 1, y = 1, colour = 1, txt = 1, foo = 1)
-#' aes_auto(df, x = xp, label = txt)
-#' aes_auto(names(df), x = xp, label = txt)
-#'
-#' df <- data.frame(foo = 1:3)
-#' aes_auto(df, x = xp, y = yp)
-#' aes_auto(df)
 aes_auto <- function(data = NULL, ...) {
+  warning("aes_auto() is deprecated", call. = FALSE)
+
   # detect names of data
   if (is.null(data)) {
     stop("aes_auto requires data.frame or names of data.frame.")
@@ -166,7 +223,7 @@ aes_auto <- function(data = NULL, ...) {
   # automatically detected aes
   vars <- intersect(.all_aesthetics, vars)
   names(vars) <- vars
-  aes <- lapply(vars, function(x) parse(text=x)[[1]])
+  aes <- lapply(vars, function(x) parse(text = x)[[1]])
 
   # explicitly defined aes
   if (length(match.call()) > 2) {
@@ -176,28 +233,3 @@ aes_auto <- function(data = NULL, ...) {
 
   structure(rename_aes(aes), class = "uneval")
 }
-
-# Aesthetic defaults
-# Convenience method for setting aesthetic defaults
-#
-# @param data values from aesthetic mappings
-# @param y. defaults
-# @param params. user specified values
-# @value a data.frame, with all factors converted to character strings
-aesdefaults <- function(data, y., params.) {
-  updated <- modifyList(y., params. %||% list())
-
-  cols <- tryapply(defaults(data, updated), function(x) eval(x, data, globalenv()))
-
-  # Need to be careful here because stat_boxplot uses a list-column to store
-  # a vector of outliers
-  cols <- Filter(function(x) is.atomic(x) || is.list(x), cols)
-  list_vars <- sapply(cols, is.list)
-  cols[list_vars] <- lapply(cols[list_vars], I)
-
-  df <- data.frame(cols, stringsAsFactors = FALSE)
-
-  factors <- sapply(df, is.factor)
-  df[factors] <- lapply(df[factors], as.character)
-  df
-}
diff --git a/R/annotation-custom.r b/R/annotation-custom.r
index 27c74f8..1659b26 100644
--- a/R/annotation-custom.r
+++ b/R/annotation-custom.r
@@ -3,8 +3,8 @@ NULL
 
 #' Annotation: Custom grob.
 #'
-#' This is a special geom intended for use as static annnotations
-#' that are the same in every panel. These anotations will not
+#' This is a special geom intended for use as static annotations
+#' that are the same in every panel. These annotations will not
 #' affect scales (i.e. the x and y axes will not grow to cover the range
 #' of the grob, and the grob will not be modified by any ggplot settings or mappings).
 #'
@@ -22,7 +22,10 @@ NULL
 #' Inf values can be used to fill the full plot panel (see examples).
 #' @examples
 #' # Dummy plot
-#' base <- qplot(1:10, 1:10, geom = "blank") + theme_bw()
+#' df <- data.frame(x = 1:10, y = 1:10)
+#' base <- ggplot(df, aes(x, y)) +
+#'   geom_blank() +
+#'   theme_bw()
 #' # Adding a table
 #' \dontrun{
 #'  if (require(gridExtra)) {
@@ -34,27 +37,47 @@ NULL
 #' }
 #' }
 #' # Inset plot
-#' g <- ggplotGrob(qplot(1, 1) +
+#' df2 <- data.frame(x = 1 , y = 1)
+#' g <- ggplotGrob(ggplot(df2, aes(x, y)) +
+#'   geom_point() +
 #'   theme(plot.background = element_rect(colour = "black")))
 #' base +
 #'   annotation_custom(grob = g, xmin = 1, xmax = 10, ymin = 8, ymax = 10)
-annotation_custom <- function (grob, xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf) {
-  GeomCustomAnn$new(geom_params = list(grob = grob, xmin = xmin,
-    xmax = xmax, ymin = ymin, ymax = ymax), stat = "identity",
-    position = "identity", data = NULL, inherit.aes = TRUE)
+annotation_custom <- function(grob, xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf) {
+  layer(
+    data = NULL,
+    stat = StatIdentity,
+    position = PositionIdentity,
+    geom = GeomCustomAnn,
+    inherit.aes = TRUE,
+    params = list(
+      grob = grob,
+      xmin = xmin,
+      xmax = xmax,
+      ymin = ymin,
+      ymax = ymax
+    )
+  )
 }
 
-GeomCustomAnn <- proto(Geom, {
-  objname <- "custom_ann"
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomCustomAnn <- ggproto("GeomCustomAnn", Geom,
+  extra_params = "",
+  handle_na = function(data, params) {
+    data
+  },
 
-  draw_groups <- function(., data, scales, coordinates, grob, xmin, xmax,
-                          ymin, ymax, ...) {
-    if (!inherits(coordinates, "cartesian")) {
+  draw_panel = function(data, panel_scales, coord, grob, xmin, xmax,
+                        ymin, ymax) {
+    if (!inherits(coord, "CoordCartesian")) {
       stop("annotation_custom only works with Cartesian coordinates",
         call. = FALSE)
     }
     corners <- data.frame(x = c(xmin, xmax), y = c(ymin, ymax))
-    data <- coord_transform(coordinates, corners, scales)
+    data <- coord$transform(corners, panel_scales)
 
     x_rng <- range(data$x, na.rm = TRUE)
     y_rng <- range(data$y, na.rm = TRUE)
@@ -62,9 +85,16 @@ GeomCustomAnn <- proto(Geom, {
     vp <- viewport(x = mean(x_rng), y = mean(y_rng),
                    width = diff(x_rng), height = diff(y_rng),
                    just = c("center","center"))
-    editGrob(grob, vp = vp)
-  }
+    editGrob(grob, vp = vp, name = paste(grob$name, annotation_id()))
+  },
 
-  default_aes <- function(.)
-    aes(xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf)
+  default_aes = aes_(xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf)
+)
+
+annotation_id <- local({
+  i <- 1
+  function() {
+    i <<- i + 1
+    i
+  }
 })
diff --git a/R/annotation-logticks.r b/R/annotation-logticks.r
index 19fe419..56d909a 100644
--- a/R/annotation-logticks.r
+++ b/R/annotation-logticks.r
@@ -7,11 +7,12 @@
 #' @param sides a string that controls which sides of the plot the log ticks appear on.
 #'   It can be set to a string containing any of \code{"trbl"}, for top, right,
 #'   bottom, and left.
-#' @param short a \code{unit} object specifying the length of the short tick marks
-#' @param mid a \code{unit} object specifying the length of the middle tick marks.
-#'   In base 10, these are the "5" ticks.
-#' @param long a \code{unit} object specifying the length of the long tick marks.
-#'   In base 10, these are the "1" (or "10") ticks.
+#' @param short a \code{\link[grid]{unit}} object specifying the length of the
+#'   short tick marks
+#' @param mid a \code{\link[grid]{unit}} object specifying the length of the
+#'   middle tick marks. In base 10, these are the "5" ticks.
+#' @param long a \code{\link[grid]{unit}} object specifying the length of the
+#'   long tick marks. In base 10, these are the "1" (or "10") ticks.
 #' @param scaled is the data already log-scaled? This should be \code{TRUE}
 #'   (default) when the data is already transformed with \code{log10()} or when
 #'   using \code{scale_y_log10}. It should be \code{FALSE} when using
@@ -30,14 +31,17 @@
 #'
 #' @examples
 #' # Make a log-log plot (without log ticks)
-#' library(MASS)
-#' library(scales)
-#' a <- ggplot(Animals, aes(x = body, y = brain)) + geom_point() +
-#'      scale_x_log10(breaks = trans_breaks("log10", function(x) 10^x),
-#'                    labels = trans_format("log10", math_format(10^.x))) +
-#'      scale_y_log10(breaks = trans_breaks("log10", function(x) 10^x),
-#'                    labels = trans_format("log10", math_format(10^.x))) +
-#'      theme_bw()
+#' a <- ggplot(msleep, aes(bodywt, brainwt)) +
+#'  geom_point(na.rm = TRUE) +
+#'  scale_x_log10(
+#'    breaks = scales::trans_breaks("log10", function(x) 10^x),
+#'    labels = scales::trans_format("log10", scales::math_format(10^.x))
+#'  ) +
+#'  scale_y_log10(
+#'    breaks = scales::trans_breaks("log10", function(x) 10^x),
+#'    labels = scales::trans_format("log10", scales::math_format(10^.x))
+#'  ) +
+#'  theme_bw()
 #'
 #' a + annotation_logticks()                # Default: log ticks on bottom and left
 #' a + annotation_logticks(sides = "lr")    # Log ticks for y, on left and right
@@ -46,62 +50,74 @@
 #' # Hide the minor grid lines because they don't align with the ticks
 #' a + annotation_logticks(sides = "trbl") + theme(panel.grid.minor = element_blank())
 #'
-#'
 #' # Another way to get the same results as 'a' above: log-transform the data before
-#   plotting it. Also hide the minor grid lines.
-#' b <- ggplot(Animals, aes(x = log10(body), y = log10(brain))) + geom_point() +
-#'      scale_x_continuous(name = "body", labels = math_format(10^.x)) +
-#'      scale_y_continuous(name = "brain", labels = math_format(10^.x)) +
-#'      theme_bw()+ theme(panel.grid.minor = element_blank())
+#' # plotting it. Also hide the minor grid lines.
+#' b <- ggplot(msleep, aes(log10(bodywt), log10(brainwt))) +
+#'  geom_point(na.rm = TRUE) +
+#'  scale_x_continuous(name = "body", labels = scales::math_format(10^.x)) +
+#'  scale_y_continuous(name = "brain", labels = scales::math_format(10^.x)) +
+#'  theme_bw() + theme(panel.grid.minor = element_blank())
 #'
 #' b + annotation_logticks()
 #'
-#'
-#' # This shows log(x) on the axes
-#' d <- ggplot(Animals, aes(x = log10(body), y = log10(brain))) + geom_point() +
-#'      theme_bw()
-#'
-#' d + annotation_logticks()
-#'
-#'
 #' # Using a coordinate transform requires scaled = FALSE
-#' t <- ggplot(Animals, aes(x = body, y = brain)) + geom_point() +
-#'      coord_trans(xtrans = "log10", ytrans = "log10") + theme_bw()
-#'
+#' t <- ggplot(msleep, aes(bodywt, brainwt)) +
+#'   geom_point() +
+#'   coord_trans(x = "log10", y = "log10") +
+#'   theme_bw()
 #' t + annotation_logticks(scaled = FALSE)
 #'
-#'
 #' # Change the length of the ticks
-#' library(grid)
-#' a + annotation_logticks(short = unit(.5,"mm"), mid = unit(3,"mm"), long = unit(4,"mm"))
-#'
-annotation_logticks <- function (base = 10, sides = "bl", scaled = TRUE,
+#' a + annotation_logticks(
+#'   short = unit(.5,"mm"),
+#'   mid = unit(3,"mm"),
+#'   long = unit(4,"mm")
+#' )
+annotation_logticks <- function(base = 10, sides = "bl", scaled = TRUE,
       short = unit(0.1, "cm"), mid = unit(0.2, "cm"), long = unit(0.3, "cm"),
-      colour = "black", size = 0.5, linetype = 1, alpha = 1, color = NULL, ...) {
-
+      colour = "black", size = 0.5, linetype = 1, alpha = 1, color = NULL, ...)
+{
   if (!is.null(color))
     colour <- color
 
   layer(
-    geom = "logticks",
-    geom_params = list(base = base, sides = sides, raw = raw, scaled = scaled,
-      short = short, mid = mid, long = long, colour = colour,
-      size = size, linetype = linetype, alpha = alpha, ...),
-    stat = "identity",
     data = data.frame(x = NA),
     mapping = NULL,
+    stat = StatIdentity,
+    geom = GeomLogticks,
+    position = PositionIdentity,
+    show.legend = FALSE,
     inherit.aes = FALSE,
-    show_guide = FALSE
+    params = list(
+      base = base,
+      sides = sides,
+      scaled = scaled,
+      short = short,
+      mid = mid,
+      long = long,
+      colour = colour,
+      size = size,
+      linetype = linetype,
+      alpha = alpha,
+      ...
+    )
   )
 }
 
-GeomLogticks <- proto(Geom, {
-  objname <- "logticks"
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomLogticks <- ggproto("GeomLogticks", Geom,
+  extra_params = "",
+  handle_na = function(data, params) {
+    data
+  },
 
-  draw_groups <- function(., data, scales, coordinates, base = 10, sides = "bl",
+  draw_panel = function(data, panel_scales, coord, base = 10, sides = "bl",
     scaled = TRUE, short = unit(0.1, "cm"), mid = unit(0.2, "cm"),
-    long = unit(0.3, "cm"), ...) {
-
+    long = unit(0.3, "cm"))
+  {
     ticks <- list()
 
     # Convert these units to numbers so that they can be put in data frames
@@ -113,25 +129,31 @@ GeomLogticks <- proto(Geom, {
     if (grepl("[b|t]", sides)) {
 
       # Get positions of x tick marks
-      xticks <- calc_logticks(base = base,
-                  minpow = floor(scales$x.range[1]), maxpow = ceiling(scales$x.range[2]),
-                  start = 0, shortend = short, midend = mid, longend = long)
+      xticks <- calc_logticks(
+        base = base,
+        minpow = floor(panel_scales$x.range[1]),
+        maxpow = ceiling(panel_scales$x.range[2]),
+        start = 0,
+        shortend = short,
+        midend = mid,
+        longend = long
+      )
 
       if (scaled)
         xticks$value <- log(xticks$value, base)
 
-      names(xticks)[names(xticks)=="value"] <- "x"           # Rename to 'x' for coord_transform
-      xticks <- coord_transform(coordinates, xticks, scales)
+      names(xticks)[names(xticks) == "value"] <- "x"   # Rename to 'x' for coordinates$transform
+      xticks <- coord$transform(xticks, panel_scales)
 
       # Make the grobs
-      if(grepl("b", sides)) {
+      if (grepl("b", sides)) {
         ticks$x_b <- with(data, segmentsGrob(
           x0 = unit(xticks$x, "native"), x1 = unit(xticks$x, "native"),
           y0 = unit(xticks$start, "cm"), y1 = unit(xticks$end, "cm"),
           gp = gpar(col = alpha(colour, alpha), lty = linetype, lwd = size * .pt)
         ))
       }
-      if(grepl("t", sides)) {
+      if (grepl("t", sides)) {
         ticks$x_t <- with(data, segmentsGrob(
           x0 = unit(xticks$x, "native"), x1 = unit(xticks$x, "native"),
           y0 = unit(1, "npc") - unit(xticks$start, "cm"), y1 = unit(1, "npc") - unit(xticks$end, "cm"),
@@ -142,25 +164,31 @@ GeomLogticks <- proto(Geom, {
 
 
     if (grepl("[l|r]", sides)) {
-      yticks <- calc_logticks(base = base,
-                  minpow = floor(scales$y.range[1]), maxpow = ceiling(scales$y.range[2]),
-                  start = 0, shortend = short, midend = mid, longend = long)
+      yticks <- calc_logticks(
+        base = base,
+        minpow = floor(panel_scales$y.range[1]),
+        maxpow = ceiling(panel_scales$y.range[2]),
+        start = 0,
+        shortend = short,
+        midend = mid,
+        longend = long
+      )
 
       if (scaled)
         yticks$value <- log(yticks$value, base)
 
-      names(yticks)[names(yticks)=="value"] <- "y"           # Rename to 'y' for coord_transform
-      yticks <- coord_transform(coordinates, yticks, scales)
+      names(yticks)[names(yticks) == "value"] <- "y"   # Rename to 'y' for coordinates$transform
+      yticks <- coord$transform(yticks, panel_scales)
 
       # Make the grobs
-      if(grepl("l", sides)) {
+      if (grepl("l", sides)) {
         ticks$y_l <- with(data, segmentsGrob(
           y0 = unit(yticks$y, "native"), y1 = unit(yticks$y, "native"),
           x0 = unit(yticks$start, "cm"), x1 = unit(yticks$end, "cm"),
           gp = gpar(col = alpha(colour, alpha), lty = linetype, lwd = size * .pt)
         ))
       }
-      if(grepl("r", sides)) {
+      if (grepl("r", sides)) {
         ticks$y_r <- with(data, segmentsGrob(
           y0 = unit(yticks$y, "native"), y1 = unit(yticks$y, "native"),
           x0 = unit(1, "npc") - unit(yticks$start, "cm"), x1 = unit(1, "npc") - unit(yticks$end, "cm"),
@@ -170,11 +198,10 @@ GeomLogticks <- proto(Geom, {
     }
 
     gTree(children = do.call("gList", ticks))
-  }
+  },
 
-  default_stat <- function(.) StatIdentity
-  default_aes <- function(.) aes(colour = "black", size = 0.5, linetype = 1, alpha = 1)
-})
+  default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = 1)
+)
 
 
 # Calculate the position of log tick marks
@@ -189,13 +216,13 @@ calc_logticks <- function(base = 10, ticks_per_base = base - 1,
   reps <- maxpow - minpow
 
   # For base 10: 1, 2, 3, ..., 7, 8, 9, 1, 2, ...
-  ticknums  <- rep(seq(1, base-1, length.out = ticks_per_base), reps)
+  ticknums  <- rep(seq(1, base - 1, length.out = ticks_per_base), reps)
 
   # For base 10: 1, 1, 1, ..., 1, 1, 1, 2, 2, ... (for example)
-  powers <- rep(seq(minpow, maxpow-1), each = ticks_per_base)
+  powers <- rep(seq(minpow, maxpow - 1), each = ticks_per_base)
 
-  ticks  <- ticknums * base^powers
-  ticks  <- c(ticks, base^maxpow)  # Add the last tick mark
+  ticks  <- ticknums * base ^ powers
+  ticks  <- c(ticks, base ^ maxpow)  # Add the last tick mark
 
   # Set all of the ticks short
   tickend <- rep(shortend, length(ticks))
diff --git a/R/annotation-map.r b/R/annotation-map.r
index 4d327dd..c7476a0 100644
--- a/R/annotation-map.r
+++ b/R/annotation-map.r
@@ -8,7 +8,7 @@ NULL
 #' @param ... other arguments used to modify aesthetics
 #' @export
 #' @examples
-#' library(maps)
+#' if (require("maps")) {
 #' usamap <- map_data("state")
 #'
 #' seal.sub <- subset(seals, long > -130 & lat < 45 & lat > 40)
@@ -24,8 +24,8 @@ NULL
 #'   annotation_map(usamap, fill = "NA", colour = "grey50") +
 #'   geom_segment(aes(xend = long + delta_long, yend = lat + delta_lat)) +
 #'   facet_grid(latr ~ longr, scales = "free", space = "free")
+#' }
 annotation_map <- function(map, ...) {
-
   # Get map input into correct form
   stopifnot(is.data.frame(map))
   if (!is.null(map$lat)) map$y <- map$lat
@@ -33,17 +33,30 @@ annotation_map <- function(map, ...) {
   if (!is.null(map$region)) map$id <- map$region
   stopifnot(all(c("x", "y", "id") %in% names(map)))
 
-  GeomAnnotationMap$new(geom_params = list(map = map, ...), data =
-    NULL, inherit.aes = FALSE)
+  layer(
+    data = NULL,
+    stat = StatIdentity,
+    geom = GeomAnnotationMap,
+    position = PositionIdentity,
+    inherit.aes = FALSE,
+    params = list(map = map, ...)
+  )
 }
 
-GeomAnnotationMap <- proto(GeomMap, {
-  objname <- "map"
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomAnnotationMap <- ggproto("GeomAnnotationMap", GeomMap,
+  extra_params = "",
+  handle_na = function(data, params) {
+    data
+  },
 
-  draw_groups <- function(., data, scales, coordinates, map, ...) {
+  draw_panel = function(data, panel_scales, coord, map) {
     # Munch, then set up id variable for polygonGrob -
     # must be sequential integers
-    coords <- coord_munch(coordinates, map, scales)
+    coords <- coord_munch(coord, map, panel_scales)
     coords$group <- coords$group %||% coords$id
     grob_id <- match(coords$group, unique(coords$group))
 
@@ -51,9 +64,9 @@ GeomAnnotationMap <- proto(GeomMap, {
       id = grob_id,
       gp = gpar(
         col = data$colour, fill = alpha(data$fill, data$alpha),
-        lwd = data$size * .pt))
-  }
-
-  required_aes <- c()
+        lwd = data$size * .pt)
+      )
+  },
 
-})
+  required_aes = c()
+)
diff --git a/R/annotation-raster.r b/R/annotation-raster.r
index 7525c69..45b49cb 100644
--- a/R/annotation-raster.r
+++ b/R/annotation-raster.r
@@ -21,43 +21,64 @@ NULL
 #' @export
 #' @examples
 #' # Generate data
-#' rainbow <- matrix(hcl(seq(0, 360, length = 50 * 50), 80, 70), nrow = 50)
-#' qplot(mpg, wt, data = mtcars) +
+#' rainbow <- matrix(hcl(seq(0, 360, length.out = 50 * 50), 80, 70), nrow = 50)
+#' ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point() +
 #'   annotation_raster(rainbow, 15, 20, 3, 4)
 #' # To fill up whole plot
-#' qplot(mpg, wt, data = mtcars) +
+#' ggplot(mtcars, aes(mpg, wt)) +
 #'   annotation_raster(rainbow, -Inf, Inf, -Inf, Inf) +
 #'   geom_point()
 #'
-#' rainbow2 <- matrix(hcl(seq(0, 360, length = 10), 80, 70), nrow = 1)
-#' qplot(mpg, wt, data = mtcars) +
+#' rainbow2 <- matrix(hcl(seq(0, 360, length.out = 10), 80, 70), nrow = 1)
+#' ggplot(mtcars, aes(mpg, wt)) +
 #'   annotation_raster(rainbow2, -Inf, Inf, -Inf, Inf) +
 #'   geom_point()
-#' rainbow2 <- matrix(hcl(seq(0, 360, length = 10), 80, 70), nrow = 1)
-#' qplot(mpg, wt, data = mtcars) +
+#' rainbow2 <- matrix(hcl(seq(0, 360, length.out = 10), 80, 70), nrow = 1)
+#' ggplot(mtcars, aes(mpg, wt)) +
 #'   annotation_raster(rainbow2, -Inf, Inf, -Inf, Inf, interpolate = TRUE) +
 #'   geom_point()
-annotation_raster <- function (raster, xmin, xmax, ymin, ymax, interpolate = FALSE) {
-  raster <- as.raster(raster)
-  GeomRasterAnn$new(geom_params = list(raster = raster, xmin = xmin,
-    xmax = xmax, ymin = ymin, ymax = ymax, interpolate = interpolate),
-    stat = "identity", position = "identity", data = NULL, inherit.aes = TRUE)
+annotation_raster <- function(raster, xmin, xmax, ymin, ymax,
+                              interpolate = FALSE) {
+  raster <- grDevices::as.raster(raster)
+
+  layer(
+    data = NULL,
+    mapping = NULL,
+    stat = StatIdentity,
+    position = PositionIdentity,
+    geom = GeomRasterAnn,
+    inherit.aes = TRUE,
+    params = list(
+      raster = raster,
+      xmin = xmin,
+      xmax = xmax,
+      ymin = ymin,
+      ymax = ymax,
+      interpolate = interpolate
+    )
+  )
+
 }
 
-GeomRasterAnn <- proto(GeomRaster, {
-  objname <- "raster_ann"
-  reparameterise <- function(., df, params) {
-    df
-  }
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomRasterAnn <- ggproto("GeomRasterAnn", Geom,
+  extra_params = "",
+  handle_na = function(data, params) {
+    data
+  },
 
-  draw_groups <- function(., data, scales, coordinates, raster, xmin, xmax,
-    ymin, ymax, interpolate = FALSE, ...) {
-    if (!inherits(coordinates, "cartesian")) {
+  draw_panel = function(data, panel_scales, coord, raster, xmin, xmax,
+                        ymin, ymax, interpolate = FALSE) {
+    if (!inherits(coord, "CoordCartesian")) {
       stop("annotation_raster only works with Cartesian coordinates",
         call. = FALSE)
     }
     corners <- data.frame(x = c(xmin, xmax), y = c(ymin, ymax))
-    data <- coord_transform(coordinates, corners, scales)
+    data <- coord$transform(corners, panel_scales)
 
     x_rng <- range(data$x, na.rm = TRUE)
     y_rng <- range(data$y, na.rm = TRUE)
@@ -66,4 +87,4 @@ GeomRasterAnn <- proto(GeomRaster, {
       diff(x_rng), diff(y_rng), default.units = "native",
       just = c("left","bottom"), interpolate = interpolate)
   }
-})
+)
diff --git a/R/annotation.r b/R/annotation.r
index 6392074..70d3f3f 100644
--- a/R/annotation.r
+++ b/R/annotation.r
@@ -2,7 +2,7 @@
 #'
 #' This function adds geoms to a plot. Unlike typical a geom function,
 #' the properties of the geoms are not mapped from variables of a data frame,
-#' but are instead in as vectors. This is useful for adding small annotations
+#' but are instead passed in as vectors. This is useful for adding small annotations
 #' (such as text labels) or if you have your data in vectors, and for some
 #' reason don't want to put them in a data frame.
 #'
@@ -12,10 +12,11 @@
 #' affect the legend.
 #'
 #' @param geom name of geom to use for annotation
-#' @param x,y,xmin,ymin,xmax,ymax positionining aesthetics - you must
-#'   specify at least one of these.
+#' @param x,y,xmin,ymin,xmax,ymax,xend,yend positioning aesthetics -
+#'   you must specify at least one of these.
 #' @param ... other aesthetics. These are not scaled so you can do (e.g.)
 #'   \code{colour = "red"} to get a red point.
+#' @inheritParams geom_point
 #' @export
 #' @examples
 #' p <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point()
@@ -29,11 +30,13 @@
 #'   colour = "red", size = 1.5)
 #'
 #' p + annotate("text", x = 2:3, y = 20:21, label = c("my label", "label 2"))
-annotate <- function(geom, x = NULL, y = NULL, xmin = NULL, xmax = NULL, ymin = NULL, ymax = NULL, ...) {
+annotate <- function(geom, x = NULL, y = NULL, xmin = NULL, xmax = NULL,
+                     ymin = NULL, ymax = NULL, xend = NULL, yend = NULL, ...,
+                     na.rm = FALSE) {
 
   position <- compact(list(
-    x = x, xmin = xmin, xmax = xmax,
-    y = y, ymin = ymin, ymax = ymax
+    x = x, xmin = xmin, xmax = xmax, xend = xend,
+    y = y, ymin = ymin, ymax = ymax, yend = yend
   ))
   aesthetics <- c(position, list(...))
 
@@ -50,12 +53,16 @@ annotate <- function(geom, x = NULL, y = NULL, xmin = NULL, xmax = NULL, ymin =
   data <- data.frame(position)
   layer(
     geom = geom,
-    geom_params = list(...),
-    stat = "identity",
+    params = list(
+      na.rm = na.rm,
+      ...
+    ),
+    stat = StatIdentity,
+    position = PositionIdentity,
     data = data,
     mapping = aes_all(names(data)),
     inherit.aes = FALSE,
-    show_guide = FALSE
+    show.legend = FALSE
   )
 }
 
diff --git a/R/autoplot.r b/R/autoplot.r
index 86a9da1..0796d4d 100644
--- a/R/autoplot.r
+++ b/R/autoplot.r
@@ -15,7 +15,7 @@ autoplot <- function(object, ...) {
 
 #' @export
 autoplot.default <- function(object, ...) {
-  error.msg <- paste("Objects of type",class(object),"not supported by autoplot.  Please use qplot() or ggplot() instead.\n")
-  stop(error.msg, call.=FALSE)
+  stop("Objects of type ", paste(class(object), collapse = "/"),
+    " not supported by autoplot.", call. = FALSE)
 }
 
diff --git a/R/bench.r b/R/bench.r
index 4096e0e..575d08f 100644
--- a/R/bench.r
+++ b/R/bench.r
@@ -5,8 +5,8 @@
 #' @export
 #' @keywords internal
 #' @examples
-#' benchplot(qplot(mpg, wt, data = mtcars))
-#' benchplot(qplot(mpg, wt, data = mtcars) + facet_grid(.~ cyl))
+#' benchplot(ggplot(mtcars, aes(mpg, wt)) + geom_point())
+#' benchplot(ggplot(mtcars, aes(mpg, wt)) + geom_point() + facet_grid(. ~ cyl))
 benchplot <- function(x) {
 
   construct <- system.time(force(x))
@@ -18,7 +18,7 @@ benchplot <- function(x) {
 
   times <- rbind(construct, build, render, draw)[, 1:3]
 
-  unrowname(data.frame(
+  plyr::unrowname(data.frame(
     step = c("construct", "build", "render", "draw", "TOTAL"),
     rbind(times, colSums(times))))
 }
diff --git a/R/coord-.r b/R/coord-.r
index 872f9cd..ce3ae43 100644
--- a/R/coord-.r
+++ b/R/coord-.r
@@ -1,115 +1,81 @@
-#' New coordinate system.
+#' @section Coordinate systems:
 #'
-#' Internal use only.
+#' All \code{coord_*} functions (like \code{coord_trans}) return a \code{Coord*}
+#' object (like \code{CoordTrans}). The \code{Coord*} object is responsible for
+#' adjusting the position of overlapping geoms.
 #'
-#' @param ... object fields
-#' @keywords internal
-#' @export
-coord <- function(..., subclass = c()) {
-  structure(list(...), class = c(subclass, "coord"))
-}
-
-#' Is this object a coordinate system?
+#' The way that the \code{coord_*} functions work is slightly different from the
+#' \code{geom_*} and \code{stat_*} functions, because a \code{coord_*} function
+#' actually "instantiates" the \code{Coord*} object by creating a descendant,
+#' and returns that.
 #'
-#' @export is.coord
-#' @keywords internal
-is.coord <- function(x) inherits(x, "coord")
-
-distance <- function(., x, y, details) {
-  max_dist <- dist_euclidean(details$x.range, details$y.range)
-  dist_euclidean(x, y) / max_dist
-}
-
-coord_aspect <- function(coord, ranges)
-  UseMethod("coord_aspect")
+#' Each of the \code{Coord*} objects is a \code{\link{ggproto}} object,
+#' descended from the top-level \code{Coord}.  To create a new type of Coord
+#' object, you typically will want to implement one or more of the following:
+#'
+#' \itemize{
+#'   \item \code{aspect}: Returns the desired aspect ratio for the plot.
+#'   \item \code{labels}: Returns a list containing labels for x and y.
+#'   \item \code{render_fg}: Renders foreground elements.
+#'   \item \code{render_bg}: Renders background elements.
+#'   \item \code{render_axis_h}: Renders the horizontal axis.
+#'   \item \code{render_axis_v}: Renders the vertical axis.
+#'   \item \code{range}: Returns the x and y ranges
+#'   \item \code{train}: Return the trained scale ranges.
+#'   \item \code{transform}: Transforms x and y coordinates.
+#'   \item \code{distance}: Calculates distance.
+#'   \item \code{is_linear}: Returns \code{TRUE} if the coordinate system is
+#'     linear; \code{FALSE} otherwise.
+#' }
+#'
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
 #' @export
-coord_aspect.default <- function(coord, ranges) NULL
+Coord <- ggproto("Coord",
 
-coord_labels <- function(coord, scales) UseMethod("coord_labels")
-#' @export
-coord_labels.default <- function(coord, scales) scales
+  aspect = function(ranges) NULL,
 
-coord_render_fg <- function(coord, scales, theme)
-  UseMethod("coord_render_fg")
-#' @export
-coord_render_fg.default <- function(coord, scales, theme)
-  element_render(theme, "panel.border")
+  labels = function(scale_details) scale_details,
 
-coord_render_bg <- function(coord, scales, theme)
-  UseMethod("coord_render_bg")
-#' @export
-coord_render_bg.default <- function(coord, details, theme) {
-  x.major <- if(length(details$x.major) > 0) unit(details$x.major, "native")
-  x.minor <- if(length(details$x.minor) > 0) unit(details$x.minor, "native")
-  y.major <- if(length(details$y.major) > 0) unit(details$y.major, "native")
-  y.minor <- if(length(details$y.minor) > 0) unit(details$y.minor, "native")
+  render_fg = function(scale_details, theme) element_render(theme, "panel.border"),
 
-  guide_grid(theme, x.minor, x.major, y.minor, y.major)
-}
+  render_bg = function(scale_details, theme) {
+    x.major <- if (length(scale_details$x.major) > 0) unit(scale_details$x.major, "native")
+    x.minor <- if (length(scale_details$x.minor) > 0) unit(scale_details$x.minor, "native")
+    y.major <- if (length(scale_details$y.major) > 0) unit(scale_details$y.major, "native")
+    y.minor <- if (length(scale_details$y.minor) > 0) unit(scale_details$y.minor, "native")
 
-coord_render_axis_h <- function(coord, scales, theme)
-  UseMethod("coord_render_axis_h")
-#' @export
-coord_render_axis_h.default <- function(coord, details, theme) {
-  guide_axis(details$x.major, details$x.labels, "bottom", theme)
-}
+    guide_grid(theme, x.minor, x.major, y.minor, y.major)
+  },
 
-coord_render_axis_v <- function(coord, scales, theme)
-  UseMethod("coord_render_axis_v")
-#' @export
-coord_render_axis_v.default <- function(coord, details, theme) {
-  guide_axis(details$y.major, details$y.labels, "left", theme)
-}
+  render_axis_h = function(scale_details, theme) {
+    guide_axis(scale_details$x.major, scale_details$x.labels, "bottom", theme)
+  },
 
-coord_range <- function(coord, scales)
-  UseMethod("coord_range")
+  render_axis_v = function(scale_details, theme) {
+    guide_axis(scale_details$y.major, scale_details$y.labels, "left", theme)
+  },
 
-#' @export
-coord_range.default <- function(coord, scales) {
-  return(list(x = scales$x.range, y = scales$y.range))
-}
+  range = function(scale_details) {
+    return(list(x = scale_details$x.range, y = scale_details$y.range))
+  },
 
-coord_train <- function(coord, scales)
-  UseMethod("coord_train")
+  train = function(scale_details) NULL,
 
-coord_transform <- function(coord, data, range)
-  UseMethod("coord_transform")
+  transform = function(data, range) NULL,
 
-coord_distance <- function(coord, x, y, details)
-  UseMethod("coord_distance")
+  distance = function(x, y, scale_details) NULL,
 
-is.linear <- function(coord) UseMethod("is.linear")
-#' @export
-is.linear.default <- function(coord) FALSE
+  is_linear = function() FALSE
+)
 
-#' Set the default expand values for the scale, if NA
+#' Is this object a coordinate system?
+#'
+#' @export is.Coord
 #' @keywords internal
-coord_expand_defaults <- function(coord, scale, aesthetic = NULL)
-  UseMethod("coord_expand_defaults")
-
-#' @export
-coord_expand_defaults.default <- function(coord, scale, aesthetic = NULL) {
-  # Expand the same regardless of whether it's x or y
-
-  # @kohske TODO:
-  # Here intentionally verbose. These constants may be held by coord as, say,
-  # coord$default.expand <- list(discrete = ..., continuous = ...)
-  #
-  # @kohske
-  # Now scale itself is not changed.
-  # This function only returns expanded (numeric) limits
-  discrete <- c(0, 0.6)
-  continuous <-  c(0.05, 0)
-  expand_default(scale, discrete, continuous)
-}
+is.Coord <- function(x) inherits(x, "Coord")
 
-# This is a utility function used by coord_expand_defaults, to expand a single scale
-expand_default <- function(scale, discrete = c(0, 0), continuous = c(0, 0)) {
-  # Default expand values for discrete and continuous scales
-  if (is.waive(scale$expand)) {
-    if (inherits(scale, "discrete")) discrete
-    else if (inherits(scale, "continuous")) continuous
-  } else {
-    return(scale$expand)
-  }
+expand_default <- function(scale, discrete = c(0, 0.6), continuous = c(0.05, 0)) {
+  scale$expand %|W|% if (scale$is_discrete()) discrete else continuous
 }
diff --git a/R/coord-cartesian-.r b/R/coord-cartesian-.r
index d195f71..5ae6e49 100644
--- a/R/coord-cartesian-.r
+++ b/R/coord-cartesian-.r
@@ -5,81 +5,99 @@
 #' plot (like you're looking at it with a magnifying glass), and will not
 #' change the underlying data like setting limits on a scale will.
 #'
-#' @param xlim limits for the x axis
-#' @param ylim limits for the y axis
-#' @param wise deprecated in 0.9.1
+#' @param xlim,ylim Limits for the x and y axes.
+#' @param expand If \code{TRUE}, the default, adds a small expansion factor to
+#'   the limits to ensure that data and axes don't overlap. If \code{FALSE},
+#'   limits are taken exactly from the data or \code{xlim}/\code{ylim}.
 #' @export
 #' @examples
 #' # There are two ways of zooming the plot display: with scales or
 #' # with coordinate systems.  They work in two rather different ways.
 #'
-#' (p <- qplot(disp, wt, data=mtcars) + geom_smooth())
+#' p <- ggplot(mtcars, aes(disp, wt)) +
+#'   geom_point() +
+#'   geom_smooth()
+#' p
 #'
-#' # Setting the limits on a scale will throw away all data that's not
-#' # inside these limits.  This is equivalent to plotting a subset of
-#' # the original data
+#' # Setting the limits on a scale converts all values outside the range to NA.
 #' p + scale_x_continuous(limits = c(325, 500))
 #'
-#' # Setting the limits on the coordinate system performs a visual zoom
-#' # the data is unchanged, and we just view a small portion of the original
-#' # plot.  See how the axis labels are the same as the original data, and
-#' # the smooth continue past the points visible on this plot.
+#' # Setting the limits on the coordinate system performs a visual zoom.
+#' # The data is unchanged, and we just view a small portion of the original
+#' # plot. Note how smooth continues past the points visible on this plot.
 #' p + coord_cartesian(xlim = c(325, 500))
 #'
+#' # By default, the same expansion factor is applied as when setting scale
+#' # limits. You can set the limits precisely by setting expand = FALSE
+#' p + coord_cartesian(xlim = c(325, 500), expand = FALSE)
+#'
+#' # Simiarly, we can use expand = FALSE to turn off expansion with the
+#' # default limits
+#' p + coord_cartesian(expand = FALSE)
+#'
 #' # You can see the same thing with this 2d histogram
-#' (d <- ggplot(diamonds, aes(carat, price)) +
-#'   stat_bin2d(bins = 25, colour="grey50"))
+#' d <- ggplot(diamonds, aes(carat, price)) +
+#'   stat_bin2d(bins = 25, colour = "white")
+#' d
 #'
 #' # When zooming the scale, the we get 25 new bins that are the same
 #' # size on the plot, but represent smaller regions of the data space
-#' d + scale_x_continuous(limits = c(0, 2))
+#' d + scale_x_continuous(limits = c(0, 1))
 #'
 #' # When zooming the coordinate system, we see a subset of original 50 bins,
 #' # displayed bigger
-#' d + coord_cartesian(xlim = c(0, 2))
-coord_cartesian <- function(xlim = NULL, ylim = NULL, wise = NULL) {
-  if (!is.null(wise))
-    gg_dep("0.9.0", "wise argument to coord_cartesian is ignored")
-  coord(limits = list(x = xlim, y = ylim), subclass = "cartesian")
+#' d + coord_cartesian(xlim = c(0, 1))
+coord_cartesian <- function(xlim = NULL, ylim = NULL, expand = TRUE) {
+  ggproto(NULL, CoordCartesian,
+    limits = list(x = xlim, y = ylim),
+    expand = expand
+  )
 }
 
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
 #' @export
-is.linear.cartesian <- function(coord) TRUE
+CoordCartesian <- ggproto("CoordCartesian", Coord,
 
-#' @export
-coord_distance.cartesian <- function(coord, x, y, details) {
-  max_dist <- dist_euclidean(details$x.range, details$y.range)
-  dist_euclidean(x, y) / max_dist
-}
+  is_linear = function() TRUE,
 
-#' @export
-coord_transform.cartesian <- function(., data, details) {
-  rescale_x <- function(data) rescale(data, from = details$x.range)
-  rescale_y <- function(data) rescale(data, from = details$y.range)
+  distance = function(x, y, scale_details) {
+    max_dist <- dist_euclidean(scale_details$x.range, scale_details$y.range)
+    dist_euclidean(x, y) / max_dist
+  },
 
-  data <- transform_position(data, rescale_x, rescale_y)
-  transform_position(data, squish_infinite, squish_infinite)
-}
+  transform = function(data, scale_details) {
+    rescale_x <- function(data) rescale(data, from = scale_details$x.range)
+    rescale_y <- function(data) rescale(data, from = scale_details$y.range)
 
-#' @export
-coord_train.cartesian <- function(coord, scales) {
-  c(train_cartesian(scales$x, coord$limits$x, "x"),
-    train_cartesian(scales$y, coord$limits$y, "y"))
-}
+    data <- transform_position(data, rescale_x, rescale_y)
+    transform_position(data, squish_infinite, squish_infinite)
+  },
 
-train_cartesian <- function(scale, limits, name) {
+  train = function(self, scale_details) {
+    train_cartesian <- function(scale_details, limits, name) {
+      if (self$expand) {
+        expand <- expand_default(scale_details)
+      } else {
+        expand <- c(0, 0)
+      }
 
-  # first, calculate the range that is the numerical limits in data space
+      if (is.null(limits)) {
+        range <- scale_details$dimension(expand)
+      } else {
+        range <- range(scale_details$transform(limits))
+        range <- expand_range(range, expand[1], expand[2])
+      }
 
-  # expand defined by scale OR coord
-  if (is.null(limits)) {
-    expand <- coord_expand_defaults(coord, scale)
-    range <- scale_dimension(scale, expand)
-  } else {
-    range <- range(scale_transform(scale, limits))
-  }
+      out <- scale_details$break_info(range)
+      names(out) <- paste(name, names(out), sep = ".")
+      out
+    }
 
-  out <- scale_break_info(scale, range)
-  names(out) <- paste(name, names(out), sep = ".")
-  out
-}
+    c(
+      train_cartesian(scale_details$x, self$limits$x, "x"),
+      train_cartesian(scale_details$y, self$limits$y, "y")
+    )
+  }
+)
diff --git a/R/coord-fixed.r b/R/coord-fixed.r
index 9e4ed8b..98eb933 100644
--- a/R/coord-fixed.r
+++ b/R/coord-fixed.r
@@ -8,29 +8,40 @@
 #' y axis longer than units on the x-axis, and vice versa. This is similar to
 #' \code{\link[MASS]{eqscplot}}, but it works for all types of graphics.
 #'
-#' @aliases coord_fixed coord_equal
-#' @export coord_fixed coord_equal
+#' @export
 #' @inheritParams coord_cartesian
 #' @param ratio aspect ratio, expressed as \code{y / x}
 #' @examples
 #' # ensures that the ranges of axes are equal to the specified ratio by
 #' # adjusting the plot aspect ratio
 #'
-#' qplot(mpg, wt, data = mtcars) + coord_fixed(ratio = 1)
-#' qplot(mpg, wt, data = mtcars) + coord_fixed(ratio = 5)
-#' qplot(mpg, wt, data = mtcars) + coord_fixed(ratio = 1/5)
+#' p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
+#' p + coord_fixed(ratio = 1)
+#' p + coord_fixed(ratio = 5)
+#' p + coord_fixed(ratio = 1/5)
 #'
 #' # Resize the plot to see that the specified aspect ratio is maintained
-coord_fixed <- function(ratio = 1, xlim = NULL, ylim = NULL, wise = NULL) {
-  if (!is.null(wise))
-    gg_dep("0.9.0", "wise argument to coord_cartesian is ignored")
-
-  coord(limits = list(x = xlim, y = ylim), ratio = ratio,
-    subclass = c("fixed", "cartesian"))
+coord_fixed <- function(ratio = 1, xlim = NULL, ylim = NULL, expand = TRUE) {
+  ggproto(NULL, CoordFixed,
+    limits = list(x = xlim, y = ylim),
+    ratio = ratio,
+    expand = expand
+  )
 }
+
+#' @export
+#' @rdname coord_fixed
+#' @usage NULL
 coord_equal <- coord_fixed
 
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
 #' @export
-coord_aspect.fixed <- function(coord, ranges) {
-  diff(ranges$y.range) / diff(ranges$x.range) * coord$ratio
-}
+CoordFixed <- ggproto("CoordFixed", CoordCartesian,
+
+  aspect = function(self, ranges) {
+    diff(ranges$y.range) / diff(ranges$x.range) * self$ratio
+  }
+)
diff --git a/R/coord-flip.r b/R/coord-flip.r
index 1260c6f..b42d64e 100644
--- a/R/coord-flip.r
+++ b/R/coord-flip.r
@@ -5,31 +5,59 @@
 #' statistics which display y conditional on x, to x conditional on y.
 #'
 #' @export
-#' @param ... Other arguments passed onto \code{\link{coord_cartesian}}
+#' @inheritParams coord_cartesian
 #' @examples
-#' \donttest{
 #' # Very useful for creating boxplots, and other interval
 #' # geoms in the horizontal instead of vertical position.
-#' qplot(cut, price, data=diamonds, geom="boxplot")
-#' last_plot() + coord_flip()
 #'
-#' qplot(cut, data=diamonds, geom="bar")
-#' last_plot() + coord_flip()
+#' ggplot(diamonds, aes(cut, price)) +
+#'   geom_boxplot() +
+#'   coord_flip()
 #'
-#' h <- qplot(carat, data=diamonds, geom="histogram")
+#' h <- ggplot(diamonds, aes(carat)) +
+#'   geom_histogram()
 #' h
 #' h + coord_flip()
 #' h + coord_flip() + scale_x_reverse()
 #'
-#' # You can also use it to flip lines and area plots:
-#' qplot(1:5, (1:5)^2, geom="area")
+#' # You can also use it to flip line and area plots:
+#' df <- data.frame(x = 1:5, y = (1:5) ^ 2)
+#' ggplot(df, aes(x, y)) +
+#'   geom_area()
 #' last_plot() + coord_flip()
-#' }
-coord_flip <- function(...) {
-  coord <- coord_cartesian(...)
-  structure(coord, class = c("flip", class(coord)))
+coord_flip <- function(xlim = NULL, ylim = NULL, expand = TRUE) {
+  ggproto(NULL, CoordFlip,
+    limits = list(x = xlim, y = ylim),
+    expand = expand
+  )
 }
 
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+CoordFlip <- ggproto("CoordFlip", CoordCartesian,
+
+  transform = function(data, scale_details) {
+    data <- flip_labels(data)
+    CoordCartesian$transform(data, scale_details)
+  },
+
+  range = function(scale_details) {
+    list(x = scale_details$y.range, y = scale_details$x.range)
+  },
+
+  train = function(self, scale_details) {
+    trained <- ggproto_parent(CoordCartesian, self)$train(scale_details)
+    flip_labels(trained)
+  },
+
+  labels = function(scale_details) {
+    flip_labels(CoordCartesian$labels(scale_details))
+  }
+)
+
+
 flip_labels <- function(x) {
   old_names <- names(x)
 
@@ -40,27 +68,3 @@ flip_labels <- function(x) {
 
   setNames(x, new_names)
 }
-
-#' @export
-is.linear.flip <- function(coord) TRUE
-
-#' @export
-coord_transform.flip <- function(coord, data, details) {
-  data <- flip_labels(data)
-  NextMethod()
-}
-
-#' @export
-coord_range.flip <- function(coord, scales) {
-  return(list(x = scales$y.range, y = scales$x.range))
-}
-
-#' @export
-coord_train.flip <- function(coord, scales) {
-  flip_labels(NextMethod())
-}
-
-#' @export
-coord_labels.flip <- function(coord, scales) {
-  flip_labels(NextMethod())
-}
diff --git a/R/coord-map.r b/R/coord-map.r
index 72e102f..5c1c5ce 100644
--- a/R/coord-map.r
+++ b/R/coord-map.r
@@ -1,11 +1,23 @@
 #' Map projections.
 #'
+#' The representation of a portion of the earth, which is approximately spherical,
+#' onto a flat 2D plane requires a projection. This is what
+#' \code{\link{coord_map}} does. These projections account for the fact that the
+#' actual length (in km) of one degree of longitude varies between the equator
+#' and the pole. Near the equator, the ratio between the lengths of one degree
+#' of latitude and one degree of longitude is approximately 1. Near the pole, it
+#' is tends towards infinity because the length of one degree of longitude tends
+#' towards 0. For regions that span only a few degrees and are not too close to
+#' the poles, setting the aspect ratio of the plot to the appropriate lat/lon
+#' ratio approximates the usual mercator projection. This is what
+#' \code{coord_quickmap} does. With \code{\link{coord_map}} all elements of the
+#' graphic have to be projected which is not the case here. So
+#' \code{\link{coord_quickmap}} has the advantage of being much faster, in
+#' particular for complex plots such as those using with
+#' \code{\link{geom_tile}}, at the expense of correctness in the projection.
 #' This coordinate system provides the full range of map projections available
 #' in the mapproj package.
 #'
-#' This is still experimental, and if you have any advice to offer regarding
-#' a better (or more correct) way to do this, please let me know
-#'
 #' @export
 #' @param projection projection to use, see
 #'    \code{\link[mapproj]{mapproject}} for list
@@ -15,32 +27,36 @@
 #'  \code{c(90, 0, mean(range(x)))}.  This is not optimal for many
 #'  projections, so you will have to supply your own. See
 #'  \code{\link[mapproj]{mapproject}} for more information.
-#' @param xlim manually specific x limits (in degrees of lontitude)
+#' @param xlim manually specific x limits (in degrees of longitude)
 #' @param ylim manually specific y limits (in degrees of latitude)
 #' @export
 #' @examples
 #' if (require("maps")) {
-#' # Create a lat-long dataframe from the maps package
 #' nz <- map_data("nz")
-#' nzmap <- ggplot(nz, aes(x=long, y=lat, group=group)) +
-#'   geom_polygon(fill="white", colour="black")
+#' # Prepare a map of NZ
+#' nzmap <- ggplot(nz, aes(x = long, y = lat, group = group)) +
+#'   geom_polygon(fill = "white", colour = "black")
 #'
-#' # Use cartesian coordinates
+#' # Plot it in cartesian coordinates
 #' nzmap
-#' # With default mercator projection
+#' # With correct mercator projection
 #' nzmap + coord_map()
+#' # With the aspect ratio approximation
+#' nzmap + coord_quickmap()
+#'
 #' # Other projections
 #' nzmap + coord_map("cylindrical")
 #' nzmap + coord_map("azequalarea",orientation=c(-36.92,174.6,0))
 #'
 #' states <- map_data("state")
-#' usamap <- ggplot(states, aes(x=long, y=lat, group=group)) +
-#'   geom_polygon(fill="white", colour="black")
+#' usamap <- ggplot(states, aes(long, lat, group = group)) +
+#'   geom_polygon(fill = "white", colour = "black")
 #'
 #' # Use cartesian coordinates
 #' usamap
 #' # With mercator projection
 #' usamap + coord_map()
+#' usamap + coord_quickmap()
 #' # See ?mapproject for coordinate systems and their parameters
 #' usamap + coord_map("gilbert")
 #' usamap + coord_map("lagrange")
@@ -57,177 +73,177 @@
 #' world <- map_data("world")
 #' worldmap <- ggplot(world, aes(x=long, y=lat, group=group)) +
 #'   geom_path() +
-#'   scale_y_continuous(breaks=(-2:2) * 30) +
-#'   scale_x_continuous(breaks=(-4:4) * 45)
+#'   scale_y_continuous(breaks = (-2:2) * 30) +
+#'   scale_x_continuous(breaks = (-4:4) * 45)
 #'
 #' # Orthographic projection with default orientation (looking down at North pole)
 #' worldmap + coord_map("ortho")
 #' # Looking up up at South Pole
-#' worldmap + coord_map("ortho", orientation=c(-90, 0, 0))
+#' worldmap + coord_map("ortho", orientation = c(-90, 0, 0))
 #' # Centered on New York (currently has issues with closing polygons)
-#' worldmap + coord_map("ortho", orientation=c(41, -74, 0))
+#' worldmap + coord_map("ortho", orientation = c(41, -74, 0))
 #' }
 coord_map <- function(projection="mercator", ..., orientation = NULL, xlim = NULL, ylim = NULL) {
-  try_require("mapproj")
-  coord(
+  ggproto(NULL, CoordMap,
     projection = projection,
     orientation = orientation,
     limits = list(x = xlim, y = ylim),
-    params = list(...),
-    subclass = "map"
+    params = list(...)
   )
 }
 
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
 #' @export
-coord_transform.map <- function(coord, data, details) {
-  trans <- mproject(coord, data$x, data$y, details$orientation)
-  out <- cunion(trans[c("x", "y")], data)
+CoordMap <- ggproto("CoordMap", Coord,
 
-  out$x <- rescale(out$x, 0:1, details$x.proj)
-  out$y <- rescale(out$y, 0:1, details$y.proj)
-  out
-}
-mproject <- function(coord, x, y, orientation) {
-  suppressWarnings(mapproj::mapproject(x, y,
-    projection = coord$projection,
-    parameters  = coord$params,
-    orientation = orientation
-  ))
-}
+  transform = function(self, data, scale_details) {
+    trans <- mproject(self, data$x, data$y, scale_details$orientation)
+    out <- cunion(trans[c("x", "y")], data)
 
-#' @export
-coord_distance.map <- function(coord, x, y, details) {
-  max_dist <- dist_central_angle(details$x.range, details$y.range)
-  dist_central_angle(x, y) / max_dist
-}
+    out$x <- rescale(out$x, 0:1, scale_details$x.proj)
+    out$y <- rescale(out$y, 0:1, scale_details$y.proj)
+    out
+  },
 
-#' @export
-coord_aspect.map <- function(coord, ranges) {
-  diff(ranges$y.proj) / diff(ranges$x.proj)
-}
+  distance = function(x, y, scale_details) {
+    max_dist <- dist_central_angle(scale_details$x.range, scale_details$y.range)
+    dist_central_angle(x, y) / max_dist
+  },
 
-#' @export
-coord_train.map <- function(coord, scales) {
+  aspect = function(ranges) {
+    diff(ranges$y.proj) / diff(ranges$x.proj)
+  },
 
-  # range in scale
-  ranges <- list()
-  for (n in c("x", "y")) {
+  train = function(self, scale_details) {
 
-    scale <- scales[[n]]
-    limits <- coord$limits[[n]]
+    # range in scale
+    ranges <- list()
+    for (n in c("x", "y")) {
 
-    if (is.null(limits)) {
-      expand <- coord_expand_defaults(coord, scale, n)
-      range <- scale_dimension(scale, expand)
-    } else {
-      range <- range(scale_transform(scale, limits))
+      scale <- scale_details[[n]]
+      limits <- self$limits[[n]]
+
+      if (is.null(limits)) {
+        range <- scale$dimension(expand_default(scale))
+      } else {
+        range <- range(scale$transform(limits))
+      }
+      ranges[[n]] <- range
     }
-    ranges[[n]] <- range
-  }
 
-  orientation <- coord$orientation %||% c(90, 0, mean(ranges$x))
+    orientation <- self$orientation %||% c(90, 0, mean(ranges$x))
 
-  # Increase chances of creating valid boundary region
-  grid <- expand.grid(
-    x = seq(ranges$x[1], ranges$x[2], length = 50),
-    y = seq(ranges$y[1], ranges$y[2], length = 50)
-  )
+    # Increase chances of creating valid boundary region
+    grid <- expand.grid(
+      x = seq(ranges$x[1], ranges$x[2], length.out = 50),
+      y = seq(ranges$y[1], ranges$y[2], length.out = 50)
+    )
 
-  ret <- list(x = list(), y = list())
+    ret <- list(x = list(), y = list())
 
-  # range in map
-  proj <- mproject(coord, grid$x, grid$y, orientation)$range
-  ret$x$proj <- proj[1:2]
-  ret$y$proj <- proj[3:4]
+    # range in map
+    proj <- mproject(self, grid$x, grid$y, orientation)$range
+    ret$x$proj <- proj[1:2]
+    ret$y$proj <- proj[3:4]
 
-  for (n in c("x", "y")) {
-    out <- scale_break_info(scales[[n]], ranges[[n]])
-    ret[[n]]$range <- out$range
-    ret[[n]]$major <- out$major_source
-    ret[[n]]$minor <- out$minor_source
-    ret[[n]]$labels <- out$labels
-  }
+    for (n in c("x", "y")) {
+      out <- scale_details[[n]]$break_info(ranges[[n]])
+      ret[[n]]$range <- out$range
+      ret[[n]]$major <- out$major_source
+      ret[[n]]$minor <- out$minor_source
+      ret[[n]]$labels <- out$labels
+    }
 
-  details <- list(
-    orientation = orientation,
-    x.range = ret$x$range, y.range = ret$y$range,
-    x.proj = ret$x$proj, y.proj = ret$y$proj,
-    x.major = ret$x$major, x.minor = ret$x$minor, x.labels = ret$x$labels,
-    y.major = ret$y$major, y.minor = ret$y$minor, y.labels = ret$y$labels
-  )
-  details
-}
+    details <- list(
+      orientation = orientation,
+      x.range = ret$x$range, y.range = ret$y$range,
+      x.proj = ret$x$proj, y.proj = ret$y$proj,
+      x.major = ret$x$major, x.minor = ret$x$minor, x.labels = ret$x$labels,
+      y.major = ret$y$major, y.minor = ret$y$minor, y.labels = ret$y$labels
+    )
+    details
+  },
+
+  render_bg = function(self, scale_details, theme) {
+    xrange <- expand_range(scale_details$x.range, 0.2)
+    yrange <- expand_range(scale_details$y.range, 0.2)
+
+    # Limit ranges so that lines don't wrap around globe
+    xmid <- mean(xrange)
+    ymid <- mean(yrange)
+    xrange[xrange < xmid - 180] <- xmid - 180
+    xrange[xrange > xmid + 180] <- xmid + 180
+    yrange[yrange < ymid - 90] <- ymid - 90
+    yrange[yrange > ymid + 90] <- ymid + 90
+
+    xgrid <- with(scale_details, expand.grid(
+      y = c(seq(yrange[1], yrange[2], length.out = 50), NA),
+      x = x.major
+    ))
+    ygrid <- with(scale_details, expand.grid(
+      x = c(seq(xrange[1], xrange[2], length.out = 50), NA),
+      y = y.major
+    ))
+
+    xlines <- self$transform(xgrid, scale_details)
+    ylines <- self$transform(ygrid, scale_details)
+
+    if (nrow(xlines) > 0) {
+      grob.xlines <- element_render(
+        theme, "panel.grid.major.x",
+        xlines$x, xlines$y, default.units = "native"
+      )
+    } else {
+      grob.xlines <- zeroGrob()
+    }
 
-#' @export
-coord_render_bg.map <- function(coord, details, theme) {
-  xrange <- expand_range(details$x.range, 0.2)
-  yrange <- expand_range(details$y.range, 0.2)
-
-  # Limit ranges so that lines don't wrap around globe
-  xmid <- mean(xrange)
-  ymid <- mean(yrange)
-  xrange[xrange < xmid - 180] <- xmid - 180
-  xrange[xrange > xmid + 180] <- xmid + 180
-  yrange[yrange < ymid - 90] <- ymid - 90
-  yrange[yrange > ymid + 90] <- ymid + 90
-
-  xgrid <- with(details, expand.grid(
-    y = c(seq(yrange[1], yrange[2], len = 50), NA),
-    x = x.major
-  ))
-  ygrid <- with(details, expand.grid(
-    x = c(seq(xrange[1], xrange[2], len = 50), NA),
-    y = y.major
-  ))
+    if (nrow(ylines) > 0) {
+      grob.ylines <- element_render(
+        theme, "panel.grid.major.y",
+        ylines$x, ylines$y, default.units = "native"
+      )
+    } else {
+      grob.ylines <- zeroGrob()
+    }
 
-  xlines <- coord_transform(coord, xgrid, details)
-  ylines <- coord_transform(coord, ygrid, details)
+    ggname("grill", grobTree(
+      element_render(theme, "panel.background"),
+      grob.xlines, grob.ylines
+    ))
+  },
 
-  if (nrow(xlines) > 0) {
-    grob.xlines <- element_render(
-      theme, "panel.grid.major.x",
-      xlines$x, xlines$y, default.units = "native"
-    )
-  } else {
-    grob.xlines <- zeroGrob()
-  }
+  render_axis_h = function(self, scale_details, theme) {
+    if (is.null(scale_details$x.major)) return(zeroGrob())
 
-  if (nrow(ylines) > 0) {
-    grob.ylines <- element_render(
-      theme, "panel.grid.major.y",
-      ylines$x, ylines$y, default.units = "native"
-    )
-  } else {
-    grob.ylines <- zeroGrob()
-  }
+    x_intercept <- with(scale_details, data.frame(
+      x = x.major,
+      y = y.range[1]
+    ))
+    pos <- self$transform(x_intercept, scale_details)
 
-  ggname("grill", grobTree(
-    element_render(theme, "panel.background"),
-    grob.xlines, grob.ylines
-  ))
-}
+    guide_axis(pos$x, scale_details$x.labels, "bottom", theme)
+  },
 
-#' @export
-coord_render_axis_h.map <- function(coord, details, theme) {
-  if (is.null(details$x.major)) return(zeroGrob())
+  render_axis_v = function(self, scale_details, theme) {
+    if (is.null(scale_details$y.major)) return(zeroGrob())
 
-  x_intercept <- with(details, data.frame(
-    x = x.major,
-    y = y.range[1]
-  ))
-  pos <- coord_transform(coord, x_intercept, details)
+    x_intercept <- with(scale_details, data.frame(
+      x = x.range[1],
+      y = y.major
+    ))
+    pos <- self$transform(x_intercept, scale_details)
 
-  guide_axis(pos$x, details$x.labels, "bottom", theme)
-}
-#' @export
-coord_render_axis_v.map <- function(coord, details, theme) {
-  if (is.null(details$y.major)) return(zeroGrob())
+    guide_axis(pos$y, scale_details$y.labels, "left", theme)
+  }
+)
 
-  x_intercept <- with(details, data.frame(
-    x = x.range[1],
-    y = y.major
-  ))
-  pos <- coord_transform(coord, x_intercept, details)
 
-  guide_axis(pos$y, details$y.labels, "left", theme)
+mproject <- function(coord, x, y, orientation) {
+  suppressWarnings(mapproj::mapproject(x, y,
+    projection = coord$projection,
+    parameters  = coord$params,
+    orientation = orientation
+  ))
 }
diff --git a/R/coord-munch.r b/R/coord-munch.r
index 50523d7..e2b56ba 100644
--- a/R/coord-munch.r
+++ b/R/coord-munch.r
@@ -1,8 +1,21 @@
+#' Munch coordinates data
+#'
+#' This function "munches" lines, dividing each line into many small pieces
+#' so they can be transformed independently. Used inside geom functions.
+#'
+#' @param coord Coordinate system definition.
+#' @param data Data set to transform - should have variables \code{x} and
+#'   \code{y} are chopped up into small pieces (as defined by \code{group}).
+#'   All other variables are duplicated as needed.
+#' @param range Panel range specification.
+#' @param segment_length Target segment length
+#' @keywords internal
+#' @export
 coord_munch <- function(coord, data, range, segment_length = 0.01) {
-  if (is.linear(coord)) return(coord_transform(coord, data, range))
+  if (coord$is_linear()) return(coord$transform(data, range))
 
   # range has theta and r values; get corresponding x and y values
-  ranges <- coord_range(coord, range)
+  ranges <- coord$range(range)
 
   # Convert any infinite locations into max/min
   # Only need to work with x and y because for munching, those are the
@@ -13,16 +26,16 @@ coord_munch <- function(coord, data, range, segment_length = 0.01) {
   data$y[data$y == Inf]  <- ranges$y[2]
 
   # Calculate distances using coord distance metric
-  dist <- coord_distance(coord, data$x, data$y, range)
+  dist <- coord$distance(data$x, data$y, range)
   dist[data$group[-1] != data$group[-nrow(data)]] <- NA
 
   # Munch and then transform result
   munched <- munch_data(data, dist, segment_length)
-  coord_transform(coord, munched, range)
+  coord$transform(munched, range)
 }
 
 # For munching, only grobs are lines and polygons: everything else is
-# transfomed into those special cases by the geom.
+# transformed into those special cases by the geom.
 #
 # @param dist distance, scaled from 0 to 1 (maximum distance on plot)
 # @keyword internal
@@ -34,26 +47,28 @@ munch_data <- function(data, dist = NULL, segment_length = 0.01) {
     dist <- dist_euclidean(data$x, data$y)
   }
 
-  # How many pieces for each old segment
-  extra <- floor(dist / segment_length) + 1
+  # How many endpoints for each old segment, not counting the last one
+  extra <- pmax(floor(dist / segment_length), 1)
   extra[is.na(extra)] <- 1
-
   # Generate extra pieces for x and y values
-  x <- unlist(mapply(interp, data$x[-n], data$x[-1], extra, SIMPLIFY = FALSE))
-  y <- unlist(mapply(interp, data$y[-n], data$y[-1], extra, SIMPLIFY = FALSE))
+  # The final point must be manually inserted at the end
+  x <- c(unlist(mapply(interp, data$x[-n], data$x[-1], extra, SIMPLIFY = FALSE)), data$x[n])
+  y <- c(unlist(mapply(interp, data$y[-n], data$y[-1], extra, SIMPLIFY = FALSE)), data$y[n])
 
-  # Replicate other aesthetics: defined by start point
-  id <- rep(seq_len(nrow(data) - 1), extra)
-  aes_df <- data[id, setdiff(names(data), c("x", "y"))]
+  # Replicate other aesthetics: defined by start point but also
+  # must include final point
+  id <- c(rep(seq_len(nrow(data) - 1), extra), nrow(data))
+  aes_df <- data[id, setdiff(names(data), c("x", "y")), drop = FALSE]
 
-  unrowname(data.frame(x = x, y = y, aes_df))
+  plyr::unrowname(data.frame(x = x, y = y, aes_df))
 }
 
 # Interpolate.
-# Interpolate n evenly spaced steps from start to end - (end - start) / n.
+# Interpolate n-1 evenly spaced steps (n points) from start to
+# (end - (end - start) / n). end is never included in sequence.
 interp <- function(start, end, n) {
   if (n == 1) return(start)
-  start + seq(0, 1, length = n) * (end - start)
+  start + seq(0, 1, length.out = n + 1)[-(n + 1)] * (end - start)
 }
 
 # Euclidean distance between points.
@@ -97,7 +112,7 @@ dist_polar <- function(r, theta) {
   # Rename x and y columns to r and t, since we're working in polar
   # Note that 'slope' actually means the spiral slope, 'a' in the spiral
   #   formula r = a * theta
-  lf <- rename(lf, c(x1 = "t1", x2 = "t2", y1 = "r1", y2 = "r2",
+  lf <- plyr::rename(lf, c(x1 = "t1", x2 = "t2", y1 = "r1", y2 = "r2",
     yintercept = "r_int",  xintercept = "t_int"), warn_missing = FALSE)
 
   # Re-normalize the theta values so that intercept for each is 0
@@ -126,7 +141,7 @@ dist_polar <- function(r, theta) {
   lf$dist[idx] <-
     spiral_arc_length(lf$slope[idx], lf$tn1[idx], lf$tn2[idx])
 
-  # Get cicular arc length for segments that have zero slope (r1 == r2)
+  # Get circular arc length for segments that have zero slope (r1 == r2)
   idx <- !is.na(lf$slope) & lf$slope == 0
   lf$dist[idx] <- lf$r1[idx] * (lf$t2[idx] - lf$t1[idx])
 
diff --git a/R/coord-polar.r b/R/coord-polar.r
index e6e0dc2..aa62111 100644
--- a/R/coord-polar.r
+++ b/R/coord-polar.r
@@ -8,12 +8,18 @@
 #' @param direction 1, clockwise; -1, anticlockwise
 #' @export
 #' @examples
-#' \donttest{
 #' # NOTE: Use these plots with caution - polar coordinates has
 #' # major perceptual problems.  The main point of these examples is
 #' # to demonstrate how these common plots can be described in the
 #' # grammar.  Use with EXTREME caution.
 #'
+#' #' # A pie chart = stacked bar chart + polar coordinates
+#' pie <- ggplot(mtcars, aes(x = factor(1), fill = factor(cyl))) +
+#'  geom_bar(width = 1)
+#' pie + coord_polar(theta = "y")
+#'
+#' \donttest{
+#'
 #' # A coxcomb plot = bar chart + polar coordinates
 #' cxc <- ggplot(mtcars, aes(x = factor(cyl))) +
 #'   geom_bar(width = 1, colour = "black")
@@ -21,18 +27,13 @@
 #' # A new type of plot?
 #' cxc + coord_polar(theta = "y")
 #'
-#' # A pie chart = stacked bar chart + polar coordinates
-#' pie <- ggplot(mtcars, aes(x = factor(1), fill = factor(cyl))) +
-#'  geom_bar(width = 1)
-#' pie + coord_polar(theta = "y")
-#'
 #' # The bullseye chart
 #' pie + coord_polar()
 #'
 #' # Hadley's favourite pie chart
 #' df <- data.frame(
-#'   variable = c("resembles", "does not resemble"),
-#'   value = c(80, 20)
+#'   variable = c("does not resemble", "resembles"),
+#'   value = c(20, 80)
 #' )
 #' ggplot(df, aes(x = "", y = value, fill = variable)) +
 #'   geom_bar(width = 1, stat = "identity") +
@@ -41,6 +42,7 @@
 #'   labs(title = "Pac man")
 #'
 #' # Windrose + doughnut plot
+#' if (require("ggplot2movies")) {
 #' movies$rrating <- cut_interval(movies$rating, length = 1)
 #' movies$budgetq <- cut_number(movies$budget, 4)
 #'
@@ -51,216 +53,252 @@
 #' # Race track plot
 #' doh + geom_bar(width = 0.9, position = "fill") + coord_polar(theta = "y")
 #' }
+#' }
 coord_polar <- function(theta = "x", start = 0, direction = 1) {
   theta <- match.arg(theta, c("x", "y"))
   r <- if (theta == "x") "y" else "x"
 
-  coord(
-    theta = theta, r = r,
-    start = start, direction = sign(direction),
-    subclass = "polar"
+  ggproto(NULL, CoordPolar,
+    theta = theta,
+    r = r,
+    start = start,
+    direction = sign(direction)
   )
 }
 
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
 #' @export
-coord_aspect.polar <- function(coord, details) 1
-
-#' @export
-coord_distance.polar <- function(coord, x, y, details) {
-  if (coord$theta == "x") {
-    r <- rescale(y, from = details$r.range)
-    theta <- theta_rescale_no_clip(coord, x, details)
-  } else {
-    r <- rescale(x, from = details$r.range)
-    theta <- theta_rescale_no_clip(coord, y, details)
-  }
+CoordPolar <- ggproto("CoordPolar", Coord,
 
-  dist_polar(r, theta)
-}
+  aspect = function(details) 1,
 
-#' @export
-coord_range.polar <- function(coord, scales) {
-  setNames(list(scales$theta.range, scales$r.range), c(coord$theta, coord$r))
-}
+  distance = function(self, x, y, details) {
+    if (self$theta == "x") {
+      r <- rescale(y, from = details$r.range)
+      theta <- theta_rescale_no_clip(self, x, details)
+    } else {
+      r <- rescale(x, from = details$r.range)
+      theta <- theta_rescale_no_clip(self, y, details)
+    }
 
-#' @export
-coord_train.polar <- function(coord, scales) {
+    dist_polar(r, theta)
+  },
 
-  ret <- list(x = list(), y = list())
-  for (n in c("x", "y")) {
+  range = function(self, scale_details) {
+    setNames(
+      list(scale_details$theta.range, scale_details$r.range),
+      c(self$theta, self$r)
+    )
+  },
+
+  train = function(self, scale_details) {
+
+    ret <- list(x = list(), y = list())
+    for (n in c("x", "y")) {
+
+      scale <- scale_details[[n]]
+      limits <- self$limits[[n]]
+
+      if (is.null(limits)) {
+        if (self$theta == n) {
+          expand <- expand_default(scale, c(0, 0.5), c(0, 0))
+        } else {
+          expand <- expand_default(scale, c(0, 0),   c(0, 0))
+        }
+        range <- scale$dimension(expand)
+      } else {
+        range <- range(scale_transform(scale, limits))
+      }
+
+      out <- scale$break_info(range)
+      ret[[n]]$range <- out$range
+      ret[[n]]$major <- out$major_source
+      ret[[n]]$minor <- out$minor_source
+      ret[[n]]$labels <- out$labels
+    }
 
-    scale <- scales[[n]]
-    limits <- coord$limits[[n]]
+    details = list(
+      x.range = ret$x$range, y.range = ret$y$range,
+      x.major = ret$x$major, x.minor = ret$x$minor, x.labels = ret$x$labels,
+      y.major = ret$y$major, y.minor = ret$y$minor, y.labels = ret$y$labels
+    )
 
-    if (is.null(limits)) {
-      expand <- coord_expand_defaults(coord, scale, n)
-      range <- scale_dimension(scale, expand)
+    if (self$theta == "y") {
+      names(details) <- gsub("x\\.", "r.", names(details))
+      names(details) <- gsub("y\\.", "theta.", names(details))
     } else {
-      range <- range(scale_transform(scale, limits))
+      names(details) <- gsub("x\\.", "theta.", names(details))
+      names(details) <- gsub("y\\.", "r.", names(details))
     }
 
-    out <- scale_break_info(scale, range)
-    ret[[n]]$range <- out$range
-    ret[[n]]$major <- out$major_source
-    ret[[n]]$minor <- out$minor_source
-    ret[[n]]$labels <- out$labels
-  }
+    details
+  },
+
+  transform = function(self, data, scale_details) {
+    data <- rename_data(self, data)
+
+    data$r  <- r_rescale(self, data$r, scale_details)
+    data$theta <- theta_rescale(self, data$theta, scale_details)
+    data$x <- data$r * sin(data$theta) + 0.5
+    data$y <- data$r * cos(data$theta) + 0.5
+
+    data
+  },
+
+  render_axis_v = function(self, scale_details, theme) {
+    x <- r_rescale(self, scale_details$r.major, scale_details) + 0.5
+    guide_axis(x, scale_details$r.labels, "left", theme)
+  },
+
+  render_axis_h = function(scale_details, theme) {
+    guide_axis(NA, "", "bottom", theme)
+  },
+
+  render_bg = function(self, scale_details, theme) {
+    scale_details <- rename_data(self, scale_details)
+
+    theta <- if (length(scale_details$theta.major) > 0)
+      theta_rescale(self, scale_details$theta.major, scale_details)
+    thetamin <- if (length(scale_details$theta.minor) > 0)
+      theta_rescale(self, scale_details$theta.minor, scale_details)
+    thetafine <- seq(0, 2 * pi, length.out = 100)
+
+    rfine <- c(r_rescale(self, scale_details$r.major, scale_details), 0.45)
+
+    # This gets the proper theme element for theta and r grid lines:
+    #   panel.grid.major.x or .y
+    majortheta <- paste("panel.grid.major.", self$theta, sep = "")
+    minortheta <- paste("panel.grid.minor.", self$theta, sep = "")
+    majorr     <- paste("panel.grid.major.", self$r,     sep = "")
+
+    ggname("grill", grobTree(
+      element_render(theme, "panel.background"),
+      if (length(theta) > 0) element_render(
+        theme, majortheta, name = "angle",
+        x = c(rbind(0, 0.45 * sin(theta))) + 0.5,
+        y = c(rbind(0, 0.45 * cos(theta))) + 0.5,
+        id.lengths = rep(2, length(theta)),
+        default.units = "native"
+      ),
+      if (length(thetamin) > 0) element_render(
+        theme, minortheta, name = "angle",
+        x = c(rbind(0, 0.45 * sin(thetamin))) + 0.5,
+        y = c(rbind(0, 0.45 * cos(thetamin))) + 0.5,
+        id.lengths = rep(2, length(thetamin)),
+        default.units = "native"
+      ),
+
+      element_render(
+        theme, majorr, name = "radius",
+        x = rep(rfine, each = length(thetafine)) * sin(thetafine) + 0.5,
+        y = rep(rfine, each = length(thetafine)) * cos(thetafine) + 0.5,
+        id.lengths = rep(length(thetafine), length(rfine)),
+        default.units = "native"
+      )
+    ))
+  },
+
+  render_fg = function(self, scale_details, theme) {
+    if (is.null(scale_details$theta.major)) {
+      return(element_render(theme, "panel.border"))
+    }
 
-  details <- list(
-    x.range = ret$x$range, y.range = ret$y$range,
-    x.major = ret$x$major, x.minor = ret$x$minor, x.labels = ret$x$labels,
-    y.major = ret$y$major, y.minor = ret$y$minor, y.labels = ret$y$labels
-  )
+    theta <- theta_rescale(self, scale_details$theta.major, scale_details)
+    labels <- scale_details$theta.labels
+
+    # Combine the two ends of the scale if they are close
+    theta <- theta[!is.na(theta)]
+    ends_apart <- (theta[length(theta)] - theta[1]) %% (2 * pi)
+    if (length(theta) > 0 && ends_apart < 0.05) {
+      n <- length(labels)
+      if (is.expression(labels)) {
+        combined <- substitute(paste(a, "/", b),
+          list(a = labels[[1]], b = labels[[n]]))
+      } else {
+        combined <- paste(labels[1], labels[n], sep = "/")
+      }
+      labels[[n]] <- combined
+      labels <- labels[-1]
+      theta <- theta[-1]
+    }
 
-  if (coord$theta == "y") {
-    names(details) <- gsub("x\\.", "r.", names(details))
-    names(details) <- gsub("y\\.", "theta.", names(details))
-  } else {
-    names(details) <- gsub("x\\.", "theta.", names(details))
-    names(details) <- gsub("y\\.", "r.", names(details))
+    grobTree(
+      if (length(labels) > 0) element_render(
+        theme, "axis.text.x",
+        labels, 0.45 * sin(theta) + 0.5, 0.45 * cos(theta) + 0.5,
+        hjust = 0.5, vjust = 0.5,
+        default.units = "native"
+      ),
+      element_render(theme, "panel.border")
+    )
+  },
+
+  render_fg = function(self, scale_details, theme) {
+    if (is.null(scale_details$theta.major)) {
+      return(element_render(theme, "panel.border"))
+    }
+
+    theta <- theta_rescale(self, scale_details$theta.major, scale_details)
+    labels <- scale_details$theta.labels
+
+    # Combine the two ends of the scale if they are close
+    theta <- theta[!is.na(theta)]
+    ends_apart <- (theta[length(theta)] - theta[1]) %% (2*pi)
+    if (length(theta) > 0 && ends_apart < 0.05) {
+      n <- length(labels)
+      if (is.expression(labels)) {
+        combined <- substitute(paste(a, "/", b),
+          list(a = labels[[1]], b = labels[[n]]))
+      } else {
+        combined <- paste(labels[1], labels[n], sep = "/")
+      }
+      labels[[n]] <- combined
+      labels <- labels[-1]
+      theta <- theta[-1]
+    }
+
+    grobTree(
+      if (length(labels) > 0) element_render(
+        theme, "axis.text.x",
+        labels,
+        unit(0.45 * sin(theta) + 0.5, "native"),
+        unit(0.45 * cos(theta) + 0.5, "native"),
+        hjust = 0.5, vjust = 0.5
+      ),
+      element_render(theme, "panel.border")
+    )
+  },
+
+  labels = function(self, scale_details) {
+    if (self$theta == "y") {
+      list(x = scale_details$y, y = scale_details$x)
+    } else {
+      scale_details
+    }
   }
+)
 
-  details
-}
 
 rename_data <- function(coord, data) {
   if (coord$theta == "y") {
-    rename(data, c("y" = "theta", "x" = "r"), warn_missing = FALSE)
+    plyr::rename(data, c("y" = "theta", "x" = "r"), warn_missing = FALSE)
   } else {
-    rename(data, c("y" = "r", "x" = "theta"), warn_missing = FALSE)
+    plyr::rename(data, c("y" = "r", "x" = "theta"), warn_missing = FALSE)
   }
 }
 
-theta_rescale_no_clip <- function(coord, x, details) {
+theta_rescale_no_clip <- function(coord, x, scale_details) {
   rotate <- function(x) (x + coord$start) * coord$direction
-  rotate(rescale(x, c(0, 2 * pi), details$theta.range))
+  rotate(rescale(x, c(0, 2 * pi), scale_details$theta.range))
 }
 
-theta_rescale <- function(coord, x, details) {
+theta_rescale <- function(coord, x, scale_details) {
   rotate <- function(x) (x + coord$start) %% (2 * pi) * coord$direction
-  rotate(rescale(x, c(0, 2 * pi), details$theta.range))
-}
-
-r_rescale <- function(coord, x, details) {
-  rescale(x, c(0, 0.4), details$r.range)
-}
-
-#' @export
-coord_expand_defaults.polar <- function(coord, scale, aesthetic) {
-  if (coord$theta == aesthetic) {
-    expand_default(scale, c(0, 0.5), c(0, 0))
-  } else {
-    expand_default(scale, c(0, 0),   c(0, 0))
-  }
-}
-
-#' @export
-coord_transform.polar <- function(coord, data, details) {
-  data <- rename_data(coord, data)
-
-  data$r  <- r_rescale(coord, data$r, details)
-  data$theta <- theta_rescale(coord, data$theta, details)
-  data$x <- data$r * sin(data$theta) + 0.5
-  data$y <- data$r * cos(data$theta) + 0.5
-
-  data
-}
-
-#' @export
-coord_render_axis_v.polar <- function(coord, details, theme) {
-  x <- r_rescale(coord,details$r.major, details) + 0.5
-  guide_axis(x, details$r.labels, "left", theme)
-}
-#' @export
-coord_render_axis_h.polar <- function(coord, details, theme) {
-  guide_axis(NA, "", "bottom", theme)
-}
-
-#' @export
-coord_render_bg.polar <- function(coord, details, theme) {
-  details <- rename_data(coord, details)
-
-  theta <- if (length(details$theta.major) > 0) theta_rescale(coord, details$theta.major, details)
-  thetamin <- if (length(details$theta.minor) > 0) theta_rescale(coord, details$theta.minor, details)
-  thetafine <- seq(0, 2 * pi, length=100)
-
-  r <- 0.4
-  rfine <- c(r_rescale(coord, details$r.major, details), 0.45)
-
-  # This gets the proper theme element for theta and r grid lines:
-  #   panel.grid.major.x or .y
-  majortheta <- paste("panel.grid.major.", coord$theta, sep = "")
-  minortheta <- paste("panel.grid.minor.", coord$theta, sep = "")
-  majorr     <- paste("panel.grid.major.", coord$r,     sep = "")
-
-  ggname("grill", grobTree(
-    element_render(theme, "panel.background"),
-    if (length(theta) > 0) element_render(
-      theme, majortheta, name = "angle",
-      x = c(rbind(0, 0.45 * sin(theta))) + 0.5,
-      y = c(rbind(0, 0.45 * cos(theta))) + 0.5,
-      id.lengths = rep(2, length(theta)),
-      default.units="native"
-    ),
-    if (length(thetamin) > 0) element_render(
-      theme, minortheta, name = "angle",
-      x = c(rbind(0, 0.45 * sin(thetamin))) + 0.5,
-      y = c(rbind(0, 0.45 * cos(thetamin))) + 0.5,
-      id.lengths = rep(2, length(thetamin)),
-      default.units="native"
-    ),
-
-    element_render(
-      theme, majorr, name = "radius",
-      x = rep(rfine, each=length(thetafine)) * sin(thetafine) + 0.5,
-      y = rep(rfine, each=length(thetafine)) * cos(thetafine) + 0.5,
-      id.lengths = rep(length(thetafine), length(rfine)),
-      default.units="native"
-    )
-  ))
+  rotate(rescale(x, c(0, 2 * pi), scale_details$theta.range))
 }
 
-#' @export
-coord_render_fg.polar <- function(coord, details, theme) {
-  if (is.null(details$theta.major)) {
-    return(element_render(theme, "panel.border"))
-  }
-
-  theta <- theta_rescale(coord, details$theta.major, details)
-  labels <- details$theta.labels
-
-  # Combine the two ends of the scale if they are close
-  theta <- theta[!is.na(theta)]
-  ends_apart <- (theta[length(theta)] - theta[1]) %% (2*pi)
-  if (ends_apart < 0.05) {
-    n <- length(labels)
-    if (is.expression(labels)) {
-      combined <- substitute(paste(a, "/", b),
-        list(a = labels[[1]], b = labels[[n]]))
-    } else {
-      combined <- paste(labels[1], labels[n], sep="/")
-    }
-    labels[[n]] <- combined
-    labels <- labels[-1]
-    theta <- theta[-1]
-  }
-
-  grobTree(
-    if (length(labels) > 0) element_render(
-      theme, "axis.text.x",
-      labels, 0.45 * sin(theta) + 0.5, 0.45 * cos(theta) + 0.5,
-      hjust = 0.5, vjust = 0.5,
-      default.units="native"
-    ),
-    element_render(theme, "panel.border")
-  )
-}
-
-#' @export
-coord_labels.polar <- function(coord, scales) {
-  if (coord$theta == "y") {
-    list(x = scales$y, y = scales$x)
-  } else {
-    scales
-  }
+r_rescale <- function(coord, x, scale_details) {
+  rescale(x, c(0, 0.4), scale_details$r.range)
 }
diff --git a/R/coord-quickmap.R b/R/coord-quickmap.R
index 48bdfb7..a16ff71 100644
--- a/R/coord-quickmap.R
+++ b/R/coord-quickmap.R
@@ -1,65 +1,36 @@
-#' Cartesian coordinates with an aspect ratio approximating Mercator projection.
-#'
-#' The represenation of a portion of the earth, wich is approximately spherical,
-#' onto a flat 2D plane requires a projection. This is what
-#' \code{\link{coord_map}} does. These projections account for the fact that the
-#' actual length (in km) of one degree of longitude varies between the equator
-#' and the pole. Near the equator, the ratio between the lengths of one degree
-#' of latitude and one degree of longitude is approximately 1. Near the pole, it
-#' is tends towards infinity because the length of one degree of longitude tends
-#' towards 0. For regions that span only a few degrees and are not too close to
-#' the poles, setting the aspect ratio of the plot to the appropriate lat/lon
-#' ratio approximates the usual mercator projection. This is what
-#' \code{coord_quickmap} does. With \code{\link{coord_map}} all elements of the
-#' graphic have to be projected which is not the case here. So
-#' \code{\link{coord_quickmap}} has the advantage of being much faster, in
-#' particular for complex plots such as those using with
-#' \code{\link{geom_tile}}, at the expense of correctedness in the projection.
-#'
-#' @export
 #' @inheritParams coord_cartesian
-#' @examples
-#' # ensures that the ranges of axes are equal to the specified ratio by
-#' # adjusting the plot aspect ratio
-#' 
-#' if (require("maps")) {
-#' # Create a lat-long dataframe from the maps package
-#' nz <- map_data("nz")
-#' # Prepare a plot of the map
-#' nzmap <- ggplot(nz, aes(x = long, y = lat, group = group)) +
-#'   geom_polygon(fill = "white", colour = "black")
-#'
-#' # Plot it in cartesian coordinates
-#' nzmap
-#' # With correct mercator projection
-#' nzmap + coord_map()
-#' # With the aspect ratio approximation
-#' nzmap + coord_quickmap()
-#' }
-#' 
-#' # Resize the plot to see that the specified aspect ratio is maintained
-coord_quickmap <- function(xlim = NULL, ylim = NULL) {
-  coord(limits = list(x = xlim, y = ylim),
-    subclass = c("quickmap", "cartesian"))
+#' @export
+#' @rdname coord_map
+coord_quickmap <- function(xlim = NULL, ylim = NULL, expand = TRUE) {
+  ggproto(NULL, CoordQuickmap,
+    limits = list(x = xlim, y = ylim),
+    expand = expand
+  )
 }
 
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
 #' @export
-coord_aspect.quickmap <- function(coord, ranges) {
-  # compute coordinates of center point of map
-  x.center <- sum(ranges$x.range) / 2
-  y.center <- sum(ranges$y.range) / 2
+CoordQuickmap <- ggproto("CoordQuickmap", CoordCartesian,
 
-  # compute distance corresponding to 1 degree in either direction
-  # from the center
-  x.dist <- dist_central_angle(x.center + c(-0.5, 0.5), rep(y.center, 2))
-  y.dist <- dist_central_angle(rep(x.center, 2), y.center+c(-0.5, 0.5))
-  # NB: this makes the projection correct in the center of the plot and
-  #     increasingly less correct towards the edges. For regions of reasonnable
-  #     size, this seems to give better results than computing this ratio from
-  #     the total lat and lon span.
+  aspect = function(ranges) {
+    # compute coordinates of center point of map
+    x.center <- sum(ranges$x.range) / 2
+    y.center <- sum(ranges$y.range) / 2
 
-  # scale the plot with this aspect ratio
-  ratio <- y.dist / x.dist
+    # compute distance corresponding to 1 degree in either direction
+    # from the center
+    x.dist <- dist_central_angle(x.center + c(-0.5, 0.5), rep(y.center, 2))
+    y.dist <- dist_central_angle(rep(x.center, 2), y.center + c(-0.5, 0.5))
+    # NB: this makes the projection correct in the center of the plot and
+    #     increasingly less correct towards the edges. For regions of reasonnable
+    #     size, this seems to give better results than computing this ratio from
+    #     the total lat and lon span.
 
-  diff(ranges$y.range) / diff(ranges$x.range) * ratio
-}
+    # scale the plot with this aspect ratio
+    ratio <- y.dist / x.dist
+
+    diff(ranges$y.range) / diff(ranges$x.range) * ratio
+  }
+)
diff --git a/R/coord-transform.r b/R/coord-transform.r
index 7496f06..cc506b1 100644
--- a/R/coord-transform.r
+++ b/R/coord-transform.r
@@ -8,22 +8,28 @@
 #' \code{\link[scales]{trans_new}} for list of transformations, and instructions on
 #' how to create your own.
 #'
-#' @param xtrans,ytrans transformers for x and y axes
+#' @param x,y transformers for x and y axes
+#' @param xtrans,ytrans Deprecated; use \code{x} and \code{y} instead.
 #' @param limx,limy limits for x and y axes. (Named so for backward
-#'    compatability)
+#'    compatibility)
 #' @export
 #' @examples
 #' \donttest{
 #' # See ?geom_boxplot for other examples
 #'
-#' # Three ways of doing transformating in ggplot:
+#' # Three ways of doing transformation in ggplot:
 #' #  * by transforming the data
-#' qplot(log10(carat), log10(price), data=diamonds)
+#' ggplot(diamonds, aes(log10(carat), log10(price))) +
+#'   geom_point()
 #' #  * by transforming the scales
-#' qplot(carat, price, data=diamonds, log="xy")
-#' qplot(carat, price, data=diamonds) + scale_x_log10() + scale_y_log10()
+#' ggplot(diamonds, aes(carat, price)) +
+#'   geom_point() +
+#'   scale_x_log10() +
+#'   scale_y_log10()
 #' #  * by transforming the coordinate system:
-#' qplot(carat, price, data=diamonds) + coord_trans(x = "log10", y = "log10")
+#' ggplot(diamonds, aes(carat, price)) +
+#'   geom_point() +
+#'   coord_trans(x = "log10", y = "log10")
 #'
 #' # The difference between transforming the scales and
 #' # transforming the coordinate system is that scale
@@ -32,10 +38,16 @@
 #' # changes the shape of geoms:
 #'
 #' d <- subset(diamonds, carat > 0.5)
-#' qplot(carat, price, data = d, log="xy") +
-#'   geom_smooth(method="lm")
-#' qplot(carat, price, data = d) +
-#'   geom_smooth(method="lm") +
+#'
+#' ggplot(d, aes(carat, price)) +
+#'   geom_point() +
+#'   geom_smooth(method = "lm") +
+#'   scale_x_log10() +
+#'   scale_y_log10()
+#'
+#' ggplot(d, aes(carat, price)) +
+#'   geom_point() +
+#'   geom_smooth(method = "lm") +
 #'   coord_trans(x = "log10", y = "log10")
 #'
 #' # Here I used a subset of diamonds so that the smoothed line didn't
@@ -44,12 +56,17 @@
 #'
 #' # With a combination of scale and coordinate transformation, it's
 #' # possible to do back-transformations:
-#' library(scales)
-#' qplot(carat, price, data=diamonds, log="xy") +
-#'   geom_smooth(method="lm") +
-#'   coord_trans(x = exp_trans(10), y = exp_trans(10))
+#' ggplot(diamonds, aes(carat, price)) +
+#'   geom_point() +
+#'   geom_smooth(method = "lm") +
+#'   scale_x_log10() +
+#'   scale_y_log10() +
+#'   coord_trans(x = scales::exp_trans(10), y = scales::exp_trans(10))
+#'
 #' # cf.
-#' qplot(carat, price, data=diamonds) + geom_smooth(method = "lm")
+#' ggplot(diamonds, aes(carat, price)) +
+#'   geom_point() +
+#'   geom_smooth(method = "lm")
 #'
 #' # Also works with discrete scales
 #' df <- data.frame(a = abs(rnorm(26)),letters)
@@ -58,65 +75,89 @@
 #' plot + coord_trans(x = "log10")
 #' plot + coord_trans(x = "sqrt")
 #' }
-coord_trans <- function(xtrans = "identity", ytrans = "identity", limx = NULL, limy = NULL) {
+coord_trans <- function(x = "identity", y = "identity", limx = NULL, limy = NULL,
+  xtrans, ytrans)
+{
+  if (!missing(xtrans)) {
+    gg_dep("1.0.1", "`xtrans` arguments is deprecated; please use `x` instead.")
+    x <- xtrans
+  }
+  if (!missing(ytrans)) {
+    gg_dep("1.0.1", "`ytrans` arguments is deprecated; please use `y` instead.")
+    y <- ytrans
+  }
+
   # @kohske
   # Now limits are implemented.
   # But for backward compatibility, xlim -> limx, ylim -> ylim
   # Because there are many examples such as
   # > coord_trans(x = "log10", y = "log10")
   # Maybe this is changed.
-  if (is.character(xtrans)) xtrans <- as.trans(xtrans)
-  if (is.character(ytrans)) ytrans <- as.trans(ytrans)
+  if (is.character(x)) x <- as.trans(x)
+  if (is.character(y)) y <- as.trans(y)
 
-  coord(trans = list(x = xtrans, y = ytrans), limits = list(x = limx, y = limy), subclass = "trans")
-}
 
-#' @export
-coord_distance.trans <- function(coord, x, y, details) {
-  max_dist <- dist_euclidean(details$x.range, details$y.range)
-  dist_euclidean(coord$trans$x$transform(x), coord$trans$y$transform(y)) / max_dist
+  ggproto(NULL, CoordTrans,
+    trans = list(x = x, y = y),
+    limits = list(x = limx, y = limy)
+  )
 }
 
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
 #' @export
-coord_transform.trans <- function(coord, data, details) {
-  trans_x <- function(data) transform_value(coord$trans$x, data, details$x.range)
-  trans_y <- function(data) transform_value(coord$trans$y, data, details$y.range)
+CoordTrans <- ggproto("CoordTrans", Coord,
+
+  distance = function(self, x, y, scale_details) {
+    max_dist <- dist_euclidean(scale_details$x.range, scale_details$y.range)
+    dist_euclidean(self$trans$x$transform(x), self$trans$y$transform(y)) / max_dist
+  },
+
+  transform = function(self, data, scale_details) {
+    trans_x <- function(data) transform_value(self$trans$x, data, scale_details$x.range)
+    trans_y <- function(data) transform_value(self$trans$y, data, scale_details$y.range)
+
+    data <- transform_position(data, trans_x, trans_y)
+    transform_position(data, squish_infinite, squish_infinite)
+  },
+
+  train = function(self, scale_details) {
+    c(train_trans(scale_details$x, self$limits$x, self$trans$x, "x"),
+      train_trans(scale_details$y, self$limits$y, self$trans$y, "y"))
+  }
+)
 
-  data <- transform_position(data, trans_x, trans_y)
-  transform_position(data, squish_infinite, squish_infinite)
-}
 transform_value <- function(trans, value, range) {
+  if (is.null(value))
+    return(value)
   rescale(trans$transform(value), 0:1, range)
 }
 
-#' @export
-coord_train.trans <- function(coord, scales) {
-  c(train_trans(scales$x, coord$limits$x, coord$trans$x, "x"),
-    train_trans(scales$y, coord$limits$y, coord$trans$y, "y"))
-}
 
-train_trans <- function(scale, limits, trans, name) {
+train_trans <- function(scale_details, limits, trans, name) {
   # first, calculate the range that is the numerical limits in data space
 
   # expand defined by scale OR coord
   # @kohske
   # Expansion of data range sometimes go beyond domain,
-  # so in trasn, expansion takes place at the fnial stage.
+  # so in trans, expansion takes place at the final stage.
   if (is.null(limits)) {
-    range <- scale_dimension(scale, c(0, 0))
+    range <- scale_details$dimension()
   } else {
-    range <- range(scale_transform(scale, limits))
+    range <- range(scale_details$transform(limits))
   }
 
   # breaks on data space
-  out <- scale_break_info(scale, range)
+  out <- scale_details$break_info(range)
 
   # trans'd range
   out$range <- trans$transform(out$range)
 
   # expansion if limits are not specified
   if (is.null(limits)) {
-    expand <- coord_expand_defaults(coord, scale)
+    expand <- expand_default(scale_details)
     out$range <- expand_range(out$range, expand[1], expand[2])
   }
 
@@ -124,8 +165,10 @@ train_trans <- function(scale, limits, trans, name) {
   out$major_source <- transform_value(trans, out$major_source, out$range)
   out$minor_source <- transform_value(trans, out$minor_source, out$range)
 
-  out <- list(range = out$range, labels = out$labels,
-              major = out$major_source, minor = out$minor_source)
+  out <- list(
+    range = out$range, labels = out$labels,
+    major = out$major_source, minor = out$minor_source
+  )
   names(out) <- paste(name, names(out), sep = ".")
   out
 }
diff --git a/R/ggplot2.r b/R/data.R
similarity index 54%
copy from R/ggplot2.r
copy to R/data.R
index 0aca6e5..adc052d 100644
--- a/R/ggplot2.r
+++ b/R/data.R
@@ -1,64 +1,56 @@
-#' ggplot2.
-#'
-#' @name ggplot2
-#' @docType package
-#' @import plyr digest scales grid reshape2 proto gtable
-NULL
-
 #' Prices of 50,000 round cut diamonds
 #'
 #' A dataset containing the prices and other attributes of almost 54,000
 #'  diamonds. The variables are as follows:
 #'
+#' @format A data frame with 53940 rows and 10 variables:
 #' \itemize{
-#'   \item price. price in US dollars (\$326--\$18,823)
-#'   \item carat. weight of the diamond (0.2--5.01)
-#'   \item cut. quality of the cut (Fair, Good, Very Good, Premium, Ideal)
-#'   \item colour. diamond colour, from J (worst) to D (best)
-#'   \item clarity. a measurement of how clear the diamond is (I1 (worst), SI1, SI2, VS1, VS2, VVS1, VVS2, IF (best))
-#'   \item x. length in mm (0--10.74)
-#'   \item y. width in mm (0--58.9)
-#'   \item z. depth in mm (0--31.8)
-#'   \item depth. total depth percentage = z / mean(x, y) = 2 * z / (x + y) (43--79)
-#'   \item table. width of top of diamond relative to widest point (43--95)
+#'   \item price: price in US dollars (\$326--\$18,823)
+#'   \item carat: weight of the diamond (0.2--5.01)
+#'   \item cut: quality of the cut (Fair, Good, Very Good, Premium, Ideal)
+#'   \item color: diamond colour, from J (worst) to D (best)
+#'   \item clarity: a measurement of how clear the diamond is
+#'      (I1 (worst), SI1, SI2, VS1, VS2, VVS1, VVS2, IF (best))
+#'   \item x: length in mm (0--10.74)
+#'   \item y: width in mm (0--58.9)
+#'   \item z: depth in mm (0--31.8)
+#'   \item depth: total depth percentage = z / mean(x, y) = 2 * z / (x + y) (43--79)
+#'   \item table: width of top of diamond relative to widest point (43--95)
 #' }
-#'
-#' @docType data
-#' @keywords datasets
-#' @name diamonds
-#' @usage data(diamonds)
-#' @format A data frame with 53940 rows and 10 variables
-NULL
+"diamonds"
 
 
 #' US economic time series.
 #'
-#' This dataset was produced from US economic time series data available from \url{http://research.stlouisfed.org/fred2}.
+#' This dataset was produced from US economic time series data available from
+#' \url{http://research.stlouisfed.org/fred2}. \code{economics} is in "wide"
+#' format, \code{economics_long} is in "long" format.
 #'
+#' @format A data frame with 478 rows and 6 variables
 #' \itemize{
 #'   \item date.  Month of data collection
-#'
-#'   \item psavert, personal savings rate, \url{http://research.stlouisfed.org/fred2/series/PSAVERT/}
-#'   \item pce, personal consumption expenditures, in billions of dollars, \url{http://research.stlouisfed.org/fred2/series/PCE}
-#'   \item unemploy, number of unemployed in thousands, \url{http://research.stlouisfed.org/fred2/series/UNEMPLOY}
-#'   \item uempmed, median duration of unemployment, in week, \url{http://research.stlouisfed.org/fred2/series/UEMPMED}
-#'   \item pop, total population, in thousands, \url{http://research.stlouisfed.org/fred2/series/POP}
-#'
+#'   \item psavert, personal savings rate,
+#'     \url{http://research.stlouisfed.org/fred2/series/PSAVERT/}
+#'   \item pce, personal consumption expenditures, in billions of dollars,
+#'     \url{http://research.stlouisfed.org/fred2/series/PCE}
+#'   \item unemploy, number of unemployed in thousands,
+#'     \url{http://research.stlouisfed.org/fred2/series/UNEMPLOY}
+#'   \item uempmed, median duration of unemployment, in week,
+#'     \url{http://research.stlouisfed.org/fred2/series/UEMPMED}
+#'   \item pop, total population, in thousands,
+#'    \url{http://research.stlouisfed.org/fred2/series/POP}
 #' }
 #'
-#' @docType data
-#' @keywords datasets
-#' @name economics
-#' @usage data(economics)
-#' @format A data frame with 478 rows and 6 variables
-NULL
+"economics"
+
+#' @rdname economics
+"economics_long"
 
 #' Midwest demographics.
 #'
 #' Demographic information of midwest counties
 #'
-#' The variables are as follows:
-#'
+#' @format A data frame with 437 rows and 28 variables
 #' \itemize{
 #'  \item PID
 #'  \item county
@@ -90,53 +82,17 @@ NULL
 #'  \item category'
 #' }
 #'
-#' @docType data
-#' @keywords datasets
-#' @name midwest
-#' @usage data(midwest)
-#' @format A data frame with 437 rows and 28 variables
-NULL
+"midwest"
 
 
-#' Movie information and user ratings from IMDB.com.
-#'
-#' The internet movie database, \url{http://imdb.com/}, is a website devoted
-#' to collecting movie data supplied by studios and fans.  It claims to be the
-#' biggest movie database on the web and is run by amazon.  More about
-#' information imdb.com can be found online,
-#' \url{http://imdb.com/help/show_leaf?about}, including information about
-#' the data collection process,
-#' \url{http://imdb.com/help/show_leaf?infosource}.
-#'
-#' Movies were selected for inclusion if they had a known length and had been rated by at least one imdb user.  The data set contains the following fields:
-#'
-#' \itemize{
-#'   \item title.  Title of the movie.
-#'   \item year.  Year of release.
-#'   \item budget.  Total budget (if known) in US dollars
-#'   \item length.  Length in minutes.
-#'   \item rating.  Average IMDB user rating.
-#'   \item votes.  Number of IMDB users who rated this movie.
-#'   \item r1-10.  Multiplying by ten gives percentile (to nearest 10\%) of users who rated this movie a 1.
-#'   \item mpaa.  MPAA rating.
-#'   \item action, animation, comedy, drama, documentary, romance, short.  Binary variables representing if movie was classified as belonging to that genre.
-#' }
-#'
-#' @docType data
-#' @keywords datasets
-#' @usage data(movies)
-#' @name movies
-#' @format A data frame with 28819 rows and 24 variables
-#' @references \url{http://had.co.nz/data/movies/}
-NULL
-
 #' Fuel economy data from 1999 and 2008 for 38 popular models of car
 #'
 #' This dataset contains a subset of the fuel economy data that the EPA makes
-#' available on \url{http://fueleconomy.gov}.  It contains only models which
+#' available on \url{http://fueleconomy.gov}. It contains only models which
 #' had a new release every year between 1999 and 2008 - this was used as a
 #' proxy for the popularity of the car.
 #'
+#' @format A data frame with 234 rows and 11 variables
 #' \itemize{
 #'   \item manufacturer.
 #'   \item model.
@@ -150,13 +106,7 @@ NULL
 #'   \item fl.
 #'   \item class.
 #' }
-#'
-#' @docType data
-#' @keywords datasets
-#' @name mpg
-#' @usage data(mpg)
-#' @format A data frame with 234 rows and 11 variables
-NULL
+"mpg"
 
 #' An updated and expanded version of the mammals sleep dataset.
 #'
@@ -169,6 +119,7 @@ NULL
 #' Additional variables order, conservation status and vore were added from
 #' wikipedia.
 #'
+#' @format A data frame with 83 rows and 11 variables
 #' \itemize{
 #'   \item name. common name
 #'   \item genus.
@@ -182,25 +133,15 @@ NULL
 #'   \item brainwt. brain weight in kilograms
 #'   \item bodywt. body weight in kilograms
 #' }
-#'
-#' @docType data
-#' @keywords datasets
-#' @name msleep
-#' @usage data(msleep)
-#' @format A data frame with 83 rows and 11 variables
-NULL
+"msleep"
 
 #' Terms of 10 presidents from Eisenhower to Bush W.
 #'
 #' The names of each president, the start and end date of their term, and
 #' their party of 10 US presidents from Eisenhower to Bush W.
 #'
-#' @docType data
-#' @keywords datasets
-#' @name presidential
-#' @usage data(presidential)
 #' @format A data frame with 10 rows and 4 variables
-NULL
+"presidential"
 
 #' Vector field of seal movements.
 #'
@@ -209,12 +150,45 @@ NULL
 #' (EDA) of the paths of moving animals". J. Statistical Planning and
 #' Inference 122 (2004), 43-63, using the methods of Brillinger, D.R.,
 #' "Learning a potential function from a trajectory", Signal Processing
-#'  Letters. December (2007).
+#' Letters. December (2007).
 #'
-#' @name seals
-#' @usage data(seals)
-#' @docType data
-#' @keywords datasets
 #' @format A data frame with 1155 rows and 4 variables
 #' @references \url{http://www.stat.berkeley.edu/~brill/Papers/jspifinal.pdf}
-NULL
+"seals"
+
+#' 2d density estimate of Old Faithful data
+#'
+#' A 2d density estimate of the waiting and eruptions variables data
+#' \link{faithful}.
+#'
+#' @format A data frame with 5,625 observations and 3 variables.
+"faithfuld"
+
+#' \code{colors()} in Luv space.
+#'
+#' All built-in \code{\link{colors}()} translated into Luv colour space.
+#'
+#' @format A data frame with 657 observations and 4 variables:
+#' \itemize{
+#' \item{L,u,v}{Position in Luv colour space}
+#' \item{col}{Colour name}
+#' }
+"luv_colours"
+
+#' Housing sales in TX.
+#'
+#' Information about the housing market in Texas provided by the TAMU
+#' real estate center, \url{http://recenter.tamu.edu/}.
+#'
+#' @format A data frame with 8602 observations and 9 variables:
+#' \itemize{
+#' \item{city}{Name of MLS area}
+#' \item{year,month,date}{Date}
+#' \item{sales}{Number of sales}
+#' \item{volume}{Total value of sales}
+#' \item{median}{Median sale price}
+#' \item{listings}{Total active listings}
+#' \item{inventory}{"Months inventory": amount of time it would take to sell
+#'   all current listings at current pace of sales.}
+#' }
+"txhousing"
diff --git a/R/facet-grid-.r b/R/facet-grid-.r
index 350a6db..acd2449 100644
--- a/R/facet-grid-.r
+++ b/R/facet-grid-.r
@@ -20,13 +20,23 @@
 #'   y scale; if \code{"free_x"} their width will be proportional to the
 #'  length of the x scale; or if \code{"free"} both height and width will
 #'  vary.  This setting has no effect unless the appropriate scales also vary.
-#' @param labeller A function that takes two arguments (\code{variable} and
-#'   \code{value}) and returns a string suitable for display in the facet
-#'   strip. See \code{\link{label_value}} for more details and pointers
-#'   to other options.
+#' @param labeller A function that takes one data frame of labels and
+#'   returns a list or data frame of character vectors. Each input
+#'   column corresponds to one factor. Thus there will be more than
+#'   one with formulae of the type \code{~cyl + am}. Each output
+#'   column gets displayed as one separate line in the strip
+#'   label. This function should inherit from the "labeller" S3 class
+#'   for compatibility with \code{\link{labeller}()}. See
+#'   \code{\link{label_value}} for more details and pointers to other
+#'   options.
 #' @param as.table If \code{TRUE}, the default, the facets are laid out like
 #'   a table with highest values at the bottom-right. If \code{FALSE}, the
 #'   facets are laid out like a plot with the highest value at the top-right.
+#' @param switch By default, the labels are displayed on the top and
+#'   right of the plot. If \code{"x"}, the top labels will be
+#'   displayed to the bottom. If \code{"y"}, the right-hand side
+#'   labels will be displayed to the left. Can also be set to
+#'   \code{"both"}.
 #' @param shrink If \code{TRUE}, will shrink scales to fit output of
 #'   statistics, not raw data. If \code{FALSE}, will be range of raw data
 #'   before statistical summary.
@@ -59,38 +69,47 @@
 #'         geom_histogram(binwidth = 1)
 #' p + facet_grid(. ~ cut)
 #'
-#' qplot(mpg, wt, data=mtcars, facets = . ~ vs + am)
-#' qplot(mpg, wt, data=mtcars, facets = vs + am ~ . )
+#' g <- ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point()
+#' g + facet_grid(. ~ vs + am)
+#' g + facet_grid(vs + am ~ .)
 #'
 #' # You can also use strings, which makes it a little easier
 #' # when writing functions that generate faceting specifications
-#' # p + facet_grid("cut ~ .")
+#'
+#' p + facet_grid("cut ~ .")
 #'
 #' # see also ?plotmatrix for the scatterplot matrix
 #'
 #' # If there isn't any data for a given combination, that panel
 #' # will be empty
-#' qplot(mpg, wt, data=mtcars) + facet_grid(cyl ~ vs)
 #'
-# If you combine a facetted dataset with a dataset that lacks those
-# facetting variables, the data will be repeated across the missing
-# combinations:
-#' p <- qplot(mpg, wt, data=mtcars, facets = vs ~ cyl)
+#' g + facet_grid(cyl ~ vs)
+#'
+#' # If you combine a facetted dataset with a dataset that lacks those
+#' # facetting variables, the data will be repeated across the missing
+#' # combinations:
+#'
+#' g + facet_grid(vs ~ cyl)
 #'
 #' df <- data.frame(mpg = 22, wt = 3)
-#' p + geom_point(data = df, colour="red", size = 2)
+#' g + facet_grid(vs ~ cyl) +
+#'   geom_point(data = df, colour = "red", size = 2)
 #'
 #' df2 <- data.frame(mpg = c(19, 22), wt = c(2,4), vs = c(0, 1))
-#' p + geom_point(data = df2, colour="red", size = 2)
+#' g + facet_grid(vs ~ cyl) +
+#'   geom_point(data = df2, colour = "red", size = 2)
 #'
 #' df3 <- data.frame(mpg = c(19, 22), wt = c(2,4), vs = c(1, 1))
-#' p + geom_point(data = df3, colour="red", size = 2)
+#' g + facet_grid(vs ~ cyl) +
+#'   geom_point(data = df3, colour = "red", size = 2)
 #'
 #'
 #' # You can also choose whether the scales should be constant
 #' # across all panels (the default), or whether they should be allowed
 #' # to vary
-#' mt <- ggplot(mtcars, aes(mpg, wt, colour = factor(cyl))) + geom_point()
+#' mt <- ggplot(mtcars, aes(mpg, wt, colour = factor(cyl))) +
+#'   geom_point()
 #'
 #' mt + facet_grid(. ~ cyl, scales = "free")
 #' # If scales and space are free, then the mapping between position
@@ -100,28 +119,28 @@
 #' mt + facet_grid(vs ~ am, scales = "free")
 #' mt + facet_grid(vs ~ am, scales = "free_x")
 #' mt + facet_grid(vs ~ am, scales = "free_y")
-#' mt + facet_grid(vs ~ am, scales = "free", space="free")
-#' mt + facet_grid(vs ~ am, scales = "free", space="free_x")
-#' mt + facet_grid(vs ~ am, scales = "free", space="free_y")
+#' mt + facet_grid(vs ~ am, scales = "free", space = "free")
+#' mt + facet_grid(vs ~ am, scales = "free", space = "free_x")
+#' mt + facet_grid(vs ~ am, scales = "free", space = "free_y")
 #'
 #' # You may need to set your own breaks for consistent display:
-#' mt + facet_grid(. ~ cyl, scales = "free_x", space="free") +
+#' mt + facet_grid(. ~ cyl, scales = "free_x", space = "free") +
 #'   scale_x_continuous(breaks = seq(10, 36, by = 2))
 #' # Adding scale limits override free scales:
 #' last_plot() + xlim(10, 15)
 #'
 #' # Free scales are particularly useful for categorical variables
-#' qplot(cty, model, data=mpg) +
+#' ggplot(mpg, aes(cty, model)) +
+#'   geom_point() +
 #'   facet_grid(manufacturer ~ ., scales = "free", space = "free")
 #' # particularly when you reorder factor levels
-#' mpg <- within(mpg, {
-#'   model <- reorder(model, cty)
-#'   manufacturer <- reorder(manufacturer, cty)
-#' })
+#' mpg$model <- reorder(mpg$model, mpg$cty)
+#' manufacturer <- reorder(mpg$manufacturer, mpg$cty)
 #' last_plot() %+% mpg + theme(strip.text.y = element_text())
 #'
 #' # Use as.table to to control direction of horizontal facets, TRUE by default
-#' h <- ggplot(mtcars, aes(x = mpg, y = wt)) + geom_point()
+#' h <- ggplot(mtcars, aes(x = mpg, y = wt)) +
+#'   geom_point()
 #' h + facet_grid(cyl ~ vs)
 #' h + facet_grid(cyl ~ vs, as.table = FALSE)
 #'
@@ -129,11 +148,13 @@
 #' h + facet_grid(cyl ~ vs, labeller = label_both)
 #' # Using label_parsed, see ?plotmath for more options
 #' mtcars$cyl2 <- factor(mtcars$cyl, labels = c("alpha", "beta", "sqrt(x, y)"))
-#' k <- qplot(wt, mpg, data = mtcars)
+#' k <- ggplot(mtcars, aes(wt, mpg)) +
+#'   geom_point()
 #' k + facet_grid(. ~ cyl2)
 #' k + facet_grid(. ~ cyl2, labeller = label_parsed)
 #' # For label_bquote the label value is x.
-#' p <- qplot(wt, mpg, data = mtcars)
+#' p <- ggplot(mtcars, aes(wt, mpg)) +
+#'   geom_point()
 #' p + facet_grid(. ~ vs, labeller = label_bquote(alpha ^ .(x)))
 #' p + facet_grid(. ~ vs, labeller = label_bquote(.(x) ^ .(x)))
 #'
@@ -149,8 +170,23 @@
 #' mg + facet_grid(vs + am ~ gear, margins = "vs")
 #' mg + facet_grid(vs + am ~ gear, margins = "gear")
 #' mg + facet_grid(vs + am ~ gear, margins = c("gear", "am"))
+#'
+#' # The facet strips can be displayed near the axes with switch
+#' data <- transform(mtcars,
+#'   am = factor(am, levels = 0:1, c("Automatic", "Manual")),
+#'   gear = factor(gear, levels = 3:5, labels = c("Three", "Four", "Five"))
+#' )
+#' p <- ggplot(data, aes(mpg, disp)) + geom_point()
+#' p + facet_grid(am ~ gear, switch = "both") + theme_light()
+#'
+#' # It may be more aesthetic to use a theme without boxes around
+#' # around the strips.
+#' p + facet_grid(am ~ gear + vs, switch = "y") + theme_minimal()
+#' p + facet_grid(am ~ ., switch = "y") +
+#'   theme_gray() %+replace% theme(strip.background  = element_blank())
 #' }
-facet_grid <- function(facets, margins = FALSE, scales = "fixed", space = "fixed", shrink = TRUE, labeller = "label_value", as.table = TRUE, drop = TRUE) {
+#' @importFrom plyr as.quoted
+facet_grid <- function(facets, margins = FALSE, scales = "fixed", space = "fixed", shrink = TRUE, labeller = "label_value", as.table = TRUE, switch = NULL, drop = TRUE) {
   scales <- match.arg(scales, c("fixed", "free_x", "free_y", "free"))
   free <- list(
     x = any(scales %in% c("free_x", "free")),
@@ -166,11 +202,11 @@ facet_grid <- function(facets, margins = FALSE, scales = "fixed", space = "fixed
   # Facets can either be a formula, a string, or a list of things to be
   # convert to quoted
   if (is.character(facets)) {
-    facets <- as.formula(facets)
+    facets <- stats::as.formula(facets)
   }
   if (is.formula(facets)) {
-    lhs <- function(x) if(length(x) == 2) NULL else x[-3]
-    rhs <- function(x) if(length(x) == 2) x else x[-2]
+    lhs <- function(x) if (length(x) == 2) NULL else x[-3]
+    rhs <- function(x) if (length(x) == 2) x else x[-2]
 
     rows <- as.quoted(lhs(facets))
     rows <- rows[!sapply(rows, identical, as.name("."))]
@@ -185,10 +221,13 @@ facet_grid <- function(facets, margins = FALSE, scales = "fixed", space = "fixed
     stop("Must specify at least one variable to facet by", call. = FALSE)
   }
 
+  # Check for deprecated labellers
+  labeller <- check_labeller(labeller)
+
   facet(
     rows = rows, cols = cols, margins = margins, shrink = shrink,
-    free = free, space_free = space_free,
-    labeller = labeller, as.table = as.table, drop = drop,
+    free = free, space_free = space_free, labeller = labeller,
+    as.table = as.table, switch = switch, drop = drop,
     subclass = "grid"
   )
 }
@@ -226,17 +265,85 @@ facet_render.grid <- function(facet, panel, coord, theme, geom_grobs) {
   strips$r$heights <- panels$heights
   strips$t$widths <- panels$widths
 
+  # Check if switch is consistent with grid layout
+  switch_x <- !is.null(facet$switch) && facet$switch %in% c("both", "x")
+  switch_y <- !is.null(facet$switch) && facet$switch %in% c("both", "y")
+  if (switch_x && length(strips$t) == 0) {
+    facet$switch <- if (facet$switch == "both") "y" else NULL
+    switch_x <- FALSE
+    warning("Cannot switch x axis strips as they do not exist", call. = FALSE)
+  }
+  if (switch_y && length(strips$r) == 0) {
+    facet$switch <- if (facet$switch == "both") "x" else NULL
+    switch_y <- FALSE
+    warning("Cannot switch y axis strips as they do not exist", call. = FALSE)
+  }
+
+
   # Combine components into complete plot
-  top <- strips$t
-  top <- gtable_add_cols(top, strips$r$widths)
-  top <- gtable_add_cols(top, axes$l$widths, pos = 0)
+  if (is.null(facet$switch)) {
+    top <- strips$t
+    top <- gtable_add_cols(top, strips$r$widths)
+    top <- gtable_add_cols(top, axes$l$widths, pos = 0)
 
-  center <- cbind(axes$l, panels, strips$r, z = c(2, 1, 3))
-  bottom <- axes$b
-  bottom <- gtable_add_cols(bottom, strips$r$widths)
-  bottom <- gtable_add_cols(bottom, axes$l$widths, pos = 0)
+    center <- cbind(axes$l, panels, strips$r, z = c(2, 1, 3))
+    bottom <- axes$b
+    bottom <- gtable_add_cols(bottom, strips$r$widths)
+    bottom <- gtable_add_cols(bottom, axes$l$widths, pos = 0)
+
+    complete <- rbind(top, center, bottom, z = c(1, 2, 3))
+
+  } else {
+    # Add padding between the switched strips and the axes
+    padding <- convertUnit(theme$strip.switch.pad.grid, "cm")
+
+    if (switch_x) {
+      t_heights <- c(padding, strips$t$heights)
+      gt_t <- gtable(widths = strips$t$widths, heights = unit(t_heights, "cm"))
+      gt_t <- gtable_add_grob(gt_t, strips$t, name = strips$t$name, clip = "off",
+        t = 1, l = 1, b = -1, r = -1)
+    }
+    if (switch_y) {
+      r_widths <- c(strips$r$widths, padding)
+      gt_r <- gtable(widths = unit(r_widths, "cm"), heights = strips$r$heights)
+      gt_r <- gtable_add_grob(gt_r, strips$r, name = strips$r$name, clip = "off",
+        t = 1, l = 1, b = -1, r = -1)
+    }
+
+    # Combine plot elements according to strip positions
+    if (switch_x && switch_y) {
+      center <- cbind(gt_r, axes$l, panels, z = c(3, 2, 1))
+
+      bottom <- rbind(axes$b, gt_t)
+      bottom <- gtable_add_cols(bottom, axes$l$widths, pos = 0)
+      bottom <- gtable_add_cols(bottom, gt_r$widths, pos = 0)
+
+      complete <- rbind(center, bottom, z = c(1, 2))
+    } else if (switch_x) {
+      center <- cbind(axes$l, panels, strips$r, z = c(2, 1, 3))
+
+      bottom <- rbind(axes$b, gt_t)
+      bottom <- gtable_add_cols(bottom, strips$r$widths)
+      bottom <- gtable_add_cols(bottom, axes$l$widths, pos = 0)
+
+      complete <- rbind(center, bottom, z = c(1, 2))
+    } else if (switch_y) {
+      top <- strips$t
+      top <- gtable_add_cols(top, axes$l$widths, pos = 0)
+      top <- gtable_add_cols(top, gt_r$widths, pos = 0)
+
+      center <- cbind(gt_r, axes$l, panels, z = c(3, 2, 1))
+      bottom <- axes$b
+      bottom <- gtable_add_cols(bottom, axes$l$widths, pos = 0)
+      bottom <- gtable_add_cols(bottom, gt_r$widths, pos = 0)
+
+      complete <- rbind(top, center, bottom, z = c(1, 2, 3))
+    } else {
+      stop("`switch` must be either NULL, 'both', 'x', or 'y'",
+        call. = FALSE)
+    }
+  }
 
-  complete <- rbind(top, center, bottom, z = c(1, 2, 3))
   complete$respect <- panels$respect
   complete$name <- "layout"
   bottom <- axes$b
@@ -249,60 +356,34 @@ facet_strips.grid <- function(facet, panel, theme) {
   col_vars <- unique(panel$layout[names(facet$cols)])
   row_vars <- unique(panel$layout[names(facet$rows)])
 
-  list(
-    r = build_strip(panel, row_vars, facet$labeller, theme, "r"),
-    t = build_strip(panel, col_vars, facet$labeller, theme, "t")
-  )
-}
+  # Adding labels metadata, useful for labellers
+  attr(col_vars, "type") <- "cols"
+  attr(col_vars, "facet") <- "grid"
+  attr(row_vars, "type") <- "rows"
+  attr(row_vars, "facet") <- "grid"
 
-build_strip <- function(panel, label_df, labeller, theme, side = "right") {
-  side <- match.arg(side, c("top", "left", "bottom", "right"))
-  horizontal <- side %in% c("top", "bottom")
-  labeller <- match.fun(labeller)
-
-  # No labelling data, so return empty row/col
-  if (empty(label_df)) {
-    if (horizontal) {
-      widths <- unit(rep(0, max(panel$layout$COL)), "null")
-      return(gtable_row_spacer(widths))
-    } else {
-      heights <- unit(rep(0, max(panel$layout$ROW)), "null")
-      return(gtable_col_spacer(heights))
-    }
+  dir <- list(r = "r", t = "t")
+  if (!is.null(facet$switch) && facet$switch %in% c("both", "x")) {
+    dir$t <- "b"
   }
-
-  # Create matrix of labels
-  labels <- matrix(list(), nrow = nrow(label_df), ncol = ncol(label_df))
-  for (i in seq_len(ncol(label_df))) {
-    labels[, i] <- labeller(names(label_df)[i], label_df[, i])
+  if (!is.null(facet$switch) && facet$switch %in% c("both", "y")) {
+    dir$r <- "l"
   }
 
-  # Render as grobs
-  grobs <- apply(labels, c(1,2), ggstrip, theme = theme,
-    horizontal = horizontal)
-
-  # Create layout
-  name <- paste("strip", side, sep = "-")
-  if (horizontal) {
-    grobs <- t(grobs)
-
-    # Each row is as high as the highest and as a wide as the panel
-    row_height <- function(row) max(laply(row, height_cm))
-    heights <- unit(apply(grobs, 1, row_height), "cm")
-    widths <- unit(rep(1, ncol(grobs)), "null")
-  } else {
-    # Each row is wide as the widest and as high as the panel
-    col_width <- function(col) max(laply(col, width_cm))
-    widths <- unit(apply(grobs, 2, col_width), "cm")
-    heights <- unit(rep(1, nrow(grobs)), "null")
-  }
-  strips <- gtable_matrix(name, grobs, heights = heights, widths = widths)
+  strips <- list(
+    r = build_strip(panel, row_vars, facet$labeller,
+      theme, dir$r, switch = facet$switch),
+    t = build_strip(panel, col_vars, facet$labeller,
+      theme, dir$t, switch = facet$switch)
+  )
 
-  if (horizontal) {
-    gtable_add_col_space(strips, theme$panel.margin.x %||% theme$panel.margin)
-  } else {
-    gtable_add_row_space(strips, theme$panel.margin.y %||% theme$panel.margin)
-  }
+  Map(function(strip, side) {
+    if (side %in% c("t", "b")) {
+      gtable_add_col_space(strip, theme$panel.margin.x %||% theme$panel.margin)
+    } else {
+      gtable_add_row_space(strip, theme$panel.margin.y %||% theme$panel.margin)
+    }
+  }, strips, dir)
 }
 
 #' @export
@@ -311,15 +392,13 @@ facet_axes.grid <- function(facet, panel, coord, theme) {
 
   # Horizontal axes
   cols <- which(panel$layout$ROW == 1)
-  grobs <- lapply(panel$ranges[cols], coord_render_axis_h,
-    coord = coord, theme = theme)
+  grobs <- lapply(panel$ranges[cols], coord$render_axis_h, theme = theme)
   axes$b <- gtable_add_col_space(gtable_row("axis-b", grobs),
     theme$panel.margin.x %||% theme$panel.margin)
 
   # Vertical axes
   rows <- which(panel$layout$COL == 1)
-  grobs <- lapply(panel$ranges[rows], coord_render_axis_v,
-    coord = coord, theme = theme)
+  grobs <- lapply(panel$ranges[rows], coord$render_axis_v, theme = theme)
   axes$l <- gtable_add_row_space(gtable_col("axis-l", grobs),
     theme$panel.margin.y %||% theme$panel.margin)
 
@@ -333,7 +412,7 @@ facet_panels.grid <- function(facet, panel, coord, theme, geom_grobs) {
   # ask the coordinate system if it wants to specify one
   aspect_ratio <- theme$aspect.ratio
   if (is.null(aspect_ratio) && !facet$free$x && !facet$free$y) {
-    aspect_ratio <- coord_aspect(coord, panel$ranges[[1]])
+    aspect_ratio <- coord$aspect(panel$ranges[[1]])
   }
   if (is.null(aspect_ratio)) {
     aspect_ratio <- 1
@@ -348,11 +427,16 @@ facet_panels.grid <- function(facet, panel, coord, theme, geom_grobs) {
   nrow <- max(panel$layout$ROW)
 
   panel_grobs <- lapply(panels, function(i) {
-    fg <- coord_render_fg(coord, panel$range[[i]], theme)
-    bg <- coord_render_bg(coord, panel$range[[i]], theme)
+    fg <- coord$render_fg(panel$ranges[[i]], theme)
+    bg <- coord$render_bg(panel$ranges[[i]], theme)
+
+    geom_grobs <- lapply(geom_grobs, `[[`, i)
 
-    geom_grobs <- lapply(geom_grobs, "[[", i)
-    panel_grobs <- c(list(bg), geom_grobs, list(fg))
+    if (theme$panel.ontop) {
+      panel_grobs <- c(geom_grobs, list(bg), list(fg))
+    } else {
+      panel_grobs <- c(list(bg), geom_grobs, list(fg))
+    }
 
     gTree(children = do.call("gList", panel_grobs))
   })
@@ -367,14 +451,14 @@ facet_panels.grid <- function(facet, panel, coord, theme, geom_grobs) {
   # In general, panel has all information for building facet.
   if (facet$space_free$x) {
     ps <- panel$layout$PANEL[panel$layout$ROW == 1]
-    widths <- vapply(ps, function(i) diff(panel$range[[i]]$x.range), numeric(1))
+    widths <- vapply(ps, function(i) diff(panel$ranges[[i]]$x.range), numeric(1))
     panel_widths <- unit(widths, "null")
   } else {
     panel_widths <- rep(unit(1, "null"), ncol)
   }
   if (facet$space_free$y) {
     ps <- panel$layout$PANEL[panel$layout$COL == 1]
-    heights <- vapply(ps, function(i) diff(panel$range[[i]]$y.range), numeric(1))
+    heights <- vapply(ps, function(i) diff(panel$ranges[[i]]$y.range), numeric(1))
     panel_heights <- unit(heights, "null")
   } else {
     panel_heights <- rep(unit(1 * aspect_ratio, "null"), nrow)
diff --git a/R/facet-labels.r b/R/facet-labels.r
index 190247a..b75e812 100644
--- a/R/facet-labels.r
+++ b/R/facet-labels.r
@@ -1,196 +1,575 @@
-#' Label facets with their value.
-#' This is the default labelling scheme.
+#' Labeller functions
 #'
-#' @param variable variable name passed in by facetter
-#' @param value variable value passed in by facetter
-#' @family facet labellers
-#' @export
+#' Labeller functions are in charge of formatting the strip labels of
+#' facet grids and wraps. Most of them accept a \code{multi_line}
+#' argument to control whether multiple factors (defined in formulae
+#' such as \code{~first + second}) should be displayed on a single
+#' line separated with commas, or each on their own line.
+#'
+#' \code{label_value()} only displays the value of a factor while
+#' \code{label_both()} displays both the variable name and the factor
+#' value. \code{label_context()} is context-dependent and uses
+#' \code{label_value()} for single factor facetting and
+#' \code{label_both()} when multiple factors are
+#' involved. \code{label_wrap_gen()} uses \code{\link[base]{strwrap}()}
+#' for line wrapping.
+#'
+#' \code{label_parsed()} interprets the labels as plotmath
+#' expressions. \code{\link{label_bquote}()} offers a more flexible
+#' way of constructing plotmath expressions. See examples and
+#' \code{\link{bquote}()} for details on the syntax of the
+#' argument.
+#'
+#' @section Writing New Labeller Functions:
+#'
+#'   Note that an easy way to write a labeller function is to
+#'   transform a function operating on character vectors with
+#'   \code{\link{as_labeller}()}.
+#'
+#'   A labeller function accepts a data frame of labels (character
+#'   vectors) containing one column for each factor. Multiple factors
+#'   occur with formula of the type \code{~first + second}.
+#'
+#'   The return value must be a rectangular list where each 'row'
+#'   characterises a single facet. The list elements can be either
+#'   character vectors or lists of plotmath expressions. When multiple
+#'   elements are returned, they get displayed on their own new lines
+#'   (i.e., each facet gets a multi-line strip of labels).
+#'
+#'   To illustrate, let's say your labeller returns a list of two
+#'   character vectors of length 3. This is a rectangular list because
+#'   all elements have the same length. The first facet will get the
+#'   first elements of each vector and display each of them on their
+#'   own line. Then the second facet gets the second elements of each
+#'   vector, and so on.
+#'
+#'   If it's useful to your labeller, you can retrieve the \code{type}
+#'   attribute of the incoming data frame of labels. The value of this
+#'   attribute reflects the kind of strips your labeller is dealing
+#'   with: \code{"cols"} for columns and \code{"rows"} for rows. Note
+#'   that \code{\link{facet_wrap}()} has columns by default and rows
+#'   when the strips are switched with the \code{switch} option. The
+#'   \code{facet} attribute also provides metadata on the labels. It
+#'   takes the values \code{"grid"} or \code{"wrap"}.
+#'
+#'   For compatibility with \code{\link{labeller}()}, each labeller
+#'   function must have the \code{labeller} S3 class.
+#'
+#' @param labels Data frame of labels. Usually contains only one
+#'   element, but facetting over multiple factors entails multiple
+#'   label variables.
+#' @param multi_line Whether to display the labels of multiple factors
+#'   on separate lines.
+#' @param sep String separating variables and values.
+#' @param width Maximum number of characters before wrapping the strip.
+#' @family facet
+#' @seealso \code{\link{labeller}()}, \code{\link{as_labeller}()},
+#'   \code{\link{label_bquote}()}
+#' @name labellers
 #' @examples
-#' p <- qplot(wt, mpg, data = mtcars)
+#' mtcars$cyl2 <- factor(mtcars$cyl, labels = c("alpha", "beta", "gamma"))
+#' p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
+#'
+#' # Displaying only the values
 #' p + facet_grid(. ~ cyl)
 #' p + facet_grid(. ~ cyl, labeller = label_value)
-label_value <- function(variable, value) as.character(value)
-
-#' Label facets with value and variable.
 #'
-#' @param variable variable name passed in by facetter
-#' @param value variable value passed in by facetter
-#' @family facet labellers
-#' @export
-#' @examples
-#' p <- qplot(wt, mpg, data = mtcars)
-#' p + facet_grid(. ~ cyl)
+#' \donttest{
+#' # Displaying both the values and the variables
 #' p + facet_grid(. ~ cyl, labeller = label_both)
-label_both <- function(variable, value) paste(variable, value, sep = ": ")
-
-#' Label facets with parsed label.
 #'
-#' @seealso \code{\link{plotmath}}
-#' @param variable variable name passed in by facetter
-#' @param value variable value passed in by facetter
-#' @family facet labellers
+#' # Displaying only the values or both the values and variables
+#' # depending on whether multiple factors are facetted over
+#' p + facet_grid(am ~ vs+cyl, labeller = label_context)
+#'
+#' # Interpreting the labels as plotmath expressions
+#' p + facet_grid(. ~ cyl2)
+#' p + facet_grid(. ~ cyl2, labeller = label_parsed)
+#' p + facet_wrap(~vs + cyl2, labeller = label_parsed)
+#' }
+NULL
+
+collapse_labels_lines <- function(labels) {
+  out <- do.call("Map", c(list(paste, sep = ", "), labels))
+  list(unname(unlist(out)))
+}
+
+#' @rdname labellers
 #' @export
-#' @examples
-#' mtcars$cyl2 <- factor(mtcars$cyl, labels = c("alpha", "beta", "gamma"))
-#' qplot(wt, mpg, data = mtcars) + facet_grid(. ~ cyl2)
-#' qplot(wt, mpg, data = mtcars) + facet_grid(. ~ cyl2,
-#'   labeller = label_parsed)
-label_parsed <- function(variable, value) {
-  llply(as.character(value), function(x) parse(text = x))
+label_value <- function(labels, multi_line = TRUE) {
+  labels <- lapply(labels, as.character)
+  if (multi_line) {
+    labels
+  } else {
+    collapse_labels_lines(labels)
+  }
 }
+# Should ideally not have the 'function' class here, but this is
+# currently needed for Roxygen
+class(label_value) <- c("function", "labeller")
 
-#' Label facet with 'bquoted' expressions
-#'
-#' See \code{\link{bquote}} for details on the syntax of the argument.  The
-#' label value is x.
+# Helper for label_both
+label_variable <- function(labels, multi_line = TRUE) {
+  if (multi_line) {
+    row <- as.list(names(labels))
+  } else {
+    row <- list(paste(names(labels), collapse = ", "))
+  }
+  lapply(row, rep, nrow(labels) %||% length(labels[[1]]))
+}
+
+#' @rdname labellers
+#' @export
+label_both <- function(labels, multi_line = TRUE, sep = ": ") {
+  value <- label_value(labels, multi_line = multi_line)
+  variable <- label_variable(labels, multi_line = multi_line)
+
+  if (multi_line) {
+    out <- vector("list", length(value))
+    for (i in seq_along(out)) {
+      out[[i]] <- paste(variable[[i]], value[[i]], sep = sep)
+    }
+  } else {
+    value <- do.call("paste", c(value, sep = ", "))
+    variable <- do.call("paste", c(variable, sep = ", "))
+    out <- Map(paste, variable, value, sep = sep)
+    out <- list(unname(unlist(out)))
+  }
+
+  out
+}
+class(label_both) <- c("function", "labeller")
+
+#' @rdname labellers
+#' @export
+label_context <- function(labels, multi_line = TRUE, sep = ": ") {
+  if (length(labels) == 1) {
+    label_value(labels, multi_line)
+  } else {
+    label_both(labels, multi_line)
+  }
+}
+class(label_context) <- c("function", "labeller")
+
+#' @rdname labellers
+#' @export
+label_parsed <- function(labels, multi_line = TRUE) {
+  labels <- label_value(labels, multi_line = multi_line)
+  if (multi_line) {
+    # Using unname() and c() to return a cleaner and easily testable
+    # object structure
+    lapply(unname(labels), lapply, function(values) {
+      c(parse(text = as.character(values)))
+    })
+  } else {
+    lapply(labels, function(values) {
+      values <- paste0("list(", values, ")")
+      lapply(values, function(expr) c(parse(text = expr)))
+    })
+  }
+}
+class(label_parsed) <- c("function", "labeller")
+
+find_names <- function(expr) {
+  if (is.call(expr)) {
+    unlist(lapply(expr[-1], find_names))
+  } else if (is.name(expr)) {
+    as.character(expr)
+  }
+}
+
+#' Backquoted labeller
 #'
-#' @param expr labelling expression to use
-#' @family facet labellers
-#' @seealso \code{\link{plotmath}}
+#' \code{\link{label_bquote}()} offers a flexible way of labelling
+#' facet rows or columns with plotmath expressions. Backquoted
+#' variables will be replaced with their value in the facet.
+#' @param rows Backquoted labelling expression for rows.
+#' @param cols Backquoted labelling expression for columns.
+#' @param default Default labeller function for the rows or the
+#'   columns when no plotmath expression is provided.
+#' @seealso \link{labellers}, \code{\link{labeller}()},
 #' @export
 #' @examples
-#' p <- qplot(wt, mpg, data = mtcars)
-#' p + facet_grid(. ~ vs, labeller = label_bquote(alpha ^ .(x)))
-#' p + facet_grid(. ~ vs, labeller = label_bquote(.(x) ^ .(x)))
-label_bquote <- function(expr = beta ^ .(x)) {
-  quoted <- substitute(expr)
+#' # The variables mentioned in the plotmath expression must be
+#' # backquoted and referred to by their names.
+#' p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
+#' p + facet_grid(vs ~ ., labeller = label_bquote(alpha ^ .(vs)))
+#' p + facet_grid(. ~ vs, labeller = label_bquote(cols = .(vs) ^ .(vs)))
+#' p + facet_grid(. ~ vs + am, labeller = label_bquote(cols = .(am) ^ .(vs)))
+label_bquote <- function(rows = NULL, cols = NULL,
+                         default = label_value) {
+  cols_quoted <- substitute(cols)
+  rows_quoted <- substitute(rows)
+  has_warned <- FALSE
+
+  fun <- function(labels) {
+    quoted <- resolve_labeller(rows_quoted, cols_quoted, labels)
+    if (is.null(quoted)) {
+      return(label_value(labels))
+    }
 
-  function(variable, value) {
-    value <- as.character(value)
-    lapply(value, function(x)
-      eval(substitute(bquote(expr, list(x = x)), list(expr = quoted))))
+    evaluate <- function(...) {
+      params <- list(...)
+
+      # Mapping `x` to the first variable for backward-compatibility,
+      # but only if there is no facetted variable also named `x`
+      if ("x" %in% find_names(quoted) && !"x" %in% names(params)) {
+        if (!has_warned) {
+          warning("Referring to `x` is deprecated, use variable name instead",
+            call. = FALSE)
+          # The function is called for each facet so this avoids
+          # multiple warnings
+          has_warned <<- TRUE
+        }
+        params$x <- params[[1]]
+      }
+
+      eval(substitute(bquote(expr, params), list(expr = quoted)))
+    }
+    list(do.call("Map", c(list(f = evaluate), labels)))
   }
+
+  structure(fun, class = "labeller")
 }
-globalVariables("x")
+globalVariables(c("x", "."))
 
+#' @rdname labellers
+#' @export
+label_wrap_gen <- function(width = 25, multi_line = TRUE) {
+  fun <- function(labels) {
+    labels <- label_value(labels, multi_line = multi_line)
+    lapply(labels, function(x) {
+      x <- strwrap(x, width = width, simplify = FALSE)
+      vapply(x, paste, character(1), collapse = "\n")
+    })
+  }
+  structure(fun, class = "labeller")
+}
+
+is_labeller <- function(x) inherits(x, "labeller")
 
-#' Label facets with a word wrapped label.
+resolve_labeller <- function(rows, cols, labels) {
+  if (is.null(cols) && is.null(rows)) {
+    stop("Supply one of rows or cols", call. = FALSE)
+  }
+  if (attr(labels, "facet") == "wrap") {
+    # Return either rows or cols for facet_wrap()
+    if (!is.null(cols) && !is.null(rows)) {
+      stop("Cannot supply both rows and cols to facet_wrap()", call. = FALSE)
+    }
+    cols %||% rows
+  } else {
+    if (attr(labels, "type") == "rows") {
+      rows
+    } else {
+      cols
+    }
+  }
+}
+
+#' Coerce to labeller function
 #'
-#' Uses \code{\link[base]{strwrap}} for line wrapping.
-#' @param width integer, target column width for output.
+#' This transforms objects to labeller functions. Used internally by
+#' \code{\link{labeller}()}.
+#' @param x Object to coerce to a labeller function. If a named
+#'   character vector, it is used as a lookup table before being
+#'   passed on to \code{default}. If a non-labeller function, it is
+#'   assumed it takes and returns character vectors and is applied to
+#'   the labels. If a labeller, it is simply applied to the labels.
+#' @param multi_line Whether to display the labels of multiple factors
+#'   on separate lines. This is passed to the labeller function.
+#' @param default Default labeller to process the labels produced by
+#'   lookup tables or modified by non-labeller functions.
+#' @seealso \code{\link{labeller}()}, \link{labellers}
 #' @export
-#' @seealso , \code{\link{labeller}}
-label_wrap_gen <- function(width = 25) {
-  function(variable, values) {
-    vapply(strwrap(as.character(values), width = width, simplify = FALSE),
-           paste, vector('character', 1), collapse = "\n")
+#' @examples
+#' p <- ggplot(mtcars, aes(disp, drat)) + geom_point()
+#' p + facet_wrap(~am)
+#'
+#' # Rename labels on the fly with a lookup character vector
+#' to_string <- as_labeller(c(`0` = "Zero", `1` = "One"))
+#' p + facet_wrap(~am, labeller = to_string)
+#'
+#' # Quickly transform a function operating on character vectors to a
+#' # labeller function:
+#' appender <- function(string, suffix = "-foo") paste0(string, suffix)
+#' p + facet_wrap(~am, labeller = as_labeller(appender))
+#'
+#' # If you have more than one facetting variable, be sure to dispatch
+#' # your labeller to the right variable with labeller()
+#' p + facet_grid(cyl ~ am, labeller = labeller(am = to_string))
+as_labeller <- function(x, default = label_value, multi_line = TRUE) {
+  force(x)
+  fun <- function(labels) {
+    labels <- lapply(labels, as.character)
+
+    # Dispatch multi_line argument to the labeller function instead of
+    # supplying it to the labeller call because some labellers do not
+    # support it.
+    default <- dispatch_args(default, multi_line = multi_line)
+
+    if (is_labeller(x)) {
+      x <- dispatch_args(x, multi_line = multi_line)
+      x(labels)
+    } else if (is.function(x)) {
+      default(lapply(labels, x))
+    } else if (is.character(x)) {
+      default(lapply(labels, function(label) x[label]))
+    } else {
+      default(labels)
+    }
   }
+  structure(fun, class = "labeller")
 }
 
 #' Generic labeller function for facets
 #'
-#' One-step function for providing methods or named character vectors
-#' for displaying labels in facets.
-#'
-#' The provided methods are checked for number of arguments.
-#' If the provided method takes less than two
-#' (e.g. \code{\link[Hmisc]{capitalize}}),
-#' the method is passed \code{values}.
-#' Else (e.g. \code{\link{label_both}}),
-#' it is passed \code{variable} and \code{values} (in that order).
-#' If you want to be certain, use e.g. an anonymous function.
-#' If errors are returned such as ``argument ".." is missing, with no default''
-#' or ``unused argument (variable)'', matching the method's arguments does not
-#' work as expected; make a wrapper function.
-#'
-#'
-#' @param ... Named arguments of the form \code{variable=values},
-#'   where \code{values} could be a vector or method.
-#' @param keep.as.numeric logical, default TRUE. When FALSE, converts numeric
-#'   values supplied as margins to the facet to characters.
+#' This function makes it easy to assign different labellers to
+#' different factors. The labeller can be a function or it can be a
+#' named character vectors that will serve as a lookup table.
+#'
+#' In case of functions, if the labeller has class \code{labeller}, it
+#' is directly applied on the data frame of labels. Otherwise, it is
+#' applied to the columns of the data frame of labels. The data frame
+#' is then processed with the function specified in the
+#' \code{.default} argument. This is intended to be used with
+#' functions taking a character vector such as
+#' \code{\link[Hmisc]{capitalize}}.
+#'
+#' @param ... Named arguments of the form \code{variable =
+#'   labeller}. Each labeller is passed to \code{\link{as_labeller}()}
+#'   and can be a lookup table, a function taking and returning
+#'   character vectors, or simply a labeller function.
+#' @param .rows,.cols Labeller for a whole margin (either the rows or
+#'   the columns). It is passed to \code{\link{as_labeller}()}. When a
+#'   margin-wide labeller is set, make sure you don't mention in
+#'   \code{...} any variable belonging to the margin.
+#' @param keep.as.numeric Deprecated. All supplied labellers and
+#'   on-labeller functions should be able to work with character
+#'   labels.
+#' @param .multi_line Whether to display the labels of multiple
+#'   factors on separate lines. This is passed to the labeller
+#'   function.
+#' @param .default Default labeller for variables not specified. Also
+#'   used with lookup tables or non-labeller functions.
 #' @family facet labeller
-#' @return Function to supply to
-#'   \code{\link{facet_grid}} for the argument \code{labeller}.
+#' @seealso \code{\link{as_labeller}()}, \link{labellers}
+#' @return A labeller function to supply to \code{\link{facet_grid}}
+#'   for the argument \code{labeller}.
 #' @export
 #' @examples
 #' \donttest{
-#' p1 <- ggplot(mpg, aes(cty, hwy)) + geom_point()
-#' p1 + facet_grid(cyl ~ class, labeller=label_both)
-#' p1 + facet_grid(cyl ~ class, labeller=labeller(cyl=label_both))
+#' p1 <- ggplot(mtcars, aes(x = mpg, y = wt)) + geom_point()
 #'
-#' ggplot(mtcars, aes(x = mpg, y = wt)) + geom_point() +
-#'   facet_grid(vs + am ~ gear, margins=TRUE,
-#'              labeller=labeller(vs=label_both, am=label_both))
+#' # You can assign different labellers to variables:
+#' p1 + facet_grid(vs + am ~ gear,
+#'   labeller = labeller(vs = label_both, am = label_value))
 #'
+#' # Or whole margins:
+#' p1 + facet_grid(vs + am ~ gear,
+#'   labeller = labeller(.rows = label_both, .cols = label_value))
+#'
+#' # You can supply functions operating on strings:
 #' capitalize <- function(string) {
 #'   substr(string, 1, 1) <- toupper(substr(string, 1, 1))
 #'   string
 #' }
-#' conservation_status <- c('cd'='Conservation Dependent',
-#'                          'en'='Endangered',
-#'                          'lc'='Least concern',
-#'                          'nt'='Near Threatened',
-#'                          'vu'='Vulnerable',
-#'                          'domesticated'='Domesticated')
-#' ## Source: http://en.wikipedia.org/wiki/Wikipedia:Conservation_status
-#'
-#' p2 <- ggplot(msleep, aes(x=sleep_total, y=awake)) + geom_point()
+#' p2 <- ggplot(msleep, aes(x = sleep_total, y = awake)) + geom_point()
 #' p2 + facet_grid(vore ~ conservation, labeller = labeller(vore = capitalize))
 #'
-#' p2 + facet_grid(vore ~ conservation,
-#'   labeller=labeller(vore = capitalize, conservation = conservation_status ))
+#' # Or use character vectors as lookup tables:
+#' conservation_status <- c(
+#'   cd = "Conservation Dependent",
+#'   en = "Endangered",
+#'   lc = "Least concern",
+#'   nt = "Near Threatened",
+#'   vu = "Vulnerable",
+#'   domesticated = "Domesticated"
+#' )
+#' ## Source: http://en.wikipedia.org/wiki/Wikipedia:Conservation_status
 #'
-#' # We could of course have renamed the levels;
-#' # then we can apply another nifty function
-#' msleep$conservation2 <- plyr::revalue(msleep$conservation, conservation_status)
+#' p2 + facet_grid(vore ~ conservation, labeller = labeller(
+#'   .default = capitalize,
+#'   conservation = conservation_status
+#' ))
 #'
+#' # In the following example, we rename the levels to the long form,
+#' # then apply a wrap labeller to the columns to prevent cropped text
+#' msleep$conservation2 <- plyr::revalue(msleep$conservation,
+#'   conservation_status)
+#'
+#' p2 %+% msleep + facet_grid(vore ~ conservation2)
 #' p2 %+% msleep +
-#'   facet_grid(vore ~ conservation2, labeller = labeller(vore = capitalize))
-#' p2 %+% msleep +
-#'  facet_grid(vore ~ conservation2, labeller = labeller(conservation2 =
-#'  label_wrap_gen(10)))
+#'   facet_grid(vore ~ conservation2,
+#'     labeller = labeller(conservation2 = label_wrap_gen(10))
+#'   )
+#'
+#' # labeller() is especially useful to act as a global labeller. You
+#' # can set it up once and use it on a range of different plots with
+#' # different facet specifications.
+#'
+#' global_labeller <- labeller(
+#'   vore = capitalize,
+#'   conservation = conservation_status,
+#'   conservation2 = label_wrap_gen(10),
+#'   .default = label_both
+#' )
+#'
+#' p2 + facet_grid(vore ~ conservation, labeller = global_labeller)
+#' p2 + facet_wrap(~vore, labeller = global_labeller)
+#' p2 %+% msleep + facet_wrap(~conservation2, labeller = global_labeller)
 #' }
-labeller <- function(..., keep.as.numeric=FALSE) {
-  args <- list(...)
-
-  function(variable, values) {
-    if (is.logical(values)) {
-      values <- as.integer(values) + 1
-    } else if (is.factor(values)) {
-      values <- as.character(values)
-    } else if (is.numeric(values) & !keep.as.numeric) {
-      values <- as.character(values)
+labeller <- function(..., .rows = NULL, .cols = NULL,
+                     keep.as.numeric = NULL, .multi_line = TRUE,
+                     .default = label_value) {
+  if (!is.null(keep.as.numeric)) {
+    .Deprecated(old = "keep.as.numeric")
+  }
+  dots <- list(...)
+  .default <- as_labeller(.default)
+
+  function(labels) {
+    if (!is.null(.rows) || !is.null(.cols)) {
+      margin_labeller <- resolve_labeller(.rows, .cols, labels)
+    } else {
+      margin_labeller <- NULL
     }
 
-    res <- args[[variable]]
+    if (is.null(margin_labeller)) {
+      labellers <- lapply(dots, as_labeller)
+    } else {
+      margin_labeller <- as_labeller(margin_labeller, default = .default,
+        multi_line = .multi_line)
 
-    if (is.null(res)) {
-      # If the facetting margin (i.e. `variable`) was not specified when calling
-      # labeller, default to use the actual values.
-      result <- values
+      # Check that variable-specific labellers do not overlap with
+      # margin-wide labeller
+      if (any(names(dots) %in% names(labels))) {
+        stop("Conflict between .", attr(labels, "type"), " and ",
+          paste(names(dots), collapse = ", "), call. = FALSE)
+      }
+    }
 
-    } else if (is.function(res)) {
-      # How should `variable` and `values` be passed to a function? ------------
-      arguments <- length(formals(res))
-      if (arguments < 2) {
-        result <- res(values)
+    # Apply relevant labeller
+    if (is.null(margin_labeller)) {
+      # Apply named labeller one by one
+      out <- lapply(names(labels), function(label) {
+        if (label %in% names(labellers)) {
+          labellers[[label]](labels[label])[[1]]
+        } else {
+          .default(labels[label])[[1]]
+        }
+      })
+      names(out) <- names(labels)
+      if (.multi_line) {
+        out
       } else {
-        result <- res(variable, values)
+        collapse_labels_lines(out)
       }
+    } else {
+      margin_labeller(labels)
+    }
+  }
+}
+
+
+build_strip <- function(panel, label_df, labeller, theme, side = "right", switch = NULL) {
+  side <- match.arg(side, c("top", "left", "bottom", "right"))
+  horizontal <- side %in% c("top", "bottom")
+  labeller <- match.fun(labeller)
 
+  # No labelling data, so return empty row/col
+  if (empty(label_df)) {
+    if (horizontal) {
+      widths <- unit(rep(0, max(panel$layout$COL)), "null")
+      return(gtable_row_spacer(widths))
     } else {
-      result <- res[values]
+      heights <- unit(rep(0, max(panel$layout$ROW)), "null")
+      return(gtable_col_spacer(heights))
     }
+  }
+
+  # Create matrix of labels
+  labels <- lapply(labeller(label_df), cbind)
+  labels <- do.call("cbind", labels)
 
-    return(result)
+  # Display the mirror of the y strip labels if switched
+  if (!is.null(switch) && switch %in% c("both", "y")) {
+    theme$strip.text.y$angle <- adjust_angle(theme$strip.text.y$angle)
   }
-}
 
+  # Render as grobs
+  grobs <- apply(labels, c(1, 2), ggstrip, theme = theme,
+    horizontal = horizontal)
 
+  # Create layout
+  name <- paste("strip", side, sep = "-")
+  if (horizontal) {
+    # Each row is as high as the highest and as a wide as the panel
+    row_height <- function(row) max(plyr::laply(row, height_cm))
+    grobs <- t(grobs)
+    heights <- unit(apply(grobs, 1, row_height), "cm")
+    widths <- unit(rep(1, ncol(grobs)), "null")
+  } else {
+    # Each row is wide as the widest and as high as the panel
+    col_width <- function(col) max(plyr::laply(col, width_cm))
+    widths <- unit(apply(grobs, 2, col_width), "cm")
+    heights <- unit(rep(1, nrow(grobs)), "null")
+  }
+  gtable_matrix(name, grobs, heights = heights, widths = widths)
+}
 
 # Grob for strip labels
-ggstrip <- function(text, horizontal=TRUE, theme) {
+ggstrip <- function(text, horizontal = TRUE, theme) {
   text_theme <- if (horizontal) "strip.text.x" else "strip.text.y"
   if (is.list(text)) text <- text[[1]]
 
-  label <- element_render(theme, text_theme, text)
+  element <- calc_element(text_theme, theme)
+  if (inherits(element, "element_blank"))
+    return(zeroGrob())
+
+  gp <- gpar(fontsize = element$size, col = element$colour,
+    fontfamily = element$family, fontface = element$face,
+    lineheight = element$lineheight)
+
+  label <- stripGrob(text, element$hjust, element$vjust, element$angle,
+    margin = element$margin, gp = gp, debug = element$debug)
 
   ggname("strip", absoluteGrob(
     gList(
       element_render(theme, "strip.background"),
       label
     ),
-    width = grobWidth(label) + unit(0.5, "lines"),
-    height = grobHeight(label) + unit(0.5, "lines")
+    width = grobWidth(label),
+    height = grobHeight(label)
   ))
+
+}
+
+# Helper to adjust angle of switched strips
+adjust_angle <- function(angle) {
+  if (is.null(angle)) {
+    -90
+  } else if ((angle + 180) > 360) {
+    angle - 180
+  } else {
+    angle + 180
+  }
+}
+
+# Check for old school labeller
+check_labeller <- function(labeller) {
+  labeller <- match.fun(labeller)
+  is_deprecated <- all(c("variable", "value") %in% names(formals(labeller)))
+
+  if (is_deprecated) {
+    old_labeller <- labeller
+    labeller <- function(labels) {
+      Map(old_labeller, names(labels), labels)
+    }
+    warning("The labeller API has been updated. Labellers taking `variable`",
+      "and `value` arguments are now deprecated. See labellers documentation.",
+      call. = FALSE)
+  }
+
+  labeller
 }
diff --git a/R/facet-layout.r b/R/facet-layout.r
index 0f551de..ef312b4 100644
--- a/R/facet-layout.r
+++ b/R/facet-layout.r
@@ -6,7 +6,8 @@
 # @return a data frame with columns \code{PANEL}, \code{ROW} and \code{COL},
 #   that match the facetting variable values up with their position in the
 #   grid
-layout_grid <- function(data, rows = NULL, cols = NULL, margins = NULL, drop = TRUE, as.table = TRUE) {
+layout_grid <- function(data, rows = NULL, cols = NULL, margins = NULL,
+                       drop = TRUE, as.table = TRUE) {
   if (length(rows) == 0 && length(cols) == 0) return(layout_null())
   rows <- as.quoted(rows)
   cols <- as.quoted(cols)
@@ -20,18 +21,19 @@ layout_grid <- function(data, rows = NULL, cols = NULL, margins = NULL, drop = T
   base <- df.grid(base_rows, base_cols)
 
   # Add margins
-  base <- add_margins(base, list(names(rows), names(cols)), margins)
+  base <- reshape2::add_margins(base, list(names(rows), names(cols)), margins)
   # Work around bug in reshape2
   base <- unique(base)
 
   # Create panel info dataset
-  panel <- id(base, drop = TRUE)
+  panel <- plyr::id(base, drop = TRUE)
   panel <- factor(panel, levels = seq_len(attr(panel, "n")))
 
-  rows <- if (is.null(names(rows))) 1L else id(base[names(rows)], drop = TRUE)
-  cols <- if (is.null(names(cols))) 1L else id(base[names(cols)], drop = TRUE)
+  rows <- if (is.null(names(rows))) 1L else plyr::id(base[names(rows)], drop = TRUE)
+  cols <- if (is.null(names(cols))) 1L else plyr::id(base[names(cols)], drop = TRUE)
 
-  panels <- data.frame(PANEL = panel, ROW = rows, COL = cols, base)
+  panels <- data.frame(PANEL = panel, ROW = rows, COL = cols, base,
+    check.names = FALSE, stringsAsFactors = FALSE)
   panels <- panels[order(panels$PANEL), , drop = FALSE]
   rownames(panels) <- NULL
   panels
@@ -41,13 +43,14 @@ layout_grid <- function(data, rows = NULL, cols = NULL, margins = NULL, drop = T
 #
 # @params drop should missing combinations be excluded from the plot?
 # @keywords internal
-layout_wrap <- function(data, vars = NULL, nrow = NULL, ncol = NULL, as.table = TRUE, drop = TRUE) {
+layout_wrap <- function(data, vars = NULL, nrow = NULL, ncol = NULL,
+                        as.table = TRUE, drop = TRUE, dir = "h") {
   vars <- as.quoted(vars)
   if (length(vars) == 0) return(layout_null())
 
-  base <- unrowname(layout_base(data, vars, drop = drop))
+  base <- plyr::unrowname(layout_base(data, vars, drop = drop))
 
-  id <- id(base, drop = TRUE)
+  id <- plyr::id(base, drop = TRUE)
   n <- attr(id, "n")
 
   dims <- wrap_dims(n, nrow, ncol)
@@ -60,13 +63,18 @@ layout_wrap <- function(data, vars = NULL, nrow = NULL, ncol = NULL, as.table =
   }
   layout$COL <- as.integer((id - 1L) %% dims[2] + 1L)
 
-  panels <- cbind(layout, unrowname(base))
+  # For vertical direction, flip row and col
+  if (identical(dir, "v")) {
+    layout[c("ROW", "COL")] <- layout[c("COL", "ROW")]
+  }
+
+  panels <- cbind(layout, plyr::unrowname(base))
   panels <- panels[order(panels$PANEL), , drop = FALSE]
   rownames(panels) <- NULL
   panels
 }
 
-layout_null <- function(data) {
+layout_null <- function() {
    data.frame(PANEL = 1, ROW = 1, COL = 1)
 }
 
@@ -81,16 +89,16 @@ layout_base <- function(data, vars = NULL, drop = TRUE) {
   if (length(vars) == 0) return(data.frame())
 
   # For each layer, compute the facet values
-  values <- compact(llply(data, quoted_df, vars = vars))
+  values <- compact(plyr::llply(data, quoted_df, vars = vars))
 
   # Form the base data frame which contains all combinations of facetting
   # variables that appear in the data
-  has_all <- unlist(llply(values, length)) == length(vars)
+  has_all <- unlist(plyr::llply(values, length)) == length(vars)
   if (!any(has_all)) {
     stop("At least one layer must contain all variables used for facetting")
   }
 
-  base <- unique(ldply(values[has_all]))
+  base <- unique(plyr::ldply(values[has_all]))
   if (!drop) {
     base <- unique_combs(base)
   }
@@ -104,12 +112,11 @@ layout_base <- function(data, vars = NULL, drop = TRUE) {
     if (drop) {
       new <- unique_combs(new)
     }
-
     base <- rbind(base, df.grid(old, new))
   }
 
-  if (is.null(base)) {
-    stop("Faceting variables must have at least one value")
+  if (empty(base)) {
+    stop("Faceting variables must have at least one value", call. = FALSE)
   }
 
   base
@@ -127,7 +134,7 @@ ulevels <- function(x) {
 unique_combs <- function(df) {
   if (length(df) == 0) return()
 
-  unique_values <- llply(df, ulevels)
+  unique_values <- plyr::llply(df, ulevels)
   rev(expand.grid(rev(unique_values), stringsAsFactors = FALSE,
     KEEP.OUT.ATTRS = TRUE))
 }
@@ -140,15 +147,15 @@ df.grid <- function(a, b) {
     i_a = seq_len(nrow(a)),
     i_b = seq_len(nrow(b))
   )
-  unrowname(cbind(
+  plyr::unrowname(cbind(
     a[indexes$i_a, , drop = FALSE],
     b[indexes$i_b, , drop = FALSE]
   ))
 }
 
 quoted_df <- function(data, vars) {
-  values <- eval.quoted(vars, data, emptyenv(), try = TRUE)
-  as.data.frame(compact(values))
+  values <- plyr::eval.quoted(vars, data, emptyenv(), try = TRUE)
+  as.data.frame(compact(values), optional = TRUE, stringsAsFactors = FALSE)
 }
 
 # Arrange 1d structure into a grid
diff --git a/R/facet-locate.r b/R/facet-locate.r
index 6255bc1..57483e4 100644
--- a/R/facet-locate.r
+++ b/R/facet-locate.r
@@ -1,3 +1,7 @@
+# A "special" value, currently not used but could be used to determine
+# if faceting is active
+NO_PANEL <- -1L
+
 # Take single layer of data and combine it with panel information to split
 # data into different panels. Adds in extra data for missing facetting
 # levels and for margins.
@@ -15,7 +19,7 @@ locate_grid <- function(data, panels, rows = NULL, cols = NULL, margins = FALSE)
   # Compute facetting values and add margins
   margin_vars <- list(intersect(names(rows), names(data)),
     intersect(names(cols), names(data)))
-  data <- add_margins(data, margin_vars, margins)
+  data <- reshape2::add_margins(data, margin_vars, margins)
 
   facet_vals <- quoted_df(data, c(rows, cols))
 
@@ -28,8 +32,8 @@ locate_grid <- function(data, panels, rows = NULL, cols = NULL, margins = FALSE)
     data_rep <- rep.int(1:nrow(data), nrow(to_add))
     facet_rep <- rep(1:nrow(to_add), each = nrow(data))
 
-    data <- unrowname(data[data_rep, , drop = FALSE])
-    facet_vals <- unrowname(cbind(
+    data <- plyr::unrowname(data[data_rep, , drop = FALSE])
+    facet_vals <- plyr::unrowname(cbind(
       facet_vals[data_rep, ,  drop = FALSE],
       to_add[facet_rep, , drop = FALSE]))
   }
@@ -37,12 +41,12 @@ locate_grid <- function(data, panels, rows = NULL, cols = NULL, margins = FALSE)
   # Add PANEL variable
   if (nrow(facet_vals) == 0) {
     # Special case of no facetting
-    data$PANEL <- 1
+    data$PANEL <- NO_PANEL
   } else {
     facet_vals[] <- lapply(facet_vals[], as.factor)
     facet_vals[] <- lapply(facet_vals[], addNA, ifany = TRUE)
 
-    keys <- join.keys(facet_vals, panels, by = vars)
+    keys <- plyr::join.keys(facet_vals, panels, by = vars)
 
     data$PANEL <- panels$PANEL[match(keys$x, keys$y)]
   }
@@ -67,13 +71,13 @@ locate_wrap <- function(data, panels, vars) {
     data_rep <- rep.int(1:nrow(data), nrow(to_add))
     facet_rep <- rep(1:nrow(to_add), each = nrow(data))
 
-    data <- unrowname(data[data_rep, , drop = FALSE])
-    facet_vals <- unrowname(cbind(
+    data <- plyr::unrowname(data[data_rep, , drop = FALSE])
+    facet_vals <- plyr::unrowname(cbind(
       facet_vals[data_rep, ,  drop = FALSE],
       to_add[facet_rep, , drop = FALSE]))
   }
 
-  keys <- join.keys(facet_vals, panels, by = names(vars))
+  keys <- plyr::join.keys(facet_vals, panels, by = names(vars))
 
   data$PANEL <- panels$PANEL[match(keys$x, keys$y)]
   data[order(data$PANEL), ]
diff --git a/R/facet-null.r b/R/facet-null.r
index 0b310a8..a320537 100644
--- a/R/facet-null.r
+++ b/R/facet-null.r
@@ -6,7 +6,6 @@
 #' # facet_null is the default facetting specification if you
 #' # don't override it with facet_grid or facet_wrap
 #' ggplot(mtcars, aes(mpg, wt)) + geom_point()
-#' qplot(mpg, wt, data = mtcars)
 facet_null <- function(shrink = TRUE) {
   facet(shrink = shrink, subclass = "null")
 }
@@ -21,7 +20,7 @@ facet_train_layout.null <- function(facet, data) {
 #' @export
 facet_map_layout.null <- function(facet, data, layout) {
   # Need the is.waive check for special case where no data, but aesthetics
-  # are mapped to vectors, like qplot(1:5, 1:5)
+  # are mapped to vectors
   if (is.waive(data) || empty(data))
     return(cbind(data, PANEL = integer(0)))
   data$PANEL <- 1L
@@ -33,7 +32,7 @@ facet_render.null <- function(facet, panel, coord, theme, geom_grobs) {
   range <- panel$ranges[[1]]
 
   # Figure out aspect ratio
-  aspect_ratio <- theme$aspect.ratio %||% coord_aspect(coord, range)
+  aspect_ratio <- theme$aspect.ratio %||% coord$aspect(range)
   if (is.null(aspect_ratio)) {
     aspect_ratio <- 1
     respect <- FALSE
@@ -41,16 +40,21 @@ facet_render.null <- function(facet, panel, coord, theme, geom_grobs) {
     respect <- TRUE
   }
 
-  fg <- coord_render_fg(coord, range, theme)
-  bg <- coord_render_bg(coord, range, theme)
+  fg <- coord$render_fg(range, theme)
+  bg <- coord$render_bg(range, theme)
 
   # Flatten layers - we know there's only one panel
   geom_grobs <- lapply(geom_grobs, "[[", 1)
-  panel_grobs <- c(list(bg), geom_grobs, list(fg))
+
+  if (theme$panel.ontop) {
+    panel_grobs <- c(geom_grobs, list(bg), list(fg))
+  } else {
+    panel_grobs <- c(list(bg), geom_grobs, list(fg))
+  }
 
   panel_grob <- gTree(children = do.call("gList", panel_grobs))
-  axis_h <- coord_render_axis_h(coord, range, theme)
-  axis_v <- coord_render_axis_v(coord, range, theme)
+  axis_h <- coord$render_axis_h(range, theme)
+  axis_v <- coord$render_axis_v(range, theme)
 
   all <- matrix(list(
     axis_v,     panel_grob,
diff --git a/R/facet-viewports.r b/R/facet-viewports.r
index 70e97ae..6f41bf5 100644
--- a/R/facet-viewports.r
+++ b/R/facet-viewports.r
@@ -15,8 +15,8 @@ assign_viewports <- function(grobs) {
     ggname(type, editGrob(grobs[[type]][[x, y]], vp = vp_path(x, y, type)))
   }
 
-  grid <- ldply(names(grobs), make_grid)
-  mlply(grid, assign_vp)
+  grid <- plyr::ldply(names(grobs), make_grid)
+  plyr::mlply(grid, assign_vp)
 }
 
 # Setup matrix of viewports for a layout with given parameters
@@ -30,11 +30,11 @@ setup_viewports <- function(type, data, offset = c(0,0), clip = "on") {
       name = vp_name(x, y, type),
       layout.pos.row = x + offset[1],
       layout.pos.col = y + offset[2],
-      clip=clip
+      clip = clip
     )
   }
-  pos <- expand.grid(x = seq_len(rows), y= seq_len(cols))
-  do.call("vpList", mlply(pos, vp))
+  pos <- expand.grid(x = seq_len(rows), y = seq_len(cols))
+  do.call("vpList", plyr::mlply(pos, vp))
 }
 
 # Calculate viewport path.
@@ -46,5 +46,5 @@ vp_path <- function(row, col, type) {
 # Compute viewport name.
 # Helps ensure a common naming scheme throughout ggplot.
 vp_name <- function(row, col, type) {
-  paste(type, row, col, sep="_")
+  paste(type, row, col, sep = "_")
 }
diff --git a/R/facet-wrap.r b/R/facet-wrap.r
index 9f1213c..ea65a14 100644
--- a/R/facet-wrap.r
+++ b/R/facet-wrap.r
@@ -1,68 +1,107 @@
 #' Wrap a 1d ribbon of panels into 2d.
 #'
-#' @param nrow number of rows
-#' @param ncol number of columns
-#' @param facets formula specifying variables to facet by
-#' @param scales should scales be fixed (\code{"fixed"}, the default),
-#'   free (\code{"free"}), or free in one dimension  (\code{"free_x"},
-#'   \code{"free_y"})
+#' Most displays are roughly rectangular, so if you have a categorical
+#' variable with many levels, it doesn't make sense to try and display them
+#' all in one row (or one column). To solve this dilemma, \code{facet_wrap}
+#' wraps a 1d sequence of panels into 2d, making best use of screen real estate.
+#'
+#' @param facets Either a formula or character vector. Use either a
+#'   one sided formula, \code{~a + b}, or a character vector, \code{c("a", "b")}.
+#' @param nrow,ncol Number of rows and columns.
+#' @param scales should Scales be fixed (\code{"fixed"}, the default),
+#'   free (\code{"free"}), or free in one dimension (\code{"free_x"},
+#'   \code{"free_y"}).
+#' @param switch By default, the labels are displayed on the top of
+#'   the plot. If \code{switch} is \code{"x"}, they will be displayed
+#'   to the bottom. If \code{"y"}, they will be displayed to the
+#'   left, near the y axis.
+#' @param dir Direction: either "h" for horizontal, the default, or "v", for
+#'   vertical.
 #' @inheritParams facet_grid
 #' @export
 #' @examples
-#' \donttest{
-#' d <- ggplot(diamonds, aes(carat, price, fill = ..density..)) +
-#'   xlim(0, 2) + stat_binhex(na.rm = TRUE) + theme(aspect.ratio = 1)
-#' d + facet_wrap(~ color)
-#' d + facet_wrap(~ color, ncol = 1)
-#' d + facet_wrap(~ color, ncol = 4)
-#' d + facet_wrap(~ color, nrow = 1)
-#' d + facet_wrap(~ color, nrow = 3)
+#' ggplot(mpg, aes(displ, hwy)) +
+#'   geom_point() +
+#'   facet_wrap(~class)
 #'
-#' # Using multiple variables continues to wrap the long ribbon of
-#' # plots into 2d - the ribbon just gets longer
-#' # d + facet_wrap(~ color + cut)
+#' # Control the number of rows and columns with nrow and ncol
+#' ggplot(mpg, aes(displ, hwy)) +
+#'   geom_point() +
+#'   facet_wrap(~class, nrow = 4)
+#'
+#' \donttest{
+#' # You can facet by multiple variables
+#' ggplot(mpg, aes(displ, hwy)) +
+#'   geom_point() +
+#'   facet_wrap(~ cyl + drv)
+#' # Or use a character vector:
+#' ggplot(mpg, aes(displ, hwy)) +
+#'   geom_point() +
+#'   facet_wrap(c("cyl", "drv"))
 #'
-#' # To change plot order of facet wrap,
-#' # change the order of varible levels with factor()
-#' diamonds$color <- factor(diamonds$color, levels = c("G", "J", "D", "E", "I", "F", "H"))
-#' # Repeat first example with new order
-#' d <- ggplot(diamonds, aes(carat, price, fill = ..density..)) +
-#' xlim(0, 2) + stat_binhex(na.rm = TRUE) + theme(aspect.ratio = 1)
-#' d + facet_wrap(~ color)
+#' # Use the `labeller` option to control how labels are printed:
+#' ggplot(mpg, aes(displ, hwy)) +
+#'   geom_point() +
+#'   facet_wrap(c("cyl", "drv"), labeller = "label_both")
 #'
-#' # You can choose to keep the scales constant across all panels
-#' # or vary the x scale, the y scale or both:
-#' p <- qplot(price, data = diamonds, geom = "histogram", binwidth = 1000)
-#' p + facet_wrap(~ color)
-#' p + facet_wrap(~ color, scales = "free_y")
+#' # To change the order in which the panels appear, change the levels
+#' # of the underlying factor.
+#' mpg$class2 <- reorder(mpg$class, mpg$displ)
+#' ggplot(mpg, aes(displ, hwy)) +
+#'   geom_point() +
+#'   facet_wrap(~class2)
 #'
-#' p <- qplot(displ, hwy, data = mpg)
-#' p + facet_wrap(~ cyl)
-#' p + facet_wrap(~ cyl, scales = "free")
+#' # By default, the same scales are used for all panels. You can allow
+#' # scales to vary across the panels with the `scales` argument.
+#' # Free scales make it easier to see patterns within each panel, but
+#' # harder to compare across panels.
+#' ggplot(mpg, aes(displ, hwy)) +
+#'   geom_point() +
+#'   facet_wrap(~class, scales = "free")
 #'
-#' # Use as.table to to control direction of horizontal facets, TRUE by default
-#' p + facet_wrap(~ cyl, as.table = FALSE)
+#' # To repeat the same data in every panel, simply construct a data frame
+#' # that does not contain the facetting variable.
+#' ggplot(mpg, aes(displ, hwy)) +
+#'   geom_point(data = transform(mpg, class = NULL), colour = "grey85") +
+#'   geom_point() +
+#'   facet_wrap(~class)
 #'
-#' # Add data that does not contain all levels of the faceting variables
-#' cyl6 <- subset(mpg, cyl == 6)
-#' p + geom_point(data = cyl6, colour = "red", size = 1) +
-#'   facet_wrap(~ cyl)
-#' p + geom_point(data = transform(cyl6, cyl = 7), colour = "red") +
-#'   facet_wrap(~ cyl)
-#' p + geom_point(data = transform(cyl6, cyl = NULL), colour = "red") +
-#'   facet_wrap(~ cyl)
+#' # Use `switch` to display the facet labels near an axis, acting as
+#' # a subtitle for this axis. This is typically used with free scales
+#' # and a theme without boxes around strip labels.
+#' ggplot(economics_long, aes(date, value)) +
+#'   geom_line() +
+#'   facet_wrap(~variable, scales = "free_y", nrow = 2, switch = "x") +
+#'   theme(strip.background = element_blank())
 #' }
-facet_wrap <- function(facets, nrow = NULL, ncol = NULL, scales = "fixed", shrink = TRUE, as.table = TRUE, drop = TRUE) {
+facet_wrap <- function(facets, nrow = NULL, ncol = NULL, scales = "fixed",
+                       shrink = TRUE, labeller = "label_value", as.table = TRUE,
+                       switch = NULL, drop = TRUE, dir = "h") {
   scales <- match.arg(scales, c("fixed", "free_x", "free_y", "free"))
+  dir <- match.arg(dir, c("h", "v"))
   free <- list(
     x = any(scales %in% c("free_x", "free")),
     y = any(scales %in% c("free_y", "free"))
   )
 
+  if (identical(dir, "v")) {
+    # swap
+    nrow <- sanitise_dim(ncol)
+    ncol <- sanitise_dim(nrow)
+  } else {
+    nrow <- sanitise_dim(nrow)
+    ncol <- sanitise_dim(ncol)
+  }
+
+  # Check for deprecated labellers
+  labeller <- check_labeller(labeller)
+
   facet(
     facets = as.quoted(facets), free = free, shrink = shrink,
-    as.table = as.table, drop = drop,
-    ncol = ncol, nrow = nrow,
+    as.table = as.table, switch = switch,
+    drop = drop, ncol = ncol, nrow = nrow,
+    labeller = labeller,
+    dir = dir,
     subclass = "wrap"
   )
 }
@@ -70,7 +109,7 @@ facet_wrap <- function(facets, nrow = NULL, ncol = NULL, scales = "fixed", shrin
 #' @export
 facet_train_layout.wrap <- function(facet, data) {
   panels <- layout_wrap(data, facet$facets, facet$nrow, facet$ncol,
-     facet$as.table, facet$drop)
+     facet$as.table, facet$drop, facet$dir)
 
   n <- nrow(panels)
   nrow <- max(panels$ROW)
@@ -103,7 +142,7 @@ facet_render.wrap <- function(facet, panel, coord, theme, geom_grobs) {
 
   # If coord is (non-cartesian or flip) and (x is free or y is free)
   # then print a warning
-  if ((!inherits(coord, "cartesian") || inherits(coord, "flip")) &&
+  if ((!inherits(coord, "CoordCartesian") || inherits(coord, "CoordFlip")) &&
     (facet$free$x || facet$free$y)) {
     stop("ggplot2 does not currently support free scales with a non-cartesian coord or coord_flip.\n")
   }
@@ -112,7 +151,7 @@ facet_render.wrap <- function(facet, panel, coord, theme, geom_grobs) {
   # ask the coordinate system if it wants to specify one
   aspect_ratio <- theme$aspect.ratio
   if (is.null(aspect_ratio) && !facet$free$x && !facet$free$y) {
-    aspect_ratio <- coord_aspect(coord, panel$ranges[[1]])
+    aspect_ratio <- coord$aspect(panel$ranges[[1]])
   }
 
   if (is.null(aspect_ratio)) {
@@ -127,10 +166,23 @@ facet_render.wrap <- function(facet, panel, coord, theme, geom_grobs) {
   nrow <- max(layout$ROW)
   n <- nrow(layout)
 
+  # Set switch to default value when misspecified
+  switch_to_x <- FALSE
+  switch_to_y <- FALSE
+  if (!is.null(facet$switch) && facet$switch == "x") {
+    switch_to_x <- TRUE
+  } else if (!is.null(facet$switch) && facet$switch == "y") {
+    switch_to_y <- TRUE
+  } else if (!is.null(facet$switch)) {
+    message("`switch` must be set to 'x', 'y' or NULL")
+    facet$switch <- NULL
+  }
+
   panels <- facet_panels(facet, panel, coord, theme, geom_grobs)
   axes <- facet_axes(facet, panel, coord, theme)
   strips <- facet_strips(facet, panel, theme)
 
+
   # Should become facet_arrange_grobs
 
   # Locate each element in panel
@@ -140,14 +192,37 @@ facet_render.wrap <- function(facet, panel, coord, theme, geom_grobs) {
     t <- size[2] * (layout$ROW - 1) + loc[2]
     data.frame(t = t, r = l, b = t, l = l, id = seq_len(n))
   }
-  locs <- list(
-    panel =   c(2, 2),
-    strip_t = c(2, 1),
-    axis_l =  c(1, 2),
-    axis_b =  c(2, 3),
-    hspace =  c(2, 4),
-    vspace =  c(3, 2)
-  )
+
+
+  if (switch_to_x) {
+    locs <- list(
+      panel =   c(2, 1),
+      strip_t = c(2, 3),
+      axis_l =  c(1, 1),
+      axis_b =  c(2, 2),
+      hspace =  c(2, 4),
+      vspace =  c(3, 1)
+    )
+  } else if (switch_to_y) {
+    locs <- list(
+      panel =   c(3, 1),
+      strip_t = c(1, 1),
+      axis_l =  c(2, 1),
+      axis_b =  c(3, 2),
+      hspace =  c(3, 3),
+      vspace =  c(4, 1)
+    )
+  } else {
+    locs <- list(
+      panel =   c(2, 2),
+      strip_t = c(2, 1),
+      axis_l =  c(1, 2),
+      axis_b =  c(2, 3),
+      hspace =  c(2, 4),
+      vspace =  c(3, 2)
+    )
+  }
+
   grobs <- list(
     panel = panels,
     strip_t = strips$t,
@@ -155,7 +230,54 @@ facet_render.wrap <- function(facet, panel, coord, theme, geom_grobs) {
     axis_b = axes$b
   )
 
-  info <- ldply(locs, find_pos, layout = layout, size = c(3, 4))
+  # If strips are switched, add padding
+  if (switch_to_x) {
+    padding <- convertUnit(theme$strip.switch.pad.wrap, "cm")
+
+    add_padding <- function(strip) {
+      gt_t <- gtable_row("strip_t", list(strip),
+        height = unit(height_cm(strip), "cm"))
+
+      # One padding above and two below, so that the strip does not look
+      # like a title for the panel just below.
+      gt_t <- gtable_add_rows(gt_t, padding, pos = 0)
+      gt_t <- gtable_add_rows(gt_t, 2 * padding, pos = 2)
+      gt_t
+    }
+    grobs$strip_t <- lapply(strips$t, add_padding)
+
+    strip_height <- lapply(strips$t, function(x) {
+       3 * as.numeric(padding) + height_cm(x)
+    })
+    strip_width <- NULL
+    size <- c(3, 4)
+
+  } else if (switch_to_y) {
+    padding <- convertUnit(theme$strip.switch.pad.wrap, "cm")
+
+    add_padding <- function(strip) {
+      gt_t <- gtable_col("strip_t", list(strip),
+        heights = unit(aspect_ratio, "null"))
+
+      gt_t <- gtable_add_cols(gt_t, padding, pos = 0)
+      gt_t <- gtable_add_cols(gt_t, padding, pos = 2)
+      gt_t
+    }
+    grobs$strip_t <- lapply(strips$t, add_padding)
+
+    strip_height <- NULL
+    strip_width <- lapply(strips$t, function(x) {
+      3 * as.numeric(padding) + width_cm(x)
+    })
+    size <- c(4, 3)
+
+  } else {
+    strip_height <- height_cm(grobs$strip_t)
+    strip_width <- NULL
+    size <- c(3, 4)
+  }
+
+  info <- plyr::ldply(locs, find_pos, layout = layout, size = size)
   names(info)[1] <- "type"
   info$clip <- ifelse(info$type == "panel", "on", "off")
   info$name <- paste(info$type, info$id, sep = "-")
@@ -164,15 +286,20 @@ facet_render.wrap <- function(facet, panel, coord, theme, geom_grobs) {
   # If not listed, assume is unit(1, "null")
   widths <- list(
     axis_l = width_cm(grobs$axis_l),
+    strip_t = strip_width,
     vspace = ifelse(layout$COL == ncol, 0, width_cm(theme$panel.margin.x %||% theme$panel.margin))
   )
   heights <- list(
     panel = unit(aspect_ratio, "null"),
-    strip_t = height_cm(grobs$strip_t),
+    strip_t = strip_height,
     axis_b = height_cm(grobs$axis_b),
     hspace = ifelse(layout$ROW == nrow, 0, height_cm(theme$panel.margin.y %||% theme$panel.margin))
   )
 
+  # Remove strip_t according to which strips are switched
+  heights <- Filter(Negate(is.null), heights)
+  widths <- Filter(Negate(is.null), widths)
+
   col_widths <- compute_grob_widths(info, widths)
   row_heights <- compute_grob_heights(info, heights)
 
@@ -182,6 +309,7 @@ facet_render.wrap <- function(facet, panel, coord, theme, geom_grobs) {
   # Keep only the rows in info that refer to grobs
   info  <- info[info$type %in% names(grobs), ]
   grobs <- unlist(grobs, recursive = FALSE)
+
   # Add the grobs
   gt <- gtable_add_grob(gt, grobs, l = info$l, t = info$t, r = info$r,
     b = info$b, name = info$name, clip = info$clip)
@@ -193,11 +321,16 @@ facet_render.wrap <- function(facet, panel, coord, theme, geom_grobs) {
 facet_panels.wrap <- function(facet, panel, coord, theme, geom_grobs) {
   panels <- panel$layout$PANEL
   lapply(panels, function(i) {
-    fg <- coord_render_fg(coord, panel$range[[i]], theme)
-    bg <- coord_render_bg(coord, panel$range[[i]], theme)
+    fg <- coord$render_fg(panel$ranges[[i]], theme)
+    bg <- coord$render_bg(panel$ranges[[i]], theme)
 
     geom_grobs <- lapply(geom_grobs, "[[", i)
-    panel_grobs <- c(list(bg), geom_grobs, list(fg))
+
+    if (theme$panel.ontop) {
+      panel_grobs <- c(geom_grobs, list(bg), list(fg))
+    } else {
+      panel_grobs <- c(list(bg), geom_grobs, list(fg))
+    }
 
     ggname(paste("panel", i, sep = "-"),
       gTree(children = do.call("gList", panel_grobs)))
@@ -207,13 +340,30 @@ facet_panels.wrap <- function(facet, panel, coord, theme, geom_grobs) {
 #' @export
 facet_strips.wrap <- function(facet, panel, theme) {
   labels_df <- panel$layout[names(facet$facets)]
-  labels_df[] <- llply(labels_df, format, justify = "none")
 
-  labels <- apply(labels_df, 1, paste, collapse=", ")
+  # Adding labels metadata, useful for labellers
+  attr(labels_df, "facet") <- "wrap"
+  if (!is.null(facet$switch) && facet$switch == "x") {
+    dir <- "b"
+    attr(labels_df, "type") <- "rows"
+  } else {
+    dir <- "t"
+    attr(labels_df, "type") <- "cols"
+  }
+
+  strips_table <- build_strip(panel, labels_df, facet$labeller,
+    theme, dir, switch = facet$switch)
 
-  list(t = llply(labels, ggstrip, theme = theme))
+  # While grid facetting works with a whole gtable, wrap processes the
+  # columns separately. So we turn the gtable into a list of columns
+  strips <- list(t = vector("list", ncol(strips_table)))
+  for (i in seq_along(strips$t)) {
+    strips$t[[i]] <- strips_table[, i]
+  }
+  strips
 }
 
+
 #' @export
 facet_axes.wrap <- function(facet, panel, coord, theme) {
   panels <- panel$layout$PANEL
@@ -221,7 +371,7 @@ facet_axes.wrap <- function(facet, panel, coord, theme) {
   axes <- list()
   axes$b <- lapply(panels, function(i) {
     if (panel$layout$AXIS_X[i]) {
-      grob <- coord_render_axis_h(coord, panel$range[[i]], theme)
+      grob <- coord$render_axis_h(panel$ranges[[i]], theme)
     } else {
       grob <- zeroGrob()
     }
@@ -230,7 +380,7 @@ facet_axes.wrap <- function(facet, panel, coord, theme) {
 
   axes$l <- lapply(panels, function(i) {
     if (panel$layout$AXIS_Y[i]) {
-      grob <- coord_render_axis_v(coord, panel$range[[i]], theme)
+      grob <- coord$render_axis_v(panel$ranges[[i]], theme)
     } else {
       grob <- zeroGrob()
     }
@@ -244,3 +394,59 @@ facet_axes.wrap <- function(facet, panel, coord, theme) {
 facet_vars.wrap <- function(facet) {
   paste(lapply(facet$facets, paste, collapse = ", "), collapse = " ~ ")
 }
+
+#' Sanitise the number of rows or columns
+#'
+#' Cleans up the input to be an integer greater than or equal to one, or
+#' \code{NULL}. Intended to be used on the \code{nrow} and \code{ncol}
+#' arguments of \code{facet_wrap}.
+#' @param n Hopefully an integer greater than or equal to one, or \code{NULL},
+#' though other inputs are handled.
+#' @return An integer greater than or equal to one, or \code{NULL}.
+#' @note If the length of the input is greater than one, only the first element
+#' is returned, with a warning.
+#' If the input is not an integer, it will be coerced to be one.
+#' If the value is less than one, \code{NULL} is returned, effectively ignoring
+#' the argument.
+#' Multiple warnings may be generated.
+#' @examples
+#' # Valid input just gets returns unchanged
+#' sanitise_dim(1)
+#' sanitise_dim(NULL)
+#' \dontrun{
+#' # Only the first element of vectors get returned
+#' sanitise_dim(10:1)
+#' # Non-integer values are coerced to integer
+#' sanitise_dim(pi)
+#' # Missing values, values less than one and non-numeric values are
+#' # treated as NULL
+#' sanitise_dim(NA_integer_)
+#' sanitise_dim(0)
+#' sanitise_dim("foo")
+#' }
+#' @noRd
+sanitise_dim <- function(n) {
+  xname <- paste0("`", deparse(substitute(n)), "`")
+  if (length(n) == 0) {
+    if (!is.null(n)) {
+      warning(xname, " has length zero and will be treated as NULL.",
+        call. = FALSE)
+    }
+    return(NULL)
+  }
+  if (length(n) > 1) {
+    warning("Only the first value of ", xname, " will be used.", call. = FALSE)
+    n <- n[1]
+  }
+  if (!is.numeric(n) || (!is.na(n) && n != round(n))) {
+    warning("Coercing ", xname, " to be an integer.", call. = FALSE)
+    n <- as.integer(n)
+  }
+  if (is.na(n) || n < 1) {
+    warning(xname, " is missing or less than 1 and will be treated as NULL.",
+      call. = FALSE)
+    return(NULL)
+  }
+  n
+}
+
diff --git a/R/fortify-lm.r b/R/fortify-lm.r
index 4d1ebca..574a834 100644
--- a/R/fortify-lm.r
+++ b/R/fortify-lm.r
@@ -3,7 +3,6 @@
 #' If you have missing values in your model data, you may need to refit
 #' the model with \code{na.action = na.exclude}.
 #'
-#'
 #' @return The original data with extra columns:
 #'   \item{.hat}{Diagonal of the hat matrix}
 #'   \item{.sigma}{Estimate of residual standard deviation when
@@ -17,40 +16,50 @@
 #' @param ... not used by this method
 #' @export
 #' @examples
-#'
 #' mod <- lm(mpg ~ wt, data = mtcars)
 #' head(fortify(mod))
 #' head(fortify(mod, mtcars))
 #'
 #' plot(mod, which = 1)
-#' qplot(.fitted, .resid, data = mod) +
+#'
+#' ggplot(mod, aes(.fitted, .resid)) +
+#'   geom_point() +
 #'   geom_hline(yintercept = 0) +
 #'   geom_smooth(se = FALSE)
-#' qplot(.fitted, .stdresid, data = mod) +
+#'
+#' ggplot(mod, aes(.fitted, .stdresid)) +
+#'   geom_point() +
 #'   geom_hline(yintercept = 0) +
 #'   geom_smooth(se = FALSE)
-#' qplot(.fitted, .stdresid, data = fortify(mod, mtcars),
-#'   colour = factor(cyl))
-#' qplot(mpg, .stdresid, data = fortify(mod, mtcars), colour = factor(cyl))
+#'
+#' ggplot(fortify(mod, mtcars), aes(.fitted, .stdresid)) +
+#'   geom_point(aes(colour = factor(cyl)))
+#'
+#' ggplot(fortify(mod, mtcars), aes(mpg, .stdresid)) +
+#'   geom_point(aes(colour = factor(cyl)))
 #'
 #' plot(mod, which = 2)
-#' # qplot(sample =.stdresid, data = mod, stat = "qq") + geom_abline()
+#' ggplot(mod) +
+#'   stat_qq(aes(sample = .stdresid)) +
+#'   geom_abline()
 #'
 #' plot(mod, which = 3)
-#' qplot(.fitted, sqrt(abs(.stdresid)), data = mod) + geom_smooth(se = FALSE)
+#' ggplot(mod, aes(.fitted, sqrt(abs(.stdresid)))) +
+#'   geom_point() +
+#'   geom_smooth(se = FALSE)
 #'
 #' plot(mod, which = 4)
-#' qplot(seq_along(.cooksd), .cooksd, data = mod, geom = "bar",
-#'  stat="identity")
+#' ggplot(mod, aes(seq_along(.cooksd), .cooksd)) +
+#'   geom_bar(stat = "identity")
 #'
 #' plot(mod, which = 5)
-#' qplot(.hat, .stdresid, data = mod) + geom_smooth(se = FALSE)
 #' ggplot(mod, aes(.hat, .stdresid)) +
 #'   geom_vline(size = 2, colour = "white", xintercept = 0) +
 #'   geom_hline(size = 2, colour = "white", yintercept = 0) +
 #'   geom_point() + geom_smooth(se = FALSE)
 #'
-#' qplot(.hat, .stdresid, data = mod, size = .cooksd) +
+#' ggplot(mod, aes(.hat, .stdresid)) +
+#'   geom_point(aes(size = .cooksd)) +
 #'   geom_smooth(se = FALSE, size = 0.5)
 #'
 #' plot(mod, which = 6)
@@ -59,16 +68,19 @@
 #'   geom_abline(slope = seq(0, 3, by = 0.5), colour = "white") +
 #'   geom_smooth(se = FALSE) +
 #'   geom_point()
-#' qplot(.hat, .cooksd, size = .cooksd / .hat, data = mod) + scale_size_area()
+#'
+#' ggplot(mod, aes(.hat, .cooksd)) +
+#'   geom_point(aes(size = .cooksd / .hat)) +
+#'   scale_size_area()
 fortify.lm <- function(model, data = model$model, ...) {
-  infl <- influence(model, do.coef = FALSE)
+  infl <- stats::influence(model, do.coef = FALSE)
   data$.hat <- infl$hat
   data$.sigma <- infl$sigma
-  data$.cooksd <- cooks.distance(model, infl)
+  data$.cooksd <- stats::cooks.distance(model, infl)
 
-  data$.fitted <- predict(model)
-  data$.resid <- resid(model)
-  data$.stdresid <- rstandard(model, infl)
+  data$.fitted <- stats::predict(model)
+  data$.resid <- stats::resid(model)
+  data$.stdresid <- stats::rstandard(model, infl)
 
   data
 }
diff --git a/R/fortify-map.r b/R/fortify-map.r
index aa9a0db..858bedd 100644
--- a/R/fortify-map.r
+++ b/R/fortify-map.r
@@ -12,12 +12,13 @@
 #' if (require("maps")) {
 #' ca <- map("county", "ca", plot = FALSE, fill = TRUE)
 #' head(fortify(ca))
-#' qplot(long, lat, data = ca, geom = "polygon", group = group)
+#' ggplot(ca, aes(long, lat)) +
+#'   geom_polygon(aes(group = group))
 #'
 #' tx <- map("county", "texas", plot = FALSE, fill = TRUE)
 #' head(fortify(tx))
-#' qplot(long, lat, data = tx, geom = "polygon", group = group,
-#'  colour = I("white"))
+#' ggplot(tx, aes(long, lat)) +
+#'   geom_polygon(aes(group = group), colour = "white")
 #' }
 fortify.map <- function(model, data, ...) {
   df <- as.data.frame(model[c("x", "y")])
@@ -28,7 +29,7 @@ fortify.map <- function(model, data, ...) {
   names <- do.call("rbind", lapply(strsplit(model$names, "[:,]"), "[", 1:2))
   df$region <- names[df$group, 1]
   df$subregion <- names[df$group, 2]
-  df[complete.cases(df$lat, df$long), ]
+  df[stats::complete.cases(df$lat, df$long), ]
 }
 
 #' Create a data frame of map data.
@@ -54,13 +55,16 @@ fortify.map <- function(model, data, ...) {
 #'
 #' choro <- merge(states, arrests, sort = FALSE, by = "region")
 #' choro <- choro[order(choro$order), ]
-#' qplot(long, lat, data = choro, group = group, fill = assault,
-#'   geom = "polygon")
-#' qplot(long, lat, data = choro, group = group, fill = assault / murder,
-#'   geom = "polygon")
+#' ggplot(choro, aes(long, lat)) +
+#'   geom_polygon(aes(group = group, fill = assault)) +
+#'   coord_map("albers",  at0 = 45.5, lat1 = 29.5)
+#'
+#' ggplot(choro, aes(long, lat)) +
+#'   geom_polygon(aes(group = group, fill = assault / murder)) +
+#'   coord_map("albers",  at0 = 45.5, lat1 = 29.5)
 #' }
 map_data <- function(map, region = ".", exact = FALSE, ...) {
-  try_require("maps")
+  try_require("maps", "map_data")
   fortify(map(map, region, exact = exact, plot = FALSE, fill = TRUE, ...))
 }
 
@@ -70,6 +74,8 @@ map_data <- function(map, region = ".", exact = FALSE, ...) {
 #' @param regions map region
 #' @param fill fill colour
 #' @param colour border colour
+#' @param xlim,ylim latitudinal and logitudinal range for extracting map
+#'   polygons, see \code{\link[maps]{map}} for details.
 #' @param ... other arguments passed onto \code{\link{geom_polygon}}
 #' @export
 #' @examples
@@ -77,8 +83,7 @@ map_data <- function(map, region = ".", exact = FALSE, ...) {
 #'
 #' ia <- map_data("county", "iowa")
 #' mid_range <- function(x) mean(range(x))
-#' library(plyr)
-#' seats <- ddply(ia, .(subregion), colwise(mid_range, .(lat, long)))
+#' seats <- plyr::ddply(ia, "subregion", plyr::colwise(mid_range, c("lat", "long")))
 #' ggplot(ia, aes(long, lat)) +
 #'   geom_polygon(aes(group = group), fill = NA, colour = "grey60") +
 #'   geom_text(aes(label = subregion), data = seats, size = 2, angle = 45)
@@ -88,11 +93,19 @@ map_data <- function(map, region = ".", exact = FALSE, ...) {
 #' ggplot(capitals, aes(long, lat)) +
 #'   borders("state") +
 #'   geom_point(aes(size = pop)) +
-#'   scale_size_area()
+#'   scale_size_area() +
+#'   coord_quickmap()
 #'
+#' # Same map, with some world context
+#' ggplot(capitals, aes(long, lat)) +
+#'   borders("world", xlim = c(-130, -60), ylim = c(20, 50)) +
+#'   geom_point(aes(size = pop)) +
+#'   scale_size_area() +
+#'   coord_quickmap()
 #' }
-borders <- function(database = "world", regions = ".", fill = NA, colour = "grey50", ...) {
-  df <- map_data(database, regions)
-  geom_polygon(aes_q(quote(long), quote(lat), group = quote(group)), data = df,
-    fill = fill, colour = colour, ...)
+borders <- function(database = "world", regions = ".", fill = NA,
+                    colour = "grey50", xlim = NULL, ylim = NULL, ...) {
+  df <- map_data(database, regions, xlim = xlim, ylim = ylim)
+  geom_polygon(aes_(~long, ~lat, group = ~group), data = df,
+    fill = fill, colour = colour, ..., inherit.aes = FALSE)
 }
diff --git a/R/fortify-multcomp.r b/R/fortify-multcomp.r
index 5a690ec..b1c19b5 100644
--- a/R/fortify-multcomp.r
+++ b/R/fortify-multcomp.r
@@ -32,10 +32,10 @@ NULL
 #' @rdname fortify-multcomp
 #' @export
 fortify.glht <- function(model, data, ...) {
-  unrowname(data.frame(
+  plyr::unrowname(data.frame(
     lhs = rownames(model$linfct),
     rhs = model$rhs,
-    estimate = coef(model),
+    estimate = stats::coef(model),
     check.names = FALSE,
     stringsAsFactors = FALSE))
 }
@@ -47,7 +47,7 @@ fortify.confint.glht <- function(model, data, ...) {
   coef <- model$confint
   colnames(coef) <- tolower(colnames(coef))
 
-  unrowname(data.frame(
+  plyr::unrowname(data.frame(
     lhs = rownames(coef),
     rhs = model$rhs,
     coef,
@@ -63,7 +63,7 @@ fortify.summary.glht <- function(model, data, ...) {
     model$test[c("coefficients", "sigma", "tstat", "pvalues")])
   names(coef) <- c("estimate", "se", "t", "p")
 
-  unrowname(data.frame(
+  plyr::unrowname(data.frame(
     lhs = rownames(coef),
     rhs = model$rhs,
     coef,
@@ -76,7 +76,7 @@ fortify.summary.glht <- function(model, data, ...) {
 #' @rdname fortify-multcomp
 #' @export
 fortify.cld <- function(model, data, ...) {
-  unrowname(data.frame(
+  plyr::unrowname(data.frame(
     lhs = names(model$mcletters$Letters),
     letters = model$mcletters$Letters,
     check.names = FALSE,
diff --git a/R/fortify-spatial.r b/R/fortify-spatial.r
index 4f83aad..3b63966 100644
--- a/R/fortify-spatial.r
+++ b/R/fortify-spatial.r
@@ -24,11 +24,10 @@ fortify.SpatialPolygonsDataFrame <- function(model, data, region = NULL, ...) {
   attr <- as.data.frame(model)
   # If not specified, split into regions based on polygons
   if (is.null(region)) {
-    coords <- ldply(model at polygons,fortify)
+    coords <- plyr::ldply(model at polygons,fortify)
     message("Regions defined for each Polygons")
   } else {
     cp <- sp::polygons(model)
-    try_require("maptools")
 
     # Union together all polygons that make up a region
     unioned <- maptools::unionSpatialPolygons(cp, attr[, region])
@@ -42,7 +41,7 @@ fortify.SpatialPolygonsDataFrame <- function(model, data, region = NULL, ...) {
 #' @export
 #' @method fortify SpatialPolygons
 fortify.SpatialPolygons <- function(model, data, ...) {
-  ldply(model at polygons, fortify)
+  plyr::ldply(model at polygons, fortify)
 }
 
 #' @rdname fortify.sp
@@ -50,18 +49,17 @@ fortify.SpatialPolygons <- function(model, data, ...) {
 #' @method fortify Polygons
 fortify.Polygons <- function(model, data, ...) {
   subpolys <- model at Polygons
-  pieces <- ldply(seq_along(subpolys), function(i) {
+  pieces <- plyr::ldply(seq_along(subpolys), function(i) {
     df <- fortify(subpolys[[model at plotOrder[i]]])
     df$piece <- i
     df
   })
 
-  within(pieces,{
-    order <- 1:nrow(pieces)
-    id <- model at ID
-    piece <- factor(piece)
-    group <- interaction(id, piece)
-  })
+  pieces$order <- 1:nrow(pieces)
+  pieces$id <- model at ID
+  pieces$piece <- factor(pieces$piece)
+  pieces$group <- interaction(pieces$id, pieces$piece)
+  pieces
 }
 
 #' @rdname fortify.sp
@@ -79,7 +77,7 @@ fortify.Polygon <- function(model, data, ...) {
 #' @export
 #' @method fortify SpatialLinesDataFrame
 fortify.SpatialLinesDataFrame <- function(model, data, ...) {
-  ldply(model at lines, fortify)
+  plyr::ldply(model at lines, fortify)
 }
 
 #' @rdname fortify.sp
@@ -87,18 +85,17 @@ fortify.SpatialLinesDataFrame <- function(model, data, ...) {
 #' @method fortify Lines
 fortify.Lines <- function(model, data, ...) {
   lines <- model at Lines
-  pieces <- ldply(seq_along(lines), function(i) {
+  pieces <- plyr::ldply(seq_along(lines), function(i) {
     df <- fortify(lines[[i]])
     df$piece <- i
     df
   })
 
-  within(pieces,{
-    order <- 1:nrow(pieces)
-    id <- model at ID
-    piece <- factor(piece)
-    group <- interaction(id, piece)
-  })
+  pieces$order <- 1:nrow(pieces)
+  pieces$id <- model at ID
+  pieces$piece <- factor(pieces$piece)
+  pieces$group <- interaction(pieces$id, pieces$piece)
+  pieces
 }
 
 #' @rdname fortify.sp
diff --git a/R/fortify.r b/R/fortify.r
index aefe91d..fa4356b 100644
--- a/R/fortify.r
+++ b/R/fortify.r
@@ -1,8 +1,8 @@
 #' Fortify a model with data.
 #'
-#' Method to convert a generic R object into a data frame useful for plotting.
-#' Takes its name from the idea of fortifying the original data with model fit
-#' statistics, and vice versa.
+#' Rather than using this function, I now recomend using the \pkg{broom}
+#' package, which implements a much wider range of methods. \code{fortify}
+#' may be deprecated in the future.
 #'
 #' @seealso \code{\link{fortify.lm}}
 #' @param model model or other R object to convert to data frame
diff --git a/R/geom-.r b/R/geom-.r
index ef8be8c..03fa679 100644
--- a/R/geom-.r
+++ b/R/geom-.r
@@ -1,48 +1,175 @@
-Geom <- proto(TopLevel, expr={
-  class <- function(.) "geom"
+#' @include legend-draw.r
+NULL
 
-  parameters <- function(.) {
-    params <- formals(get("draw", .))
-    params <- params[setdiff(names(params), c(".","data","scales", "coordinates", "..."))]
+#' @section Geoms:
+#'
+#' All \code{geom_*} functions (like \code{geom_point}) return a layer that
+#' contains a \code{Geom*} object (like \code{GeomPoint}). The \code{Geom*}
+#' object is responsible for rendering the data in the plot.
+#'
+#' Each of the \code{Geom*} objects is a \code{\link{ggproto}} object, descended
+#' from the top-level \code{Geom}, and each implements various methods and
+#' fields. To create a new type of Geom object, you typically will want to
+#' implement one or more of the following:
+#'
+#' Compared to \code{Stat} and \code{Position}, \code{Geom} is a little
+#' different because the execution of the setup and compute functions is
+#' split up. \code{setup_data} runs before position adjustments, and
+#' \code{draw_layer} is not run until render time,  much later. This
+#' means there is no \code{setup_params} because it's hard to communicate
+#' the changes.
+#'
+#' \itemize{
+#'   \item Override either \code{draw_panel(self, data, panel_scales, coord)} or
+#'     \code{draw_group(self, data, panel_scales, coord)}. \code{draw_panel} is
+#'     called once per panel, \code{draw_group} is called once per group.
+#'
+#'     Use \code{draw_panel} if each row in the data represents a
+#'     single element. Use \code{draw_group} if each group represents
+#'     an element (e.g. a smooth, a violin).
+#'
+#'     \code{data} is a data frame of scaled aesthetics. \code{panel_scales}
+#'     is a list containing information about the scales in the current
+#'     panel. \code{coord} is a coordinate specification. You'll
+#'     need to call \code{coord$transform(data, panel_scales)} to work
+#'     with non-Cartesian coords. To work with non-linear coordinate systems,
+#'     you typically need to convert into a primitive geom (e.g. point, path
+#'     or polygon), and then pass on to the corresponding draw method
+#'     for munching.
+#'
+#'     Must return a grob. Use \code{\link{zeroGrob}} if there's nothing to
+#'     draw.
+#'   \item \code{draw_key}: Renders a single legend key.
+#'   \item \code{required_aes}: A character vector of aesthetics needed to
+#'     render the geom.
+#'   \item \code{default_aes}: A list (generated by \code{\link{aes}()} of
+#'     default values for aesthetics.
+#'   \item \code{reparameterise}: Converts width and height to xmin and xmax,
+#'     and ymin and ymax values. It can potentially set other values as well.
+#' }
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+Geom <- ggproto("Geom",
+  required_aes = character(),
+  non_missing_aes = character(),
 
-    required <- rep(NA, length(.$required_aes))
-    names(required) <- .$required_aes
-    aesthetics <- c(.$default_aes(), required)
+  default_aes = aes(),
 
-    c(params, aesthetics[setdiff(names(aesthetics), names(params))])
-  }
+  draw_key = draw_key_point,
+
+  handle_na = function(self, data, params) {
+    remove_missing(data, params$na.rm,
+      c(self$required_aes, self$non_missing_aes),
+      snake_class(self)
+    )
+  },
 
-  required_aes <- c()
-  default_aes <- function(.) {}
-  default_pos <- function(.) PositionIdentity
+  draw_layer = function(self, data, params, panel, coord) {
+    if (empty(data)) return(list(zeroGrob()))
 
-  guide_geom <- function(.) "point"
+    # Trim off extra parameters
+    params <- params[intersect(names(params), self$parameters())]
 
-  draw <- function(...) {}
-  draw_groups <- function(., data, scales, coordinates, ...) {
-    if (empty(data)) return(zeroGrob())
+    args <- c(list(quote(data), quote(panel_scales), quote(coord)), params)
+    plyr::dlply(data, "PANEL", function(data) {
+      if (empty(data)) return(zeroGrob())
 
+      panel_scales <- panel$ranges[[data$PANEL[1]]]
+      do.call(self$draw_panel, args)
+    }, .drop = FALSE)
+  },
+
+  draw_panel = function(self, data, panel_scales, coord, ...) {
     groups <- split(data, factor(data$group))
-    grobs <- lapply(groups, function(group) .$draw(group, scales, coordinates, ...))
+    grobs <- lapply(groups, function(group) {
+      self$draw_group(group, panel_scales, coord, ...)
+    })
 
-    ggname(paste(.$objname, "s", sep=""), gTree(
+    ggname(snake_class(self), gTree(
       children = do.call("gList", grobs)
     ))
-  }
+  },
 
-  new <- function(., mapping=NULL, data=NULL, stat=NULL, position=NULL, ...){
-    do.call("layer", list(mapping=mapping, data=data, stat=stat, geom=., position=position, ...))
-  }
+  draw_group = function(self, data, panel_scales, coord) {
+    stop("Not implemented")
+  },
+
+  setup_data = function(data, params) data,
+
+  # Combine data with defaults and set aesthetics from parameters
+  use_defaults = function(self, data, params = list()) {
+    # Fill in missing aesthetics with their defaults
+    missing_aes <- setdiff(names(self$default_aes), names(data))
+    if (empty(data)) {
+      data <- plyr::quickdf(self$default_aes[missing_aes])
+    } else {
+      data[missing_aes] <- self$default_aes[missing_aes]
+    }
+
+    # Override mappings with params
+    aes_params <- intersect(self$aesthetics(), names(params))
+    check_aesthetics(params[aes_params], nrow(data))
+    data[aes_params] <- params[aes_params]
+    data
+  },
 
-  pprint <- function(., newline=TRUE) {
-    cat("geom_", .$objname, ": ", sep="") #  , clist(.$parameters())
-    if (newline) cat("\n")
+  # Most parameters for the geom are taken automatically from draw_panel() or
+  # draw_groups(). However, some additional parameters may be needed
+  # for setup_data() or handle_na(). These can not be imputed automatically,
+  # so the slightly hacky "extra_params" field is used instead. By
+  # default it contains `na.rm`
+  extra_params = c("na.rm"),
+
+  parameters = function(self, extra = FALSE) {
+    # Look first in draw_panel. If it contains ... then look in draw groups
+    panel_args <- names(ggproto_formals(self$draw_panel))
+    group_args <- names(ggproto_formals(self$draw_group))
+    args <- if ("..." %in% panel_args) group_args else panel_args
+
+    # Remove arguments of defaults
+    args <- setdiff(args, names(ggproto_formals(Geom$draw_group)))
+
+    if (extra) {
+      args <- union(args, self$extra_params)
+    }
+    args
+  },
+
+  aesthetics = function(self) {
+    c(union(self$required_aes, names(self$default_aes)), "group")
   }
 
-  reparameterise <- function(., data, params) data
+)
 
-  # Html documentation ----------------------------------
 
+#' Graphical units
+#'
+#' Multiply size in mm by these constants in order to convert to the units
+#' that grid uses internally for \code{lwd} and \code{fontsize}.
+#'
+#' @name graphical-units
+NULL
 
+#' @export
+#' @rdname graphical-units
+.pt <- 72.27 / 25.4
+#' @export
+#' @rdname graphical-units
+.stroke <- 96 / 25.4
+
+check_aesthetics <- function(x, n) {
+  ns <- vapply(x, length, numeric(1))
+  good <- ns == 1L | ns == n
+
+  if (all(good)) {
+    return()
+  }
 
-})
+  stop(
+    "Aesthetics must be either length 1 or the same as the data (", n, "): ",
+    paste(names(!good), collapse = ", "),
+    call. = FALSE
+  )
+}
diff --git a/R/geom-abline.r b/R/geom-abline.r
index fc0cde2..818745e 100644
--- a/R/geom-abline.r
+++ b/R/geom-abline.r
@@ -1,98 +1,126 @@
-#' Line specified by slope and intercept.
+#' @include stat-.r
+NULL
+
+#' Lines: horizontal, vertical, and specified by slope and intercept.
+#'
+#' These paired geoms and stats add straight lines to a plot, either
+#' horizontal, vertical or specified by slope and intercept. These are useful
+#' for annotating plots.
 #'
-#' The abline geom adds a line with specified slope and intercept to the
-#' plot.
+#' These geoms act slightly different to other geoms. You can supply the
+#' parameters in two ways: either as arguments to the layer function,
+#' or via aesthetics. If you use arguments, e.g.
+#' \code{geom_abline(intercept = 0, slope = 1)}, then behind the scenes
+#' the geom makes a new data frame containing just the data you've supplied.
+#' That means that the lines will be the same in all facets; if you want them
+#' to vary across facets, construct the data frame yourself and use aesthetics.
 #'
-#' With its siblings \code{geom_hline} and \code{geom_vline}, it's useful for
-#' annotating plots.  You can supply the parameters for geom_abline,
-#' intercept and slope, in two ways: either explicitly as fixed values, or
-#' in a data frame.  If you specify the fixed values
-#' (\code{geom_abline(intercept=0, slope=1)}) then the line will be the same
-#' in all panels.  If the intercept and slope are stored in the data, then
-#' they can vary from panel to panel.  See the examples for more ideas.
+#' Unlike most other geoms, these geoms do not inherit aesthetics from the plot
+#' default, because they do not understand x and y aesthetics which are
+#' commonly set in the plot. They also do not affect the x and y scales.
 #'
 #' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "abline")}
+#' These geoms are drawn using with \code{\link{geom_line}} so support the
+#' same aesthetics: alpha, colour, linetype and size. They also each have
+#' aesthetics that control the position of the line:
+#'
+#' \itemize{
+#'   \item \code{geom_vline}: \code{xintercept}
+#'   \item \code{geom_hline}: \code{yintercept}
+#'   \item \code{geom_abline}: \code{slope} and \code{intercept}
+#' }
 #'
-#' @seealso \code{\link{stat_smooth}} to add lines derived from the data,
-#'  \code{\link{geom_hline}} for horizontal lines,
-#'  \code{\link{geom_vline}} for vertical lines
-#'  \code{\link{geom_segment}}
-#' @param show_guide should a legend be drawn? (defaults to \code{FALSE})
+#' @seealso See \code{\link{geom_segment}} for a more general approach to
+#'   adding straight line segments to a plot.
+#' @param xintercept,yintercept,slope,intercept Parameters that control the
+#'   position of the line. If these are set, \code{data}, \code{mapping} and
+#'   \code{show.legend} are overridden
 #' @inheritParams geom_point
 #' @export
 #' @examples
-#' p <- qplot(wt, mpg, data = mtcars)
+#' p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
+#'
+#' # Fixed values
+#' p + geom_vline(xintercept = 5)
+#' p + geom_vline(xintercept = 1:5)
+#' p + geom_hline(yintercept = 20)
 #'
-#' # Fixed slopes and intercepts
 #' p + geom_abline() # Can't see it - outside the range of the data
 #' p + geom_abline(intercept = 20)
 #'
 #' # Calculate slope and intercept of line of best fit
 #' coef(lm(mpg ~ wt, data = mtcars))
 #' p + geom_abline(intercept = 37, slope = -5)
-#' p + geom_abline(intercept = 10, colour = "red", size = 2)
-#'
-#' # See ?stat_smooth for fitting smooth models to data
-#' p + stat_smooth(method="lm", se=FALSE)
+#' # But this is easier to do with geom_smooth:
+#' p + geom_smooth(method = "lm", se = FALSE)
 #'
-#' # Slopes and intercepts as data
-#' p <- ggplot(mtcars, aes(x = wt, y=mpg), . ~ cyl) + geom_point()
-#' df <- data.frame(a=rnorm(10, 25), b=rnorm(10, 0))
-#' p + geom_abline(aes(intercept=a, slope=b), data=df)
+#' # To show different lines in different facets, use aesthetics
+#' p <- ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point() +
+#'   facet_wrap(~ cyl)
 #'
-#' # Slopes and intercepts from linear model
-#' library(plyr)
-#' coefs <- ddply(mtcars, .(cyl), function(df) {
-#'   m <- lm(mpg ~ wt, data=df)
-#'   data.frame(a = coef(m)[1], b = coef(m)[2])
-#' })
-#' str(coefs)
-#' p + geom_abline(data=coefs, aes(intercept=a, slope=b))
+#' mean_wt <- data.frame(cyl = c(4, 6, 8), wt = c(2.28, 3.11, 4.00))
+#' p + geom_hline(aes(yintercept = wt), mean_wt)
 #'
-#' # It's actually a bit easier to do this with stat_smooth
-#' p + geom_smooth(aes(group=cyl), method="lm")
-#' p + geom_smooth(aes(group=cyl), method="lm", fullrange=TRUE)
-#'
-#' # With coordinate transforms
-#' p + geom_abline(intercept = 37, slope = -5) + coord_flip()
-#' p + geom_abline(intercept = 37, slope = -5) + coord_polar()
-geom_abline <- function (mapping = NULL, data = NULL, stat = "abline", position = "identity", show_guide = FALSE, ...) {
-  GeomAbline$new(mapping = mapping, data = data, stat = stat, position = position, show_guide = show_guide, ...)
-}
+#' # You can also control other aesthetics
+#' ggplot(mtcars, aes(mpg, wt, colour = wt)) +
+#'   geom_point() +
+#'   geom_hline(aes(yintercept = wt, colour = wt), mean_wt) +
+#'   facet_wrap(~ cyl)
+geom_abline <- function(mapping = NULL, data = NULL,
+                        ...,
+                        slope, intercept,
+                        na.rm = FALSE, show.legend = NA) {
+
+  # If nothing set, default to y = x
+  if (missing(mapping) && missing(slope) && missing(intercept)) {
+    slope <- 1
+    intercept <- 0
+  }
 
-GeomAbline <- proto(Geom, {
-  objname <- "abline"
+  # Act like an annotation
+  if (!missing(slope) || !missing(intercept)) {
+    if (missing(slope)) slope <- 1
+    if (missing(intercept)) intercept <- 0
 
-  new <- function(., mapping = NULL, ...) {
-    mapping <- compact(defaults(mapping, aes(group = 1)))
-    class(mapping) <- "uneval"
-    .super$new(., ..., mapping = mapping, inherit.aes = FALSE)
+    data <- data.frame(intercept = intercept, slope = slope)
+    mapping <- aes(intercept = intercept, slope = slope)
+    show.legend <- FALSE
   }
 
-  draw <- function(., data, scales, coordinates, ...) {
-    ranges <- coord_range(coordinates, scales)
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatIdentity,
+    geom = GeomAbline,
+    position = PositionIdentity,
+    show.legend = show.legend,
+    inherit.aes = FALSE,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomAbline <- ggproto("GeomAbline", Geom,
+  draw_panel = function(data, panel_scales, coord) {
+    ranges <- coord$range(panel_scales)
 
     data$x    <- ranges$x[1]
     data$xend <- ranges$x[2]
     data$y    <- ranges$x[1] * data$slope + data$intercept
     data$yend <- ranges$x[2] * data$slope + data$intercept
 
-    GeomSegment$draw(unique(data), scales, coordinates)
-  }
+    GeomSegment$draw_panel(unique(data), panel_scales, coord)
+  },
 
-  guide_geom <- function(.) "abline"
+  default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = NA),
+  required_aes = c("slope", "intercept"),
 
-  default_stat <- function(.) StatAbline
-  default_aes <- function(.) aes(colour="black", size=0.5, linetype=1, alpha = NA)
-
-  draw_legend <- function(., data, ...) {
-    data <- aesdefaults(data, .$default_aes(), list(...))
-
-    with(data,
-      ggname(.$my_name(), segmentsGrob(0, 0, 1, 1, default.units="npc",
-      gp=gpar(col=alpha(colour, alpha), lwd=size * .pt, lty=linetype,
-        lineend="butt")))
-    )
-  }
-})
+  draw_key = draw_key_abline
+)
diff --git a/R/geom-bar-.r b/R/geom-bar-.r
deleted file mode 100644
index b771b6d..0000000
--- a/R/geom-bar-.r
+++ /dev/null
@@ -1,149 +0,0 @@
-#' Bars, rectangles with bases on x-axis
-#'
-#' The bar geom is used to produce 1d area plots: bar charts for categorical
-#' x, and histograms for continuous y.  stat_bin explains the details of
-#' these summaries in more detail.  In particular, you can use the
-#' \code{weight} aesthetic to create weighted histograms and barcharts where
-#' the height of the bar no longer represent a count of observations, but a
-#' sum over some other variable.  See the examples for a practical
-#' example.
-#'
-#' The heights of the bars commonly represent one of two things: either a
-#' count of cases in each group, or the values in a column of the data frame.
-#' By default, \code{geom_bar} uses \code{stat="bin"}. This makes the height
-#' of each bar equal to the number of cases in each group, and it is
-#' incompatible with mapping values to the \code{y} aesthetic. If you want
-#' the heights of the bars to represent values in the data, use
-#' \code{stat="identity"} and map a value to the \code{y} aesthetic.
-#'
-#' By default, multiple x's occuring in the same place will be stacked a top
-#' one another by position_stack.  If you want them to be dodged from
-#' side-to-side, see \code{\link{position_dodge}}. Finally,
-#' \code{\link{position_fill}} shows relative propotions at each x by stacking
-#' the bars and then stretching or squashing to the same height.
-#'
-#' Sometimes, bar charts are used not as a distributional summary, but
-#' instead of a dotplot.  Generally, it's preferable to use a dotplot (see
-#' \code{geom_point}) as it has a better data-ink ratio.  However, if you do
-#' want to create this type of plot, you can set y to the value you have
-#' calculated, and use \code{stat='identity'}
-#'
-#' A bar chart maps the height of the bar to a variable, and so the base of
-#' the bar must always been shown to produce a valid visual comparison.
-#' Naomi Robbins has a nice
-#' \href{http://www.b-eye-network.com/view/index.php?cid=2468}{article on this topic}.
-#' This is the reason it doesn't make sense to use a log-scaled y axis with a bar chart
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "bar")}
-#'
-#' @seealso \code{\link{stat_bin}} for more details of the binning alogirithm,
-#'   \code{\link{position_dodge}} for creating side-by-side barcharts,
-#'   \code{\link{position_stack}} for more info on stacking,
-#' @export
-#' @inheritParams geom_point
-#' @examples
-#' \donttest{
-#' # Generate data
-#' c <- ggplot(mtcars, aes(factor(cyl)))
-#'
-#' # By default, uses stat="bin", which gives the count in each category
-#' c + geom_bar()
-#' c + geom_bar(width=.5)
-#' c + geom_bar() + coord_flip()
-#' c + geom_bar(fill="white", colour="darkgreen")
-#'
-#' # Use qplot
-#' qplot(factor(cyl), data=mtcars, geom="bar")
-#' qplot(factor(cyl), data=mtcars, geom="bar", fill=factor(cyl))
-#'
-#' # When the data contains y values in a column, use stat="identity"
-#' library(plyr)
-#' # Calculate the mean mpg for each level of cyl
-#' mm <- ddply(mtcars, "cyl", summarise, mmpg = mean(mpg))
-#' ggplot(mm, aes(x = factor(cyl), y = mmpg)) + geom_bar(stat = "identity")
-#'
-#' # Stacked bar charts
-#' qplot(factor(cyl), data=mtcars, geom="bar", fill=factor(vs))
-#' qplot(factor(cyl), data=mtcars, geom="bar", fill=factor(gear))
-#'
-#' # Stacked bar charts are easy in ggplot2, but not effective visually,
-#' # particularly when there are many different things being stacked
-#' ggplot(diamonds, aes(clarity, fill=cut)) + geom_bar()
-#' ggplot(diamonds, aes(color, fill=cut)) + geom_bar() + coord_flip()
-#'
-#' # Faceting is a good alternative:
-#' ggplot(diamonds, aes(clarity)) + geom_bar() +
-#'   facet_wrap(~ cut)
-#' # If the x axis is ordered, using a line instead of bars is another
-#' # possibility:
-#' ggplot(diamonds, aes(clarity)) +
-#'   geom_freqpoly(aes(group = cut, colour = cut))
-#'
-#' # Dodged bar charts
-#' ggplot(diamonds, aes(clarity, fill=cut)) + geom_bar(position="dodge")
-#' # compare with
-#' ggplot(diamonds, aes(cut, fill=cut)) + geom_bar() +
-#'   facet_grid(. ~ clarity)
-#'
-#' # But again, probably better to use frequency polygons instead:
-#' ggplot(diamonds, aes(clarity, colour=cut)) +
-#'   geom_freqpoly(aes(group = cut))
-#'
-#' # Often we don't want the height of the bar to represent the
-#' # count of observations, but the sum of some other variable.
-#' # For example, the following plot shows the number of diamonds
-#' # of each colour
-#' qplot(color, data=diamonds, geom="bar")
-#' # If, however, we want to see the total number of carats in each colour
-#' # we need to weight by the carat variable
-#' qplot(color, data=diamonds, geom="bar", weight=carat, ylab="carat")
-#'
-#' # A bar chart used to display means
-#' meanprice <- tapply(diamonds$price, diamonds$cut, mean)
-#' cut <- factor(levels(diamonds$cut), levels = levels(diamonds$cut))
-#' qplot(cut, meanprice)
-#' qplot(cut, meanprice, geom="bar", stat="identity")
-#' qplot(cut, meanprice, geom="bar", stat="identity", fill = I("grey50"))
-#'
-#' # Another stacked bar chart example
-#' k <- ggplot(mpg, aes(manufacturer, fill=class))
-#' k + geom_bar()
-#' # Use scales to change aesthetics defaults
-#' k + geom_bar() + scale_fill_brewer()
-#' k + geom_bar() + scale_fill_grey()
-#'
-#' # To change plot order of class varible
-#' # use factor() to change order of levels
-#' mpg$class <- factor(mpg$class, levels = c("midsize", "minivan",
-#' "suv", "compact", "2seater", "subcompact", "pickup"))
-#' m <- ggplot(mpg, aes(manufacturer, fill=class))
-#' m + geom_bar()
-#' }
-geom_bar <- function (mapping = NULL, data = NULL, stat = "bin", position = "stack", ...) {
-  GeomBar$new(mapping = mapping, data = data, stat = stat, position = position, ...)
-}
-
-GeomBar <- proto(Geom, {
-  objname <- "bar"
-
-  default_stat <- function(.) StatBin
-  default_pos <- function(.) PositionStack
-  default_aes <- function(.) aes(colour=NA, fill="grey20", size=0.5, linetype=1, weight = 1, alpha = NA)
-
-  required_aes <- c("x")
-
-  reparameterise <- function(., df, params) {
-    df$width <- df$width %||%
-      params$width %||% (resolution(df$x, FALSE) * 0.9)
-    transform(df,
-      ymin = pmin(y, 0), ymax = pmax(y, 0),
-      xmin = x - width / 2, xmax = x + width / 2, width = NULL
-    )
-  }
-
-  draw_groups <- function(., data, scales, coordinates, ...) {
-    GeomRect$draw_groups(data, scales, coordinates, ...)
-  }
-  guide_geom <- function(.) "polygon"
-})
diff --git a/R/geom-bar-histogram.r b/R/geom-bar-histogram.r
deleted file mode 100644
index b0e05e1..0000000
--- a/R/geom-bar-histogram.r
+++ /dev/null
@@ -1,123 +0,0 @@
-#' Histogram
-#'
-#' \code{geom_histogram} is an alias for \code{\link{geom_bar}} plus
-#' \code{\link{stat_bin}} so you will need to look at the documentation for
-#' those objects to get more information about the parameters.
-#'
-#' By default, \code{stat_bin} uses 30 bins - this is not a good default,
-#' but the idea is to get you experimenting with different binwidths. You
-#' may need to look at a few to uncover the full story behind your data.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "histogram")}
-#'
-#' @export
-#' @inheritParams geom_point
-#' @examples
-#' \donttest{
-#' set.seed(5689)
-#' movies <- movies[sample(nrow(movies), 1000), ]
-#' # Simple examples
-#' qplot(rating, data=movies, geom="histogram")
-#' qplot(rating, data=movies, weight=votes, geom="histogram")
-#' qplot(rating, data=movies, weight=votes, geom="histogram", binwidth=1)
-#' qplot(rating, data=movies, weight=votes, geom="histogram", binwidth=0.1)
-#'
-#' # More complex
-#' m <- ggplot(movies, aes(x=rating))
-#' m + geom_histogram()
-#' m + geom_histogram(aes(y = ..density..)) + geom_density()
-#'
-#' m + geom_histogram(binwidth = 1)
-#' m + geom_histogram(binwidth = 0.5)
-#' m + geom_histogram(binwidth = 0.1)
-#'
-#' # Add aesthetic mappings
-#' m + geom_histogram(aes(weight = votes))
-#' m + geom_histogram(aes(y = ..count..))
-#' m + geom_histogram(aes(fill = ..count..))
-#'
-#' # Change scales
-#' m + geom_histogram(aes(fill = ..count..)) +
-#'   scale_fill_gradient("Count", low = "green", high = "red")
-#'
-#' # Often we don't want the height of the bar to represent the
-#' # count of observations, but the sum of some other variable.
-#' # For example, the following plot shows the number of movies
-#' # in each rating.
-#' qplot(rating, data=movies, geom="bar", binwidth = 0.1)
-#' # If, however, we want to see the number of votes cast in each
-#' # category, we need to weight by the votes variable
-#' qplot(rating, data=movies, geom="bar", binwidth = 0.1,
-#'   weight=votes, ylab = "votes")
-#'
-#' m <- ggplot(movies, aes(x = votes))
-#' # For transformed scales, binwidth applies to the transformed data.
-#' # The bins have constant width on the transformed scale.
-#' m + geom_histogram() + scale_x_log10()
-#' m + geom_histogram(binwidth = 1) + scale_x_log10()
-#' m + geom_histogram() + scale_x_sqrt()
-#' m + geom_histogram(binwidth = 10) + scale_x_sqrt()
-#'
-#' # For transformed coordinate systems, the binwidth applies to the
-#' # raw data.  The bins have constant width on the original scale.
-#'
-#' # Using log scales does not work here, because the first
-#' # bar is anchored at zero, and so when transformed becomes negative
-#' # infinity.  This is not a problem when transforming the scales, because
-#' # no observations have 0 ratings.
-#' m + geom_histogram(origin = 0) + coord_trans(x = "log10")
-#' # Use origin = 0, to make sure we don't take sqrt of negative values
-#' m + geom_histogram(origin = 0) + coord_trans(x = "sqrt")
-#' m + geom_histogram(origin = 0, binwidth = 1000) + coord_trans(x = "sqrt")
-#'
-#' # You can also transform the y axis.  Remember that the base of the bars
-#' # has value 0, so log transformations are not appropriate
-#' m <- ggplot(movies, aes(x = rating))
-#' m + geom_histogram(binwidth = 0.5) + scale_y_sqrt()
-#' m + geom_histogram(binwidth = 0.5) + scale_y_reverse()
-#'
-#' # Set aesthetics to fixed value
-#' m + geom_histogram(colour = "darkgreen", fill = "white", binwidth = 0.5)
-#'
-#' # Use facets
-#' m <- m + geom_histogram(binwidth = 0.5)
-#' m + facet_grid(Action ~ Comedy)
-#'
-#' # Often more useful to use density on the y axis when facetting
-#' m <- m + aes(y = ..density..)
-#' m + facet_grid(Action ~ Comedy)
-#' m + facet_wrap(~ mpaa)
-#'
-#' # Multiple histograms on the same graph
-#' # see ?position, ?position_fill, etc for more details.
-#' set.seed(6298)
-#' diamonds_small <- diamonds[sample(nrow(diamonds), 1000), ]
-#' ggplot(diamonds_small, aes(x=price)) + geom_bar()
-#' hist_cut <- ggplot(diamonds_small, aes(x=price, fill=cut))
-#' hist_cut + geom_bar() # defaults to stacking
-#' hist_cut + geom_bar(position="fill")
-#' hist_cut + geom_bar(position="dodge")
-#'
-#' # This is easy in ggplot2, but not visually effective.  It's better
-#' # to use a frequency polygon or density plot.  Like this:
-#' ggplot(diamonds_small, aes(price, ..density.., colour = cut)) +
-#'   geom_freqpoly(binwidth = 1000)
-#' # Or this:
-#' ggplot(diamonds_small, aes(price, colour = cut)) +
-#'   geom_density()
-#' # Or if you want to be fancy, maybe even this:
-#' ggplot(diamonds_small, aes(price, fill = cut)) +
-#'   geom_density(alpha = 0.2)
-#' # Which looks better when the distributions are more distinct
-#' ggplot(diamonds_small, aes(depth, fill = cut)) +
-#'   geom_density(alpha = 0.2) + xlim(55, 70)
-#' }
-#' rm(movies)
-geom_histogram <- function (mapping = NULL, data = NULL, stat = "bin", position = "stack", ...) {
-  GeomHistogram$new(mapping = mapping, data = data, stat = stat, position = position, ...)
-}
-
-GeomHistogram <- proto(GeomBar, {
-  objname <- "histogram"
-})
diff --git a/R/geom-bar.r b/R/geom-bar.r
new file mode 100644
index 0000000..52ae972
--- /dev/null
+++ b/R/geom-bar.r
@@ -0,0 +1,125 @@
+#' Bars, rectangles with bases on x-axis
+#'
+#' There are two types of bar charts, determined by what is mapped to bar
+#' height. By default, \code{geom_bar} uses \code{stat="count"} which makes the
+#' height of the bar proportion to the number of cases in each group (or if the
+#' \code{weight} aethetic is supplied, the sum of the weights). If you want the
+#' heights of the bars to represent values in the data, use
+#' \code{stat="identity"} and map a variable to the \code{y} aesthetic.
+#'
+#' A bar chart maps the height of the bar to a variable, and so the base of the
+#' bar must always be shown to produce a valid visual comparison. Naomi Robbins
+#' has a nice
+#' \href{http://www.b-eye-network.com/view/index.php?cid=2468}{article on this
+#' topic}. This is why it doesn't make sense to use a log-scaled y axis with a
+#' bar chart.
+#'
+#' By default, multiple x's occurring in the same place will be stacked atop one
+#' another by \code{\link{position_stack}}. If you want them to be dodged
+#' side-to-side, see \code{\link{position_dodge}}. Finally,
+#' \code{\link{position_fill}} shows relative proportions at each x by stacking
+#' the bars and then stretching or squashing to the same height.
+#'
+#' @section Aesthetics:
+#'   \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "bar")}
+#'
+#' @seealso \code{\link{geom_histogram}} for continuous data,
+#'   \code{\link{position_dodge}} for creating side-by-side barcharts.
+#' @export
+#' @inheritParams geom_point
+#' @param width Bar width. By default, set to 90\% of the resolution of the data.
+#' @param binwidth \code{geom_bar} no longer has a binwidth argument - if
+#'   you use it you'll get an warning telling to you use
+#'   \code{\link{geom_histogram}} instead.
+#' @param geom,stat Override the default connection between \code{geom_bar} and
+#'   \code{stat_count}.
+#' @examples
+#' # geom_bar is designed to make it easy to create bar charts that show
+#' # counts (or sums of weights)
+#' g <- ggplot(mpg, aes(class))
+#' # Number of cars in each class:
+#' g + geom_bar()
+#' # Total engine displacement of each class
+#' g + geom_bar(aes(weight = displ))
+#'
+#' # To show (e.g.) means, you need stat = "identity"
+#' df <- data.frame(trt = c("a", "b", "c"), outcome = c(2.3, 1.9, 3.2))
+#' ggplot(df, aes(trt, outcome)) +
+#'   geom_bar(stat = "identity")
+#' # But geom_point() display exactly the same information and doesn't
+#' # require the y-axis to touch zero.
+#' ggplot(df, aes(trt, outcome)) +
+#'   geom_point()
+#'
+#' # You can also use geom_bar() with continuous data, in which case
+#' # it will show counts at unique locations
+#' df <- data.frame(x = rep(c(2.9, 3.1, 4.5), c(5, 10, 4)))
+#' ggplot(df, aes(x)) + geom_bar()
+#' # cf. a histogram of the same data
+#' ggplot(df, aes(x)) + geom_histogram(binwidth = 0.5)
+#'
+#' \donttest{
+#' # Bar charts are automatically stacked when multiple bars are placed
+#' # at the same location
+#' g + geom_bar(aes(fill = drv))
+#'
+#' # You can instead dodge, or fill them
+#' g + geom_bar(aes(fill = drv), position = "dodge")
+#' g + geom_bar(aes(fill = drv), position = "fill")
+#'
+#' # To change plot order of bars, change levels in underlying factor
+#' reorder_size <- function(x) {
+#'   factor(x, levels = names(sort(table(x))))
+#' }
+#' ggplot(mpg, aes(reorder_size(class))) + geom_bar()
+#' }
+geom_bar <- function(mapping = NULL, data = NULL, stat = "count",
+                     position = "stack", width = NULL, binwidth = NULL, ...,
+                     na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) {
+
+  if (!is.null(binwidth)) {
+    warning("`geom_bar()` no longer has a `binwidth` parameter. ",
+      "Please use `geom_histogram()` instead.", call. = "FALSE")
+    return(geom_histogram(mapping = mapping, data = data,
+      position = position, width = width, binwidth = binwidth, ...,
+      na.rm = na.rm, show.legend = show.legend, inherit.aes = inherit.aes))
+  }
+
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomBar,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      width = width,
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+#' @include geom-rect.r
+GeomBar <- ggproto("GeomBar", GeomRect,
+  required_aes = "x",
+
+  setup_data = function(data, params) {
+    data$width <- data$width %||%
+      params$width %||% (resolution(data$x, FALSE) * 0.9)
+    transform(data,
+      ymin = pmin(y, 0), ymax = pmax(y, 0),
+      xmin = x - width / 2, xmax = x + width / 2, width = NULL
+    )
+  },
+
+  draw_panel = function(self, data, panel_scales, coord, width = NULL) {
+    # Hack to ensure that width is detected as a parameter
+    ggproto_parent(GeomRect, self)$draw_panel(data, panel_scales, coord)
+  }
+)
diff --git a/R/geom-bin2d.r b/R/geom-bin2d.r
index 0e3678e..97bbdff 100644
--- a/R/geom-bin2d.r
+++ b/R/geom-bin2d.r
@@ -1,33 +1,39 @@
 #' Add heatmap of 2d bin counts.
 #'
 #' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "bin2d")}
+#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "bin2d")}
 #'
 #' @export
 #' @inheritParams geom_point
+#' @param geom,stat Use to override the default connection between
+#'   \code{geom_bin2d} and \code{stat_bin2d}.
+#' @seealso \code{\link{stat_binhex}} for hexagonal binning
 #' @examples
-#' d <- ggplot(diamonds, aes(x = x, y = y)) + xlim(4,10) + ylim(4,10)
+#' d <- ggplot(diamonds, aes(x, y)) + xlim(4, 10) + ylim(4, 10)
 #' d + geom_bin2d()
-#' d + geom_bin2d(binwidth = c(0.1, 0.1))
 #'
-#' # See ?stat_bin2d for more examples
-geom_bin2d <- function (mapping = NULL, data = NULL, stat = "bin2d", position = "identity", ...) {
-  GeomBin2d$new(mapping = mapping, data = data, stat = stat, position = position, ...)
-}
-
-GeomBin2d <- proto(Geom, {
-  draw <- function(., data, scales, coordinates, ...) {
-    GeomRect$draw(data, scales, coordinates, ...)
-  }
-
-  objname <- "bin2d"
-
-  guide_geom <- function(.) "polygon"
-
-  default_stat <- function(.) StatBin2d
-  required_aes <- c("xmin", "xmax", "ymin", "ymax")
-  default_aes <- function(.) {
-    aes(colour = NA, fill = "grey60", size = 0.5, linetype = 1, weight = 1, , alpha = NA)
-  }
+#' # You can control the size of the bins by specifying the number of
+#' # bins in each direction:
+#' d + geom_bin2d(bins = 10)
+#' d + geom_bin2d(bins = 30)
+#'
+#' # Or by specifying the width of the bins
+#' d + geom_bin2d(binwidth = c(0.1, 0.1))
+geom_bin2d <- function(mapping = NULL, data = NULL, stat = "bin2d",
+                       position = "identity", na.rm = FALSE,
+                       show.legend = NA, inherit.aes = TRUE, ...) {
 
-})
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomTile,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
diff --git a/R/geom-blank.r b/R/geom-blank.r
index bb0117a..fc9cc74 100644
--- a/R/geom-blank.r
+++ b/R/geom-blank.r
@@ -6,7 +6,7 @@
 #' @export
 #' @inheritParams geom_point
 #' @examples
-#' qplot(length, rating, data = movies, geom = "blank")
+#' ggplot(mtcars, aes(wt, mpg)) + geom_blank()
 #' # Nothing to see here!
 #'
 #' # Take the following scatter plot
@@ -21,18 +21,28 @@
 #' # Switching to geom_blank() gets the desired plot
 #' c <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_blank()
 #' c + geom_abline(aes(intercept = a, slope = b), data = df)
-geom_blank <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity", ...) {
-  GeomBlank$new(mapping = mapping, data = data, stat = stat, position = position, ...)
+geom_blank <- function(mapping = NULL, data = NULL, stat = "identity",
+                       position = "identity", show.legend = NA,
+                       inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomBlank,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(...)
+  )
 }
 
-GeomBlank <- proto(Geom, {
-  objname <- "blank"
 
-  default_stat <- function(.) StatIdentity
-  default_aes <- function(.) aes()
-
-  draw_legend <- function(., data, ...) {
-    zeroGrob()
-  }
-
-})
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomBlank <- ggproto("GeomBlank", Geom,
+  default_aes = aes(),
+  handle_na = function(data, params) data,
+  draw_panel = function(...) nullGrob()
+)
diff --git a/R/geom-boxplot.r b/R/geom-boxplot.r
index 53d4807..f17bc31 100644
--- a/R/geom-boxplot.r
+++ b/R/geom-boxplot.r
@@ -1,6 +1,6 @@
 #' Box and whiskers plot.
 #'
-#' The upper and lower "hinges" correspond to the first and third quartiles
+#' The lower and upper "hinges" correspond to the first and third quartiles
 #' (the 25th and 75th percentiles). This differs slightly from the method used
 #' by the \code{boxplot} function, and may be apparent with small samples.
 #' See \code{\link{boxplot.stats}} for for more information on how hinge
@@ -20,149 +20,136 @@
 #' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "boxplot")}
 #'
 #' @seealso \code{\link{stat_quantile}} to view quantiles conditioned on a
-#'   continuous variable,  \code{\link{geom_jitter}} for another way to look
-#'   at conditional distributions"
+#'   continuous variable, \code{\link{geom_jitter}} for another way to look
+#'   at conditional distributions.
 #' @inheritParams geom_point
-#' @param outlier.colour colour for outlying points. Uses the default from geom_point().
-#' @param outlier.shape shape of outlying points. Uses the default from geom_point().
-#' @param outlier.size size of outlying points. Uses the default from geom_point().
+#' @param geom,stat Use to override the default connection between
+#'   \code{geom_boxplot} and \code{stat_boxplot}.
+#' @param outlier.colour,outlier.shape,outlier.size,outlier.stroke Default
+#'   aesthetics for outliers. Set to \code{NULL} to inherit from the aesthetics
+#'   used for the box.
 #' @param notch if \code{FALSE} (default) make a standard box plot. If
-#'    \code{TRUE}, make a notched box plot. Notches are used to compare groups;
-#'    if the notches of two boxes do not overlap, this is strong evidence that
-#'    the medians differ.
+#'   \code{TRUE}, make a notched box plot. Notches are used to compare groups;
+#'   if the notches of two boxes do not overlap, this suggests that the medians
+#'   are significantly different.
 #' @param notchwidth for a notched box plot, width of the notch relative to
-#'    the body (default 0.5)
+#'   the body (default 0.5)
 #' @param varwidth if \code{FALSE} (default) make a standard box plot. If
-#'    \code{TRUE}, boxes are drawn with widths proportional to the
-#'    square-roots of the number of observations in the groups (possibly
-#'    weighted, using the \code{weight} aesthetic).
+#'   \code{TRUE}, boxes are drawn with widths proportional to the
+#'   square-roots of the number of observations in the groups (possibly
+#'   weighted, using the \code{weight} aesthetic).
 #' @export
-#'
 #' @references McGill, R., Tukey, J. W. and Larsen, W. A. (1978) Variations of
 #'     box plots. The American Statistician 32, 12-16.
-#'
 #' @examples
-#' \donttest{
-#' p <- ggplot(mtcars, aes(factor(cyl), mpg))
-#'
+#' p <- ggplot(mpg, aes(class, hwy))
 #' p + geom_boxplot()
-#' qplot(factor(cyl), mpg, data = mtcars, geom = "boxplot")
-#'
-#' p + geom_boxplot() + geom_jitter()
+#' p + geom_boxplot() + geom_jitter(width = 0.2)
 #' p + geom_boxplot() + coord_flip()
-#' qplot(factor(cyl), mpg, data = mtcars, geom = "boxplot") +
-#'   coord_flip()
 #'
 #' p + geom_boxplot(notch = TRUE)
-#' p + geom_boxplot(notch = TRUE, notchwidth = .3)
-#'
-#' p + geom_boxplot(outlier.colour = "green", outlier.size = 3)
-#'
-#' # Add aesthetic mappings
-#' # Note that boxplots are automatically dodged when any aesthetic is
-#' # a factor
-#' p + geom_boxplot(aes(fill = cyl))
-#' p + geom_boxplot(aes(fill = factor(cyl)))
-#' p + geom_boxplot(aes(fill = factor(vs)))
-#' p + geom_boxplot(aes(fill = factor(am)))
-#'
-#' # Set aesthetics to fixed value
-#' p + geom_boxplot(fill = "grey80", colour = "#3366FF")
-#' qplot(factor(cyl), mpg, data = mtcars, geom = "boxplot",
-#'   colour = I("#3366FF"))
-#'
-#' # Scales vs. coordinate transforms -------
-#' # Scale transformations occur before the boxplot statistics are computed.
-#' # Coordinate transformations occur afterwards.  Observe the effect on the
-#' # number of outliers.
-#' library(plyr) # to access round_any
-#' m <- ggplot(movies, aes(y = votes, x = rating,
-#'    group = round_any(rating, 0.5)))
-#' m + geom_boxplot()
-#' m + geom_boxplot() + scale_y_log10()
-#' m + geom_boxplot() + coord_trans(y = "log10")
-#' m + geom_boxplot() + scale_y_log10() + coord_trans(y = "log10")
-#'
-#' # Boxplots with continuous x:
-#' # Use the group aesthetic to group observations in boxplots
-#' qplot(year, budget, data = movies, geom = "boxplot")
-#' qplot(year, budget, data = movies, geom = "boxplot",
-#'   group = round_any(year, 10, floor))
-#'
-#' # Using precomputed statistics
-#' # generate sample data
-#' abc <- adply(matrix(rnorm(100), ncol = 5), 2, quantile, c(0, .25, .5, .75, 1))
-#' b <- ggplot(abc, aes(x = X1, ymin = `0%`, lower = `25%`,
-#'    middle = `50%`, upper = `75%`, ymax = `100%`))
-#' b + geom_boxplot(stat = "identity")
-#' b + geom_boxplot(stat = "identity") + coord_flip()
-#' b + geom_boxplot(aes(fill = X1), stat = "identity")
-#'
-#' # Using varwidth
 #' p + geom_boxplot(varwidth = TRUE)
-#' qplot(factor(cyl), mpg, data = mtcars, geom = "boxplot", varwidth = TRUE)
+#' p + geom_boxplot(fill = "white", colour = "#3366FF")
+#' # By default, outlier points match the colour of the box. Use
+#' # outlier.colour to override
+#' p + geom_boxplot(outlier.colour = "red", outlier.shape = 1)
 #'
-#' # Update the defaults for the outliers by changing the defaults for geom_point
+#' # Boxplots are automatically dodged when any aesthetic is a factor
+#' p + geom_boxplot(aes(colour = drv))
 #'
-#' p <- ggplot(mtcars, aes(factor(cyl), mpg))
-#' p + geom_boxplot()
+#' # You can also use boxplots with continuous x, as long as you supply
+#' # a grouping variable. cut_width is particularly useful
+#' ggplot(diamonds, aes(carat, price)) +
+#'   geom_boxplot()
+#' ggplot(diamonds, aes(carat, price)) +
+#'   geom_boxplot(aes(group = cut_width(carat, 0.25)))
 #'
-#' update_geom_defaults("point", list(shape = 1, colour = "red", size = 5))
-#' p + geom_boxplot()
+#' \donttest{
+#' # It's possible to draw a boxplot with your own computations if you
+#' # use stat = "identity":
+#' y <- rnorm(100)
+#' df <- data.frame(
+#'   x = 1,
+#'   y0 = min(y),
+#'   y25 = quantile(y, 0.25),
+#'   y50 = median(y),
+#'   y75 = quantile(y, 0.75),
+#'   y100 = max(y)
+#' )
+#' ggplot(df, aes(x)) +
+#'   geom_boxplot(
+#'    aes(ymin = y0, lower = y25, middle = y50, upper = y75, ymax = y100),
+#'    stat = "identity"
+#'  )
 #' }
-geom_boxplot <- function (mapping = NULL, data = NULL, stat = "boxplot",
-                          position = "dodge", outlier.colour = NULL,
-                          outlier.shape = NULL, outlier.size = NULL,
-                          notch = FALSE, notchwidth = .5, varwidth = FALSE,
-                          ...) {
-
-  outlier_defaults <- Geom$find('point')$default_aes()
-
-  outlier.colour   <- outlier.colour %||% outlier_defaults$colour
-  outlier.shape    <- outlier.shape  %||% outlier_defaults$shape
-  outlier.size     <- outlier.size   %||% outlier_defaults$size
-
-  GeomBoxplot$new(mapping = mapping, data = data, stat = stat,
-    position = position, outlier.colour = outlier.colour,
-    outlier.shape = outlier.shape, outlier.size = outlier.size, notch = notch,
-    notchwidth = notchwidth, varwidth = varwidth, ...)
+geom_boxplot <- function(mapping = NULL, data = NULL, stat = "boxplot",
+                         position = "dodge", outlier.colour = NULL,
+                         outlier.shape = 19, outlier.size = 1.5,
+                         outlier.stroke = 0.5, notch = FALSE, notchwidth = 0.5,
+                         varwidth = FALSE, na.rm = FALSE,
+                         show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomBoxplot,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      outlier.colour = outlier.colour,
+      outlier.shape = outlier.shape,
+      outlier.size = outlier.size,
+      outlier.stroke = outlier.stroke,
+      notch = notch,
+      notchwidth = notchwidth,
+      varwidth = varwidth,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-GeomBoxplot <- proto(Geom, {
-  objname <- "boxplot"
-
-  reparameterise <- function(., df, params) {
-    df$width <- df$width %||%
-      params$width %||% (resolution(df$x, FALSE) * 0.9)
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomBoxplot <- ggproto("GeomBoxplot", Geom,
+  setup_data = function(data, params) {
+    data$width <- data$width %||%
+      params$width %||% (resolution(data$x, FALSE) * 0.9)
 
-    if (!is.null(df$outliers)) {
+    if (!is.null(data$outliers)) {
       suppressWarnings({
-        out_min <- vapply(df$outliers, min, numeric(1))
-        out_max <- vapply(df$outliers, max, numeric(1))
+        out_min <- vapply(data$outliers, min, numeric(1))
+        out_max <- vapply(data$outliers, max, numeric(1))
       })
 
-      df$ymin_final <- pmin(out_min, df$ymin)
-      df$ymax_final <- pmax(out_max, df$ymax)
+      data$ymin_final <- pmin(out_min, data$ymin)
+      data$ymax_final <- pmax(out_max, data$ymax)
     }
 
     # if `varwidth` not requested or not available, don't use it
-    if (is.null(params) || is.null(params$varwidth) || !params$varwidth || is.null(df$relvarwidth)) {
-      df$xmin <- df$x - df$width / 2
-      df$xmax <- df$x + df$width / 2
+    if (is.null(params) || is.null(params$varwidth) || !params$varwidth || is.null(data$relvarwidth)) {
+      data$xmin <- data$x - data$width / 2
+      data$xmax <- data$x + data$width / 2
     } else {
       # make `relvarwidth` relative to the size of the largest group
-      df$relvarwidth <- df$relvarwidth / max(df$relvarwidth)
-      df$xmin <- df$x - df$relvarwidth * df$width / 2
-      df$xmax <- df$x + df$relvarwidth * df$width / 2
+      data$relvarwidth <- data$relvarwidth / max(data$relvarwidth)
+      data$xmin <- data$x - data$relvarwidth * data$width / 2
+      data$xmax <- data$x + data$relvarwidth * data$width / 2
     }
-    df$width <- NULL
-    if (!is.null(df$relvarwidth)) df$relvarwidth <- NULL
+    data$width <- NULL
+    if (!is.null(data$relvarwidth)) data$relvarwidth <- NULL
+
+    data
+  },
 
-    df
-  }
+  draw_group = function(data, panel_scales, coord, fatten = 2,
+                        outlier.colour = NULL, outlier.shape = 19,
+                        outlier.size = 1.5, outlier.stroke = 0.5,
+                        notch = FALSE, notchwidth = 0.5, varwidth = FALSE) {
 
-  draw <- function(., data, ..., fatten = 2, outlier.colour = NULL, outlier.shape = NULL, outlier.size = 2,
-                   notch = FALSE, notchwidth = .5, varwidth = FALSE) {
     common <- data.frame(
       colour = data$colour,
       size = data$size,
@@ -178,7 +165,9 @@ GeomBoxplot <- proto(Geom, {
       y = c(data$upper, data$lower),
       yend = c(data$ymax, data$ymin),
       alpha = NA,
-      common)
+      common,
+      stringsAsFactors = FALSE
+    )
 
     box <- data.frame(
       xmin = data$xmin,
@@ -190,7 +179,9 @@ GeomBoxplot <- proto(Geom, {
       ynotchupper = ifelse(notch, data$notchupper, NA),
       notchwidth = notchwidth,
       alpha = data$alpha,
-      common)
+      common,
+      stringsAsFactors = FALSE
+    )
 
     if (!is.null(data$outliers) && length(data$outliers[[1]] >= 1)) {
       outliers <- data.frame(
@@ -199,36 +190,27 @@ GeomBoxplot <- proto(Geom, {
         colour = outlier.colour %||% data$colour[1],
         shape = outlier.shape %||% data$shape[1],
         size = outlier.size %||% data$size[1],
+        stroke = outlier.stroke %||% data$stroke[1],
         fill = NA,
         alpha = NA,
-        stringsAsFactors = FALSE)
-      outliers_grob <- GeomPoint$draw(outliers, ...)
+        stringsAsFactors = FALSE
+      )
+      outliers_grob <- GeomPoint$draw_panel(outliers, panel_scales, coord)
     } else {
       outliers_grob <- NULL
     }
 
-    ggname(.$my_name(), grobTree(
+    ggname("geom_boxplot", grobTree(
       outliers_grob,
-      GeomSegment$draw(whiskers, ...),
-      GeomCrossbar$draw(box, fatten = fatten, ...)
+      GeomSegment$draw_panel(whiskers, panel_scales, coord),
+      GeomCrossbar$draw_panel(box, fatten = fatten, panel_scales, coord)
     ))
-  }
+  },
 
-  guide_geom <- function(.) "boxplot"
-  draw_legend <- function(., data, ...)  {
-    data <- aesdefaults(data, .$default_aes(), list(...))
-    gp <- with(data, gpar(col=colour, fill=alpha(fill, alpha), lwd=size * .pt, lty = linetype))
-    gTree(gp = gp, children = gList(
-      linesGrob(0.5, c(0.1, 0.25)),
-      linesGrob(0.5, c(0.75, 0.9)),
-      rectGrob(height=0.5, width=0.75),
-      linesGrob(c(0.125, 0.875), 0.5)
-    ))
-  }
+  draw_key = draw_key_boxplot,
 
-  default_stat <- function(.) StatBoxplot
-  default_pos <- function(.) PositionDodge
-  default_aes <- function(.) aes(weight=1, colour="grey20", fill="white", size=0.5, alpha = NA, shape = 16, linetype = "solid")
-  required_aes <- c("x", "lower", "upper", "middle", "ymin", "ymax")
+  default_aes = aes(weight = 1, colour = "grey20", fill = "white", size = 0.5,
+    alpha = NA, shape = 19, linetype = "solid"),
 
-})
+  required_aes = c("x", "lower", "upper", "middle", "ymin", "ymax")
+)
diff --git a/R/geom-contour.r b/R/geom-contour.r
new file mode 100644
index 0000000..93edb20
--- /dev/null
+++ b/R/geom-contour.r
@@ -0,0 +1,67 @@
+#' Display contours of a 3d surface in 2d.
+#'
+#' @section Aesthetics:
+#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "contour")}
+#'
+#' @inheritParams geom_point
+#' @inheritParams geom_path
+#' @seealso \code{\link{geom_density_2d}}: 2d density contours
+#' @export
+#' @export
+#' @examples
+#' #' # Basic plot
+#' v <- ggplot(faithfuld, aes(waiting, eruptions, z = density))
+#' v + geom_contour()
+#'
+#' # Or compute from raw data
+#' ggplot(faithful, aes(waiting, eruptions)) +
+#'   geom_density_2d()
+#'
+#' \donttest{
+#' # Setting bins creates evenly spaced contours in the range of the data
+#' v + geom_contour(bins = 2)
+#' v + geom_contour(bins = 10)
+#'
+#' # Setting binwidth does the same thing, parameterised by the distance
+#' # between contours
+#' v + geom_contour(binwidth = 0.01)
+#' v + geom_contour(binwidth = 0.001)
+#'
+#' # Other parameters
+#' v + geom_contour(aes(colour = ..level..))
+#' v + geom_contour(colour = "red")
+#' v + geom_raster(aes(fill = density)) +
+#'   geom_contour(colour = "white")
+#' }
+geom_contour <- function(mapping = NULL, data = NULL, stat = "contour",
+                         position = "identity", lineend = "butt",
+                         linejoin = "round", linemitre = 1,
+                         na.rm = FALSE, show.legend = NA,
+                         inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomContour,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      lineend = lineend,
+      linejoin = linejoin,
+      linemitre = linemitre,
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+#' @include geom-path.r
+GeomContour <- ggproto("GeomContour", GeomPath,
+  default_aes = aes(weight = 1, colour = "#3366FF", size = 0.5, linetype = 1,
+    alpha = NA)
+)
diff --git a/R/geom-count.r b/R/geom-count.r
new file mode 100644
index 0000000..54b5e0e
--- /dev/null
+++ b/R/geom-count.r
@@ -0,0 +1,59 @@
+#' Count the number of observations at each location.
+#'
+#' This is a variant \code{\link{geom_point}} that counts the number of
+#' observations at each location, then maps the count to point size. It
+#' useful when you have discrete data.
+#'
+#' @section Aesthetics:
+#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "point")}
+#' @param geom,stat Use to override the default connection between
+#'   \code{geom_count} and \code{stat_sum}.
+#' @inheritParams geom_point
+#' @export
+#' @examples
+#' ggplot(mpg, aes(cty, hwy)) +
+#'  geom_point()
+#'
+#' ggplot(mpg, aes(cty, hwy)) +
+#'  geom_count()
+#'
+#' # Best used in conjunction with scale_size_area which ensures that
+#' # counts of zero would be given size 0. Doesn't make much different
+#' # here because the smallest count is already close to 0.
+#' ggplot(mpg, aes(cty, hwy)) +
+#'  geom_count()
+#'  scale_size_area()
+#'
+#' # Display proportions instead of counts -------------------------------------
+#' # By default, all categorical variables in the plot form the groups.
+#' # Specifying geom_count without a group identifier leads to a plot which is
+#' # not useful:
+#' d <- ggplot(diamonds, aes(x = cut, y = clarity))
+#' d + geom_count(aes(size = ..prop..))
+#' # To correct this problem and achieve a more desirable plot, we need
+#' # to specify which group the proportion is to be calculated over.
+#' d + geom_count(aes(size = ..prop.., group = 1)) +
+#'   scale_size_area(max_size = 10)
+#'
+#' # Or group by x/y variables to have rows/columns sum to 1.
+#' d + geom_count(aes(size = ..prop.., group = cut)) +
+#'   scale_size_area(max_size = 10)
+#' d + geom_count(aes(size = ..prop.., group = clarity)) +
+#'   scale_size_area(max_size = 10)
+geom_count <- function(mapping = NULL, data = NULL, stat = "sum",
+                       position = "identity", na.rm = FALSE,
+                       show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomPoint,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
diff --git a/R/geom-crossbar.r b/R/geom-crossbar.r
index bb6db95..381bb94 100644
--- a/R/geom-crossbar.r
+++ b/R/geom-crossbar.r
@@ -1,45 +1,41 @@
-#' Hollow bar with middle indicated by horizontal line.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "crossbar")}
-#'
-#' @inheritParams geom_point
-#' @param fatten a multiplicate factor to fatten middle bar by
-#' @seealso \code{\link{geom_errorbar}} for error bars,
-#' \code{\link{geom_pointrange}} and \code{\link{geom_linerange}} for other
-#' ways of showing mean + error, \code{\link{stat_summary}} to compute
-#' errors from the data, \code{\link{geom_smooth}} for the continuous analog.
 #' @export
-#' @examples
-#' # See geom_linerange for examples
-geom_crossbar <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity",
-fatten = 2, ...) {
-  GeomCrossbar$new(mapping = mapping, data = data, stat = stat,
-  position = position, fatten = fatten, ...)
+#' @rdname geom_linerange
+geom_crossbar <- function(mapping = NULL, data = NULL, stat = "identity",
+                          position = "identity", fatten = 2.5, na.rm = FALSE,
+                          show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomCrossbar,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      fatten = fatten,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-GeomCrossbar <- proto(Geom, {
-  objname <- "crossbar"
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomCrossbar <- ggproto("GeomCrossbar", Geom,
+  setup_data = function(data, params) {
+    GeomErrorbar$setup_data(data, params)
+  },
 
-  reparameterise <- function(., df, params) {
-    GeomErrorbar$reparameterise(df, params)
-  }
+  default_aes = aes(colour = "black", fill = NA, size = 0.5, linetype = 1,
+    alpha = NA),
 
-  default_stat <- function(.) StatIdentity
-  default_pos <- function(.) PositionIdentity
-  default_aes = function(.) aes(colour="black", fill=NA, size=0.5, linetype=1, alpha = NA)
-  required_aes <- c("x", "y", "ymin", "ymax")
-  guide_geom <- function(.) "crossbar"
-  draw_legend <- function(., data, ...)  {
-    data <- aesdefaults(data, .$default_aes(), list(...))
-    gp <- with(data, gpar(col=colour, fill=alpha(fill, alpha), lwd=size * .pt, lty = linetype))
-    gTree(gp = gp, children = gList(
-      rectGrob(height=0.5, width=0.75),
-      linesGrob(c(0.125, 0.875), 0.5)
-    ))
-  }
+  required_aes = c("x", "y", "ymin", "ymax"),
 
-  draw <- function(., data, scales, coordinates, fatten = 2, width = NULL, ...) {
+  draw_key = draw_key_crossbar,
+
+  draw_panel = function(data, panel_scales, coord, fatten = 2.5, width = NULL) {
     middle <- transform(data, x = xmin, xend = xmax, yend = y, size = size * fatten, alpha = NA)
 
     has_notch <- !is.null(data$ynotchlower) && !is.null(data$ynotchupper) &&
@@ -55,29 +51,41 @@ GeomCrossbar <- proto(Geom, {
       middle$xend <- middle$xend - notchindent
 
       box <- data.frame(
-              x = c(data$xmin, data$xmin, data$xmin + notchindent, data$xmin, data$xmin,
-                    data$xmax, data$xmax, data$xmax - notchindent, data$xmax, data$xmax,
-                    data$xmin),
-              y = c(data$ymax, data$ynotchupper, data$y, data$ynotchlower, data$ymin,
-                    data$ymin, data$ynotchlower, data$y, data$ynotchupper, data$ymax,
-                    data$ymax),
-              alpha = data$alpha, colour = data$colour, size = data$size,
-              linetype = data$linetype, fill = data$fill, group = data$group,
-              stringsAsFactors = FALSE)
-
+        x = c(
+          data$xmin, data$xmin, data$xmin + notchindent, data$xmin, data$xmin,
+          data$xmax, data$xmax, data$xmax - notchindent, data$xmax, data$xmax,
+          data$xmin
+        ),
+        y = c(
+          data$ymax, data$ynotchupper, data$y, data$ynotchlower, data$ymin,
+          data$ymin, data$ynotchlower, data$y, data$ynotchupper, data$ymax,
+          data$ymax
+        ),
+        alpha = data$alpha,
+        colour = data$colour,
+        size = data$size,
+        linetype = data$linetype, fill = data$fill,
+        group = seq_len(nrow(data)),
+        stringsAsFactors = FALSE
+      )
     } else {
       # No notch
       box <- data.frame(
-              x = c(data$xmin, data$xmin, data$xmax, data$xmax, data$xmin),
-              y = c(data$ymax, data$ymin, data$ymin, data$ymax, data$ymax),
-              alpha = data$alpha, colour = data$colour, size = data$size,
-              linetype = data$linetype, fill = data$fill, group = data$group,
-              stringsAsFactors = FALSE)
+        x = c(data$xmin, data$xmin, data$xmax, data$xmax, data$xmin),
+        y = c(data$ymax, data$ymin, data$ymin, data$ymax, data$ymax),
+        alpha = data$alpha,
+        colour = data$colour,
+        size = data$size,
+        linetype = data$linetype,
+        fill = data$fill,
+        group = seq_len(nrow(data)), # each bar forms it's own group
+        stringsAsFactors = FALSE
+      )
     }
 
-    ggname(.$my_name(), gTree(children=gList(
-      GeomPolygon$draw(box, scales, coordinates, ...),
-      GeomSegment$draw(middle, scales, coordinates, ...)
+    ggname("geom_crossbar", gTree(children = gList(
+      GeomPolygon$draw_panel(box, panel_scales, coord),
+      GeomSegment$draw_panel(middle, panel_scales, coord)
     )))
   }
-})
+)
diff --git a/R/geom-curve.r b/R/geom-curve.r
new file mode 100644
index 0000000..cf3df3d
--- /dev/null
+++ b/R/geom-curve.r
@@ -0,0 +1,54 @@
+#' @inheritParams grid::curveGrob
+#' @export
+#' @rdname geom_segment
+geom_curve <- function(mapping = NULL, data = NULL, stat = "identity",
+                       position = "identity", curvature = 0.5, angle = 90,
+                       ncp = 5, arrow = NULL, lineend = "butt",
+                       na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomCurve,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      arrow = arrow,
+      curvature = curvature,
+      angle = angle,
+      ncp = ncp,
+      lineend = lineend,
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @include geom-segment.r
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomCurve <- ggproto("GeomCurve", GeomSegment,
+  draw_panel = function(data, panel_scales, coord, curvature = 0.5, angle = 90,
+                        ncp = 5, arrow = NULL, lineend = "butt", na.rm = FALSE) {
+    if (!coord$is_linear()) {
+      warning("geom_curve is not implemented for non-linear coordinates",
+        call. = FALSE)
+    }
+    trans <- coord$transform(data, panel_scales)
+    curveGrob(
+      trans$x, trans$y, trans$xend, trans$yend,
+      default.units = "native",
+      curvature = curvature, angle = angle, ncp = ncp,
+      square = FALSE, squareShape = 1, inflect = FALSE, open = TRUE,
+      gp = gpar(
+        col = alpha(trans$colour, trans$alpha),
+        lwd = trans$size * .pt,
+        lty = trans$linetype,
+        lineend = trans$lineend),
+      arrow = arrow
+    )
+  }
+)
diff --git a/R/geom-defaults.r b/R/geom-defaults.r
index f21f247..44b11a3 100644
--- a/R/geom-defaults.r
+++ b/R/geom-defaults.r
@@ -1,28 +1,41 @@
 #' Modify geom/stat aesthetic defaults for future plots
 #'
-#' @param stat,geom name of geom/stat to modify
-#' @param new named list of aesthetics
+#' @param stat,geom Name of geom/stat to modify (like \code{"point"} or
+#'   \code{"bin"}), or a Geom/Stat object (like \code{GeomPoint} or
+#'   \code{StatBin}).
+#' @param new Named list of aesthetics.
 #' @export
 #' @examples
 #' update_geom_defaults("point", list(colour = "darkblue"))
-#' qplot(mpg, wt, data = mtcars)
+#' ggplot(mtcars, aes(mpg, wt)) + geom_point()
 #' update_geom_defaults("point", list(colour = "black"))
 #' @rdname update_defaults
 update_geom_defaults <- function(geom, new) {
-  g <- Geom$find(geom)
-  old <- g$default_aes()
+  if (is.character(geom)) {
+    g <- find_subclass("Geom", geom)
+  } else if (inherits(geom, "Geom")) {
+    g <- geom
+  } else {
+    stop('`geom` must be a string (like "point") or a Geom object (like GeomPoint).',
+      call. = FALSE)
+  }
 
-  aes <- defaults(new, old)
-
-  g$default_aes <- eval(substitute(function(.) aes, list(aes = aes)))
+  old <- g$default_aes
+  g$default_aes <- defaults(new, old)
 }
 
 #' @rdname update_defaults
 #' @export
 update_stat_defaults <- function(stat, new) {
-  g <- Stat$find(stat)
-  old <- g$default_aes()
+  if (is.character(stat)) {
+    g <- find_subclass("Stat", stat)
+  } else if (inherits(stat, "Stat")) {
+    g <- stat
+  } else {
+    stop('`stat` must be a string (like "point") or a Stat object (like StatBin).',
+      call. = FALSE)
+  }
 
-  aes <- defaults(new, old)
-  g$default_aes <- eval(substitute(function(.) aes, list(aes = aes)))
+  old <- g$default_aes
+  g$default_aes <- defaults(new, old)
 }
diff --git a/R/geom-density.r b/R/geom-density.r
new file mode 100644
index 0000000..01f521c
--- /dev/null
+++ b/R/geom-density.r
@@ -0,0 +1,77 @@
+#' Display a smooth density estimate.
+#'
+#' A kernel density estimate, useful for display the distribution of variables
+#' with underlying smoothness.
+#'
+#' @section Aesthetics:
+#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "density")}
+#'
+#' @seealso See \code{\link{geom_histogram}}, \code{\link{geom_freqpoly}} for
+#'   other methods of displaying continuous distribution.
+#'   See \code{\link{geom_violin}} for a compact density display.
+#' @inheritParams geom_point
+#' @param geom,stat Use to override the default connection between
+#'   \code{geom_density} and \code{stat_density}.
+#' @export
+#' @examples
+#' ggplot(diamonds, aes(carat)) +
+#'   geom_density()
+#'
+#' ggplot(diamonds, aes(carat)) +
+#'   geom_density(adjust = 1/5)
+#' ggplot(diamonds, aes(carat)) +
+#'   geom_density(adjust = 5)
+#'
+#' ggplot(diamonds, aes(depth, colour = cut)) +
+#'   geom_density() +
+#'   xlim(55, 70)
+#' ggplot(diamonds, aes(depth, fill = cut, colour = cut)) +
+#'   geom_density(alpha = 0.1) +
+#'   xlim(55, 70)
+#'
+#' \donttest{
+#' # Stacked density plots: if you want to create a stacked density plot, you
+#' # probably want to 'count' (density * n) variable instead of the default
+#' # density
+#'
+#' # Loses marginal densities
+#' ggplot(diamonds, aes(carat, fill = cut)) +
+#'   geom_density(position = "stack")
+#' # Preserves marginal densities
+#' ggplot(diamonds, aes(carat, ..count.., fill = cut)) +
+#'   geom_density(position = "stack")
+#'
+#' # You can use position="fill" to produce a conditional density estimate
+#' ggplot(diamonds, aes(carat, ..count.., fill = cut)) +
+#'   geom_density(position = "fill")
+#' }
+geom_density <- function(mapping = NULL, data = NULL, stat = "density",
+                         position = "identity", na.rm = FALSE,
+                         show.legend = NA, inherit.aes = TRUE, ...) {
+
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomDensity,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+#' @include geom-ribbon.r
+GeomDensity <- ggproto("GeomDensity", GeomArea,
+  default_aes = defaults(
+    aes(fill = NA, weight = 1, colour = "black", alpha = NA),
+    GeomArea$default_aes
+  )
+)
diff --git a/R/geom-density2d.r b/R/geom-density2d.r
new file mode 100644
index 0000000..29dd2ce
--- /dev/null
+++ b/R/geom-density2d.r
@@ -0,0 +1,72 @@
+#' Contours from a 2d density estimate.
+#'
+#' Perform a 2D kernel density estimation using kde2d and display the
+#' results with contours. This can be useful for dealing with overplotting.
+#'
+#' @section Aesthetics:
+#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "density_2d")}
+#'
+#' @seealso \code{\link{geom_contour}} for contour drawing geom,
+#'  \code{\link{stat_sum}} for another way of dealing with overplotting
+#' @param geom,stat Use to override the default connection between
+#'   \code{geom_density_2d} and \code{stat_density_2d}.
+#' @inheritParams geom_point
+#' @inheritParams geom_path
+#' @export
+#' @examples
+#' m <- ggplot(faithful, aes(x = eruptions, y = waiting)) +
+#'  geom_point() +
+#'  xlim(0.5, 6) +
+#'  ylim(40, 110)
+#' m + geom_density_2d()
+#' \donttest{
+#' m + stat_density_2d(aes(fill = ..level..), geom = "polygon")
+#'
+#' set.seed(4393)
+#' dsmall <- diamonds[sample(nrow(diamonds), 1000), ]
+#' d <- ggplot(dsmall, aes(x, y))
+#' # If you map an aesthetic to a categorical variable, you will get a
+#' # set of contours for each value of that variable
+#' d + geom_density_2d(aes(colour = cut))
+#'
+#' # If we turn contouring off, we can use use geoms like tiles:
+#' d + stat_density_2d(geom = "raster", aes(fill = ..density..), contour = FALSE)
+#' # Or points:
+#' d + stat_density_2d(geom = "point", aes(size = ..density..), n = 20, contour = FALSE)
+#' }
+geom_density_2d <- function(mapping = NULL, data = NULL, stat = "density2d",
+                           position = "identity", lineend = "butt",
+                           linejoin = "round", linemitre = 1,
+                           na.rm = FALSE, show.legend = NA, inherit.aes = TRUE,
+                           ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomDensity2d,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      lineend = lineend,
+      linejoin = linejoin,
+      linemitre = linemitre,
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @export
+#' @rdname geom_density_2d
+#' @usage NULL
+geom_density2d <- geom_density_2d
+
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomDensity2d <- ggproto("GeomDensity2d", GeomPath,
+  default_aes = aes(colour = "#3366FF", size = 0.5, linetype = 1, alpha = NA)
+)
diff --git a/R/geom-dotplot.r b/R/geom-dotplot.r
index 9cda82c..eefeef2 100644
--- a/R/geom-dotplot.r
+++ b/R/geom-dotplot.r
@@ -20,16 +20,6 @@
 #' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "dotplot")}
 #'
 #' @inheritParams geom_point
-#' @param binaxis which axis to bin along "x" (default) or "y"
-#' @param method "dotdensity" (default) for dot-density binning, or
-#'   "histodot" for fixed bin widths (like stat_bin)
-#' @param binwidth When \code{method} is "dotdensity", this specifies maximum bin width.
-#'    When method is "histodot", this specifies bin width.
-#'   Defaults to 1/30 of the range of the data
-#' @param binpositions When \code{method} is "dotdensity", "bygroup" (default)
-#'   determines positions of the bins for each group separately. "all" determines
-#'   positions of the bins with all the data taken together; this is used for
-#'   aligning dot stacks across multiple groups.
 #' @param stackdir which direction to stack the dots. "up" (default),
 #'   "down", "center", "centerwhole" (centered, but with dots aligned)
 #' @param stackratio how close to stack the dots. Default is 1, where dots just
@@ -38,13 +28,38 @@
 #' @param stackgroups should dots be stacked across groups? This has the effect
 #'   that \code{position = "stack"} should have, but can't (because this geom has
 #'   some odd properties).
+#' @param binaxis The axis to bin along, "x" (default) or "y"
+#' @param method "dotdensity" (default) for dot-density binning, or
+#'   "histodot" for fixed bin widths (like stat_bin)
+#' @param binwidth When \code{method} is "dotdensity", this specifies maximum bin
+#'   width. When \code{method} is "histodot", this specifies bin width.
+#'   Defaults to 1/30 of the range of the data
+#' @param binpositions When \code{method} is "dotdensity", "bygroup" (default)
+#'   determines positions of the bins for each group separately. "all" determines
+#'   positions of the bins with all the data taken together; this is used for
+#'   aligning dot stacks across multiple groups.
+#' @param origin When \code{method} is "histodot", origin of first bin
+#' @param right When \code{method} is "histodot", should intervals be closed
+#'   on the right (a, b], or not [a, b)
+#' @param width When \code{binaxis} is "y", the spacing of the dot stacks
+#'   for dodging.
+#' @param drop If TRUE, remove all bins with zero counts
+#' @section Computed variables:
+#' \describe{
+#'   \item{x}{center of each bin, if binaxis is "x"}
+#'   \item{y}{center of each bin, if binaxis is "x"}
+#'   \item{binwidth}{max width of each bin if method is "dotdensity";
+#'     width of each bin if method is "histodot"}
+#'   \item{count}{number of points in bin}
+#'   \item{ncount}{count, scaled to maximum of 1}
+#'   \item{density}{density of points in bin, scaled to integrate to 1,
+#'     if method is "histodot"}
+#'   \item{ndensity}{density, scaled to maximum of 1, if method is "histodot"}
+#' }
 #' @export
-#'
 #' @references Wilkinson, L. (1999) Dot plots. The American Statistician,
 #'    53(3), 276-281.
-#'
 #' @examples
-#'
 #' ggplot(mtcars, aes(x = mpg)) + geom_dotplot()
 #' ggplot(mtcars, aes(x = mpg)) + geom_dotplot(binwidth = 1.5)
 #'
@@ -60,15 +75,15 @@
 #'
 #' # y axis isn't really meaningful, so hide it
 #' ggplot(mtcars, aes(x = mpg)) + geom_dotplot(binwidth = 1.5) +
-#'   scale_y_continuous(name = "", breaks = NULL)
+#'   scale_y_continuous(NULL, breaks = NULL)
 #'
 #' # Overlap dots vertically
 #' ggplot(mtcars, aes(x = mpg)) + geom_dotplot(binwidth = 1.5, stackratio = .7)
 #'
 #' # Expand dot diameter
-#' ggplot(mtcars, aes(x  =mpg)) + geom_dotplot(binwidth = 1.5, dotsize = 1.25)
-#'
+#' ggplot(mtcars, aes(x = mpg)) + geom_dotplot(binwidth = 1.5, dotsize = 1.25)
 #'
+#' \donttest{
 #' # Examples with stacking along y axis instead of x
 #' ggplot(mtcars, aes(x = 1, y = mpg)) +
 #'   geom_dotplot(binaxis = "y", stackdir = "center")
@@ -95,67 +110,68 @@
 #'
 #' ggplot(mtcars, aes(x = 1, y = mpg, fill = factor(cyl))) +
 #'   geom_dotplot(binaxis = "y", stackgroups = TRUE, binwidth = 1, method = "histodot")
-#'
-#' # Use qplot instead
-#' qplot(mpg, data = mtcars, geom = "dotplot")
-#'
-geom_dotplot <- function (mapping = NULL, data = NULL, stat = "bindot", position = "identity",
-na.rm = FALSE, binwidth = NULL, binaxis = "x", method="dotdensity", binpositions = "bygroup", stackdir = "up",
-stackratio = 1, dotsize = 1, stackgroups = FALSE, ...) {
-  GeomDotplot$new(mapping = mapping, data = data, stat = stat, position = position,
-  na.rm = na.rm, binwidth = binwidth, binaxis = binaxis, method = method, binpositions = binpositions,
-  stackdir = stackdir, stackratio = stackratio, dotsize = dotsize, stackgroups = stackgroups, ...)
+#' }
+geom_dotplot <- function(mapping = NULL, data = NULL,
+                         position = "identity", binwidth = NULL, binaxis = "x",
+                         method = "dotdensity", binpositions = "bygroup",
+                         stackdir = "up", stackratio = 1, dotsize = 1,
+                         stackgroups = FALSE, origin = NULL, right = TRUE,
+                         width = 0.9, drop = FALSE, na.rm = FALSE,
+                         show.legend = NA, inherit.aes = TRUE, ...) {
+  # If identical(position, "stack") or position is position_stack(), tell them
+  # to use stackgroups=TRUE instead. Need to use identical() instead of ==,
+  # because == will fail if object is position_stack() or position_dodge()
+  if (!is.null(position) &&
+      (identical(position, "stack") || (inherits(position, "PositionStack"))))
+    message("position=\"stack\" doesn't work properly with geom_dotplot. Use stackgroups=TRUE instead.")
+
+  if (stackgroups && method == "dotdensity" && binpositions == "bygroup")
+    message('geom_dotplot called with stackgroups=TRUE and method="dotdensity". You probably want to set binpositions="all"')
+
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatBindot,
+    geom = GeomDotplot,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    # Need to make sure that the binaxis goes to both the stat and the geom
+    params = list(
+      binaxis = binaxis,
+      binwidth = binwidth,
+      binpositions = binpositions,
+      method = method,
+      origin = origin,
+      right = right,
+      width = width,
+      drop = drop,
+      stackdir = stackdir,
+      stackratio = stackratio,
+      dotsize = dotsize,
+      stackgroups = stackgroups,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-GeomDotplot <- proto(Geom, {
-  objname <- "dotplot"
-
-  new <- function(., mapping = NULL, data = NULL, stat = NULL, position = NULL, ...){
-    # This code is adapted from Layer$new. It's needed to pull out the stat_params
-    # and geom_params, then manually add binaxis to both sets of params. Otherwise
-    # Layer$new will give binaxis only to the geom.
-
-    stat <- Stat$find(stat)
-    match.params <- function(possible, params) {
-      if ("..." %in% names(possible)) {
-        params
-      } else {
-        params[match(names(possible), names(params), nomatch = 0)]
-      }
-    }
-
-    params <- list(...)
-    # American names must be changed here so that they'll go to geom_params;
-    # otherwise they'll end up in stat_params
-    params <- rename_aes(params)
-
-    geom_params <- match.params(.$parameters(), params)
-    stat_params <- match.params(stat$parameters(), params)
-    stat_params <- stat_params[setdiff(names(stat_params), names(geom_params))]
-    # Add back binaxis
-    stat_params <- c(stat_params, binaxis=params$binaxis)
-
-    # If identical(position, "stack") or position is position_stack() (the test
-    #  is kind of complex), tell them to use stackgroups=TRUE instead. Need to
-    #  use identical() instead of ==, because == will fail if object is
-    #  position_stack() or position_dodge()
-    if (!is.null(position) && (identical(position, "stack") || (is.proto(position) && position$objname == "stack")))
-      message("position=\"stack\" doesn't work properly with geom_dotplot. Use stackgroups=TRUE instead.")
-
-    if (params$stackgroups && params$method == "dotdensity" && params$binpositions == "bygroup")
-      message('geom_dotplot called with stackgroups=TRUE and method="dotdensity". You probably want to set binpositions="all"')
-
-    do.call("layer", list(mapping = mapping, data = data, stat = stat, geom = ., position = position,
-                          geom_params = geom_params, stat_params = stat_params, ...))
-  }
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomDotplot <- ggproto("GeomDotplot", Geom,
+  required_aes = c("x", "y"),
+  non_missing_aes = c("size", "shape"),
 
+  default_aes = aes(colour = "black", fill = "black", alpha = NA),
 
-  reparameterise <- function(., df, params) {
-    df$width <- df$width %||%
-      params$width %||% (resolution(df$x, FALSE) * 0.9)
+  setup_data = function(data, params) {
+    data$width <- data$width %||%
+      params$width %||% (resolution(data$x, FALSE) * 0.9)
 
     # Set up the stacking function and range
-    if(is.null(params$stackdir) || params$stackdir == "up") {
+    if (is.null(params$stackdir) || params$stackdir == "up") {
       stackdots <- function(a)  a - .5
       stackaxismin <- 0
       stackaxismax <- 1
@@ -175,7 +191,7 @@ GeomDotplot <- proto(Geom, {
 
 
     # Fill the bins: at a given x (or y), if count=3, make 3 entries at that x
-    df <- df[rep(1:nrow(df), df$count), ]
+    data <- data[rep(1:nrow(data), data$count), ]
 
     # Next part will set the position of each dot within each stack
     # If stackgroups=TRUE, split only on x (or y) and panel; if not stacking, also split by group
@@ -185,7 +201,7 @@ GeomDotplot <- proto(Geom, {
       plyvars <- c(plyvars, "group")
 
     # Within each x, or x+group, set countidx=1,2,3, and set stackpos according to stack function
-    df <- ddply(df, plyvars, function(xx) {
+    data <- plyr::ddply(data, plyvars, function(xx) {
             xx$countidx <- 1:nrow(xx)
             xx$stackpos <- stackdots(xx$countidx)
             xx
@@ -197,11 +213,11 @@ GeomDotplot <- proto(Geom, {
       # ymin, ymax, xmin, and xmax define the bounding rectangle for each stack
       # Can't do bounding box per dot, because y position isn't real.
       # After position code is rewritten, each dot should have its own bounding box.
-      df$xmin <- df$x - df$binwidth / 2
-      df$xmax <- df$x + df$binwidth / 2
-      df$ymin <- stackaxismin
-      df$ymax <- stackaxismax
-      df$y    <- 0
+      data$xmin <- data$x - data$binwidth / 2
+      data$xmax <- data$x + data$binwidth / 2
+      data$ymin <- stackaxismin
+      data$ymax <- stackaxismax
+      data$y    <- 0
 
     } else if (params$binaxis == "y") {
       # ymin, ymax, xmin, and xmax define the bounding rectangle for each stack
@@ -210,69 +226,48 @@ GeomDotplot <- proto(Geom, {
       # works. They're just set to the standard x +- width/2 so that dot clusters
       # can be dodged like other geoms.
       # After position code is rewritten, each dot should have its own bounding box.
-      df <- ddply(df, .(group), transform,
+      data <- plyr::ddply(data, "group", transform,
             ymin = min(y) - binwidth[1] / 2,
             ymax = max(y) + binwidth[1] / 2)
 
-      df$xmin <- df$x + df$width * stackaxismin
-      df$xmax <- df$x + df$width * stackaxismax
+      data$xmin <- data$x + data$width * stackaxismin
+      data$xmax <- data$x + data$width * stackaxismax
       # Unlike with y above, don't change x because it will cause problems with dodging
     }
-    df
-  }
-
+    data
+  },
 
-  draw <- function(., data, scales, coordinates, na.rm = FALSE, binaxis = "x",
-                   stackdir = "up", stackratio = 1, dotsize = 1, stackgroups = FALSE, ...) {
 
-    data <- remove_missing(data, na.rm, c("x", "y", "size", "shape"), name = "geom_dotplot")
-    if (empty(data)) return(zeroGrob())
-
-    if (!is.linear(coordinates)) {
+  draw_group = function(data, panel_scales, coord, na.rm = FALSE,
+                        binaxis = "x", stackdir = "up", stackratio = 1,
+                        dotsize = 1, stackgroups = FALSE) {
+    if (!coord$is_linear()) {
       warning("geom_dotplot does not work properly with non-linear coordinates.")
     }
 
-    tdata <- coord_transform(coordinates, data, scales)
+    tdata <- coord$transform(data, panel_scales)
 
     # Swap axes if using coord_flip
-    if ("flip" %in% attr(coordinates, "class"))
-      binaxis <- ifelse (binaxis == "x", "y", "x")
+    if (inherits(coord, "CoordFlip"))
+      binaxis <- ifelse(binaxis == "x", "y", "x")
 
     if (binaxis == "x") {
       stackaxis = "y"
-      dotdianpc <- dotsize * tdata$binwidth[1] / (max(scales$x.range) - min(scales$x.range))
+      dotdianpc <- dotsize * tdata$binwidth[1] / (max(panel_scales$x.range) - min(panel_scales$x.range))
 
     } else if (binaxis == "y") {
       stackaxis = "x"
-      dotdianpc <- dotsize * tdata$binwidth[1] / (max(scales$y.range) - min(scales$y.range))
+      dotdianpc <- dotsize * tdata$binwidth[1] / (max(panel_scales$y.range) - min(panel_scales$y.range))
     }
 
-    ggname(.$my_name(),
+    ggname("geom_dotplot",
       dotstackGrob(stackaxis = stackaxis, x = tdata$x, y = tdata$y, dotdia = dotdianpc,
                   stackposition = tdata$stackpos, stackratio = stackratio,
                   default.units = "npc",
                   gp = gpar(col = alpha(tdata$colour, tdata$alpha),
                             fill = alpha(tdata$fill, tdata$alpha)))
     )
-  }
-
-  guide_geom <- function(.) "dotplot"
-  draw_legend <- function(., data, ...) {
-    data$shape <- 21
-
-    data <- aesdefaults(data, .$default_aes(), list(...))
-
-    with(data,
-      pointsGrob(0.5, 0.5, size = unit(.5, "npc"), pch = shape,
-        gp = gpar(
-          col = alpha(colour, alpha),
-          fill = alpha(fill, alpha))
-      )
-    )
-  }
-
-  default_stat <- function(.) StatBindot
-  required_aes <- c("x", "y")
-  default_aes <- function(.) aes(y=..count.., colour="black", fill = "black", alpha = NA)
+  },
 
-})
+  draw_key = draw_key_dotplot
+)
diff --git a/R/geom-error.r b/R/geom-error.r
deleted file mode 100644
index 08f22c0..0000000
--- a/R/geom-error.r
+++ /dev/null
@@ -1,81 +0,0 @@
-#' Error bars.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "errorbar")}
-#'
-#' @seealso \code{\link{geom_pointrange}}: range indicated by straight line,
-#'   with point in the middle; \code{\link{geom_linerange}}: range indicated
-#'   by straight line; \code{\link{geom_crossbar}}: hollow bar with middle
-#'   indicated by horizontal line; \code{\link{stat_summary}}: examples of
-#'   these guys in use, \code{\link{geom_smooth}} for continuous analog
-#' @inheritParams geom_point
-#' @export
-#' @examples
-#' # Create a simple example dataset
-#' df <- data.frame(
-#'   trt = factor(c(1, 1, 2, 2)),
-#'   resp = c(1, 5, 3, 4),
-#'   group = factor(c(1, 2, 1, 2)),
-#'   se = c(0.1, 0.3, 0.3, 0.2)
-#' )
-#' df2 <- df[c(1,3),]
-#'
-#' # Define the top and bottom of the errorbars
-#' limits <- aes(ymax = resp + se, ymin=resp - se)
-#'
-#' p <- ggplot(df, aes(fill=group, y=resp, x=trt))
-#' p + geom_bar(position="dodge", stat="identity")
-#'
-#' # Because the bars and errorbars have different widths
-#' # we need to specify how wide the objects we are dodging are
-#' dodge <- position_dodge(width=0.9)
-#' p + geom_bar(position=dodge) + geom_errorbar(limits, position=dodge, width=0.25)
-#'
-#' p <- ggplot(df2, aes(fill=group, y=resp, x=trt))
-#' p + geom_bar(position=dodge)
-#' p + geom_bar(position=dodge) + geom_errorbar(limits, position=dodge, width=0.25)
-#'
-#' p <- ggplot(df, aes(colour=group, y=resp, x=trt))
-#' p + geom_point() + geom_errorbar(limits, width=0.2)
-#' p + geom_pointrange(limits)
-#' p + geom_crossbar(limits, width=0.2)
-#'
-#' # If we want to draw lines, we need to manually set the
-#' # groups which define the lines - here the groups in the
-#' # original dataframe
-#' p + geom_line(aes(group=group)) + geom_errorbar(limits, width=0.2)
-geom_errorbar <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity", ...) {
-  GeomErrorbar$new(mapping = mapping, data = data, stat = stat, position = position, ...)
-}
-
-GeomErrorbar <- proto(Geom, {
-  objname <- "errorbar"
-
-  default_stat <- function(.) StatIdentity
-  default_aes <- function(.) aes(colour = "black", size=0.5, linetype=1, width=0.5, alpha = NA)
-  guide_geom <- function(.) "path"
-  required_aes <- c("x", "ymin", "ymax")
-
-  reparameterise <- function(., df, params) {
-    df$width <- df$width %||%
-      params$width %||% (resolution(df$x, FALSE) * 0.9)
-
-    transform(df,
-      xmin = x - width / 2, xmax = x + width / 2, width = NULL
-    )
-  }
-
-  draw <- function(., data, scales, coordinates, width = NULL, ...) {
-    GeomPath$draw(with(data, data.frame(
-      x = as.vector(rbind(xmin, xmax, NA, x,    x,    NA, xmin, xmax)),
-      y = as.vector(rbind(ymax, ymax, NA, ymax, ymin, NA, ymin, ymin)),
-      colour = rep(colour, each = 8),
-      alpha = rep(alpha, each = 8),
-      size = rep(size, each = 8),
-      linetype = rep(linetype, each = 8),
-      group = rep(1:(nrow(data)), each = 8),
-      stringsAsFactors = FALSE,
-      row.names = 1:(nrow(data) * 8)
-    )), scales, coordinates, ...)
-  }
-})
diff --git a/R/geom-errorbar.r b/R/geom-errorbar.r
new file mode 100644
index 0000000..f42ec52
--- /dev/null
+++ b/R/geom-errorbar.r
@@ -0,0 +1,55 @@
+#' @export
+#' @rdname geom_linerange
+geom_errorbar <- function(mapping = NULL, data = NULL, stat = "identity",
+                          position = "identity", na.rm = FALSE,
+                          show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomErrorbar,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomErrorbar <- ggproto("GeomErrorbar", Geom,
+  default_aes = aes(colour = "black", size = 0.5, linetype = 1, width = 0.5,
+    alpha = NA),
+
+  draw_key = draw_key_path,
+
+  required_aes = c("x", "ymin", "ymax"),
+
+  setup_data = function(data, params) {
+    data$width <- data$width %||%
+      params$width %||% (resolution(data$x, FALSE) * 0.9)
+
+    transform(data,
+      xmin = x - width / 2, xmax = x + width / 2, width = NULL
+    )
+  },
+
+  draw_panel = function(data, panel_scales, coord, width = NULL) {
+    GeomPath$draw_panel(data.frame(
+      x = as.vector(rbind(data$xmin, data$xmax, NA, data$x,    data$x,    NA, data$xmin, data$xmax)),
+      y = as.vector(rbind(data$ymax, data$ymax, NA, data$ymax, data$ymin, NA, data$ymin, data$ymin)),
+      colour = rep(data$colour, each = 8),
+      alpha = rep(data$alpha, each = 8),
+      size = rep(data$size, each = 8),
+      linetype = rep(data$linetype, each = 8),
+      group = rep(1:(nrow(data)), each = 8),
+      stringsAsFactors = FALSE,
+      row.names = 1:(nrow(data) * 8)
+    ), panel_scales, coord)
+  }
+)
diff --git a/R/geom-errorbarh.r b/R/geom-errorbarh.r
new file mode 100644
index 0000000..2682fcd
--- /dev/null
+++ b/R/geom-errorbarh.r
@@ -0,0 +1,77 @@
+#' Horizontal error bars
+#'
+#' @section Aesthetics:
+#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "errorbarh")}
+#'
+#' @seealso \code{\link{geom_errorbar}}: vertical error bars
+#' @inheritParams geom_point
+#' @export
+#' @examples
+#' df <- data.frame(
+#'   trt = factor(c(1, 1, 2, 2)),
+#'   resp = c(1, 5, 3, 4),
+#'   group = factor(c(1, 2, 1, 2)),
+#'   se = c(0.1, 0.3, 0.3, 0.2)
+#' )
+#'
+#' # Define the top and bottom of the errorbars
+#'
+#' p <- ggplot(df, aes(resp, trt, colour = group))
+#' p + geom_point() +
+#'   geom_errorbarh(aes(xmax = resp + se, xmin = resp - se))
+#' p + geom_point() +
+#'   geom_errorbarh(aes(xmax = resp + se, xmin = resp - se, height = .2))
+geom_errorbarh <- function(mapping = NULL, data = NULL, stat = "identity",
+                           position = "identity", na.rm = FALSE,
+                           show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomErrorbarh,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomErrorbarh <- ggproto("GeomErrorbarh", Geom,
+  default_aes = aes(colour = "black", size = 0.5, linetype = 1, height = 0.5,
+    alpha = NA),
+
+  draw_key = draw_key_path,
+
+  required_aes = c("x", "xmin", "xmax", "y"),
+
+  setup_data = function(data, params) {
+    data$height <- data$height %||%
+      params$height %||% (resolution(data$y, FALSE) * 0.9)
+
+    transform(data,
+      ymin = y - height / 2, ymax = y + height / 2, height = NULL
+    )
+  },
+
+  draw_panel = function(data, panel_scales, coord, height = NULL) {
+    GeomPath$draw_panel(data.frame(
+      x = as.vector(rbind(data$xmax, data$xmax, NA, data$xmax, data$xmin, NA, data$xmin, data$xmin)),
+      y = as.vector(rbind(data$ymin, data$ymax, NA, data$y,    data$y,    NA, data$ymin, data$ymax)),
+      colour = rep(data$colour, each = 8),
+      alpha = rep(data$alpha, each = 8),
+      size = rep(data$size, each = 8),
+      linetype = rep(data$linetype, each = 8),
+      group = rep(1:(nrow(data)), each = 8),
+      stringsAsFactors = FALSE,
+      row.names = 1:(nrow(data) * 8)
+    ), panel_scales, coord)
+  }
+)
diff --git a/R/geom-errorh.r b/R/geom-errorh.r
deleted file mode 100644
index 9953b6c..0000000
--- a/R/geom-errorh.r
+++ /dev/null
@@ -1,59 +0,0 @@
-#' Horizontal error bars
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "errorbarh")}
-#'
-#' @seealso \code{\link{geom_errorbar}}: vertical error bars
-#' @inheritParams geom_point
-#' @export
-#' @examples
-#' df <- data.frame(
-#'   trt = factor(c(1, 1, 2, 2)),
-#'   resp = c(1, 5, 3, 4),
-#'   group = factor(c(1, 2, 1, 2)),
-#'   se = c(0.1, 0.3, 0.3, 0.2)
-#' )
-#'
-#' # Define the top and bottom of the errorbars
-#'
-#' p <- ggplot(df, aes(resp, trt, colour = group))
-#' p + geom_point() +
-#'   geom_errorbarh(aes(xmax = resp + se, xmin = resp - se))
-#' p + geom_point() +
-#'   geom_errorbarh(aes(xmax = resp + se, xmin = resp - se, height = .2))
-geom_errorbarh <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity", ...) {
-  GeomErrorbarh$new(mapping = mapping, data = data, stat = stat, position = position, ...)
-}
-
-GeomErrorbarh <- proto(Geom, {
-  objname <- "errorbarh"
-
-  default_stat <- function(.) StatIdentity
-  default_aes <- function(.) aes(colour = "black", size=0.5, linetype=1, height=0.5, alpha = NA)
-  guide_geom <- function(.) "path"
-  required_aes <- c("x", "xmin", "xmax", "y")
-
-  reparameterise <- function(., df, params) {
-    df$height <- df$height %||%
-      params$height %||% (resolution(df$y, FALSE) * 0.9)
-
-    transform(df,
-      ymin = y - height / 2, ymax = y + height / 2, height = NULL
-    )
-  }
-
-  draw <- function(., data, scales, coordinates, height = NULL, ...) {
-    GeomPath$draw(with(data, data.frame(
-      x = as.vector(rbind(xmax, xmax, NA, xmax, xmin, NA, xmin, xmin)),
-      y = as.vector(rbind(ymin, ymax, NA, y,    y,    NA, ymin, ymax)),
-      colour = rep(colour, each = 8),
-      alpha = rep(alpha, each = 8),
-      size = rep(size, each = 8),
-      linetype = rep(linetype, each = 8),
-      group = rep(1:(nrow(data)), each = 8),
-      stringsAsFactors = FALSE,
-      row.names = 1:(nrow(data) * 8)
-    )), scales, coordinates, ...)
-  }
-
-})
diff --git a/R/geom-freqpoly.r b/R/geom-freqpoly.r
index 0f11912..02fd656 100644
--- a/R/geom-freqpoly.r
+++ b/R/geom-freqpoly.r
@@ -1,30 +1,19 @@
-#' Frequency polygon.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "freqpoly")}
-#'
-#' @seealso \code{\link{geom_histogram}}: histograms
-#' @inheritParams geom_point
 #' @export
-#' @examples
-#' qplot(carat, data = diamonds, geom = "freqpoly")
-#' qplot(carat, data = diamonds, geom = "freqpoly", binwidth = 0.1)
-#' qplot(carat, data = diamonds, geom = "freqpoly", binwidth = 0.01)
-#'
-#' qplot(price, data = diamonds, geom = "freqpoly", binwidth = 1000)
-#' qplot(price, data = diamonds, geom = "freqpoly", binwidth = 1000,
-#'   colour = color)
-#' qplot(price, ..density.., data = diamonds, geom = "freqpoly",
-#'   binwidth = 1000, colour = color)
-geom_freqpoly <- function (mapping = NULL, data = NULL, stat = "bin", position = "identity", ...) {
-  GeomFreqpoly$new(mapping = mapping, data = data, stat = stat, position = position, ...)
+#' @rdname geom_histogram
+geom_freqpoly <- function(mapping = NULL, data = NULL, stat = "bin",
+                          position = "identity", na.rm = FALSE,
+                          show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomPath,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
-
-GeomFreqpoly <- proto(Geom, {
-  objname <- "freqpoly"
-
-  default_aes <- function(.) GeomPath$default_aes()
-  default_stat <- function(.) StatBin
-  draw <- function(., ...) GeomPath$draw(...)
-  guide_geom <- function(.) "path"
-})
diff --git a/R/geom-hex.r b/R/geom-hex.r
index be4c2b1..b3f128b 100644
--- a/R/geom-hex.r
+++ b/R/geom-hex.r
@@ -1,32 +1,70 @@
-#' Hexagon bining.
+#' Hexagon binning.
 #'
 #' @section Aesthetics:
 #' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "hex")}
 #'
+#' @seealso \code{\link{stat_bin2d}} for rectangular binning
+#' @param geom,stat Override the default connection between \code{geom_hex} and
+#'   \code{stat_binhex.}
 #' @export
 #' @inheritParams geom_point
+#' @export
 #' @examples
-#' # See ?stat_binhex for examples
-geom_hex <- function (mapping = NULL, data = NULL, stat = "binhex", position = "identity", ...) {
-  GeomHex$new(mapping = mapping, data = data, stat = stat, position = position, ...)
+#' d <- ggplot(diamonds, aes(carat, price))
+#' d + geom_hex()
+#'
+#' \donttest{
+#' # You can control the size of the bins by specifying the number of
+#' # bins in each direction:
+#' d + geom_hex(bins = 10)
+#' d + geom_hex(bins = 30)
+#'
+#' # Or by specifying the width of the bins
+#' d + geom_hex(binwidth = c(1, 1000))
+#' d + geom_hex(binwidth = c(.1, 500))
+#' }
+geom_hex <- function(mapping = NULL, data = NULL, stat = "binhex",
+                     position = "identity", na.rm = FALSE,
+                     show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomHex,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-GeomHex <- proto(Geom, {
-  objname <- "hex"
 
-  draw <- function(., data, scales, coordinates, ...) {
-    with(coord_transform(coordinates, data, scales),
-      ggname(.$my_name(), hexGrob(x, y, col=colour,
-        fill = alpha(fill, alpha)))
-    )
-  }
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomHex <- ggproto("GeomHex", Geom,
+  draw_group = function(data, panel_scales, coord) {
+    if (!inherits(coord, "CoordCartesian")) {
+      stop("geom_hex() only works with Cartesian coordinates", call. = FALSE)
+    }
+
+    coord <- coord$transform(data, panel_scales)
+    ggname("geom_hex", hexGrob(
+      coord$x, coord$y, colour = coord$colour,
+      fill = alpha(coord$fill, coord$alpha)
+    ))
+  },
+
+  required_aes = c("x", "y"),
 
-  required_aes <- c("x", "y")
-  default_aes <- function(.) aes(colour=NA, fill = "grey50", size=0.5, alpha = NA)
-  default_stat <- function(.) StatBinhex
-  guide_geom <- function(.) "polygon"
+  default_aes = aes(colour = NA, fill = "grey50", size = 0.5, alpha = NA),
 
-})
+  draw_key = draw_key_polygon
+)
 
 
 # Draw hexagon grob
diff --git a/R/geom-histogram.r b/R/geom-histogram.r
new file mode 100644
index 0000000..90e2028
--- /dev/null
+++ b/R/geom-histogram.r
@@ -0,0 +1,95 @@
+#' Histograms and frequency polygons.
+#'
+#' Display a 1d distribution by dividing into bins and counting the number
+#' of observations in each bin. Histograms use bars; frequency polygons use
+#' lines.
+#'
+#' By default, \code{stat_bin} uses 30 bins - this is not a good default,
+#' but the idea is to get you experimenting with different binwidths. You
+#' may need to look at a few to uncover the full story behind your data.
+#'
+#' @section Aesthetics:
+#' \code{geom_histogram} uses the same aesthetics as \code{geom_bar};
+#' \code{geom_freqpoly} uses the same aesthetics as \code{geom_line}.
+#'
+#' @export
+#' @inheritParams geom_point
+#' @param geom,stat Use to override the default connection between
+#'   \code{geom_histogram}/\code{geom_freqpoly} and \code{stat_bin}.
+#' @examples
+#' ggplot(diamonds, aes(carat)) +
+#'   geom_histogram()
+#' ggplot(diamonds, aes(carat)) +
+#'   geom_histogram(binwidth = 0.01)
+#' ggplot(diamonds, aes(carat)) +
+#'   geom_histogram(bins = 200)
+#'
+#' # Rather than stacking histograms, it's easier to compare frequency
+#' # polygons
+#' ggplot(diamonds, aes(price, fill = cut)) +
+#'   geom_histogram(binwidth = 500)
+#' ggplot(diamonds, aes(price, colour = cut)) +
+#'   geom_freqpoly(binwidth = 500)
+#'
+#' # To make it easier to compare distributions with very different counts,
+#' # put density on the y axis instead of the default count
+#' ggplot(diamonds, aes(price, ..density.., colour = cut)) +
+#'   geom_freqpoly(binwidth = 500)
+#'
+#' if (require("ggplot2movies")) {
+#' # Often we don't want the height of the bar to represent the
+#' # count of observations, but the sum of some other variable.
+#' # For example, the following plot shows the number of movies
+#' # in each rating.
+#' m <- ggplot(movies, aes(rating))
+#' m + geom_histogram(binwidth = 0.1)
+#'
+#' # If, however, we want to see the number of votes cast in each
+#' # category, we need to weight by the votes variable
+#' m + geom_histogram(aes(weight = votes), binwidth = 0.1) + ylab("votes")
+#'
+#' # For transformed scales, binwidth applies to the transformed data.
+#' # The bins have constant width on the transformed scale.
+#' m + geom_histogram() + scale_x_log10()
+#' m + geom_histogram(binwidth = 0.05) + scale_x_log10()
+#'
+#' # For transformed coordinate systems, the binwidth applies to the
+#' # raw data. The bins have constant width on the original scale.
+#'
+#' # Using log scales does not work here, because the first
+#' # bar is anchored at zero, and so when transformed becomes negative
+#' # infinity. This is not a problem when transforming the scales, because
+#' # no observations have 0 ratings.
+#' m + geom_histogram(origin = 0) + coord_trans(x = "log10")
+#' # Use origin = 0, to make sure we don't take sqrt of negative values
+#' m + geom_histogram(origin = 0) + coord_trans(x = "sqrt")
+#'
+#' # You can also transform the y axis.  Remember that the base of the bars
+#' # has value 0, so log transformations are not appropriate
+#' m <- ggplot(movies, aes(x = rating))
+#' m + geom_histogram(binwidth = 0.5) + scale_y_sqrt()
+#' }
+#' rm(movies)
+geom_histogram <- function(mapping = NULL, data = NULL, stat = "bin",
+                           binwidth = NULL, bins = NULL, origin = NULL,
+                           right = FALSE, position = "stack", na.rm = FALSE,
+                           show.legend = NA, inherit.aes = TRUE, ...) {
+
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomBar,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      binwidth = binwidth,
+      bins = bins,
+      origin = origin,
+      right = right,
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
diff --git a/R/geom-hline.r b/R/geom-hline.r
index eb47ca5..ba8cec6 100644
--- a/R/geom-hline.r
+++ b/R/geom-hline.r
@@ -1,69 +1,53 @@
-#' Horizontal line.
-#'
-#' This geom allows you to annotate the plot with horizontal lines (see
-#' \code{\link{geom_vline}} and \code{\link{geom_abline}} for other types of
-#' lines).
-#'
-#' There are two ways to use it. You can either specify the intercept of
-#' the line in the call to the geom, in which case the line will be in the
-#' same position in every panel. Alternatively, you can supply a different
-#' intercept for each panel using a data.frame. See the examples for the
-#' differences
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "hline")}
-#'
-#' @seealso \code{\link{geom_vline}} for vertical lines,
-#'  \code{\link{geom_abline}} for lines defined by a slope and intercept,
-#'  \code{\link{geom_segment}} for a more general approach
-#' @export
-#' @inheritParams geom_point
-#' @param show_guide should a legend be drawn? (defaults to \code{FALSE})
-#' @examples
-#' p <- ggplot(mtcars, aes(x = wt, y=mpg)) + geom_point()
-#'
-#' p + geom_hline(aes(yintercept=mpg))
-#' p + geom_hline(yintercept=20)
-#' p + geom_hline(yintercept=seq(10, 30, by=5))
-#'
-#' # With coordinate transforms
-#' p + geom_hline(aes(yintercept=mpg)) + coord_equal()
-#' p + geom_hline(aes(yintercept=mpg)) + coord_flip()
-#' p + geom_hline(aes(yintercept=mpg)) + coord_polar()
-#'
-#' # To display different lines in different facets, you need to
-#' # create a data frame.
-#' p <- qplot(mpg, wt, data=mtcars, facets = vs ~ am)
-#'
-#' hline.data <- data.frame(z = 1:4, vs = c(0,0,1,1), am = c(0,1,0,1))
-#' p + geom_hline(aes(yintercept = z), hline.data)
-geom_hline <- function (mapping = NULL, data = NULL, stat = "hline", position = "identity", show_guide = FALSE, ...) {
-  GeomHline$new(mapping = mapping, data = data, stat = stat, position = position, show_guide = show_guide, ...)
-}
+#' @include stat-.r
+NULL
 
-GeomHline <- proto(Geom, {
-  objname <- "hline"
+#' @export
+#' @rdname geom_abline
+geom_hline <- function(mapping = NULL, data = NULL,
+                       ...,
+                       yintercept,
+                       na.rm = FALSE, show.legend = NA) {
 
-  new <- function(., data = NULL, mapping = NULL, yintercept = NULL, ...) {
-    if (is.numeric(yintercept)) {
-      data <- data.frame(yintercept = yintercept)
-      yintercept <- NULL
-      mapping <- aes_all(names(data))
-    }
-    .super$new(., data = data, mapping = mapping, inherit.aes = FALSE,
-      yintercept = yintercept, ...)
+  # Act like an annotation
+  if (!missing(yintercept)) {
+    data <- data.frame(yintercept = yintercept)
+    mapping <- aes(yintercept = yintercept)
+    show.legend <- FALSE
   }
 
-  draw <- function(., data, scales, coordinates, ...) {
-    ranges <- coord_range(coordinates, scales)
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatIdentity,
+    geom = GeomHline,
+    position = PositionIdentity,
+    show.legend = show.legend,
+    inherit.aes = FALSE,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomHline <- ggproto("GeomHline", Geom,
+  draw_panel = function(data, panel_scales, coord) {
+    ranges <- coord$range(panel_scales)
 
     data$x    <- ranges$x[1]
     data$xend <- ranges$x[2]
+    data$y    <- data$yintercept
+    data$yend <- data$yintercept
 
-    GeomSegment$draw(unique(data), scales, coordinates)
-  }
+    GeomSegment$draw_panel(unique(data), panel_scales, coord)
+  },
+
+  default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = NA),
+  required_aes = "yintercept",
 
-  default_stat <- function(.) StatHline
-  default_aes <- function(.) aes(colour="black", size=0.5, linetype=1, alpha = NA)
-  guide_geom <- function(.) "path"
-})
+  draw_key = draw_key_path
+)
diff --git a/R/geom-jitter.r b/R/geom-jitter.r
new file mode 100644
index 0000000..4dab784
--- /dev/null
+++ b/R/geom-jitter.r
@@ -0,0 +1,57 @@
+#' Points, jittered to reduce overplotting.
+#'
+#' The jitter geom is a convenient default for geom_point with position =
+#' 'jitter'. It's a useful way of handling overplotting caused by discreteness
+#' in smaller datasets.
+#'
+#' @section Aesthetics:
+#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "point")}
+#'
+#' @inheritParams geom_point
+#' @inheritParams position_jitter
+#' @seealso
+#'  \code{\link{geom_point}} for regular, unjittered points,
+#'  \code{\link{geom_boxplot}} for another way of looking at the conditional
+#'     distribution of a variable
+#' @export
+#' @examples
+#' p <- ggplot(mpg, aes(cyl, hwy))
+#' p + geom_point()
+#' p + geom_jitter()
+#'
+#' # Add aesthetic mappings
+#' p + geom_jitter(aes(colour = class))
+#'
+#' # Use smaller width/height to emphasise categories
+#' ggplot(mpg, aes(cyl, hwy)) + geom_jitter()
+#' ggplot(mpg, aes(cyl, hwy)) + geom_jitter(width = 0.25)
+#'
+#' # Use larger width/height to completely smooth away discreteness
+#' ggplot(mpg, aes(cty, hwy)) + geom_jitter()
+#' ggplot(mpg, aes(cty, hwy)) + geom_jitter(width = 0.5, height = 0.5)
+geom_jitter <- function(mapping = NULL, data = NULL,
+                        width = NULL, height = NULL, stat = "identity",
+                        position = "jitter", na.rm = FALSE,
+                        show.legend = NA, inherit.aes = TRUE, ...) {
+  if (!missing(width) || !missing(height)) {
+    if (!missing(position)) {
+      stop("Specify either `position` or `width`/`height`", call. = FALSE)
+    }
+
+    position <- position_jitter(width = width, height = height)
+  }
+
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomPoint,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
diff --git a/R/geom-label.R b/R/geom-label.R
new file mode 100644
index 0000000..34260b4
--- /dev/null
+++ b/R/geom-label.R
@@ -0,0 +1,141 @@
+#' @export
+#' @rdname geom_text
+#' @param label.padding Amount of padding around label. Defaults to 0.25 lines.
+#' @param label.r Radius of rounded corners. Defaults to 0.15 lines.
+#' @param label.size Size of label border, in mm.
+geom_label <- function(mapping = NULL, data = NULL, stat = "identity",
+                       position = "identity", parse = FALSE, ...,
+                       nudge_x = 0, nudge_y = 0,
+                       label.padding = unit(0.25, "lines"),
+                       label.r = unit(0.15, "lines"), label.size = 0.25,
+                       na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) {
+  if (!missing(nudge_x) || !missing(nudge_y)) {
+    if (!missing(position)) {
+      stop("Specify either `position` or `nudge_x`/`nudge_y`", call. = FALSE)
+    }
+
+    position <- position_nudge(nudge_x, nudge_y)
+  }
+
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomLabel,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      parse = parse,
+      label.padding = label.padding,
+      label.r = label.r,
+      label.size = label.size,
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomLabel <- ggproto("GeomLabel", Geom,
+  required_aes = c("x", "y", "label"),
+
+  default_aes = aes(
+    colour = "black", fill = "white", size = 3.88, angle = 0,
+    hjust = 0.5, vjust = 0.5, alpha = NA, family = "", fontface = 1,
+    lineheight = 1.2
+  ),
+
+  draw_panel = function(self, data, panel_scales, coord, parse = FALSE,
+                        na.rm = FALSE,
+                        label.padding = unit(0.25, "lines"),
+                        label.r = unit(0.15, "lines"),
+                        label.size = 0.25) {
+    lab <- data$label
+    if (parse) {
+      lab <- parse(text = as.character(lab))
+    }
+
+    data <- coord$transform(data, panel_scales)
+    if (is.character(data$vjust)) {
+      data$vjust <- compute_just(data$vjust, data$y)
+    }
+    if (is.character(data$hjust)) {
+      data$hjust <- compute_just(data$hjust, data$x)
+    }
+
+    grobs <- lapply(1:nrow(data), function(i) {
+      row <- data[i, , drop = FALSE]
+      labelGrob(lab[i],
+        x = unit(row$x, "native"),
+        y = unit(row$y, "native"),
+        just = c(row$hjust, row$vjust),
+        padding = label.padding,
+        r = label.r,
+        text.gp = gpar(
+          col = row$colour,
+          fontsize = row$size * .pt,
+          fontfamily = row$family,
+          fontface = row$fontface,
+          lineheight = row$lineheight
+        ),
+        rect.gp = gpar(
+          col = row$colour,
+          fill = alpha(row$fill, row$alpha),
+          lwd = label.size * .pt
+        )
+      )
+    })
+    class(grobs) <- "gList"
+
+    ggname("geom_label", grobTree(children = grobs))
+  },
+
+  draw_key = draw_key_label
+)
+
+labelGrob <- function(label, x = unit(0.5, "npc"), y = unit(0.5, "npc"),
+                      just = "center", padding = unit(0.25, "lines"), r = unit(0.1, "snpc"),
+                      default.units = "npc", name = NULL,
+                      text.gp = gpar(), rect.gp = gpar(fill = "white"), vp = NULL) {
+
+  stopifnot(length(label) == 1)
+
+  if (!is.unit(x))
+    x <- unit(x, default.units)
+  if (!is.unit(y))
+    y <- unit(y, default.units)
+
+  gTree(label = label, x = x, y = y, just = just, padding = padding, r = r,
+    name = name, text.gp = text.gp, rect.gp = rect.gp, vp = vp, cl = "labelgrob")
+}
+
+#' @export
+makeContent.labelgrob <- function(x) {
+  hj <- resolveHJust(x$just, NULL)
+  vj <- resolveVJust(x$just, NULL)
+
+  t <- textGrob(
+    x$label,
+    x$x + 2 * (0.5 - hj) * x$padding,
+    x$y + 2 * (0.5 - vj) * x$padding,
+    just = c(hj, vj),
+    gp = x$text.gp,
+    name = "text"
+  )
+
+  r <- roundrectGrob(x$x, x$y, default.units = "native",
+    width = grobWidth(t) + 2 * x$padding,
+    height = grobHeight(t) + 2 * x$padding,
+    just = c(hj, vj),
+    r = x$r,
+    gp = x$rect.gp,
+    name = "box"
+  )
+
+  setChildren(x, gList(r, t))
+}
diff --git a/R/geom-linerange.r b/R/geom-linerange.r
index 02e213e..f177599 100644
--- a/R/geom-linerange.r
+++ b/R/geom-linerange.r
@@ -1,52 +1,84 @@
-#' An interval represented by a vertical line.
+#' Vertical intervals: lines, crossbars & errorbars.
+#'
+#' Various ways of representing a vertical interval defined by \code{x},
+#' \code{ymin} and \code{ymax}.
 #'
 #' @section Aesthetics:
 #' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "linerange")}
 #'
-#' @seealso \code{\link{geom_errorbar}}: error bars;
-#'   \code{\link{geom_pointrange}}: range indicated by straight line, with
-#'   point in the middle; \code{\link{geom_crossbar}}: hollow bar with middle
-#'   indicated by horizontal line; \code{\link{stat_summary}}: examples of
-#'   these guys in use; \code{\link{geom_smooth}}: for continuous analog
+#' @param fatten A multiplicative factor used to increase the size of the
+#'   middle bar in \code{geom_crossbar()} and the middle point in
+#'   \code{geom_pointrange()}.
+#' @seealso
+#'  \code{\link{stat_summary}} for examples of these guys in use,
+#'  \code{\link{geom_smooth}} for continuous analog
 #' @export
 #' @inheritParams geom_point
 #' @examples
-#' # Generate data: means and standard errors of means for prices
-#' # for each type of cut
-#' dmod <- lm(price ~ cut, data=diamonds)
-#' cuts <- data.frame(cut = unique(diamonds$cut),
-#'   predict(dmod, data.frame(cut = unique(diamonds$cut)), se=TRUE)[c("fit","se.fit")])
+#' #' # Create a simple example dataset
+#' df <- data.frame(
+#'   trt = factor(c(1, 1, 2, 2)),
+#'   resp = c(1, 5, 3, 4),
+#'   group = factor(c(1, 2, 1, 2)),
+#'   upper = c(1.1, 5.3, 3.3, 4.2),
+#'   lower = c(0.8, 4.6, 2.4, 3.6)
+#' )
+#'
+#' p <- ggplot(df, aes(trt, resp, colour = group))
+#' p + geom_linerange(aes(ymin = lower, ymax = upper))
+#' p + geom_pointrange(aes(ymin = lower, ymax = upper))
+#' p + geom_crossbar(aes(ymin = lower, ymax = upper), width = 0.2)
+#' p + geom_errorbar(aes(ymin = lower, ymax = upper), width = 0.2)
 #'
-#' qplot(cut, fit, data=cuts)
-#' # With a bar chart, we are comparing lengths, so the y-axis is
-#' # automatically extended to include 0
-#' qplot(cut, fit, data=cuts, geom="bar")
+#' # Draw lines connecting group means
+#' p +
+#'   geom_line(aes(group = group)) +
+#'   geom_errorbar(aes(ymin = lower, ymax = upper), width = 0.2)
 #'
-#' # Display estimates and standard errors in various ways
-#' se <- ggplot(cuts, aes(cut, fit,
-#'   ymin = fit - se.fit, ymax=fit + se.fit, colour = cut))
-#' se + geom_linerange()
-#' se + geom_pointrange()
-#' se + geom_errorbar(width = 0.5)
-#' se + geom_crossbar(width = 0.5)
+#' # If you want to dodge bars and errorbars, you need to manually
+#' # specify the dodge width
+#' p <- ggplot(df, aes(trt, resp, fill = group))
+#' p +
+#'  geom_bar(position = "dodge", stat = "identity") +
+#'  geom_errorbar(aes(ymin = lower, ymax = upper), position = "dodge", width = 0.25)
 #'
-#' # Use coord_flip to flip the x and y axes
-#' se + geom_linerange() + coord_flip()
-geom_linerange <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity", ...) {
-  GeomLinerange$new(mapping = mapping, data = data, stat = stat, position = position, ...)
+#' # Because the bars and errorbars have different widths
+#' # we need to specify how wide the objects we are dodging are
+#' dodge <- position_dodge(width=0.9)
+#' p +
+#'   geom_bar(position = dodge, stat = "identity") +
+#'   geom_errorbar(aes(ymin = lower, ymax = upper), position = dodge, width = 0.25)
+geom_linerange <- function(mapping = NULL, data = NULL, stat = "identity",
+                           position = "identity", na.rm = FALSE,
+                           show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomLinerange,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-GeomLinerange <- proto(Geom, {
-  objname <- "linerange"
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomLinerange <- ggproto("GeomLinerange", Geom,
+  default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = NA),
 
-  default_stat <- function(.) StatIdentity
-  default_aes <- function(.) aes(colour = "black", size=0.5, linetype=1, alpha = NA)
-  guide_geom <- function(.) "path"
-  required_aes <- c("x", "ymin", "ymax")
+  draw_key = draw_key_vpath,
 
-  draw <- function(., data, scales, coordinates, ...) {
-    munched <- coord_transform(coordinates, data, scales)
-    ggname(.$my_name(), GeomSegment$draw(transform(data, xend=x, y=ymin, yend=ymax), scales, coordinates, ...))
-  }
+  required_aes = c("x", "ymin", "ymax"),
 
-})
+  draw_panel = function(data, panel_scales, coord) {
+    data <- transform(data, xend = x, y = ymin, yend = ymax)
+    ggname("geom_linerange", GeomSegment$draw_panel(data, panel_scales, coord))
+  }
+)
diff --git a/R/geom-map.r b/R/geom-map.r
index 89af85c..ce7b394 100644
--- a/R/geom-map.r
+++ b/R/geom-map.r
@@ -46,8 +46,7 @@ NULL
 #'
 #' # Better example
 #' crimes <- data.frame(state = tolower(rownames(USArrests)), USArrests)
-#' library(reshape2) # for melt
-#' crimesm <- melt(crimes, id = 1)
+#' crimesm <- reshape2::melt(crimes, id = 1)
 #' if (require(maps)) {
 #'   states_map <- map_data("state")
 #'   ggplot(crimes, aes(map_id = state)) +
@@ -60,8 +59,8 @@ NULL
 #'     expand_limits(x = states_map$long, y = states_map$lat) +
 #'     facet_wrap( ~ variable)
 #' }
-geom_map <- function(mapping = NULL, data = NULL, map, stat = "identity", ...) {
-
+geom_map <- function(mapping = NULL, data = NULL, map, stat = "identity",
+                     na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...) {
   # Get map input into correct form
   stopifnot(is.data.frame(map))
   if (!is.null(map$lat)) map$y <- map$lat
@@ -69,14 +68,28 @@ geom_map <- function(mapping = NULL, data = NULL, map, stat = "identity", ...) {
   if (!is.null(map$region)) map$id <- map$region
   stopifnot(all(c("x", "y", "id") %in% names(map)))
 
-  GeomMap$new(geom_params = list(map = map, ...), mapping = mapping,
-    data = data, stat = stat, ...)
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomMap,
+    position = PositionIdentity,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      map = map,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-GeomMap <- proto(GeomPolygon, {
-  objname <- "map"
-
-  draw_groups <- function(., data, scales, coordinates, map, ...) {
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomMap <- ggproto("GeomMap", GeomPolygon,
+  draw_panel = function(data, panel_scales, coord, map) {
     # Only use matching data and map ids
     common <- intersect(data$map_id, map$id)
     data <- data[data$map_id %in% common, , drop = FALSE]
@@ -84,7 +97,7 @@ GeomMap <- proto(GeomPolygon, {
 
     # Munch, then set up id variable for polygonGrob -
     # must be sequential integers
-    coords <- coord_munch(coordinates, map, scales)
+    coords <- coord_munch(coord, map, panel_scales)
     coords$group <- coords$group %||% coords$id
     grob_id <- match(coords$group, unique(coords$group))
 
@@ -95,9 +108,10 @@ GeomMap <- proto(GeomPolygon, {
     polygonGrob(coords$x, coords$y, default.units = "native", id = grob_id,
       gp = gpar(
         col = data$colour, fill = alpha(data$fill, data$alpha),
-        lwd = data$size * .pt))
-  }
-
-  required_aes <- c("map_id")
+        lwd = data$size * .pt
+      )
+    )
+  },
 
-})
+  required_aes = c("map_id")
+)
diff --git a/R/geom-path-.r b/R/geom-path-.r
deleted file mode 100644
index 72ef80d..0000000
--- a/R/geom-path-.r
+++ /dev/null
@@ -1,207 +0,0 @@
-#' Connect observations in original order
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "path")}
-#'
-#' @inheritParams geom_point
-#' @param lineend Line end style (round, butt, square)
-#' @param linejoin Line join style (round, mitre, bevel)
-#' @param linemitre Line mitre limit (number greater than 1)
-#' @param arrow Arrow specification, as created by ?grid::arrow
-#' @seealso \code{\link{geom_line}}: Functional (ordered) lines;
-#'  \code{\link{geom_polygon}}: Filled paths (polygons);
-#'  \code{\link{geom_segment}}: Line segments
-#' @export
-#' @examples
-#' \donttest{
-#' # Generate data
-#' library(plyr)
-#' myear <- ddply(movies, .(year), colwise(mean, .(length, rating)))
-#' p <- ggplot(myear, aes(length, rating))
-#' p + geom_path()
-#'
-#' # Add aesthetic mappings
-#' p + geom_path(aes(size = year))
-#' p + geom_path(aes(colour = year))
-#'
-#' # Change scale
-#' p + geom_path(aes(size = year)) + scale_size(range = c(1, 3))
-#'
-#' # Set aesthetics to fixed value
-#' p + geom_path(colour = "green")
-#'
-#' # Control line join parameters
-#' df <- data.frame(x = 1:3, y = c(4, 1, 9))
-#' base <- ggplot(df, aes(x, y))
-#' base + geom_path(size = 10)
-#' base + geom_path(size = 10, lineend = "round")
-#' base + geom_path(size = 10, linejoin = "mitre", lineend = "butt")
-#'
-#' # Use qplot instead
-#' qplot(length, rating, data=myear, geom="path")
-#'
-#' # Using economic data:
-#' # How is unemployment and personal savings rate related?
-#' qplot(unemploy/pop, psavert, data=economics)
-#' qplot(unemploy/pop, psavert, data=economics, geom="path")
-#' qplot(unemploy/pop, psavert, data=economics, geom="path", size=as.numeric(date))
-#'
-#' # How is rate of unemployment and length of unemployment?
-#' qplot(unemploy/pop, uempmed, data=economics)
-#' qplot(unemploy/pop, uempmed, data=economics, geom="path")
-#' qplot(unemploy/pop, uempmed, data=economics, geom="path") +
-#'   geom_point(data=head(economics, 1), colour="red") +
-#'   geom_point(data=tail(economics, 1), colour="blue")
-#' qplot(unemploy/pop, uempmed, data=economics, geom="path") +
-#'   geom_text(data=head(economics, 1), label="1967", colour="blue") +
-#'   geom_text(data=tail(economics, 1), label="2007", colour="blue")
-#'
-#' # geom_path removes missing values on the ends of a line.
-#' # use na.rm = T to suppress the warning message
-#' df <- data.frame(
-#'   x = 1:5,
-#'   y1 = c(1, 2, 3, 4, NA),
-#'   y2 = c(NA, 2, 3, 4, 5),
-#'   y3 = c(1, 2, NA, 4, 5),
-#'   y4 = c(1, 2, 3, 4, 5))
-#' qplot(x, y1, data = df, geom = c("point","line"))
-#' qplot(x, y2, data = df, geom = c("point","line"))
-#' qplot(x, y3, data = df, geom = c("point","line"))
-#' qplot(x, y4, data = df, geom = c("point","line"))
-#'
-#' # Setting line type vs colour/size
-#' # Line type needs to be applied to a line as a whole, so it can
-#' # not be used with colour or size that vary across a line
-#'
-#' x <- seq(0.01, .99, length=100)
-#' df <- data.frame(x = rep(x, 2), y = c(qlogis(x), 2 * qlogis(x)), group = rep(c("a","b"), each=100))
-#' p <- ggplot(df, aes(x=x, y=y, group=group))
-#'
-#' # Should work
-#' p + geom_line(linetype = 2)
-#' p + geom_line(aes(colour = group), linetype = 2)
-#' p + geom_line(aes(colour = x))
-#'
-#' # Should fail
-#' should_stop(p + geom_line(aes(colour = x), linetype=2))
-#'
-#' # Use the arrow parameter to add an arrow to the line
-#' # See ?grid::arrow for more details
-#' library(grid)
-#' c <- ggplot(economics, aes(x = date, y = pop))
-#' # Arrow defaults to "last"
-#' c + geom_path(arrow = arrow())
-#' c + geom_path(arrow = arrow(angle = 15, ends = "both", length = unit(0.6, "inches")))
-#' }
-geom_path <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity",
-lineend = "butt", linejoin = "round", linemitre = 1, na.rm = FALSE, arrow = NULL, ...) {
-  GeomPath$new(mapping = mapping, data = data, stat = stat, position = position,
-  lineend = lineend, linejoin = linejoin, linemitre = linemitre, na.rm = na.rm, arrow = arrow, ...)
-}
-
-GeomPath <- proto(Geom, {
-  objname <- "path"
-
-  draw_groups <- function(., ...) .$draw(...)
-
-  draw <- function(., data, scales, coordinates, arrow = NULL, lineend = "butt", linejoin = "round", linemitre = 1, ..., na.rm = FALSE) {
-    if (!anyDuplicated(data$group)) {
-      message("geom_path: Each group consist of only one observation. Do you need to adjust the group aesthetic?")
-    }
-
-    keep <- function(x) {
-      # from first non-missing to last non-missing
-      first <- match(FALSE, x, nomatch = 1) - 1
-      last <- length(x) - match(FALSE, rev(x), nomatch = 1) + 1
-      c(
-        rep(FALSE, first),
-        rep(TRUE, last - first),
-        rep(FALSE, length(x) - last))
-    }
-    # Drop missing values at the start or end of a line - can't drop in the
-    # middle since you expect those to be shown by a break in the line
-    missing <- !complete.cases(data[c("x", "y", "size", "colour",
-      "linetype")])
-    kept <- ave(missing, data$group, FUN=keep)
-    data <- data[kept, ]
-    # must be sorted on group
-    data <- arrange(data, group)
-
-    if (!all(kept) && !na.rm) {
-      warning("Removed ", sum(!kept), " rows containing missing values",
-        " (geom_path).", call. = FALSE)
-    }
-
-    munched <- coord_munch(coordinates, data, scales)
-
-    # Silently drop lines with less than two points, preserving order
-    rows <- ave(seq_len(nrow(munched)), munched$group, FUN = length)
-    munched <- munched[rows >= 2, ]
-    if (nrow(munched) < 2) return(zeroGrob())
-
-    # Work out whether we should use lines or segments
-    attr <- ddply(munched, .(group), function(df) {
-      data.frame(
-        solid = identical(unique(df$linetype), 1),
-        constant = nrow(unique(df[, c("alpha", "colour","size", "linetype")])) == 1
-      )
-    })
-    solid_lines <- all(attr$solid)
-    constant <- all(attr$constant)
-    if (!solid_lines && !constant) {
-      stop("geom_path: If you are using dotted or dashed lines",
-        ", colour, size and linetype must be constant over the line",
-        call.=FALSE)
-    }
-
-    # Work out grouping variables for grobs
-    n <- nrow(munched)
-    group_diff <- munched$group[-1] != munched$group[-n]
-    start <- c(TRUE, group_diff)
-    end <-   c(group_diff, TRUE)
-
-    if (!constant) {
-      with(munched,
-        segmentsGrob(
-          x[!end], y[!end], x[!start], y[!start],
-          default.units="native", arrow = arrow,
-          gp = gpar(
-            col = alpha(colour, alpha)[!end], fill = alpha(colour, alpha)[!end],
-            lwd = size[!end] * .pt, lty = linetype[!end],
-            lineend = lineend, linejoin = linejoin, linemitre = linemitre
-          )
-        )
-      )
-    } else {
-      id <- match(munched$group, unique(munched$group))
-      with(munched,
-        polylineGrob(
-          x, y, id = id,
-          default.units = "native", arrow = arrow,
-          gp = gpar(
-            col = alpha(colour, alpha)[start], fill = alpha(colour, alpha)[start],
-            lwd = size[start] * .pt, lty = linetype[start],
-            lineend = lineend, linejoin = linejoin, linemitre = linemitre)
-        )
-      )
-    }
-  }
-
-  draw_legend <- function(., data, ...) {
-    data$arrow <- NULL
-    data <- aesdefaults(data, .$default_aes(), list(...))
-
-    with(data,
-      ggname(.$my_name(), segmentsGrob(0.1, 0.5, 0.9, 0.5, default.units="npc",
-      gp=gpar(col=alpha(colour, alpha), lwd=size * .pt,
-        lty=linetype, lineend="butt")))
-    )
-  }
-
-  default_stat <- function(.) StatIdentity
-  required_aes <- c("x", "y")
-  default_aes <- function(.) aes(colour="black", size=0.5, linetype=1, alpha = NA)
-  guide_geom <- function(.) "path"
-
-})
-
diff --git a/R/geom-path-contour.r b/R/geom-path-contour.r
deleted file mode 100644
index 4a555c8..0000000
--- a/R/geom-path-contour.r
+++ /dev/null
@@ -1,25 +0,0 @@
-#' Display contours of a 3d surface in 2d.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "contour")}
-#'
-#' @inheritParams geom_point
-#' @inheritParams geom_path
-#' @seealso \code{\link{geom_density2d}}: 2d density contours
-#' @export
-#' @examples
-#' # See stat_contour for examples
-geom_contour <- function (mapping = NULL, data = NULL, stat = "contour", position = "identity",
-lineend = "butt", linejoin = "round", linemitre = 1, na.rm = FALSE, ...) {
-  GeomContour$new(mapping = mapping, data = data, stat = stat, position = position,
-  lineend = lineend, linejoin = linejoin, linemitre = linemitre, na.rm = na.rm, ...)
-}
-
-GeomContour <- proto(GeomPath, {
-  objname <- "contour"
-
-  default_aes <- function(.) aes(weight=1, colour="#3366FF", size = 0.5, linetype = 1, alpha = NA)
-
-  default_stat <- function(.) StatContour
-})
-
diff --git a/R/geom-path-density2d.r b/R/geom-path-density2d.r
deleted file mode 100644
index 7fff76e..0000000
--- a/R/geom-path-density2d.r
+++ /dev/null
@@ -1,29 +0,0 @@
-#' Contours from a 2d density estimate.
-#'
-#' Perform a 2D kernel density estimatation using kde2d and display the
-#' results with contours.
-#'
-#' This can be useful for dealing with overplotting.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "density2d")}
-#'
-#' @seealso \code{\link{geom_contour}} for contour drawing geom,
-#'  \code{\link{stat_sum}} for another way of dealing with overplotting
-#' @inheritParams geom_point
-#' @inheritParams geom_path
-#' @export
-#' @examples
-#' # See stat_density2d for examples
-geom_density2d <- function (mapping = NULL, data = NULL, stat = "density2d", position = "identity",
-lineend = "butt", linejoin = "round", linemitre = 1, na.rm = FALSE, ...) {
-  GeomDensity2d$new(mapping = mapping, data = data, stat = stat, position = position,
-  lineend = lineend, linejoin = linejoin, linemitre = linemitre, na.rm = na.rm, ...)
-}
-
-GeomDensity2d <- proto(GeomPath, {
-  objname <- "density2d"
-
-  default_stat <- function(.) StatDensity2d
-  default_aes <- function(.) aes(colour="#3366FF", size = 0.5, linetype = 1, alpha = NA)
-})
diff --git a/R/geom-path-line.r b/R/geom-path-line.r
deleted file mode 100644
index 80149ec..0000000
--- a/R/geom-path-line.r
+++ /dev/null
@@ -1,77 +0,0 @@
-#' Connect observations, ordered by x value.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "line")}
-#'
-#' @seealso \code{\link{geom_path}}: connect observations in data order,
-#'  \code{\link{geom_segment}}: draw line segments,
-#'  \code{\link{geom_ribbon}}: fill between line and x-axis
-#' @inheritParams geom_point
-#' @export
-#' @examples
-#' # Summarise number of movie ratings by year of movie
-#' mry <- do.call(rbind, by(movies, round(movies$rating), function(df) {
-#'   nums <- tapply(df$length, df$year, length)
-#'   data.frame(rating=round(df$rating[1]), year = as.numeric(names(nums)), number=as.vector(nums))
-#' }))
-#'
-#' p <- ggplot(mry, aes(x=year, y=number, group=rating))
-#' p + geom_line()
-#'
-#' # Add aesthetic mappings
-#' p + geom_line(aes(size = rating))
-#' p + geom_line(aes(colour = rating))
-#'
-#' # Change scale
-#' p + geom_line(aes(colour = rating)) + scale_colour_gradient(low="red")
-#' p + geom_line(aes(size = rating)) + scale_size(range = c(0.1, 3))
-#'
-#' # Set aesthetics to fixed value
-#' p + geom_line(colour = "red", size = 1)
-#'
-#' # Use qplot instead
-#' qplot(year, number, data=mry, group=rating, geom="line")
-#'
-#' # Using a time series
-#' qplot(date, pop, data=economics, geom="line")
-#' qplot(date, pop, data=economics, geom="line", log="y")
-#' qplot(date, pop, data=subset(economics, date > as.Date("2006-1-1")), geom="line")
-#' qplot(date, pop, data=economics, size=unemploy/pop, geom="line")
-#'
-#' # Use the arrow parameter to add an arrow to the line
-#' # See ?grid::arrow for more details
-#' c <- ggplot(economics, aes(x = date, y = pop))
-#' # Arrow defaults to "last"
-#' library(grid)
-#' c + geom_line(arrow = arrow())
-#' c + geom_line(arrow = arrow(angle = 15, ends = "both", type = "closed"))
-#'
-#' # See scale_date for examples of plotting multiple times series on
-#' # a single graph
-#'
-#' # A simple pcp example
-#'
-#' y2005 <- runif(300, 20, 120)
-#' y2010 <- y2005 * runif(300, -1.05, 1.5)
-#' group <- rep(LETTERS[1:3], each = 100)
-#'
-#' df <- data.frame(id = seq_along(group), group, y2005, y2010)
-#' library(reshape2) # for melt
-#' dfm <- melt(df, id.var = c("id", "group"))
-#' ggplot(dfm, aes(variable, value, group = id, colour = group)) +
-#'   geom_path(alpha = 0.5)
-geom_line <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity", ...) {
-  GeomLine$new(mapping = mapping, data = data, stat = stat, position = position, ...)
-}
-
-GeomLine <- proto(GeomPath, {
-  objname <- "line"
-
-  draw <- function(., data, scales, coordinates, arrow = NULL, ...) {
-    data <- data[order(data$group, data$x), ]
-    GeomPath$draw(data, scales, coordinates, arrow, ...)
-  }
-
-  default_stat <- function(.) StatIdentity
-
-})
diff --git a/R/geom-path-step.r b/R/geom-path-step.r
deleted file mode 100644
index 9705967..0000000
--- a/R/geom-path-step.r
+++ /dev/null
@@ -1,73 +0,0 @@
-#' Connect observations by stairs.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "step")}
-#'
-#' @inheritParams geom_point
-#' @param direction direction of stairs: 'vh' for vertical then horizontal, or
-#'   'hv' for horizontal then vertical
-#' @export
-#' @examples
-#' # Simple quantiles/ECDF from examples(plot)
-#' x <- sort(rnorm(47))
-#' qplot(seq_along(x), x, geom="step")
-#'
-#' # Steps go horizontally, then vertically (default)
-#' qplot(seq_along(x), x, geom="step", direction = "hv")
-#' plot(x, type = "s")
-#' # Steps go vertically, then horizontally
-#' qplot(seq_along(x), x, geom="step", direction = "vh")
-#' plot(x, type = "S")
-#'
-#' # Also works with other aesthetics
-#' df <- data.frame(
-#'   x = sort(rnorm(50)),
-#'   trt = sample(c("a", "b"), 50, rep = TRUE)
-#' )
-#' qplot(seq_along(x), x, data = df, geom="step", colour = trt)
-geom_step <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity",
-direction = "hv", ...) {
-  GeomStep$new(mapping = mapping, data = data, stat = stat, position = position,
-  direction = direction, ...)
-}
-
-GeomStep <- proto(Geom, {
-  objname <- "step"
-
-  details <- "Equivalent to plot(type='s')."
-
-  default_aes <- function(.) aes(colour="black", size=0.5, linetype=1, alpha = NA)
-
-  draw <- function(., data, scales, coordinates, direction = "hv", ...) {
-    data <- stairstep(data, direction)
-    GeomPath$draw(data, scales, coordinates, ...)
-  }
-  guide_geom <- function(.) "path"
-
-  default_stat <- function(.) StatIdentity
-})
-
-
-# Calculate stairsteps
-# Used by \code{\link{geom_step}}
-#
-# @keyword internal
-stairstep <- function(data, direction="hv") {
-  direction <- match.arg(direction, c("hv", "vh"))
-  data <- as.data.frame(data)[order(data$x), ]
-  n <- nrow(data)
-
-  if (direction == "vh") {
-    xs <- rep(1:n, each = 2)[-2*n]
-    ys <- c(1, rep(2:n, each=2))
-  } else {
-    ys <- rep(1:n, each = 2)[-2*n]
-    xs <- c(1, rep(2:n, each=2))
-  }
-
-  data.frame(
-    x = data$x[xs],
-    y = data$y[ys],
-    data[xs, setdiff(names(data), c("x", "y"))]
-  )
-}
diff --git a/R/geom-path.r b/R/geom-path.r
new file mode 100644
index 0000000..97e91cb
--- /dev/null
+++ b/R/geom-path.r
@@ -0,0 +1,306 @@
+#' Connect observations.
+#'
+#' \code{geom_path()} connects the observations in the order in which they appear
+#' in the data. \code{geom_line()} connects them in order of the variable on the
+#' x axis. \code{geom_step()} creates a stairstep plot, highlighting exactly
+#' when changes occur.
+#'
+#' @section Aesthetics:
+#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "path")}
+#'
+#' @inheritParams geom_point
+#' @param lineend Line end style (round, butt, square)
+#' @param linejoin Line join style (round, mitre, bevel)
+#' @param linemitre Line mitre limit (number greater than 1)
+#' @param arrow Arrow specification, as created by \code{\link[grid]{arrow}}
+#' @seealso
+#'  \code{\link{geom_polygon}}: Filled paths (polygons);
+#'  \code{\link{geom_segment}}: Line segments
+#' @export
+#' @examples
+#' # geom_line() is suitable for time series
+#' ggplot(economics, aes(date, unemploy)) + geom_line()
+#' ggplot(economics_long, aes(date, value01, colour = variable)) +
+#'   geom_line()
+#'
+#' # geom_step() is useful when you want to highlight exactly when
+#' # the y value chanes
+#' recent <- economics[economics$date > as.Date("2013-01-01"), ]
+#' ggplot(recent, aes(date, unemploy)) + geom_line()
+#' ggplot(recent, aes(date, unemploy)) + geom_step()
+#'
+#' # geom_path lets you explore how two variables are related over time,
+#' # e.g. unemployment and personal savings rate
+#' m <- ggplot(economics, aes(unemploy/pop, psavert))
+#' m + geom_path()
+#' m + geom_path(aes(colour = as.numeric(date)))
+#'
+#' # Changing parameters ----------------------------------------------
+#' ggplot(economics, aes(date, unemploy)) +
+#'   geom_line(colour = "red")
+#'
+#' # Use the arrow parameter to add an arrow to the line
+#' # See ?arrow for more details
+#' c <- ggplot(economics, aes(x = date, y = pop))
+#' c + geom_line(arrow = arrow())
+#' c + geom_line(
+#'   arrow = arrow(angle = 15, ends = "both", type = "closed")
+#' )
+#'
+#' # Control line join parameters
+#' df <- data.frame(x = 1:3, y = c(4, 1, 9))
+#' base <- ggplot(df, aes(x, y))
+#' base + geom_path(size = 10)
+#' base + geom_path(size = 10, lineend = "round")
+#' base + geom_path(size = 10, linejoin = "mitre", lineend = "butt")
+#'
+#' # NAs break the line. Use na.rm = T to suppress the warning message
+#' df <- data.frame(
+#'   x = 1:5,
+#'   y1 = c(1, 2, 3, 4, NA),
+#'   y2 = c(NA, 2, 3, 4, 5),
+#'   y3 = c(1, 2, NA, 4, 5)
+#' )
+#' ggplot(df, aes(x, y1)) + geom_point() + geom_line()
+#' ggplot(df, aes(x, y2)) + geom_point() + geom_line()
+#' ggplot(df, aes(x, y3)) + geom_point() + geom_line()
+#'
+#' \donttest{
+#' # Setting line type vs colour/size
+#' # Line type needs to be applied to a line as a whole, so it can
+#' # not be used with colour or size that vary across a line
+#' x <- seq(0.01, .99, length.out = 100)
+#' df <- data.frame(
+#'   x = rep(x, 2),
+#'   y = c(qlogis(x), 2 * qlogis(x)),
+#'   group = rep(c("a","b"),
+#'   each = 100)
+#' )
+#' p <- ggplot(df, aes(x=x, y=y, group=group))
+#' # These work
+#' p + geom_line(linetype = 2)
+#' p + geom_line(aes(colour = group), linetype = 2)
+#' p + geom_line(aes(colour = x))
+#' # But this doesn't
+#' should_stop(p + geom_line(aes(colour = x), linetype=2))
+#' }
+geom_path <- function(mapping = NULL, data = NULL, stat = "identity",
+                      position = "identity", lineend = "butt",
+                      linejoin = "round", linemitre = 1, na.rm = FALSE,
+                      arrow = NULL, show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomPath,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      lineend = lineend,
+      linejoin = linejoin,
+      linemitre = linemitre,
+      arrow = arrow,
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomPath <- ggproto("GeomPath", Geom,
+  required_aes = c("x", "y"),
+
+  default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = NA),
+
+  handle_na = function(data, params) {
+    keep <- function(x) {
+      # from first non-missing to last non-missing
+      first <- match(FALSE, x, nomatch = 1) - 1
+      last <- length(x) - match(FALSE, rev(x), nomatch = 1) + 1
+      c(
+        rep(FALSE, first),
+        rep(TRUE, last - first),
+        rep(FALSE, length(x) - last)
+      )
+    }
+    # Drop missing values at the start or end of a line - can't drop in the
+    # middle since you expect those to be shown by a break in the line
+    missing <- !stats::complete.cases(data[c("x", "y", "size", "colour",
+      "linetype")])
+    kept <- stats::ave(missing, data$group, FUN = keep)
+    data <- data[kept, ]
+
+    if (!all(kept) && !params$na.rm) {
+      warning("Removed ", sum(!kept), " rows containing missing values",
+        " (geom_path).", call. = FALSE)
+    }
+
+    data
+  },
+
+  draw_panel = function(data, panel_scales, coord, arrow = NULL,
+                        lineend = "butt", linejoin = "round", linemitre = 1,
+                        na.rm = FALSE) {
+    if (!anyDuplicated(data$group)) {
+      message_wrap("geom_path: Each group consists of only one observation. ",
+        "Do you need to adjust the group aesthetic?")
+    }
+
+    # must be sorted on group
+    data <- data[order(data$group), , drop = FALSE]
+    munched <- coord_munch(coord, data, panel_scales)
+
+    # Silently drop lines with less than two points, preserving order
+    rows <- stats::ave(seq_len(nrow(munched)), munched$group, FUN = length)
+    munched <- munched[rows >= 2, ]
+    if (nrow(munched) < 2) return(zeroGrob())
+
+    # Work out whether we should use lines or segments
+    attr <- plyr::ddply(munched, "group", function(df) {
+      data.frame(
+        solid = identical(unique(df$linetype), 1),
+        constant = nrow(unique(df[, c("alpha", "colour","size", "linetype")])) == 1
+      )
+    })
+    solid_lines <- all(attr$solid)
+    constant <- all(attr$constant)
+    if (!solid_lines && !constant) {
+      stop("geom_path: If you are using dotted or dashed lines",
+        ", colour, size and linetype must be constant over the line",
+        call. = FALSE)
+    }
+
+    # Work out grouping variables for grobs
+    n <- nrow(munched)
+    group_diff <- munched$group[-1] != munched$group[-n]
+    start <- c(TRUE, group_diff)
+    end <-   c(group_diff, TRUE)
+
+    if (!constant) {
+      segmentsGrob(
+        munched$x[!end], munched$y[!end], munched$x[!start], munched$y[!start],
+        default.units = "native", arrow = arrow,
+        gp = gpar(
+          col = alpha(munched$colour, munched$alpha)[!end],
+          fill = alpha(munched$colour, munched$alpha)[!end],
+          lwd = munched$size[!end] * .pt,
+          lty = munched$linetype[!end],
+          lineend = lineend,
+          linejoin = linejoin,
+          linemitre = linemitre
+        )
+      )
+    } else {
+      id <- match(munched$group, unique(munched$group))
+      polylineGrob(
+        munched$x, munched$y, id = id,
+        default.units = "native", arrow = arrow,
+        gp = gpar(
+          col = alpha(munched$colour, munched$alpha)[start],
+          fill = alpha(munched$colour, munched$alpha)[start],
+          lwd = munched$size[start] * .pt,
+          lty = munched$linetype[start],
+          lineend = lineend,
+          linejoin = linejoin,
+          linemitre = linemitre
+        )
+      )
+    }
+  },
+
+  draw_key = draw_key_path
+)
+
+#' @export
+#' @rdname geom_path
+geom_line <- function(mapping = NULL, data = NULL, stat = "identity",
+                      position = "identity", na.rm = FALSE,
+                      show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomLine,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+#' @include geom-path.r
+GeomLine <- ggproto("GeomLine", GeomPath,
+  setup_data = function(data, params) {
+    data[order(data$PANEL, data$group, data$x), ]
+  }
+)
+
+#' @param direction direction of stairs: 'vh' for vertical then horizontal, or
+#'   'hv' for horizontal then vertical
+#' @export
+#' @rdname geom_path
+geom_step <- function(mapping = NULL, data = NULL, stat = "identity",
+                      position = "identity", direction = "hv",
+                      na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomStep,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      direction = direction,
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+#' @include geom-path.r
+GeomStep <- ggproto("GeomStep", GeomPath,
+  draw_panel = function(data, panel_scales, coord, direction = "hv") {
+    data <- plyr::ddply(data, "group", stairstep, direction = direction)
+    GeomPath$draw_panel(data, panel_scales, coord)
+  }
+)
+
+# Calculate stairsteps
+# Used by \code{\link{geom_step}}
+#
+# @keyword internal
+stairstep <- function(data, direction="hv") {
+  direction <- match.arg(direction, c("hv", "vh"))
+  data <- as.data.frame(data)[order(data$x), ]
+  n <- nrow(data)
+
+  if (direction == "vh") {
+    xs <- rep(1:n, each = 2)[-2*n]
+    ys <- c(1, rep(2:n, each = 2))
+  } else {
+    ys <- rep(1:n, each = 2)[-2*n]
+    xs <- c(1, rep(2:n, each = 2))
+  }
+
+  data.frame(
+    x = data$x[xs],
+    y = data$y[ys],
+    data[xs, setdiff(names(data), c("x", "y"))]
+  )
+}
diff --git a/R/geom-point-.r b/R/geom-point-.r
deleted file mode 100644
index 27e3468..0000000
--- a/R/geom-point-.r
+++ /dev/null
@@ -1,143 +0,0 @@
-#' Points, as for a scatterplot
-#'
-#' The point geom is used to create scatterplots.
-#'
-#' The scatterplot is useful for displaying the relationship between two
-#' continuous variables, although it can also be used with one continuous
-#' and one categorical variable, or two categorical variables.  See
-#' \code{\link{geom_jitter}} for possibilities.
-#'
-#' The \emph{bubblechart} is a scatterplot with a third variable mapped to
-#' the size of points.  There are no special names for scatterplots where
-#' another variable is mapped to point shape or colour, however.
-#'
-#' The biggest potential problem with a scatterplot is overplotting: whenever
-#' you have more than a few points, points may be plotted on top of one
-#' another. This can severely distort the visual appearance of the plot.
-#' There is no one solution to this problem, but there are some techniques
-#' that can help.  You can add additional information with
-#' \code{\link{stat_smooth}}, \code{\link{stat_quantile}} or
-#' \code{\link{stat_density2d}}.  If you have few unique x values,
-#' \code{\link{geom_boxplot}} may also be useful.  Alternatively, you can
-#' summarise the number of points at each location and display that in some
-#' way, using \code{\link{stat_sum}}. Another technique is to use transparent
-#' points, \code{geom_point(alpha = 0.05)}.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "point")}
-#'
-#' @seealso \code{\link{scale_size}} to see scale area of points, instead of
-#'   radius, \code{\link{geom_jitter}} to jitter points to reduce (mild)
-#'   overplotting
-#' @param mapping The aesthetic mapping, usually constructed with
-#'    \code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-#'    at the layer level if you are overriding the plot defaults.
-#' @param data A layer specific dataset - only needed if you want to override
-#'    the plot defaults.
-#' @param stat The statistical transformation to use on the data for this
-#'    layer.
-#' @param position The position adjustment to use for overlapping points
-#'    on this layer
-#' @param na.rm If \code{FALSE} (the default), removes missing values with
-#'    a warning.  If \code{TRUE} silently removes missing values.
-#' @param ... other arguments passed on to \code{\link{layer}}. This can
-#'   include aesthetics whose values you want to set, not map. See
-#'   \code{\link{layer}} for more details.
-#' @export
-#' @examples
-#' \donttest{
-#' p <- ggplot(mtcars, aes(wt, mpg))
-#' p + geom_point()
-#'
-#' # Add aesthetic mappings
-#' p + geom_point(aes(colour = qsec))
-#' p + geom_point(aes(alpha = qsec))
-#' p + geom_point(aes(colour = factor(cyl)))
-#' p + geom_point(aes(shape = factor(cyl)))
-#' p + geom_point(aes(size = qsec))
-#'
-#' # Change scales
-#' p + geom_point(aes(colour = cyl)) + scale_colour_gradient(low = "blue")
-#' p + geom_point(aes(size = qsec)) + scale_size_area()
-#' p + geom_point(aes(shape = factor(cyl))) + scale_shape(solid = FALSE)
-#'
-#' # Set aesthetics to fixed value
-#' p + geom_point(colour = "red", size = 3)
-#' qplot(wt, mpg, data = mtcars, colour = I("red"), size = I(3))
-#'
-#' # Varying alpha is useful for large datasets
-#' d <- ggplot(diamonds, aes(carat, price))
-#' d + geom_point(alpha = 1/10)
-#' d + geom_point(alpha = 1/20)
-#' d + geom_point(alpha = 1/100)
-#'
-#' # You can create interesting shapes by layering multiple points of
-#' # different sizes
-#' p <- ggplot(mtcars, aes(mpg, wt))
-#' p + geom_point(colour="grey50", size = 4) + geom_point(aes(colour = cyl))
-#' p + aes(shape = factor(cyl)) +
-#'   geom_point(aes(colour = factor(cyl)), size = 4) +
-#'   geom_point(colour="grey90", size = 1.5)
-#' p + geom_point(colour="black", size = 4.5) +
-#'   geom_point(colour="pink", size = 4) +
-#'   geom_point(aes(shape = factor(cyl)))
-#'
-#' # These extra layers don't usually appear in the legend, but we can
-#' # force their inclusion
-#' p + geom_point(colour="black", size = 4.5, show_guide = TRUE) +
-#'   geom_point(colour="pink", size = 4, show_guide = TRUE) +
-#'   geom_point(aes(shape = factor(cyl)))
-#'
-#' # Transparent points:
-#' qplot(mpg, wt, data = mtcars, size = I(5), alpha = I(0.2))
-#'
-#' # geom_point warns when missing values have been dropped from the data set
-#' # and not plotted, you can turn this off by setting na.rm = TRUE
-#' mtcars2 <- transform(mtcars, mpg = ifelse(runif(32) < 0.2, NA, mpg))
-#' qplot(wt, mpg, data = mtcars2)
-#' qplot(wt, mpg, data = mtcars2, na.rm = TRUE)
-#'
-#' # Use qplot instead
-#' qplot(wt, mpg, data = mtcars)
-#' qplot(wt, mpg, data = mtcars, colour = factor(cyl))
-#' qplot(wt, mpg, data = mtcars, colour = I("red"))
-#' }
-geom_point <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity",
-na.rm = FALSE, ...) {
-  GeomPoint$new(mapping = mapping, data = data, stat = stat, position = position,
-  na.rm = na.rm, ...)
-}
-
-GeomPoint <- proto(Geom, {
-  objname <- "point"
-
-  draw_groups <- function(., ...) .$draw(...)
-  draw <- function(., data, scales, coordinates, na.rm = FALSE, ...) {
-    data <- remove_missing(data, na.rm,
-      c("x", "y", "size", "shape"), name = "geom_point")
-    if (empty(data)) return(zeroGrob())
-
-    with(coord_transform(coordinates, data, scales),
-      ggname(.$my_name(), pointsGrob(x, y, size=unit(size, "mm"), pch=shape,
-      gp=gpar(col=alpha(colour, alpha), fill = alpha(fill, alpha), fontsize = size * .pt)))
-    )
-  }
-
-  draw_legend <- function(., data, ...) {
-    data <- aesdefaults(data, .$default_aes(), list(...))
-
-    with(data,
-      pointsGrob(0.5, 0.5, size=unit(size, "mm"), pch=shape,
-      gp=gpar(
-        col=alpha(colour, alpha),
-        fill=alpha(fill, alpha),
-        fontsize = size * .pt)
-      )
-    )
-  }
-
-  default_stat <- function(.) StatIdentity
-  required_aes <- c("x", "y")
-  default_aes <- function(.) aes(shape=16, colour="black", size=2, fill = NA, alpha = NA)
-
-})
diff --git a/R/geom-point-jitter.r b/R/geom-point-jitter.r
deleted file mode 100644
index bd3f5b4..0000000
--- a/R/geom-point-jitter.r
+++ /dev/null
@@ -1,46 +0,0 @@
-#' Points, jittered to reduce overplotting.
-#'
-#' The jitter geom is a convenient default for geom_point with position =
-#' 'jitter'.  See \code{\link{position_jitter}} to see how to adjust amount
-#' of jittering.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "jitter")}
-#'
-#' @inheritParams geom_point
-#' @seealso
-#'  \code{\link{geom_point}} for regular, unjittered points,
-#'  \code{\link{geom_boxplot}} for another way of looking at the conditional
-#'     distribution of a variable,
-#'  \code{\link{position_jitter}} for examples of using jittering with other
-#'    geoms
-#' @export
-#' @examples
-#' p <- ggplot(mpg, aes(displ, hwy))
-#' p + geom_point()
-#' p + geom_point(position = "jitter")
-#'
-#' # Add aesthetic mappings
-#' p + geom_jitter(aes(colour = cyl))
-#'
-#' # Vary parameters
-#' p + geom_jitter(position = position_jitter(width = .5))
-#' p + geom_jitter(position = position_jitter(height = .5))
-#'
-#' # Use qplot instead
-#' qplot(displ, hwy, data = mpg, geom = "jitter")
-#' qplot(class, hwy, data = mpg, geom = "jitter")
-#' qplot(class, hwy, data = mpg, geom = c("boxplot", "jitter"))
-#' qplot(class, hwy, data = mpg, geom = c("jitter", "boxplot"))
-geom_jitter <- function (mapping = NULL, data = NULL, stat = "identity", position = "jitter",
-na.rm = FALSE, ...) {
-  GeomJitter$new(mapping = mapping, data = data, stat = stat, position = position,
-  na.rm = na.rm, ...)
-}
-
-GeomJitter <- proto(GeomPoint, {
-  objname <- "jitter"
-
-  default_stat <- function(.) StatIdentity
-  default_pos <- function(.) PositionJitter
-})
diff --git a/R/geom-point.r b/R/geom-point.r
new file mode 100644
index 0000000..b67fc35
--- /dev/null
+++ b/R/geom-point.r
@@ -0,0 +1,164 @@
+#' Points, as for a scatterplot
+#'
+#' The point geom is used to create scatterplots.
+#'
+#' The scatterplot is useful for displaying the relationship between two
+#' continuous variables, although it can also be used with one continuous
+#' and one categorical variable, or two categorical variables.  See
+#' \code{\link{geom_jitter}} for possibilities.
+#'
+#' The \emph{bubblechart} is a scatterplot with a third variable mapped to
+#' the size of points.  There are no special names for scatterplots where
+#' another variable is mapped to point shape or colour, however.
+#'
+#' The biggest potential problem with a scatterplot is overplotting: whenever
+#' you have more than a few points, points may be plotted on top of one
+#' another. This can severely distort the visual appearance of the plot.
+#' There is no one solution to this problem, but there are some techniques
+#' that can help.  You can add additional information with
+#' \code{\link{geom_smooth}}, \code{\link{geom_quantile}} or
+#' \code{\link{geom_density_2d}}.  If you have few unique x values,
+#' \code{\link{geom_boxplot}} may also be useful.  Alternatively, you can
+#' summarise the number of points at each location and display that in some
+#' way, using \code{\link{stat_sum}}. Another technique is to use transparent
+#' points, e.g. \code{geom_point(alpha = 0.05)}.
+#'
+#' @section Aesthetics:
+#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "point")}
+#'
+#' @seealso \code{\link{scale_size}} to see scale area of points, instead of
+#'   radius, \code{\link{geom_jitter}} to jitter points to reduce (mild)
+#'   overplotting
+#' @param mapping Set of aesthetic mappings created by \code{\link{aes}} or
+#'   \code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+#'   default), is combined with the default mapping at the top level of the
+#'   plot. You only need to supply \code{mapping} if there isn't a mapping
+#'   defined for the plot.
+#' @param data A data frame. If specified, overrides the default data frame
+#'   defined at the top level of the plot.
+#' @param position Position adjustment, either as a string, or the result of
+#'  a call to a position adjustment function.
+#' @param stat The statistical transformation to use on the data for this
+#'    layer, as a string.
+#' @param na.rm If \code{FALSE} (the default), removes missing values with
+#'    a warning.  If \code{TRUE} silently removes missing values.
+#' @param show.legend logical. Should this layer be included in the legends?
+#'   \code{NA}, the default, includes if any aesthetics are mapped.
+#'   \code{FALSE} never includes, and \code{TRUE} always includes.
+#' @param inherit.aes If \code{FALSE}, overrides the default aesthetics,
+#'   rather than combining with them. This is most useful for helper functions
+#'   that define both data and aesthetics and shouldn't inherit behaviour from
+#'   the default plot specification, e.g. \code{\link{borders}}.
+#' @param ... other arguments passed on to \code{\link{layer}}. There are
+#'   three types of arguments you can use here:
+#'
+#'   \itemize{
+#'   \item Aesthetics: to set an aesthetic to a fixed value, like
+#'      \code{color = "red"} or \code{size = 3}.
+#'   \item Other arguments to the layer, for example you override the
+#'     default \code{stat} associated with the layer.
+#'   \item Other arguments passed on to the stat.
+#'   }
+#' @inheritParams layer
+#' @export
+#' @examples
+#' p <- ggplot(mtcars, aes(wt, mpg))
+#' p + geom_point()
+#'
+#' # Add aesthetic mappings
+#' p + geom_point(aes(colour = factor(cyl)))
+#' p + geom_point(aes(shape = factor(cyl)))
+#' p + geom_point(aes(size = qsec))
+#'
+#' # Change scales
+#' p + geom_point(aes(colour = cyl)) + scale_colour_gradient(low = "blue")
+#' p + geom_point(aes(shape = factor(cyl))) + scale_shape(solid = FALSE)
+#'
+#' # Set aesthetics to fixed value
+#' ggplot(mtcars, aes(wt, mpg)) + geom_point(colour = "red", size = 3)
+#'
+#' \donttest{
+#' # Varying alpha is useful for large datasets
+#' d <- ggplot(diamonds, aes(carat, price))
+#' d + geom_point(alpha = 1/10)
+#' d + geom_point(alpha = 1/20)
+#' d + geom_point(alpha = 1/100)
+#' }
+#'
+#' # For shapes that have a border (like 21), you can colour the inside and
+#' # outside separately. Use the stroke aesthetic to modify the width of the
+#' # border
+#' ggplot(mtcars, aes(wt, mpg)) +
+#'   geom_point(shape = 21, colour = "black", fill = "white", size = 5, stroke = 5)
+#'
+#' \donttest{
+#' # You can create interesting shapes by layering multiple points of
+#' # different sizes
+#' p <- ggplot(mtcars, aes(mpg, wt, shape = factor(cyl)))
+#' p + geom_point(aes(colour = factor(cyl)), size = 4) +
+#'   geom_point(colour = "grey90", size = 1.5)
+#' p + geom_point(colour = "black", size = 4.5) +
+#'   geom_point(colour = "pink", size = 4) +
+#'   geom_point(aes(shape = factor(cyl)))
+#'
+#' # These extra layers don't usually appear in the legend, but we can
+#' # force their inclusion
+#' p + geom_point(colour = "black", size = 4.5, show.legend = TRUE) +
+#'   geom_point(colour = "pink", size = 4, show.legend = TRUE) +
+#'   geom_point(aes(shape = factor(cyl)))
+#'
+#' # geom_point warns when missing values have been dropped from the data set
+#' # and not plotted, you can turn this off by setting na.rm = TRUE
+#' mtcars2 <- transform(mtcars, mpg = ifelse(runif(32) < 0.2, NA, mpg))
+#' ggplot(mtcars2, aes(wt, mpg)) + geom_point()
+#' ggplot(mtcars2, aes(wt, mpg)) + geom_point(na.rm = TRUE)
+#' }
+geom_point <- function(mapping = NULL, data = NULL, stat = "identity",
+                       position = "identity", na.rm = FALSE,
+                       show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomPoint,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomPoint <- ggproto("GeomPoint", Geom,
+  required_aes = c("x", "y"),
+  non_missing_aes = c("size", "shape"),
+  default_aes = aes(
+    shape = 19, colour = "black", size = 1.5, fill = NA,
+    alpha = NA, stroke = 0.5
+  ),
+
+  draw_panel = function(data, panel_scales, coord, na.rm = FALSE) {
+    coords <- coord$transform(data, panel_scales)
+    ggname("geom_point",
+      pointsGrob(
+        coords$x, coords$y,
+        pch = coords$shape,
+        gp = gpar(
+          col = alpha(coords$colour, coords$alpha),
+          fill = alpha(coords$fill, coords$alpha),
+          # Stroke is added around the outside of the point
+          fontsize = coords$size * .pt + coords$stroke * .stroke / 2,
+          lwd = coords$stroke * .stroke / 2
+        )
+      )
+    )
+  },
+
+  draw_key = draw_key_point
+)
diff --git a/R/geom-pointrange.r b/R/geom-pointrange.r
index 1d66bad..c1b9156 100644
--- a/R/geom-pointrange.r
+++ b/R/geom-pointrange.r
@@ -1,45 +1,45 @@
-#' An interval represented by a vertical line, with a point in the middle.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "pointrange")}
-#'
-#' @inheritParams geom_point
-#' @seealso
-#'  \code{\link{geom_errorbar}} for error bars,
-#'  \code{\link{geom_linerange}} for range indicated by straight line, + examples,
-#'  \code{\link{geom_crossbar}} for hollow bar with middle indicated by horizontal line,
-#'  \code{\link{stat_summary}} for examples of these guys in use,
-#'  \code{\link{geom_smooth}} for continuous analog"
 #' @export
-#' @examples
-#' # See geom_linerange for examples
-geom_pointrange <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity", ...) {
-  GeomPointrange$new(mapping = mapping, data = data, stat = stat, position = position, ...)
+#' @rdname geom_linerange
+geom_pointrange <- function(mapping = NULL, data = NULL, stat = "identity",
+                            position = "identity", ..., fatten = 4,
+                            na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomPointrange,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      fatten = fatten,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-GeomPointrange <- proto(Geom, {
-  objname <- "pointrange"
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomPointrange <- ggproto("GeomPointrange", Geom,
+  default_aes = aes(colour = "black", size = 0.5, linetype = 1, shape = 19,
+    fill = NA, alpha = NA, stroke = 1),
 
-  default_stat <- function(.) StatIdentity
-  default_aes <- function(.) aes(colour = "black", size=0.5, linetype=1, shape=16, fill=NA, alpha = NA)
-  guide_geom <- function(.) "pointrange"
-  required_aes <- c("x", "y", "ymin", "ymax")
+  draw_key = draw_key_pointrange,
 
-  draw <- function(., data, scales, coordinates, ...) {
-    if (is.null(data$y)) return(GeomLinerange$draw(data, scales, coordinates, ...))
-    ggname(.$my_name(),gTree(children=gList(
-      GeomLinerange$draw(data, scales, coordinates, ...),
-      GeomPoint$draw(transform(data, size = size * 4), scales, coordinates, ...)
-    )))
-  }
+  required_aes = c("x", "y", "ymin", "ymax"),
 
-  draw_legend <- function(., data, ...) {
-    data <- aesdefaults(data, .$default_aes(), list(...))
+  draw_panel = function(data, panel_scales, coord, fatten = 4) {
+    if (is.null(data$y))
+      return(GeomLinerange$draw_panel(data, panel_scales, coord))
 
-    grobTree(
-      GeomPath$draw_legend(data, ...),
-      GeomPoint$draw_legend(transform(data, size = size * 4), ...)
+    ggname("geom_pointrange",
+      gTree(children = gList(
+        GeomLinerange$draw_panel(data, panel_scales, coord),
+        GeomPoint$draw_panel(transform(data, size = size * fatten), panel_scales, coord)
+      ))
     )
   }
-
-})
+)
diff --git a/R/geom-polygon.r b/R/geom-polygon.r
index 5cc3366..be41e0e 100644
--- a/R/geom-polygon.r
+++ b/R/geom-polygon.r
@@ -46,25 +46,34 @@
 #'
 #' # And if the positions are in longitude and latitude, you can use
 #' # coord_map to produce different map projections.
-geom_polygon <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity", ...) {
-  GeomPolygon$new(mapping = mapping, data = data, stat = stat, position = position, ...)
+geom_polygon <- function(mapping = NULL, data = NULL, stat = "identity",
+                         position = "identity", na.rm = FALSE, show.legend = NA,
+                         inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomPolygon,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-GeomPolygon <- proto(Geom, {
-  objname <- "polygon"
-
-  draw_groups <- function(., ...) .$draw(...)
-
-  draw <- function(., data, scales, coordinates, ...) {
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomPolygon <- ggproto("GeomPolygon", Geom,
+  draw_panel = function(data, panel_scales, coord) {
     n <- nrow(data)
-    if (n == 1) return()
-
-    # Check if group is numeric, to make polygonGrob happy (factors are numeric,
-    # but is.numeric() will report FALSE because it actually checks something else)
-    if (mode(data$group) != "numeric")
-      data$group <- factor(data$group)
+    if (n == 1) return(zeroGrob())
 
-    munched <- coord_munch(coordinates, data, scales)
+    munched <- coord_munch(coord, data, panel_scales)
     # Sort by group to make sure that colors, fill, etc. come in same order
     munched <- munched[order(munched$group), ]
 
@@ -74,32 +83,28 @@ GeomPolygon <- proto(Geom, {
     first_idx <- !duplicated(munched$group)
     first_rows <- munched[first_idx, ]
 
-    ggname(.$my_name(), gTree(children = gList(
+    ggname("geom_polygon",
       polygonGrob(munched$x, munched$y, default.units = "native",
         id = munched$group,
         gp = gpar(
-          col = first_rows$colour,
+          col = alpha(first_rows$colour, first_rows$alpha),
           fill = alpha(first_rows$fill, first_rows$alpha),
           lwd = first_rows$size * .pt,
           lty = first_rows$linetype
         )
       )
-    )))
-  }
+    )
+  },
 
-  default_stat <- function(.) StatIdentity
-  default_aes <- function(.) aes(colour="NA", fill="grey20", size=0.5, linetype=1, alpha = NA)
-  required_aes <- c("x", "y")
-  guide_geom <- function(.) "polygon"
+  default_aes = aes(colour = "NA", fill = "grey20", size = 0.5, linetype = 1,
+    alpha = NA),
 
-  draw_legend <- function(., data, ...)  {
-    data <- aesdefaults(data, .$default_aes(), list(...))
+  handle_na = function(data, params) {
+    data
+  },
 
-    with(data, grobTree(
-      rectGrob(gp = gpar(col = colour, fill = alpha(fill, alpha), lty = linetype)),
-      linesGrob(gp = gpar(col = colour, lwd = size * .pt, lineend="butt", lty = linetype))
-    ))
-  }
+  required_aes = c("x", "y"),
 
-})
+  draw_key = draw_key_polygon
+)
 
diff --git a/R/geom-quantile.r b/R/geom-quantile.r
index 70d94b4..c957030 100644
--- a/R/geom-quantile.r
+++ b/R/geom-quantile.r
@@ -8,19 +8,56 @@
 #' @export
 #' @inheritParams geom_point
 #' @inheritParams geom_path
-#' @seealso See \code{\link{stat_quantile}} for examples.
+#' @param method.args List of additional arguments passed on to the modelling
+#'   function defined by \code{method}.
+#' @param geom,stat Use to override the default connection between
+#'   \code{geom_quantile} and \code{stat_quantile}.
 #' @examples
-#' # See stat_quantile for examples
-geom_quantile <- function (mapping = NULL, data = NULL, stat = "quantile", position = "identity",
-lineend = "butt", linejoin = "round", linemitre = 1, na.rm = FALSE, ...) {
-  GeomQuantile$new(mapping = mapping, data = data, stat = stat, position = position,
-  lineend = lineend, linejoin = linejoin, linemitre = linemitre, na.rm = na.rm, ...)
-}
+#' m <- ggplot(mpg, aes(displ, 1 / hwy)) + geom_point()
+#' m + geom_quantile()
+#' m + geom_quantile(quantiles = 0.5)
+#' q10 <- seq(0.05, 0.95, by = 0.05)
+#' m + geom_quantile(quantiles = q10)
+#'
+#' # You can also use rqss to fit smooth quantiles
+#' m + geom_quantile(method = "rqss")
+#' # Note that rqss doesn't pick a smoothing constant automatically, so
+#' # you'll need to tweak lambda yourself
+#' m + geom_quantile(method = "rqss", lambda = 0.1)
+#'
+#' # Set aesthetics to fixed value
+#' m + geom_quantile(colour = "red", size = 2, alpha = 0.5)
+geom_quantile <- function(mapping = NULL, data = NULL, stat = "quantile",
+                          position = "identity", lineend = "butt",
+                          linejoin = "round", linemitre = 1,
+                          na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...) {
 
-GeomQuantile <- proto(GeomPath, {
-  objname <- "quantile"
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomQuantile,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      lineend = lineend,
+      linejoin = linejoin,
+      linemitre = linemitre,
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
 
-  default_stat <- function(.) StatQuantile
-  default_aes <- function(.) defaults(aes(weight=1, colour="#3366FF", size=0.5), GeomPath$default_aes())
-  guide_geom <- function(.) "path"
-})
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+#' @include geom-path.r
+GeomQuantile <- ggproto("GeomQuantile", GeomPath,
+  default_aes = defaults(
+    aes(weight = 1, colour = "#3366FF", size = 0.5),
+    GeomPath$default_aes
+  )
+)
diff --git a/R/geom-raster.r b/R/geom-raster.r
index 63c6bd1..431a41a 100644
--- a/R/geom-raster.r
+++ b/R/geom-raster.r
@@ -1,92 +1,68 @@
 #' @include geom-.r
 NULL
 
-#' High-performance rectangular tiling.
-#'
-#' This is a special case of \code{\link{geom_tile}} where all tiles are
-#' the same size.  It is implemented highly efficiently using the internal
-#' \code{rasterGrob} function.
-#'
-#' By default, \code{geom_raster} add a vertical and horizontal padding.
-#' The size of padding depends on the resolution of data.
-#' If you want to manually set the padding (e.g. want zero-padding),
-#' you can change the behavior by setting \code{hpad} and \code{vpad}.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "raster")}
-#'
-#' @inheritParams geom_point
+#' @export
+#' @rdname geom_tile
 #' @param hjust,vjust horizontal and vertical justification of the grob.  Each
 #'   justification value should be a number between 0 and 1.  Defaults to 0.5
 #'   for both, centering each pixel over its data location.
 #' @param interpolate If \code{TRUE} interpolate linearly, if \code{FALSE}
 #'   (the default) don't interpolate.
-#' @export
-#' @examples
-#' \donttest{
-#' # Generate data
-#' pp <- function (n,r=4) {
-#'  x <- seq(-r*pi, r*pi, len=n)
-#'  df <- expand.grid(x=x, y=x)
-#'  df$r <- sqrt(df$x^2 + df$y^2)
-#'  df$z <- cos(df$r^2)*exp(-df$r/6)
-#'  df
-#' }
-#' qplot(x, y, data = pp(20), fill = z, geom = "raster")
-#' # Interpolation worsens the apperance of this plot, but can help when
-#' # rendering images.
-#' qplot(x, y, data = pp(20), fill = z, geom = "raster", interpolate = TRUE)
-#'
-#' # For the special cases where it is applicable, geom_raster is much
-#' # faster than geom_tile:
-#' pp200 <- pp(200)
-#' base <- ggplot(pp200, aes(x, y, fill = z))
-#' benchplot(base + geom_raster())
-#' benchplot(base + geom_tile())
-#'
-#' # justification
-#' df <- expand.grid(x = 0:5, y = 0:5)
-#' df$z <- runif(nrow(df))
-#' # default is compatible with geom_tile()
-#' ggplot(df, aes(x, y, fill = z)) + geom_raster()
-#' # zero padding
-#' ggplot(df, aes(x, y, fill = z)) + geom_raster(hjust = 0, vjust = 0)
-#' }
-geom_raster <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity", hjust = 0.5, vjust = 0.5, interpolate = FALSE, ...) {
+geom_raster <- function(mapping = NULL, data = NULL, stat = "identity",
+                        position = "identity", hjust = 0.5, vjust = 0.5,
+                        interpolate = FALSE, na.rm = FALSE,
+                        show.legend = NA, inherit.aes = TRUE, ...)
+{
   stopifnot(is.numeric(hjust), length(hjust) == 1)
   stopifnot(is.numeric(vjust), length(vjust) == 1)
 
-  GeomRaster$new(mapping = mapping, data = data, stat = stat, position = position, hjust = hjust, vjust = vjust, interpolate = interpolate, ...)
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomRaster,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      hjust = hjust,
+      vjust = vjust,
+      interpolate = interpolate,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-GeomRaster <- proto(Geom, {
-  objname <- "raster"
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomRaster <- ggproto("GeomRaster", Geom,
+  default_aes = aes(fill = "grey20", alpha = NA),
+  non_missing_aes = "fill",
+  required_aes = c("x", "y"),
 
-  reparameterise <- function(., df, params) {
+  setup_data = function(data, params) {
     hjust <- params$hjust %||% 0.5
     vjust <- params$vjust %||% 0.5
 
-    w <- resolution(df$x, FALSE)
-    h <- resolution(df$y, FALSE)
+    w <- resolution(data$x, FALSE)
+    h <- resolution(data$y, FALSE)
 
-    df$xmin <- df$x - w * (1 - hjust)
-    df$xmax <- df$x + w * hjust
-    df$ymin <- df$y - h * (1 - vjust)
-    df$ymax <- df$y + h * vjust
-    df
-  }
+    data$xmin <- data$x - w * (1 - hjust)
+    data$xmax <- data$x + w * hjust
+    data$ymin <- data$y - h * (1 - vjust)
+    data$ymax <- data$y + h * vjust
+    data
+  },
 
-  # This is a dummy function to make sure that vjust and hjust are recongised
-  # as parameters and are accessible to reparameterise.
-  draw <- function(vjust = 0.5, hjust = 0.5) {}
-
-  draw_groups <- function(., data, scales, coordinates, interpolate = FALSE, ...) {
-    if (!inherits(coordinates, "cartesian")) {
+  draw_panel = function(data, panel_scales, coord, interpolate = FALSE,
+                        hjust = 0.5, vjust = 0.5) {
+    if (!inherits(coord, "CoordCartesian")) {
       stop("geom_raster only works with Cartesian coordinates", call. = FALSE)
     }
-    data <- remove_missing(data, TRUE, c("x", "y", "fill"),
-      name = "geom_raster")
-    data <- coord_transform(coordinates, data, scales)
+    data <- coord$transform(data, panel_scales)
 
     # Convert vector of data to raster
     x_pos <- as.integer((data$x - min(data$x)) / resolution(data$x, FALSE))
@@ -102,13 +78,11 @@ GeomRaster <- proto(Geom, {
     x_rng <- c(min(data$xmin, na.rm = TRUE), max(data$xmax, na.rm = TRUE))
     y_rng <- c(min(data$ymin, na.rm = TRUE), max(data$ymax, na.rm = TRUE))
 
-    rasterGrob(raster, x = mean(x_rng), y = mean(y_rng),
+    rasterGrob(raster,
+      x = mean(x_rng), y = mean(y_rng),
       width = diff(x_rng), height = diff(y_rng),
-      default.units = "native", interpolate = interpolate)
-  }
-
-  default_stat <- function(.) StatIdentity
-  default_aes <- function(.) aes(fill = "grey20", alpha = NA)
-  required_aes <- c("x", "y")
-  guide_geom <- function(.) "polygon"
-})
+      default.units = "native", interpolate = interpolate
+    )
+  },
+  draw_key = draw_key_rect
+)
diff --git a/R/geom-rect.r b/R/geom-rect.r
index 6f58d68..ef41546 100644
--- a/R/geom-rect.r
+++ b/R/geom-rect.r
@@ -1,63 +1,70 @@
-#' 2d rectangles.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "rect")}
-#'
-#' @inheritParams geom_point
 #' @export
-#' @examples
-#' df <- data.frame(
-#'   x = sample(10, 20, replace = TRUE),
-#'   y = sample(10, 20, replace = TRUE)
-#' )
-#' ggplot(df, aes(xmin = x, xmax = x + 1, ymin = y, ymax = y + 2)) +
-#' geom_rect()
-geom_rect <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity", ...) {
-  GeomRect$new(mapping = mapping, data = data, stat = stat, position = position, ...)
+#' @rdname geom_tile
+geom_rect <- function(mapping = NULL, data = NULL, stat = "identity",
+                      position = "identity", na.rm = FALSE,
+                      show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomRect,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-GeomRect <- proto(Geom, {
-  objname <- "rect"
-
-  default_stat <- function(.) StatIdentity
-  default_pos <- function(.) PositionIdentity
-  default_aes <- function(.) aes(colour=NA, fill="grey20", size=0.5, linetype=1, alpha = NA)
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomRect <- ggproto("GeomRect", Geom,
+  default_aes = aes(colour = NA, fill = "grey35", size = 0.5, linetype = 1,
+    alpha = NA),
 
-  required_aes <- c("xmin", "xmax", "ymin", "ymax")
+  required_aes = c("xmin", "xmax", "ymin", "ymax"),
 
-  draw <- draw_groups <- function(., data, scales, coordinates, ...) {
-    if (!is.linear(coordinates)) {
+  draw_panel = function(self, data, panel_scales, coord) {
+    if (!coord$is_linear()) {
       aesthetics <- setdiff(
-        names(data), c("x", "y", "xmin","xmax", "ymin", "ymax")
+        names(data), c("x", "y", "xmin", "xmax", "ymin", "ymax")
       )
 
-      polys <- alply(data, 1, function(row) {
-        poly <- with(row, rect_to_poly(xmin, xmax, ymin, ymax))
+      polys <- plyr::alply(data, 1, function(row) {
+        poly <- rect_to_poly(row$xmin, row$xmax, row$ymin, row$ymax)
         aes <- as.data.frame(row[aesthetics],
           stringsAsFactors = FALSE)[rep(1,5), ]
 
-        GeomPolygon$draw(cbind(poly, aes), scales, coordinates)
+        GeomPolygon$draw_panel(cbind(poly, aes), panel_scales, coord)
       })
 
-      ggname("bar",do.call("grobTree", polys))
+      ggname("bar", do.call("grobTree", polys))
     } else {
-      with(coord_transform(coordinates, data, scales),
-        ggname(.$my_name(), rectGrob(
-          xmin, ymax,
-          width = xmax - xmin, height = ymax - ymin,
-          default.units = "native", just = c("left", "top"),
-          gp=gpar(
-            col=colour, fill=alpha(fill, alpha),
-            lwd=size * .pt, lty=linetype, lineend="butt"
-          )
-        ))
-      )
+      coords <- coord$transform(data, panel_scales)
+      ggname("geom_rect", rectGrob(
+        coords$xmin, coords$ymax,
+        width = coords$xmax - coords$xmin,
+        height = coords$ymax - coords$ymin,
+        default.units = "native",
+        just = c("left", "top"),
+        gp = gpar(
+          col = alpha(coords$colour, coords$alpha),
+          fill = alpha(coords$fill, coords$alpha),
+          lwd = coords$size * .pt,
+          lty = coords$linetype,
+          lineend = "butt"
+        )
+      ))
     }
+  },
 
-  }
-  guide_geom <- function(.) "polygon"
+  draw_key = draw_key_polygon
+)
 
-})
 
 # Convert rectangle to polygon
 # Useful for non-Cartesian coordinate systems where it's easy to work purely in terms of locations, rather than locations and dimensions.
diff --git a/R/geom-ribbon-.r b/R/geom-ribbon-.r
deleted file mode 100644
index 13b69cb..0000000
--- a/R/geom-ribbon-.r
+++ /dev/null
@@ -1,131 +0,0 @@
-#' Ribbons, y range with continuous x values.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "ribbon")}
-#'
-#' @seealso
-#'   \code{\link{geom_bar}} for discrete intervals (bars),
-#'   \code{\link{geom_linerange}} for discrete intervals (lines),
-#'   \code{\link{geom_polygon}} for general polygons"
-#' @inheritParams geom_point
-#' @export
-#' @examples
-#' \donttest{
-#' # Generate data
-#' huron <- data.frame(year = 1875:1972, level = as.vector(LakeHuron))
-#' library(plyr) # to access round_any
-#' huron$decade <- round_any(huron$year, 10, floor)
-#'
-#' h <- ggplot(huron, aes(x=year))
-#'
-#' h + geom_ribbon(aes(ymin=0, ymax=level))
-#' h + geom_area(aes(y = level))
-#'
-#' # Add aesthetic mappings
-#' h + geom_ribbon(aes(ymin=level-1, ymax=level+1))
-#' h + geom_ribbon(aes(ymin=level-1, ymax=level+1)) + geom_line(aes(y=level))
-#'
-#' # Take out some values in the middle for an example of NA handling
-#' huron[huron$year > 1900 & huron$year < 1910, "level"] <- NA
-#' h <- ggplot(huron, aes(x=year))
-#' h + geom_ribbon(aes(ymin=level-1, ymax=level+1)) + geom_line(aes(y=level))
-#'
-#' # Another data set, with multiple y's for each x
-#' m <- ggplot(movies, aes(y=votes, x=year))
-#' (m <- m + geom_point())
-#'
-#' # The default summary isn't that useful
-#' m + stat_summary(geom="ribbon", fun.ymin="min", fun.ymax="max")
-#' m + stat_summary(geom="ribbon", fun.data="median_hilow")
-#'
-#' # Use qplot instead
-#' qplot(year, level, data=huron, geom=c("area", "line"))
-#' }
-geom_ribbon <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity",
-na.rm = FALSE, ...) {
-  GeomRibbon$new(mapping = mapping, data = data, stat = stat, position = position,
-  na.rm = na.rm, ...)
-}
-
-GeomRibbon <- proto(Geom, {
-  objname <- "ribbon"
-
-  default_stat <- function(.) StatIdentity
-  default_aes <- function(.) aes(colour=NA, fill="grey20", size=0.5, linetype=1, alpha = NA)
-  required_aes <- c("x", "ymin", "ymax")
-  guide_geom <- function(.) "polygon"
-
-
-  draw <- function(., data, scales, coordinates, na.rm = FALSE, ...) {
-    if (na.rm) data <- data[complete.cases(data[required_aes]), ]
-    data <- data[order(data$group, data$x), ]
-
-    # Check that aesthetics are constant
-    aes <- unique(data[c("colour", "fill", "size", "linetype", "alpha")])
-    if (nrow(aes) > 1) {
-      stop("Aesthetics can not vary with a ribbon")
-    }
-    aes <- as.list(aes)
-
-    # Instead of removing NA values from the data and plotting a single
-    # polygon, we want to "stop" plotting the polygon whenever we're
-    # missing values and "start" a new polygon as soon as we have new
-    # values.  We do this by creating an id vector for polygonGrob that
-    # has distinct polygon numbers for sequences of non-NA values and NA
-    # for NA values in the original data.  Example: c(NA, 2, 2, 2, NA, NA,
-    # 4, 4, 4, NA)
-    missing_pos <- !complete.cases(data[required_aes])
-    ids <- cumsum(missing_pos) + 1
-    ids[missing_pos] <- NA
-
-    positions <- summarise(data,
-      x = c(x, rev(x)), y = c(ymax, rev(ymin)), id = c(ids, rev(ids)))
-    munched <- coord_munch(coordinates,positions, scales)
-
-    ggname(.$my_name(), polygonGrob(
-      munched$x, munched$y, id = munched$id,
-      default.units = "native",
-      gp = gpar(
-        fill = alpha(aes$fill, aes$alpha),
-        col = aes$colour,
-        lwd = aes$size * .pt,
-        lty = aes$linetype)
-    ))
-  }
-
-})
-
-#' Area plot.
-#'
-#' An area plot is the continuous analog of a stacked bar chart (see
-#' \code{\link{geom_bar}}), and can be used to show how composition of the
-#' whole varies over the range of x.  Choosing the order in which different
-#' components is stacked is very important, as it becomes increasing hard to
-#' see the individual pattern as you move up the stack.
-#'
-#' An area plot is a special case of \code{\link{geom_ribbon}}, where the
-#' minimum of the range is fixed to 0, and the position adjustment defaults
-#' to position_stacked.
-#'
-#' @inheritParams geom_point
-#' @export
-#' @examples
-#' # see geom_ribbon
-geom_area <- function (mapping = NULL, data = NULL, stat = "identity", position = "stack",
-na.rm = FALSE, ...) {
-  GeomArea$new(mapping = mapping, data = data, stat = stat, position = position,
-  na.rm = na.rm, ...)
-}
-
-GeomArea <- proto(GeomRibbon,{
-  objname <- "area"
-
-  default_aes <- function(.) aes(colour=NA, fill="grey20", size=0.5, linetype=1, alpha = NA)
-  default_pos <- function(.) PositionStack
-  required_aes <- c("x", "y")
-
-  reparameterise <- function(., df, params) {
-    transform(df, ymin = 0, ymax = y)
-  }
-
-})
diff --git a/R/geom-ribbon-density.r b/R/geom-ribbon-density.r
deleted file mode 100644
index 9247913..0000000
--- a/R/geom-ribbon-density.r
+++ /dev/null
@@ -1,27 +0,0 @@
-#' Display a smooth density estimate.
-#'
-#' A smooth density estimate calculated by \code{\link{stat_density}}.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "density")}
-#'
-#' @seealso \code{\link{geom_histogram}} for the histogram and
-#'   \code{\link{stat_density}} for examples.
-#' @inheritParams geom_point
-#' @export
-#' @examples
-#' # See stat_density for examples
-geom_density <- function (mapping = NULL, data = NULL, stat = "density", position = "identity",
-na.rm = FALSE, ...) {
-  GeomDensity$new(mapping = mapping, data = data, stat = stat, position = position,
-  na.rm = na.rm, ...)
-}
-
-GeomDensity <- proto(GeomArea, {
-  objname <- "density"
-
-  default_stat <- function(.) StatDensity
-  default_pos <- function(.) PositionIdentity
-
-  default_aes <- function(.) defaults(aes(fill=NA, weight=1, colour="black", alpha = NA), GeomArea$default_aes())
-})
diff --git a/R/geom-ribbon.r b/R/geom-ribbon.r
new file mode 100644
index 0000000..e7f81bc
--- /dev/null
+++ b/R/geom-ribbon.r
@@ -0,0 +1,135 @@
+#' Ribbons and area plots.
+#'
+#' For each continuous x value, \code{geom_interval} displays a y interval.
+#' \code{geom_area} is a special case of \code{geom_ribbon}, where the
+#' minimum of the range is fixed to 0.
+#'
+#' An area plot is the continuous analog of a stacked bar chart (see
+#' \code{\link{geom_bar}}), and can be used to show how composition of the
+#' whole varies over the range of x.  Choosing the order in which different
+#' components is stacked is very important, as it becomes increasing hard to
+#' see the individual pattern as you move up the stack.
+#'
+#' @section Aesthetics:
+#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "ribbon")}
+#'
+#' @seealso
+#'   \code{\link{geom_bar}} for discrete intervals (bars),
+#'   \code{\link{geom_linerange}} for discrete intervals (lines),
+#'   \code{\link{geom_polygon}} for general polygons
+#' @inheritParams geom_point
+#' @export
+#' @examples
+#' # Generate data
+#' huron <- data.frame(year = 1875:1972, level = as.vector(LakeHuron))
+#' h <- ggplot(huron, aes(year))
+#'
+#' h + geom_ribbon(aes(ymin=0, ymax=level))
+#' h + geom_area(aes(y = level))
+#'
+#' # Add aesthetic mappings
+#' h +
+#'   geom_ribbon(aes(ymin = level - 1, ymax = level + 1), fill = "grey70") +
+#'   geom_line(aes(y = level))
+geom_ribbon <- function(mapping = NULL, data = NULL, stat = "identity",
+                        position = "identity", na.rm = FALSE, show.legend = NA,
+                        inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomRibbon,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomRibbon <- ggproto("GeomRibbon", Geom,
+  default_aes = aes(colour = NA, fill = "grey20", size = 0.5, linetype = 1,
+    alpha = NA),
+
+  required_aes = c("x", "ymin", "ymax"),
+
+  draw_key = draw_key_polygon,
+
+  draw_group = function(data, panel_scales, coord, na.rm = FALSE) {
+    if (na.rm) data <- data[stats::complete.cases(data[c("x", "ymin", "ymax")]), ]
+    data <- data[order(data$group, data$x), ]
+
+    # Check that aesthetics are constant
+    aes <- unique(data[c("colour", "fill", "size", "linetype", "alpha")])
+    if (nrow(aes) > 1) {
+      stop("Aesthetics can not vary with a ribbon")
+    }
+    aes <- as.list(aes)
+
+    # Instead of removing NA values from the data and plotting a single
+    # polygon, we want to "stop" plotting the polygon whenever we're
+    # missing values and "start" a new polygon as soon as we have new
+    # values.  We do this by creating an id vector for polygonGrob that
+    # has distinct polygon numbers for sequences of non-NA values and NA
+    # for NA values in the original data.  Example: c(NA, 2, 2, 2, NA, NA,
+    # 4, 4, 4, NA)
+    missing_pos <- !stats::complete.cases(data[c("x", "ymin", "ymax")])
+    ids <- cumsum(missing_pos) + 1
+    ids[missing_pos] <- NA
+
+    positions <- plyr::summarise(data,
+      x = c(x, rev(x)), y = c(ymax, rev(ymin)), id = c(ids, rev(ids)))
+    munched <- coord_munch(coord, positions, panel_scales)
+
+    ggname("geom_ribbon", polygonGrob(
+      munched$x, munched$y, id = munched$id,
+      default.units = "native",
+      gp = gpar(
+        fill = alpha(aes$fill, aes$alpha),
+        col = alpha(aes$colour, aes$alpha),
+        lwd = aes$size * .pt,
+        lty = aes$linetype)
+    ))
+  }
+)
+
+#' @rdname geom_ribbon
+#' @export
+geom_area <- function(mapping = NULL, data = NULL, stat = "identity",
+                      position = "stack", na.rm = FALSE, show.legend = NA,
+                      inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomArea,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomArea <- ggproto("GeomArea", GeomRibbon,
+  default_aes = aes(colour = NA, fill = "grey20", size = 0.5, linetype = 1,
+    alpha = NA),
+
+  required_aes = c("x", "y"),
+
+  setup_data = function(data, params) {
+    transform(data, ymin = 0, ymax = y)
+  }
+)
diff --git a/R/geom-rug.r b/R/geom-rug.r
index c6c188f..dada4e6 100644
--- a/R/geom-rug.r
+++ b/R/geom-rug.r
@@ -9,62 +9,82 @@
 #'   bottom, and left.
 #' @export
 #' @examples
-#' p <- ggplot(mtcars, aes(x=wt, y=mpg))
+#' p <- ggplot(mtcars, aes(wt, mpg))
 #' p + geom_point()
 #' p + geom_point() + geom_rug()
 #' p + geom_point() + geom_rug(sides="b")    # Rug on bottom only
 #' p + geom_point() + geom_rug(sides="trbl") # All four sides
 #' p + geom_point() + geom_rug(position='jitter')
-geom_rug <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity", sides = "bl", ...) {
-  GeomRug$new(mapping = mapping, data = data, stat = stat, position = position, sides = sides, ...)
+geom_rug <- function(mapping = NULL, data = NULL, stat = "identity",
+                     position = "identity", sides = "bl",
+                     na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomRug,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      sides = sides,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-GeomRug <- proto(Geom, {
-  objname <- "rug"
 
-  draw <- function(., data, scales, coordinates, sides, ...) {
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomRug <- ggproto("GeomRug", Geom,
+  draw_panel = function(data, panel_scales, coord, sides = "bl") {
     rugs <- list()
-    data <- coord_transform(coordinates, data, scales)
+    data <- coord$transform(data, panel_scales)
+
+    gp <- gpar(col = alpha(data$colour, data$alpha), lty = data$linetype, lwd = data$size * .pt)
     if (!is.null(data$x)) {
-      if(grepl("b", sides)) {
+      if (grepl("b", sides)) {
         rugs$x_b <- segmentsGrob(
           x0 = unit(data$x, "native"), x1 = unit(data$x, "native"),
           y0 = unit(0, "npc"), y1 = unit(0.03, "npc"),
-          gp = gpar(col = alpha(data$colour, data$alpha), lty = data$linetype, lwd = data$size * .pt)
+          gp = gp
         )
       }
 
-      if(grepl("t", sides)) {
+      if (grepl("t", sides)) {
         rugs$x_t <- segmentsGrob(
           x0 = unit(data$x, "native"), x1 = unit(data$x, "native"),
           y0 = unit(1, "npc"), y1 = unit(0.97, "npc"),
-          gp = gpar(col = alpha(data$colour, data$alpha), lty = data$linetype, lwd = data$size * .pt)
+          gp = gp
         )
       }
     }
 
     if (!is.null(data$y)) {
-      if(grepl("l", sides)) {
+      if (grepl("l", sides)) {
         rugs$y_l <- segmentsGrob(
           y0 = unit(data$y, "native"), y1 = unit(data$y, "native"),
           x0 = unit(0, "npc"), x1 = unit(0.03, "npc"),
-          gp = gpar(col = alpha(data$colour, data$alpha), lty = data$linetype, lwd = data$size * .pt)
+          gp = gp
         )
       }
 
-      if(grepl("r", sides)) {
+      if (grepl("r", sides)) {
         rugs$y_r <- segmentsGrob(
           y0 = unit(data$y, "native"), y1 = unit(data$y, "native"),
           x0 = unit(1, "npc"), x1 = unit(0.97, "npc"),
-          gp = gpar(col = alpha(data$colour, data$alpha), lty = data$linetype, lwd = data$size * .pt)
+          gp = gp
         )
       }
     }
 
     gTree(children = do.call("gList", rugs))
-  }
+  },
+
+  default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = NA),
 
-  default_stat <- function(.) StatIdentity
-  default_aes <- function(.) aes(colour="black", size=0.5, linetype=1, alpha = NA)
-  guide_geom <- function(.) "path"
-})
+  draw_key = draw_key_path
+)
diff --git a/R/geom-segment.r b/R/geom-segment.r
index 3afe1fd..adc1247 100644
--- a/R/geom-segment.r
+++ b/R/geom-segment.r
@@ -1,4 +1,7 @@
-#' Single line segments.
+#' Line segments and curves.
+#'
+#' \code{geom_segment} draws a straight line between points (x1, y1) and
+#' (x2, y2). \code{geom_curve} draws a curved line.
 #'
 #' @section Aesthetics:
 #' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "segment")}
@@ -8,83 +11,102 @@
 #' @param lineend Line end style (round, butt, square)
 #' @seealso \code{\link{geom_path}} and \code{\link{geom_line}} for multi-
 #'   segment lines and paths.
+#' @seealso \code{\link{geom_spoke}} for a segment parameterised by a location
+#'   (x, y), and an angle and radius.
 #' @export
 #' @examples
-#' library(grid) # needed for arrow function
-#' p <- ggplot(seals, aes(x = long, y = lat))
-#' (p <- p + geom_segment(aes(xend = long + delta_long, yend = lat + delta_lat),
-#'   arrow = arrow(length = unit(0.1,"cm"))))
+#' b <- ggplot(mtcars, aes(wt, mpg)) +
+#'   geom_point()
 #'
-#' if (require("maps")) {
+#' df <- data.frame(x1 = 2.62, x2 = 3.57, y1 = 21.0, y2 = 15.0)
+#' b +
+#'  geom_curve(aes(x = x1, y = y1, xend = x2, yend = y2, colour = "curve"), data = df) +
+#'  geom_segment(aes(x = x1, y = y1, xend = x2, yend = y2, colour = "segment"), data = df)
 #'
-#' xlim <- range(seals$long)
-#' ylim <- range(seals$lat)
-#' usamap <- data.frame(map("world", xlim = xlim, ylim = ylim, plot =
-#' FALSE)[c("x","y")])
-#' usamap <- rbind(usamap, NA, data.frame(map('state', xlim = xlim, ylim
-#' = ylim, plot = FALSE)[c("x","y")]))
-#' names(usamap) <- c("long", "lat")
+#' b + geom_curve(aes(x = x1, y = y1, xend = x2, yend = y2), data = df, curvature = -0.2)
+#' b + geom_curve(aes(x = x1, y = y1, xend = x2, yend = y2), data = df, curvature = 1)
+#' b + geom_curve(
+#'   aes(x = x1, y = y1, xend = x2, yend = y2),
+#'   data = df,
+#'   arrow = arrow(length = unit(0.03, "npc"))
+#' )
 #'
-#' p + geom_path(data = usamap) + scale_x_continuous(limits = xlim)
-#' }
+#' ggplot(seals, aes(long, lat)) +
+#'   geom_segment(aes(xend = long + delta_long, yend = lat + delta_lat),
+#'     arrow = arrow(length = unit(0.1,"cm"))) +
+#'   borders("state")
 #'
 #' # You can also use geom_segment to recreate plot(type = "h") :
 #' counts <- as.data.frame(table(x = rpois(100,5)))
 #' counts$x <- as.numeric(as.character(counts$x))
 #' with(counts, plot(x, Freq, type = "h", lwd = 10))
 #'
-#' qplot(x, Freq, data = counts, geom = "segment",
-#'   yend = 0, xend = x, size = I(10))
-#'
-#' # Adding line segments
-#' library(grid) # needed for arrow function
-#' b <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
-#' b + geom_segment(aes(x = 2, y = 15, xend = 2, yend = 25))
-#' b + geom_segment(aes(x = 2, y = 15, xend = 3, yend = 15))
-#' b + geom_segment(aes(x = 5, y = 30, xend = 3.5, yend = 25),
-#'    arrow = arrow(length = unit(0.5, "cm")))
-geom_segment <- function (mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", arrow = NULL, lineend = "butt", na.rm = FALSE, ...) {
-
-  GeomSegment$new(mapping = mapping, data = data, stat = stat,
-    position = position, arrow = arrow, lineend = lineend, na.rm = na.rm, ...)
+#' ggplot(counts, aes(x, Freq)) +
+#'   geom_segment(aes(xend = x, yend = 0), size = 10, lineend = "butt")
+geom_segment <- function(mapping = NULL, data = NULL, stat = "identity",
+                         position = "identity", arrow = NULL, lineend = "butt",
+                         na.rm = FALSE, show.legend = NA, inherit.aes = TRUE,
+                         ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomSegment,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      arrow = arrow,
+      lineend = lineend,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-GeomSegment <- proto(Geom, {
-  objname <- "segment"
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomSegment <- ggproto("GeomSegment", Geom,
+  required_aes = c("x", "y", "xend", "yend"),
+  non_missing_aes = c("linetype", "size", "shape"),
+  default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = NA),
 
-  draw <- function(., data, scales, coordinates, arrow = NULL,
-    lineend = "butt", na.rm = FALSE, ...) {
+  draw_panel = function(data, panel_scales, coord, arrow = NULL,
+                        lineend = "butt", na.rm = FALSE) {
 
     data <- remove_missing(data, na.rm = na.rm,
       c("x", "y", "xend", "yend", "linetype", "size", "shape"),
       name = "geom_segment")
     if (empty(data)) return(zeroGrob())
 
-    if (is.linear(coordinates)) {
-      return(with(coord_transform(coordinates, data, scales),
-        segmentsGrob(x, y, xend, yend, default.units="native",
-        gp = gpar(col=alpha(colour, alpha), fill = alpha(colour, alpha),
-          lwd=size * .pt, lty=linetype, lineend = lineend),
-        arrow = arrow)
+    if (coord$is_linear()) {
+      coord <- coord$transform(data, panel_scales)
+      return(segmentsGrob(coord$x, coord$y, coord$xend, coord$yend,
+        default.units = "native",
+        gp = gpar(
+          col = alpha(coord$colour, coord$alpha),
+          fill = alpha(coord$colour, coord$alpha),
+          lwd = coord$size * .pt,
+          lty = coord$linetype,
+          lineend = lineend
+        ),
+        arrow = arrow
       ))
     }
 
     data$group <- 1:nrow(data)
     starts <- subset(data, select = c(-xend, -yend))
-    ends <- rename(subset(data, select = c(-x, -y)), c("xend" = "x", "yend" = "y"),
+    ends <- plyr::rename(subset(data, select = c(-x, -y)), c("xend" = "x", "yend" = "y"),
       warn_missing = FALSE)
 
     pieces <- rbind(starts, ends)
     pieces <- pieces[order(pieces$group),]
 
-    GeomPath$draw_groups(pieces, scales, coordinates, arrow = arrow, ...)
-  }
-
-
-  default_stat <- function(.) StatIdentity
-  required_aes <- c("x", "y", "xend", "yend")
-  default_aes <- function(.) aes(colour="black", size=0.5, linetype=1, alpha = NA)
-  guide_geom <- function(.) "path"
-})
+    GeomPath$draw_panel(pieces, panel_scales, coord, arrow = arrow,
+      lineend = lineend)
+  },
 
+  draw_key = draw_key_path
+)
diff --git a/R/geom-smooth.r b/R/geom-smooth.r
index 4e3db12..bce8461 100644
--- a/R/geom-smooth.r
+++ b/R/geom-smooth.r
@@ -1,75 +1,130 @@
 #' Add a smoothed conditional mean.
 #'
+#' Aids the eye in seeing patterns in the presence of overplotting.
+#' \code{geom_smooth} and \code{stat_smooth} are effectively aliases: they
+#' both use the same arguments. Use \code{geom_smooth} unless you want to
+#' display the results with a non-standard geom.
+#'
+#' Calculation is performed by the (currently undocumented)
+#' \code{predictdf} generic and its methods.  For most methods the standard
+#' error bounds are computed using the \code{\link{predict}} method - the
+#' exceptions are \code{loess} which uses a t-based approximation, and
+#' \code{glm} where the normal confidence interval is constructed on the link
+#' scale, and then back-transformed to the response scale.
+#'
 #' @section Aesthetics:
 #' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "smooth")}
 #'
 #' @inheritParams geom_point
-#' @seealso The default stat for this geom is \code{\link{stat_smooth}} see
-#'   that documentation for more options to control the underlying statistical transformation.
+#' @param geom,stat Use to override the default connection between
+#'   \code{geom_smooth} and \code{stat_smooth}.
+#' @seealso See individual modelling functions for more details:
+#'   \code{\link{lm}} for linear smooths,
+#'   \code{\link{glm}} for generalised linear smooths,
+#'   \code{\link{loess}} for local smooths
 #' @export
 #' @examples
-#' # See stat_smooth for examples of using built in model fitting
-#' # if you need some more flexible, this example shows you how to
-#' # plot the fits from any model of your choosing
-#' qplot(wt, mpg, data=mtcars, colour=factor(cyl))
+#' ggplot(mpg, aes(displ, hwy)) +
+#'   geom_point() +
+#'   geom_smooth()
 #'
-#' model <- lm(mpg ~ wt + factor(cyl), data=mtcars)
-#' grid <- with(mtcars, expand.grid(
-#'   wt = seq(min(wt), max(wt), length = 20),
-#'   cyl = levels(factor(cyl))
-#' ))
+#' # Use span to control the "wiggliness" of the default loess smoother
+#' # The span is the fraction of points used to fit each local regression:
+#' # small numbers make a wigglier curve, larger numbers make a smoother curve.
+#' ggplot(mpg, aes(displ, hwy)) +
+#'   geom_point() +
+#'   geom_smooth(span = 0.3)
 #'
-#' grid$mpg <- stats::predict(model, newdata=grid)
+#' # Instead of a loess smooth, you can use any other modelling function:
+#' ggplot(mpg, aes(displ, hwy)) +
+#'   geom_point() +
+#'   geom_smooth(method = "lm", se = FALSE)
 #'
-#' qplot(wt, mpg, data=mtcars, colour=factor(cyl)) + geom_line(data=grid)
+#' ggplot(mpg, aes(displ, hwy)) +
+#'   geom_point() +
+#'   geom_smooth(method = "lm", formula = y ~ splines::bs(x, 3), se = FALSE)
 #'
-#' # or with standard errors
+#' # Smoothes are automatically fit to each group (defined by categorical
+#' # aesthetics or the group aesthetic) and for each facet
 #'
-#' err <- stats::predict(model, newdata=grid, se = TRUE)
-#' grid$ucl <- err$fit + 1.96 * err$se.fit
-#' grid$lcl <- err$fit - 1.96 * err$se.fit
+#' ggplot(mpg, aes(displ, hwy, colour = class)) +
+#'   geom_point() +
+#'   geom_smooth(se = FALSE, method = "lm")
+#' ggplot(mpg, aes(displ, hwy)) +
+#'   geom_point() +
+#'   geom_smooth(span = 0.8) +
+#'   facet_wrap(~drv)
 #'
-#' qplot(wt, mpg, data=mtcars, colour=factor(cyl)) +
-#'   geom_smooth(aes(ymin = lcl, ymax = ucl), data=grid, stat="identity")
-geom_smooth <- function (mapping = NULL, data = NULL, stat = "smooth", position = "identity", ...) {
-  GeomSmooth$new(mapping = mapping, data = data, stat = stat, position = position, ...)
-}
+#' \dontrun{
+#' # To fit a logistic regression, you need to coerce the values to
+#' # a numeric vector lying between 0 and 1.
+#' binomial_smooth <- function(...) {
+#'   geom_smooth(method = "glm", method.args = list(family = "binomial"), ...)
+#' }
+#'
+#' ggplot(rpart::kyphosis, aes(Age, Kyphosis)) +
+#'   geom_jitter(height = 0.05) +
+#'   binomial_smooth()
+#'
+#' ggplot(rpart::kyphosis, aes(Age, as.numeric(Kyphosis) - 1)) +
+#'   geom_jitter(height = 0.05) +
+#'   binomial_smooth()
+#'
+#' ggplot(rpart::kyphosis, aes(Age, as.numeric(Kyphosis) - 1)) +
+#'   geom_jitter(height = 0.05) +
+#'   binomial_smooth(formula = y ~ splines::ns(x, 2))
+#'
+#' # But in this case, it's probably better to fit the model yourself
+#' # so you can exercise more control and see whether or not it's a good model
+#' }
+geom_smooth <- function(mapping = NULL, data = NULL, stat = "smooth",
+                        method = "auto", formula = y ~ x, se = TRUE,
+                        position = "identity", na.rm = FALSE,
+                        show.legend = NA, inherit.aes = TRUE, ...) {
+
+  params <- list(
+    na.rm = na.rm,
+    ...
+  )
+  if (identical(stat, "smooth")) {
+    params$method <- method
+    params$formula <- formula
+    params$se <- se
+  }
 
-GeomSmooth <- proto(Geom, {
-  objname <- "smooth"
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomSmooth,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = params
+  )
+}
 
-  draw <- function(., data, scales, coordinates, ...) {
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomSmooth <- ggproto("GeomSmooth", Geom,
+  draw_group = function(data, panel_scales, coord) {
     ribbon <- transform(data, colour = NA)
     path <- transform(data, alpha = NA)
 
-    has_ribbon <- function(x) !is.null(data$ymax) && !is.null(data$ymin)
+    has_ribbon <- !is.null(data$ymax) && !is.null(data$ymin)
 
     gList(
-      if (has_ribbon(data)) GeomRibbon$draw(ribbon, scales, coordinates),
-      GeomLine$draw(path, scales, coordinates)
+      if (has_ribbon) GeomRibbon$draw_group(ribbon, panel_scales, coord),
+      GeomLine$draw_panel(path, panel_scales, coord)
     )
-  }
+  },
 
-  guide_geom <- function(.) "smooth"
+  draw_key = draw_key_smooth,
 
-  default_stat <- function(.) StatSmooth
-  required_aes <- c("x", "y")
-  default_aes <- function(.) aes(colour="#3366FF", fill="grey60", size=0.5, linetype=1, weight=1, alpha=0.4)
-
-
-  draw_legend <- function(., data, params, ...) {
-    data <- aesdefaults(data, .$default_aes(), list(...))
-    data$fill <- alpha(data$fill, data$alpha)
-    data$alpha <- 1
-
-    if (is.null(params$se) || params$se) {
-      gTree(children = gList(
-        rectGrob(gp = gpar(col = NA, fill = data$fill)),
-        GeomPath$draw_legend(data, ...)
-      ))
-    } else {
-      GeomPath$draw_legend(data, ...)
-    }
-  }
+  required_aes = c("x", "y"),
 
-})
+  default_aes = aes(colour = "#3366FF", fill = "grey60", size = 1,
+    linetype = 1, weight = 1, alpha = 0.4)
+)
diff --git a/R/geom-spoke.r b/R/geom-spoke.r
new file mode 100644
index 0000000..3c3bdd3
--- /dev/null
+++ b/R/geom-spoke.r
@@ -0,0 +1,61 @@
+#' A line segment parameterised by location, direction and distance.
+#'
+#' @section Aesthetics:
+#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "spoke")}
+#'
+#' @inheritParams geom_segment
+#' @export
+#' @examples
+#' df <- expand.grid(x = 1:10, y=1:10)
+#' df$angle <- runif(100, 0, 2*pi)
+#' df$speed <- runif(100, 0, sqrt(0.1 * df$x))
+#'
+#' ggplot(df, aes(x, y)) +
+#'   geom_point() +
+#'   geom_spoke(aes(angle = angle), radius = 0.5)
+#'
+#' ggplot(df, aes(x, y)) +
+#'   geom_point() +
+#'   geom_spoke(aes(angle = angle, radius = speed))
+geom_spoke <- function(mapping = NULL, data = NULL, stat = "identity",
+                       position = "identity", na.rm = FALSE,
+                       show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    geom = GeomSpoke,
+    stat = stat,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @export
+#' @rdname geom_spoke
+#' @usage NULL
+stat_spoke <- function(...) {
+  message("stat_spoke is deprecated, please use geom_spoke")
+  geom_spoke(...)
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomSpoke <- ggproto("GeomSpoke", GeomSegment,
+  setup_data = function(data, params) {
+    data$radius <- data$radius %||% params$radius
+    data$angle <- data$angle %||% params$angle
+
+    transform(data,
+      xend = x + cos(angle) * radius,
+      yend = y + sin(angle) * radius
+    )
+  },
+  required_aes = c("x", "y", "angle", "radius")
+)
diff --git a/R/geom-text.r b/R/geom-text.r
index 2e7c909..679040c 100644
--- a/R/geom-text.r
+++ b/R/geom-text.r
@@ -1,32 +1,67 @@
 #' Textual annotations.
 #'
+#' \code{geom_text} adds text directly to the plot. \code{geom_label} draws
+#' a rectangle underneath the text, making it easier to read.
+#'
+#' Note the the "width" and "height" of a text element are 0, so stacking
+#' and dodging text will not work by default, and axis limits are not
+#' automatically expanded to include all text. Obviously, labels do have
+#' height and width, but they are physical units, not data units. The amount of
+#' space they occupy on that plot is not constant in data units: when you
+#' resize a plot, labels stay the same size, but the size of the axes changes.
+#'
 #' @section Aesthetics:
 #' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "text")}
 #'
+#' @section \code{geom_label}:
+#' Currently \code{geom_label} does not support the \code{rot} parameter and
+#' is considerably slower than \code{geom_text}. The \code{fill} aesthetic
+#' controls the background colour of the label.
+#'
+#' @section Alignment:
+#' You can modify text alignment with the \code{vjust} and \code{hjust}
+#' aesthetics. These can either be a number between 0 (right/bottom) and
+#' 1 (top/left) or a character ("left", "middle", "right", "bottom", "center",
+#' "top"). There are two special alignments: "inward" and "outward".
+#' Inward always aligns text towards the center, and outward aligns
+#' it away from the center
+#'
 #' @inheritParams geom_point
 #' @param parse If TRUE, the labels will be parsed into expressions and
 #'   displayed as described in ?plotmath
+#' @param nudge_x,nudge_y Horizontal and vertical adjustment to nudge labels by.
+#'   Useful for offsetting text from points, particularly on discrete scales.
+#' @param check_overlap If \code{TRUE}, text that overlaps previous text in the
+#'   same layer will not be plotted. A quick and dirty way
 #' @export
 #' @examples
-#' \donttest{
-#' p <- ggplot(mtcars, aes(x=wt, y=mpg, label=rownames(mtcars)))
+#' p <- ggplot(mtcars, aes(wt, mpg, label = rownames(mtcars)))
 #'
 #' p + geom_text()
+#' # Avoid overlaps
+#' p + geom_text(check_overlap = TRUE)
+#' # Labels with background
+#' p + geom_label()
 #' # Change size of the label
-#' p + geom_text(size=10)
-#' p <- p + geom_point()
+#' p + geom_text(size = 10)
 #'
 #' # Set aesthetics to fixed value
-#' p + geom_text()
-#' p + geom_point() + geom_text(hjust=0, vjust=0)
+#' p + geom_point() + geom_text(hjust = 0, nudge_x = 0.05)
+#' p + geom_point() + geom_text(vjust = 0, nudge_y = 0.5)
 #' p + geom_point() + geom_text(angle = 45)
+#' \dontrun{
+#' p + geom_text(family = "Times New Roman")
+#' }
 #'
 #' # Add aesthetic mappings
-#' p + geom_text(aes(colour=factor(cyl)))
-#' p + geom_text(aes(colour=factor(cyl))) + scale_colour_discrete(l=40)
+#' p + geom_text(aes(colour = factor(cyl)))
+#' p + geom_text(aes(colour = factor(cyl))) +
+#'   scale_colour_discrete(l = 40)
+#' p + geom_label(aes(fill = factor(cyl)), colour = "white", fontface = "bold")
 #'
-#' p + geom_text(aes(size=wt))
-#' p + geom_text(aes(size=wt)) + scale_size(range=c(3,6))
+#' p + geom_text(aes(size = wt))
+#' # Scale height of text, rather than sqrt(height)
+#' p + geom_text(aes(size = wt)) + scale_radius(range = c(3,6))
 #'
 #' # You can display expressions by setting parse = TRUE.  The
 #' # details of the display are described in ?plotmath, but note that
@@ -34,64 +69,142 @@
 #' p + geom_text(aes(label = paste(wt, "^(", cyl, ")", sep = "")),
 #'   parse = TRUE)
 #'
-#' # Add an annotation not from a variable source
-#' c <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
-#' c + geom_text(data = NULL, x = 5, y = 30, label = "plot mpg vs. wt")
-#' # Or, you can use annotate
-#' c + annotate("text", label = "plot mpg vs. wt", x = 2, y = 15, size = 8, colour = "red")
-#'
-#' # Use qplot instead
-#' qplot(wt, mpg, data = mtcars, label = rownames(mtcars),
-#'    geom=c("point", "text"))
-#' qplot(wt, mpg, data = mtcars, label = rownames(mtcars), size = wt) +
-#'   geom_text(colour = "red")
-#'
-#' # You can specify family, fontface and lineheight
-#' p <- ggplot(mtcars, aes(x=wt, y=mpg, label=rownames(mtcars)))
-#' p + geom_text(fontface=3)
-#' p + geom_text(aes(fontface=am+1))
-#' p + geom_text(aes(family=c("serif", "mono")[am+1]))
+#' # Add a text annotation
+#' p +
+#'   geom_text() +
+#'   annotate("text", label = "plot mpg vs. wt", x = 2, y = 15, size = 8, colour = "red")
+#'
+#' \donttest{
+#' # Aligning labels and bars --------------------------------------------------
+#' df <- data.frame(
+#'   x = factor(c(1, 1, 2, 2)),
+#'   y = c(1, 3, 2, 1),
+#'   grp = c("a", "b", "a", "b")
+#' )
+#'
+#' # ggplot2 doesn't know you want to give the labels the same virtual width
+#' # as the bars:
+#' ggplot(data = df, aes(x, y, fill = grp, label = y)) +
+#'   geom_bar(stat = "identity", position = "dodge") +
+#'   geom_text(position = "dodge")
+#' # So tell it:
+#' ggplot(data = df, aes(x, y, fill = grp, label = y)) +
+#'   geom_bar(stat = "identity", position = "dodge") +
+#'   geom_text(position = position_dodge(0.9))
+#' # Use you can't nudge and dodge text, so instead adjust the y postion
+#' ggplot(data = df, aes(x, y, fill = grp, label = y)) +
+#'   geom_bar(stat = "identity", position = "dodge") +
+#'   geom_text(aes(y = y + 0.05), position = position_dodge(0.9), vjust = 0)
+#'
+#' # To place text in the middle of each bar in a stacked barplot, you
+#' # need to do the computation yourself
+#' df <- transform(df, mid_y = ave(df$y, df$x, FUN = function(val) cumsum(val) - (0.5 * val)))
+#'
+#' ggplot(data = df, aes(x, y, fill = grp, label = y)) +
+#'  geom_bar(stat = "identity") +
+#'  geom_text(aes(y = mid_y))
+#'
+#' # Justification -------------------------------------------------------------
+#' df <- data.frame(
+#'   x = c(1, 1, 2, 2, 1.5),
+#'   y = c(1, 2, 1, 2, 1.5),
+#'   text = c("bottom-left", "bottom-right", "top-left", "top-right", "center")
+#' )
+#' ggplot(df, aes(x, y)) +
+#'   geom_text(aes(label = text))
+#' ggplot(df, aes(x, y)) +
+#'   geom_text(aes(label = text), vjust = "inward", hjust = "inward")
 #' }
-geom_text <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity",
-parse = FALSE, ...) {
-  GeomText$new(mapping = mapping, data = data, stat = stat, position = position,
-  parse = parse, ...)
+geom_text <- function(mapping = NULL, data = NULL, stat = "identity",
+                      position = "identity", parse = FALSE, ...,
+                      nudge_x = 0, nudge_y = 0, check_overlap = FALSE,
+                      na.rm = FALSE, show.legend = NA, inherit.aes = TRUE)
+{
+  if (!missing(nudge_x) || !missing(nudge_y)) {
+    if (!missing(position)) {
+      stop("Specify either `position` or `nudge_x`/`nudge_y`", call. = FALSE)
+    }
+
+    position <- position_nudge(nudge_x, nudge_y)
+  }
+
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomText,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      parse = parse,
+      check_overlap = check_overlap,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-GeomText <- proto(Geom, {
-  objname <- "text"
 
-  draw_groups <- function(., ...) .$draw(...)
-  draw <- function(., data, scales, coordinates, ..., parse = FALSE, na.rm = FALSE) {
-    data <- remove_missing(data, na.rm,
-      c("x", "y", "label"), name = "geom_text")
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomText <- ggproto("GeomText", Geom,
+  required_aes = c("x", "y", "label"),
+
+  default_aes = aes(
+    colour = "black", size = 3.88, angle = 0, hjust = 0.5,
+    vjust = 0.5, alpha = NA, family = "", fontface = 1, lineheight = 1.2
+  ),
 
+  draw_panel = function(data, panel_scales, coord, parse = FALSE,
+                        na.rm = FALSE, check_overlap = FALSE) {
     lab <- data$label
     if (parse) {
-      lab <- parse(text = lab)
+      lab <- parse(text = as.character(lab))
     }
 
-    with(coord_transform(coordinates, data, scales),
-      textGrob(lab, x, y, default.units="native",
-        hjust=hjust, vjust=vjust, rot=angle,
-        gp = gpar(col = alpha(colour, alpha), fontsize = size * .pt,
-          fontfamily = family, fontface = fontface, lineheight = lineheight))
-    )
-  }
+    data <- coord$transform(data, panel_scales)
+    if (is.character(data$vjust)) {
+      data$vjust <- compute_just(data$vjust, data$y)
+    }
+    if (is.character(data$hjust)) {
+      data$hjust <- compute_just(data$hjust, data$x)
+    }
 
-  draw_legend <- function(., data, ...) {
-    data <- aesdefaults(data, .$default_aes(), list(...))
-    with(data,
-      textGrob("a", 0.5, 0.5, rot = angle,
-      gp=gpar(col=alpha(colour, alpha), fontsize = size * .pt))
+    textGrob(
+      lab,
+      data$x, data$y, default.units = "native",
+      hjust = data$hjust, vjust = data$vjust,
+      rot = data$angle,
+      gp = gpar(
+        col = alpha(data$colour, data$alpha),
+        fontsize = data$size * .pt,
+        fontfamily = data$family,
+        fontface = data$fontface,
+        lineheight = data$lineheight
+      ),
+      check.overlap = check_overlap
     )
-  }
+  },
 
+  draw_key = draw_key_text
+)
 
-  default_stat <- function(.) StatIdentity
-  required_aes <- c("x", "y", "label")
-  default_aes <- function(.) aes(colour="black", size=5 , angle=0, hjust=0.5,
-    vjust=0.5, alpha = NA, family="", fontface=1, lineheight=1.2)
-  guide_geom <- function(x) "text"
+compute_just <- function(just, x) {
+  inward <- just == "inward"
+  just[inward] <- c("left", "middle", "right")[just_dir(x[inward])]
+  outward <- just == "outward"
+  just[outward] <- c("right", "middle", "left")[just_dir(x[outward])]
 
-})
+  unname(c(left = 0, center = 0.5, right = 1,
+    bottom = 0, middle = 0.5, top = 1)[just])
+}
+
+just_dir <- function(x, tol = 0.001) {
+  out <- rep(2L, length(x))
+  out[x < 0.5 - tol] <- 1L
+  out[x > 0.5 + tol] <- 3L
+  out
+}
diff --git a/R/geom-tile.r b/R/geom-tile.r
index 551bfe0..94d5e51 100644
--- a/R/geom-tile.r
+++ b/R/geom-tile.r
@@ -1,6 +1,11 @@
-#' Tile plane with rectangles.
+#' Draw rectangles.
 #'
-#' Similar to \code{\link{levelplot}} and \code{\link{image}}.
+#' \code{geom_rect} and \code{geom_tile} do the same thing, but are
+#' parameterised differently. \code{geom_rect} uses the locations of the four
+#' corners (\code{xmin}, \code{xmax}, \code{ymin} and \code{ymax}).
+#' \code{geom_tile} uses the center of the tile and its size (\code{x},
+#' \code{y}, \code{width}, \code{height}). \code{geom_raster} is a high
+#' performance special case for when all the tiles are the same size.
 #'
 #' @section Aesthetics:
 #' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "tile")}
@@ -8,91 +13,86 @@
 #' @inheritParams geom_point
 #' @export
 #' @examples
-#' \donttest{
-#' # Generate data
-#' pp <- function (n,r=4) {
-#'  x <- seq(-r*pi, r*pi, len=n)
-#'  df <- expand.grid(x=x, y=x)
-#'  df$r <- sqrt(df$x^2 + df$y^2)
-#'  df$z <- cos(df$r^2)*exp(-df$r/6)
-#'  df
-#' }
-#' p <- ggplot(pp(20), aes(x=x,y=y))
-#'
-#' p + geom_tile() #pretty useless!
-#'
-#' # Add aesthetic mappings
-#' p + geom_tile(aes(fill=z))
-#'
-#' # Change scale
-#' p + geom_tile(aes(fill=z)) + scale_fill_gradient(low="green", high="red")
-#'
-#' # Use qplot instead
-#' qplot(x, y, data=pp(20), geom="tile", fill=z)
-#' qplot(x, y, data=pp(100), geom="tile", fill=z)
-#'
-#' # Missing values
-#' p <- ggplot(pp(20)[sample(20*20, size=200),], aes(x=x,y=y,fill=z))
-#' p + geom_tile()
-#'
-#' # Input that works with image
-#' image(t(volcano)[ncol(volcano):1,])
-#' library(reshape2) # for melt
-#' ggplot(melt(volcano), aes(x=Var1, y=Var2, fill=value)) + geom_tile()
+#' # The most common use for rectangles is to draw a surface. You always want
+#' # to use geom_raster here because it's so much faster, and produces
+#' # smaller output when saving to PDF
+#' ggplot(faithfuld, aes(waiting, eruptions)) +
+#'  geom_raster(aes(fill = density))
 #'
-#' # inspired by the image-density plots of Ken Knoblauch
-#' cars <- ggplot(mtcars, aes(y=factor(cyl), x=mpg))
-#' cars + geom_point()
-#' cars + stat_bin(aes(fill=..count..), geom="tile", binwidth=3, position="identity")
-#' cars + stat_bin(aes(fill=..density..), geom="tile", binwidth=3, position="identity")
-#'
-#' cars + stat_density(aes(fill=..density..), geom="tile", position="identity")
-#' cars + stat_density(aes(fill=..count..), geom="tile", position="identity")
+#' # Interpolation smooths the surface & is most helpful when rendering images.
+#' ggplot(faithfuld, aes(waiting, eruptions)) +
+#'  geom_raster(aes(fill = density), interpolate = TRUE)
 #'
-#' # Another example with with unequal tile sizes
-#' x.cell.boundary <- c(0, 4, 6, 8, 10, 14)
-#' example <- data.frame(
+#' # If you want to draw arbitrary rectangles, use geom_tile() or geom_rect()
+#' df <- data.frame(
 #'   x = rep(c(2, 5, 7, 9, 12), 2),
-#'   y = factor(rep(c(1,2), each=5)),
-#'   z = rep(1:5, each=2),
-#'   w = rep(diff(x.cell.boundary), 2)
+#'   y = rep(c(1, 2), each = 5),
+#'   z = factor(rep(1:5, each = 2)),
+#'   w = rep(diff(c(0, 4, 6, 8, 10, 14)), 2)
 #' )
+#' ggplot(df, aes(x, y)) +
+#'   geom_tile(aes(fill = z))
+#' ggplot(df, aes(x, y)) +
+#'   geom_tile(aes(fill = z, width = w), colour = "grey50")
+#' ggplot(df, aes(xmin = x - w / 2, xmax = x + w / 2, ymin = y, ymax = y + 1)) +
+#'   geom_rect(aes(fill = z, width = w), colour = "grey50")
+#'
+#' \donttest{
+#' # Justification controls where the cells are anchored
+#' df <- expand.grid(x = 0:5, y = 0:5)
+#' df$z <- runif(nrow(df))
+#' # default is compatible with geom_tile()
+#' ggplot(df, aes(x, y, fill = z)) + geom_raster()
+#' # zero padding
+#' ggplot(df, aes(x, y, fill = z)) + geom_raster(hjust = 0, vjust = 0)
 #'
-#' qplot(x, y, fill=z, data=example, geom="tile")
-#' qplot(x, y, fill=z, data=example, geom="tile", width=w)
-#' qplot(x, y, fill=factor(z), data=example, geom="tile", width=w)
+#' # Inspired by the image-density plots of Ken Knoblauch
+#' cars <- ggplot(mtcars, aes(mpg, factor(cyl)))
+#' cars + geom_point()
+#' cars + stat_bin2d(aes(fill = ..count..), binwidth = c(3,1))
+#' cars + stat_bin2d(aes(fill = ..density..), binwidth = c(3,1))
 #'
-#' # You can manually set the colour of the tiles using
-#' # scale_manual
-#' col <- c("darkblue", "blue", "green", "orange", "red")
-#' qplot(x, y, fill=col[z], data=example, geom="tile", width=w, group=1) +
-#'   scale_fill_identity(labels=letters[1:5], breaks=col)
+#' cars + stat_density(aes(fill = ..density..), geom = "raster", position = "identity")
+#' cars + stat_density(aes(fill = ..count..), geom = "raster", position = "identity")
 #' }
-geom_tile <- function (mapping = NULL, data = NULL, stat = "identity", position = "identity", ...) {
-  GeomTile$new(mapping = mapping, data = data, stat = stat, position = position, ...)
+geom_tile <- function(mapping = NULL, data = NULL, stat = "identity",
+                      position = "identity", na.rm = FALSE,
+                      show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomTile,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-GeomTile <- proto(Geom, {
-  objname <- "tile"
-
-  reparameterise <- function(., df, params) {
-    df$width <- df$width %||% params$width %||% resolution(df$x, FALSE)
-    df$height <- df$height %||% params$height %||% resolution(df$y, FALSE)
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+#' @include geom-rect.r
+GeomTile <- ggproto("GeomTile", GeomRect,
+  setup_data = function(data, params) {
+    data$width <- data$width %||% params$width %||% resolution(data$x, FALSE)
+    data$height <- data$height %||% params$height %||% resolution(data$y, FALSE)
 
-    transform(df,
+    transform(data,
       xmin = x - width / 2,  xmax = x + width / 2,  width = NULL,
       ymin = y - height / 2, ymax = y + height / 2, height = NULL
     )
-  }
+  },
 
-  draw_groups <- function(., data,  scales, coordinates, ...) {
-    # data$colour[is.na(data$colour)] <- data$fill[is.na(data$colour)]
-    GeomRect$draw_groups(data, scales, coordinates, ...)
-  }
+  default_aes = aes(fill = "grey20", colour = NA, size = 0.1, linetype = 1,
+    alpha = NA),
 
+  required_aes = c("x", "y"),
 
-  default_stat <- function(.) StatIdentity
-  default_aes <- function(.) aes(fill="grey20", colour=NA, size=0.1, linetype=1, alpha = NA)
-  required_aes <- c("x", "y")
-  guide_geom <- function(.) "polygon"
-})
+  draw_key = draw_key_rect
+)
diff --git a/R/geom-violin.r b/R/geom-violin.r
index 105c2b5..0a84d92 100644
--- a/R/geom-violin.r
+++ b/R/geom-violin.r
@@ -4,23 +4,22 @@
 #' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "violin")}
 #'
 #' @inheritParams geom_point
+#' @param draw_quantiles If \code{not(NULL)} (default), draw horizontal lines
+#'   at the given quantiles of the density estimate.
 #' @param trim If \code{TRUE} (default), trim the tails of the violins
 #'   to the range of the data. If \code{FALSE}, don't trim the tails.
-#' @param scale if "area" (default), all violins have the same area (before trimming
-#'   the tails). If "count", areas are scaled proportionally to the number of
-#'   observations. If "width", all violins have the same maximum width.
+#' @param geom,stat Use to override the default connection between
+#'   \code{geom_violin} and \code{stat_ydensity}.
 #' @export
+#' @references Hintze, J. L., Nelson, R. D. (1998) Violin Plots: A Box
+#' Plot-Density Trace Synergism. The American Statistician 52, 181-184.
 #' @examples
-#' \donttest{
 #' p <- ggplot(mtcars, aes(factor(cyl), mpg))
-#'
 #' p + geom_violin()
-#' qplot(factor(cyl), mpg, data = mtcars, geom = "violin")
 #'
+#' \donttest{
 #' p + geom_violin() + geom_jitter(height = 0)
 #' p + geom_violin() + coord_flip()
-#' qplot(factor(cyl), mpg, data = mtcars, geom = "violin") +
-#'   coord_flip()
 #'
 #' # Scale maximum width proportional to sample size:
 #' p + geom_violin(scale = "count")
@@ -44,16 +43,16 @@
 #'
 #' # Set aesthetics to fixed value
 #' p + geom_violin(fill = "grey80", colour = "#3366FF")
-#' qplot(factor(cyl), mpg, data = mtcars, geom = "violin",
-#'   colour = I("#3366FF"))
+#'
+#' # Show quartiles
+#' p + geom_violin(draw_quantiles = c(0.25, 0.5, 0.75))
 #'
 #' # Scales vs. coordinate transforms -------
+#' if (require("ggplot2movies")) {
 #' # Scale transformations occur before the density statistics are computed.
 #' # Coordinate transformations occur afterwards.  Observe the effect on the
 #' # number of outliers.
-#' library(plyr) # to access round_any
-#' m <- ggplot(movies, aes(y = votes, x = rating,
-#'    group = round_any(rating, 0.5)))
+#' m <- ggplot(movies, aes(y = votes, x = rating, group = cut_width(rating, 0.5)))
 #' m + geom_violin()
 #' m + geom_violin() + scale_y_log10()
 #' m + geom_violin() + coord_trans(y = "log10")
@@ -61,54 +60,113 @@
 #'
 #' # Violin plots with continuous x:
 #' # Use the group aesthetic to group observations in violins
-#' qplot(year, budget, data = movies, geom = "violin")
-#' qplot(year, budget, data = movies, geom = "violin",
-#'   group = round_any(year, 10, floor))
+#' ggplot(movies, aes(year, budget)) + geom_violin()
+#' ggplot(movies, aes(year, budget)) +
+#'   geom_violin(aes(group = cut_width(year, 10)), scale = "width")
 #' }
-geom_violin <- function (mapping = NULL, data = NULL, stat = "ydensity", position = "dodge",
-trim = TRUE, scale = "area", ...) {
-  GeomViolin$new(mapping = mapping, data = data, stat = stat,
-  position = position, trim = trim, scale = scale, ...)
+#' }
+geom_violin <- function(mapping = NULL, data = NULL, stat = "ydensity",
+                        draw_quantiles = NULL, position = "dodge",
+                        trim = TRUE, scale = "area",
+                        na.rm = FALSE, show.legend = NA, inherit.aes = TRUE,
+                        ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = stat,
+    geom = GeomViolin,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      trim = trim,
+      scale = scale,
+      draw_quantiles = draw_quantiles,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-GeomViolin <- proto(Geom, {
-  objname <- "violin"
-
-  reparameterise <- function(., df, params) {
-    df$width <- df$width %||%
-      params$width %||% (resolution(df$x, FALSE) * 0.9)
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomViolin <- ggproto("GeomViolin", Geom,
+  setup_data = function(data, params) {
+    data$width <- data$width %||%
+      params$width %||% (resolution(data$x, FALSE) * 0.9)
 
     # ymin, ymax, xmin, and xmax define the bounding rectangle for each group
-    ddply(df, .(group), transform,
-          ymin = min(y),
-          ymax = max(y),
-          xmin = x - width / 2,
-          xmax = x + width / 2)
-
-  }
-
-  draw <- function(., data, ...) {
+    plyr::ddply(data, "group", transform,
+      xmin = x - width / 2,
+      xmax = x + width / 2
+    )
+  },
 
+  draw_group = function(self, data, ..., draw_quantiles = NULL) {
     # Find the points for the line to go all the way around
-    data <- transform(data, xminv = x - violinwidth * (x-xmin),
-                            xmaxv = x + violinwidth * (xmax-x))
+    data <- transform(data,
+      xminv = x - violinwidth * (x - xmin),
+      xmaxv = x + violinwidth * (xmax - x)
+    )
 
     # Make sure it's sorted properly to draw the outline
-    newdata <- rbind(arrange(transform(data, x = xminv), y),
-                     arrange(transform(data, x = xmaxv), -y))
+    newdata <- rbind(
+      plyr::arrange(transform(data, x = xminv), y),
+      plyr::arrange(transform(data, x = xmaxv), -y)
+    )
 
     # Close the polygon: set first and last point the same
     # Needed for coord_polar and such
     newdata <- rbind(newdata, newdata[1,])
 
-    ggname(.$my_name(), GeomPolygon$draw(newdata, ...))
-  }
+    # Draw quantiles if requested
+    if (length(draw_quantiles) > 0) {
+      stopifnot(all(draw_quantiles >= 0), all(draw_quantiles <= 1))
+
+      # Compute the quantile segments and combine with existing aesthetics
+      quantiles <- create_quantile_segment_frame(data, draw_quantiles)
+      aesthetics <- data[
+        rep(1, nrow(quantiles)),
+        setdiff(names(data), c("x", "y")),
+        drop = FALSE
+      ]
+      both <- cbind(quantiles, aesthetics)
+      quantile_grob <- GeomPath$draw_panel(both, ...)
+
+      ggname("geom_violin", grobTree(
+        GeomPolygon$draw_panel(newdata, ...),
+        quantile_grob)
+      )
+    } else {
+      ggname("geom_violin", GeomPolygon$draw_panel(newdata, ...))
+    }
+  },
+
+  draw_key = draw_key_polygon,
 
-  guide_geom <- function(.) "polygon"
+  default_aes = aes(weight = 1, colour = "grey20", fill = "white", size = 0.5,
+    alpha = NA, linetype = "solid"),
 
-  default_stat <- function(.) StatYdensity
-  default_pos <- function(.) PositionDodge
-  default_aes <- function(.) aes(weight=1, colour="grey20", fill="white", size=0.5, alpha = NA, linetype = "solid")
-  required_aes <- c("x", "y")
+  required_aes = c("x", "y")
+)
+
+# Returns a data.frame with info needed to draw quantile segments.
+create_quantile_segment_frame <- function(data, draw_quantiles) {
+  dens <- cumsum(data$density) / sum(data$density)
+  ecdf <- stats::approxfun(dens, data$y)
+  ys <- ecdf(draw_quantiles) # these are all the y-values for quantiles
+
+  # Get the violin bounds for the requested quantiles
+  violin.xminvs <- (stats::approxfun(data$y, data$xminv))(ys)
+  violin.xmaxvs <- (stats::approxfun(data$y, data$xmaxv))(ys)
+
+  # We have two rows per segment drawn. Each segments gets its own group.
+  data.frame(
+    x = interleave(violin.xminvs, violin.xmaxvs),
+    y = rep(ys, each = 2),
+    group = rep(ys, each = 2)
+  )
+}
 
-})
diff --git a/R/geom-vline.r b/R/geom-vline.r
index 4281b89..27afdc6 100644
--- a/R/geom-vline.r
+++ b/R/geom-vline.r
@@ -1,84 +1,53 @@
-#' Line, vertical.
-#'
-#' This geom allows you to annotate the plot with vertical lines (see
-#' \code{\link{geom_hline}} and \code{\link{geom_abline}} for other types of
-#' lines.
-#'
-#' There are two ways to use it.  You can either specify the intercept of the
-#' line in the call to the geom, in which case the line will be in the same
-#' position in every panel.  Alternatively, you can supply a different
-#' intercept for each panel using a data.frame.  See the examples for the
-#' differences.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "vline")}
-#'
-#' @param show_guide should a legend be drawn? (defaults to \code{FALSE})
-#' @inheritParams geom_point
-#' @seealso
-#'  \code{\link{geom_hline}} for horizontal lines,
-#'  \code{\link{geom_abline}} for lines defined by a slope and intercept,
-#'  \code{\link{geom_segment}} for a more general approach"
-#' @export
-#' @examples
-#' # Fixed lines
-#' p <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point()
-#' p + geom_vline(xintercept = 5)
-#' p + geom_vline(xintercept = 1:5)
-#' p + geom_vline(xintercept = 1:5, colour="green", linetype = "longdash")
-#' p + geom_vline(aes(xintercept = wt))
-#'
-#' # With coordinate transforms
-#' p + geom_vline(aes(xintercept = wt)) + coord_equal()
-#' p + geom_vline(aes(xintercept = wt)) + coord_flip()
-#' p + geom_vline(aes(xintercept = wt)) + coord_polar()
-#'
-#' p2 <- p + aes(colour = factor(cyl))
-#' p2 + geom_vline(xintercept = 15)
-#'
-#' # To display different lines in different facets, you need to
-#' # create a data frame.
-#' p <- qplot(mpg, wt, data=mtcars, facets = vs ~ am)
-#' vline.data <- data.frame(z = c(15, 20, 25, 30), vs = c(0, 0, 1, 1), am = c(0, 1, 0, 1))
-#' p + geom_vline(aes(xintercept = z), vline.data)
-geom_vline <- function (mapping = NULL, data = NULL, stat = "vline", position = "identity", show_guide = FALSE, ...) {
-  GeomVline$new(mapping = mapping, data = data, stat = stat, position = position, show_guide = show_guide, ...)
-}
+#' @include stat-.r
+NULL
 
-GeomVline <- proto(Geom, {
-  objname <- "vline"
-
-  new <- function(., data = NULL, mapping = NULL, xintercept = NULL, ...) {
-    if (is.numeric(xintercept)) {
-      data <- data.frame(xintercept = xintercept)
-      xintercept <- NULL
-      mapping <- aes_all(names(data))
-    }
-    .super$new(., data = data, mapping = mapping, inherit.aes = FALSE,
-      xintercept = xintercept, ...)
+#' @export
+#' @rdname geom_abline
+geom_vline <- function(mapping = NULL, data = NULL,
+                       ...,
+                       xintercept,
+                       na.rm = FALSE, show.legend = NA) {
+
+  # Act like an annotation
+  if (!missing(xintercept)) {
+    data <- data.frame(xintercept = xintercept)
+    mapping <- aes(xintercept = xintercept)
+    show.legend <- FALSE
   }
 
-  draw <- function(., data, scales, coordinates, ...) {
-    ranges <- coord_range(coordinates, scales)
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatIdentity,
+    geom = GeomVline,
+    position = PositionIdentity,
+    show.legend = show.legend,
+    inherit.aes = FALSE,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+GeomVline <- ggproto("GeomVline", Geom,
+  draw_panel = function(data, panel_scales, coord) {
+    ranges <- coord$range(panel_scales)
 
+    data$x    <- data$xintercept
+    data$xend <- data$xintercept
     data$y    <- ranges$y[1]
     data$yend <- ranges$y[2]
 
-    GeomSegment$draw(unique(data), scales, coordinates)
-  }
-
-
-  default_stat <- function(.) StatVline
-  default_aes <- function(.) aes(colour="black", size=0.5, linetype=1, alpha = NA)
-  guide_geom <- function(.) "vline"
+    GeomSegment$draw_panel(unique(data), panel_scales, coord)
+  },
 
-  draw_legend <- function(., data, ...) {
-    data <- aesdefaults(data, .$default_aes(), list(...))
-
-    with(data,
-      ggname(.$my_name(), segmentsGrob(0.5, 0, 0.5, 1, default.units="npc",
-      gp=gpar(col=alpha(colour, alpha), lwd=size * .pt, lty=linetype, lineend="butt")))
-    )
-  }
+  default_aes = aes(colour = "black", size = 0.5, linetype = 1, alpha = NA),
+  required_aes = "xintercept",
 
-})
+  draw_key = draw_key_vline
+)
diff --git a/R/ggplot2.r b/R/ggplot2.r
index 0aca6e5..90f86f6 100644
--- a/R/ggplot2.r
+++ b/R/ggplot2.r
@@ -1,220 +1,4 @@
-#' ggplot2.
-#'
-#' @name ggplot2
-#' @docType package
-#' @import plyr digest scales grid reshape2 proto gtable
-NULL
-
-#' Prices of 50,000 round cut diamonds
-#'
-#' A dataset containing the prices and other attributes of almost 54,000
-#'  diamonds. The variables are as follows:
-#'
-#' \itemize{
-#'   \item price. price in US dollars (\$326--\$18,823)
-#'   \item carat. weight of the diamond (0.2--5.01)
-#'   \item cut. quality of the cut (Fair, Good, Very Good, Premium, Ideal)
-#'   \item colour. diamond colour, from J (worst) to D (best)
-#'   \item clarity. a measurement of how clear the diamond is (I1 (worst), SI1, SI2, VS1, VS2, VVS1, VVS2, IF (best))
-#'   \item x. length in mm (0--10.74)
-#'   \item y. width in mm (0--58.9)
-#'   \item z. depth in mm (0--31.8)
-#'   \item depth. total depth percentage = z / mean(x, y) = 2 * z / (x + y) (43--79)
-#'   \item table. width of top of diamond relative to widest point (43--95)
-#' }
-#'
-#' @docType data
-#' @keywords datasets
-#' @name diamonds
-#' @usage data(diamonds)
-#' @format A data frame with 53940 rows and 10 variables
-NULL
-
-
-#' US economic time series.
-#'
-#' This dataset was produced from US economic time series data available from \url{http://research.stlouisfed.org/fred2}.
-#'
-#' \itemize{
-#'   \item date.  Month of data collection
-#'
-#'   \item psavert, personal savings rate, \url{http://research.stlouisfed.org/fred2/series/PSAVERT/}
-#'   \item pce, personal consumption expenditures, in billions of dollars, \url{http://research.stlouisfed.org/fred2/series/PCE}
-#'   \item unemploy, number of unemployed in thousands, \url{http://research.stlouisfed.org/fred2/series/UNEMPLOY}
-#'   \item uempmed, median duration of unemployment, in week, \url{http://research.stlouisfed.org/fred2/series/UEMPMED}
-#'   \item pop, total population, in thousands, \url{http://research.stlouisfed.org/fred2/series/POP}
-#'
-#' }
-#'
-#' @docType data
-#' @keywords datasets
-#' @name economics
-#' @usage data(economics)
-#' @format A data frame with 478 rows and 6 variables
-NULL
-
-#' Midwest demographics.
-#'
-#' Demographic information of midwest counties
-#'
-#' The variables are as follows:
-#'
-#' \itemize{
-#'  \item PID
-#'  \item county
-#'  \item state
-#'  \item area
-#'  \item poptotal.  Total population
-#'  \item popdensity. Population density
-#'  \item popwhite.  Number of whites.
-#'  \item popblack.  Number of blacks.
-#'  \item popamerindian.  Number of American Indians.
-#'  \item popasian.  Number of Asians.
-#'  \item popother.  Number of other races.
-#'  \item percwhite.  Percent white.
-#'  \item percblack.  Percent black.
-#'  \item percamerindan.  Percent American Indian.
-#'  \item percasian. Percent Asian.
-#'  \item percother. Percent other races.
-#'  \item popadults.  Number of adults.
-#'  \item perchsd.
-#'  \item percollege.  Percent college educated.
-#'  \item percprof.  Percent profession.
-#'  \item poppovertyknown.
-#'  \item percpovertyknown
-#'  \item percbelowpoverty
-#'  \item percchildbelowpovert
-#'  \item percadultpoverty
-#'  \item percelderlypoverty
-#'  \item inmetro.  In a metro area.
-#'  \item category'
-#' }
-#'
-#' @docType data
-#' @keywords datasets
-#' @name midwest
-#' @usage data(midwest)
-#' @format A data frame with 437 rows and 28 variables
-NULL
-
-
-#' Movie information and user ratings from IMDB.com.
-#'
-#' The internet movie database, \url{http://imdb.com/}, is a website devoted
-#' to collecting movie data supplied by studios and fans.  It claims to be the
-#' biggest movie database on the web and is run by amazon.  More about
-#' information imdb.com can be found online,
-#' \url{http://imdb.com/help/show_leaf?about}, including information about
-#' the data collection process,
-#' \url{http://imdb.com/help/show_leaf?infosource}.
-#'
-#' Movies were selected for inclusion if they had a known length and had been rated by at least one imdb user.  The data set contains the following fields:
-#'
-#' \itemize{
-#'   \item title.  Title of the movie.
-#'   \item year.  Year of release.
-#'   \item budget.  Total budget (if known) in US dollars
-#'   \item length.  Length in minutes.
-#'   \item rating.  Average IMDB user rating.
-#'   \item votes.  Number of IMDB users who rated this movie.
-#'   \item r1-10.  Multiplying by ten gives percentile (to nearest 10\%) of users who rated this movie a 1.
-#'   \item mpaa.  MPAA rating.
-#'   \item action, animation, comedy, drama, documentary, romance, short.  Binary variables representing if movie was classified as belonging to that genre.
-#' }
-#'
-#' @docType data
-#' @keywords datasets
-#' @usage data(movies)
-#' @name movies
-#' @format A data frame with 28819 rows and 24 variables
-#' @references \url{http://had.co.nz/data/movies/}
-NULL
-
-#' Fuel economy data from 1999 and 2008 for 38 popular models of car
-#'
-#' This dataset contains a subset of the fuel economy data that the EPA makes
-#' available on \url{http://fueleconomy.gov}.  It contains only models which
-#' had a new release every year between 1999 and 2008 - this was used as a
-#' proxy for the popularity of the car.
-#'
-#' \itemize{
-#'   \item manufacturer.
-#'   \item model.
-#'   \item displ. engine displacement, in litres
-#'   \item year.
-#'   \item cyl. number of cylinders
-#'   \item trans. type of transmission
-#'   \item drv. f = front-wheel drive, r = rear wheel drive, 4 = 4wd
-#'   \item cty. city miles per gallon
-#'   \item hwy. highway miles per gallon
-#'   \item fl.
-#'   \item class.
-#' }
-#'
-#' @docType data
-#' @keywords datasets
-#' @name mpg
-#' @usage data(mpg)
-#' @format A data frame with 234 rows and 11 variables
-NULL
-
-#' An updated and expanded version of the mammals sleep dataset.
-#'
-#' This is an updated and expanded version of the mammals sleep dataset.
-#' Updated sleep times and weights were taken from V. M. Savage and G. B.
-#' West. A quantitative, theoretical framework for understanding mammalian
-#' sleep. Proceedings of the National Academy of Sciences, 104 (3):1051-1056,
-#' 2007.
-#'
-#' Additional variables order, conservation status and vore were added from
-#' wikipedia.
-#'
-#' \itemize{
-#'   \item name. common name
-#'   \item genus.
-#'   \item vore. carnivore, omnivore or herbivore?
-#'   \item order.
-#'   \item conservation. the conservation status of the animal
-#'   \item sleep\_total. total amount of sleep, in hours
-#'   \item sleep\_rem. rem sleep, in hours
-#'   \item sleep\_cycle. length of sleep cycle, in hours
-#'   \item awake. amount of time spent awake, in hours
-#'   \item brainwt. brain weight in kilograms
-#'   \item bodywt. body weight in kilograms
-#' }
-#'
-#' @docType data
-#' @keywords datasets
-#' @name msleep
-#' @usage data(msleep)
-#' @format A data frame with 83 rows and 11 variables
-NULL
-
-#' Terms of 10 presidents from Eisenhower to Bush W.
-#'
-#' The names of each president, the start and end date of their term, and
-#' their party of 10 US presidents from Eisenhower to Bush W.
-#'
-#' @docType data
-#' @keywords datasets
-#' @name presidential
-#' @usage data(presidential)
-#' @format A data frame with 10 rows and 4 variables
-NULL
-
-#' Vector field of seal movements.
-#'
-#' This vector field was produced from the data described in Brillinger, D.R.,
-#' Preisler, H.K., Ager, A.A. and Kie, J.G. "An exploratory data analysis
-#' (EDA) of the paths of moving animals". J. Statistical Planning and
-#' Inference 122 (2004), 43-63, using the methods of Brillinger, D.R.,
-#' "Learning a potential function from a trajectory", Signal Processing
-#'  Letters. December (2007).
-#'
-#' @name seals
-#' @usage data(seals)
-#' @docType data
-#' @keywords datasets
-#' @format A data frame with 1155 rows and 4 variables
-#' @references \url{http://www.stat.berkeley.edu/~brill/Papers/jspifinal.pdf}
+#' @import scales grid gtable
+#' @importFrom plyr defaults
+#' @importFrom stats setNames
 NULL
diff --git a/R/ggproto.r b/R/ggproto.r
new file mode 100644
index 0000000..903d2d2
--- /dev/null
+++ b/R/ggproto.r
@@ -0,0 +1,280 @@
+#' Create a new ggproto object
+#'
+#' ggproto is inspired by the proto package, but it has some important
+#' differences. Notably, it cleanly supports cross-package inheritance, and has
+#' faster performance.
+#'
+#' @section Calling ggproto methods:
+#'
+#' ggproto methods can take an optional \code{self} argument: if it is present,
+#' it is a regular method; if it's absent, it's a "static" method (i.e. it
+#' doesn't use any fields).
+#'
+#' Imagine you have a ggproto object \code{Adder}, which has a
+#' method \code{addx = function(self, n) n + self$x}. Then, to call this
+#' function, you would use \code{Adder$addx(10)} -- the \code{self} is passed
+#' in automatically by the wrapper function. \code{self} be located anywhere
+#' in the function signature, although customarily it comes first.
+#'
+#' @section Calling methods in a parent:
+#'
+#' To explicitly call a methods in a parent, use
+#' \code{ggproto_parent(Parent, self)}.
+#'
+#' @param _class Class name to assign to the object. This is stored as the class
+#'   attribute of the object. If \code{NULL} (the default), no class name will
+#'   be added to the object.
+#' @param _inherit ggproto object to inherit from. If \code{NULL}, don't inherit
+#'   from any object.
+#' @param parent,self Access parent class \code{parent} of object \code{self}.
+#' @param ... A list of members in the ggproto object.
+#' @export
+ggproto <- function(`_class` = NULL, `_inherit` = NULL, ...) {
+  e <- new.env(parent = emptyenv())
+
+  members <- list(...)
+  if (length(members) != sum(nzchar(names(members)))) {
+    stop("All members of a ggproto object must be named.")
+  }
+  list2env(members, envir = e)
+
+  if (!is.null(`_inherit`)) {
+    if (!is.ggproto(`_inherit`)) {
+      stop("`_inherit` must be a ggproto object.")
+    }
+    e$super <- `_inherit`
+    class(e) <- c(`_class`, class(`_inherit`))
+
+  } else {
+    class(e) <- c(`_class`, "ggproto")
+  }
+
+  e
+}
+
+#' Is an object a ggproto object?
+#'
+#' @param x An object to test.
+#' @export
+is.ggproto <- function(x) inherits(x, "ggproto")
+
+fetch_ggproto <- function(x, name) {
+  res <- NULL
+
+  val <- .subset2(x, name)
+  # The is.null check is an optimization for a common case; exists() also
+  # catches the case where the value exists but has a NULL value.
+  if (!is.null(val) || exists(name, envir = x, inherits = FALSE)) {
+    res <- val
+  } else {
+    # If not found here, recurse into super environments
+    super <- .subset2(x, "super")
+    if (is.ggproto(super))
+      res <- fetch_ggproto(super, name)
+  }
+
+  res
+}
+
+#' @export
+#' @rdname ggproto
+ggproto_parent <- function(parent, self) {
+  structure(list(parent = parent, self = self), class = "ggproto_parent")
+}
+
+#' @export
+`$.ggproto` <- function(x, name) {
+  res <- fetch_ggproto(x, name)
+  if (!is.function(res)) {
+    return(res)
+  }
+
+  make_proto_method(x, res)
+}
+
+#' @export
+`$.ggproto_parent` <- function(x, name) {
+  res <- fetch_ggproto(.subset2(x, "parent"), name)
+  if (!is.function(res)) {
+    return(res)
+  }
+
+  make_proto_method(.subset2(x, "self"), res)
+}
+
+make_proto_method <- function(self, f) {
+  args <- formals(f)
+  # is.null is a fast path for a common case; the %in% check is slower but also
+  # catches the case where there's a `self = NULL` argument.
+  has_self  <- !is.null(args[["self"]]) || "self"  %in% names(args)
+
+  if (has_self) {
+    fun <- function(...) f(..., self = self)
+  } else {
+    fun <- function(...) f(...)
+  }
+
+  class(fun) <- "ggproto_method"
+  fun
+}
+
+
+#' @export
+`[[.ggproto` <- `$.ggproto`
+
+#' Convert a ggproto object to a list
+#'
+#' This will not include the object's \code{super} member.
+#'
+#' @param x A ggproto object to convert to a list.
+#' @param inherit If \code{TRUE} (the default), flatten all inherited items into
+#'   the returned list. If \code{FALSE}, do not include any inherited items.
+#' @param ... Further arguments to pass to \code{as.list.environment}.
+#' @export
+as.list.ggproto <- function(x, inherit = TRUE, ...) {
+  res <- list()
+
+  if (inherit) {
+    if (!is.null(x$super)) {
+      res <- as.list(x$super)
+    }
+  }
+
+  current <- as.list.environment(x, ...)
+  res[names(current)] <- current
+  res$super <- NULL
+  res
+}
+
+
+#' Print a ggproto object
+#'
+#' If a ggproto object has a \code{$print} method, this will call that method.
+#' Otherwise, it will print out the members of the object, and optionally, the
+#' members of the inherited objects.
+#'
+#' @param x A ggproto object to print.
+#' @param flat If \code{TRUE} (the default), show a flattened list of all local
+#'   and inherited members. If \code{FALSE}, show the inheritance hierarchy.
+#' @param ... If the ggproto object has a \code{print} method, further arguments
+#'   will be passed to it. Otherwise, these arguments are unused.
+#'
+#' @export
+print.ggproto <- function(x, ..., flat = TRUE) {
+  if (is.function(x$print)) {
+    x$print(...)
+
+  } else {
+    cat(format(x, flat = flat), "\n", sep = "")
+    invisible(x)
+  }
+}
+
+
+#' Format a ggproto object
+#'
+#' @inheritParams print.ggproto
+#' @export
+format.ggproto <-  function(x, ..., flat = TRUE) {
+  classes_str <- function(obj) {
+    classes <- setdiff(class(obj), "ggproto")
+    if (length(classes) == 0)
+      return("")
+    paste0(": Class ", paste(classes, collapse = ', '))
+  }
+
+  # Get a flat list if requested
+  if (flat) {
+    objs <- as.list(x, inherit = TRUE)
+  } else {
+    objs <- x
+  }
+
+  str <- paste0(
+    "<ggproto object", classes_str(x), ">\n",
+    indent(object_summaries(objs, flat = flat), 4)
+  )
+
+  if (flat && !is.null(x$super)) {
+    str <- paste0(
+      str, "\n",
+      indent(
+        paste0("super: ", " <ggproto object", classes_str(x$super), ">"),
+        4
+      )
+    )
+  }
+
+  str
+}
+
+# Return a summary string of the items of a list or environment
+# x must be a list or environment
+object_summaries <- function(x, exclude = NULL, flat = TRUE) {
+  if (length(x) == 0)
+    return(NULL)
+
+  if (is.list(x))
+    obj_names <- sort(names(x))
+  else if (is.environment(x))
+    obj_names <- ls(x, all.names = TRUE)
+
+  obj_names <- setdiff(obj_names, exclude)
+
+  values <- vapply(obj_names, function(name) {
+    obj <- x[[name]]
+    if (is.function(obj)) "function"
+    else if (is.ggproto(obj)) format(obj, flat = flat)
+    else if (is.environment(obj)) "environment"
+    else if (is.null(obj)) "NULL"
+    else if (is.atomic(obj)) trim(paste(as.character(obj), collapse = " "))
+    else paste(class(obj), collapse = ", ")
+  }, FUN.VALUE = character(1))
+
+  paste0(obj_names, ": ", values, sep = "", collapse = "\n")
+}
+
+# Given a string, indent every line by some number of spaces.
+# The exception is to not add spaces after a trailing \n.
+indent <- function(str, indent = 0) {
+  gsub("(\\n|^)(?!$)",
+    paste0("\\1", paste(rep(" ", indent), collapse = "")),
+    str,
+    perl = TRUE
+  )
+}
+
+# Trim a string to n characters; if it's longer than n, add " ..." to the end
+trim <- function(str, n = 60) {
+  if (nchar(str) > n) paste(substr(str, 1, 56), "...")
+  else str
+}
+
+#' @export
+print.ggproto_method <- function(x, ...) {
+  cat(format(x), sep = "")
+}
+
+#' @export
+format.ggproto_method <- function(x, ...) {
+
+  # Given a function, return a string from srcref if present. If not present,
+  # paste the deparsed lines of code together.
+  format_fun <- function(fn) {
+    srcref <- attr(fn, "srcref", exact = TRUE)
+    if (is.null(srcref))
+      return(paste(format(fn), collapse = "\n"))
+
+    paste(as.character(srcref), collapse = "\n")
+  }
+
+  x <- unclass(x)
+  paste0(
+    "<ggproto method>",
+    "\n  <Wrapper function>\n    ", format_fun(x),
+    "\n\n  <Inner function (f)>\n    ", format_fun(environment(x)$f)
+  )
+}
+
+# proto2 TODO: better way of getting formals for self$draw
+ggproto_formals <- function(x) formals(environment(x)$f)
diff --git a/R/grob-absolute.r b/R/grob-absolute.r
index a2d9388..cce1387 100644
--- a/R/grob-absolute.r
+++ b/R/grob-absolute.r
@@ -1,6 +1,6 @@
 #' Absolute grob
 #'
-#' This grob has fixed dimesions and position.
+#' This grob has fixed dimensions and position.
 #'
 #' It's still experimental
 #'
@@ -12,7 +12,7 @@ absoluteGrob <- function(grob, width = NULL, height = NULL,
     children = grob,
     width = width, height = height,
     xmin = xmin, ymin = ymin,
-    vp = vp, cl="absoluteGrob"
+    vp = vp, cl = "absoluteGrob"
   )
 }
 
diff --git a/R/grob-dotstack.r b/R/grob-dotstack.r
index 3f257ba..be53344 100644
--- a/R/grob-dotstack.r
+++ b/R/grob-dotstack.r
@@ -1,4 +1,4 @@
-dotstackGrob <- function (
+dotstackGrob <- function(
     x = unit(0.5, "npc"),     # x pos of the dotstack's origin
     y = unit(0.5, "npc"),     # y pos of the dotstack's origin
     stackaxis = "y",
@@ -22,27 +22,25 @@ dotstackGrob <- function (
 }
 
 #' @export
-#' @method drawDetails dotstackGrob
-drawDetails.dotstackGrob <- function(x, recording = TRUE) {
-
+makeContext.dotstackGrob <- function(x, recording = TRUE) {
   # Need absolute coordinates because when using npc coords with circleGrob,
   # the radius is in the _smaller_ of the two axes. We need the radius
   # to instead be defined in terms of the non-stack axis.
-  xmm   <- convertX(x$x, "mm", valueOnly = TRUE)
-  ymm   <- convertY(x$y, "mm", valueOnly = TRUE)
+  xmm <- convertX(x$x, "mm", valueOnly = TRUE)
+  ymm <- convertY(x$y, "mm", valueOnly = TRUE)
 
-  if(x$stackaxis == "x") {
+  if (x$stackaxis == "x") {
     dotdiamm <- convertY(x$dotdia, "mm", valueOnly = TRUE)
     xpos <- xmm + dotdiamm * (x$stackposition * x$stackratio + (1 - x$stackratio) / 2)
     ypos <- ymm
-  } else if(x$stackaxis == "y") {
+  } else if (x$stackaxis == "y") {
     dotdiamm <- convertX(x$dotdia, "mm", valueOnly = TRUE)
     xpos <- xmm
     ypos <- ymm + dotdiamm * (x$stackposition * x$stackratio + (1 - x$stackratio) / 2)
   }
 
-  grid.draw(
-    circleGrob(x = xpos, y = ypos, r = dotdiamm / 2, default.units = "mm",
-               name = x$name, gp = x$gp, vp = x$vp),
+  circleGrob(
+    x = xpos, y = ypos, r = dotdiamm / 2, default.units = "mm",
+    name = x$name, gp = x$gp, vp = x$vp
   )
 }
diff --git a/R/grob-null.r b/R/grob-null.r
index b86ff24..5af4c40 100644
--- a/R/grob-null.r
+++ b/R/grob-null.r
@@ -1,6 +1,7 @@
 #' The zero grob draws nothing and has zero size.
 #'
 #' @keywords internal
+#' @export
 zeroGrob <- function() .zeroGrob
 
 .zeroGrob <- grob(cl = "zeroGrob", name = "NULL")
diff --git a/R/grouping.r b/R/grouping.r
new file mode 100644
index 0000000..52c3432
--- /dev/null
+++ b/R/grouping.r
@@ -0,0 +1,39 @@
+# This needs to be less than 1, to distinguish it from "regular" return values
+# of plyr::id() used by add_group()
+NO_GROUP <- -1L
+
+# Ensure that the data frame contains a grouping variable.
+#
+# If the \code{group} variable is not present, then a new group
+# variable is generated from the interaction of all discrete (factor or
+# character) vectors, excluding \code{label}. The special value \code{NO_GROUP}
+# is used for all observations if no discrete variables exist.
+add_group <- function(data) {
+  if (empty(data)) return(data)
+
+  if (is.null(data$group)) {
+    disc <- vapply(data, is.discrete, logical(1))
+    disc[names(disc) %in% c("label", "PANEL")] <- FALSE
+
+    if (any(disc)) {
+      data$group <- plyr::id(data[disc], drop = TRUE)
+    } else {
+      data$group <- NO_GROUP
+    }
+  } else {
+    data$group <- plyr::id(data["group"], drop = TRUE)
+  }
+
+  data
+}
+
+# Is a grouping available?
+# (Will return TRUE if an explicit group or a discrete variable with only one
+# level existed when add_group() was called.)
+has_groups <- function(data) {
+  # If no group aesthetic is specified, all values of the group column equal to
+  # NO_GROUP. On the other hand, if a group aesthetic is specified, all values
+  # are different from NO_GROUP (since they are a result of plyr::id()). NA is
+  # returned for 0-row data frames.
+  data$group[1L] != NO_GROUP
+}
diff --git a/R/guide-colorbar.r b/R/guide-colorbar.r
index cc97ed6..9a52361 100644
--- a/R/guide-colorbar.r
+++ b/R/guide-colorbar.r
@@ -5,18 +5,18 @@
 #' For more information, see the inspiration for this function:
 #' \href{http://www.mathworks.com/help/techdoc/ref/colorbar.html}{Matlab's colorbar function}.
 #'
-#' Guides can be specified in each scale or in \code{\link{guides}}.
-#' \code{guide="legend"} in scale is syntax sugar for
-#' \code{guide=guide_legend()} - but the second form allows you to specify
-#' more options. As for how to specify the guide for each
-#' scales, see \code{\link{guides}}.
+#' Guides can be specified in each \code{scale_*} or in \code{\link{guides}}.
+#' \code{guide="legend"} in \code{scale_*} is syntactic sugar for
+#' \code{guide=guide_legend()} (e.g. \code{scale_color_manual(guide = "legend")}).
+#' As for how to specify the guide for each scale in more detail,
+#' see \code{\link{guides}}.
 #'
 #' @inheritParams guide_legend
-#' @param barwidth A numeric or a unit object specifying the width of the
-#'   colorbar. Default value is \code{legend.key.width} or
+#' @param barwidth A numeric or a \code{\link[grid]{unit}} object specifying
+#'   the width of the colorbar. Default value is \code{legend.key.width} or
 #'   \code{legend.key.size} in \code{\link{theme}} or theme.
-#' @param barheight A numeric or a unit object specifying the height of the
-#'   colorbar. Default value is \code{legend.key.height} or
+#' @param barheight A numeric or a \code{\link[grid]{unit}} object specifying
+#'   the height of the colorbar. Default value is \code{legend.key.height} or
 #'   \code{legend.key.size} in \code{\link{theme}} or theme.
 #' @param nbin A numeric specifying the number of bins for drawing colorbar. A
 #'   smoother colorbar for a larger value.
@@ -32,8 +32,8 @@
 #'   be visible.
 #' @param direction  A character string indicating the direction of the guide.
 #'   One of "horizontal" or "vertical."
-#' @param default.unit A character string indicating unit for \code{barwidth}
-#    and \code{barheight}.
+#' @param default.unit A character string indicating \code{\link[grid]{unit}}
+#'   for \code{barwidth} and \code{barheight}.
 #' @param reverse logical. If \code{TRUE} the colorbar is reversed. By default,
 #'   the highest value is on the top and the lowest value is on the bottom
 #' @param ... ignored.
@@ -41,8 +41,7 @@
 #' @export
 #' @family guides
 #' @examples
-#' library(reshape2) # for melt
-#' df <- melt(outer(1:4, 1:4), varnames = c("X1", "X2"))
+#' df <- reshape2::melt(outer(1:4, 1:4), varnames = c("X1", "X2"))
 #'
 #' p1 <- ggplot(df, aes(X1, X2)) + geom_tile(aes(fill = value))
 #' p2 <- p1 + geom_point(aes(size = value))
@@ -159,10 +158,9 @@ guide_colourbar <- function(
     order = order,
 
     # parameter
-    available_aes = c("colour", "color", "fill"),
-
-    ..., name="colorbar"),
-    class=c("guide", "colorbar"))
+    available_aes = c("colour", "color", "fill"), ..., name = "colorbar"),
+    class = c("guide", "colorbar")
+  )
 }
 
 #' @export
@@ -173,29 +171,35 @@ guide_train.colorbar <- function(guide, scale) {
     warning("colorbar guide needs colour or fill scales.")
     return(NULL)
   }
-  if (!inherits(scale, "continuous")) {
+  if (scale$is_discrete()) {
     warning("colorbar guide needs continuous scales.")
     return(NULL)
   }
 
 
-  # ticks - label (i.e. breaks)
-  output <- scale$aesthetics[1]
-  breaks <- scale_breaks(scale)
-  guide$key <- data.frame(scale_map(scale, breaks), I(scale_labels(scale, breaks)), breaks,
-                          stringsAsFactors = FALSE)
+  # create data frame for tick display
+  breaks <- scale$get_breaks()
+  if (length(breaks) == 0 || all(is.na(breaks)))
+    return()
+
+  ticks <- as.data.frame(setNames(list(scale$map(breaks)), scale$aesthetics[1]))
+  ticks$.value <- breaks
+  ticks$.label <- scale$get_labels(breaks)
 
-  # .value = breaks (numeric) is used for determining the position of ticks in gengrob
-  names(guide$key) <- c(output, ".label", ".value")
+  guide$key <- ticks
 
   # bar specification (number of divs etc)
-  .bar <- discard(pretty(scale_limits(scale), n = guide$nbin), scale_limits(scale))
-  guide$bar <- data.frame(colour=scale_map(scale, .bar), value=.bar, stringsAsFactors = FALSE)
+  .limits <- scale$get_limits()
+  .bar <- discard(pretty(.limits, n = guide$nbin), scale$get_limits())
+  if (length(.bar) == 0) {
+    .bar = unique(.limits)
+  }
+  guide$bar <- data.frame(colour = scale$map(.bar), value = .bar, stringsAsFactors = FALSE)
   if (guide$reverse) {
     guide$key <- guide$key[nrow(guide$key):1, ]
     guide$bar <- guide$bar[nrow(guide$bar):1, ]
   }
-  guide$hash <- with(guide, digest(list(title, key$.label, bar, name)))
+  guide$hash <- with(guide, digest::digest(list(title, key$.label, bar, name)))
   guide
 }
 
@@ -243,7 +247,7 @@ guide_gengrob.colorbar <- function(guide, theme) {
   grob.bar <-
     if (guide$raster) {
       image <- switch(guide$direction, horizontal = t(guide$bar$colour), vertical = rev(guide$bar$colour))
-      rasterGrob(image = image, width=barwidth.c, height=barheight.c, default.units = "mm", gp=gpar(col=NA), interpolate = TRUE)
+      rasterGrob(image = image, width = barwidth.c, height = barheight.c, default.units = "mm", gp = gpar(col = NA), interpolate = TRUE)
     } else {
       switch(guide$direction,
              horizontal = {
@@ -261,25 +265,21 @@ guide_gengrob.colorbar <- function(guide, theme) {
   }
 
   # tick and label position
-  tic_pos.c <- rescale(guide$key$.value, c(0.5, guide$nbin-0.5), guide$bar$value[c(1, nrow(guide$bar))]) * barlength.c / guide$nbin
+  tic_pos.c <- rescale(guide$key$.value, c(0.5, guide$nbin - 0.5), guide$bar$value[c(1, nrow(guide$bar))]) * barlength.c / guide$nbin
   label_pos <- unit(tic_pos.c, "mm")
   if (!guide$draw.ulim) tic_pos.c <- tic_pos.c[-1]
   if (!guide$draw.llim) tic_pos.c <- tic_pos.c[-length(tic_pos.c)]
 
   # title
-  # hjust of title should depend on title.position
-  title.theme <- guide$title.theme %||% calc_element("legend.title", theme)
-  title.hjust <- title.x <- guide$title.hjust %||% theme$legend.title.align %||% 0
-  title.vjust <- title.y <- guide$title.vjust %||% 0.5
-  grob.title <- {
-    if (is.null(guide$title))
-      zeroGrob()
-    else {
-      g <- element_grob(title.theme, label=guide$title,
-        hjust = title.hjust, vjust = title.vjust, x = title.x, y = title.y)
-      ggname("guide.title", g)
-    }
-  }
+  grob.title <- ggname("guide.title",
+    element_grob(
+      guide$title.theme %||% calc_element("legend.title", theme),
+      label = guide$title,
+      hjust = guide$title.hjust %||% theme$legend.title.align %||% 0,
+      vjust = guide$title.vjust %||% 0.5
+    )
+  )
+
 
   title_width <- convertWidth(grobWidth(grob.title), "mm")
   title_width.c <- c(title_width)
@@ -337,7 +337,7 @@ guide_gengrob.colorbar <- function(guide, theme) {
           y1 = rep(tic_pos.c, 2)
         })
       segmentsGrob(x0 = x0, y0 = y0, x1 = x1, y1 = y1,
-                   default.units = "mm", gp = gpar(col="white", lwd=0.5, lineend="butt"))
+                   default.units = "mm", gp = gpar(col = "white", lwd = 0.5, lineend = "butt"))
     }
 
   # layout of bar and label
@@ -376,15 +376,15 @@ guide_gengrob.colorbar <- function(guide, theme) {
   # layout of title and bar+label
   switch(guide$title.position,
     "top" = {
-      widths <- c(bl_widths, max(0, title_width.c-sum(bl_widths)))
+      widths <- c(bl_widths, max(0, title_width.c - sum(bl_widths)))
       heights <- c(title_height.c, vgap, bl_heights)
       vps <- with(vps,
-                  list(bar.row = bar.row+2, bar.col = bar.col,
-                       label.row = label.row+2, label.col = label.col,
+                  list(bar.row = bar.row + 2, bar.col = bar.col,
+                       label.row = label.row + 2, label.col = label.col,
                        title.row = 1, title.col = 1:length(widths)))
     },
     "bottom" = {
-      widths <- c(bl_widths, max(0, title_width.c-sum(bl_widths)))
+      widths <- c(bl_widths, max(0, title_width.c - sum(bl_widths)))
       heights <- c(bl_heights, vgap, title_height.c)
       vps <- with(vps,
                   list(bar.row = bar.row, bar.col = bar.col,
@@ -393,15 +393,15 @@ guide_gengrob.colorbar <- function(guide, theme) {
     },
     "left" = {
       widths <- c(title_width.c, hgap, bl_widths)
-      heights <- c(bl_heights, max(0, title_height.c-sum(bl_heights)))
+      heights <- c(bl_heights, max(0, title_height.c - sum(bl_heights)))
       vps <- with(vps,
-                  list(bar.row = bar.row, bar.col = bar.col+2,
-                       label.row = label.row, label.col = label.col+2,
+                  list(bar.row = bar.row, bar.col = bar.col + 2,
+                       label.row = label.row, label.col = label.col + 2,
                        title.row = 1:length(heights), title.col = 1))
     },
     "right" = {
       widths <- c(bl_widths, hgap, title_width.c)
-      heights <- c(bl_heights, max(0, title_height.c-sum(bl_heights)))
+      heights <- c(bl_heights, max(0, title_height.c - sum(bl_heights)))
       vps <- with(vps,
                   list(bar.row = bar.row, bar.col = bar.col,
                        label.row = label.row, label.col = label.col,
diff --git a/R/guide-legend.r b/R/guide-legend.r
index 900be97..7f33b08 100644
--- a/R/guide-legend.r
+++ b/R/guide-legend.r
@@ -3,14 +3,15 @@
 #' Legend type guide shows key (i.e., geoms) mapped onto values.
 #' Legend guides for various scales are integrated if possible.
 #'
-#' Guides can be specified in each scale or in \code{\link{guides}}.
-#' \code{guide="legend"} in scale is syntactic sugar for
-#' \code{guide=guide_legend()}. As for how to specify the guide for each
-#' scales in more detail, see \code{\link{guides}}.
+#' Guides can be specified in each \code{scale_*} or in \code{\link{guides}}.
+#' \code{guide="legend"} in \code{scale_*} is syntactic sugar for
+#' \code{guide=guide_legend()} (e.g. \code{scale_color_manual(guide = "legend")}).
+#' As for how to specify the guide for each scale in more detail,
+#' see \code{\link{guides}}.
 #'
 #' @param title A character string or expression indicating a title of guide.
 #'   If \code{NULL}, the title is not shown. By default
-#'   (\code{\link{waiver}}), the name of the scale object or tha name
+#'   (\code{\link{waiver}}), the name of the scale object or the name
 #'   specified in \code{\link{labs}} is used for the title.
 #' @param title.position A character string indicating the position of a
 #'   title. One of "top" (default for a vertical guide), "bottom", "left"
@@ -26,7 +27,7 @@
 #'   \code{FALSE} then the labels are invisible.
 #' @param label.position A character string indicating the position of a
 #'   label. One of "top", "bottom" (default for horizontal guide), "left", or
-#'   "right" (default for vertical gudie).
+#'   "right" (default for vertical guide).
 #' @param label.theme A theme object for rendering the label text. Usually the
 #'   object of \code{\link{element_text}} is expected. By default, the theme is
 #'   specified by \code{legend.text} in \code{\link{theme}} or theme.
@@ -34,16 +35,16 @@
 #'   label text.
 #' @param label.vjust A numeric specifying vertical justification of the label
 #'   text.
-#' @param keywidth A numeric or a unit object specifying the width of the
-#'   legend key. Default value is \code{legend.key.width} or
+#' @param keywidth A numeric or a \code{\link[grid]{unit}} object specifying
+#'   the width of the legend key. Default value is \code{legend.key.width} or
 #'   \code{legend.key.size} in \code{\link{theme}} or theme.
-#' @param keyheight A numeric or a unit object specifying the height of the
-#'   legend key. Default value is \code{legend.key.height} or
+#' @param keyheight A numeric or a \code{\link[grid]{unit}} object specifying
+#'   the height of the legend key. Default value is \code{legend.key.height} or
 #'   \code{legend.key.size} in \code{\link{theme}} or theme.
 #' @param direction  A character string indicating the direction of the guide.
 #'   One of "horizontal" or "vertical."
-#' @param default.unit A character string indicating unit for \code{keywidth}
-#'   and \code{keyheight}.
+#' @param default.unit A character string indicating \code{\link[grid]{unit}}
+#'   for \code{keywidth} and \code{keyheight}.
 #' @param override.aes A list specifying aesthetic parameters of legend key.
 #'   See details and examples.
 #' @param nrow The desired number of rows of legends.
@@ -51,17 +52,17 @@
 #' @param byrow logical. If \code{FALSE} (the default) the legend-matrix is
 #'   filled by columns, otherwise the legend-matrix is filled by rows.
 #' @param reverse logical. If \code{TRUE} the order of legends is reversed.
-#' @param order positive integer less that 99 that specify the order of
-#'   this guide in the multiple guides. If 0 (default), the order is determined
-#'   by a secret algorithm.
+#' @param order positive integer less that 99 that specifies the order of
+#'   this guide among multiple guides. This controls the order in which
+#'   multiple guides are displayed, not the contents of the guide itself.
+#'   If 0 (default), the order is determined by a secret algorithm.
 #' @param ... ignored.
 #' @return A guide object
 #' @export
 #' @family guides
 #' @examples
 #' \donttest{
-#' library(reshape2) # for melt
-#' df <- melt(outer(1:4, 1:4), varnames = c("X1", "X2"))
+#' df <- reshape2::melt(outer(1:4, 1:4), varnames = c("X1", "X2"))
 #'
 #' p1 <- ggplot(df, aes(X1, X2)) + geom_tile(aes(fill = value))
 #' p2 <- p1 + geom_point(aes(size = value))
@@ -73,7 +74,6 @@
 #' # Guide title
 #'
 #' p1 + scale_fill_continuous(guide = guide_legend(title = "V")) # title text
-#' p1 + scale_fill_continuous(name = "V") # same
 #' p1 + scale_fill_continuous(guide = guide_legend(title = NULL)) # no title
 #'
 #' # Control styles
@@ -101,15 +101,17 @@
 #' # Set aesthetic of legend key
 #'
 #' # very low alpha value make it difficult to see legend key
-#' p3 <- qplot(carat, price, data = diamonds, colour = color,
-#'   alpha = I(1/100))
+#' p3 <- ggplot(diamonds, aes(carat, price)) +
+#'   geom_point(aes(colour=color), alpha=1/100)
 #' p3
 #'
 #' # override.aes overwrites the alpha
 #' p3 + guides(colour = guide_legend(override.aes = list(alpha = 1)))
 #'
 #' # multiple row/col legends
-#' p <- qplot(1:20, 1:20, colour = letters[1:20])
+#' df <- data.frame(x = 1:20, y = 1:20, color = letters[1:20])
+#' p <- ggplot(df, aes(x, y)) +
+#'   geom_point(aes(colour = color))
 #' p + guides(col = guide_legend(nrow = 8))
 #' p + guides(col = guide_legend(ncol = 8))
 #' p + guides(col = guide_legend(nrow = 8, byrow = TRUE))
@@ -153,49 +155,53 @@ guide_legend <- function(
   if (!is.null(keywidth) && !is.unit(keywidth)) keywidth <- unit(keywidth, default.unit)
   if (!is.null(keyheight) && !is.unit(keyheight)) keyheight <- unit(keyheight, default.unit)
 
-  structure(list(
-    # title
-    title = title,
-    title.position = title.position,
-    title.theme = title.theme,
-    title.hjust = title.hjust,
-    title.vjust = title.vjust,
-
-    # label
-    label = label,
-    label.position = label.position,
-    label.theme = label.theme,
-    label.hjust = label.hjust,
-    label.vjust = label.vjust,
-
-    # size of key
-    keywidth = keywidth,
-    keyheight = keyheight,
-
-    # general
-    direction = direction,
-    default.unit = default.unit,
-    override.aes = override.aes,
-    nrow = nrow,
-    ncol = ncol,
-    byrow = byrow,
-    reverse = reverse,
-    order = order,
-
-    # parameter
-    available_aes = c("any"),
-
-    ..., name="legend"),
-    class=c("guide", "legend"))
+  structure(
+    list(
+      # title
+      title = title,
+      title.position = title.position,
+      title.theme = title.theme,
+      title.hjust = title.hjust,
+      title.vjust = title.vjust,
+
+      # label
+      label = label,
+      label.position = label.position,
+      label.theme = label.theme,
+      label.hjust = label.hjust,
+      label.vjust = label.vjust,
+
+      # size of key
+      keywidth = keywidth,
+      keyheight = keyheight,
+
+      # general
+      direction = direction,
+      override.aes = rename_aes(override.aes),
+      nrow = nrow,
+      ncol = ncol,
+      byrow = byrow,
+      reverse = reverse,
+      order = order,
+
+      # parameter
+      available_aes = c("any"),
+      ...,
+      name = "legend"
+    ),
+    class = c("guide", "legend")
+  )
 }
 
 #' @export
 guide_train.legend <- function(guide, scale) {
-  breaks <- scale_breaks(scale)
-  key <- data.frame(
-    values = scale_map(scale, breaks),
-    labels = I(scale_labels(scale)),
+  breaks <- scale$get_breaks()
+  if (length(breaks) == 0 || all(is.na(breaks)))
+    return()
+
+  key <- as.data.frame(setNames(list(scale$map(breaks)), scale$aesthetics[1]),
     stringsAsFactors = FALSE)
+  key$.label <- scale$get_labels(breaks)
 
   # this is a quick fix for #118
   # some scales have NA as na.value (e.g., size)
@@ -204,27 +210,25 @@ guide_train.legend <- function(guide, scale) {
   #
   # Also, drop out-of-range values for continuous scale
   # (should use scale$oob?)
-  if (inherits(scale, "continuous")) {
-    limits <- scale_limits(scale)
+  if (scale$is_discrete()) {
+    key <- key[!is.na(breaks), , drop = FALSE]
+  } else {
+    limits <- scale$get_limits()
     noob <- !is.na(breaks) & limits[1] <= breaks & breaks <= limits[2]
     key <- key[noob, , drop = FALSE]
-  } else {
-    key <- key[!is.na(breaks), , drop = FALSE]
   }
 
-  if (empty(key) || all(is.na(breaks))) return(NULL)
-  names(key) <- c(scale$aesthetics[1], ".label")
 
   if (guide$reverse) key <- key[nrow(key):1, ]
 
   guide$key <- key
-  guide$hash <- with(guide, digest(list(title, key$.label, direction, name)))
+  guide$hash <- with(guide, digest::digest(list(title, key$.label, direction, name)))
   guide
 }
 
 #' @export
 guide_merge.legend <- function(guide, new_guide) {
-  guide$key <- merge(guide$key, new_guide$key, sort=FALSE)
+  guide$key <- merge(guide$key, new_guide$key, sort = FALSE)
   guide$override.aes <- c(guide$override.aes, new_guide$override.aes)
   if (any(duplicated(names(guide$override.aes)))) warning("Duplicated override.aes is ignored.")
   guide$override.aes <- guide$override.aes[!duplicated(names(guide$override.aes))]
@@ -233,56 +237,41 @@ guide_merge.legend <- function(guide, new_guide) {
 
 #' @export
 guide_geom.legend <- function(guide, layers, default_mapping) {
-
-  # TODO: how to deal with same geoms of multiple layers.
-  #
-  # currently all geoms are overlayed irrespective to that they are duplicated or not.
-  # but probably it is better to sensitive to that and generate only one geom like this:
-  #
-  # geoms <- unique(sapply(layers, function(layer) if (is.na(layer$legend) || layer$legend) layer$geom$guide_geom() else NULL))
-  #
-  # but in this case, some conflicts occurs, e.g.,
-  #
-  # d <- data.frame(x=1:5, y=1:5, v=factor(1:5))
-  # ggplot(d, aes(x, y, colour=v, group=1)) + geom_point() + geom_line(colour="red", legend=T) + geom_rug(colour="blue", legend=T)
-  #
-  # geom_line generate path geom with red and geom_rug generate it with blue.
-  # how to deal with them ?
-
   # arrange common data for vertical and horizontal guide
-  guide$geoms <- llply(layers, function(layer) {
-    all <- names(c(layer$mapping, default_mapping, layer$stat$default_aes()))
-    geom <- c(layer$geom$required_aes, names(layer$geom$default_aes()))
+  guide$geoms <- plyr::llply(layers, function(layer) {
+    all <- names(c(layer$mapping, if (layer$inherit.aes) default_mapping, layer$stat$default_aes))
+    geom <- c(layer$geom$required_aes, names(layer$geom$default_aes))
     matched <- intersect(intersect(all, geom), names(guide$key))
     matched <- setdiff(matched, names(layer$geom_params))
-    data <-
-      if (length(matched) > 0) {
-        # This layer contributes to the legend
-        if (is.na(layer$show_guide) || layer$show_guide) {
-          # Default is to include it
-          layer$use_defaults(guide$key[matched])
-        } else {
-          NULL
-        }
+    matched <- setdiff(matched, names(layer$aes_params))
+
+    if (length(matched) > 0) {
+      # This layer contributes to the legend
+      if (is.na(layer$show.legend) || layer$show.legend) {
+        # Default is to include it
+        data <- layer$geom$use_defaults(guide$key[matched], layer$aes_params)
+      } else {
+        return(NULL)
+      }
+    } else {
+      # This layer does not contribute to the legend
+      if (is.na(layer$show.legend) || !layer$show.legend) {
+        # Default is to exclude it
+        return(NULL)
       } else {
-        # This layer does not contribute to the legend
-        if (is.na(layer$show_guide) || !layer$show_guide) {
-          # Default is to exclude it
-          NULL
-        } else {
-          layer$use_defaults(NULL)[rep(1, nrow(guide$key)), ]
-        }
+        data <- layer$geom$use_defaults(NULL, layer$aes_params)[rep(1, nrow(guide$key)), ]
       }
-    if (is.null(data)) return(NULL)
+    }
 
     # override.aes in guide_legend manually changes the geom
-    for (aes in intersect(names(guide$override.aes), names(data))) data[[aes]] <- guide$override.aes[[aes]]
+    data <- utils::modifyList(data, guide$override.aes)
 
-    geom <- Geom$find(layer$geom$guide_geom())
-    params <- c(layer$geom_params, layer$stat_params)
-    list(geom = geom, data = data, params = params)
-  }
-  )
+    list(
+      draw_key = layer$geom$draw_key,
+      data = data,
+      params = c(layer$geom_params, layer$stat_params)
+    )
+  })
 
   # remove null geom
   guide$geoms <- compact(guide$geoms)
@@ -303,210 +292,197 @@ guide_gengrob.legend <- function(guide, theme) {
   nbreak <- nrow(guide$key)
 
   # gap between keys etc
-  hgap <- c(convertWidth(unit(0.3, "lines"), "mm"))
+  hgap <- width_cm(unit(0.3, "lines"))
   vgap <- hgap
 
-  # title
-  title.theme <- guide$title.theme %||% calc_element("legend.title", theme)
-  title.hjust <- title.x <- guide$title.hjust %||% theme$legend.title.align %||% 0
-  title.vjust <- title.y <- guide$title.vjust %||% 0.5
-
-  grob.title <- {
-    if (is.null(guide$title))
-      zeroGrob()
-    else {
-      g <- element_grob(title.theme, label=guide$title,
-        hjust = title.hjust, vjust = title.vjust, x = title.x, y = title.y)
-      ggname("guide.title", g)
-    }
-  }
+  grob.title <- ggname("guide.title",
+    element_grob(
+      guide$title.theme %||% calc_element("legend.title", theme),
+      label = guide$title,
+      hjust = guide$title.hjust %||% theme$legend.title.align %||% 0,
+      vjust = guide$title.vjust %||% 0.5
+    )
+  )
 
-  title_width <- convertWidth(grobWidth(grob.title), "mm")
-  title_width.c <- c(title_width)
-  title_height <- convertHeight(grobHeight(grob.title), "mm")
-  title_height.c <- c(title_height)
+  title_width <- width_cm(grob.title)
+  title_height <- height_cm(grob.title)
 
-  # Label
-  # Rules of lable adjustment
-  #
-  # label.theme in param of guide_legend() > theme$legend.text.align > default
-  # hjust/vjust in theme$legend.text and label.theme are ignored.
-  #
-  # Default:
-  #   If label includes expression, the label is right-alignd (hjust = 0). Ohterwise, left-aligned (x = 1, hjust = 1).
-  #   Vertical adjustment is always mid-alined (vjust = 0.5).
-  label.theme <- guide$label.theme %||% calc_element("legend.text", theme)
-  grob.labels <- {
-    if (!guide$label)
-      zeroGrob()
-    else {
-      hjust <- x <- guide$label.hjust %||% theme$legend.text.align %||%
-        if (any(is.expression(guide$key$.label))) 1 else 0
-      vjust <- y <- guide$label.vjust %||% 0.5
-
-      lapply(guide$key$.label,
-        function(label, ...) {
-          g <- element_grob(element = label.theme, label = label,
-            x = x, y = y, hjust = hjust, vjust = vjust)
-          ggname("guide.label", g)
-        }
-      )
-    }
+  # Labels
+  if (!guide$label || is.null(guide$key$.label)) {
+    grob.labels <- rep(list(zeroGrob()), nrow(guide$key))
+  } else {
+    label.theme <- guide$label.theme %||% calc_element("legend.text", theme)
+
+    # label.theme in param of guide_legend() > theme$legend.text.align > default
+    # hjust/vjust in theme$legend.text and label.theme are ignored.
+    hjust <- x <- guide$label.hjust %||% theme$legend.text.align %||%
+      if (any(is.expression(guide$key$.label))) 1 else 0
+    vjust <- y <- guide$label.vjust %||% 0.5
+
+    grob.labels <- lapply(guide$key$.label, function(label, ...) {
+      g <- element_grob(element = label.theme, label = label,
+        x = x, y = y, hjust = hjust, vjust = vjust)
+      ggname("guide.label", g)
+    })
   }
 
-  label_widths <- lapply(grob.labels, function(g)convertWidth(grobWidth(g), "mm"))
-  label_heights <- lapply(grob.labels, function(g)convertHeight(grobHeight(g), "mm"))
-  label_widths.c <- unlist(label_widths)
-  label_heights.c <- unlist(label_heights)
-
-  # key size
-
-  key_width <- convertWidth(guide$keywidth %||% theme$legend.key.width %||% theme$legend.key.size, "mm")
-  key_height <- convertHeight(guide$keyheight %||% theme$legend.key.height %||% theme$legend.key.size, "mm")
+  label_widths <- width_cm(grob.labels)
+  label_heights <- height_cm(grob.labels)
 
-  key_width.c <- c(key_width)
-  key_height.c <- c(key_height)
+  # Keys
+  key_width <- width_cm(guide$keywidth %||% theme$legend.key.width %||% theme$legend.key.size)
+  key_height <- height_cm(guide$keyheight %||% theme$legend.key.height %||% theme$legend.key.size)
 
-  key_size_mat <- do.call("cbind", llply(guide$geoms, function(g) g$data$size))
-  key_sizes <- if (is.null(key_size_mat)) rep(0, nbreak) else apply(key_size_mat, 1, max)
+  key_size_mat <- do.call("cbind", lapply(guide$geoms, function(g) g$data$size / 10))
+  if (nrow(key_size_mat) == 0 || ncol(key_size_mat) == 0) {
+    key_size_mat <- matrix(0, ncol = 1, nrow = nbreak)
+  }
+  key_sizes <- apply(key_size_mat, 1, max)
 
   if (!is.null(guide$nrow) && !is.null(guide$ncol) && guide$nrow * guide$ncol < nbreak)
-    stop("nrow x ncol need to be larger than the number of breaks")
-  legend.nrow <- guide$nrow %||%
-    if (!is.null(guide$ncol)) ceiling(nbreak/guide$ncol)
-    else switch(guide$direction, horizontal = 1, vertical = nbreak)
-  legend.ncol <- guide$ncol %||%
-    if (!is.null(guide$nrow)) ceiling(nbreak/guide$nrow)
-    else switch(guide$direction, horizontal = nbreak, vertical = 1)
+    stop("`nrow` * `ncol` needs to be larger than the number of breaks", call. = FALSE)
+
+  # If neither nrow/ncol specified, guess with "reasonable" values
+  if (is.null(guide$nrow) && is.null(guide$ncol)) {
+    if (guide$direction == "horizontal") {
+      guide$nrow <- ceiling(nbreak / 5)
+    } else {
+      guide$ncol <- ceiling(nbreak / 20)
+    }
+  }
+  legend.nrow <- guide$nrow %||% ceiling(nbreak / guide$ncol)
+  legend.ncol <- guide$ncol %||% ceiling(nbreak / guide$nrow)
+
   key_sizes <- matrix(c(key_sizes, rep(0, legend.nrow * legend.ncol - nbreak)),
                       legend.nrow, legend.ncol, byrow = guide$byrow)
 
-  key_widths.c <- pmax(key_width.c, apply(key_sizes, 2, max))
-  key_heights.c <-pmax(key_height.c, apply(key_sizes, 1, max))
+  key_widths <- pmax(key_width, apply(key_sizes, 2, max))
+  key_heights <- pmax(key_height, apply(key_sizes, 1, max))
 
-  label_widths.c <- apply(matrix(c(label_widths.c, rep(0, legend.nrow * legend.ncol - nbreak)),
+  label_widths <- apply(matrix(c(label_widths, rep(0, legend.nrow * legend.ncol - nbreak)),
                                  legend.nrow, legend.ncol, byrow = guide$byrow),
                           2, max)
-  label_heights.c <- apply(matrix(c(label_heights.c, rep(0, legend.nrow * legend.ncol - nbreak)),
+  label_heights <- apply(matrix(c(label_heights, rep(0, legend.nrow * legend.ncol - nbreak)),
                                   legend.nrow, legend.ncol, byrow = guide$byrow),
                            1, max)
 
-  if (guide$byrow) vps <- data.frame(ceiling(seq(nbreak)/legend.ncol), (seq(nbreak)-1)%%legend.ncol+1)
-  else vps <- data.frame(arrayInd(seq(nbreak), dim(key_sizes)))
-  names(vps) <- c("R", "C")
+  if (guide$byrow) {
+    vps <- data.frame(
+      R = ceiling(seq(nbreak) / legend.ncol),
+      C = (seq(nbreak) - 1) %% legend.ncol + 1
+    )
+  } else {
+    vps <- as.data.frame(arrayInd(seq(nbreak), dim(key_sizes)))
+    names(vps) <- c("R", "C")
+  }
 
   # layout of key-label depends on the direction of the guide
   if (guide$byrow == TRUE) {
     switch(label.position,
       "top" = {
-        kl_widths <- pmax(label_widths.c, key_widths.c)
-        kl_heights <- head(interleave(label_heights.c, vgap/2, key_heights.c, vgap/2), -1)
-        vps <- transform(vps, key.row = R*4-1, key.col = C, label.row = R*4-3, label.col = C)
+        kl_widths <- pmax(label_widths, key_widths)
+        kl_heights <- utils::head(interleave(label_heights, vgap/2, key_heights, vgap/2), -1)
+        vps <- transform(vps, key.row = R * 4 - 1, key.col = C, label.row = R * 4 - 3, label.col = C)
       },
       "bottom" = {
-        kl_widths <- pmax(label_widths.c, key_widths.c)
-        kl_heights <- head(interleave(key_heights.c, vgap/2, label_heights.c, vgap/2), -1)
-        vps <- transform(vps, key.row = R*4-3, key.col = C, label.row = R*4-1, label.col = C)
+        kl_widths <- pmax(label_widths, key_widths)
+        kl_heights <- utils::head(interleave(key_heights, vgap/2, label_heights, vgap/2), -1)
+        vps <- transform(vps, key.row = R * 4 - 3, key.col = C, label.row = R * 4 - 1, label.col = C)
       },
       "left" = {
-        kl_widths <- head(interleave(label_widths.c, hgap/2, key_widths.c, hgap/2), -1)
-        kl_heights <- head(interleave(pmax(label_heights.c, key_heights.c), vgap/2), -1)
-        vps <- transform(vps, key.row = R*2-1, key.col = C*4-1, label.row = R*2-1, label.col = C*4-3)
+        kl_widths <- utils::head(interleave(label_widths, hgap/2, key_widths, hgap/2), -1)
+        kl_heights <- utils::head(interleave(pmax(label_heights, key_heights), vgap/2), -1)
+        vps <- transform(vps, key.row = R * 2 - 1, key.col = C * 4 - 1, label.row = R * 2 - 1, label.col = C * 4 - 3)
       },
       "right" = {
-        kl_widths <- head(interleave(key_widths.c, hgap/2, label_widths.c, hgap/2), -1)
-        kl_heights <- head(interleave(pmax(label_heights.c, key_heights.c), vgap/2), -1)
-        vps <- transform(vps, key.row = R*2-1, key.col = C*4-3, label.row = R*2-1, label.col = C*4-1)
+        kl_widths <- utils::head(interleave(key_widths, hgap/2, label_widths, hgap/2), -1)
+        kl_heights <- utils::head(interleave(pmax(label_heights, key_heights), vgap/2), -1)
+        vps <- transform(vps, key.row = R * 2 - 1, key.col = C * 4 - 3, label.row = R * 2 - 1, label.col = C * 4 - 1)
         })
   } else {
     switch(label.position,
       "top" = {
-        kl_widths <- head(interleave(pmax(label_widths.c, key_widths.c), hgap/2), -1)
-        kl_heights <- head(interleave(label_heights.c, vgap/2, key_heights.c, vgap/2), -1)
-        vps <- transform(vps, key.row = R*4-1, key.col = C*2-1, label.row = R*4-3, label.col = C*2-1)
+        kl_widths <- utils::head(interleave(pmax(label_widths, key_widths), hgap/2), -1)
+        kl_heights <- utils::head(interleave(label_heights, vgap/2, key_heights, vgap/2), -1)
+        vps <- transform(vps, key.row = R * 4 - 1, key.col = C * 2 - 1, label.row = R * 4 - 3, label.col = C * 2 - 1)
       },
       "bottom" = {
-        kl_widths <- head(interleave(pmax(label_widths.c, key_widths.c), hgap/2), -1)
-        kl_heights <- head(interleave(key_heights.c, vgap/2, label_heights.c, vgap/2), -1)
-        vps <- transform(vps, key.row = R*4-3, key.col = C*2-1, label.row = R*4-1, label.col = C*2-1)
+        kl_widths <- utils::head(interleave(pmax(label_widths, key_widths), hgap/2), -1)
+        kl_heights <- utils::head(interleave(key_heights, vgap/2, label_heights, vgap/2), -1)
+        vps <- transform(vps, key.row = R * 4 - 3, key.col = C * 2 - 1, label.row = R * 4 - 1, label.col = C * 2 - 1)
       },
       "left" = {
-        kl_widths <- head(interleave(label_widths.c, hgap/2, key_widths.c, hgap/2), -1)
-        kl_heights <- pmax(key_heights.c, label_heights.c)
-        vps <- transform(vps, key.row = R, key.col = C*4-1, label.row = R, label.col = C*4-3)
+        kl_widths <- utils::head(interleave(label_widths, hgap/2, key_widths, hgap/2), -1)
+        kl_heights <- pmax(key_heights, label_heights)
+        vps <- transform(vps, key.row = R, key.col = C * 4 - 1, label.row = R, label.col = C * 4 - 3)
       },
       "right" = {
-        kl_widths <- head(interleave(key_widths.c, hgap/2, label_widths.c, hgap/2), -1)
-        kl_heights <- pmax(key_heights.c, label_heights.c)
-        vps <- transform(vps, key.row = R, key.col = C*4-3, label.row = R, label.col = C*4-1)
+        kl_widths <- utils::head(interleave(key_widths, hgap/2, label_widths, hgap/2), -1)
+        kl_heights <- pmax(key_heights, label_heights)
+        vps <- transform(vps, key.row = R, key.col = C * 4 - 3, label.row = R, label.col = C * 4 - 1)
       })
   }
 
   # layout the title over key-label
   switch(guide$title.position,
     "top" = {
-      widths <- c(kl_widths, max(0, title_width.c-sum(kl_widths)))
-      heights <- c(title_height.c, vgap, kl_heights)
-      vps <- transform(vps, key.row = key.row+2, key.col = key.col, label.row = label.row+2, label.col = label.col)
+      widths <- c(kl_widths, max(0, title_width - sum(kl_widths)))
+      heights <- c(title_height, vgap, kl_heights)
+      vps <- transform(vps, key.row = key.row + 2, key.col = key.col, label.row = label.row + 2, label.col = label.col)
       vps.title.row = 1; vps.title.col = 1:length(widths)
     },
     "bottom" = {
-      widths <- c(kl_widths, max(0, title_width.c-sum(kl_widths)))
-      heights <- c(kl_heights, vgap, title_height.c)
+      widths <- c(kl_widths, max(0, title_width - sum(kl_widths)))
+      heights <- c(kl_heights, vgap, title_height)
       vps <- transform(vps, key.row = key.row, key.col = key.col, label.row = label.row, label.col = label.col)
       vps.title.row = length(heights); vps.title.col = 1:length(widths)
     },
     "left" = {
-      widths <- c(title_width.c, hgap, kl_widths)
-      heights <- c(kl_heights, max(0, title_height.c-sum(kl_heights)))
-      vps <- transform(vps, key.row = key.row, key.col = key.col+2, label.row = label.row, label.col = label.col+2)
+      widths <- c(title_width, hgap, kl_widths)
+      heights <- c(kl_heights, max(0, title_height - sum(kl_heights)))
+      vps <- transform(vps, key.row = key.row, key.col = key.col + 2, label.row = label.row, label.col = label.col + 2)
       vps.title.row = 1:length(heights); vps.title.col = 1
     },
     "right" = {
-      widths <- c(kl_widths, hgap, title_width.c)
-      heights <- c(kl_heights, max(0, title_height.c-sum(kl_heights)))
+      widths <- c(kl_widths, hgap, title_width)
+      heights <- c(kl_heights, max(0, title_height - sum(kl_heights)))
       vps <- transform(vps, key.row = key.row, key.col = key.col, label.row = label.row, label.col = label.col)
       vps.title.row = 1:length(heights); vps.title.col = length(widths)
     })
 
   # grob for key
-  grob.keys <- list()
-
-  for (i in 1:nbreak) {
-
-    # layout position
-    pos.row <- vps$key.row[i]
-    pos.col <- vps$key.col[i]
+  key_size <- c(key_width, key_height) * 10
 
-    # bg. of key
-    grob.keys[[length(grob.keys)+1]] <- element_render(theme, "legend.key")
-
-    # overlay geoms
-    for(geom in guide$geoms)
-      grob.keys[[length(grob.keys)+1]] <- geom$geom$draw_legend(geom$data[i, ], geom$params)
+  draw_key <- function(i) {
+    bg <- element_render(theme, "legend.key")
+    keys <- lapply(guide$geoms, function(g) {
+      g$draw_key(g$data[i, ], g$params, key_size)
+    })
+    c(list(bg), keys)
   }
+  grob.keys <- unlist(lapply(seq_len(nbreak), draw_key), recursive = FALSE)
 
   # background
   grob.background <- element_render(theme, "legend.background")
 
   ngeom <- length(guide$geoms) + 1
-  kcols <- rep(vps$key.col, each =  ngeom)
-  krows <- rep(vps$key.row, each =  ngeom)
+  kcols <- rep(vps$key.col, each = ngeom)
+  krows <- rep(vps$key.row, each = ngeom)
 
   # padding
-  padding <- unit(1.5, "mm")
+  padding <- 0.15
   widths <- c(padding, widths, padding)
   heights <- c(padding, heights, padding)
 
   # Create the gtable for the legend
-  gt <- gtable(widths = unit(widths, "mm"), heights = unit(heights, "mm"))
+  gt <- gtable(widths = unit(widths, "cm"), heights = unit(heights, "cm"))
   gt <- gtable_add_grob(gt, grob.background, name = "background", clip = "off",
     t = 1, r = -1, b = -1, l = 1)
   gt <- gtable_add_grob(gt, grob.title, name = "title", clip = "off",
     t = 1 + min(vps.title.row), r = 1 + max(vps.title.col),
     b = 1 + max(vps.title.row), l = 1 + min(vps.title.col))
   gt <- gtable_add_grob(gt, grob.keys,
-    name = paste("key", krows, kcols, c("bg", seq(ngeom-1)), sep = "-"), clip = "off",
+    name = paste("key", krows, kcols, c("bg", seq(ngeom - 1)), sep = "-"), clip = "off",
     t = 1 + krows, r = 1 + kcols,
     b = 1 + krows, l = 1 + kcols)
   gt <- gtable_add_grob(gt, grob.labels,
@@ -517,4 +493,4 @@ guide_gengrob.legend <- function(guide, theme) {
   gt
 }
 
-globalVariables(c("R", "key.row", "key.col", "label.row", "label.col"))
+globalVariables(c("C", "R", "key.row", "key.col", "label.row", "label.col"))
diff --git a/R/guides-.r b/R/guides-.r
index 436649f..4f6ddf9 100644
--- a/R/guides-.r
+++ b/R/guides-.r
@@ -29,6 +29,10 @@
 #'  scale_size_discrete(guide = "legend") +
 #'  scale_shape(guide = "legend")
 #'
+#'  # Remove some guides
+#'  p + guides(colour = "none")
+#'  p + guides(colour = "colorbar",size = "none")
+#'
 #' # Guides are integrated where possible
 #'
 #' p + guides(colour = guide_legend("title"), size = guide_legend("title"),
@@ -44,11 +48,13 @@
 #' p + theme(legend.position = "bottom", legend.box = "horizontal")
 #'
 #' # Set order for multiple guides
-#'
-#' qplot(data = mpg, x = displ, y = cty, size = hwy, colour = cyl, shape = drv) +
-#'   guides(colour = guide_colourbar(order = 1),
-#'          alpha = guide_legend(order = 2),
-#'          size = guide_legend(order = 3))
+#' ggplot(mpg, aes(displ, cty)) +
+#'   geom_point(aes(size = hwy, colour = cyl, shape = drv)) +
+#'   guides(
+#'    colour = guide_colourbar(order = 1),
+#'    shape = guide_legend(order = 2),
+#'    size = guide_legend(order = 3)
+#'  )
 #' }
 guides <- function(...) {
   args <- list(...)
@@ -102,7 +108,7 @@ build_guides <- function(scales, layers, default_mapping, position, theme, guide
   theme$legend.direction <-
     theme$legend.direction %||%
     if (length(position) == 1 && position %in% c("top", "bottom", "left", "right"))
-      switch(position[1], top =, bottom = "horizontal", left =, right = "vertical")
+      switch(position[1], top = , bottom = "horizontal", left = , right = "vertical")
     else
       "vertical"
 
@@ -110,7 +116,7 @@ build_guides <- function(scales, layers, default_mapping, position, theme, guide
   theme$legend.box.just <-
     theme$legend.box.just %||%
     if (length(position) == 1 && position %in% c("top", "bottom", "left", "right"))
-      switch(position, bottom =, top = c("center", "top"), left =, right = c("left", "top"))
+      switch(position, bottom = , top = c("center", "top"), left = , right = c("left", "top"))
     else
       c("center", "center")
 
@@ -136,9 +142,9 @@ build_guides <- function(scales, layers, default_mapping, position, theme, guide
 
 # validate guide object
 validate_guide <- function(guide) {
-  # if guide is specified by character, then find the corrsponding guide
+  # if guide is specified by character, then find the corresponding guide
   if (is.character(guide))
-    match.fun(paste("guide_", guide, sep=""))()
+    match.fun(paste("guide_", guide, sep = ""))()
   else if (inherits(guide, "guide"))
     guide
   else
@@ -149,7 +155,7 @@ validate_guide <- function(guide) {
 guides_train <- function(scales, theme, guides, labels) {
 
   gdefs <- list()
-  for(scale in scales$scales) {
+  for (scale in scales$scales) {
 
     # guides(XXX) is stored in guides[[XXX]],
     # which is prior to scale_ZZZ(guide=XXX)
@@ -161,19 +167,17 @@ guides_train <- function(scales, theme, guides, labels) {
     # this should be changed to testing guide == "none"
     # scale$legend is backward compatibility
     # if guides(XXX=FALSE), then scale_ZZZ(guides=XXX) is discarded.
-    if (guide=="none" || (is.logical(guide) && !guide)) next
-    if ((!is.null(scale$legend) && !scale$legend) || is.null(scale_limits(scale))) next # for backward compatibility
+    if (guide == "none" || (is.logical(guide) && !guide)) next
 
     # check the validity of guide.
     # if guide is character, then find the guide object
     guide <- validate_guide(guide)
 
     # check the consistency of the guide and scale.
-    if (guide$available_aes != "any" && ! scale$aesthetics %in% guide$available_aes)
-      stop (paste("Guide '", guide$name, "' cannot be used for '", scale$aesthetics, "'.", sep=""))
+    if (guide$available_aes != "any" && !scale$aesthetics %in% guide$available_aes)
+      stop("Guide '", guide$name, "' cannot be used for '", scale$aesthetics, "'.")
 
-    # title of this grob
-    if (is.waive(guide$title)) guide$title <- scale$name %||% labels[[output]]
+    guide$title <- guide$title %|W|% scale$name %|W|% labels[[output]]
 
     # direction of this grob
     guide$direction <- guide$direction %||% theme$legend.direction
@@ -182,14 +186,14 @@ guides_train <- function(scales, theme, guides, labels) {
     # so Guides (i.e., the container of guides) need not to know about them
     guide <- guide_train(guide, scale)
 
-    if (!is.null(guide)) gdefs[[length(gdefs)+1]] <- guide
+    if (!is.null(guide)) gdefs[[length(gdefs) + 1]] <- guide
   }
   gdefs
 }
 
 # merge overlapped guides
 guides_merge <- function(gdefs) {
-  # split gdefs based on hash, and apply Reduce (guide_merge) to each gdef groug.
+  # split gdefs based on hash, and apply Reduce (guide_merge) to each gdef group.
   gdefs <- lapply(gdefs, function(g) {
     if (g$order == 0) {
       order <- "99"
@@ -212,8 +216,9 @@ guides_gengrob <- function(gdefs, theme) {
   # common drawing process for all guides
   gdefs <- lapply(gdefs,
     function(g) {
-      g$title.position <- g$title.position %||% switch(g$direction, vertical="top", horizontal="left")
-      if (!g$title.position %in% c("top", "bottom", "left", "right")) stop("title position \"", g$title.position, "\" is invalid")
+      g$title.position <- g$title.position %||% switch(g$direction, vertical = "top", horizontal = "left")
+      if (!g$title.position %in% c("top", "bottom", "left", "right"))
+        stop("title position \"", g$title.position, "\" is invalid")
       g
     })
 
@@ -222,12 +227,9 @@ guides_gengrob <- function(gdefs, theme) {
 
 # build up all guide boxes into one guide-boxes.
 guides_build <- function(ggrobs, theme) {
-
-  n <- length(ggrobs)
-
-  theme$guide.margin <- theme$guide.margin %||% unit(0.5, "lines")
-  theme$guide.vmargin <- theme$guide.vmargin  %||% theme$guide.margin
-  theme$guide.hmargin <- theme$guide.hmargin  %||% theme$guide.margin
+  theme$legend.margin <- theme$legend.margin %||% unit(0.5, "lines")
+  theme$legend.vmargin <- theme$legend.vmargin  %||% theme$legend.margin
+  theme$legend.hmargin <- theme$legend.hmargin  %||% theme$legend.margin
 
   widths <- do.call("unit.c", lapply(ggrobs, function(g)sum(g$widths)))
   heights <- do.call("unit.c", lapply(ggrobs, function(g)sum(g$heights)))
@@ -238,7 +240,7 @@ guides_build <- function(ggrobs, theme) {
   xjust <- just[1]
   yjust <- just[2]
 
-  # setting that is different for vergical and horizontal guide-boxes.
+  # setting that is different for vertical and horizontal guide-boxes.
   if (theme$legend.box == "horizontal") {
     # Set justification for each legend
     for (i in seq_along(ggrobs)) {
@@ -252,7 +254,7 @@ guides_build <- function(ggrobs, theme) {
       widths = widths, height = max(heights))
 
     # add space between the guide-boxes
-    guides <- gtable_add_col_space(guides, theme$guide.hmargin)
+    guides <- gtable_add_col_space(guides, theme$legend.hmargin)
 
   } else if (theme$legend.box == "vertical") {
     # Set justification for each legend
@@ -267,14 +269,14 @@ guides_build <- function(ggrobs, theme) {
       width = max(widths), heights = heights)
 
     # add space between the guide-boxes
-    guides <- gtable_add_row_space(guides, theme$guide.vmargin)
+    guides <- gtable_add_row_space(guides, theme$legend.vmargin)
   }
 
   # add margins around the guide-boxes.
-  guides <- gtable_add_cols(guides, theme$guide.hmargin, pos = 0)
-  guides <- gtable_add_cols(guides, theme$guide.hmargin, pos = ncol(guides))
-  guides <- gtable_add_rows(guides, theme$guide.vmargin, pos = 0)
-  guides <- gtable_add_rows(guides, theme$guide.vmargin, pos = nrow(guides))
+  guides <- gtable_add_cols(guides, theme$legend.hmargin, pos = 0)
+  guides <- gtable_add_cols(guides, theme$legend.hmargin, pos = ncol(guides))
+  guides <- gtable_add_rows(guides, theme$legend.vmargin, pos = 0)
+  guides <- gtable_add_rows(guides, theme$legend.vmargin, pos = nrow(guides))
 
   guides$name <- "guide-box"
   guides
diff --git a/R/guides-axis.r b/R/guides-axis.r
index b076513..715bb2a 100644
--- a/R/guides-axis.r
+++ b/R/guides-axis.r
@@ -4,21 +4,12 @@
 # @param labels at ticks
 # @param position of axis (top, bottom, left or right)
 # @param range of data values
-guide_axis <- function(at, labels, position="right", theme) {
-  position <- match.arg(position, c("top", "bottom", "right", "left"))
-
-  # Quick fix for conflicts #297 and #118
-  # Previously, at = NA if there is no breaks (breaks = NA).
-  # Fix for oob bug changed so that at = numeric(0) if there is no breaks.
-  # Temporally, at is set as NA if there is no breaks.
-  # see also SHA: f332070fca77399a84ea7a116e8c63f6990abaf6, SHA: 2ae13ad0a856c24cab6a69b523da0936ef7a94d8
-  if (length(at) == 0) at <- NA
+guide_axis <- function(at, labels, position = "right", theme) {
+  if (length(at) == 0)
+    return(zeroGrob())
 
   at <- unit(at, "native")
-  length <- theme$axis.ticks.length
-  label_pos <- length + theme$axis.ticks.margin
-
-  nticks <- length(at)
+  position <- match.arg(position, c("top", "bottom", "right", "left"))
 
   zero <- unit(0, "npc")
   one <- unit(1, "npc")
@@ -31,14 +22,14 @@ guide_axis <- function(at, labels, position="right", theme) {
   label_x <- switch(position,
     top = ,
     bottom = at,
-    right = label_pos,
-    left = one - label_pos
+    right = theme$axis.ticks.length,
+    left = one - theme$axis.ticks.length
   )
   label_y <- switch(position,
-    top = label_pos,
-    bottom = one - label_pos,
+    top = theme$axis.ticks.length,
+    bottom = one - theme$axis.ticks.length,
     right = ,
-    left = at,
+    left = at
   )
 
   if (is.list(labels)) {
@@ -51,9 +42,9 @@ guide_axis <- function(at, labels, position="right", theme) {
 
   labels <- switch(position,
     top = ,
-    bottom = element_render(theme, label_render, labels, x = label_x),
+    bottom = element_render(theme, label_render, labels, x = label_x, expand_y = TRUE),
     right = ,
-    left =  element_render(theme, label_render, labels, y = label_y))
+    left =  element_render(theme, label_render, labels, y = label_y, expand_x = TRUE))
 
   line <- switch(position,
     top =    element_render(theme, "axis.line.x", c(0, 1), c(0, 0), id.lengths = 2),
@@ -62,22 +53,24 @@ guide_axis <- function(at, labels, position="right", theme) {
     left =   element_render(theme, "axis.line.y", c(1, 1), c(0, 1), id.lengths = 2)
   )
 
+  nticks <- length(at)
+
   ticks <- switch(position,
     top = element_render(theme, "axis.ticks.x",
-      x          = rep(at, each=2),
-      y          = rep(unit.c(zero, length), nticks),
+      x          = rep(at, each = 2),
+      y          = rep(unit.c(zero, theme$axis.ticks.length), nticks),
       id.lengths = rep(2, nticks)),
     bottom = element_render(theme, "axis.ticks.x",
-      x          = rep(at, each=2),
-      y          = rep(unit.c(one-length, one), nticks),
+      x          = rep(at, each = 2),
+      y          = rep(unit.c(one - theme$axis.ticks.length, one), nticks),
       id.lengths = rep(2, nticks)),
     right = element_render(theme, "axis.ticks.y",
-      x          = rep(unit.c(zero, length), nticks),
-      y          = rep(at, each=2),
+      x          = rep(unit.c(zero, theme$axis.ticks.length), nticks),
+      y          = rep(at, each = 2),
       id.lengths = rep(2, nticks)),
     left = element_render(theme, "axis.ticks.y",
-      x          = rep(unit.c(one-length, one), nticks),
-      y          = rep(at, each=2),
+      x          = rep(unit.c(one - theme$axis.ticks.length, one), nticks),
+      y          = rep(at, each = 2),
       id.lengths = rep(2, nticks))
   )
 
@@ -86,19 +79,23 @@ guide_axis <- function(at, labels, position="right", theme) {
     top    = gtable_col("axis",
       grobs   = list(labels, ticks),
       width   = one,
-      heights = unit.c(grobHeight(labels), label_pos)),
+      heights = unit.c(grobHeight(labels), theme$axis.ticks.length)
+    ),
     bottom = gtable_col("axis",
       grobs   = list(ticks, labels),
       width   = one,
-      heights = unit.c(label_pos, grobHeight(labels))),
+      heights = unit.c(theme$axis.ticks.length, grobHeight(labels))
+    ),
     right  = gtable_row("axis",
       grobs   = list(ticks, labels),
-      widths  = unit.c(label_pos, grobWidth(labels)),
-      height  = one),
+      widths  = unit.c(theme$axis.ticks.length, grobWidth(labels)),
+      height  = one
+    ),
     left   = gtable_row("axis",
       grobs   = list(labels, ticks),
-      widths  = unit.c(grobWidth(labels), label_pos),
-      height  = one)
+      widths  = unit.c(grobWidth(labels), theme$axis.ticks.length),
+      height  = one
+    )
   )
 
   # Viewport for justifying the axis grob
diff --git a/R/guides-grid.r b/R/guides-grid.r
index a90ed7c..ef24733 100644
--- a/R/guides-grid.r
+++ b/R/guides-grid.r
@@ -6,24 +6,24 @@ guide_grid <- function(theme, x.minor, x.major, y.minor, y.major) {
 
   ggname("grill", grobTree(
     element_render(theme, "panel.background"),
-    if(length(y.minor) > 0) element_render(
+    if (length(y.minor) > 0) element_render(
       theme, "panel.grid.minor.y",
-      x = rep(0:1, length(y.minor)), y = rep(y.minor, each=2),
+      x = rep(0:1, length(y.minor)), y = rep(y.minor, each = 2),
       id.lengths = rep(2, length(y.minor))
     ),
-    if(length(x.minor) > 0) element_render(
+    if (length(x.minor) > 0) element_render(
       theme, "panel.grid.minor.x",
-      x = rep(x.minor, each=2), y = rep(0:1, length(x.minor)),
+      x = rep(x.minor, each = 2), y = rep(0:1, length(x.minor)),
       id.lengths = rep(2, length(x.minor))
     ),
-    if(length(y.major) > 0) element_render(
+    if (length(y.major) > 0) element_render(
       theme, "panel.grid.major.y",
-      x = rep(0:1, length(y.major)), y = rep(y.major, each=2),
+      x = rep(0:1, length(y.major)), y = rep(y.major, each = 2),
       id.lengths = rep(2, length(y.major))
     ),
-    if(length(x.major) > 0) element_render(
+    if (length(x.major) > 0) element_render(
       theme, "panel.grid.major.x",
-      x = rep(x.major, each=2), y = rep(0:1, length(x.major)),
+      x = rep(x.major, each = 2), y = rep(0:1, length(x.major)),
       id.lengths = rep(2, length(x.major))
     )
   ))
diff --git a/R/labels.r b/R/labels.r
index 8966ea7..6398cd3 100644
--- a/R/labels.r
+++ b/R/labels.r
@@ -4,7 +4,7 @@
 #' @param labels named list of new labels
 #' @export
 #' @examples
-#' p <- qplot(mpg, wt, data = mtcars)
+#' p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
 #' update_labels(p, list(x = "New x"))
 #' update_labels(p, list(x = expression(x / y ^ 2)))
 #' update_labels(p, list(x = "New x", y = "New Y"))
@@ -21,20 +21,20 @@ update_labels <- function(p, labels) {
 #' @param ... a list of new names in the form aesthetic = "new name"
 #' @export
 #' @examples
-#' p <- qplot(mpg, wt, data = mtcars)
+#' p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
 #' p + labs(title = "New plot title")
 #' p + labs(x = "New x label")
 #' p + xlab("New x label")
 #' p + ylab("New y label")
 #' p + ggtitle("New plot title")
 #'
-#' # This should work indepdendently of other functions that modify the
+#' # This should work independently of other functions that modify the
 #' # the scale names
 #' p + ylab("New y label") + ylim(2, 4)
 #' p + ylim(2, 4) + ylab("New y label")
 #'
 #' # The labs function also modifies legend labels
-#' p <- qplot(mpg, wt, data = mtcars, colour = cyl)
+#' p <- ggplot(mtcars, aes(mpg, wt, colour = cyl)) + geom_point()
 #' p + labs(colour = "Cylinders")
 #'
 #' # Can also pass in a list, if that is more convenient
diff --git a/R/layer.r b/R/layer.r
index e219210..7e522a1 100644
--- a/R/layer.r
+++ b/R/layer.r
@@ -1,259 +1,245 @@
-# Create a new layer
-# Layer objects store the layer of an object.
-#
-# They have the following attributes:
-#
-#  * data
-#  * geom + parameters
-#  * statistic + parameters
-#  * position + parameters
-#  * aesthetic mapping
-#  * flag for display guide: TRUE/FALSE/NA. in the case of NA, decision depends on a guide itself.
-#
-# Can think about grob creation as a series of data frame transformations.
-Layer <- proto(expr = {
-  geom <- NULL
-  geom_params <- NULL
-  stat <- NULL
-  stat_params <- NULL
-  data <- NULL
-  mapping <- NULL
-  position <- NULL
-  params <- NULL
-  inherit.aes <- FALSE
-
-  new <- function (., geom=NULL, geom_params=NULL, stat=NULL, stat_params=NULL, data=NULL, mapping=NULL, position=NULL, params=NULL, ..., inherit.aes = TRUE, legend = NA, subset = NULL, show_guide = NA) {
-
-    # now, as for the guide, we can choose only if the layer is included or not in the guide: guide = TRUE or guide = FALSE
-    # in future, it may be better if we can choose which aes of this layer is included in the guide, e.g.: guide = c(colour = TRUE, size = FALSE)
-    if (!is.na(legend)) {
-      gg_dep("0.8.9", "\"legend\" argument in geom_XXX and stat_XXX is deprecated. Use show_guide = TRUE or show_guide = FALSE for display or suppress the guide display.")
-      show_guide = legend
-    }
-
-    if (!is.na(show_guide) && !is.logical(show_guide)) {
-      warning("`show_guide` in geom_XXX and stat_XXX must be logical.")
-      show_guide = FALSE
-    }
-
-
-    if (is.null(geom) && is.null(stat)) stop("Need at least one of stat and geom")
-
-    data <- fortify(data)
-    if (!is.null(mapping) && !inherits(mapping, "uneval")) stop("Mapping should be a list of unevaluated mappings created by aes or aes_string")
-
-    if (is.character(geom)) geom <- Geom$find(geom)
-    if (is.character(stat)) stat <- Stat$find(stat)
-    if (is.character(position)) position <- Position$find(position)$new()
-
-    if (is.null(geom)) geom <- stat$default_geom()
-    if (is.null(stat)) stat <- geom$default_stat()
-    if (is.null(position)) position <- geom$default_pos()$new()
-
-    match.params <- function(possible, params) {
-      if ("..." %in% names(possible)) {
-        params
-      } else {
-        params[match(names(possible), names(params), nomatch=0)]
-      }
-    }
-
-    if (is.null(geom_params) && is.null(stat_params)) {
-      params <- c(params, list(...))
-      params <- rename_aes(params) # Rename American to British spellings etc
-
-      geom_params <- match.params(geom$parameters(), params)
-      stat_params <- match.params(stat$parameters(), params)
-      stat_params <- stat_params[setdiff(names(stat_params),
-        names(geom_params))]
-    } else {
-      geom_params <- rename_aes(geom_params)
-    }
-
-    proto(.,
-      geom=geom, geom_params=geom_params,
-      stat=stat, stat_params=stat_params,
-      data=data, mapping=mapping, subset=subset,
-      position=position,
-      inherit.aes = inherit.aes,
-      show_guide = show_guide,
-    )
+#' Create a new layer
+#'
+#' @export
+#' @inheritParams geom_point
+#' @param geom,stat,position Geom, stat and position adjustment to use in
+#'   this layer. Can either be the name of a ggproto object, or the object
+#'   itself.
+#' @param params Additional parameters to the \code{geom} and \code{stat}.
+#' @param subset DEPRECATED. An older way of subsetting the dataset used in a
+#'   layer.
+#' @examples
+#' # geom calls are just a short cut for layer
+#' ggplot(mpg, aes(displ, hwy)) + geom_point()
+#' # shortcut for
+#' ggplot(mpg, aes(displ, hwy)) +
+#'   layer(geom = "point", stat = "identity", position = "identity",
+#'     params = list(na.rm = FALSE)
+#'   )
+layer <- function(geom = NULL, stat = NULL,
+                  data = NULL, mapping = NULL,
+                  position = NULL, params = list(),
+                  inherit.aes = TRUE, subset = NULL, show.legend = NA) {
+  if (is.null(geom))
+    stop("Attempted to create layer with no geom.", call. = FALSE)
+  if (is.null(stat))
+    stop("Attempted to create layer with no stat.", call. = FALSE)
+  if (is.null(position))
+    stop("Attempted to create layer with no position.", call. = FALSE)
+
+  # Handle show_guide/show.legend
+  if (!is.null(params$show_guide)) {
+    warning("`show_guide` has been deprecated. Please use `show.legend` instead.",
+      call. = FALSE)
+    show.legend <- params$show_guide
+    params$show_guide <- NULL
+  }
+  if (!is.logical(show.legend) || length(show.legend) != 1) {
+    warning("`show.legend` must be a logical vector of length 1.", call. = FALSE)
+    show.legend <- FALSE
   }
 
-  clone <- function(.) as.proto(.$as.list(all.names=TRUE))
+  data <- fortify(data)
+  if (!is.null(mapping) && !inherits(mapping, "uneval")) {
+    stop("Mapping must be created by `aes()` or `aes_()`", call. = FALSE)
+  }
 
-  use_defaults <- function(., data) {
-    df <- aesdefaults(data, .$geom$default_aes(), NULL)
+  if (is.character(geom))
+    geom <- find_subclass("Geom", geom)
+  if (is.character(stat))
+    stat <- find_subclass("Stat", stat)
+  if (is.character(position))
+    position <- find_subclass("Position", position)
 
-    # Override mappings with atomic parameters
-    gp <- intersect(c(names(df), .$geom$required_aes), names(.$geom_params))
-    gp <- gp[unlist(lapply(.$geom_params[gp], is.atomic))]
+  # Split up params between aesthetics, geom, and stat
+  params <- rename_aes(params)
 
-    # Check that mappings are compatable length: either 1 or the same length
-    # as the data
-    param_lengths <- vapply(.$geom_params[gp], length, numeric(1))
-    bad <- param_lengths != 1L & param_lengths != nrow(df)
-    if (any(bad)) {
-      stop("Incompatible lengths for set aesthetics: ",
-        paste(names(bad), collapse = ", "), call. = FALSE)
-    }
+  aes_params  <- params[intersect(names(params), geom$aesthetics())]
+  geom_params <- params[intersect(names(params), geom$parameters(TRUE))]
+  stat_params <- params[intersect(names(params), stat$parameters(TRUE))]
 
-    df[gp] <- .$geom_params[gp]
-    df
+  all <- c(geom$parameters(TRUE), stat$parameters(TRUE), geom$aesthetics())
+  extra <- setdiff(names(params), all)
+  if (length(extra) > 0) {
+    stop("Unknown parameters: ", paste(extra, collapse = ", "), call. = FALSE)
   }
 
-  layer_mapping <- function(., mapping = NULL) {
-    # For certain geoms, it is useful to be able to ignore the default
-    # aesthetics and only use those set in the layer
-    if (.$inherit.aes) {
-      aesthetics <- compact(defaults(.$mapping, mapping))
+  ggproto("LayerInstance", Layer,
+    geom = geom,
+    geom_params = geom_params,
+    stat = stat,
+    stat_params = stat_params,
+    data = data,
+    mapping = mapping,
+    aes_params = aes_params,
+    subset = subset,
+    position = position,
+    inherit.aes = inherit.aes,
+    show.legend = show.legend
+  )
+}
+
+Layer <- ggproto("Layer", NULL,
+  geom = NULL,
+  geom_params = NULL,
+  stat = NULL,
+  stat_params = NULL,
+  data = NULL,
+  aes_params = NULL,
+  mapping = NULL,
+  position = NULL,
+  inherit.aes = FALSE,
+
+  print = function(self) {
+    if (!is.null(self$mapping)) {
+      cat("mapping:", clist(self$mapping), "\n")
+    }
+    cat(snakeize(class(self$geom)[[1]]), ": ", clist(self$geom_params), "\n",
+      sep = "")
+    cat(snakeize(class(self$stat)[[1]]), ": ", clist(self$stat_params), "\n",
+      sep = "")
+    cat(snakeize(class(self$position)[[1]]), "\n")
+  },
+
+  compute_aesthetics = function(self, data, plot) {
+    # For annotation geoms, it is useful to be able to ignore the default aes
+    if (self$inherit.aes) {
+      aesthetics <- defaults(self$mapping, plot$mapping)
     } else {
-      aesthetics <- .$mapping
+      aesthetics <- self$mapping
     }
 
     # Drop aesthetics that are set or calculated
-    set <- names(aesthetics) %in% names(.$geom_params)
+    set <- names(aesthetics) %in% names(self$aes_params)
     calculated <- is_calculated_aes(aesthetics)
+    aesthetics <- aesthetics[!set & !calculated]
 
-    aesthetics[!set & !calculated]
-  }
-
-  pprint <- function(.) {
-    if (is.null(.$geom)) {
-      cat("Empty layer\n")
-      return(invisible());
-    }
-    if (!is.null(.$mapping)) {
-      cat("mapping:", clist(.$mapping), "\n")
+    # Override grouping if set in layer
+    if (!is.null(self$geom_params$group)) {
+      aesthetics[["group"]] <- self$aes_params$group
     }
-    .$geom$print(newline=FALSE)
-    cat(clist(.$geom_params), "\n")
-    .$stat$print(newline=FALSE)
-    cat(clist(.$stat_params), "\n")
-    .$position$print()
-  }
-
-
-  compute_aesthetics <- function(., data, plot) {
-    aesthetics <- .$layer_mapping(plot$mapping)
 
-    if (!is.null(.$subset)) {
-      include <- data.frame(eval.quoted(.$subset, data, plot$env))
+    # Old subsetting method
+    if (!is.null(self$subset)) {
+      include <- data.frame(plyr::eval.quoted(self$subset, data, plot$env))
       data <- data[rowSums(include, na.rm = TRUE) == ncol(include), ]
     }
 
-    # Override grouping if set in layer.
-    if (!is.null(.$geom_params$group)) {
-      aesthetics["group"] <- .$geom_params$group
-    }
-
     scales_add_defaults(plot$scales, data, aesthetics, plot$plot_env)
 
-    # Evaluate aesthetics in the context of their data frame
-    evaled <- compact(
-      eval.quoted(aesthetics, data, plot$plot_env))
-
-    lengths <- vapply(evaled, length, integer(1))
-    n <- if (length(lengths) > 0) max(lengths) else 0
+    # Evaluate and check aesthetics
+    aesthetics <- compact(aesthetics)
+    evaled <- lapply(aesthetics, eval, envir = data, enclos = plot$plot_env)
 
-    wrong <- lengths != 1 & lengths != n
-    if (any(wrong)) {
-      stop("Aesthetics must either be length one, or the same length as the data",
-        "Problems:", paste(aesthetics[wrong], collapse = ", "), call. = FALSE)
+    n <- nrow(data)
+    if (n == 0) {
+      # No data, so look at longest evaluated aesthetic
+      n <- max(vapply(evaled, length, integer(1)))
     }
+    check_aesthetics(evaled, n)
 
+    # Set special group and panel vars
     if (empty(data) && n > 0) {
-      # No data, and vectors suppled to aesthetics
       evaled$PANEL <- 1
     } else {
       evaled$PANEL <- data$PANEL
     }
-    data.frame(evaled)
-  }
-
-
-  calc_statistic <- function(., data, scales) {
-    if (empty(data)) return(data.frame())
+    evaled <- data.frame(evaled, stringsAsFactors = FALSE)
+    evaled <- add_group(evaled)
+    evaled
+  },
 
-    check_required_aesthetics(.$stat$required_aes,
-      c(names(data), names(.$stat_params)),
-      paste("stat_", .$stat$objname, sep=""))
+  compute_statistic = function(self, data, panel) {
+    if (empty(data))
+      return(data.frame())
 
-    res <- NULL
-    try(res <- do.call(.$stat$calculate_groups, c(
-      list(data=as.name("data"), scales=as.name("scales")),
-      .$stat_params)
-    ))
-    if (is.null(res)) return(data.frame())
+    params <- self$stat$setup_params(data, self$stat_params)
+    data <- self$stat$setup_data(data, params)
+    self$stat$compute_layer(data, params, panel)
+  },
 
-    res
-
-  }
-
-
-  map_statistic <- function(., data, plot) {
+  map_statistic = function(self, data, plot) {
     if (empty(data)) return(data.frame())
 
     # Assemble aesthetics from layer, plot and stat mappings
-    aesthetics <- .$mapping
-    if (.$inherit.aes) {
+    aesthetics <- self$mapping
+    if (self$inherit.aes) {
       aesthetics <- defaults(aesthetics, plot$mapping)
     }
-    aesthetics <- defaults(aesthetics, .$stat$default_aes())
+    aesthetics <- defaults(aesthetics, self$stat$default_aes)
     aesthetics <- compact(aesthetics)
 
     new <- strip_dots(aesthetics[is_calculated_aes(aesthetics)])
     if (length(new) == 0) return(data)
 
     # Add map stat output to aesthetics
-    stat_data <- as.data.frame(lapply(new, eval, data, baseenv()))
+    stat_data <- plyr::quickdf(lapply(new, eval, data, baseenv()))
     names(stat_data) <- names(new)
 
     # Add any new scales, if needed
     scales_add_defaults(plot$scales, data, new, plot$plot_env)
     # Transform the values, if the scale say it's ok
     # (see stat_spoke for one exception)
-    if (.$stat$retransform) {
+    if (self$stat$retransform) {
       stat_data <- scales_transform_df(plot$scales, stat_data)
     }
 
     cunion(stat_data, data)
-  }
+  },
 
-  reparameterise <- function(., data) {
+  compute_geom_1 = function(self, data) {
     if (empty(data)) return(data.frame())
-    .$geom$reparameterise(data, .$geom_params)
-  }
+    data <- self$geom$setup_data(data, c(self$geom_params, self$aes_params))
 
+    check_required_aesthetics(
+      self$geom$required_aes,
+      c(names(data), names(self$aes_params)),
+      snake_class(self$geom)
+    )
 
-  adjust_position <- function(., data) {
-    ddply(data, "PANEL", function(data) {
-      .$position$adjust(data)
-    })
-  }
+    data
+  },
+
+  compute_position = function(self, data, panel) {
+    if (empty(data)) return(data.frame())
+
+    params <- self$position$setup_params(data)
+    data <- self$position$setup_data(data, params)
 
-  make_grob <- function(., data, scales, cs) {
-    if (empty(data)) return(zeroGrob())
+    self$position$compute_layer(data, params, panel)
+  },
 
-    data <- .$use_defaults(data)
+  compute_geom_2 = function(self, data) {
+    # Combine aesthetics, defaults, & params
+    if (empty(data)) return(data)
 
-    check_required_aesthetics(.$geom$required_aes,
-      c(names(data), names(.$geom_params)),
-      paste("geom_", .$geom$objname, sep=""))
+    self$geom$use_defaults(data, self$aes_params)
+  },
 
-    do.call(.$geom$draw_groups, c(
-      data = list(as.name("data")),
-      scales = list(as.name("scales")),
-      coordinates = list(as.name("cs")),
-      .$geom_params
-    ))
+  draw_geom = function(self, data, panel, coord) {
+    if (empty(data)) {
+      n <- nrow(panel$layout)
+      return(rep(list(zeroGrob()), n))
+    }
+
+    data <- self$geom$handle_na(data, self$geom_params)
+    self$geom$draw_layer(data, self$geom_params, panel, coord)
   }
+)
 
-  class <- function(.) "layer"
-})
+is.layer <- function(x) inherits(x, "Layer")
 
-#' Create a new layer
-#'
-#' @keywords internal
-#' @export
-layer <- Layer$new
+
+find_subclass <- function(super, class) {
+  name <- paste0(super, camelize(class, first = TRUE))
+  if (!exists(name)) {
+    stop("No ", tolower(super), " called ", name, ".", call. = FALSE)
+  }
+
+  obj <- get(name)
+  if (!inherits(obj, super)) {
+    stop("Found object is not a ", tolower(super), ".", call. = FALSE)
+  }
+
+  obj
+}
diff --git a/R/legend-draw.r b/R/legend-draw.r
new file mode 100644
index 0000000..8d82faf
--- /dev/null
+++ b/R/legend-draw.r
@@ -0,0 +1,201 @@
+#' Key drawing functions
+#'
+#' Each Geom has an associated function that draws the key when the geom needs
+#' to be displayed in a legend. These are the options built into ggplot2.
+#'
+#' @return A grid grob.
+#' @param data A single row data frame containing the scaled aesthetics to
+#'   display in this key
+#' @param params A list of additional parameters supplied to the geom.
+#' @param size Width and height of key in mm.
+#' @keywords internal
+#' @name draw_key
+NULL
+
+#' @export
+#' @rdname draw_key
+draw_key_point <- function(data, params, size) {
+  pointsGrob(0.5, 0.5,
+    pch = data$shape,
+    gp = gpar(
+      col = alpha(data$colour, data$alpha),
+      fill = alpha(data$fill, data$alpha),
+      fontsize = data$size * .pt + data$stroke * .stroke / 2,
+      lwd = data$stroke * .stroke / 2
+    )
+  )
+}
+
+#' @export
+#' @rdname draw_key
+draw_key_abline <- function(data, params, size) {
+  segmentsGrob(0, 0, 1, 1,
+    gp = gpar(
+      col = alpha(data$colour, data$alpha),
+      lwd = data$size * .pt,
+      lty = data$linetype,
+      lineend = "butt"
+    )
+  )
+}
+
+#' @export
+#' @rdname draw_key
+draw_key_rect <- function(data, params, size) {
+  rectGrob(gp = gpar(
+    col = NA,
+    fill = alpha(data$fill, data$alpha),
+    lty = data$linetype
+  ))
+}
+#' @export
+#' @rdname draw_key
+draw_key_polygon <- function(data, params, size) {
+  lwd <- min(data$size, min(size) / 4)
+
+  rectGrob(
+    width = unit(1, "npc") - unit(lwd, "mm"),
+    height = unit(1, "npc") - unit(lwd, "mm"),
+    gp = gpar(
+      col = data$colour,
+      fill = alpha(data$fill, data$alpha),
+      lty = data$linetype,
+      lwd = lwd * .pt,
+      linejoin = "mitre"
+  ))
+}
+
+#' @export
+#' @rdname draw_key
+draw_key_blank <- function(data, params, size) {
+  zeroGrob()
+}
+
+#' @export
+#' @rdname draw_key
+draw_key_boxplot <- function(data, params, size) {
+  grobTree(
+    linesGrob(0.5, c(0.1, 0.25)),
+    linesGrob(0.5, c(0.75, 0.9)),
+    rectGrob(height = 0.5, width = 0.75),
+    linesGrob(c(0.125, 0.875), 0.5),
+    gp = gpar(
+      col = data$colour,
+      fill = alpha(data$fill, data$alpha),
+      lwd = data$size * .pt,
+      lty = data$linetype
+    )
+  )
+}
+
+#' @export
+#' @rdname draw_key
+draw_key_crossbar <- function(data, params, size) {
+  grobTree(
+    rectGrob(height = 0.5, width = 0.75),
+    linesGrob(c(0.125, 0.875), 0.5),
+    gp = gpar(
+      col = data$colour,
+      fill = alpha(data$fill, data$alpha),
+      lwd = data$size * .pt,
+      lty = data$linetype
+    )
+  )
+}
+
+#' @export
+#' @rdname draw_key
+draw_key_path <- function(data, params, size) {
+  segmentsGrob(0.1, 0.5, 0.9, 0.5,
+    gp = gpar(
+      col = alpha(data$colour, data$alpha),
+      lwd = data$size * .pt,
+      lty = data$linetype,
+      lineend = "butt"
+    ),
+    arrow = params$arrow
+  )
+}
+
+#' @export
+#' @rdname draw_key
+draw_key_vpath <- function(data, params, size) {
+  segmentsGrob(0.5, 0.1, 0.5, 0.9,
+    gp = gpar(
+      col = alpha(data$colour, data$alpha),
+      lwd = data$size * .pt,
+      lty = data$linetype,
+      lineend = "butt"
+    ),
+    arrow = params$arrow
+  )
+}
+
+#' @export
+#' @rdname draw_key
+draw_key_dotplot <- function(data, params, size) {
+  pointsGrob(0.5, 0.5, size = unit(.5, "npc"),
+    pch = 21,
+    gp = gpar(
+      col = alpha(data$colour, data$alpha),
+      fill = alpha(data$fill, data$alpha)
+    )
+  )
+}
+
+#' @export
+#' @rdname draw_key
+draw_key_pointrange <- function(data, params, size) {
+  grobTree(
+    draw_key_vpath(data, params, size),
+    draw_key_point(transform(data, size = data$size * 4), params)
+  )
+}
+
+#' @export
+#' @rdname draw_key
+draw_key_smooth <- function(data, params, size) {
+  data$fill <- alpha(data$fill, data$alpha)
+  data$alpha <- 1
+
+  grobTree(
+    if (isTRUE(params$se)) rectGrob(gp = gpar(col = NA, fill = data$fill)),
+    draw_key_path(data, params)
+  )
+}
+
+#' @export
+#' @rdname draw_key
+draw_key_text <- function(data, params, size) {
+  textGrob("a", 0.5, 0.5,
+    rot = data$angle,
+    gp = gpar(
+      col = alpha(data$colour, data$alpha),
+      fontfamily = data$family,
+      fontface = data$fontface,
+      fontsize = data$size * .pt
+    )
+  )
+}
+
+#' @export
+#' @rdname draw_key
+draw_key_label <- function(data, params, size) {
+  grobTree(
+    draw_key_rect(data, list()),
+    draw_key_text(data, list())
+  )
+}
+
+#' @export
+#' @rdname draw_key
+draw_key_vline <- function(data, params, size) {
+  segmentsGrob(0.5, 0, 0.5, 1,
+    gp = gpar(
+      col = alpha(data$colour, data$alpha),
+      lwd = data$size * .pt,
+      lty = data$linetype,
+      lineend = "butt"
+    )
+  )
+}
diff --git a/R/limits.r b/R/limits.r
index 97f737e..315f442 100644
--- a/R/limits.r
+++ b/R/limits.r
@@ -1,14 +1,14 @@
-#' Convenience functions to set the limits of the x and y axis.
+#' Convenience functions to set the axis limits.
 #'
 #' Observations not in this range will be dropped completely and
 #' not passed to any other layers.  If a NA value is substituted for one of the
 #' limits that limit is automatically calculated.
 #'
-#' @param ... if numeric, will create a continuous scale, if factor or
-#'   character, will create a discrete scale.
+#' @param ... If numeric, will create a continuous scale, if factor or
+#'   character, will create a discrete scale.  For \code{lims}, every
+#'   argument must be named.
 #' @seealso For changing x or y axis limits \strong{without} dropping data
 #'   observations, see \code{\link{coord_cartesian}}.
-#' @rdname xylim
 #' @export
 #' @examples
 #' # xlim
@@ -16,30 +16,44 @@
 #' xlim(20, 15)
 #' xlim(c(10, 20))
 #' xlim("a", "b", "c")
-#' qplot(mpg, wt, data=mtcars) + xlim(15, 20)
+#'
+#' ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point() +
+#'   xlim(15, 20)
 #' # with automatic lower limit
-#' qplot(mpg, wt, data=mtcars) + xlim(NA, 20)
+#' ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point() +
+#'   xlim(NA, 20)
 #'
-#' # ylim
-#' ylim(15, 20)
-#' ylim(c(10, 20))
-#' ylim("a", "b", "c")
-#' qplot(mpg, wt, data=mtcars) + ylim(0, 4)
-#' # with automatic upper limit
-#' qplot(mpg, wt, data=mtcars) + ylim(0, NA)
+#' # Change both xlim and ylim
+#' ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point() +
+#'   lims(x = c(10, 20), y = c(3, 5))
+lims <- function(...) {
+  args <- list(...)
+
+  if (any(!has_name(args))) {
+    stop("All arguments must be named", call. = FALSE)
+  }
+
+  Map(limits, args, names(args))
+}
+
+#' @export
+#' @rdname lims
 xlim <- function(...) {
   limits(c(...), "x")
 }
 
-#' @rdname xylim
 #' @export
+#' @rdname lims
 ylim <- function(...) {
   limits(c(...), "y")
 }
 
 #' Generate correct scale type for specified limits
 #'
-#' @param limts vector of limits
+#' @param limits vector of limits
 #' @param var name of variable
 #' @keywords internal
 #' @examples
@@ -100,17 +114,19 @@ limits.POSIXlt <- function(lims, var) {
 #'   should be included in each scale.
 #' @export
 #' @examples
-#' p <- qplot(mpg, wt, data = mtcars)
+#' p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
 #' p + expand_limits(x = 0)
 #' p + expand_limits(y = c(1, 9))
 #' p + expand_limits(x = 0, y = 0)
 #'
-#' qplot(mpg, wt, data = mtcars, colour = cyl) +
-#'  expand_limits(colour = seq(2, 10, by = 2))
-#' qplot(mpg, wt, data = mtcars, colour = factor(cyl)) +
-#'  expand_limits(colour = factor(seq(2, 10, by = 2)))
+#' ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point(aes(colour = cyl)) +
+#'   expand_limits(colour = seq(2, 10, by = 2))
+#' ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point(aes(colour = factor(cyl))) +
+#'   expand_limits(colour = factor(seq(2, 10, by = 2)))
 expand_limits <- function(...) {
-  data <- data.frame(...)
+  data <- data.frame(..., stringsAsFactors = FALSE)
 
   geom_blank(aes_all(names(data)), data, inherit.aes = FALSE)
 }
diff --git a/R/margins.R b/R/margins.R
new file mode 100644
index 0000000..967b272
--- /dev/null
+++ b/R/margins.R
@@ -0,0 +1,168 @@
+#' Define margins.
+#'
+#' This is a convenience function that creates a grid unit object of the
+#' correct length to use for setting margins.
+#'
+#' @export
+#' @param t,b,r,l Dimensions of each margin. (To remember order, think trouble).
+#' @param unit Default units of dimensions. Defaults to "pt" so it
+#'   can be most easily scaled with the text.
+#' @export
+#' @examples
+#' margin(4)
+#' margin(4, 2)
+#' margin(4, 3, 2, 1)
+margin <- function(t = 0, r = 0, b = 0, l = 0, unit = "pt") {
+  structure(unit(c(t, r, b, l), unit), class = c("margin", "unit"))
+}
+
+
+margin_height <- function(grob, margins) {
+  if (is.zero(grob)) return(unit(0, "cm"))
+
+  grobHeight(grob) + margins[1] + margins[3]
+}
+
+margin_width <- function(grob, margins) {
+  if (is.zero(grob)) return(unit(0, "cm"))
+
+  grobWidth(grob) + margins[2] + margins[4]
+}
+
+titleGrob <- function(label, x, y, hjust, vjust, angle = 0, gp = gpar(),
+                      margin = NULL, expand_x = FALSE, expand_y = FALSE,
+                      debug = FALSE) {
+
+  if (is.null(label))
+    return(zeroGrob())
+
+  if (is.null(margin)) {
+    margin <- margin(0, 0, 0, 0)
+  }
+
+  angle <- angle %% 360
+  if (angle == 90) {
+    xp <- 1 - vjust
+    yp <- hjust
+  } else if (angle == 180) {
+    xp <- 1 - hjust
+    yp <- 1 - vjust
+  } else if (angle == 270) {
+    xp <- vjust
+    yp <- 1 - hjust
+  } else {
+    xp <- hjust
+    yp <- vjust
+  }
+
+  n <- max(length(x), length(y), 1)
+  x <- x %||% unit(rep(xp, n), "npc")
+  y <- y %||% unit(rep(yp, n), "npc")
+
+  text_grob <- textGrob(label, x, y, hjust = hjust, vjust = vjust,
+    rot = angle, gp = gp)
+
+  if (expand_x && expand_y) {
+    widths <- unit.c(margin[4], unit(1, "grobwidth", text_grob), margin[2])
+    heights <- unit.c(margin[1], unit(1, "grobheight", text_grob), margin[3])
+
+    vp <- viewport(layout = grid.layout(3, 3, heights = heights, widths = widths), gp = gp)
+    child_vp <- viewport(layout.pos.row = 2, layout.pos.col = 2)
+  } else if (expand_x) {
+    widths <- unit.c(margin[4], unit(1, "grobwidth", text_grob), margin[2])
+    vp <- viewport(layout = grid.layout(1, 3, widths = widths), gp = gp)
+    child_vp <- viewport(layout.pos.col = 2)
+
+    heights <- unit(1, "null")
+  } else if (expand_y) {
+    heights <- unit.c(margin[1], unit(1, "grobheight", text_grob), margin[3])
+
+    vp <- viewport(layout = grid.layout(3, 1, heights = heights), gp = gp)
+    child_vp <- viewport(layout.pos.row = 2)
+
+    widths <- unit(1, "null")
+  } else {
+    return(text_grob)
+  }
+
+  if (debug) {
+    children <- gList(
+      rectGrob(gp = gpar(fill = "cornsilk", col = NA)),
+      pointsGrob(x, y, pch = 20, gp = gpar(col = "gold")),
+      text_grob
+    )
+  } else {
+    children <- gList(text_grob)
+  }
+
+  gTree(
+    children = children,
+    vp = vpTree(vp, vpList(child_vp)),
+    widths = widths,
+    heights = heights,
+    cl = "titleGrob"
+  )
+}
+
+#' @export
+widthDetails.titleGrob <- function(x) {
+  sum(x$widths)
+}
+
+#' @export
+heightDetails.titleGrob <- function(x) {
+  sum(x$heights)
+}
+
+# Works like titleGrob, but designed to place one label per viewport.
+# This means it doesn't have the lengths of labels available, so must use
+# alternative layout strategy
+stripGrob <- function(label, hjust, vjust, angle = 0, gp = gpar(),
+                      margin = NULL, debug = FALSE) {
+  if (is.null(margin)) {
+    margin <- margin()
+  }
+
+  text_grob <- textGrob(label, rot = angle, gp = gp)
+
+  widths <- unit.c(margin[4], unit(1, "grobwidth", text_grob), margin[2])
+  heights <- unit.c(margin[1], unit(1, "grobheight", text_grob), margin[3])
+
+  vp <- viewport(
+    hjust, vjust, just = c(hjust, vjust),
+    width = sum(widths),
+    height = sum(heights),
+    layout = grid.layout(3, 3, heights = heights, widths = widths),
+    name = "top"
+  )
+  child_vp <- viewport(layout.pos.row = 2, layout.pos.col = 2)
+
+  if (debug) {
+    children <- gList(
+      rectGrob(gp = gpar(fill = "cornsilk", col = NA)),
+      pointsGrob(unit(hjust, "npc"), unit(vjust, "npc"), pch = 20,
+        gp = gpar(col = "gold")),
+      text_grob
+    )
+  } else {
+    children <- gList(text_grob)
+  }
+
+  gTree(
+    children = children,
+    vp = vpTree(vp, vpList(child_vp)),
+    widths = widths,
+    heights = heights,
+    cl = "stripGrob"
+  )
+}
+
+#' @export
+widthDetails.stripGrob <- function(x) {
+  sum(x$widths)
+}
+
+#' @export
+heightDetails.stripGrob <- function(x) {
+  sum(x$heights)
+}
diff --git a/R/panel.r b/R/panel.r
index fdb5ea7..e147464 100644
--- a/R/panel.r
+++ b/R/panel.r
@@ -66,14 +66,14 @@ train_position <- function(panel, data, x_scale, y_scale) {
   # Initialise scales if needed, and possible.
   layout <- panel$layout
   if (is.null(panel$x_scales) && !is.null(x_scale)) {
-    panel$x_scales <- rlply(max(layout$SCALE_X), scale_clone(x_scale))
+    panel$x_scales <- plyr::rlply(max(layout$SCALE_X), x_scale$clone())
   }
   if (is.null(panel$y_scales) && !is.null(y_scale)) {
-    panel$y_scales <- rlply(max(layout$SCALE_Y), scale_clone(y_scale))
+    panel$y_scales <- plyr::rlply(max(layout$SCALE_Y), y_scale$clone())
   }
 
   # loop over each layer, training x and y scales in turn
-  for(layer_data in data) {
+  for (layer_data in data) {
 
     match_id <- match(layer_data$PANEL, layout$PANEL)
 
@@ -81,14 +81,14 @@ train_position <- function(panel, data, x_scale, y_scale) {
       x_vars <- intersect(x_scale$aesthetics, names(layer_data))
       SCALE_X <- layout$SCALE_X[match_id]
 
-      scale_apply(layer_data, x_vars, scale_train, SCALE_X, panel$x_scales)
+      scale_apply(layer_data, x_vars, "train", SCALE_X, panel$x_scales)
     }
 
     if (!is.null(y_scale)) {
       y_vars <- intersect(y_scale$aesthetics, names(layer_data))
       SCALE_Y <- layout$SCALE_Y[match_id]
 
-      scale_apply(layer_data, y_vars, scale_train, SCALE_Y, panel$y_scales)
+      scale_apply(layer_data, y_vars, "train", SCALE_Y, panel$y_scales)
     }
   }
 
@@ -98,8 +98,9 @@ train_position <- function(panel, data, x_scale, y_scale) {
 
 reset_scales <- function(panel) {
   if (!panel$shrink) return()
-  l_ply(panel$x_scales, scale_reset)
-  l_ply(panel$y_scales, scale_reset)
+  lapply(panel$x_scales, function(s) s$reset())
+  lapply(panel$y_scales, function(s) s$reset())
+  invisible()
 }
 
 # Map data with scales.
@@ -119,36 +120,34 @@ map_position <- function(panel, data, x_scale, y_scale) {
     x_vars <- intersect(x_scale$aesthetics, names(layer_data))
     names(x_vars) <- x_vars
     SCALE_X <- layout$SCALE_X[match_id]
-    new_x <- scale_apply(layer_data, x_vars, scale_map, SCALE_X,
-       panel$x_scales)
+    new_x <- scale_apply(layer_data, x_vars, "map", SCALE_X, panel$x_scales)
     layer_data[, x_vars] <- new_x
 
     y_vars <- intersect(y_scale$aesthetics, names(layer_data))
     names(y_vars) <- y_vars
     SCALE_Y <- layout$SCALE_Y[match_id]
-    new_y <- scale_apply(layer_data, y_vars, scale_map, SCALE_Y,
-       panel$y_scales)
+    new_y <- scale_apply(layer_data, y_vars, "map", SCALE_Y, panel$y_scales)
 
     layer_data[, y_vars] <- new_y
     layer_data
   })
 }
 
-# Function for applying scale function to multiple variables in a given
-# data set.  Implement in such a way to minimise copying and hence maximise
+# Function for applying scale method to multiple variables in a given
+# data set.  Implement in such a way to minimize copying and hence maximise
 # speed
-scale_apply <- function(data, vars, f, scale_id, scales) {
+scale_apply <- function(data, vars, method, scale_id, scales) {
   if (length(vars) == 0) return()
   if (nrow(data) == 0) return()
 
   n <- length(scales)
   if (any(is.na(scale_id))) stop()
 
-  scale_index <- split_indices(scale_id, n)
+  scale_index <- plyr::split_indices(scale_id, n)
 
   lapply(vars, function(var) {
     pieces <- lapply(seq_along(scales), function(i) {
-      f(scales[[i]], data[[var]][scale_index[[i]]])
+      scales[[i]][[method]](data[[var]][scale_index[[i]]])
     })
     # Join pieces back together, if necessary
     if (!is.null(pieces)) {
@@ -171,7 +170,7 @@ panel_scales <- function(panel, i) {
 train_ranges <- function(panel, coord) {
   compute_range <- function(ix, iy) {
     # TODO: change coord_train method to take individual x and y scales
-    coord_train(coord, list(x = panel$x_scales[[ix]], y = panel$y_scales[[iy]]))
+    coord$train(list(x = panel$x_scales[[ix]], y = panel$y_scales[[iy]]))
   }
 
   panel$ranges <- Map(compute_range,
@@ -179,28 +178,10 @@ train_ranges <- function(panel, coord) {
   panel
 }
 
-# Calculate statistics
-#
-# @param layers list of layers
-# @param data a list of data frames (one for each layer)
-calculate_stats <- function(panel, data, layers) {
-
-  lapply(seq_along(data), function(i) {
-    d <- data[[i]]
-    l <- layers[[i]]
-
-    ddply(d, "PANEL", function(panel_data) {
-      scales <- panel_scales(panel, panel_data$PANEL[1])
-      l$calc_statistic(panel_data, scales)
-    })
-  })
-}
-
-
 xlabel <- function(panel, labels) {
-  panel$x_scales[[1]]$name %||% labels$x
+  panel$x_scales[[1]]$name %|W|% labels$x
 }
 
 ylabel <- function(panel, labels) {
-  panel$y_scales[[1]]$name %||% labels$y
+  panel$y_scales[[1]]$name %|W|% labels$y
 }
diff --git a/R/plot-build.r b/R/plot-build.r
index a691ea8..d4ef2a2 100644
--- a/R/plot-build.r
+++ b/R/plot-build.r
@@ -1,29 +1,35 @@
 #' Build ggplot for rendering.
 #'
-#' This function takes the plot object, and performs all steps necessary to
-#' produce an object that can be rendered.  This function outputs two pieces:
+#' \code{ggplot_build} takes the plot object, and performs all steps necessary
+#' to produce an object that can be rendered.  This function outputs two pieces:
 #' a list of data frames (one for each layer), and a panel object, which
 #' contain all information about axis limits, breaks etc.
 #'
+#' \code{layer_data}, \code{layer_grob}, and \code{layer_scales} are helper
+#' functions that returns the data, grob, or scales associated with a given
+#' layer. These are useful for tests.
+#'
 #' @param plot ggplot object
-#' @seealso \code{\link{print.ggplot}} and \code{link{benchplot}} for
-#'  for functions that contain the complete set of steps for generating
+#' @seealso \code{\link{print.ggplot}} and \code{\link{benchplot}} for
+#'  functions that contain the complete set of steps for generating
 #'  a ggplot2 plot.
 #' @keywords internal
 #' @export
 ggplot_build <- function(plot) {
-  if (length(plot$layers) == 0) stop("No layers in plot", call.=FALSE)
-
   plot <- plot_clone(plot)
+  if (length(plot$layers) == 0) {
+    plot <- plot + geom_blank()
+  }
+
   layers <- plot$layers
   layer_data <- lapply(layers, function(y) y$data)
 
   scales <- plot$scales
   # Apply function to layer and matching data
-  dlapply <- function(f) {
+  by_layer <- function(f) {
     out <- vector("list", length(data))
-    for(i in seq_along(data)) {
-      out[[i]] <- f(d = data[[i]], p = layers[[i]])
+    for (i in seq_along(data)) {
+      out[[i]] <- f(l = layers[[i]], d = data[[i]])
     }
     out
   }
@@ -36,8 +42,7 @@ ggplot_build <- function(plot) {
   data <- map_layout(panel, plot$facet, layer_data, plot$data)
 
   # Compute aesthetics to produce data with generalised variable names
-  data <- dlapply(function(d, p) p$compute_aesthetics(d, plot))
-  data <- lapply(data, add_group)
+  data <- by_layer(function(l, d) l$compute_aesthetics(d, plot))
 
   # Transform all scales
   data <- lapply(data, scales_transform_df, scales = scales)
@@ -51,18 +56,17 @@ ggplot_build <- function(plot) {
   data <- map_position(panel, data, scale_x(), scale_y())
 
   # Apply and map statistics
-  data <- calculate_stats(panel, data, layers)
-  data <- dlapply(function(d, p) p$map_statistic(d, plot))
-  data <- lapply(data, order_groups)
+  data <- by_layer(function(l, d) l$compute_statistic(d, panel))
+  data <- by_layer(function(l, d) l$map_statistic(d, plot))
 
   # Make sure missing (but required) aesthetics are added
-  scales_add_missing(plot, c("x", "y"))
+  scales_add_missing(plot, c("x", "y"), plot$plot_env)
 
   # Reparameterise geoms from (e.g.) y and width to ymin and ymax
-  data <- dlapply(function(d, p) p$reparameterise(d))
+  data <- by_layer(function(l, d) l$compute_geom_1(d))
 
   # Apply position adjustments
-  data <- dlapply(function(d, p) p$adjust_position(d))
+  data <- by_layer(function(l, d) l$compute_position(d, panel))
 
   # Reset position scales, then re-train and map.  This ensures that facets
   # have control over the range of a plot: is it generated from what's
@@ -81,6 +85,199 @@ ggplot_build <- function(plot) {
   # Train coordinate system
   panel <- train_ranges(panel, plot$coordinates)
 
+  # Fill in defaults etc.
+  data <- by_layer(function(l, d) l$compute_geom_2(d))
+
   list(data = data, panel = panel, plot = plot)
 }
 
+#' @export
+#' @rdname ggplot_build
+layer_data <- function(plot, i = 1L) {
+  ggplot_build(plot)$data[[i]]
+}
+
+#' @export
+#' @rdname ggplot_build
+layer_scales <- function(plot, i = 1L, j = 1L) {
+  b <- ggplot_build(plot)
+
+  layout <- b$panel$layout
+  selected <- layout[layout$ROW == i & layout$COL == j, , drop = FALSE]
+
+  list(
+    x = b$panel$x_scales[[selected$SCALE_X]],
+    y = b$panel$y_scales[[selected$SCALE_Y]]
+  )
+}
+
+#' @export
+#' @rdname ggplot_build
+layer_grob <- function(plot, i = 1L) {
+  b <- ggplot_build(plot)
+
+  b$plot$layers[[i]]$draw_geom(b$data[[i]], b$panel, b$plot$coordinates)
+}
+
+#' Build a plot with all the usual bits and pieces.
+#'
+#' This function builds all grobs necessary for displaying the plot, and
+#' stores them in a special data structure called a \code{\link{gtable}}.
+#' This object is amenable to programmatic manipulation, should you want
+#' to (e.g.) make the legend box 2 cm wide, or combine multiple plots into
+#' a single display, preserving aspect ratios across the plots.
+#'
+#' @seealso \code{\link{print.ggplot}} and \code{link{benchplot}} for
+#'  for functions that contain the complete set of steps for generating
+#'  a ggplot2 plot.
+#' @return a \code{\link{gtable}} object
+#' @keywords internal
+#' @param plot plot object
+#' @param data plot data generated by \code{\link{ggplot_build}}
+#' @export
+ggplot_gtable <- function(data) {
+  plot <- data$plot
+  panel <- data$panel
+  data <- data$data
+  theme <- plot_theme(plot)
+
+  geom_grobs <- Map(function(l, d) l$draw_geom(d, panel, plot$coordinates),
+    plot$layers, data)
+
+  plot_table <- facet_render(plot$facet, panel, plot$coordinates,
+    theme, geom_grobs)
+
+  # Axis labels
+  labels <- plot$coordinates$labels(list(
+    x = xlabel(panel, plot$labels),
+    y = ylabel(panel, plot$labels)
+  ))
+  xlabel <- element_render(theme, "axis.title.x", labels$x, expand_y = TRUE)
+  ylabel <- element_render(theme, "axis.title.y", labels$y, expand_x = TRUE)
+
+  # helper function return the position of panels in plot_table
+  find_panel <- function(table) {
+    layout <- table$layout
+    panels <- layout[grepl("^panel", layout$name), , drop = FALSE]
+
+    data.frame(
+      t = min(panels$t),
+      r = max(panels$r),
+      b = max(panels$b),
+      l = min(panels$l)
+    )
+  }
+  panel_dim <-  find_panel(plot_table)
+
+  xlab_height <- grobHeight(xlabel)
+  plot_table <- gtable_add_rows(plot_table, xlab_height)
+  plot_table <- gtable_add_grob(plot_table, xlabel, name = "xlab",
+    l = panel_dim$l, r = panel_dim$r, t = -1, clip = "off")
+
+  ylab_width <- grobWidth(ylabel)
+  plot_table <- gtable_add_cols(plot_table, ylab_width, pos = 0)
+  plot_table <- gtable_add_grob(plot_table, ylabel, name = "ylab",
+    l = 1, b = panel_dim$b, t = panel_dim$t, clip = "off")
+
+  # Legends
+  position <- theme$legend.position
+  if (length(position) == 2) {
+    position <- "manual"
+  }
+
+  legend_box <- if (position != "none") {
+    build_guides(plot$scales, plot$layers, plot$mapping, position, theme, plot$guides, plot$labels)
+  } else {
+    zeroGrob()
+  }
+
+  if (is.zero(legend_box)) {
+    position <- "none"
+  } else {
+    # these are a bad hack, since it modifies the contents of viewpoint directly...
+    legend_width  <- gtable_width(legend_box)  + theme$legend.margin
+    legend_height <- gtable_height(legend_box) + theme$legend.margin
+
+    # Set the justification of the legend box
+    # First value is xjust, second value is yjust
+    just <- valid.just(theme$legend.justification)
+    xjust <- just[1]
+    yjust <- just[2]
+
+    if (position == "manual") {
+      xpos <- theme$legend.position[1]
+      ypos <- theme$legend.position[2]
+
+      # x and y are specified via theme$legend.position (i.e., coords)
+      legend_box <- editGrob(legend_box,
+        vp = viewport(x = xpos, y = ypos, just = c(xjust, yjust),
+          height = legend_height, width = legend_width))
+    } else {
+      # x and y are adjusted using justification of legend box (i.e., theme$legend.justification)
+      legend_box <- editGrob(legend_box,
+        vp = viewport(x = xjust, y = yjust, just = c(xjust, yjust)))
+    }
+  }
+
+  panel_dim <-  find_panel(plot_table)
+  # for align-to-device, use this:
+  # panel_dim <-  summarise(plot_table$layout, t = min(t), r = max(r), b = max(b), l = min(l))
+
+  if (position == "left") {
+    plot_table <- gtable_add_cols(plot_table, legend_width, pos = 0)
+    plot_table <- gtable_add_grob(plot_table, legend_box, clip = "off",
+      t = panel_dim$t, b = panel_dim$b, l = 1, r = 1, name = "guide-box")
+  } else if (position == "right") {
+    plot_table <- gtable_add_cols(plot_table, legend_width, pos = -1)
+    plot_table <- gtable_add_grob(plot_table, legend_box, clip = "off",
+      t = panel_dim$t, b = panel_dim$b, l = -1, r = -1, name = "guide-box")
+  } else if (position == "bottom") {
+    plot_table <- gtable_add_rows(plot_table, legend_height, pos = -1)
+    plot_table <- gtable_add_grob(plot_table, legend_box, clip = "off",
+      t = -1, b = -1, l = panel_dim$l, r = panel_dim$r, name = "guide-box")
+  } else if (position == "top") {
+    plot_table <- gtable_add_rows(plot_table, legend_height, pos = 0)
+    plot_table <- gtable_add_grob(plot_table, legend_box, clip = "off",
+      t = 1, b = 1, l = panel_dim$l, r = panel_dim$r, name = "guide-box")
+  } else if (position == "manual") {
+    # should guide box expand whole region or region without margin?
+    plot_table <- gtable_add_grob(plot_table, legend_box,
+      t = panel_dim$t, b = panel_dim$b, l = panel_dim$l, r = panel_dim$r,
+      clip = "off", name = "guide-box")
+  }
+
+  # Title
+  title <- element_render(theme, "plot.title", plot$labels$title, expand_y = TRUE)
+  title_height <- grobHeight(title)
+
+  pans <- plot_table$layout[grepl("^panel", plot_table$layout$name), ,
+    drop = FALSE]
+
+  plot_table <- gtable_add_rows(plot_table, title_height, pos = 0)
+  plot_table <- gtable_add_grob(plot_table, title, name = "title",
+    t = 1, b = 1, l = min(pans$l), r = max(pans$r), clip = "off")
+
+  # Margins
+  plot_table <- gtable_add_rows(plot_table, theme$plot.margin[1], pos = 0)
+  plot_table <- gtable_add_cols(plot_table, theme$plot.margin[2])
+  plot_table <- gtable_add_rows(plot_table, theme$plot.margin[3])
+  plot_table <- gtable_add_cols(plot_table, theme$plot.margin[4], pos = 0)
+
+  if (inherits(theme$plot.background, "element")) {
+    plot_table <- gtable_add_grob(plot_table,
+      element_render(theme, "plot.background"),
+      t = 1, l = 1, b = -1, r = -1, name = "background", z = -Inf)
+    plot_table$layout <- plot_table$layout[c(nrow(plot_table$layout), 1:(nrow(plot_table$layout) - 1)),]
+    plot_table$grobs <- plot_table$grobs[c(nrow(plot_table$layout), 1:(nrow(plot_table$layout) - 1))]
+  }
+  plot_table
+}
+
+#' Generate a ggplot2 plot grob.
+#'
+#' @param x ggplot2 object
+#' @keywords internal
+#' @export
+ggplotGrob <- function(x) {
+  ggplot_gtable(ggplot_build(x))
+}
diff --git a/R/plot-construction.r b/R/plot-construction.r
index cbbe477..af1015e 100644
--- a/R/plot-construction.r
+++ b/R/plot-construction.r
@@ -23,18 +23,22 @@
 #' For theme objects, the \code{+} operator and the \code{\%+replace\%}
 #' can be used to modify elements in themes.
 #'
-#' The \code{+} operator completely replaces elements
-#' with elements from e2.
+#' The \code{+} operator updates the elements of e1 that differ from
+#' elements specified (not NULL) in e2.
+#' Thus this operator can be used to incrementally add or modify attributes
+#' of a ggplot theme.
 #'
-#' In contrast, the \code{\%+replace\%} operator does not replace the
-#' entire element; it only updates element properties which are present
-#' (not NULL) in the second object.
+#' In contrast, the \code{\%+replace\%} operator replaces the
+#' entire element; any element of a theme not specified in e2 will not be
+#' present in the resulting theme (i.e. NULL).
+#' Thus this operator can be used to overwrite an entire theme.
 #'
 #' @examples
-#'
 #' ### Adding objects to a ggplot object
-#' p <- qplot(wt, mpg, colour = hp, data = mtcars)
+#' p <- ggplot(mtcars, aes(wt, mpg, colour = disp)) +
+#'   geom_point()
 #'
+#' p
 #' p + coord_cartesian(ylim = c(0, 40))
 #' p + scale_colour_continuous(breaks = c(100, 300))
 #' p + guides(colour = "colourbar")
@@ -43,7 +47,6 @@
 #' m <- mtcars[1:10, ]
 #' p %+% m
 #'
-#'
 #' ### Adding objects to a theme object
 #' # Compare these results of adding theme objects to other theme objects
 #' add_el <- theme_grey() + theme(text = element_text(family = "Times"))
@@ -54,9 +57,7 @@
 #'
 #' @param e1 An object of class \code{ggplot} or \code{theme}
 #' @param e2 A component to add to \code{e1}
-#'
 #' @export
-#'
 #' @seealso \code{\link{theme}}
 #' @method + gg
 #' @rdname gg-add
@@ -83,46 +84,36 @@ add_ggplot <- function(p, object, objectname) {
     p$data <- object
   } else if (is.theme(object)) {
     p$theme <- update_theme(p$theme, object)
-  } else if (inherits(object, "scale")) {
+  } else if (inherits(object, "Scale")) {
     p$scales$add(object)
-  } else if(inherits(object, "labels")) {
+  } else if (inherits(object, "labels")) {
     p <- update_labels(p, object)
-  } else if(inherits(object, "guides")) {
+  } else if (inherits(object, "guides")) {
     p <- update_guides(p, object)
-  } else if(inherits(object, "uneval")) {
+  } else if (inherits(object, "uneval")) {
       p$mapping <- defaults(object, p$mapping)
 
       labels <- lapply(object, deparse)
       names(labels) <- names(object)
       p <- update_labels(p, labels)
-  } else if (is.coord(object)) {
+  } else if (is.Coord(object)) {
       p$coordinates <- object
       p
   } else if (is.facet(object)) {
       p$facet <- object
       p
-  } else if(is.list(object)) {
+  } else if (is.list(object)) {
     for (o in object) {
       p <- p + o
     }
-  } else if(is.proto(object)) {
-    p <- switch(object$class(),
-      layer  = {
-        p$layers <- append(p$layers, object)
-
-        # Add any new labels
-        mapping <- make_labels(object$mapping)
-        default <- make_labels(object$stat$default_aes())
+  } else if (is.layer(object)) {
+    p$layers <- append(p$layers, object)
 
-        new_labels <- defaults(mapping, default)
-        p$labels <- defaults(p$labels, new_labels)
-        p
-      },
-      coord = {
-        p$coordinates <- object
-        p
-      }
-    )
+    # Add any new labels
+    mapping <- make_labels(object$mapping)
+    default <- make_labels(object$stat$default_aes)
+    new_labels <- defaults(mapping, default)
+    p$labels <- defaults(p$labels, new_labels)
   } else {
     stop("Don't know how to add ", objectname, " to a plot",
       call. = FALSE)
diff --git a/R/plot-render.r b/R/plot-render.r
deleted file mode 100644
index d976465..0000000
--- a/R/plot-render.r
+++ /dev/null
@@ -1,210 +0,0 @@
-#' Build a plot with all the usual bits and pieces.
-#'
-#' This function builds all grobs necessary for displaying the plot, and
-#' stores them in a special data structure called a \code{\link{gtable}}.
-#' This object is amenable to programmatic manipulation, should you want
-#' to (e.g.) make the legend box 2 cm wide, or combine multiple plots into
-#' a single display, preserving aspect ratios across the plots.
-#'
-#' @seealso \code{\link{print.ggplot}} and \code{link{benchplot}} for
-#'  for functions that contain the complete set of steps for generating
-#'  a ggplot2 plot.
-#' @return a \code{\link{gtable}} object
-#' @keywords internal
-#' @param plot plot object
-#' @param data plot data generated by \code{\link{ggplot_build}}
-#' @export
-ggplot_gtable <- function(data) {
-
-  plot <- data$plot
-  panel <- data$panel
-  data <- data$data
-  theme <- plot_theme(plot)
-
-  build_grob <- function(layer, layer_data) {
-    if (nrow(layer_data) == 0) return()
-
-    dlply(layer_data, "PANEL", function(df) {
-      panel_i <- match(df$PANEL[1], panel$layout$PANEL)
-      layer$make_grob(df, scales = panel$ranges[[panel_i]], cs = plot$coord)
-    }, .drop = FALSE)
-  }
-
-  # helper function return the position of panels in plot_table
-  find_panel <- function(table) {
-    layout <- table$layout
-    panels <- layout[grepl("^panel", layout$name), , drop = FALSE]
-
-    data.frame(
-      t = min(panels$t),
-      r = max(panels$r),
-      b = max(panels$b),
-      l = min(panels$l)
-    )
-  }
-
-  # List by layer, list by panel
-  geom_grobs <- Map(build_grob, plot$layer, data)
-
-  plot_table <- facet_render(plot$facet, panel, plot$coordinates,
-    plot_theme(plot), geom_grobs)
-
-  # Axis labels
-  labels <- coord_labels(plot$coordinates, list(
-    x = xlabel(panel, plot$labels),
-    y = ylabel(panel, plot$labels)
-  ))
-  xlabel <- element_render(theme, "axis.title.x", labels$x)
-  ylabel <- element_render(theme, "axis.title.y", labels$y)
-
-  panel_dim <-  find_panel(plot_table)
-
-  xlab_height <- grobHeight(xlabel) +
-    if (is.null(labels$x)) unit(0, "lines") else unit(0.5, "lines")
-  plot_table <- gtable_add_rows(plot_table, xlab_height)
-  plot_table <- gtable_add_grob(plot_table, xlabel, name = "xlab",
-    l = panel_dim$l, r = panel_dim$r, t = -1, clip = "off")
-
-  ylab_width <- grobWidth(ylabel) +
-    if (is.null(labels$y)) unit(0, "lines") else unit(0.5, "lines")
-  plot_table <- gtable_add_cols(plot_table, ylab_width, pos = 0)
-  plot_table <- gtable_add_grob(plot_table, ylabel, name = "ylab",
-    l = 1, b = panel_dim$b, t = panel_dim$t, clip = "off")
-
-  # Legends
-  position <- theme$legend.position
-  if (length(position) == 2) {
-    coords <- position
-    position <- "manual"
-  }
-
-  legend_box <- if (position != "none") {
-    build_guides(plot$scales, plot$layers, plot$mapping, position, theme, plot$guides, plot$labels)
-  } else {
-    zeroGrob()
-  }
-
-  if (is.zero(legend_box)) {
-    position <- "none"
-  } else {
-    # these are a bad hack, since it modifies the contents fo viewpoint directly...
-    legend_width  <- gtable_width(legend_box)  + theme$legend.margin
-    legend_height <- gtable_height(legend_box) + theme$legend.margin
-
-    # Set the justification of the legend box
-    # First value is xjust, second value is yjust
-    just <- valid.just(theme$legend.justification)
-    xjust <- just[1]
-    yjust <- just[2]
-
-    if (position == "manual") {
-      xpos <- theme$legend.position[1]
-      ypos <- theme$legend.position[2]
-
-      # x and y are specified via theme$legend.position (i.e., coords)
-      legend_box <- editGrob(legend_box,
-        vp = viewport(x = xpos, y = ypos, just = c(xjust, yjust),
-          height = legend_height, width = legend_width))
-    } else {
-      # x and y are adjusted using justification of legend box (i.e., theme$legend.justification)
-      legend_box <- editGrob(legend_box,
-        vp = viewport(x = xjust, y = yjust, just = c(xjust, yjust)))
-    }
-  }
-
-  panel_dim <-  find_panel(plot_table)
-  # for align-to-device, use this:
-  # panel_dim <-  summarise(plot_table$layout, t = min(t), r = max(r), b = max(b), l = min(l))
-
-  if (position == "left") {
-    plot_table <- gtable_add_cols(plot_table, legend_width, pos = 0)
-    plot_table <- gtable_add_grob(plot_table, legend_box, clip = "off",
-      t = panel_dim$t, b = panel_dim$b, l = 1, r = 1, name = "guide-box")
-  } else if (position == "right") {
-    plot_table <- gtable_add_cols(plot_table, legend_width, pos = -1)
-    plot_table <- gtable_add_grob(plot_table, legend_box, clip = "off",
-      t = panel_dim$t, b = panel_dim$b, l = -1, r = -1, name = "guide-box")
-  } else if (position == "bottom") {
-    plot_table <- gtable_add_rows(plot_table, legend_height, pos = -1)
-    plot_table <- gtable_add_grob(plot_table, legend_box, clip = "off",
-      t = -1, b = -1, l = panel_dim$l, r = panel_dim$r, name = "guide-box")
-  } else if (position == "top") {
-    plot_table <- gtable_add_rows(plot_table, legend_height, pos = 0)
-    plot_table <- gtable_add_grob(plot_table, legend_box, clip = "off",
-      t = 1, b = 1, l = panel_dim$l, r = panel_dim$r, name = "guide-box")
-  } else if (position == "manual") {
-    # should guide box expand whole region or region withoug margin?
-    plot_table <- gtable_add_grob(plot_table, legend_box,
-        t = panel_dim$t, b = panel_dim$b, l = panel_dim$l, r = panel_dim$r,
-        clip = "off", name = "guide-box")
-  }
-
-  # Title
-  title <- element_render(theme, "plot.title", plot$labels$title)
-  title_height <- grobHeight(title) +
-    if (is.null(plot$labels$title)) unit(0, "lines") else unit(0.5, "lines")
-
-  pans <- plot_table$layout[grepl("^panel", plot_table$layout$name), ,
-    drop = FALSE]
-
-  plot_table <- gtable_add_rows(plot_table, title_height, pos = 0)
-  plot_table <- gtable_add_grob(plot_table, title, name = "title",
-    t = 1, b = 1, l = min(pans$l), r = max(pans$r), clip = "off")
-
-  # Margins
-  plot_table <- gtable_add_rows(plot_table, theme$plot.margin[1], pos = 0)
-  plot_table <- gtable_add_cols(plot_table, theme$plot.margin[2])
-  plot_table <- gtable_add_rows(plot_table, theme$plot.margin[3])
-  plot_table <- gtable_add_cols(plot_table, theme$plot.margin[4], pos = 0)
-
-  if (inherits(theme$plot.background, "element")) {
-    plot_table <- gtable_add_grob(plot_table,
-      element_render(theme, "plot.background"),
-      t = 1, l = 1, b = -1, r = -1, name = "background", z = -Inf)
-    plot_table$layout <- plot_table$layout[c(nrow(plot_table$layout), 1:(nrow(plot_table$layout) - 1)),]
-    plot_table$grobs <- plot_table$grobs[c(nrow(plot_table$layout), 1:(nrow(plot_table$layout) - 1))]
-  }
-  plot_table
-}
-
-#' Draw plot on current graphics device.
-#'
-#' @param x plot to display
-#' @param newpage draw new (empty) page first?
-#' @param vp viewport to draw plot in
-#' @param ... other arguments not used by this method
-#' @keywords hplot
-#' @export
-#' @method print ggplot
-print.ggplot <- function(x, newpage = is.null(vp), vp = NULL, ...) {
-  set_last_plot(x)
-  if (newpage) grid.newpage()
-
-  data <- ggplot_build(x)
-
-  gtable <- ggplot_gtable(data)
-  if (is.null(vp)) {
-    grid.draw(gtable)
-  } else {
-    if (is.character(vp)) seekViewport(vp) else pushViewport(vp)
-    grid.draw(gtable)
-    upViewport()
-  }
-
-  invisible(data)
-}
-#' @rdname print.ggplot
-#' @method plot ggplot
-#' @export
-plot.ggplot <- print.ggplot
-
-
-#' Generate a ggplot2 plot grob.
-#'
-#' @param x ggplot2 object
-#' @keywords internal
-#' @export
-ggplotGrob <- function(x) {
-  ggplot_gtable(ggplot_build(x))
-}
-
diff --git a/R/plot.r b/R/plot.r
index 808f036..3a066ca 100644
--- a/R/plot.r
+++ b/R/plot.r
@@ -1,4 +1,4 @@
-#' Create a new ggplot plot
+#' Create a new ggplot plot.
 #'
 #' \code{ggplot()} initializes a ggplot object. It can be used to
 #' declare the input data frame for a graphic and to specify the
@@ -31,21 +31,21 @@
 #' multiple data frames are used to produce different layers, as
 #' is often the case in complex graphics.
 #'
-#' The examples below illustrate how these methods of
-#' invoking \code{ggplot} can be used in constructing a
-#' graphic.
-#' @seealso \url{http://had.co.nz/ggplot2}
+#' @param data Default dataset to use for plot. If not already a data.frame,
+#'   will be converted to one by \code{\link{fortify}}. If not specified,
+#'   must be suppled in each layer added to the plot.
+#' @param mapping Default list of aesthetic mappings to use for plot.
+#'   If not specified, must be suppled in each layer added to the plot.
+#' @param ... Other arguments passed on to methods. Not currently used.
+#' @param environment If an variable defined in the aesthetic mapping is not
+#'   found in the data, ggplot will look for it in this environment. It defaults
+#'   to using the environment in which \code{ggplot()} is called.
 #' @export
-#' @keywords internal
-#' @param data default data set
-#' @param ... other arguments passed to specific methods
 #' @examples
-#
 #' df <- data.frame(gp = factor(rep(letters[1:3], each = 10)),
 #'                  y = rnorm(30))
 #' # Compute sample mean and standard deviation in each group
-#' library(plyr)
-#' ds <- ddply(df, .(gp), summarise, mean = mean(y), sd = sd(y))
+#' ds <- plyr::ddply(df, "gp", plyr::summarise, mean = mean(y), sd = sd(y))
 #'
 #' # Declare the data frame and common aesthetics.
 #' # The summary data frame ds is used to plot
@@ -71,35 +71,32 @@
 #'   geom_errorbar(data = ds, aes(x = gp, y = mean,
 #'                     ymin = mean - sd, ymax = mean + sd),
 #'                     colour = 'red', width = 0.4)
-ggplot <- function(data = NULL, ...) UseMethod("ggplot")
-
-#' @export
-ggplot.default <- function(data = NULL, mapping = aes(), ...) {
-  ggplot.data.frame(fortify(data, ...), mapping)
+ggplot <- function(data = NULL, mapping = aes(), ...,
+                   environment = parent.frame()) {
+  UseMethod("ggplot")
 }
 
-#' Reports whether x is a ggplot object
-#' @param x An object to test
 #' @export
-is.ggplot <- function(x) inherits(x, "ggplot")
+#' @rdname ggplot
+#' @usage NULL
+ggplot.default <- function(data = NULL, mapping = aes(), ...,
+                           environment = parent.frame()) {
+  ggplot.data.frame(fortify(data, ...), mapping, environment = environment)
+}
 
-#' Create a new ggplot plot from a data frame
-#'
-#' @param data default data frame for plot
-#' @param mapping default list of aesthetic mappings (these can be colour,
-#'   size, shape, line type -- see individual geom functions for more details)
-#' @param ... ignored
-#' @param environment in which evaluation of aesthetics should occur
-#' @seealso \url{http://had.co.nz/ggplot2}
-#' @method ggplot data.frame
 #' @export
-ggplot.data.frame <- function(data, mapping=aes(), ..., environment = globalenv()) {
-  if (!missing(mapping) && !inherits(mapping, "uneval")) stop("Mapping should be created with aes or aes_string")
+#' @rdname ggplot
+#' @usage NULL
+ggplot.data.frame <- function(data, mapping = aes(), ...,
+                              environment = parent.frame()) {
+  if (!missing(mapping) && !inherits(mapping, "uneval")) {
+    stop("Mapping should be created with aes or aes_string")
+  }
 
   p <- structure(list(
     data = data,
     layers = list(),
-    scales = Scales$new(),
+    scales = scales_list(),
     mapping = mapping,
     theme = list(),
     coordinates = coord_cartesian(),
@@ -116,7 +113,54 @@ ggplot.data.frame <- function(data, mapping=aes(), ..., environment = globalenv(
 plot_clone <- function(plot) {
   p <- plot
   p$scales <- plot$scales$clone()
-  p$layers <- lapply(plot$layers, function(x) x$clone())
 
   p
 }
+
+#' Reports whether x is a ggplot object
+#' @param x An object to test
+#' @keywords internal
+#' @export
+is.ggplot <- function(x) inherits(x, "ggplot")
+
+#' Draw plot on current graphics device.
+#'
+#' @param x plot to display
+#' @param newpage draw new (empty) page first?
+#' @param vp viewport to draw plot in
+#' @param ... other arguments not used by this method
+#' @keywords hplot
+#' @return Invisibly returns the result of \code{\link{ggplot_build}}, which
+#'   is a list with components that contain the plot itself, the data,
+#'   information about the scales, panels etc.
+#' @export
+#' @method print ggplot
+print.ggplot <- function(x, newpage = is.null(vp), vp = NULL, ...) {
+  set_last_plot(x)
+  if (newpage) grid.newpage()
+
+  # Record dependency on 'ggplot2' on the display list
+  # (AFTER grid.newpage())
+  grDevices::recordGraphics(
+    requireNamespace("ggplot2", quietly = TRUE),
+    list(),
+    getNamespace("ggplot2")
+  )
+
+  data <- ggplot_build(x)
+
+  gtable <- ggplot_gtable(data)
+  if (is.null(vp)) {
+    grid.draw(gtable)
+  } else {
+    if (is.character(vp)) seekViewport(vp) else pushViewport(vp)
+    grid.draw(gtable)
+    upViewport()
+  }
+
+  invisible(data)
+}
+#' @rdname print.ggplot
+#' @method plot ggplot
+#' @export
+plot.ggplot <- print.ggplot
diff --git a/R/position-.r b/R/position-.r
index dbd1351..253b796 100644
--- a/R/position-.r
+++ b/R/position-.r
@@ -1,35 +1,83 @@
-# Position adjustment occurs over all groups within a geom
-# They work only with discrete x scales and may affect x and y position.
-# Should occur after statistics and scales have been applied.
-Position <- proto(TopLevel, expr = {
-  adjust <- function(., data, scales, ...) data
-
-  class <- function(.) "position"
-
-  width <- NULL
-  height <- NULL
-  new <- function(., width = NULL, height = NULL) {
-    .$proto(width = width, height = height)
-  }
+#' @section Positions:
+#'
+#' All \code{position_*} functions (like \code{position_dodge}) return a
+#' \code{Position*} object (like \code{PositionDodge}). The \code{Position*}
+#' object is responsible for adjusting the position of overlapping geoms.
+#'
+#' The way that the \code{position_*} functions work is slightly different from
+#' the \code{geom_*} and \code{stat_*} functions, because a \code{position_*}
+#' function actually "instantiates" the \code{Position*} object by creating a
+#' descendant, and returns that.
+#'
+#' Each of the \code{Position*} objects is a \code{\link{ggproto}} object,
+#' descended from the top-level \code{Position}, and each implements the
+#' following methods:
+#'
+#' \itemize{
+#'   \item \code{compute_layer(self, data, params, panel)} is called once
+#'     per layer. \code{panel} is currently an internal data structure, so
+#'     this method should not be overriden.
+#'
+#'   \item \code{compute_panel(self, data, params, panel)} is called once per
+#'     panel and should return a modified data frame.
+#'
+#'     \code{data} is a data frame containing the variables named according
+#'     to the aesthetics that they're mapped to. \code{scales} is a list
+#'     containing the \code{x} and \code{y} scales. There functions are called
+#'     before the facets are trained, so they are global scales, not local
+#'     to the individual panels. \code{params} contains the parameters returned by
+#'     \code{setup_params()}.
+#'   \item \code{setup_params(data, params)}: called once for each layer.
+#'      Used to setup defaults that need to complete dataset, and to inform
+#'      the user of important choices. Should return list of parameters.
+#'   \item \code{setup_data(data, params)}: called once for each layer,
+#'      after \code{setp_params()}. Should return modified \code{data}.
+#'      Default checks that required aesthetics are present.
+#' }
+#'
+#' And the following fields
+#' \itemize{
+#'   \item \code{required_aes}: a character vector giving the aesthetics
+#'      that must be present for this position adjustment to work.
+#' }
+#'
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+Position <- ggproto("Position",
+  required_aes = character(),
 
-  parameters <- function(.) {
-    pnames <- setdiff(names(formals(get("new", .))), ".")
-    values <- lapply(pnames, get, envir = .)
-    names(values) <- pnames
+  setup_params = function(self, data) {
+    list()
+  },
 
-    values
-  }
+  setup_data = function(self, data, params) {
+    check_required_aesthetics(self$required_aes, names(data), snake_class(self))
+    data
+  },
 
-  pprint <- function(., newline=TRUE) {
-    cat("position_", .$objname, ": (", clist(.$parameters()), ")", sep="")
-    if (newline) cat("\n")
-  }
+  compute_layer = function(self, data, params, panel) {
+    plyr::ddply(data, "PANEL", function(data) {
+      if (empty(data)) return(data.frame())
 
-})
+      scales <- panel_scales(panel, data$PANEL[1])
+      self$compute_panel(data = data, params = params, scales = scales)
+    })
+  },
 
+  compute_panel = function(self, data, params, scales) {
+    stop("Not implemented", call. = FALSE)
+  }
+)
 
-# Convenience function to ensure that all position variables
-# (x, xmin, xmax, xend) are transformed in the same way
+#' Convenience function to transform all position variables.
+#'
+#' @param trans_x,trans_y Transformation functions for x and y aesthetics.
+#'   (will transform x, xmin, xmax, xend etc)
+#' @param ... Additional arguments passed to \code{trans_x} and \code{trans_y}.
+#' @keywords internal
+#' @export
 transform_position <- function(df, trans_x = NULL, trans_y = NULL, ...) {
   scales <- aes_to_scale(names(df))
 
diff --git a/R/position-collide.r b/R/position-collide.r
index a4628b6..5516886 100644
--- a/R/position-collide.r
+++ b/R/position-collide.r
@@ -6,7 +6,7 @@ collide <- function(data, width = NULL, name, strategy, check.width = TRUE) {
     # Width set manually
     if (!(all(c("xmin", "xmax") %in% names(data)))) {
       data$xmin <- data$x - width / 2
-      data$xmax <- data$x - width / 2
+      data$xmax <- data$x + width / 2
     }
   } else {
     if (!(all(c("xmin", "xmax") %in% names(data)))) {
@@ -17,10 +17,12 @@ collide <- function(data, width = NULL, name, strategy, check.width = TRUE) {
     # Width determined from data, must be floating point constant
     widths <- unique(data$xmax - data$xmin)
     widths <- widths[!is.na(widths)]
-    if (!zero_range(range(widths))) {
-      warning(name, " requires constant width: output may be incorrect",
-        call. = FALSE)
-    }
+
+#   # Suppress warning message since it's not reliable
+#     if (!zero_range(range(widths))) {
+#       warning(name, " requires constant width: output may be incorrect",
+#         call. = FALSE)
+#     }
     width <- widths[1]
   }
 
@@ -39,12 +41,10 @@ collide <- function(data, width = NULL, name, strategy, check.width = TRUE) {
   }
 
   if (!is.null(data$ymax)) {
-    ddply(data, "xmin", strategy, width = width)
+    plyr::ddply(data, "xmin", strategy, width = width)
   } else if (!is.null(data$y)) {
-    message("ymax not defined: adjusting position using y instead")
-
     data$ymax <- data$y
-    data <- ddply(data, "xmin", strategy, width = width)
+    data <- plyr::ddply(data, "xmin", strategy, width = width)
     data$y <- data$ymax
     data
   } else {
@@ -58,28 +58,27 @@ pos_stack <- function(df, width) {
   if (nrow(df) == 1) return(df)
 
   n <- nrow(df) + 1
-  y <- with(df, ifelse(is.na(y), 0, y))
+  y <- ifelse(is.na(df$y), 0, df$y)
   if (all(is.na(df$x))) {
     heights <- rep(NA, n)
   } else {
     heights <- c(0, cumsum(y))
   }
 
-  within(df, {
-    ymin <- heights[-n]
-    ymax <- heights[-1]
-    y <- ymax
-  })
+  df$ymin <- heights[-n]
+  df$ymax <- heights[-1]
+  df$y <- df$ymax
+  df
 }
 
 # Stack overlapping intervals and set height to 1.
 # Assumes that each set has the same horizontal position.
 pos_fill <- function(df, width) {
-  within(pos_stack(df, width), {
-    ymin <- ymin / max(ymax)
-    ymax <- ymax / max(ymax)
-    y <- ymax
-  })
+  stacked <- pos_stack(df, width)
+  stacked$ymin <- stacked$ymin / max(stacked$ymax)
+  stacked$ymax <- stacked$ymax / max(stacked$ymax)
+  stacked$y <- stacked$ymax
+  stacked
 }
 
 # Dodge overlapping interval.
@@ -94,10 +93,9 @@ pos_dodge <- function(df, width) {
   }
 
   d_width <- max(df$xmax - df$xmin)
-  diff <- width - d_width
 
   # df <- data.frame(n = c(2:5, 10, 26), div = c(4, 3, 2.666666,  2.5, 2.2, 2.1))
-  # qplot(n, div, data = df)
+  # ggplot(df, aes(n, div)) + geom_point()
 
   # Have a new group index from 1 to number of groups.
   # This might be needed if the group numbers in this set don't include all of 1:n
diff --git a/R/position-dodge.r b/R/position-dodge.r
index 3241c6f..9682f10 100644
--- a/R/position-dodge.r
+++ b/R/position-dodge.r
@@ -1,44 +1,60 @@
 #' Adjust position by dodging overlaps to the side.
 #'
 #' @inheritParams position_identity
+#' @param width Dodging width, when different to the width of the individual
+#'   elements. This is useful when you want to align narrow geoms with wider
+#'   geoms. See the examples for a use case.
 #' @family position adjustments
 #' @export
 #' @examples
+#' ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) +
+#'   geom_bar(position = "dodge")
 #' \donttest{
-#' ggplot(mtcars, aes(x=factor(cyl), fill=factor(vs))) +
-#'   geom_bar(position="dodge")
-#' ggplot(diamonds, aes(x=price, fill=cut)) + geom_bar(position="dodge")
+#' ggplot(diamonds, aes(price, fill = cut)) +
+#'   geom_histogram(position="dodge")
 #' # see ?geom_boxplot and ?geom_bar for more examples
 #'
-#' # Dodging things with different widths is tricky
-#' df <- data.frame(x=c("a","a","b","b"), y=1:4, g = rep(1:2, 2))
-#' (p <- qplot(x, y, data=df, group=g, position="dodge", geom="bar",
-#'   stat="identity"))
+#' # To dodge items with different widths, you need to be explicit
+#' df <- data.frame(x=c("a","a","b","b"), y=2:5, g = rep(1:2, 2))
+#' p <- ggplot(df, aes(x, y, group = g)) +
+#'   geom_bar(
+#'     stat = "identity", position = "dodge",
+#'     fill = "grey50", colour = "black"
+#'   )
+#' p
 #'
-#' p + geom_linerange(aes(ymin = y-1, ymax = y+1), position="dodge")
+#' # A line range has no width:
+#' p + geom_linerange(aes(ymin = y-1, ymax = y+1), position = "dodge")
 #' # You need to explicitly specify the width for dodging
 #' p + geom_linerange(aes(ymin = y-1, ymax = y+1),
 #'   position = position_dodge(width = 0.9))
 #'
 #' # Similarly with error bars:
 #' p + geom_errorbar(aes(ymin = y-1, ymax = y+1), width = 0.2,
-#'   position="dodge")
+#'   position = "dodge")
 #' p + geom_errorbar(aes(ymin = y-1, ymax = y+1, width = 0.2),
 #'   position = position_dodge(width = 0.90))
 #' }
-position_dodge <- function (width = NULL, height = NULL) {
-  PositionDodge$new(width = width, height = height)
+position_dodge <- function(width = NULL) {
+  ggproto(NULL, PositionDodge, width = width)
 }
 
-PositionDodge <- proto(Position, {
-  objname <- "dodge"
-
-  adjust <- function(., data) {
-    if (empty(data)) return(data.frame())
-    check_required_aesthetics("x", names(data), "position_dodge")
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+PositionDodge <- ggproto("PositionDodge", Position,
+  required_aes = "x",
+  width = NULL,
+  setup_params = function(self, data) {
+    if (is.null(data$xmin) && is.null(data$xmax) && is.null(self$width)) {
+      warning("Width not defined. Set with `position_dodge(width = ?)`",
+        call. = FALSE)
+    }
+    list(width = self$width)
+  },
 
-    collide(data, .$width, .$my_name(), pos_dodge, check.width = FALSE)
+  compute_panel = function(data, params, scales) {
+    collide(data, params$width, "position_dodge", pos_dodge, check.width = FALSE)
   }
-
-})
-
+)
diff --git a/R/position-fill.r b/R/position-fill.r
index d6e7edd..1d6b66a 100644
--- a/R/position-fill.r
+++ b/R/position-fill.r
@@ -1,37 +1,24 @@
-#' Stack overlapping objects on top of one another, and standardise to have
-#' equal height.
-#'
-#' @inheritParams position_identity
-#' @family position adjustments
-#' @seealso See \code{\link{geom_bar}} and \code{\link{geom_area}} for
-#'   more examples.
 #' @export
-#' @examples
-#' \donttest{
-#' # See ?geom_bar and ?geom_area for more examples
-#' ggplot(mtcars, aes(x=factor(cyl), fill=factor(vs))) +
-#'   geom_bar(position="fill")
-#'
-#' cde <- geom_histogram(position="fill", binwidth = 500)
-#'
-#' ggplot(diamonds, aes(x=price)) + cde
-#' ggplot(diamonds, aes(x=price, fill=cut)) + cde
-#' ggplot(diamonds, aes(x=price, fill=clarity)) + cde
-#' ggplot(diamonds, aes(x=price, fill=color)) + cde
-#' }
-position_fill <- function (width = NULL, height = NULL) {
-  PositionFill$new(width = width, height = height)
+#' @rdname position_stack
+position_fill <- function() {
+  PositionFill
 }
 
-PositionFill <- proto(Position, {
-  objname <- "fill"
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+PositionFill <- ggproto("PositionFill", Position,
+  required_aes = c("x", "ymax"),
 
-  adjust <- function(., data) {
-    if (empty(data)) return(data.frame())
+  setup_data = function(self, data, params) {
+    if (!is.null(data$ymin) && !all(data$ymin == 0))
+      warning("Filling not well defined when ymin != 0", call. = FALSE)
 
-    check_required_aesthetics(c("x", "ymax"), names(data), "position_fill")
-    if (!all(data$ymin == 0)) warning("Filling not well defined when ymin != 0")
-    collide(data, .$width, .$my_name(), pos_fill)
-  }
+    ggproto_parent(Position, self)$setup_data(data)
+  },
 
-})
+  compute_panel = function(data, params, scales) {
+    collide(data, NULL, "position_fill", pos_fill)
+  }
+)
diff --git a/R/position-identity.r b/R/position-identity.r
index 7305f27..956efd1 100644
--- a/R/position-identity.r
+++ b/R/position-identity.r
@@ -1,15 +1,17 @@
 #' Don't adjust position
 #'
-#' @param width Manually specify width (does not affect all position
-#'   adjustments)
-#' @param height Manually specify height (does not affect all position
-#'   adjustments)
 #' @family position adjustments
 #' @export
-position_identity <- function (width = NULL, height = NULL) {
-  PositionIdentity$new(width = width, height = height)
+position_identity <- function() {
+  PositionIdentity
 }
 
-PositionIdentity <- proto(Position, {
-  objname <- "identity"
-})
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+PositionIdentity <- ggproto("PositionIdentity", Position,
+  compute_layer = function(data, params, scales) {
+    data
+  }
+)
diff --git a/R/position-jitter.r b/R/position-jitter.r
index 338d07b..1a5bc2c 100644
--- a/R/position-jitter.r
+++ b/R/position-jitter.r
@@ -1,51 +1,58 @@
 #' Jitter points to avoid overplotting.
 #'
 #' @family position adjustments
-#' @param width degree of jitter in x direction. Defaults to 40\% of the
-#'   resolution of the data.
-#' @param height degree of jitter in y direction. Defaults to 40\% of the
-#'   resolution of the data
+#' @param width,height Amount of vertical and horizontal jitter. The jitter
+#'   is added in both positive and negative directions, so the total spread
+#'   is twice the value specified here.
+#'
+#'   If omitted, defaults to 40\% of the resolution of the data: this means the
+#'   jitter values will occupy 80\% of the implied bins. Categorical data
+#'   is aligned on the integers, so a width or height of 0.5 will spread the
+#'   data so it's not possible to see the distinction between the categories.
 #' @export
 #' @examples
-#' qplot(am, vs, data = mtcars)
+#' ggplot(mtcars, aes(am, vs)) + geom_point()
 #'
 #' # Default amount of jittering will generally be too much for
 #' # small datasets:
-#' qplot(am, vs, data = mtcars, position = "jitter")
-#' # Control the amount as follows
-#' qplot(am, vs, data = mtcars, position = position_jitter(w = 0.1, h = 0.1))
+#' ggplot(mtcars, aes(am, vs)) + geom_jitter()
 #'
-#' # With ggplot
-#' ggplot(mtcars, aes(x = am, y = vs)) + geom_point(position = "jitter")
-#' ggplot(mtcars, aes(x = am, y = vs)) + geom_point(position = position_jitter(w = 0.1, h = 0.1))
+#' # Two ways to override
+#' ggplot(mtcars, aes(am, vs)) +
+#'   geom_jitter(width = 0.1, height = 0.1)
+#' ggplot(mtcars, aes(am, vs)) +
+#'   geom_jitter(position = position_jitter(width = 0.1, height = 0.1))
 #'
 #' # The default works better for large datasets, where it will
 #' # take up as much space as a boxplot or a bar
-#' qplot(class, hwy, data = mpg, geom = c("boxplot", "jitter"))
-position_jitter <- function (width = NULL, height = NULL) {
-  PositionJitter$new(width = width, height = height)
+#' ggplot(mpg, aes(class, hwy)) +
+#'   geom_jitter() +
+#'   geom_boxplot()
+position_jitter <- function(width = NULL, height = NULL) {
+  ggproto(NULL, PositionJitter,
+    width = width,
+    height = height
+  )
 }
 
-PositionJitter <- proto(Position, {
-  objname <- "jitter"
-
-  adjust <- function(., data) {
-    if (empty(data)) return(data.frame())
-    check_required_aesthetics(c("x", "y"), names(data), "position_jitter")
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+PositionJitter <- ggproto("PositionJitter", Position,
+  required_aes = c("x", "y"),
 
-    if (is.null(.$width)) .$width <- resolution(data$x, zero = FALSE) * 0.4
-    if (is.null(.$height)) .$height <- resolution(data$y, zero = FALSE) * 0.4
+  setup_params = function(self, data) {
+    list(
+      width = self$width %||% resolution(data$x, zero = FALSE) * 0.4,
+      height = self$height %||% resolution(data$y, zero = FALSE) * 0.4
+    )
+  },
 
-    trans_x <- NULL
-    trans_y <- NULL
-    if(.$width > 0) {
-      trans_x <- function(x) jitter(x, amount = .$width)
-    }
-    if(.$height > 0) {
-      trans_y <- function(x) jitter(x, amount = .$height)
-    }
+  compute_layer = function(data, params, panel) {
+    trans_x <- if (params$width > 0) function(x) jitter(x, amount = params$width)
+    trans_y <- if (params$height > 0) function(x) jitter(x, amount = params$height)
 
     transform_position(data, trans_x, trans_y)
   }
-
-})
+)
diff --git a/R/position-jitterdodge.R b/R/position-jitterdodge.R
index 903062d..b65be70 100644
--- a/R/position-jitterdodge.R
+++ b/R/position-jitterdodge.R
@@ -16,72 +16,48 @@
 #' ggplot(dsub, aes(x = cut, y = carat, fill = clarity)) +
 #'   geom_boxplot(outlier.size = 0) +
 #'   geom_point(pch = 21, position = position_jitterdodge())
-position_jitterdodge <- function (jitter.width = NULL,
-                                  jitter.height = NULL,
-                                  dodge.width = NULL) {
-
-  PositionJitterDodge$new(jitter.width = jitter.width,
-                          jitter.height = jitter.height,
-                          dodge.width = dodge.width)
+position_jitterdodge <- function(jitter.width = NULL, jitter.height = 0,
+                                 dodge.width = 0.75) {
+
+  ggproto(NULL, PositionJitterdodge,
+    jitter.width = jitter.width,
+    jitter.height = jitter.height,
+    dodge.width = dodge.width
+  )
 }
 
-PositionJitterDodge <- proto(Position, {
-
-  jitter.width <- NULL
-  jitter.height <- NULL
-  dodge.width <- NULL
-
-  new <- function(.,
-                  jitter.width = NULL,
-                  jitter.height = NULL,
-                  dodge.width = NULL) {
-
-    .$proto(jitter.width=jitter.width,
-            jitter.height=jitter.height,
-            dodge.width=dodge.width)
-
-  }
-
-  objname <- "jitterdodge"
-
-  adjust <- function(., data) {
-
-    if (empty(data)) return(data.frame())
-    check_required_aesthetics(c("x", "y", "fill"), names(data), "position_jitterdodge")
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+PositionJitterdodge <- ggproto("PositionJitterdodge", Position,
+  jitter.width = NULL,
+  jitter.height = NULL,
+  dodge.width = NULL,
 
-    ## Workaround to avoid this warning:
-    ## ymax not defined: adjusting position using y instead
-    if (!("ymax" %in% names(data))) {
-      data$ymax <- data$y
-    }
+  required_aes = c("x", "y", "fill"),
 
-    ## Adjust the x transformation based on the number of 'fill' variables
+  setup_params = function(self, data) {
+    width <- self$jitter.width %||% resolution(data$x, zero = FALSE) * 0.4
+    # Adjust the x transformation based on the number of 'fill' variables
     nfill <- length(levels(data$fill))
 
-    if (is.null(.$jitter.width)) {
-      .$jitter.width <- resolution(data$x, zero = FALSE) * 0.4
-    }
-
-    if (is.null(.$jitter.height)) {
-      .$jitter.height <- 0
-    }
+    list(
+      dodge.width = self$dodge.width,
+      jitter.height = self$jitter.height,
+      jitter.width = width / (nfill + 2)
+    )
+  },
 
-    trans_x <- NULL
-    trans_y <- NULL
-    if (.$jitter.width > 0) {
-      trans_x <- function(x) jitter(x, amount = .$jitter.width / (nfill + 2))
-    }
-    if (.$jitter.height > 0) {
-      trans_y <- function(x) jitter(x, amount = .$jitter.height)
-    }
 
-    if (is.null(.$dodge.width)) {
-      .$dodge.width <- 0.75
-    }
+  compute_panel = function(data, params, scales) {
+    data <- collide(data, params$dodge.width, "position_jitterdodge", pos_dodge,
+      check.width = FALSE)
 
-    ## dodge, then jitter
-    data <- collide(data, .$dodge.width, .$my_name(), pos_dodge, check.width = FALSE)
-    transform_position(data, trans_x, trans_y)
+    # then jitter
+    transform_position(data,
+      if (params$jitter.width > 0) function(x) jitter(x, amount = params$jitter.width),
+      if (params$jitter.height > 0) function(x) jitter(x, amount = params$jitter.height)
+    )
   }
-
-})
+)
diff --git a/R/position-nudge.R b/R/position-nudge.R
new file mode 100644
index 0000000..a77920c
--- /dev/null
+++ b/R/position-nudge.R
@@ -0,0 +1,46 @@
+#' Nudge points.
+#'
+#' This is useful if you want to nudge labels a little ways from their
+#' points.
+#'
+#' @family position adjustments
+#' @param x,y Amount of vertical and horizontal distance to move.
+#' @export
+#' @examples
+#' df <- data.frame(
+#'   x = c(1,3,2,5),
+#'   y = c("a","c","d","c")
+#' )
+#'
+#' ggplot(df, aes(x, y)) +
+#'   geom_point() +
+#'   geom_text(aes(label = y))
+#'
+#' ggplot(df, aes(x, y)) +
+#'   geom_point() +
+#'   geom_text(aes(label = y), position = position_nudge(y = -0.1))
+position_nudge <- function(x = 0, y = 0) {
+  ggproto(NULL, PositionNudge,
+    x = x,
+    y = y
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+PositionNudge <- ggproto("PositionNudge", Position,
+  x = NULL,
+  y = NULL,
+
+  required_aes = c("x", "y"),
+
+  setup_params = function(self, data) {
+    list(x = self$x, y = self$y)
+  },
+
+  compute_layer = function(data, params, panel) {
+    transform_position(data, function(x) x + params$x, function(y) y + params$y)
+  }
+)
diff --git a/R/position-stack.r b/R/position-stack.r
index 3404a87..4267928 100644
--- a/R/position-stack.r
+++ b/R/position-stack.r
@@ -1,18 +1,29 @@
 #' Stack overlapping objects on top of one another.
 #'
-#' @inheritParams position_identity
+#' \code{position_fill} additionally standardises each stack to have unit
+#' height.
+#'
 #' @family position adjustments
+#' @seealso See \code{\link{geom_bar}} and \code{\link{geom_area}} for
+#'   more examples.
 #' @export
 #' @examples
 #' # Stacking is the default behaviour for most area plots:
 #' ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) + geom_bar()
+#' # Fill makes it easier to compare proportions
+#' ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) +
+#'   geom_bar(position = "fill")
 #'
 #' # To change stacking order, use factor() to change order of levels
 #' mtcars$vs <- factor(mtcars$vs, levels = c(1,0))
 #' ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) + geom_bar()
 #'
-#' ggplot(diamonds, aes(price)) + geom_histogram(binwidth=500)
-#' ggplot(diamonds, aes(price, fill = cut)) + geom_histogram(binwidth=500)
+#' ggplot(diamonds, aes(price, fill = cut)) +
+#'   geom_histogram(binwidth = 500)
+#' # When used with a histogram, position_fill creates a conditional density
+#' # estimate
+#' ggplot(diamonds, aes(price, fill = cut)) +
+#'   geom_histogram(binwidth = 500, position = "fill")
 #'
 #' # Stacking is also useful for time series
 #' data.set <- data.frame(
@@ -21,24 +32,28 @@
 #'   Value = rpois(16, 10)
 #' )
 #'
-#' qplot(Time, Value, data = data.set, fill = Type, geom = "area")
+#' ggplot(data.set, aes(Time, Value)) + geom_area(aes(fill = Type))
+#'
 #' # If you want to stack lines, you need to say so:
-#' qplot(Time, Value, data = data.set, colour = Type, geom = "line")
-#' qplot(Time, Value, data = data.set, colour = Type, geom = "line",
-#'   position = "stack")
+#' ggplot(data.set, aes(Time, Value)) + geom_line(aes(colour = Type))
+#' ggplot(data.set, aes(Time, Value)) +
+#'   geom_line(position = "stack", aes(colour = Type))
+#'
 #' # But realise that this makes it *much* harder to compare individual
 #' # trends
-position_stack <- function (width = NULL, height = NULL) {
-  PositionStack$new(width = width, height = height)
+position_stack <- function() {
+  PositionStack
 }
 
-PositionStack <- proto(Position, {
-  objname <- "stack"
-
-  adjust <- function(., data) {
-    if (empty(data)) return(data.frame())
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+PositionStack <- ggproto("PositionStack", Position,
+  # requires one of c("ymax", "y"),
 
-    data <- remove_missing(data, FALSE,
+  setup_data = function(self, data, params) {
+    data = remove_missing(data, FALSE,
       c("x", "y", "ymin", "ymax", "xmin", "xmax"), name = "position_stack")
 
     if (is.null(data$ymax) && is.null(data$y)) {
@@ -50,7 +65,10 @@ PositionStack <- proto(Position, {
     if (!is.null(data$ymin) && !all(data$ymin == 0))
       warning("Stacking not well defined when ymin != 0", call. = FALSE)
 
-    collide(data, .$width, .$my_name(), pos_stack)
-  }
+    data
+  },
 
-})
+  compute_panel = function(data, params, scales) {
+    collide(data, NULL, "position_stack", pos_stack)
+  }
+)
diff --git a/R/quick-plot.r b/R/quick-plot.r
index b1fd2dc..2714f86 100644
--- a/R/quick-plot.r
+++ b/R/quick-plot.r
@@ -1,59 +1,38 @@
 #' Quick plot
 #'
 #' \code{qplot} is the basic plotting function in the ggplot2 package,
-#' designed to be familiar if you're used to \code{\link{plot}}
-#' from the base package. It is a convenient wrapper for creating
-#' a number of different types of plots using a consistent
-#' calling scheme. See \url{http://had.co.nz/ggplot2/book/qplot.pdf}
-#' for the chapter in the \code{ggplot2} book which describes the usage
-#' of \code{qplot} in detail.
+#' designed to be familiar if you're used to base \code{\link{plot}()}.
+#' It's a convenient wrapper for creating a number of different types of plots
+#' using a consistent calling scheme.
 #'
-#' @param x x values
-#' @param y y values
-#' @param ... other aesthetics passed for each layer
-#' @param data data frame to use (optional).  If not specified, will create
+#' @param x,y,... Aesthetics passed into each layer
+#' @param data Data frame to use (optional).  If not specified, will create
 #'   one, extracting vectors from the current environment.
-#' @param facets faceting formula to use.  Picks \code{\link{facet_wrap}} or
-#'   \code{\link{facet_grid}} depending on whether the formula is one sided
+#' @param facets faceting formula to use. Picks \code{\link{facet_wrap}} or
+#'   \code{\link{facet_grid}} depending on whether the formula is one-
 #'   or two-sided
-#' @param margins whether or not margins will be displayed
-#' @param geom character vector specifying geom to use.  Defaults to
+#' @param margins See \code{facet_grid}: display marginal facets?
+#' @param geom Character vector specifying geom(s) to draw. Defaults to
 #'  "point" if x and y are specified, and "histogram" if only x is specified.
-#' @param stat character vector specifying statistics to use
-#' @param position character vector giving position adjustment to use
-#' @param xlim limits for x axis
-#' @param ylim limits for y axis
-#' @param log which variables to log transform ("x", "y", or "xy")
-#' @param main character vector or expression for plot title
-#' @param xlab character vector or expression for x axis label
-#' @param ylab character vector or expression for y axis label
-#' @param asp the y/x aspect ratio
-#' @aliases qplot quickplot
-#' @export qplot quickplot
+#' @param stat,position DEPRECATED.
+#' @param xlim,ylim X and y axis limits
+#' @param log Which variables to log transform ("x", "y", or "xy")
+#' @param main,xlab,ylab Character vector (or expression) giving plot title,
+#'   x axis label, and y axis label respectively.
+#' @param asp The y/x aspect ratio
+#' @export
 #' @examples
-#' \donttest{
 #' # Use data from data.frame
-#' qplot(mpg, wt, data=mtcars)
-#' qplot(mpg, wt, data=mtcars, colour=cyl)
-#' qplot(mpg, wt, data=mtcars, size=cyl)
-#' qplot(mpg, wt, data=mtcars, facets=vs ~ am)
-#'
-#' # It will use data from local environment
-#' hp <- mtcars$hp
-#' wt <- mtcars$wt
-#' cyl <- mtcars$cyl
-#' vs <- mtcars$vs
-#' am <- mtcars$am
-#' qplot(hp, wt)
-#' qplot(hp, wt, colour=cyl)
-#' qplot(hp, wt, size=cyl)
-#' qplot(hp, wt, facets=vs ~ am)
+#' qplot(mpg, wt, data = mtcars)
+#' qplot(mpg, wt, data = mtcars, colour = cyl)
+#' qplot(mpg, wt, data = mtcars, size = cyl)
+#' qplot(mpg, wt, data = mtcars, facets = vs ~ am)
 #'
+#' \donttest{
 #' qplot(1:10, rnorm(10), colour = runif(10))
 #' qplot(1:10, letters[1:10])
 #' mod <- lm(mpg ~ wt, data=mtcars)
 #' qplot(resid(mod), fitted(mod))
-#' qplot(resid(mod), fitted(mod), facets = . ~ vs)
 #'
 #' f <- function() {
 #'    a <- 1:10
@@ -62,6 +41,9 @@
 #' }
 #' f()
 #'
+#' # To set aesthetics, wrap in I()
+#' qplot(mpg, wt, data = mtcars, colour = I("red"))
+#'
 #' # qplot will attempt to guess what geom you want depending on the input
 #' # both x and y supplied = scatterplot
 #' qplot(mpg, wt, data = mtcars)
@@ -71,14 +53,23 @@
 #' qplot(y = mpg, data = mtcars)
 #'
 #' # Use different geoms
-#' qplot(mpg, wt, data = mtcars, geom="path")
-#' qplot(factor(cyl), wt, data = mtcars, geom=c("boxplot", "jitter"))
+#' qplot(mpg, wt, data = mtcars, geom = "path")
+#' qplot(factor(cyl), wt, data = mtcars, geom = c("boxplot", "jitter"))
 #' qplot(mpg, data = mtcars, geom = "dotplot")
 #' }
-qplot <- function(x, y = NULL, ..., data, facets = NULL, margins=FALSE, geom = "auto", stat=list(NULL), position=list(NULL), xlim = c(NA, NA), ylim = c(NA, NA), log = "", main = NULL, xlab = deparse(substitute(x)), ylab = deparse(substitute(y)), asp = NA) {
+qplot <- function(x, y = NULL, ..., data, facets = NULL, margins=FALSE,
+                  geom = "auto", xlim = c(NA, NA),
+                  ylim = c(NA, NA), log = "", main = NULL,
+                  xlab = deparse(substitute(x)), ylab = deparse(substitute(y)),
+                  asp = NA, stat = NULL, position = NULL) {
+
+  if (!missing(stat)) warning("`stat` is deprecated", call. = FALSE)
+  if (!missing(position)) warning("`position` is deprecated", call. = FALSE)
+  if (!is.character(geom)) stop("`geom` must be a character vector", call. = FALSE)
 
-  argnames <- names(as.list(match.call(expand.dots=FALSE)[-1]))
+  argnames <- names(as.list(match.call(expand.dots = FALSE)[-1]))
   arguments <- as.list(match.call()[-1])
+  env <- parent.frame()
 
   aesthetics <- compact(arguments[.all_aesthetics])
   aesthetics <- aesthetics[!is.constant(aesthetics)]
@@ -94,18 +85,22 @@ qplot <- function(x, y = NULL, ..., data, facets = NULL, margins=FALSE, geom = "
     facetvars <- all.vars(facets)
     facetvars <- facetvars[facetvars != "."]
     names(facetvars) <- facetvars
-    facetsdf <- as.data.frame(lapply(facetvars, get))
+    facetsdf <- as.data.frame(mget(facetvars, envir = env))
     if (nrow(facetsdf)) data <- facetsdf
   }
 
   # Work out plot data, and modify aesthetics, if necessary
   if ("auto" %in% geom) {
-    if (stat == "qq" || "sample" %in% aes_names) {
-      geom[geom == "auto"] <- "point"
-      stat <- "qq"
+    if ("sample" %in% aes_names) {
+      geom[geom == "auto"] <- "qq"
     } else if (missing(y)) {
-      geom[geom == "auto"] <- "histogram"
-      if (is.null(ylab)) ylab <- "count"
+      x <- eval(aesthetics$x, data, env)
+      if (is.discrete(x)) {
+        geom[geom == "auto"] <- "bar"
+      } else {
+        geom[geom == "auto"] <- "histogram"
+      }
+      if (missing(ylab)) ylab <- "count"
     } else {
       if (missing(x)) {
         aesthetics$x <- bquote(seq_along(.(y)), aesthetics)
@@ -114,7 +109,6 @@ qplot <- function(x, y = NULL, ..., data, facets = NULL, margins=FALSE, geom = "
     }
   }
 
-  env <- parent.frame()
   p <- ggplot(data, aesthetics, environment = env)
 
   if (is.null(facets)) {
@@ -128,20 +122,15 @@ qplot <- function(x, y = NULL, ..., data, facets = NULL, margins=FALSE, geom = "
   if (!is.null(main)) p <- p + ggtitle(main)
 
   # Add geoms/statistics
-  if (is.proto(position)) position <- list(position)
-
-  mapply(function(g, s, ps) {
-    if(is.character(g)) g <- Geom$find(g)
-    if(is.character(s)) s <- Stat$find(s)
-    if(is.character(ps)) ps <- Position$find(ps)
-
-    # Have to use non-standard evaluation because we can't evaluate ...
+  for (g in geom) {
+    # Arguments are unevaluated because some are aesthetics. Need to evaluate
+    # params - can't do in correct env because that's lost (no lazyeval)
+    # so do the best we can by evaluating in parent frame.
     params <- arguments[setdiff(names(arguments), c(aes_names, argnames))]
-    # 1: mapply, 2: qplot, 3: caller of qplot
-    params <- lapply(params, eval, parent.frame(3))
+    params <- lapply(params, eval, parent.frame())
 
-    p <<- p + layer(geom=g, stat=s, geom_params=params, stat_params=params, position=ps)
-  }, geom, stat, position)
+    p <- p + do.call(paste0("geom_", g), params)
+  }
 
   logv <- function(var) var %in% strsplit(log, "")[[1]]
 
@@ -158,9 +147,12 @@ qplot <- function(x, y = NULL, ..., data, facets = NULL, margins=FALSE, geom = "
 
   p
 }
+
+#' @export
+#' @rdname qplot
 quickplot <- qplot
 
-# is.constant
 is.constant <- function(x) {
-  sapply(x, function(x) "I" %in% all.names(asOneSidedFormula(x)))
+  is_I_call <- function(x) is.call(x) && identical(x[[1]], quote(I))
+  vapply(x, is_I_call, logical(1))
 }
diff --git a/R/range.r b/R/range.r
new file mode 100644
index 0000000..5d363ad
--- /dev/null
+++ b/R/range.r
@@ -0,0 +1,33 @@
+#' Mutable ranges have a two methods (\code{train} and \code{reset}), and make
+#' it possible to build up complete ranges with multiple passes.
+#'
+#' These range objects should be instantiated with
+#' \code{\link{continuous_range}} and \code{\link{discrete_range}}.
+#'
+#' @noRd
+Range <- ggproto("Range", NULL,
+  range = NULL,
+  reset = function(self) {
+    self$range <- NULL
+  }
+)
+
+RangeDiscrete <- ggproto("RangeDiscrete", Range,
+  train = function(self, x, drop = FALSE) {
+    self$range <- scales::train_discrete(x, self$range, drop)
+  }
+)
+
+RangeContinuous <- ggproto("RangeContinuous", Range,
+  train = function(self, x) {
+    self$range <- scales::train_continuous(x, self$range)
+  }
+)
+
+continuous_range <- function() {
+  ggproto(NULL, RangeContinuous)
+}
+
+discrete_range <- function() {
+  ggproto(NULL, RangeDiscrete)
+}
diff --git a/R/save.r b/R/save.r
index 0e95ba1..70adca2 100644
--- a/R/save.r
+++ b/R/save.r
@@ -1,125 +1,135 @@
-#' Save a ggplot with sensible defaults
+#' Save a ggplot (or other grid object) with sensible defaults
 #'
-#' ggsave is a convenient function for saving a plot.  It defaults to
-#' saving the last plot that you displayed, and for a default size uses
-#' the size of the current graphics device.  It also guesses the type of
-#' graphics device from the extension.  This means the only argument you
-#' need to supply is the filename.
+#' \code{ggsave()} is a convenient function for saving a plot. It defaults to
+#' saving the last plot that you displayed, using the size of the current
+#' graphics device. It also guesses the type of graphics device from the
+#' extension.
 #'
-#' \code{ggsave} currently recognises the extensions eps/ps, tex (pictex),
-#' pdf, jpeg, tiff, png, bmp, svg and wmf (windows only).
-#'
-#' @param filename file name/filename of plot
-#' @param plot plot to save, defaults to last plot displayed
-#' @param device device to use, automatically extract from file name extension
-#' @param path path to save plot to (if you just want to set path and not
-#'    filename)
-#' @param scale scaling factor
-#' @param width width (defaults to the width of current plotting window)
-#' @param height height (defaults to the height of current plotting window)
-#' @param units units for width and height when either one is explicitly specified (in, cm, or mm)
-#' @param dpi dpi to use for raster graphics
-#' @param limitsize when \code{TRUE} (the default), \code{ggsave} will not
+#' @param filename File name to create on disk.
+#' @param plot Plot to save, defaults to last plot displayed.
+#' @param device Device to use (function or any of the recognized extensions,
+#'   e.g. \code{"pdf"}). By default, extracted from filename extension.
+#'   \code{ggsave} currently recognises eps/ps, tex (pictex), pdf, jpeg, tiff,
+#'   png, bmp, svg and wmf (windows only).
+#' @param path Path to save plot to (combined with filename).
+#' @param scale Multiplicative scaling factor.
+#' @param width,height Plot dimensions, defaults to size of current graphics
+#'   device.
+#' @param units Units for width and height when specified explicitly (in, cm,
+#'   or mm)
+#' @param dpi Resolution used for raster outputs.
+#' @param limitsize When \code{TRUE} (the default), \code{ggsave} will not
 #'   save images larger than 50x50 inches, to prevent the common error of
 #'   specifying dimensions in pixels.
-#' @param ... other arguments passed to graphics device
+#' @param ... Other arguments passed on to graphics device
 #' @export
 #' @examples
 #' \dontrun{
-#' ratings <- qplot(rating, data=movies, geom="histogram")
-#' qplot(length, data=movies, geom="histogram")
-#' ggsave("length-hist.pdf")
-#' ggsave("length-hist.png")
-#' ggsave("ratings.pdf", ratings)
-#' ggsave("ratings.pdf", ratings, width=4, height=4)
-#' # make twice as big as on screen
-#' ggsave("ratings.pdf", ratings, scale=2)
+#' ggplot(mtcars, aes(mpg, wt)) + geom_point()
+#'
+#' ggsave("mtcars.pdf")
+#' ggsave("mtcars.png")
+#'
+#' ggsave("mtcars.pdf", width = 4, height = 4)
+#' ggsave("mtcars.pdf", width = 20, height = 20, units = "cm")
+#'
+#' unlink("mtcars.pdf")
+#' unlink("mtcars.png")
+#'
+#' # specify device when saving to a file with unknown extension
+#' # (for example a server supplied temporary file)
+#' file <- tempfile()
+#' ggsave(file, device = "pdf")
+#' unlink(file)
 #' }
-ggsave <- function(filename = default_name(plot), plot = last_plot(),
-  device = default_device(filename), path = NULL, scale = 1,
-  width = par("din")[1], height = par("din")[2], units = c("in", "cm", "mm"),
-  dpi = 300, limitsize = TRUE, ...) {
-
-  if (!inherits(plot, "ggplot")) stop("plot should be a ggplot2 plot")
-
-  eps <- ps <- function(..., width, height)
-    grDevices::postscript(..., width=width, height=height, onefile=FALSE,
-      horizontal = FALSE, paper = "special")
-  tex <- function(..., width, height)
-    grDevices::pictex(..., width=width, height=height)
-  pdf <- function(..., version="1.4")
-    grDevices::pdf(..., version=version)
-  svg <- function(...)
-    grDevices::svg(...)
-  wmf <- function(..., width, height)
-    grDevices::win.metafile(..., width=width, height=height)
-  emf <- function(..., width, height)
-    grDevices::win.metafile(..., width=width, height=height)
-
-  png <- function(..., width, height)
-    grDevices::png(...,  width=width, height=height, res = dpi, units = "in")
-  jpg <- jpeg <- function(..., width, height)
-    grDevices::jpeg(..., width=width, height=height, res = dpi, units = "in")
-  bmp <- function(..., width, height)
-    grDevices::bmp(...,  width=width, height=height, res = dpi, units = "in")
-  tiff <- function(..., width, height)
-    grDevices::tiff(..., width=width, height=height, res = dpi, units = "in")
-
-  default_name <- function(plot) {
-    paste(digest.ggplot(plot), ".pdf", sep="")
-  }
+ggsave <- function(filename, plot = last_plot(),
+                   device = NULL, path = NULL, scale = 1,
+                   width = NA, height = NA, units = c("in", "cm", "mm"),
+                   dpi = 300, limitsize = TRUE, ...) {
+
+  dev <- plot_dev(device, filename, dpi = dpi)
+  dim <- plot_dim(c(width, height), scale = scale, units = units,
+    limitsize = limitsize)
 
-  default_device <- function(filename) {
-    pieces <- strsplit(filename, "\\.")[[1]]
-    ext <- tolower(pieces[length(pieces)])
-    match.fun(ext)
+  if (!is.null(path)) {
+    filename <- file.path(path, filename)
   }
+  dev(file = filename, width = dim[1], height = dim[2], ...)
+  on.exit(utils::capture.output(grDevices::dev.off()))
+  grid.draw(plot)
+
+  invisible()
+}
+
+plot_dim <- function(dim = c(NA, NA), scale = 1, units = c("in", "cm", "mm"),
+                     limitsize = TRUE) {
 
   units <- match.arg(units)
-  convert_to_inches <- function(x, units) {
-    x <- switch(units,
-      `in` = x,
-      cm = x / 2.54,
-      mm = x / 2.54 /10
-    )
-  }
+  to_inches <- function(x) x / c(`in` = 1, cm = 2.54, mm = 2.54 * 10)[units]
+  from_inches <- function(x) x * c(`in` = 1, cm = 2.54, mm = 2.54 * 10)[units]
 
-  convert_from_inches <- function(x, units) {
-    x <- switch(units,
-      `in` = x,
-      cm = x * 2.54,
-      mm = x * 2.54 * 10
-    )
-  }
+  dim <- to_inches(dim) * scale
+
+  if (any(is.na(dim))) {
+    if (length(grDevices::dev.list()) == 0) {
+      default_dim <- c(7, 7)
+    } else {
+      default_dim <- grDevices::dev.size() * scale
+    }
+    dim[is.na(dim)] <- default_dim[is.na(dim)]
+    dim_f <- prettyNum(from_inches(dim), digits = 3)
 
-  # dimensions need to be in inches for all graphic devices
-  # convert width and height into inches when they are specified
-  if (!missing(width)) {
-    width <- convert_to_inches(width, units)
+    message("Saving ", dim_f[1], " x ", dim_f[2], " ", units, " image")
   }
-  if (!missing(height)) {
-    height <- convert_to_inches(height, units)
+
+  if (limitsize && any(dim >= 50)) {
+    stop("Dimensions exceed 50 inches (height and width are specified in '",
+      units, "' not pixels). If you're sure you a plot that big, use ",
+      "`limitsize = FALSE`.", call. = FALSE)
   }
-  # if either width or height is not specified, display an information message
-  # units are those specified by the user
-  if (missing(width) || missing(height)) {
-    message("Saving ", prettyNum(convert_from_inches(width * scale, units), digits=3), " x ", prettyNum(convert_from_inches(height * scale, units), digits=3), " ", units, " image")
+
+  dim
+}
+
+plot_dev <- function(device, filename, dpi = 300) {
+  if (is.function(device))
+    return(device)
+
+  eps <- function(...) {
+    grDevices::postscript(..., onefile = FALSE, horizontal = FALSE,
+      paper = "special")
   }
+  devices <- list(
+    eps =  eps,
+    ps =   eps,
+    tex =  function(...) grDevices::pictex(...),
+    pdf =  function(..., version = "1.4") grDevices::pdf(..., version = version),
+    svg =  function(...) grDevices::svg(...),
+    emf =  function(...) grDevices::win.metafile(...),
+    wmf =  function(...) grDevices::win.metafile(...),
+    png =  function(...) grDevices::png(..., res = dpi, units = "in"),
+    jpg =  function(...) grDevices::jpeg(..., res = dpi, units = "in"),
+    jpeg = function(...) grDevices::jpeg(..., res = dpi, units = "in"),
+    bmp =  function(...) grDevices::bmp(..., res = dpi, units = "in"),
+    tiff = function(...) grDevices::tiff(..., res = dpi, units = "in")
+  )
 
-  width <- width * scale
-  height <- height * scale
+  if (is.null(device)) {
+    device <- tolower(tools::file_ext(filename))
+  }
 
-  if (limitsize && (width >= 50 || height >= 50)) {
-    stop("Dimensions exceed 50 inches (height and width are specified in inches/cm/mm, not pixels).",
-      " If you are sure you want these dimensions, use 'limitsize=FALSE'.")
+  if (!is.character(device) || length(device) != 1) {
+    stop("`device` must be NULL, a string or a function.", call. = FALSE)
   }
 
-  if (!is.null(path)) {
-    filename <- file.path(path, filename)
+  dev <- devices[[device]]
+  if (is.null(dev)) {
+    stop("Unknown graphics device '", device, "'", call. = FALSE)
   }
-  device(file=filename, width=width, height=height, ...)
-  on.exit(capture.output(dev.off()))
-  print(plot)
+  dev
+}
 
-  invisible()
+#' @export
+grid.draw.ggplot <- function(x, recording = TRUE) {
+  print(x)
 }
diff --git a/R/scale-.r b/R/scale-.r
index 19b6acb..ef71fa8 100644
--- a/R/scale-.r
+++ b/R/scale-.r
@@ -1,58 +1,530 @@
-#' Components of a scale:
+#' @section Scales:
 #'
-#' Guide related:
+#' All \code{scale_*} functions (like \code{scale_x_continuous}) return a
+#' \code{Scale*} object (like \code{ScaleContinuous}). The \code{Scale*}
+#' object represents a single scale.
 #'
-#' \itemize{
-#'   \item name
-#'   \item breaks
-#'   \item labels
-#'   \item expand
-#' }
-#'
-#' Mapping related:
-#' \itemize{
-#'   \item aesthetic
-#'   \item limits
-#'   \item palette
-#'   \item trans
-#' }
+#' Each of the \code{Scale*} objects is a \code{\link{ggproto}} object,
+#' descended from the top-level \code{Scale}.
 #'
-#' Scales are an S3 class with a single mutable component implemented with
-#' a reference class - the range of the data.  This mutability makes working
-#' with scales much easier, because it makes it possible to distribute the
-#' training, without having to worry about collecting all the pieces back
-#' together again.
-#'
-#' @name ggscale
-#' @keywords internal
-NULL
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+Scale <- ggproto("Scale", NULL,
+
+  call = NULL,
+
+  aesthetics = aes(),
+  scale_name = NULL,
+  palette = function() {
+    stop("Not implemented", call. = FALSE)
+  },
+
+  range = ggproto(NULL, Range),
+  limits = NULL,
+  na.value = NA,
+  expand = waiver(),
+
+  name = waiver(),
+  breaks = waiver(),
+  labels = waiver(),
+  guide = "legend",
+
+
+  is_discrete = function() {
+    stop("Not implemented", call. = FALSE)
+  },
+
+  # Train scale from a data frame.
+  #
+  # @return updated range (invisibly)
+  # @seealso \code{\link{scale_train}} for scale specific generic method
+  train_df = function(self, df) {
+    if (empty(df)) return()
+
+    aesthetics <- intersect(self$aesthetics, names(df))
+    for (aesthetic in aesthetics) {
+      self$train(df[[aesthetic]])
+    }
+    invisible()
+  },
+
+  # Train an individual scale from a vector of data.
+  train = function(self, x) {
+    stop("Not implemented", call. = FALSE)
+  },
+
+  # Reset scale, untraining ranges
+  reset = function(self) {
+    self$range$reset()
+  },
+
+  is_empty = function(self) {
+    is.null(self$range$range) && is.null(self$limits)
+  },
+
+  # @return list of transformed variables
+  transform_df = function(self, df) {
+    if (empty(df)) return()
+
+    aesthetics <- intersect(self$aesthetics, names(df))
+    if (length(aesthetics) == 0) return()
+
+    lapply(df[aesthetics], self$transform)
+  },
+
+  transform = function(self, x) {
+    stop("Not implemented", call. = FALSE)
+  },
+
+  # @return list of mapped variables
+  map_df = function(self, df, i = NULL) {
+    if (empty(df)) return()
+
+    aesthetics <- intersect(self$aesthetics, names(df))
+    names(aesthetics) <- aesthetics
+    if (length(aesthetics) == 0) return()
+
+    if (is.null(i)) {
+      lapply(aesthetics, function(j) self$map(df[[j]]))
+    } else {
+      lapply(aesthetics, function(j) self$map(df[[j]][i]))
+    }
+  },
+
+  # @kohske
+  # map tentatively accept limits argument.
+  # map replaces oob (i.e., outside limits) values with NA.
+  #
+  # Previously limits are always scale_limits(scale).
+  # But if this function is called to get breaks,
+  # and breaks spans oob, the oob breaks is replaces by NA.
+  # This makes impossible to display oob breaks.
+  # Now coord_train calls this function with limits determined by coord (with expansion).
+  map = function(self, x, limits = self$get_limits()) {
+    stop("Not implemented", call. = FALSE)
+  },
+
+  #  if scale contains a NULL, use the default scale range
+  #  if scale contains a NA, use the default range for that axis, otherwise
+  #  use the user defined limit for that axis
+  get_limits = function(self) {
+    if (self$is_empty()) return(c(0, 1))
+
+    if (!is.null(self$limits)) {
+      ifelse(!is.na(self$limits), self$limits, self$range$range)
+    } else {
+      self$range$range
+    }
+  },
+
+  # The physical size of the scale.
+  # This always returns a numeric vector of length 2, giving the physical
+  # dimensions of a scale.
+  dimension = function(self, expand = c(0, 0)) {
+    stop("Not implemented", call. = FALSE)
+  },
+
+  get_breaks = function(self, limits = self$get_limits()) {
+    stop("Not implemented", call. = FALSE)
+  },
+
+  # The numeric position of scale breaks, used by coord/guide
+  break_positions = function(self, range = self$get_limits()) {
+    self$map(self$get_breaks(range))
+  },
+
+  get_breaks_minor = function(self, n = 2, b = self$break_positions(), limits = self$get_limits()) {
+    stop("Not implemented", call. = FALSE)
+  },
+
+  get_labels = function(self, breaks = self$get_breaks()) {
+    stop("Not implemented", call. = FALSE)
+  },
+
+  # Each implementation of a Scale must implement a clone method that makes
+  # copies of reference objecsts.
+  clone = function(self) {
+    stop("Not implemented", call. = FALSE)
+  },
+
+  break_info = function(self, range = NULL) {
+    stop("Not implemented", call. = FALSE)
+  }
+)
+
+check_breaks_labels <- function(breaks, labels) {
+  if (is.null(breaks)) return(TRUE)
+  if (is.null(labels)) return(TRUE)
+
+  bad_labels <- is.atomic(breaks) && is.atomic(labels) &&
+    length(breaks) != length(labels)
+  if (bad_labels) {
+    stop("`breaks` and `labels` must have the same length", call. = FALSE)
+  }
+
+  TRUE
+}
+
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+ScaleContinuous <- ggproto("ScaleContinuous", Scale,
+  range = continuous_range(),
+  na.value = NA_real_,
+  rescaler = rescale, # Used by diverging and n colour gradients x
+  oob = censor,
+  minor_breaks = waiver(),
+
+  is_discrete = function() FALSE,
+
+  train = function(self, x) {
+    if (length(x) == 0) return()
+    self$range$train(x)
+  },
+
+  transform = function(self, x) {
+     self$trans$transform(x)
+  },
+
+  map = function(self, x, limits = self$get_limits()) {
+    x <- self$oob(self$rescaler(x, from = limits))
+
+    uniq <- unique(x)
+    pal <- self$palette(uniq)
+    scaled <- pal[match(x, uniq)]
+
+    ifelse(!is.na(scaled), scaled, self$na.value)
+  },
+
+  dimension = function(self, expand = c(0, 0)) {
+    expand_range(self$get_limits(), expand[1], expand[2])
+  },
+
+  get_breaks = function(self, limits = self$get_limits()) {
+    if (self$is_empty()) return(numeric())
+
+    # Limits in transformed space need to be converted back to data space
+    limits <- self$trans$inverse(limits)
+
+    if (is.null(self$breaks)) {
+      return(NULL)
+    } else if (identical(self$breaks, NA)) {
+      stop("Invalid breaks specification. Use NULL, not NA")
+    } else if (zero_range(as.numeric(limits))) {
+      breaks <- limits[1]
+    } else if (is.waive(self$breaks)) {
+      breaks <- self$trans$breaks(limits)
+    } else if (is.function(self$breaks)) {
+      breaks <- self$breaks(limits)
+    } else {
+      breaks <- self$breaks
+    }
+
+    # Breaks in data space need to be converted back to transformed space
+    # And any breaks outside the dimensions need to be flagged as missing
+    #
+    # @kohske
+    # TODO: replace NA with something else for flag.
+    #       guides cannot discriminate oob from missing value.
+    breaks <- censor(self$trans$transform(breaks), self$trans$transform(limits),
+                     only.finite = FALSE)
+    if (length(breaks) == 0) {
+      stop("Zero breaks in scale for ", paste(self$aesthetics, collapse = "/"),
+        call. = FALSE)
+    }
+    breaks
+  },
+
+  get_breaks_minor = function(self, n = 2, b = self$break_positions(), limits = self$get_limits()) {
+    if (zero_range(as.numeric(limits))) {
+      return()
+    }
+
+    if (is.null(self$minor_breaks)) {
+      return(NULL)
+    } else if (identical(self$minor_breaks, NA)) {
+      stop("Invalid minor_breaks specification. Use NULL, not NA", call. = FALSE)
+    } else if (is.waive(self$minor_breaks)) {
+      if (is.null(b)) {
+        breaks <- NULL
+      } else {
+        b <- b[!is.na(b)]
+        if (length(b) < 2) return()
+
+        bd <- diff(b)[1]
+        if (min(limits) < min(b)) b <- c(b[1] - bd, b)
+        if (max(limits) > max(b)) b <- c(b, b[length(b)] + bd)
+        breaks <- unique(unlist(mapply(seq, b[-length(b)], b[-1], length.out = n + 1,
+          SIMPLIFY = FALSE)))
+      }
+    } else if (is.function(self$minor_breaks)) {
+      # Find breaks in data space, and convert to numeric
+      breaks <- self$minor_breaks(self$trans$inverse(limits))
+      breaks <- self$trans$transform(breaks)
+    } else {
+      breaks <- self$trans$transform(self$minor_breaks)
+    }
+
+    # Any minor breaks outside the dimensions need to be thrown away
+    discard(breaks, limits)
+  },
+
+  get_labels = function(self, breaks = self$get_breaks()) {
+    if (is.null(breaks)) return(NULL)
+
+    breaks <- self$trans$inverse(breaks)
+
+    if (is.null(self$labels)) {
+      return(NULL)
+    } else if (identical(self$labels, NA)) {
+      stop("Invalid labels specification. Use NULL, not NA", call. = FALSE)
+    } else if (is.waive(self$labels)) {
+      labels <- self$trans$format(breaks)
+    } else if (is.function(self$labels)) {
+      labels <- self$labels(breaks)
+    } else {
+      labels <- self$labels
+    }
+    if (length(labels) != length(breaks)) {
+      stop("Breaks and labels are different lengths")
+    }
+    labels
+  },
+
+  clone = function(self) {
+    new <- ggproto(NULL, self)
+    new$range <- continuous_range()
+    new
+  },
+
+  break_info = function(self, range = NULL) {
+    # range
+    if (is.null(range)) range <- self$dimension()
+
+    # major breaks
+    major <- self$get_breaks(range)
+
+    # labels
+    labels <- self$get_labels(major)
+
+    # drop oob breaks/labels by testing major == NA
+    if (!is.null(labels)) labels <- labels[!is.na(major)]
+    if (!is.null(major)) major <- major[!is.na(major)]
+
+    # minor breaks
+    minor <- self$get_breaks_minor(b = major, limits = range)
+    if (!is.null(minor)) minor <- minor[!is.na(minor)]
+
+    # rescale breaks [0, 1], which are used by coord/guide
+    major_n <- rescale(major, from = range)
+    minor_n <- rescale(minor, from = range)
+
+    list(range = range, labels = labels,
+         major = major_n, minor = minor_n,
+         major_source = major, minor_source = minor)
+  },
+
+  print = function(self, ...) {
+    show_range <- function(x) paste0(formatC(x, digits = 3), collapse = " -- ")
+
+    cat("<", class(self)[[1]], ">\n", sep = "")
+    cat(" Range:  ", show_range(self$range$range), "\n", sep = "")
+    cat(" Limits: ", show_range(self$dimension()), "\n", sep = "")
+  }
+)
+
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+ScaleDiscrete <- ggproto("ScaleDiscrete", Scale,
+  drop = TRUE,
+  na.value = NA,
+
+  is_discrete = function() TRUE,
+
+  train = function(self, x) {
+    if (length(x) == 0) return()
+    self$range$train(x, drop = self$drop)
+  },
+
+  transform = function(x) {
+    x
+  },
+
+  map = function(self, x, limits = self$get_limits()) {
+    n <- sum(!is.na(limits))
+    pal <- self$palette(n)
+
+    if (is.null(names(pal))) {
+      pal_match <- pal[match(as.character(x), limits)]
+    } else {
+      pal_match <- pal[match(as.character(x), names(pal))]
+      pal_match <- unname(pal_match)
+    }
+
+    ifelse(is.na(x) | is.na(pal_match), self$na.value, pal_match)
+  },
+
+  dimension = function(self, expand = c(0, 0)) {
+    expand_range(length(self$get_limits()), expand[1], expand[2])
+  },
+
+  get_breaks = function(self, limits = self$get_limits()) {
+    if (self$is_empty()) return(numeric())
+
+    if (is.null(self$breaks)) {
+      return(NULL)
+    } else if (identical(self$breaks, NA)) {
+      stop("Invalid breaks specification. Use NULL, not NA", call. = FALSE)
+    } else if (is.waive(self$breaks)) {
+      breaks <- limits
+    } else if (is.function(self$breaks)) {
+      breaks <- self$breaks(limits)
+    } else {
+      breaks <- self$breaks
+    }
+
+    # Breaks can only occur only on values in domain
+    in_domain <- intersect(breaks, self$get_limits())
+    structure(in_domain, pos = match(in_domain, breaks))
+  },
+
+  get_breaks_minor = function(...) NULL,
+
+  get_labels = function(self, breaks = self$get_breaks()) {
+    if (self$is_empty()) return(character())
+
+    if (is.null(breaks)) return(NULL)
+
+    if (is.null(self$labels)) {
+      return(NULL)
+    } else if (identical(self$labels, NA)) {
+      stop("Invalid labels specification. Use NULL, not NA", call. = FALSE)
+    }else if (is.waive(self$labels)) {
+      format(self$get_breaks(), justify = "none", trim = TRUE)
+    } else if (is.function(self$labels)) {
+      self$labels(breaks)
+    } else {
+      if (!is.null(names(self$labels))) {
+        # If labels have names, use them to match with breaks
+        labels <- breaks
+
+        map <- match(names(self$labels), labels, nomatch = 0)
+        labels[map] <- self$labels[map != 0]
+        labels
+      } else {
+        labels <- self$labels
+
+        # Need to ensure that if breaks were dropped, corresponding labels are too
+        pos <- attr(breaks, "pos")
+        if (!is.null(pos)) {
+          labels <- labels[pos]
+        }
+        labels
+      }
+    }
+  },
+
+  clone = function(self) {
+    new <- ggproto(NULL, self)
+    new$range <- discrete_range()
+    new
+  },
+
+  break_info = function(self, range = NULL) {
+    # for discrete, limits != range
+    limits <- self$get_limits()
+
+    major <- self$get_breaks(limits)
+    if (is.null(major)) {
+      labels <- major_n <- NULL
+    } else {
+
+      labels <- self$get_labels(major)
+
+      major <- self$map(major)
+      major <- major[!is.na(major)]
+
+      # rescale breaks [0, 1], which are used by coord/guide
+      major_n <- rescale(major, from = range)
+    }
+
+    list(range = range, labels = labels,
+         major = major_n, minor = NULL,
+         major_source = major, minor_source = NULL)
+  }
+)
+
 
 #' Continuous scale constructor.
 #'
 #' @export
 #' @inheritParams discrete_scale
-#' @param minor_breaks Used with date or datetime scales. Either \code{NULL} for
-#'   no minor breaks, \code{waiver()} for the default breaks (one minor break
-#'   between each major break), a numeric vector of positions, or a function
-#'   that given the limits returns a vector of minor breaks.
-#' @param limits A numeric vector of length two describing the scale limits.
+#' @param name The name of the scale. Used as axis or legend title. If
+#'   \code{NULL}, the default, the name of the scale is taken from the first
+#'   mapping used for that aesthetic.
+#' @param breaks One of: \itemize{
+#'   \item \code{NULL} for no breaks
+#'   \item \code{waiver()} for the default breaks computed by the
+#'     transformation object
+#'   \item A numeric vector of positions
+#'   \item A function that takes the limits as input and returns breaks
+#'     as output
+#' }
+#' @param minor_breaks One of: \itemize{
+#'   \item \code{NULL} for no minor breaks
+#'   \item \code{waiver()} for the default breaks (one minor break between
+#'     each major break)
+#'   \item A numeric vector of positions
+#'   \item A function that given the limits returns a vector of minor breaks.
+#' }
+#' @param labels One of: \itemize{
+#'   \item \code{NULL} for no labels
+#'   \item \code{waiver()} for the default labels computed by the
+#'     transformation object
+#'   \item A character vector giving labels (must be same length as \code{breaks})
+#'   \item A function that takes the breaks as input and returns labels
+#'     as output
+#' }
+#' @param limits A numeric vector of length two providing limits of the scale.
+#'   Use \code{NA} to refer to the existing minimum or maximum.
 #' @param rescaler  Used by diverging and n colour gradients
 #'   (i.e. \code{\link{scale_colour_gradient2}}, \code{\link{scale_colour_gradientn}}).
-#' @param oob What to do with values outside scale limits (out of bounds)?
+#'   A function used to scale the input values to the range [0, 1].
+#' @param oob Function that handles limits outside of the scale limits
+#'   (out of bounds). The default replaces out of bounds values with NA.
+#' @param na.value Missing values will be replaced with this value.
+#' @param trans Either the name of a transformation object, or the
+#'   object itself. Built-in transformations include "asn", "atanh",
+#'   "boxcox", "exp", "identity", "log", "log10", "log1p", "log2",
+#'   "logit", "probability", "probit", "reciprocal", "reverse" and "sqrt".
+#'
+#'   A transformation object bundles together a transform, it's inverse,
+#'   and methods for generating breaks and labels. Transformation objects
+#'   are defined in the scales package, and are called \code{name_trans}, e.g.
+#'   \code{\link[scales]{boxcox_trans}}. You can create your own
+#'   transformation with \code{\link[scales]{trans_new}}.
+#' @param expand A numeric vector of length two giving multiplicative and
+#'   additive expansion constants. These constants ensure that the data is
+#'   placed some distance away from the axes. The defaults are
+#'   \code{c(0.05, 0)} for continuous variables, and \code{c(0, 0.6)} for
+#'   discrete variables.
+#' @param guide Name of guide object, or object itself.
 #' @keywords internal
-continuous_scale <- function(aesthetics, scale_name, palette, name = NULL, breaks = waiver(), minor_breaks = waiver(), labels = waiver(), legend = NULL, limits = NULL, rescaler = rescale, oob = censor, expand = waiver(), na.value = NA_real_, trans = "identity", guide="legend") {
+continuous_scale <- function(aesthetics, scale_name, palette, name = waiver(),
+                             breaks = waiver(), minor_breaks = waiver(),
+                             labels = waiver(), limits = NULL,
+                             rescaler = rescale, oob = censor,
+                             expand = waiver(), na.value = NA_real_,
+                             trans = "identity", guide = "legend") {
 
-  if (!is.null(legend)) {
-    gg_dep("0.8.9", "\"legend\" argument in scale_XXX is deprecated. Use guide=\"none\" for suppress the guide display.")
-    if (legend == FALSE) guide = "none"
-    else if (legend == TRUE) guide = "legend"
-  }
-
-  bad_labels <- is.vector(breaks) && is.vector(labels) &&
-    length(breaks) != length(labels)
-  if (bad_labels) {
-    stop("Breaks and labels have unequal lengths", call. = FALSE)
-  }
+  check_breaks_labels(breaks, labels)
 
   if (is.null(breaks) && !is_position_aes(aesthetics) && guide != "none") {
     guide <- "none"
@@ -60,17 +532,17 @@ continuous_scale <- function(aesthetics, scale_name, palette, name = NULL, break
 
   trans <- as.trans(trans)
   if (!is.null(limits)) {
-    limits <- trans$trans(limits)
+    limits <- trans$transform(limits)
   }
 
-  structure(list(
+  ggproto(NULL, ScaleContinuous,
     call = match.call(),
 
     aesthetics = aesthetics,
     scale_name = scale_name,
     palette = palette,
 
-    range = ContinuousRange$new(),
+    range = continuous_range(),
     limits = limits,
     trans = trans,
     na.value = na.value,
@@ -83,9 +555,8 @@ continuous_scale <- function(aesthetics, scale_name, palette, name = NULL, break
     minor_breaks = minor_breaks,
 
     labels = labels,
-    legend = legend,
     guide = guide
-  ), class = c(scale_name, "continuous", "scale"))
+  )
 }
 
 #' Discrete scale constructor.
@@ -120,40 +591,32 @@ continuous_scale <- function(aesthetics, scale_name, palette, name = NULL, break
 #'   labels (labels the same as breaks), a character vector the same length
 #'   as breaks, or a named character vector whose names are used to match
 #'   replacement the labels for matching breaks.
-#' @param legend deprecated.  Use \code{guide} instead.
 #' @param expand a numeric vector of length two, giving a multiplicative and
 #'   additive constant used to expand the range of the scales so that there
-#'   is a small gap between the data and the axes.
+#'   is a small gap between the data and the axes. The defaults are (0,0.6)
+#'   for discrete scales and (0.05,0) for continuous scales.
 #' @param na.value how should missing values be displayed?
 #' @param guide the name of, or actual function, used to create the
-#'   guide.
+#'   guide. See \code{\link{guides}} for more info.
 #' @keywords internal
-discrete_scale <- function(aesthetics, scale_name, palette, name = NULL, breaks = waiver(), labels = waiver(), legend = NULL, limits = NULL, expand = waiver(), na.value = NA, drop = TRUE, guide="legend") {
-
-  if (!is.null(legend)) {
-    gg_dep("0.8.9", "\"legend\" argument in scale_XXX is deprecated. Use guide=\"none\" for suppress the guide display.")
-    if (legend == FALSE) guide = "none"
-    else if (legend == TRUE) guide = "legend"
-  }
+discrete_scale <- function(aesthetics, scale_name, palette, name = waiver(), breaks = waiver(),
+  labels = waiver(), limits = NULL, expand = waiver(), na.value = NA, drop = TRUE,
+  guide = "legend") {
 
-  bad_labels <- is.vector(breaks) && is.vector(labels) &&
-    length(breaks) != length(labels)
-  if (bad_labels) {
-    stop("Breaks and labels have unequal lengths", call. = FALSE)
-  }
+  check_breaks_labels(breaks, labels)
 
   if (is.null(breaks) && !is_position_aes(aesthetics) && guide != "none") {
     guide <- "none"
   }
 
-  structure(list(
+  ggproto(NULL, ScaleDiscrete,
     call = match.call(),
 
     aesthetics = aesthetics,
     scale_name = scale_name,
     palette = palette,
 
-    range = DiscreteRange$new(),
+    range = discrete_range(),
     limits = limits,
     na.value = na.value,
     expand = expand,
@@ -161,434 +624,7 @@ discrete_scale <- function(aesthetics, scale_name, palette, name = NULL, breaks
     name = name,
     breaks = breaks,
     labels = labels,
-    legend = legend,
     drop = drop,
     guide = guide
-  ), class = c(scale_name, "discrete", "scale"))
-}
-
-# Train scale from a data frame.
-#
-# @return updated range (invisibly)
-# @seealso \code{\link{scale_train}} for scale specific generic method
-scale_train_df <- function(scale, df) {
-  if (empty(df)) return()
-
-  aesthetics <- intersect(scale$aesthetics, names(df))
-  for(aesthetic in aesthetics) {
-    scale_train(scale, df[[aesthetic]])
-  }
-  invisible()
-}
-
-# Train an individual scale from a vector of data.
-#
-scale_train <- function(scale, x) {
-  if (length(x) == 0) return()
-  UseMethod("scale_train")
-}
-
-#' @export
-scale_train.continuous <- function(scale, x) {
-  scale$range$train(x)
-}
-#' @export
-scale_train.discrete <- function(scale, x) {
-  scale$range$train(x, drop = scale$drop)
-}
-
-# Reset scale, untraining ranges
-scale_reset <- function(scale, x) UseMethod("scale_reset")
-#' @export
-scale_reset.default <- function(scale, x) {
-  scale$range$reset()
-}
-
-scale_is_empty <- function(scale) UseMethod("scale_is_empty")
-
-#' @export
-scale_is_empty.default <- function(scale) {
-  is.null(scale$range$range) && is.null(scale$limits)
-}
-
-# @return list of transformed variables
-scale_transform_df <- function(scale, df) {
-  if (empty(df)) return()
-
-  aesthetics <- intersect(scale$aesthetics, names(df))
-  if (length(aesthetics) == 0) return()
-
-  lapply(df[aesthetics], scale_transform, scale = scale)
-}
-
-scale_transform <- function(scale, x) UseMethod("scale_transform")
-
-#' @export
-scale_transform.continuous <- function(scale, x) {
-  scale$trans$trans(x)
-}
-#' @export
-scale_transform.discrete <- function(scale, x) {
-  x
-}
-
-# @return list of mapped variables
-scale_map_df <- function(scale, df, i = NULL) {
-  if (empty(df)) return()
-
-  aesthetics <- intersect(scale$aesthetics, names(df))
-  names(aesthetics) <- aesthetics
-  if (length(aesthetics) == 0) return()
-
-  if (is.null(i)) {
-    lapply(aesthetics, function(j) scale_map(scale, df[[j]]))
-  } else {
-    lapply(aesthetics, function(j) scale_map(scale, df[[j]][i]))
-  }
-}
-
-# @kohske
-# scale_map tentatively accept limits argument.
-# scale_map replaces oob (i.e., outside limits) values with NA.
-#
-# Previously limits are always scale_limits(scale).
-# But if this function is called to get breaks,
-# and breaks spans oob, the oob breaks is replaces by NA.
-# This makes impossible to display oob breaks.
-# Now coord_train calls this function with limits determined by coord (with expansion).
-scale_map <- function(scale, x, limits) UseMethod("scale_map")
-
-#' @export
-scale_map.continuous <- function(scale, x, limits = scale_limits(scale)) {
-  x <- scale$oob(scale$rescaler(x, from = limits))
-
-  # Points are rounded to the nearest 500th, to reduce the amount of
-  # work that the scale palette must do - this is particularly important
-  # for colour scales which are rather slow.  This shouldn't have any
-  # perceptual impacts.
-  x <- round_any(x, 1 / 500)
-  uniq <- unique(x)
-  pal <- scale$palette(uniq)
-  scaled <- pal[match(x, uniq)]
-
-  ifelse(!is.na(scaled), scaled, scale$na.value)
-}
-
-#' @export
-scale_map.discrete <- function(scale, x, limits = scale_limits(scale)) {
-  n <- sum(!is.na(limits))
-  pal <- scale$palette(n)
-
-  if (is.null(names(pal))) {
-    pal_match <- pal[match(as.character(x), limits)]
-  } else {
-    pal_match <- pal[match(as.character(x), names(pal))]
-    pal_match <- unname(pal_match)
-  }
-
-  ifelse(is.na(x) | is.na(pal_match), scale$na.value, pal_match)
-}
-
-scale_limits <- function(scale) {
-  if (scale_is_empty(scale)) return(c(0, 1))
-
-  UseMethod("scale_limits")
-}
-
-
-#  if scale contains a NULL, use the default scale range
-#  if scale contains a NA, use the default range for that axis, otherwise
-#  use the user defined limit for that axis
-#' @export
-scale_limits.default <- function(scale) {
-  if(!is.null(scale$limits)) {
-    ifelse(!is.na(scale$limits), scale$limits, scale$range$range)
-  } else {
-    scale$range$range
-  }
-}
-
-# @kohske
-# this (internal) function always returns a vector of length 2 of giving
-# multiplicative and additive expansion constants.
-# if scale' expand is specified, return it.
-# if is.waive, return c(0, 0)
-scale_expand <- function(scale) UseMethod("scale_expand")
-#' @export
-scale_expand.default <- function(scale) {
-  if (is.waive(scale$expand)) c(0, 0)
-  else scale$expand
-}
-
-# The phyical size of the scale, if a position scale
-# Unlike limits, this always returns a numeric vector of length 2
-# @kohske
-# scale_dimension uses scale_expand(scale) for expansion by default.
-scale_dimension <- function(scale, expand = scale_expand(scale)) UseMethod("scale_dimension")
-
-#' @export
-scale_dimension.continuous  <- function(scale, expand = scale_expand(scale)) {
-  expand_range(scale_limits(scale), expand[1], expand[2])
-}
-#' @export
-scale_dimension.discrete <- function(scale, expand = scale_expand(scale)) {
-  expand_range(length(scale_limits(scale)), expand[1], expand[2])
-}
-
-scale_breaks <- function(scale, limits = scale_limits(scale)) {
-  if (scale_is_empty(scale)) return(numeric())
-
-  UseMethod("scale_breaks")
-}
-
-#' @export
-scale_breaks.continuous <- function(scale, limits = scale_limits(scale)) {
-  # Limits in transformed space need to be converted back to data space
-  limits <- scale$trans$inv(limits)
-
-  if (is.null(scale$breaks)) {
-    return(NULL)
-  } else if (length(scale$breaks) == 1 && !is.function(scale$breaks) && is.na(scale$breaks)) {
-    gg_dep("0.8.9", "breaks = NA is deprecated. Please use breaks = NULL to remove breaks in the scale.")
-    return(NULL)
-  } else if (zero_range(as.numeric(limits))) {
-    breaks <- limits[1]
-  } else if (is.waive(scale$breaks)) {
-    breaks <- scale$trans$breaks(limits)
-  } else if (is.function(scale$breaks)) {
-    breaks <- scale$breaks(limits)
-  } else {
-    breaks <- scale$breaks
-  }
-
-  # Breaks in data space need to be converted back to transformed space
-  # And any breaks outside the dimensions need to be flagged as missing
-  #
-  # @kohske
-  # TODO: replace NA with something else for flag.
-  #       guides cannot discriminate oob from missing value.
-  breaks <- censor(scale$trans$trans(breaks), scale$trans$trans(limits))
-  if (length(breaks) == 0) {
-    stop("Zero breaks in scale for ", paste(scale$aesthetics, collapse = "/"),
-      call. = FALSE)
-  }
-  breaks
-}
-
-#' @export
-scale_breaks.discrete <- function(scale, limits = scale_limits(scale)) {
-  if (is.null(scale$breaks)) {
-    return(NULL)
-  } else if (length(scale$breaks) == 1 && !is.function(scale$breaks) && is.na(scale$breaks)) {
-    gg_dep("0.8.9", "breaks = NA is deprecated. Please use breaks = NULL to remove breaks in the scale.")
-    return(NULL)
-  } else if (is.waive(scale$breaks)) {
-    breaks <- limits
-  } else if (is.function(scale$breaks)) {
-    breaks <- scale$breaks(limits)
-  } else {
-    breaks <- scale$breaks
-  }
-
-  # Breaks can only occur only on values in domain
-  in_domain <- intersect(breaks, scale_limits(scale))
-  structure(in_domain, pos = match(in_domain, breaks))
-}
-
-# The numeric position of scale breaks, used by coord/guide
-scale_break_positions <- function(scale, range = scale_limits(scale)) {
-  scale_map(scale, scale_breaks(scale, range))
-}
-
-scale_breaks_minor<- function(scale, n = 2, b = scale_break_positions(scale), limits = scale_limits(scale)) {
-  UseMethod("scale_breaks_minor")
-}
-
-#' @export
-scale_breaks_minor.continuous <- function(scale, n = 2, b = scale_break_positions(scale), limits = scale_limits(scale)) {
-  if (zero_range(as.numeric(limits))) {
-    return()
-  }
-
-  if (is.null(scale$minor_breaks)) {
-    return(NULL)
-  } else if (length(scale$minor_breaks) == 1 && !is.function(scale$minor_breaks) && is.na(scale$minor_breaks)) {
-    gg_dep("0.8.9", "minor_breaks = NA is deprecated. Please use minor_breaks = NULL to remove minor breaks in the scale.")
-    return(NULL)
-  } else if (is.waive(scale$minor_breaks)) {
-    if (is.null(b)) {
-      breaks <- NULL
-    } else {
-      b <- b[!is.na(b)]
-      if (length(b) < 2) return()
-
-      bd <- diff(b)[1]
-      if (min(limits) < min(b)) b <- c(b[1] - bd, b)
-      if (max(limits) > max(b)) b <- c(b, b[length(b)] + bd)
-      breaks <- unique(unlist(mapply(seq, b[-length(b)], b[-1], length=n+1,
-        SIMPLIFY = FALSE)))
-    }
-  } else if (is.function(scale$minor_breaks)) {
-    # Find breaks in data space, and convert to numeric
-    breaks <- scale$minor_breaks(scale$trans$inv(limits))
-    breaks <- scale$trans$trans(breaks)
-  } else {
-    breaks <- scale$minor_breaks
-  }
-
-  # Any minor breaks outside the dimensions need to be thrown away
-  discard(breaks, limits)
-}
-
-#' @export
-scale_breaks_minor.discrete <- function(...) NULL
-
-scale_breaks_minor_positions <- function(scale) {
-  scale_map(scale, scale_breaks_minor(scale))
-}
-
-scale_labels <- function(scale, breaks = scale_breaks(scale)) {
-  if (scale_is_empty(scale)) return(character())
-
-  UseMethod("scale_labels")
-}
-
-#' @export
-scale_labels.continuous <- function(scale, breaks = scale_breaks(scale)) {
-  if (is.null(breaks)) return(NULL)
-
-  breaks <- scale$trans$inv(breaks)
-
-  if (is.null(scale$labels)) {
-    return(NULL)
-  } else if (length(scale$labels) == 1 && !is.function(scale$labels) && is.na(scale$labels)) {
-    gg_dep("0.8.9", "labels = NA is deprecated. Please use labels = NULL to remove labels in the scale.")
-    return(NULL)
-  } else if (is.waive(scale$labels)) {
-    labels <- scale$trans$format(breaks)
-  } else if (is.function(scale$labels)) {
-    labels <- scale$labels(breaks)
-  } else {
-    labels <- scale$labels
-  }
-  if (length(labels) != length(breaks)) {
-    stop("Breaks and labels are different lengths")
-  }
-  labels
-}
-
-#' @export
-scale_labels.discrete <- function(scale, breaks = scale_breaks(scale)) {
-  if (is.null(breaks)) return(NULL)
-
-  if (is.null(scale$labels)) {
-    return(NULL)
-  } else if (length(scale$labels) == 1 && !is.function(scale$labels) && is.na(scale$labels)) {
-    gg_dep("0.8.9", "labels = NA is deprecated. Please use labels = NULL to remove labels in the scale.")
-    return(NULL)
-  }else if (is.waive(scale$labels)) {
-    format(scale_breaks(scale), justify = "none", trim = TRUE)
-  } else if (is.function(scale$labels)) {
-    scale$labels(breaks)
-  } else {
-    if (!is.null(names(scale$labels))) {
-      # If labels have names, use them to match with breaks
-      labels <- breaks
-
-      map <- match(names(scale$labels), labels, nomatch = 0)
-      labels[map] <- scale$labels[map != 0]
-      labels
-    } else {
-      labels <- scale$labels
-
-      # Need to ensure that if breaks were dropped, corresponding labels are too
-      pos <- attr(breaks, "pos")
-      if (!is.null(pos)) {
-        labels <- labels[pos]
-      }
-      labels
-    }
-
-  }
-}
-
-named_labels <- function(breaks, labels) {
-  breaks[match(names(labels), breaks, nomatch = 0)] <- labels
-  breaks
-}
-
-#' @export
-print.scale <- function(x, ...) {
-  print(x$call)
-}
-
-scale_clone <- function(scale) UseMethod("scale_clone")
-
-#' @export
-scale_clone.continuous <- function(scale) {
-  new <- scale
-  new$range <- ContinuousRange$new()
-  new
-}
-
-#' @export
-scale_clone.discrete <- function(scale) {
-  new <- scale
-  new$range <- DiscreteRange$new()
-  new
-}
-
-
-scale_break_info <- function(scale, range = NULL)  UseMethod("scale_break_info")
-#' @export
-scale_break_info.discrete <- function(scale, range = NULL) {
-
-  # for discrete, limits != range
-  limits <- scale_limits(scale)
-
-  major <- scale_breaks(scale, limits)
-  if (is.null(major)) {
-    labels <- major_n <- NULL
-  } else {
-
-    labels <- scale_labels(scale, major)
-    labels <- labels[!is.na(labels)]
-
-    major <- scale_map(scale, major)
-    major <- major[!is.na(major)]
-
-    # rescale breaks [0, 1], which are used by coord/guide
-    major_n <- rescale(major, from = range)
-  }
-
-  list(range = range, labels = labels,
-       major = major_n, minor = NULL,
-       major_source = major, minor_source = NULL)
-}
-#' @export
-scale_break_info.continuous <- function(scale, range = NULL) {
-  # range
-  if (is.null(range)) range <- scale_dimension(scale)
-
-  # major breaks
-  major <- scale_breaks(scale, range)
-
-  # labels
-  labels <- scale_labels(scale, major)
-
-  # drop oob breaks/labels by testing major == NA
-  if (!is.null(labels)) labels <- labels[!is.na(major)]
-  if (!is.null(major)) major <- major[!is.na(major)]
-
-  # minor breaks
-  minor <- scale_breaks_minor(scale, b = major, limits = range)
-  if (!is.null(minor)) minor <- minor[!is.na(minor)]
-
-  # rescale breaks [0, 1], which are used by coord/guide
-  major_n <- rescale(major, from = range)
-  minor_n <- rescale(minor, from = range)
-
-  list(range = range, labels = labels,
-       major = major_n, minor = minor_n,
-       major_source = major, minor_source = minor)
+  )
 }
diff --git a/R/scale-alpha.r b/R/scale-alpha.r
index 8d5599d..06026e4 100644
--- a/R/scale-alpha.r
+++ b/R/scale-alpha.r
@@ -9,13 +9,15 @@
 #' @param range range of output alpha values.  Should lie between 0 and 1.
 #' @export
 #' @examples
-#' (p <- qplot(mpg, cyl, data = mtcars, alpha = cyl))
+#' (p <- ggplot(mtcars, aes(mpg, cyl)) +
+#'   geom_point(aes(alpha = cyl)))
 #' p + scale_alpha("cylinders")
 #' p + scale_alpha("number\nof\ncylinders")
 #'
 #' p + scale_alpha(range = c(0.4, 0.8))
 #'
-#' (p <- qplot(mpg, cyl, data=mtcars, alpha = factor(cyl)))
+#' (p <- ggplot(mtcars, aes(mpg, cyl)) +
+#'   geom_point(aes(alpha = factor(cyl))))
 #' p + scale_alpha_discrete(range = c(0.4, 0.8))
 scale_alpha <- function(..., range = c(0.1, 1)) {
   continuous_scale("alpha", "alpha_c", rescale_pal(range), ...)
@@ -29,5 +31,5 @@ scale_alpha_continuous <- scale_alpha
 #' @export
 scale_alpha_discrete <- function(..., range = c(0.1, 1)) {
   discrete_scale("alpha", "alpha_d",
-    function(n) seq(range[1], range[2], length = n), ...)
+    function(n) seq(range[1], range[2], length.out = n), ...)
 }
diff --git a/R/scale-area.r b/R/scale-area.r
deleted file mode 100644
index a469f37..0000000
--- a/R/scale-area.r
+++ /dev/null
@@ -1,18 +0,0 @@
-#' Scale area instead of radius (for size).
-#'
-#' \code{\link{scale_area}} is deprecated and will be removed in a future
-#' version of ggplot2. Use \code{\link{scale_size_area}} instead. Note that the
-#' default behavir of \code{\link{scale_size_area}} is slightly different: by
-#' default, it makes the area proportional to the numeric value.
-#'
-#' @param ... Other arguments passed on to \code{\link{continuous_scale}}
-#'   to control name, limits, breaks, labels and so forth.
-#' @param range Range of output sizes.  Should be greater than 0.
-#' @export
-scale_area <- function(..., range = c(1, 6)) {
-  gg_dep("0.9.2", paste(sep = "\n",
-    "scale_area is deprecated. Use scale_size_area instead.",
-    "  Note that the behavior of scale_size_area is slightly different:",
-    "  by default it makes the area proportional to the numeric value."))
-  continuous_scale("size", "area", area_pal(range), ...)
-}
diff --git a/R/scale-brewer.r b/R/scale-brewer.r
index aa73238..70d5b90 100644
--- a/R/scale-brewer.r
+++ b/R/scale-brewer.r
@@ -8,85 +8,90 @@
 #' more saturated colours which do not look as good). However, the original
 #' colour schemes (particularly the qualitative ones) were not intended for this
 #' and the perceptual result is left to the appreciation of the user.
-#'
 #' See \url{http://colorbrewer2.org} for more information.
 #'
+#' @section Palettes:
+#' The following palettes are available for use with these scales:
+#' \describe{
+#'   \item{Diverging}{BrBG, PiYG, PRGn, PuOr, RdBu, RdGy, RdYlBu, RdYlGn, Spectral}
+#'   \item{Qualitative}{Accent, Dark2, Paired, Pastel1, Pastel2, Set1, Set2, Set3}
+#'   \item{Sequential}{Blues, BuGn, BuPu, GnBu, Greens, Greys, Oranges,
+#'      OrRd, PuBu, PuBuGn, PuRd, Purples, RdPu, Reds, YlGn, YlGnBu, YlOrBr, YlOrRd}
+#' }
+#'
 #' @inheritParams scales::brewer_pal
 #' @inheritParams scale_colour_hue
 #' @inheritParams scale_colour_gradient
 #' @inheritParams scales::gradient_n_pal
-#' @family colour scales
+#' @seealso Other colour scales:
+#'   \code{\link{scale_colour_gradient}},
+#'   \code{\link{scale_colour_grey}},
+#'   \code{\link{scale_colour_hue}}
 #' @rdname scale_brewer
 #' @export
 #' @examples
 #' dsamp <- diamonds[sample(nrow(diamonds), 1000), ]
-#' (d <- qplot(carat, price, data = dsamp, colour = clarity))
+#' (d <- ggplot(dsamp, aes(carat, price)) +
+#'   geom_point(aes(colour = clarity)))
 #'
 #' # Change scale label
 #' d + scale_colour_brewer()
-#' d + scale_colour_brewer("clarity")
-#' d + scale_colour_brewer(expression(clarity[beta]))
+#' d + scale_colour_brewer("Diamond\nclarity")
 #'
 #' # Select brewer palette to use, see ?scales::brewer_pal for more details
-#' d + scale_colour_brewer(type = "seq")
-#' d + scale_colour_brewer(type = "seq", palette = 3)
-#'
-#' d + scale_colour_brewer(palette = "Blues")
+#' d + scale_colour_brewer(palette = "Greens")
 #' d + scale_colour_brewer(palette = "Set1")
 #'
+#' \donttest{
 #' # scale_fill_brewer works just the same as
 #' # scale_colour_brewer but for fill colours
-#' ggplot(diamonds, aes(x = price, fill = cut)) +
-#'   geom_histogram(position = "dodge", binwidth = 1000) +
-#'   scale_fill_brewer()
-#'
-#' # Generate map data
-#' library(reshape2) # for melt
-#' volcano3d <- melt(volcano)
-#' names(volcano3d) <- c("x", "y", "z")
+#' p <- ggplot(diamonds, aes(x = price, fill = cut)) +
+#'   geom_histogram(position = "dodge", binwidth = 1000)
+#' p + scale_fill_brewer()
+#' # the order of colour can be reversed
+#' p + scale_fill_brewer(direction = -1)
+#' # the brewer scales look better on a darker background
+#' p + scale_fill_brewer(direction = -1) + theme_dark()
+#' }
 #'
-#' # Basic plot
-#' v <- ggplot() + geom_tile(aes(x = x, y = y, fill = z), data = volcano3d)
+#' # Use distiller variant with continous data
+#' v <- ggplot(faithfuld) +
+#'   geom_tile(aes(waiting, eruptions, fill = density))
 #' v
 #' v + scale_fill_distiller()
-#' v + scale_fill_distiller(palette = 2)
-#' v + scale_fill_distiller(type = "div")
 #' v + scale_fill_distiller(palette = "Spectral")
-#' v + scale_fill_distiller(palette = "Spectral", trans = "reverse")
-#' v + scale_fill_distiller(type = "qual")
-#' # Not appropriate for continuous data, issues a warning
-scale_colour_brewer <- function(..., type = "seq", palette = 1) {
-  discrete_scale("colour", "brewer", brewer_pal(type, palette), ...)
+scale_colour_brewer <- function(..., type = "seq", palette = 1, direction = 1) {
+  discrete_scale("colour", "brewer", brewer_pal(type, palette, direction), ...)
 }
 
 #' @export
 #' @rdname scale_brewer
-scale_fill_brewer <- function(..., type = "seq", palette = 1) {
-  discrete_scale("fill", "brewer", brewer_pal(type, palette), ...)
+scale_fill_brewer <- function(..., type = "seq", palette = 1, direction = 1) {
+  discrete_scale("fill", "brewer", brewer_pal(type, palette, direction), ...)
 }
 
 #' @export
 #' @rdname scale_brewer
-scale_colour_distiller <- function(..., type = "seq", palette = 1, values = NULL, space = "Lab", na.value = "grey50") {
+scale_colour_distiller <- function(..., type = "seq", palette = 1, direction = -1, values = NULL, space = "Lab", na.value = "grey50", guide = "colourbar") {
   # warn about using a qualitative brewer palette to generate the gradient
   type <- match.arg(type, c("seq", "div", "qual"))
   if (type == "qual") {
     warning("Using a discrete colour palette in a continuous scale.\n  Consider using type = \"seq\" or type = \"div\" instead", call. = FALSE)
   }
   continuous_scale("colour", "distiller",
-    gradient_n_pal(brewer_pal(type, palette)(6), values, space), na.value = na.value, ...)
+    gradient_n_pal(brewer_pal(type, palette, direction)(6), values, space), na.value = na.value, guide = guide, ...)
   # NB: 6 colours per palette gives nice gradients; more results in more saturated colours which do not look as good
 }
 
 #' @export
 #' @rdname scale_brewer
-scale_fill_distiller <- function(..., type = "seq", palette = 1, values = NULL, space = "Lab", na.value = "grey50") {
+scale_fill_distiller <- function(..., type = "seq", palette = 1, direction = -1, values = NULL, space = "Lab", na.value = "grey50", guide = "colourbar") {
   type <- match.arg(type, c("seq", "div", "qual"))
   if (type == "qual") {
     warning("Using a discrete colour palette in a continuous scale.\n  Consider using type = \"seq\" or type = \"div\" instead", call. = FALSE)
   }
   continuous_scale("fill", "distiller",
-    gradient_n_pal(brewer_pal(type, palette)(6), values, space), na.value = na.value, ...)
+    gradient_n_pal(brewer_pal(type, palette, direction)(6), values, space), na.value = na.value, guide = guide, ...)
 }
 
 # icon.brewer <- function() {
diff --git a/R/scale-continuous.r b/R/scale-continuous.r
index 123acd0..c6f3c22 100644
--- a/R/scale-continuous.r
+++ b/R/scale-continuous.r
@@ -1,29 +1,29 @@
 #' Continuous position scales (x & y).
 #'
-#' @param ... common continuous scale parameters: \code{name}, \code{breaks},
-#'  \code{labels}, \code{na.value}, \code{limits} and \code{trans}.  See
-#'  \code{\link{continuous_scale}} for more details
-#' @param expand a numeric vector of length two giving multiplicative and
-#'   additive expansion constants. These constants ensure that the data is
-#'   placed some distance away from the axes.
-#' @family position scales
-#' @rdname scale_continuous
-#' @export
+#' \code{scale_x_continuous} and \code{scale_y_continuous} are the key functions.
+#' The others, \code{scale_x_log10}, \code{scale_y_sqrt} etc, are aliases
+#' that set the \code{trans} argument to commonly used transformations.
+#'
+#' @inheritParams continuous_scale
+#' @seealso \code{\link{scale_date}} for date/time position scales.
+#' @param ... Other arguments passed on to \code{scale_(x|y)_continuous}
 #' @examples
 #' \donttest{
-#' (m <- qplot(rating, votes, data=subset(movies, votes > 1000),
-#'   na.rm = TRUE))
+#' if (require(ggplot2movies)) {
+#' m <- ggplot(subset(movies, votes > 1000), aes(rating, votes)) +
+#'   geom_point(na.rm = TRUE)
+#' m
 #'
 #' # Manipulating the default position scales lets you:
 #'
 #' #  * change the axis labels
 #' m + scale_y_continuous("number of votes")
-#' m + scale_y_continuous(expression(votes^alpha))
+#' m + scale_y_continuous(quote(votes ^ alpha))
 #'
 #' #  * modify the axis limits
-#' m + scale_y_continuous(limits=c(0, 5000))
-#' m + scale_y_continuous(limits=c(1000, 10000))
-#' m + scale_x_continuous(limits=c(7, 8))
+#' m + scale_y_continuous(limits = c(0, 5000))
+#' m + scale_y_continuous(limits = c(1000, 10000))
+#' m + scale_x_continuous(limits = c(7, 8))
 #'
 #' # you can also use the short hand functions xlim and ylim
 #' m + ylim(0, 5000)
@@ -31,60 +31,108 @@
 #' m + xlim(7, 8)
 #'
 #' #  * choose where the ticks appear
-#' m + scale_x_continuous(breaks=1:10)
-#' m + scale_x_continuous(breaks=c(1,3,7,9))
+#' m + scale_x_continuous(breaks = 1:10)
+#' m + scale_x_continuous(breaks = c(1,3,7,9))
 #'
 #' #  * manually label the ticks
-#' m + scale_x_continuous(breaks=c(2,5,8), labels=c("two", "five", "eight"))
-#' m + scale_x_continuous(breaks=c(2,5,8), labels=c("horrible", "ok", "awesome"))
-#' m + scale_x_continuous(breaks=c(2,5,8), labels=expression(Alpha, Beta, Omega))
+#' m + scale_x_continuous(breaks = c(2,5,8), labels = c("two", "five", "eight"))
+#' m + scale_x_continuous(breaks = c(2,5,8), labels = c("horrible", "ok", "awesome"))
+#' m + scale_x_continuous(breaks = c(2,5,8), labels = expression(Alpha, Beta, Omega))
 #'
 #' # There are a few built in transformation that you can use:
 #' m + scale_y_log10()
 #' m + scale_y_sqrt()
 #' m + scale_y_reverse()
 #' # You can also create your own and supply them to the trans argument.
-#' # See ?scale::trans_new
+#' # See ?scales::trans_new
 #'
 #' # You can control the formatting of the labels with the formatter
 #' # argument.  Some common formats are built into the scales package:
-#' x <- rnorm(10) * 100000
-#' y <- seq(0, 1, length = 10)
-#' p <- qplot(x, y)
-#' library(scales)
-#' p + scale_y_continuous(labels = percent)
-#' p + scale_y_continuous(labels = dollar)
-#' p + scale_x_continuous(labels = comma)
+#' df <- data.frame(
+#'   x = rnorm(10) * 100000,
+#'   y = seq(0, 1, length.out = 10)
+#' )
+#' p <- ggplot(df, aes(x, y)) + geom_point()
+#' p + scale_y_continuous(labels = scales::percent)
+#' p + scale_y_continuous(labels = scales::dollar)
+#' p + scale_x_continuous(labels = scales::comma)
 #'
-#' # qplot allows you to do some of this with a little less typing:
-#' #   * axis limits
-#' qplot(rating, votes, data=movies, ylim=c(1e4, 5e4))
+#' # Other shortcut functions
+#' ggplot(movies, aes(rating, votes)) +
+#'   geom_point() +
+#'   ylim(1e4, 5e4)
 #' #   * axis labels
-#' qplot(rating, votes, data=movies, xlab="My x axis", ylab="My y axis")
+#' ggplot(movies, aes(rating, votes)) +
+#'   geom_point() +
+#'   labs(x = "My x axis", y = "My y axis")
 #' #   * log scaling
-#' qplot(rating, votes, data=movies, log="xy")
+#' ggplot(movies, aes(rating, votes)) +
+#'   geom_point() +
+#'   scale_x_log10() +
+#'   scale_y_log10()
 #' }
-scale_x_continuous <- function(..., expand = waiver()) {
-  continuous_scale(c("x", "xmin", "xmax", "xend", "xintercept"), "position_c", identity,
-    ..., expand = expand, guide = "none")
+#' }
+#' @name scale_continuous
+NULL
+
+#' @rdname scale_continuous
+#' @export
+scale_x_continuous <- function(name = waiver(), breaks = waiver(),
+                               minor_breaks = waiver(), labels = waiver(),
+                               limits = NULL, expand = waiver(), oob = censor,
+                               na.value = NA_real_, trans = "identity") {
+  sc <- continuous_scale(
+    c("x", "xmin", "xmax", "xend", "xintercept"),
+    "position_c", identity, name = name, breaks = breaks,
+    minor_breaks = minor_breaks, labels = labels, limits = limits,
+    expand = expand, oob = oob, na.value = na.value, trans = trans,
+    guide = "none"
+  )
+
+  # TODO: Fix this hack. We're reassigning the parent ggproto object, but this
+  # object should in the first place be created with the correct parent.
+  sc$super <- ScaleContinuousPosition
+  class(sc) <- class(ScaleContinuousPosition)
+
+  sc
 }
 
 #' @rdname scale_continuous
 #' @export
-scale_y_continuous <- function(..., expand = waiver()) {
-  continuous_scale(c("y", "ymin", "ymax", "yend", "yintercept", "ymin_final", "ymax_final"), "position_c", identity,
-    ..., expand = expand, guide = "none")
+scale_y_continuous <- function(name = waiver(), breaks = waiver(),
+                               minor_breaks = waiver(), labels = waiver(),
+                               limits = NULL, expand = waiver(), oob = censor,
+                               na.value = NA_real_, trans = "identity") {
+  sc <- continuous_scale(
+    c("y", "ymin", "ymax", "yend", "yintercept", "ymin_final", "ymax_final", "lower", "middle", "upper"),
+    "position_c", identity, name = name, breaks = breaks,
+    minor_breaks = minor_breaks, labels = labels, limits = limits,
+    expand = expand, oob = oob, na.value = na.value, trans = trans,
+    guide = "none"
+  )
+
+  # TODO: Fix this hack. We're reassigning the parent ggproto object, but this
+  # object should in the first place be created with the correct parent.
+  sc$super <- ScaleContinuousPosition
+  class(sc) <- class(ScaleContinuousPosition)
+
+  sc
 }
 
 
-# Position aesthetics don't map, because the coordinate system takes
-# care of it. But they do need to be made in to doubles, so stat methods
-# can tell the difference between continuous and discrete data.
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
 #' @export
-scale_map.position_c <- function(scale, x, limits = scale_limits(scale)) {
-  scaled <- as.numeric(scale$oob(x, limits))
-  ifelse(!is.na(scaled), scaled, scale$na.value)
-}
+ScaleContinuousPosition <- ggproto("ScaleContinuousPosition", ScaleContinuous,
+  # Position aesthetics don't map, because the coordinate system takes
+  # care of it. But they do need to be made in to doubles, so stat methods
+  # can tell the difference between continuous and discrete data.
+  map = function(self, x, limits = self$get_limits()) {
+    scaled <- as.numeric(self$oob(x, limits))
+    ifelse(!is.na(scaled), scaled, self$na.value)
+  }
+)
 
 # Transformed scales ---------------------------------------------------------
 
diff --git a/R/scale-date.r b/R/scale-date.r
index 03b2b6a..a437adf 100644
--- a/R/scale-date.r
+++ b/R/scale-date.r
@@ -1,112 +1,162 @@
-#' Position scale, date
+#' Position scale, date & date times
 #'
-#' @rdname scale_date
-#' @inheritParams scale_x_continuous
-#' @param breaks  A vector of breaks, a function that given the scale limits
-#'   returns a vector of breaks, or a character vector, specifying the width
-#'   between breaks. For more information about the first two, see
-#'   \code{\link{continuous_scale}}, for more information about the last,
-#'   see \code{\link[scales]{date_breaks}}`.
-#' @param minor_breaks Either \code{NULL} for no minor breaks, \code{waiver()}
-#'   for the default breaks (one minor break between each major break), a
-#'   numeric vector of positions, or a function that given the limits returns
-#'   a vector of minor breaks.
-#' @family position scales
-#' @export
+#' Use \code{scale_*_date} with \code{Date} variables, and
+#' \code{scale_*_datetime} with \code{POSIXct} variables.
+#'
+#' @name scale_date
+#' @inheritParams continuous_scale
+#' @param date_breaks A string giving the distance between breaks like "2
+#'   weeks", or "10 years". If both \code{breaks} and \code{date_breaks} are
+#'   specified, \code{date_breaks} wins.
+#' @param date_minor_breaks A string giving the distance between minor breaks
+#'   like "2 weeks", or "10 years". If both \code{minor_breaks} and
+#'   \code{date_minor_breaks} are specified, \code{date_minor_breaks} wins.
+#' @param date_labels A string giving the formatting specification for the
+#'   labels. Codes are defined in \code{\link{strftime}}. If both \code{labels}
+#'   and \code{date_labels} are specified, \code{date_labels} wins.
+#' @seealso \code{\link{scale_continuous}} for continuous position scales.
 #' @examples
-#' # We'll start by creating some nonsense data with dates
+#' last_month <- Sys.Date() - 0:29
 #' df <- data.frame(
-#'   date = seq(Sys.Date(), len=100, by="1 day")[sample(100, 50)],
-#'   price = runif(50)
+#'   date = last_month,
+#'   price = runif(30)
 #' )
-#' df <- df[order(df$date), ]
-#' dt <- qplot(date, price, data=df, geom="line") + theme(aspect.ratio = 1/4)
-#'
-#' # We can control the format of the labels, and the frequency of
-#' # the major and minor tickmarks.  See ?format.Date and ?seq.Date
-#' # for more details.
-#' library(scales) # to access breaks/formatting functions
-#' dt + scale_x_date()
-#' dt + scale_x_date(labels = date_format("%m/%d"))
-#' dt + scale_x_date(labels = date_format("%W"))
-#' dt + scale_x_date(labels = date_format("%W"), breaks = date_breaks("week"))
-#'
-#' dt + scale_x_date(breaks = date_breaks("months"),
-#'   labels = date_format("%b"))
-#' dt + scale_x_date(breaks = date_breaks("4 weeks"),
-#'   labels = date_format("%d-%b"))
-#'
-#' # We can use character string for breaks.
-#' # See \code{\link{by}} argument in \code{\link{seq.Date}}.
-#' dt + scale_x_date(breaks = "2 weeks")
-#' dt + scale_x_date(breaks = "1 month", minor_breaks = "1 week")
+#' base <- ggplot(df, aes(date, price)) +
+#'   geom_line()
 #'
 #' # The date scale will attempt to pick sensible defaults for
-#' # major and minor tick marks
-#' qplot(date, price, data=df[1:10,], geom="line")
-#' qplot(date, price, data=df[1:4,], geom="line")
-#'
-#' df <- data.frame(
-#'   date = seq(Sys.Date(), len=1000, by="1 day"),
-#'   price = runif(500)
-#' )
-#' qplot(date, price, data=df, geom="line")
-#'
-#' # A real example using economic time series data
-#' qplot(date, psavert, data=economics)
-#' qplot(date, psavert, data=economics, geom="path")
+#' # major and minor tick marks. Override with date_breaks, date_labels
+#' # date_minor_breaks arguments.
+#' base + scale_x_date(date_labels = "%b %d")
+#' base + scale_x_date(date_breaks = "1 week", date_labels = "%W")
+#' base + scale_x_date(date_minor_breaks = "1 day")
 #'
-#' end <- max(economics$date)
-#' last_plot() + scale_x_date(limits = c(as.Date("2000-1-1"), end))
-#' last_plot() + scale_x_date(limits = c(as.Date("2005-1-1"), end))
-#' last_plot() + scale_x_date(limits = c(as.Date("2006-1-1"), end))
-#'
-#' # If we want to display multiple series, one for each variable
-#' # it's easiest to first change the data from a "wide" to a "long"
-#' # format:
-#' library(reshape2) # for melt
-#' em <- melt(economics, id = "date")
-#'
-#' # Then we can group and facet by the new "variable" variable
-#' qplot(date, value, data = em, geom = "line", group = variable)
-#' qplot(date, value, data = em, geom = "line", group = variable) +
-#'   facet_grid(variable ~ ., scale = "free_y")
-scale_x_date <- function(..., expand = waiver(), breaks = pretty_breaks(),
-  minor_breaks = waiver()) {
-
-  scale_date(c("x", "xmin", "xmax", "xend"), expand = expand, breaks = breaks,
-    minor_breaks = minor_breaks, ...)
+#' # Set limits
+#' base + scale_x_date(limits = c(Sys.Date() - 7, NA))
+NULL
+
+#' @rdname scale_date
+#' @export
+scale_x_date <- function(name = waiver(),
+                         breaks = waiver(), date_breaks = waiver(),
+                         labels = waiver(), date_labels = waiver(),
+                         minor_breaks = waiver(), date_minor_breaks = waiver(),
+                         limits = NULL, expand = waiver()) {
+
+  scale_datetime(c("x", "xmin", "xmax", "xend"), "date",
+    name = name,
+    breaks = breaks, date_breaks = date_breaks,
+    labels = labels, date_labels = date_labels,
+    minor_breaks = minor_breaks, date_minor_breaks = date_minor_breaks,
+    limits = limits, expand = expand
+  )
 }
 
 #' @rdname scale_date
 #' @export
-scale_y_date <- function(..., expand = waiver(), breaks = pretty_breaks(),
-  minor_breaks = waiver()) {
+scale_y_date <- function(name = waiver(),
+                         breaks = waiver(), date_breaks = waiver(),
+                         labels = waiver(), date_labels = waiver(),
+                         minor_breaks = waiver(), date_minor_breaks = waiver(),
+                         limits = NULL, expand = waiver()) {
 
-  scale_date(c("y", "ymin", "ymax", "yend"), expand = expand, breaks = breaks,
-    minor_breaks = minor_breaks, ...)
+  scale_datetime(c("y", "ymin", "ymax", "yend"), "date",
+    name = name,
+    breaks = breaks, date_breaks = date_breaks,
+    labels = labels, date_labels = date_labels,
+    minor_breaks = minor_breaks, date_minor_breaks = date_minor_breaks,
+    limits = limits, expand = expand
+  )
 }
 
-# base class for scale_{xy}_date
-scale_date <- function(aesthetics, expand = waiver(), breaks = pretty_breaks(),
-  minor_breaks = waiver(), ...) {
 
-  if (is.character(breaks)) {
-    breaks_str <- breaks
-    breaks <- date_breaks(breaks_str)
-  }
+#' @export
+#' @rdname scale_date
+scale_x_datetime <- function(name = waiver(),
+                             breaks = waiver(), date_breaks = waiver(),
+                             labels = waiver(), date_labels = waiver(),
+                             minor_breaks = waiver(), date_minor_breaks = waiver(),
+                             limits = NULL, expand = waiver()) {
 
-  if (is.character(minor_breaks)) {
-    mbreaks_str <- minor_breaks
-    minor_breaks <- date_breaks(mbreaks_str)
+  scale_datetime(c("x", "xmin", "xmax", "xend"), "time",
+    name = name,
+    breaks = breaks, date_breaks = date_breaks,
+    labels = labels, date_labels = date_labels,
+    minor_breaks = minor_breaks, date_minor_breaks = date_minor_breaks,
+    limits = limits, expand = expand
+  )
+}
+
+
+#' @rdname scale_date
+#' @export
+scale_y_datetime <- function(name = waiver(),
+                             breaks = waiver(), date_breaks = waiver(),
+                             labels = waiver(), date_labels = waiver(),
+                             minor_breaks = waiver(), date_minor_breaks = waiver(),
+                             limits = NULL, expand = waiver()) {
+
+  scale_datetime(c("y", "ymin", "ymax", "yend"), "time",
+    name = name,
+    breaks = breaks, date_breaks = date_breaks,
+    labels = labels, date_labels = date_labels,
+    minor_breaks = minor_breaks, date_minor_breaks = date_minor_breaks,
+    limits = limits, expand = expand
+  )
+}
+
+scale_datetime <- function(aesthetics, trans,
+                           breaks = pretty_breaks(), minor_breaks = waiver(),
+                           labels = waiver(), date_breaks = waiver(),
+                           date_labels = waiver(),
+                           date_minor_breaks = waiver(),
+                           ...) {
+
+  name <- switch(trans, date = "date", time = "datetime")
+
+  # Backward compatibility
+  if (is.character(breaks)) breaks <- date_breaks(breaks)
+  if (is.character(minor_breaks)) minor_breaks <- date_breaks(minor_breaks)
+
+  if (!is.waive(date_breaks)) {
+    breaks <- date_breaks(date_breaks)
   }
+  if (!is.waive(date_minor_breaks)) {
+    minor_breaks <- date_breaks(date_minor_breaks)
+  }
+  if (!is.waive(date_labels)) {
+    labels <- date_format(date_labels)
+  }
+
+  sc <- continuous_scale(aesthetics, name, identity,
+    breaks = breaks, minor_breaks = minor_breaks, labels = labels,
+    guide = "none", trans = trans, ...)
 
-  continuous_scale(aesthetics, "date", identity, breaks = breaks,
-    minor_breaks = minor_breaks, guide = "none", expand = expand,
-    trans = "date", ...)
+  # TODO: Fix this hack. We're reassigning the parent ggproto object, but this
+  # object should in the first place be created with the correct parent.
+  scale_class <- switch(trans, date = ScaleContinuousDate, time = ScaleContinuousDatetime)
+  sc$super <- scale_class
+  class(sc) <- class(scale_class)
+  sc
 }
 
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
 #' @export
-scale_map.date <- function(scale, x, limits = scale_limits(scale)) {
-  x
-}
+ScaleContinuousDatetime <- ggproto("ScaleContinuousDatetime", ScaleContinuous,
+  map = function(self, x, limits = self$get_limits()) {
+    self$oob(x, limits)
+  }
+)
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+ScaleContinuousDate <- ggproto("ScaleContinuousDate", ScaleContinuous,
+  map = function(self, x, limits = self$get_limits()) {
+    self$oob(x, limits)
+  }
+)
diff --git a/R/scale-datetime.r b/R/scale-datetime.r
deleted file mode 100644
index 1283114..0000000
--- a/R/scale-datetime.r
+++ /dev/null
@@ -1,92 +0,0 @@
-#' Position scale, date
-#'
-#' @rdname scale_datetime
-#' @family position scales
-#' @inheritParams scale_x_continuous
-#' @param breaks  A vector of breaks, a function that given the scale limits
-#'   returns a vector of breaks, or a character vector, specifying the width
-#'   between breaks. For more information about the first two, see
-#'   \code{\link{continuous_scale}}, for more information about the last,
-#'   see \code{\link[scales]{date_breaks}}.
-#' @param minor_breaks Either \code{NULL} for no minor breaks, \code{waiver()}
-#'   for the default breaks (one minor break between each major break), a
-#'   numeric vector of positions, or a function that given the limits returns
-#'   a vector of minor breaks.
-#' @export
-#' @examples
-#' start <- ISOdate(2001, 1, 1, tz = "")
-#' df <- data.frame(
-#'   day30  = start + round(runif(100, max = 30 * 86400)),
-#'   day7  = start + round(runif(100, max = 7 * 86400)),
-#'   day   = start + round(runif(100, max = 86400)),
-#'   hour10 = start + round(runif(100, max = 10 * 3600)),
-#'   hour5 = start + round(runif(100, max = 5 * 3600)),
-#'   hour  = start + round(runif(100, max = 3600)),
-#'   min10 = start + round(runif(100, max = 10 * 60)),
-#'   min5  = start + round(runif(100, max = 5 * 60)),
-#'   min   = start + round(runif(100, max = 60)),
-#'   sec10 = start + round(runif(100, max = 10)),
-#'   y = runif(100)
-#' )
-#'
-#' # Automatic scale selection
-#' qplot(sec10, y, data = df)
-#' qplot(min, y, data = df)
-#' qplot(min5, y, data = df)
-#' qplot(min10, y, data = df)
-#' qplot(hour, y, data = df)
-#' qplot(hour5, y, data = df)
-#' qplot(hour10, y, data = df)
-#' qplot(day, y, data = df)
-#' qplot(day30, y, data = df)
-#'
-#' # Manual scale selection
-#' qplot(day30, y, data = df)
-#' library(scales) # to access breaks/formatting functions
-#' last_plot() + scale_x_datetime(breaks = date_breaks("2 weeks"))
-#' last_plot() + scale_x_datetime(breaks = date_breaks("10 days"))
-#' library(scales) # to access breaks/formatting functions
-#' last_plot() + scale_x_datetime(breaks = date_breaks("10 days"),
-#'   labels = date_format("%d/%m"))
-#' last_plot() + scale_x_datetime(breaks = date_breaks("1 day"),
-#'   minor_breaks = date_breaks("2 hour"))
-scale_x_datetime <- function(..., expand = waiver(), breaks = pretty_breaks(),
-  minor_breaks = waiver()) {
-
-  scale_datetime(c("x", "xmin", "xmax", "xend"), expand = expand,
-    breaks = breaks, minor_breaks = minor_breaks, ...)
-}
-
-#' @export
-scale_map.datetime <- function(scale, x, limits = scale_limits(scale)) {
-  x
-}
-
-#' @rdname scale_datetime
-#' @export
-scale_y_datetime <- function(..., expand = waiver(), breaks = pretty_breaks(),
-  minor_breaks = waiver()) {
-
-  scale_datetime(c("y", "ymin", "ymax", "yend"), expand = expand,
-    breaks = breaks, minor_breaks = minor_breaks, ...)
-}
-
-
-# base class for scale_{xy}_datetime
-scale_datetime <- function(aesthetics, expand = waiver(), breaks = pretty_breaks(),
-  minor_breaks = waiver(), ...) {
-
-  if (is.character(breaks)) {
-    breaks_str <- breaks
-    breaks <- date_breaks(breaks_str)
-  }
-
-  if (is.character(minor_breaks)) {
-    mbreaks_str <- minor_breaks
-    minor_breaks <- date_breaks(mbreaks_str)
-  }
-
-  continuous_scale(aesthetics, "datetime", identity, breaks = breaks,
-    minor_breaks = minor_breaks, guide = "none", expand = expand,
-    trans = "time", ...)
-}
diff --git a/R/scale-discrete-.r b/R/scale-discrete-.r
index 393e52d..01dc58d 100644
--- a/R/scale-discrete-.r
+++ b/R/scale-discrete-.r
@@ -6,7 +6,6 @@
 #' level, and increasing by one for each level (i.e. the labels are placed
 #' at integer positions).  This is what allows jittering to work.
 #'
-#'
 #' @param ... common discrete scale parameters: \code{name}, \code{breaks},
 #'  \code{labels}, \code{na.value}, \code{limits} and \code{guide}.  See
 #'  \code{\link{discrete_scale}} for more details
@@ -14,17 +13,17 @@
 #'   additive expansion constants. These constants ensure that the data is
 #'   placed some distance away from the axes.
 #' @rdname scale_discrete
-#' @family position scales
 #' @export
 #' @examples
 #' \donttest{
-#' qplot(cut, data=diamonds, stat="bin")
-#' qplot(cut, data=diamonds, geom="bar")
+#' ggplot(diamonds, aes(cut)) + stat_bin()
+#' ggplot(diamonds, aes(cut)) + geom_bar()
 #'
 #' # The discrete position scale is added automatically whenever you
 #' # have a discrete position.
 #'
-#' (d <- qplot(cut, clarity, data=subset(diamonds, carat > 1), geom="jitter"))
+#' (d <- ggplot(subset(diamonds, carat > 1), aes(cut, clarity)) +
+#'       geom_jitter())
 #'
 #' d + scale_x_discrete("Cut")
 #' d + scale_x_discrete("Cut", labels = c("Fair" = "F","Good" = "G",
@@ -42,19 +41,25 @@
 #' d + ylim("I1", "IF")
 #'
 #' # See ?reorder to reorder based on the values of another variable
-#' qplot(manufacturer, cty, data=mpg)
-#' qplot(reorder(manufacturer, cty), cty, data=mpg)
-#' qplot(reorder(manufacturer, displ), cty, data=mpg)
+#' ggplot(mpg, aes(manufacturer, cty)) + geom_point()
+#' ggplot(mpg, aes(reorder(manufacturer, cty), cty)) + geom_point()
+#' ggplot(mpg, aes(reorder(manufacturer, displ), cty)) + geom_point()
 #'
 #' # Use abbreviate as a formatter to reduce long names
-#' qplot(reorder(manufacturer, cty), cty, data=mpg) +
+#' ggplot(mpg, aes(reorder(manufacturer, displ), cty)) +
+#'   geom_point() +
 #'   scale_x_discrete(labels = abbreviate)
 #' }
 scale_x_discrete <- function(..., expand = waiver()) {
   sc <- discrete_scale(c("x", "xmin", "xmax", "xend"), "position_d", identity, ...,
     expand = expand, guide = "none")
 
-  sc$range_c <- ContinuousRange$new()
+  # TODO: Fix this hack. We're reassigning the parent ggproto object, but this
+  # object should in the first place be created with the correct parent.
+  sc$super <- ScaleDiscretePosition
+  class(sc) <- class(ScaleDiscretePosition)
+
+  sc$range_c <- continuous_range()
   sc
 }
 #' @rdname scale_discrete
@@ -62,7 +67,13 @@ scale_x_discrete <- function(..., expand = waiver()) {
 scale_y_discrete <- function(..., expand = waiver()) {
   sc <- discrete_scale(c("y", "ymin", "ymax", "yend"), "position_d", identity, ...,
     expand = expand, guide = "none")
-  sc$range_c <- ContinuousRange$new()
+
+  # TODO: Fix this hack. We're reassigning the parent ggproto object, but this
+  # object should in the first place be created with the correct parent.
+  sc$super <- ScaleDiscretePosition
+  class(sc) <- class(ScaleDiscretePosition)
+
+  sc$range_c <- continuous_range()
   sc
 }
 
@@ -71,61 +82,64 @@ scale_y_discrete <- function(..., expand = waiver()) {
 # mapping, but makes it possible to place objects at non-integer positions,
 # as is necessary for jittering etc.
 
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
 #' @export
-scale_train.position_d <- function(scale, x) {
-  if (is.discrete(x)) {
-    scale$range$train(x, drop = scale$drop)
-  } else {
-    scale$range_c$train(x)
-  }
-}
+ScaleDiscretePosition <- ggproto("ScaleDiscretePosition", ScaleDiscrete,
 
-# If range not available from discrete range, implies discrete scale been
-# used with purely continuous data, so construct limits accordingly
-#' @export
-scale_limits.position_d <- function(scale) {
-  dis_limits <- function(x) seq.int(floor(min(x)), ceiling(max(x)), by = 1L)
+  train = function(self, x) {
+    if (is.discrete(x)) {
+      self$range$train(x, drop = self$drop)
+    } else {
+      self$range_c$train(x)
+    }
+  },
 
-  scale$limits %||% scale$range$range %||% dis_limits(scale$range_c$range)
-}
+  # If range not available from discrete range, implies discrete scale been
+  # used with purely continuous data, so construct limits accordingly
+  get_limits = function(self) {
+    if (self$is_empty()) return(c(0, 1))
 
-#' @export
-scale_is_empty.position_d <- function(scale) {
-  NextMethod() && is.null(scale$range_c$range)
-}
+    dis_limits <- function(x) seq.int(floor(min(x)), ceiling(max(x)), by = 1L)
 
-#' @export
-scale_reset.position_d <- function(scale, x) {
-  # Can't reset discrete scale because no way to recover values
-  scale$range_c$reset()
-}
+    self$limits %||% self$range$range %||% dis_limits(self$range_c$range)
+  },
 
+  is_empty = function(self) {
+    is.null(self$range$range) && is.null(self$limits) && is.null(self$range_c$range)
+  },
 
-#' @export
-scale_map.position_d <- function(scale, x, limits = scale_limits(scale)) {
-  if (is.discrete(x)) {
-    seq_along(limits)[match(as.character(x), limits)]
-  } else {
-    x
-  }
-}
+  reset = function(self) {
+    # Can't reset discrete scale because no way to recover values
+    self$range_c$reset()
+  },
 
-#' @export
-scale_dimension.position_d <- function(scale, expand = scale$expand) {
-  if(is.waive(expand))
-    expand <- c(0, 0)
-  disc_range <- c(1, length(scale_limits(scale)))
-  disc <- expand_range(disc_range, 0, expand[2], 1)
-  cont <- expand_range(scale$range_c$range, expand[1], 0, expand[2])
-
-  range(disc, cont)
-}
+  map = function(self, x, limits = self$get_limits()) {
+    if (is.discrete(x)) {
+      seq_along(limits)[match(as.character(x), limits)]
+    } else {
+      x
+    }
+  },
 
-#' @export
-scale_clone.position_d <- function(scale) {
-  new <- scale
-  new$range <- DiscreteRange$new()
-  new$range_c <- ContinuousRange$new()
+  dimension = function(self, expand = c(0, 0)) {
+    disc_range <- c(1, length(self$get_limits()))
+    disc <- expand_range(disc_range, 0, expand[2], 1)
 
-  new
-}
+    # if no data was trained (i.e. range_c is infinite) return disc range
+    if (any(is.infinite(self$range_c$range))) {
+      return(disc)
+    }
+
+    cont <- expand_range(self$range_c$range, expand[1], 0, expand[2])
+    range(disc, cont)
+  },
+
+  clone = function(self) {
+    new <- ggproto(NULL, self)
+    new$range <- discrete_range()
+    new$range_c <- continuous_range()
+    new
+  }
+)
diff --git a/R/scale-gradient.r b/R/scale-gradient.r
index b13dd0a..ad57695 100644
--- a/R/scale-gradient.r
+++ b/R/scale-gradient.r
@@ -1,62 +1,61 @@
 #' Smooth gradient between two colours
 #'
+#' \code{scale_*_gradient} creates a two colour gradient (low-high),
+#' \code{scale_*_gradient2} creates a diverging colour gradient (low-mid-high),
+#' \code{scale_*_gradientn} creats a n-colour gradient.
+#'
 #' Default colours are generated with \pkg{munsell} and
 #' \code{mnsl(c("2.5PB 2/4", "2.5PB 7/10")}. Generally, for continuous
 #' colour scales you want to keep hue constant, but vary chroma and
 #' luminance. The \pkg{munsell} package makes this easy to do using the
 #' Munsell colour system.
 #'
-#' @inheritParams scale_colour_hue
 #' @inheritParams scales::seq_gradient_pal
+#' @inheritParams scale_colour_hue
+#' @param low,high Colours for low and high ends of the gradient.
 #' @param guide Type of legend. Use \code{"colourbar"} for continuous
 #'   colour bar, or \code{"legend"} for discrete colour legend.
 #' @seealso \code{\link[scales]{seq_gradient_pal}} for details on underlying
 #'   palette
+#' @seealso Other colour scales:
+#'   \code{\link{scale_colour_brewer}},
+#'   \code{\link{scale_colour_grey}},
+#'   \code{\link{scale_colour_hue}}
 #' @rdname scale_gradient
-#' @family colour scales
 #' @export
 #' @examples
-#' \donttest{
-#' # It's hard to see, but look for the bright yellow dot
-#' # in the bottom right hand corner
-#' dsub <- subset(diamonds, x > 5 & x < 6 & y > 5 & y < 6)
-#' (d <- qplot(x, y, data=dsub, colour=z))
-#' # That one point throws our entire scale off.  We could
-#' # remove it, or manually tweak the limits of the scale
+#' df <- data.frame(
+#'   x = runif(100),
+#'   y = runif(100),
+#'   z1 = rnorm(100),
+#'   z2 = abs(rnorm(100))
+#' )
 #'
-#' # Tweak scale limits.  Any points outside these limits will not be
-#' # plotted, and will not affect the calculation of statistics, etc
-#' d + scale_colour_gradient(limits=c(3, 10))
-#' d + scale_colour_gradient(limits=c(3, 4))
-#' # Setting the limits manually is also useful when producing
-#' # multiple plots that need to be comparable
+#' # Default colour scale colours from light blue to dark blue
+#' ggplot(df, aes(x, y)) +
+#'   geom_point(aes(colour = z2))
 #'
-#' # Alternatively we could try transforming the scale:
-#' d + scale_colour_gradient(trans = "log")
-#' d + scale_colour_gradient(trans = "sqrt")
+#' # For diverging colour scales use gradient2
+#' ggplot(df, aes(x, y)) +
+#'   geom_point(aes(colour = z1)) +
+#'   scale_colour_gradient2()
 #'
-#' # Other more trivial manipulations, including changing the name
-#' # of the scale and the colours.
+#' # Use your own colour scale with gradientn
+#' ggplot(df, aes(x, y)) +
+#'   geom_point(aes(colour = z1)) +
+#'   scale_colour_gradientn(colours = terrain.colors(10))
 #'
-#' d + scale_colour_gradient("Depth")
-#' d + scale_colour_gradient(expression(Depth[mm]))
+#' # Equivalent fill scales do the same job for the fill aesthetic
+#' ggplot(faithfuld, aes(waiting, eruptions)) +
+#'   geom_raster(aes(fill = density)) +
+#'   scale_fill_gradientn(colours = terrain.colors(10))
 #'
-#' d + scale_colour_gradient(limits=c(3, 4), low="red")
-#' d + scale_colour_gradient(limits=c(3, 4), low="red", high="white")
-#' # Much slower
-#' d + scale_colour_gradient(limits=c(3, 4), low="red", high="white", space="Lab")
-#' d + scale_colour_gradient(limits=c(3, 4), space="Lab")
-#'
-#' # scale_fill_continuous works similarly, but for fill colours
-#' (h <- qplot(x - y, data=dsub, geom="histogram", binwidth=0.01, fill=..count..))
-#' h + scale_fill_continuous(low="black", high="pink", limits=c(0,3100))
-#'
-#' # Colour of missing values is controlled with na.value:
-#' miss <- sample(c(NA, 1:5), nrow(mtcars), rep = TRUE)
-#' qplot(mpg, wt, data = mtcars, colour = miss)
-#' qplot(mpg, wt, data = mtcars, colour = miss) +
-#'   scale_colour_gradient(na.value = "black")
-#' }
+#' # Adjust colour choices with low and high
+#' ggplot(df, aes(x, y)) +
+#'   geom_point(aes(colour = z2)) +
+#'   scale_colour_gradient(low = "white", high = "black")
+#' # Avoid red-green colour contrasts because ~10% of men have difficulty
+#' # seeing them
 scale_colour_gradient <- function(..., low = "#132B43", high = "#56B1F7", space = "Lab", na.value = "grey50", guide = "colourbar") {
   continuous_scale("colour", "gradient", seq_gradient_pal(low, high, space),
     na.value = na.value, guide = guide, ...)
@@ -68,3 +67,47 @@ scale_fill_gradient <- function(..., low = "#132B43", high = "#56B1F7", space =
   continuous_scale("fill", "gradient", seq_gradient_pal(low, high, space),
     na.value = na.value, guide = guide, ...)
 }
+
+#' @inheritParams scales::div_gradient_pal
+#' @param midpoint The midpoint (in data value) of the diverging scale.
+#'   Defaults to 0.
+#' @rdname scale_gradient
+#' @export
+scale_colour_gradient2 <- function(..., low = muted("red"), mid = "white", high = muted("blue"), midpoint = 0, space = "Lab", na.value = "grey50", guide = "colourbar") {
+  continuous_scale("colour", "gradient2",
+    div_gradient_pal(low, mid, high, space), na.value = na.value, guide = guide, ...,
+    rescaler = mid_rescaler(mid = midpoint))
+}
+
+#' @rdname scale_gradient
+#' @export
+scale_fill_gradient2 <- function(..., low = muted("red"), mid = "white", high = muted("blue"), midpoint = 0, space = "Lab", na.value = "grey50", guide = "colourbar") {
+  continuous_scale("fill", "gradient2",
+    div_gradient_pal(low, mid, high, space), na.value = na.value, guide = guide, ...,
+    rescaler = mid_rescaler(mid = midpoint))
+}
+
+mid_rescaler <- function(mid) {
+  function(x, to = c(0, 1), from = range(x, na.rm = TRUE)) {
+    rescale_mid(x, to, from, mid)
+  }
+}
+
+#' @inheritParams scales::gradient_n_pal
+#' @param colours,colors Vector of colours to use for n-colour gradient.
+#' @rdname scale_gradient
+#' @export
+scale_colour_gradientn <- function(..., colours, values = NULL, space = "Lab", na.value = "grey50", guide = "colourbar", colors) {
+  colours <- if (missing(colours)) colors else colours
+
+  continuous_scale("colour", "gradientn",
+    gradient_n_pal(colours, values, space), na.value = na.value, guide = guide, ...)
+}
+#' @rdname scale_gradient
+#' @export
+scale_fill_gradientn <- function(..., colours, values = NULL, space = "Lab", na.value = "grey50", guide = "colourbar", colors) {
+  colours <- if (missing(colours)) colors else colours
+
+  continuous_scale("fill", "gradientn",
+    gradient_n_pal(colours, values, space), na.value = na.value, guide = guide, ...)
+}
diff --git a/R/scale-gradient2.r b/R/scale-gradient2.r
deleted file mode 100644
index 33d090c..0000000
--- a/R/scale-gradient2.r
+++ /dev/null
@@ -1,72 +0,0 @@
-#' Diverging colour gradient
-#'
-#' @inheritParams scale_colour_hue
-#' @inheritParams scales::div_gradient_pal
-#' @param midpoint The midpoint (in data value) of the diverging scale.
-#'   Defaults to 0.
-#' @param guide Type of legend. Use \code{"colourbar"} for continuous
-#'   colour bar, or \code{"legend"} for discrete colour legend.
-#' @family colour scales
-#' @rdname scale_gradient2
-#' @export
-#' @examples
-#' \donttest{
-#' dsub <- subset(diamonds, x > 5 & x < 6 & y > 5 & y < 6)
-#' dsub$diff <- with(dsub, sqrt(abs(x-y))* sign(x-y))
-#' (d <- qplot(x, y, data=dsub, colour=diff))
-#'
-#' d + scale_colour_gradient2()
-#' # Change scale name
-#' d + scale_colour_gradient2(expression(sqrt(abs(x - y))))
-#' d + scale_colour_gradient2("Difference\nbetween\nwidth and\nheight")
-#'
-#' # Change limits and colours
-#' d + scale_colour_gradient2(limits=c(-0.2, 0.2))
-#'
-#' # Using "muted" colours makes for pleasant graphics
-#' # (and they have better perceptual properties too)
-#' library(scales) # for muted
-#' d + scale_colour_gradient2(low="red", high="blue")
-#' d + scale_colour_gradient2(low=muted("red"), high=muted("blue"))
-#'
-#' # Using the Lab colour space also improves perceptual properties
-#' # at the price of slightly slower operation
-#' d + scale_colour_gradient2(space="Lab")
-#'
-#' # About 5% of males are red-green colour blind, so it's a good
-#' # idea to avoid that combination
-#' d + scale_colour_gradient2(high=muted("green"))
-#'
-#' # We can also make the middle stand out
-#' d + scale_colour_gradient2(mid=muted("green"), high="white", low="white")
-#'
-#' # or use a non zero mid point
-#' (d <- qplot(carat, price, data=diamonds, colour=price/carat))
-#' d + scale_colour_gradient2(midpoint=mean(diamonds$price / diamonds$carat))
-#'
-#' # Fill gradients work much the same way
-#' p <- qplot(letters[1:5], 1:5, fill= c(-3, 3, 5, 2, -2), geom = "bar",
-#'   stat = "identity")
-#' p + scale_fill_gradient2("fill")
-#' # Note how positive and negative values of the same magnitude
-#' # have similar intensity
-#' }
-scale_colour_gradient2 <- function(..., low = muted("red"), mid = "white", high = muted("blue"), midpoint = 0, space = "rgb", na.value = "grey50", guide = "colourbar") {
-  continuous_scale("colour", "gradient2",
-    div_gradient_pal(low, mid, high, space), na.value = na.value, guide = guide, ...,
-    rescaler = mid_rescaler(mid = midpoint))
-}
-
-#' @rdname scale_gradient2
-#' @export
-scale_fill_gradient2 <- function(..., low = muted("red"), mid = "white", high = muted("blue"), midpoint = 0, space = "rgb", na.value = "grey50", guide = "colourbar") {
-  continuous_scale("fill", "gradient2",
-    div_gradient_pal(low, mid, high, space), na.value = na.value, guide = guide, ...,
-    rescaler = mid_rescaler(mid = midpoint))
-}
-
-mid_rescaler <- function(mid) {
-  function(x, to = c(0, 1), from = range(x, na.rm = TRUE)) {
-    rescale_mid(x, to, from, mid)
-  }
-}
diff --git a/R/scale-gradientn.r b/R/scale-gradientn.r
deleted file mode 100644
index 067de17..0000000
--- a/R/scale-gradientn.r
+++ /dev/null
@@ -1,45 +0,0 @@
-#' Smooth colour gradient between n colours
-#'
-#' @inheritParams scales::gradient_n_pal
-#' @inheritParams scale_colour_hue
-#' @param guide Type of legend. Use \code{"colourbar"} for continuous
-#'   colour bar, or \code{"legend"} for discrete colour legend.
-#' @family colour scales
-#' @rdname scale_gradientn
-#' @export
-#' @examples
-#' \donttest{
-#' # scale_colour_gradient make it easy to use existing colour palettes
-#'
-#' dsub <- subset(diamonds, x > 5 & x < 6 & y > 5 & y < 6)
-#' dsub$diff <- with(dsub, sqrt(abs(x-y))* sign(x-y))
-#' (d <- qplot(x, y, data=dsub, colour=diff))
-#'
-#' d + scale_colour_gradientn(colours = rainbow(7))
-#' breaks <- c(-0.5, 0, 0.5)
-#' d + scale_colour_gradientn(colours = rainbow(7),
-#'   breaks = breaks, labels = format(breaks))
-#'
-#' d + scale_colour_gradientn(colours = topo.colors(10))
-#' d + scale_colour_gradientn(colours = terrain.colors(10))
-#'
-#' # You can force them to be symmetric by supplying a vector of
-#' # values, and turning rescaling off
-#' max_val <- max(abs(dsub$diff))
-#' values <- seq(-max_val, max_val, length = 11)
-#'
-#' d + scale_colour_gradientn(colours = topo.colors(10),
-#'   values = values, rescaler = function(x, ...) x, oob = identity)
-#' d + scale_colour_gradientn(colours = terrain.colors(10),
-#'   values = values, rescaler = function(x, ...) x, oob = identity)
-#' }
-scale_colour_gradientn <- function(..., colours, values = NULL, space = "Lab", na.value = "grey50", guide = "colourbar") {
-  continuous_scale("colour", "gradientn",
-    gradient_n_pal(colours, values, space), na.value = na.value, guide = guide, ...)
-}
-#' @rdname scale_gradientn
-#' @export
-scale_fill_gradientn <- function(..., colours, values = NULL, space = "Lab", na.value = "grey50", guide = "colourbar") {
-  continuous_scale("fill", "gradientn",
-    gradient_n_pal(colours, values, space), na.value = na.value, guide = guide, ...)
-}
diff --git a/R/scale-grey.r b/R/scale-grey.r
index b1c0c3f..fc941f5 100644
--- a/R/scale-grey.r
+++ b/R/scale-grey.r
@@ -4,11 +4,14 @@
 #'
 #' @inheritParams scales::grey_pal
 #' @inheritParams scale_colour_hue
-#' @family colour scales
+#' @seealso Other colour scales:
+#'   \code{\link{scale_colour_brewer}},
+#'   \code{\link{scale_colour_gradient}},
+#'   \code{\link{scale_colour_hue}}
 #' @rdname scale_grey
 #' @export
 #' @examples
-#' p <- qplot(mpg, wt, data=mtcars, colour=factor(cyl))
+#' p <- ggplot(mtcars, aes(mpg, wt)) + geom_point(aes(colour = factor(cyl)))
 #' p + scale_colour_grey()
 #' p + scale_colour_grey(end = 0)
 #'
@@ -16,9 +19,12 @@
 #' p + scale_colour_grey() + theme_bw()
 #'
 #' # Colour of missing values is controlled with na.value:
-#' miss <- factor(sample(c(NA, 1:5), nrow(mtcars), rep = TRUE))
-#' qplot(mpg, wt, data = mtcars, colour = miss) + scale_colour_grey()
-#' qplot(mpg, wt, data = mtcars, colour = miss) +
+#' miss <- factor(sample(c(NA, 1:5), nrow(mtcars), replace = TRUE))
+#' ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point(aes(colour = miss)) +
+#'   scale_colour_grey()
+#' ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point(aes(colour = miss)) +
 #'   scale_colour_grey(na.value = "green")
 scale_colour_grey <- function(..., start = 0.2, end = 0.8, na.value = "red") {
   discrete_scale("colour", "grey", grey_pal(start, end),
@@ -27,7 +33,7 @@ scale_colour_grey <- function(..., start = 0.2, end = 0.8, na.value = "red") {
 
 #' @rdname scale_grey
 #' @export
-scale_fill_grey <- function(..., start = 0.2, end = 0.8, na.value = "grey50") {
+scale_fill_grey <- function(..., start = 0.2, end = 0.8, na.value = "red") {
   discrete_scale("fill", "grey", grey_pal(start, end),
     na.value = na.value, ...)
 }
diff --git a/R/scale-hue.r b/R/scale-hue.r
index 483bd6d..39c578f 100644
--- a/R/scale-hue.r
+++ b/R/scale-hue.r
@@ -6,11 +6,14 @@
 #' @inheritParams scales::hue_pal
 #' @rdname scale_hue
 #' @export
-#' @family colour scales
+#' @seealso Other colour scales:
+#'   \code{\link{scale_colour_brewer}},
+#'   \code{\link{scale_colour_gradient}},
+#'   \code{\link{scale_colour_grey}}
 #' @examples
 #' \donttest{
 #' dsamp <- diamonds[sample(nrow(diamonds), 1000), ]
-#' (d <- qplot(carat, price, data=dsamp, colour=clarity))
+#' (d <- ggplot(dsamp, aes(carat, price)) + geom_point(aes(colour = clarity)))
 #'
 #' # Change scale label
 #' d + scale_colour_hue()
@@ -37,9 +40,10 @@
 #' d + geom_point(alpha = 0.2)
 #'
 #' # Colour of missing values is controlled with na.value:
-#' miss <- factor(sample(c(NA, 1:5), nrow(mtcars), rep = TRUE))
-#' qplot(mpg, wt, data = mtcars, colour = miss)
-#' qplot(mpg, wt, data = mtcars, colour = miss) +
+#' miss <- factor(sample(c(NA, 1:5), nrow(mtcars), replace = TRUE))
+#' ggplot(mtcars, aes(mpg, wt)) + geom_point(aes(colour = miss))
+#' ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point(aes(colour = miss)) +
 #'   scale_colour_hue(na.value = "black")
 #' }
 scale_colour_hue <- function(..., h = c(0, 360) + 15, c = 100, l = 65, h.start = 0, direction = 1, na.value = "grey50") {
diff --git a/R/scale-identity.r b/R/scale-identity.r
index 2e552ec..4c771cc 100644
--- a/R/scale-identity.r
+++ b/R/scale-identity.r
@@ -5,79 +5,150 @@
 #'   \code{\link{continuous_scale}}
 #' @param guide Guide to use for this scale - defaults to \code{"none"}.
 #' @examples
-#' colour <- c("red", "green", "blue", "yellow")
-#' qplot(1:4, 1:4, fill = colour, geom = "tile")
-#' qplot(1:4, 1:4, fill = colour, geom = "tile") + scale_fill_identity()
+#' ggplot(luv_colours, aes(u, v)) +
+#'   geom_point(aes(colour = col), size = 3) +
+#'   scale_color_identity() +
+#'   coord_equal()
+#'
+#' df <- data.frame(
+#'   x = 1:4,
+#'   y = 1:4,
+#'   colour = c("red", "green", "blue", "yellow")
+#' )
+#' ggplot(df, aes(x, y)) + geom_tile(aes(fill = colour))
+#' ggplot(df, aes(x, y)) +
+#'   geom_tile(aes(fill = colour)) +
+#'   scale_fill_identity()
 #'
 #' # To get a legend guide, specify guide = "legend"
-#' qplot(1:4, 1:4, fill = colour, geom = "tile") +
+#' ggplot(df, aes(x, y)) +
+#'   geom_tile(aes(fill = colour)) +
 #'   scale_fill_identity(guide = "legend")
 #' # But you'll typically also need to supply breaks and labels:
-#' qplot(1:4, 1:4, fill = colour, geom = "tile") +
-#'   scale_fill_identity("trt", labels = letters[1:4], breaks = colour,
+#' ggplot(df, aes(x, y)) +
+#'   geom_tile(aes(fill = colour)) +
+#'   scale_fill_identity("trt", labels = letters[1:4], breaks = df$colour,
 #'   guide = "legend")
 #'
 #' # cyl scaled to appropriate size
-#' qplot(mpg, wt, data = mtcars, size = cyl)
+#' ggplot(mtcars, aes(mpg, wt)) + geom_point(aes(size = cyl))
 #'
 #' # cyl used as point size
-#' qplot(mpg, wt, data = mtcars, size = cyl) + scale_size_identity()
+#' ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point(aes(size = cyl)) +
+#'   scale_size_identity()
 NULL
 
 #' @rdname scale_identity
 #' @export
 scale_colour_identity <- function(..., guide = "none") {
-  identity_scale(discrete_scale("colour", "identity", identity_pal(), ..., guide = guide))
+  sc <- discrete_scale("colour", "identity", identity_pal(), ..., guide = guide)
+
+  # TODO: Fix this hack. We're reassigning the parent ggproto object, but this
+  # object should in the first place be created with the correct parent.
+  sc$super <- ScaleDiscreteIdentity
+  class(sc) <- class(ScaleDiscreteIdentity)
+  sc
 }
 
 #' @rdname scale_identity
 #' @export
 scale_fill_identity <- function(..., guide = "none") {
-  identity_scale(discrete_scale("fill", "identity", identity_pal(), ..., guide = guide))
+  sc <- discrete_scale("fill", "identity", identity_pal(), ..., guide = guide)
 
+  # TODO: Fix this hack. We're reassigning the parent ggproto object, but this
+  # object should in the first place be created with the correct parent.
+  sc$super <- ScaleDiscreteIdentity
+  class(sc) <- class(ScaleDiscreteIdentity)
+  sc
 }
 
 #' @rdname scale_identity
 #' @export
 scale_shape_identity <- function(..., guide = "none") {
-  identity_scale(continuous_scale("shape", "identity", identity_pal(), ...,  guide = guide))
+  sc <- continuous_scale("shape", "identity", identity_pal(), ..., guide = guide)
+
+  # TODO: Fix this hack. We're reassigning the parent ggproto object, but this
+  # object should in the first place be created with the correct parent.
+  sc$super <- ScaleContinuousIdentity
+  class(sc) <- class(ScaleContinuousIdentity)
+  sc
 }
 
 #' @rdname scale_identity
 #' @export
 scale_linetype_identity <- function(..., guide = "none") {
-  identity_scale(discrete_scale("linetype", "identity", identity_pal(), ..., guide = guide))
+  sc <- discrete_scale("linetype", "identity", identity_pal(), ..., guide = guide)
 
+  # TODO: Fix this hack. We're reassigning the parent ggproto object, but this
+  # object should in the first place be created with the correct parent.
+  sc$super <- ScaleDiscreteIdentity
+  class(sc) <- class(ScaleDiscreteIdentity)
+  sc
 }
 
 #' @rdname scale_identity
 #' @export
 scale_alpha_identity <- function(..., guide = "none") {
-  identity_scale(continuous_scale("alpha", "identity", identity_pal(), ..., guide = guide))
+  sc <- continuous_scale("alpha", "identity", identity_pal(), ..., guide = guide)
 
+  # TODO: Fix this hack. We're reassigning the parent ggproto object, but this
+  # object should in the first place be created with the correct parent.
+  sc$super <- ScaleContinuousIdentity
+  class(sc) <- class(ScaleContinuousIdentity)
+  sc
 }
 
 #' @rdname scale_identity
 #' @export
 scale_size_identity <- function(..., guide = "none") {
-  identity_scale(continuous_scale("size", "identity", identity_pal(), ..., guide = guide))
-}
+  sc <- continuous_scale("size", "identity", identity_pal(), ..., guide = guide)
 
-identity_scale <- function(x) {
-  structure(x, class = c("identity", class(x)))
+  # TODO: Fix this hack. We're reassigning the parent ggproto object, but this
+  # object should in the first place be created with the correct parent.
+  sc$super <- ScaleContinuousIdentity
+  class(sc) <- class(ScaleContinuousIdentity)
+  sc
 }
 
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
 #' @export
-scale_map.identity <- function(scale, x) {
-  if (is.factor(x)) {
-    as.character(x)
-  } else {
-    x
+ScaleDiscreteIdentity <- ggproto("ScaleDiscreteIdentity", ScaleDiscrete,
+  map = function(x) {
+    if (is.factor(x)) {
+      as.character(x)
+    } else {
+      x
+    }
+  },
+
+  train = function(self, x) {
+    # do nothing if no guide, otherwise train so we know what breaks to use
+    if (self$guide == "none") return()
+    ggproto_parent(ScaleDiscrete, self)$train(x)
   }
-}
+)
+
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
 #' @export
-scale_train.identity <- function(scale, x) {
-  # do nothing if no guide, otherwise train so we know what breaks to use
-  if (scale$guide == "none") return()
-  NextMethod()
-}
+ScaleContinuousIdentity <- ggproto("ScaleContinuousIdentity", ScaleContinuous,
+  map = function(x) {
+    if (is.factor(x)) {
+      as.character(x)
+    } else {
+      x
+    }
+  },
+
+  train = function(self, x) {
+    # do nothing if no guide, otherwise train so we know what breaks to use
+    if (self$guide == "none") return()
+    ggproto_parent(ScaleDiscrete, self)$train(x)
+  }
+)
diff --git a/R/scale-linetype.r b/R/scale-linetype.r
index cc6d195..f505b60 100644
--- a/R/scale-linetype.r
+++ b/R/scale-linetype.r
@@ -9,15 +9,9 @@
 #' @rdname scale_linetype
 #' @export
 #' @examples
-#' library(reshape2) # for melt
-#' library(plyr) # for ddply
-#' ecm <- melt(economics, id = "date")
-#' rescale01 <- function(x) (x - min(x)) / diff(range(x))
-#' ecm <- ddply(ecm, "variable", transform, value = rescale01(value))
-#'
-#' qplot(date, value, data=ecm, geom="line", group=variable)
-#' qplot(date, value, data=ecm, geom="line", linetype=variable)
-#' qplot(date, value, data=ecm, geom="line", colour=variable)
+#' base <- ggplot(economics_long, aes(date, value01))
+#' base + geom_line(aes(group = variable))
+#' base + geom_line(aes(linetype = variable))
 #'
 #' # See scale_manual for more flexibility
 scale_linetype <- function(..., na.value = "blank") {
diff --git a/R/scale-manual.r b/R/scale-manual.r
index 00ecf71..4ff4037 100644
--- a/R/scale-manual.r
+++ b/R/scale-manual.r
@@ -9,7 +9,8 @@
 #'   given \code{na.value}.
 #' @examples
 #' \donttest{
-#' p <- qplot(mpg, wt, data = mtcars, colour = factor(cyl))
+#' p <- ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point(aes(colour = factor(cyl)))
 #'
 #' p + scale_colour_manual(values = c("red","blue", "green"))
 #' p + scale_colour_manual(
diff --git a/R/scale-shape.r b/R/scale-shape.r
index 3caf122..8822e48 100644
--- a/R/scale-shape.r
+++ b/R/scale-shape.r
@@ -9,18 +9,18 @@
 #' @examples
 #' dsmall <- diamonds[sample(nrow(diamonds), 100), ]
 #'
-#' (d <- qplot(carat, price, data=dsmall, shape=cut))
+#' (d <- ggplot(dsmall, aes(carat, price)) + geom_point(aes(shape = cut)))
 #' d + scale_shape(solid = TRUE) # the default
 #' d + scale_shape(solid = FALSE)
-#' d + scale_shape(name="Cut of diamond")
-#' d + scale_shape(name="Cut of\ndiamond")
+#' d + scale_shape(name = "Cut of diamond")
+#' d + scale_shape(name = "Cut of\ndiamond")
 #'
 #' # To change order of levels, change order of
 #' # underlying factor
 #' levels(dsmall$cut) <- c("Fair", "Good", "Very Good", "Premium", "Ideal")
 #'
 #' # Need to recreate plot to pick up new data
-#' qplot(price, carat, data=dsmall, shape=cut)
+#' ggplot(dsmall, aes(price, carat)) + geom_point(aes(shape = cut))
 #'
 #' # Or for short:
 #' d %+% dsmall
diff --git a/R/scale-size.r b/R/scale-size.r
index d753d86..0782475 100644
--- a/R/scale-size.r
+++ b/R/scale-size.r
@@ -1,37 +1,55 @@
-#' Size scale.
+#' Scale size (area or radius).
+#'
+#' \code{scale_size} scales area, \code{scale_radius} scales radius. The size
+#' aesthetic is most commonly used for points and text, and humans perceive
+#' the area of points (not their radius), so this provides for optimal
+#' perception. \code{scale_size_area} ensures that a value of 0 is mapped
+#' to a size of 0.
 #'
 #' @name scale_size
-#' @inheritParams scale_x_continuous
+#' @inheritParams continuous_scale
 #' @param range a numeric vector of length 2 that specifies the minimum and
 #'   maximum size of the plotting symbol after transformation.
+#' @seealso \code{\link{scale_size_area}} if you want 0 values to be mapped
+#'   to points with size 0.
 #' @examples
-#' \donttest{
-#' (p <- qplot(mpg, cyl, data=mtcars, size=cyl))
-#' p + scale_size("cylinders")
-#' p + scale_size("number\nof\ncylinders")
-#'
+#' p <- ggplot(mpg, aes(displ, hwy, size = hwy)) +
+#'    geom_point()
+#' p
+#' p + scale_size("Highway mpg")
 #' p + scale_size(range = c(0, 10))
-#' p + scale_size(range = c(1, 2))
 #'
-#' # Map area, instead of width/radius
-#' # Perceptually, this is a little better
+#' # If you want zero value to have zero size, use scale_size_area:
 #' p + scale_size_area()
-#' p + scale_size_area(max_size = 25)
 #'
-#' # Also works with factors, but not a terribly good
-#' # idea, unless your factor is ordered, as in this example
-#' qplot(mpg, cyl, data=mtcars, size=factor(cyl))
+#' # This is most useful when size is a count
+#' ggplot(mpg, aes(class, cyl)) +
+#'   geom_count() +
+#'   scale_size_area()
 #'
-#' # To control the size mapping for discrete variable, use
-#' # scale_size_manual:
-#' last_plot() + scale_size_manual(values=c(2,4,6))
-#' }
+#' # If you want to map size to radius (usually bad idea), use scale_radius
+#' p + scale_radius()
 NULL
 
 #' @rdname scale_size
 #' @export
-scale_size_continuous <- function(..., range = c(1, 6)) {
-  continuous_scale("size", "size_c", rescale_pal(range), ...)
+#' @usage NULL
+scale_size_continuous <- function(name = waiver(), breaks = waiver(), labels = waiver(),
+                                  limits = NULL, range = c(1, 6),
+                                  trans = "identity", guide = "legend") {
+  continuous_scale("size", "area", area_pal(range), name = name,
+    breaks = breaks, labels = labels, limits = limits, trans = trans,
+    guide = guide)
+}
+
+#' @rdname scale_size
+#' @export
+scale_radius <- function(name = waiver(), breaks = waiver(), labels = waiver(),
+                         limits = NULL, range = c(1, 6),
+                         trans = "identity", guide = "legend") {
+  continuous_scale("size", "radius", rescale_pal(range), name = name,
+    breaks = breaks, labels = labels, limits = limits, trans = trans,
+    guide = guide)
 }
 
 #' @rdname scale_size
@@ -40,24 +58,19 @@ scale_size <- scale_size_continuous
 
 #' @rdname scale_size
 #' @export
-scale_size_discrete <- function(..., range = c(1, 6)) {
-  discrete_scale("size", "size_d",
-    function(n) seq(range[1], range[2], length = n), ...)
+#' @usage NULL
+scale_size_discrete <- function(..., range = c(2, 6)) {
+  discrete_scale("size", "size_d", function(n) {
+    area <- seq(range[1] ^ 2, range[2] ^ 2, length.out = n)
+    sqrt(area)
+  }, ...)
 }
 
-#' Scale area instead of radius, for size.
-#'
-#' When \code{scale_size_area} is used, the default behavior is to scale the
-#' area of points to be proportional to the value.
-#'
-#' Note that this controls the size scale, so it will also control
-#' the thickness of lines. Line thickness will be proportional to the square
-#' root of the value, which is probably undesirable in most cases.
-#'
 #' @param ... Other arguments passed on to \code{\link{continuous_scale}}
 #'   to control name, limits, breaks, labels and so forth.
 #' @param max_size Size of largest points.
 #' @export
+#' @rdname scale_size
 scale_size_area <- function(..., max_size = 6) {
   continuous_scale("size", "area",
     palette = abs_area(max_size),
diff --git a/R/scales-.r b/R/scales-.r
index 792a302..3498cd1 100644
--- a/R/scales-.r
+++ b/R/scales-.r
@@ -1,75 +1,85 @@
-# Scales object encapsultes multiple scales.
+# Scales object encapsulates multiple scales.
 # All input and output done with data.frames to facilitate
 # multiple input and output variables
 
-#' @importFrom methods setRefClass
-Scales <- setRefClass("Scales", fields = "scales", methods = list(
-  find = function(aesthetic) {
-    vapply(scales, function(x) any(aesthetic %in% x$aesthetics), logical(1))
+scales_list <- function() {
+  ggproto(NULL, ScalesList)
+}
+
+ScalesList <- ggproto("ScalesList", NULL,
+  scales = NULL,
+
+  find = function(self, aesthetic) {
+    vapply(self$scales, function(x) any(aesthetic %in% x$aesthetics), logical(1))
   },
-  has_scale = function(aesthetic) {
-    any(find(aesthetic))
+
+  has_scale = function(self, aesthetic) {
+    any(self$find(aesthetic))
   },
-  add = function(scale) {
-    prev_aes <- find(scale$aesthetics)
+
+  add = function(self, scale) {
+    prev_aes <- self$find(scale$aesthetics)
     if (any(prev_aes)) {
       # Get only the first aesthetic name in the returned vector -- it can
       # sometimes be c("x", "xmin", "xmax", ....)
-      scalename <- scales[prev_aes][[1]]$aesthetics[1]
-      message("Scale for '", scalename,
+      scalename <- self$scales[prev_aes][[1]]$aesthetics[1]
+      message_wrap("Scale for '", scalename,
         "' is already present. Adding another scale for '", scalename,
         "', which will replace the existing scale.")
     }
 
     # Remove old scale for this aesthetic (if it exists)
-    scales <<- c(scales[!prev_aes], list(scale))
-  },
-  clone = function() {
-    new_scales <- lapply(scales, scale_clone)
-    Scales$new(new_scales)
+    self$scales <- c(self$scales[!prev_aes], list(scale))
   },
-  n = function() {
-    length(scales)
+
+  n = function(self) {
+    length(self$scales)
   },
-  input = function() {
-    unlist(lapply(scales, "[[", "aesthetics"))
+
+  input = function(self) {
+    unlist(lapply(self$scales, "[[", "aesthetics"))
   },
-  initialize = function(scales = NULL) {
-    initFields(scales = scales)
+
+  # This actually makes a descendant of self, which is functionally the same
+  # as a actually clone for most purposes.
+  clone = function(self) {
+    ggproto(NULL, self, scales = lapply(self$scales, function(s) s$clone()))
   },
-  non_position_scales = function(.) {
-    Scales$new(scales[!find("x") & !find("y")])
+
+  non_position_scales = function(self) {
+    ggproto(NULL, self, scales = self$scales[!self$find("x") & !self$find("y")])
   },
-  get_scales = function(output) {
-    scale <- scales[find(output)]
+
+  get_scales = function(self, output) {
+    scale <- self$scales[self$find(output)]
     if (length(scale) == 0) return()
     scale[[1]]
   }
-))
+)
 
 # Train scale from a data frame
 scales_train_df <- function(scales, df, drop = FALSE) {
   if (empty(df) || length(scales$scales) == 0) return()
 
-  lapply(scales$scales, scale_train_df, df = df)
+  lapply(scales$scales, function(scale) scale$train_df(df = df))
 }
 
 # Map values from a data.frame. Returns data.frame
 scales_map_df <- function(scales, df) {
   if (empty(df) || length(scales$scales) == 0) return(df)
 
-  mapped <- unlist(lapply(scales$scales, scale_map_df, df = df), recursive = FALSE)
+  mapped <- unlist(lapply(scales$scales, function(scale) scale$map_df(df = df)), recursive = FALSE)
 
-  quickdf(c(mapped, df[setdiff(names(df), names(mapped))]))
+  plyr::quickdf(c(mapped, df[setdiff(names(df), names(mapped))]))
 }
 
 # Transform values to cardinal representation
 scales_transform_df <- function(scales, df) {
   if (empty(df) || length(scales$scales) == 0) return(df)
 
-  transformed <- unlist(lapply(scales$scales, scale_transform_df, df = df),
+  transformed <- unlist(lapply(scales$scales, function(s) s$transform_df(df = df)),
     recursive = FALSE)
-  quickdf(c(transformed, df[setdiff(names(df), names(transformed))]))
+  plyr::quickdf(c(transformed, df[setdiff(names(df), names(transformed))]))
 }
 
 # @param aesthetics A list of aesthetic-variable mappings. The name of each
@@ -82,14 +92,14 @@ scales_add_defaults <- function(scales, data, aesthetics, env) {
   # No new aesthetics, so no new scales to add
   if (is.null(new_aesthetics)) return()
 
-  datacols <- tryapply(
+  datacols <- plyr::tryapply(
     aesthetics[new_aesthetics], eval,
     envir = data, enclos = env
   )
 
-  for(aes in names(datacols)) {
+  for (aes in names(datacols)) {
     type <- scale_type(datacols[[aes]])
-    scale_name <- paste("scale", aes, type, sep="_")
+    scale_name <- paste("scale", aes, type, sep = "_")
 
     # Skip aesthetics with no scales (e.g. group, order, etc)
     scale_f <- find_global(scale_name, env, mode = "function")
@@ -108,7 +118,7 @@ scales_add_missing <- function(plot, aesthetics, env) {
   aesthetics <- setdiff(aesthetics, plot$scales$input())
 
   for (aes in aesthetics) {
-    scale_name <- paste("scale", aes, "continuous", sep="_")
+    scale_name <- paste("scale", aes, "continuous", sep = "_")
 
     scale_f <- find_global(scale_name, env, mode = "function")
     plot$scales$add(scale_f())
diff --git a/R/stat-.r b/R/stat-.r
index 3ea4b43..25879f5 100644
--- a/R/stat-.r
+++ b/R/stat-.r
@@ -1,41 +1,105 @@
-Stat <- proto(TopLevel, expr={
-  objname <- ""
-  desc <- ""
-
+#' @section Stats:
+#'
+#' All \code{stat_*} functions (like \code{stat_bin}) return a layer that
+#' contains a \code{Stat*} object (like \code{StatBin}). The \code{Stat*}
+#' object is responsible for rendering the data in the plot.
+#'
+#' Each of the \code{Stat*} objects is a \code{\link{ggproto}} object, descended
+#' from the top-level \code{Stat}, and each implements various methods and
+#' fields. To create a new type of Stat object, you typically will want to
+#' implement one or more of the following:
+#'
+#' \itemize{
+#'   \item Override one of :
+#'     \code{compute_layer(self, data, scales, ...)},
+#'     \code{compute_panel(self, data, scales, ...)}, or
+#'     \code{compute_group(self, data, scales, ...)}.
+#'
+#'     \code{compute_layer()} is called once per layer, \code{compute_panel_()}
+#'     is called once per panel, and \code{compute_group()} is called once per
+#'     group. All must return a data frame.
+#'
+#'     It's usually best to start by overriding \code{compute_group}: if
+#'     you find substantial performance optimisations, override higher up.
+#'     You'll need to read the source code of the default methods to see
+#'     what else you should be doing.
+#'
+#'     \code{data} is a data frame containing the variables named according
+#'     to the aesthetics that they're mapped to. \code{scales} is a list
+#'     containing the \code{x} and \code{y} scales. There functions are called
+#'     before the facets are trained, so they are global scales, not local
+#'     to the individual panels.\code{...} contains the parameters returned by
+#'     \code{setup_params()}.
+#'   \item \code{setup_params(data, params)}: called once for each layer.
+#'      Used to setup defaults that need to complete dataset, and to inform
+#'      the user of important choices. Should return list of parameters.
+#'   \item \code{setup_data(data, params)}: called once for each layer,
+#'      after \code{setp_params()}. Should return modified \code{data}.
+#'      Default methods removes all rows containing a missing value in
+#'      required aesthetics (with a warning if \code{!na.rm}).
+#'   \item \code{required_aes}: A character vector of aesthetics needed to
+#'     render the geom.
+#'   \item \code{default_aes}: A list (generated by \code{\link{aes}()} of
+#'     default values for aesthetics.
+#' }
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+Stat <- ggproto("Stat",
   # Should the values produced by the statistic also be transformed
   # in the second pass when recently added statistics are trained to
   # the scales
-  retransform <- TRUE
+  retransform = TRUE,
 
-  default_geom <- function(.) Geom
-  default_aes <- function(.) aes()
-  default_pos <- function(.) .$default_geom()$default_pos()
-  required_aes <- c()
+  default_aes = aes(),
 
-  aesthetics <- list()
-  calculate <- function(., data, scales, ...) {}
+  required_aes = character(),
 
-  calculate_groups <- function(., data, scales, ...) {
-    if (empty(data)) return(data.frame())
+  non_missing_aes = character(),
+
+  setup_params = function(data, params) {
+    params
+  },
+
+  setup_data = function(data, params) {
+    data
+  },
+
+  compute_layer = function(self, data, params, panels) {
+    check_required_aesthetics(
+      self$stat$required_aes,
+      c(names(data), names(params)),
+      snake_class(self$stat)
+    )
+
+    data <- remove_missing(data, params$na.rm,
+      c(self$required_aes, self$non_missing_aes),
+      snake_class(self),
+      finite = TRUE
+    )
+
+    # Trim off extra parameters
+    params <- params[intersect(names(params), self$parameters())]
 
-    force(data)
-    force(scales)
-
-    # # Alternative approach: cleaner, but much slower
-    # # Compute statistic for each group
-    # stats <- ddply(data, "group", function(group) {
-    #   .$calculate(group, scales, ...)
-    # })
-    # stats$ORDER <- seq_len(nrow(stats))
-    #
-    # # Combine statistics with original columns
-    # unique <- ddply(data, .(group), uniquecols)
-    # stats <- merge(stats, unique, by = "group")
-    # stats[stats$ORDER, ]
+    args <- c(list(data = quote(data), scales = quote(scales)), params)
+    plyr::ddply(data, "PANEL", function(data) {
+      scales <- panel_scales(panels, data$PANEL[1])
+      tryCatch(do.call(self$compute_panel, args), error = function(e) {
+        warning("Computation failed in `", snake_class(self), "()`:\n",
+          e$message, call. = FALSE)
+        data.frame()
+      })
+    })
+  },
+
+  compute_panel = function(self, data, scales, ...) {
+    if (empty(data)) return(data.frame())
 
     groups <- split(data, data$group)
-    stats <- lapply(groups, function(group)
-      .$calculate(data = group, scales = scales, ...))
+    stats <- lapply(groups, function(group) {
+      self$compute_group(data = group, scales = scales, ...)
+    })
 
     stats <- mapply(function(new, old) {
       if (empty(new)) return(data.frame())
@@ -43,28 +107,32 @@ Stat <- proto(TopLevel, expr={
       missing <- !(names(unique) %in% names(new))
       cbind(
         new,
-        unique[rep(1, nrow(new)), missing,drop=FALSE]
+        unique[rep(1, nrow(new)), missing,drop = FALSE]
       )
-    }, stats, groups, SIMPLIFY=FALSE)
+    }, stats, groups, SIMPLIFY = FALSE)
 
-    do.call(rbind.fill, stats)
-  }
+    do.call(plyr::rbind.fill, stats)
+  },
 
+  compute_group = function(self, data, scales) {
+    stop("Not implemented", call. = FALSE)
+  },
 
-  pprint <- function(., newline=TRUE) {
-    cat("stat_", .$objname ,": ", sep="") # , clist(.$parameters())
-    if (newline) cat("\n")
-  }
 
-  parameters <- function(.) {
-    params <- formals(get("calculate", .))
-    params[setdiff(names(params), c(".","data","scales"))]
-  }
+  # See discussion at Geom$parameters()
+  extra_params = "na.rm",
+  parameters = function(self, extra = FALSE) {
+    # Look first in compute_panel. If it contains ... then look in compute_group
+    panel_args <- names(ggproto_formals(self$compute_panel))
+    group_args <- names(ggproto_formals(self$compute_group))
+    args <- if ("..." %in% panel_args) group_args else panel_args
 
-  class <- function(.) "stat"
+    # Remove arguments of defaults
+    args <- setdiff(args, names(ggproto_formals(Stat$compute_group)))
 
-  new <- function(., mapping=aes(), data=NULL, geom=NULL, position=NULL, ...){
-    do.call("layer", list(mapping=mapping, data=data, geom=geom, stat=., position=position, ...))
+    if (extra) {
+      args <- union(args, self$extra_params)
+    }
+    args
   }
-
-})
+)
diff --git a/R/stat-bin.r b/R/stat-bin.r
index 3b26f2c..7acf609 100644
--- a/R/stat-bin.r
+++ b/R/stat-bin.r
@@ -1,100 +1,101 @@
-#' Bin data.
+#' \code{stat_bin} is suitable only for continuous x data. If your x data is
+#'   discrete, you probably want to use \code{\link{stat_count}}.
 #'
-#' Missing values are currently silently dropped.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "bin")}
-#'
-#' @inheritParams stat_identity
-#' @param binwidth Bin width to use. Defaults to 1/30 of the range of the
-#'   data
-#' @param breaks Actual breaks to use.  Overrides bin width and origin
+#' @param binwidth Bin width to use. Defaults to 1/\code{bins} of the range of
+#'   the data
+#' @param bins Number of bins. Overridden by \code{binwidth} or \code{breaks}.
+#'   Defaults to 30
+#' @param breaks Actual breaks to use. Overrides bin width, bin number and
+#'   origin
 #' @param origin Origin of first bin
 #' @param width Width of bars when used with categorical data
 #' @param right If \code{TRUE}, right-closed, left-open, if \code{FALSE},
 #'   the default, right-open, left-closed.
 #' @param drop If TRUE, remove all bins with zero counts
-#' @return New data frame with additional columns:
+#' @section Computed variables:
+#' \describe{
 #'   \item{count}{number of points in bin}
 #'   \item{density}{density of points in bin, scaled to integrate to 1}
 #'   \item{ncount}{count, scaled to maximum of 1}
 #'   \item{ndensity}{density, scaled to maximum of 1}
-#' @export
-#' @examples
-#' \donttest{
-#' simple <- data.frame(x = rep(1:10, each = 2))
-#' base <- ggplot(simple, aes(x))
-#' # By default, right = FALSE intervals are of the form [a, b)
-#' base + stat_bin(binwidth = 1, drop = FALSE, right = FALSE, col = "black")
-#' # If right = TRUE, and intervals are of the form (a, b]
-#' base + stat_bin(binwidth = 1, drop = FALSE, right = TRUE, col = "black")
-#'
-#' m <- ggplot(movies, aes(x=rating))
-#' m + stat_bin()
-#' m + stat_bin(binwidth=0.1)
-#' m + stat_bin(breaks=seq(4,6, by=0.1))
-#' # See geom_histogram for more histogram examples
-#'
-#' # To create a unit area histogram, use aes(y = ..density..)
-#' (linehist <- m + stat_bin(aes(y = ..density..), binwidth=0.1,
-#'   geom="line", position="identity"))
-#' linehist + stat_density(colour="blue", fill=NA)
-#'
-#' # Also works with categorical variables
-#' ggplot(movies, aes(x=mpaa)) + stat_bin()
-#' qplot(mpaa, data=movies, stat="bin")
 #' }
-stat_bin <- function (mapping = NULL, data = NULL, geom = "bar", position = "stack",
-width = 0.9, drop = FALSE, right = FALSE, binwidth = NULL, origin = NULL, breaks = NULL, ...) {
-  StatBin$new(mapping = mapping, data = data, geom = geom, position = position,
-  width = width, drop = drop, right = right, binwidth = binwidth, origin = origin, breaks = breaks, ...)
+#'
+#' @seealso \code{\link{stat_count}}, which counts the number of cases at each x
+#'   posotion, without binning. It is suitable for both discrete and continuous
+#'   x data, whereas \link{stat_bin} is suitable only for continuous x data.
+#' @export
+#' @rdname geom_histogram
+stat_bin <- function(mapping = NULL, data = NULL, geom = "bar",
+                     position = "stack", width = 0.9, drop = FALSE,
+                     right = FALSE, binwidth = NULL, bins = NULL, origin = NULL,
+                     breaks = NULL, na.rm = FALSE,
+                     show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatBin,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      width = width,
+      drop = drop,
+      right = right,
+      bins = bins,
+      binwidth = binwidth,
+      origin = origin,
+      breaks = breaks,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-StatBin <- proto(Stat, {
-  objname <- "bin"
-  informed <- FALSE
-
-  calculate_groups <- function(., data, ...) {
-    if (!is.null(data$y) || !is.null(match.call()$y)) {
-      # Deprecate this behavior
-      gg_dep("0.9.2", paste(sep = "\n",
-        "Mapping a variable to y and also using stat=\"bin\".",
-        "  With stat=\"bin\", it will attempt to set the y value to the count of cases in each group.",
-        "  This can result in unexpected behavior and will not be allowed in a future version of ggplot2.",
-        "  If you want y to represent counts of cases, use stat=\"bin\" and don't map a variable to y.",
-        "  If you want y to represent values in the data, use stat=\"identity\".",
-        "  See ?geom_bar for examples."))
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatBin <- ggproto("StatBin", Stat,
+  setup_params = function(data, params) {
+    if (!is.null(data$y) || !is.null(params$y)) {
+      stop("stat_bin() must not be used with a y aesthetic.", call. = FALSE)
+    }
+    if (is.integer(data$x)) {
+      stop('StatBin requires a continuous x variable the x variable is discrete. Perhaps you want stat="count"?',
+        call. = FALSE)
     }
 
-    .$informed <- FALSE
-    .super$calculate_groups(., data, ...)
-  }
-
-  calculate <- function(., data, scales, binwidth=NULL, origin=NULL, breaks=NULL, width=0.9, drop = FALSE, right = FALSE, ...) {
-    range <- scale_dimension(scales$x, c(0, 0))
-
-    if (is.null(breaks) && is.null(binwidth) && !is.integer(data$x) && !.$informed) {
-      message("stat_bin: binwidth defaulted to range/30. Use 'binwidth = x' to adjust this.")
-      .$informed <- TRUE
+    if (is.null(params$breaks) && is.null(params$binwidth) && is.null(params$bins)) {
+      message_wrap("`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.")
     }
 
-    bin(data$x, data$weight, binwidth=binwidth, origin=origin, breaks=breaks, range=range, width=width, drop = drop, right = right)
-  }
+    params
+  },
 
-  default_aes <- function(.) aes(y = ..count..)
-  required_aes <- c("x")
-  default_geom <- function(.) GeomBar
+  compute_group = function(data, scales, binwidth = NULL, bins = NULL,
+                           origin = NULL, breaks = NULL, width = 0.9, drop = FALSE,
+                           right = FALSE) {
+    range <- scales$x$dimension()
 
-})
+    bin(data$x, data$weight, binwidth = binwidth, bins = bins,
+        origin = origin, breaks = breaks, range = range, width = width,
+        drop = drop, right = right)
+  },
 
-bin <- function(x, weight=NULL, binwidth=NULL, origin=NULL, breaks=NULL, range=NULL, width=0.9, drop = FALSE, right = TRUE) {
+  default_aes = aes(y = ..count..),
+  required_aes = c("x")
+)
 
-  if (length(na.omit(x)) == 0) return(data.frame())
+bin <- function(x, weight=NULL, binwidth=NULL, bins=NULL, origin=NULL, breaks=NULL, range=NULL, width=0.9, drop = FALSE, right = FALSE) {
+
+  if (length(stats::na.omit(x)) == 0) return(data.frame())
   if (is.null(weight))  weight <- rep(1, length(x))
   weight[is.na(weight)] <- 0
 
-  if (is.null(range))    range <- range(x, na.rm = TRUE, finite=TRUE)
-  if (is.null(binwidth)) binwidth <- diff(range) / 30
+  if (is.null(range))    range    <- range(x, na.rm = TRUE, finite = TRUE)
+  if (is.null(bins))     bins     <- 30
+  if (is.null(binwidth)) binwidth <- diff(range) / bins
 
   if (is.integer(x)) {
     bins <- x
@@ -103,7 +104,7 @@ bin <- function(x, weight=NULL, binwidth=NULL, origin=NULL, breaks=NULL, range=N
   } else if (diff(range) == 0) {
     width <- width
     bins <- x
-  } else { # if (is.numeric(x))
+  } else {# if (is.numeric(x))
     if (is.null(breaks)) {
       if (is.null(origin)) {
         breaks <- fullseq(range, binwidth, pad = TRUE)
@@ -122,7 +123,7 @@ bin <- function(x, weight=NULL, binwidth=NULL, origin=NULL, breaks=NULL, range=N
     }
     fuzzybreaks <- sort(breaks) + fuzz
 
-    bins <- cut(x, fuzzybreaks, include.lowest=TRUE, right = right)
+    bins <- cut(x, fuzzybreaks, include.lowest = TRUE, right = right)
     left <- breaks[-length(breaks)]
     right <- breaks[-1]
     x <- (left + right)/2
@@ -130,7 +131,7 @@ bin <- function(x, weight=NULL, binwidth=NULL, origin=NULL, breaks=NULL, range=N
   }
 
   results <- data.frame(
-    count = as.numeric(tapply(weight, bins, sum, na.rm=TRUE)),
+    count = as.numeric(tapply(weight, bins, sum, na.rm = TRUE)),
     x = x,
     width = width
   )
@@ -139,12 +140,12 @@ bin <- function(x, weight=NULL, binwidth=NULL, origin=NULL, breaks=NULL, range=N
     return(results)
   }
 
-  res <- within(results, {
-    count[is.na(count)] <- 0
-    density <- count / width / sum(abs(count), na.rm=TRUE)
-    ncount <- count / max(abs(count), na.rm=TRUE)
-    ndensity <- density / max(abs(density), na.rm=TRUE)
-  })
-  if (drop) res <- subset(res, count > 0)
-  res
+  results$count[is.na(results$count)] <- 0
+  results$density <- results$count / results$width / sum(abs(results$count), na.rm = TRUE)
+  results$ncount <- results$count / max(abs(results$count), na.rm = TRUE)
+  results$ndensity <- results$density / max(abs(results$density), na.rm = TRUE)
+  if (drop) {
+    results <- results[results$count > 0, , drop = FALSE]
+  }
+  results
 }
diff --git a/R/stat-bin2d.r b/R/stat-bin2d.r
index ce0ad7c..c8bf0e4 100644
--- a/R/stat-bin2d.r
+++ b/R/stat-bin2d.r
@@ -1,121 +1,140 @@
-#' Count number of observation in rectangular bins.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "bin2d")}
-#'
-#' @inheritParams stat_identity
 #' @param bins numeric vector giving number of bins in both vertical and
 #'   horizontal directions. Set to 30 by default.
+#' @param binwidth Numeric vector giving bin width in both vertical and
+#'   horizontal directions. Overrides \code{bins} if both set.
 #' @param drop if \code{TRUE} removes all cells with 0 counts.
-#' @seealso \code{\link{stat_binhex}} for hexagonal binning
 #' @export
-#' @examples
-#' \donttest{
-#' d <- ggplot(diamonds, aes(carat, price))
-#' d + stat_bin2d()
-#' d + geom_bin2d()
-#'
-#' # You can control the size of the bins by specifying the number of
-#' # bins in each direction:
-#' d + stat_bin2d(bins = 10)
-#' d + stat_bin2d(bins = 30)
-#'
-#' # Or by specifying the width of the bins
-#' d + stat_bin2d(binwidth = c(1, 1000))
-#' d + stat_bin2d(binwidth = c(.1, 500))
-#'
-#' # Or with a list of breaks
-#' x <- seq(min(diamonds$carat), max(diamonds$carat), by = 0.1)
-#' y <- seq(min(diamonds$price), max(diamonds$price), length = 50)
-#' d + stat_bin2d(breaks = list(x = x, y = y))
-#'
-#' # With qplot
-#' qplot(x, y, data = diamonds, geom="bin2d",
-#'   xlim = c(4, 10), ylim = c(4, 10))
-#' qplot(x, y, data = diamonds, geom="bin2d", binwidth = c(0.1, 0.1),
-#'   xlim = c(4, 10), ylim = c(4, 10))
-#' }
-stat_bin2d <- function (mapping = NULL, data = NULL, geom = NULL, position = "identity",
-bins = 30, drop = TRUE, ...) {
-
-  StatBin2d$new(mapping = mapping, data = data, geom = geom, position = position,
-  bins = bins, drop = drop, ...)
+#' @rdname geom_bin2d
+stat_bin_2d <- function(mapping = NULL, data = NULL, geom = "tile",
+                        position = "identity", bins = 30, binwidth = NULL,
+                        drop = TRUE, na.rm = FALSE,
+                        show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatBin2d,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      bins = bins,
+      binwidth = binwidth,
+      drop = drop,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-StatBin2d <- proto(Stat, {
-  objname <- "bin2d"
 
-  default_aes <- function(.) aes(fill = ..count..)
-  required_aes <- c("x", "y")
-  default_geom <- function(.) GeomRect
+#' @export
+#' @rdname geom_bin2d
+#' @usage NULL
+stat_bin2d <- stat_bin_2d
 
-  calculate <- function(., data, scales, binwidth = NULL, bins = 30, breaks = NULL, origin = NULL, drop = TRUE, ...) {
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatBin2d <- ggproto("StatBin2d", Stat,
+  default_aes = aes(fill = ..count..),
+  required_aes = c("x", "y"),
 
-    range <- list(
-      x = scale_dimension(scales$x, c(0, 0)),
-      y = scale_dimension(scales$y, c(0, 0))
-    )
+  compute_group = function(data, scales, binwidth = NULL, bins = 30,
+                           breaks = NULL, origin = NULL, drop = TRUE) {
 
-    # Determine origin, if omitted
-    if (is.null(origin)) {
-      origin <- c(NA, NA)
-    } else {
-      stopifnot(is.numeric(origin))
-      stopifnot(length(origin) == 2)
-    }
-    originf <- function(x) if (is.integer(x)) -0.5 else min(x, na.rm = TRUE)
-    if (is.na(origin[1])) origin[1] <- originf(data$x)
-    if (is.na(origin[2])) origin[2] <- originf(data$y)
-
-    # Determine binwidth, if omitted
-    if (is.null(binwidth)) {
-      binwidth <- c(NA, NA)
-      if (is.integer(data$x)) {
-        binwidth[1] <- 1
-      } else {
-        binwidth[1] <- diff(range$x) / bins
-      }
-      if (is.integer(data$y)) {
-        binwidth[2] <- 1
-      } else {
-        binwidth[2] <- diff(range$y) / bins
-      }
-    }
-    stopifnot(is.numeric(binwidth))
-    stopifnot(length(binwidth) == 2)
-
-    # Determine breaks, if omitted
-    if (is.null(breaks)) {
-      breaks <- list(
-        seq(origin[1], max(range$x) + binwidth[1], binwidth[1]),
-        seq(origin[2], max(range$y) + binwidth[2], binwidth[2])
-      )
+    origin <- dual_param(origin, list(NULL, NULL))
+    binwidth <- dual_param(binwidth, list(NULL, NULL))
+    breaks <- dual_param(breaks, list(NULL, NULL))
+    bins <- dual_param(bins, list(x = 30, y = 30))
+
+    xbreaks <- bin_breaks(scales$x, breaks$x, origin$x, binwidth$x, bins$x)
+    ybreaks <- bin_breaks(scales$y, breaks$y, origin$y, binwidth$y, bins$y)
+
+    xbin <- cut(data$x, xbreaks, include.lowest = TRUE, labels = FALSE)
+    ybin <- cut(data$y, ybreaks, include.lowest = TRUE, labels = FALSE)
+
+    if (is.null(data$weight))
+      data$weight <- 1
+
+    out <- tapply_df(data$weight, list(xbin = xbin, ybin = ybin), sum, drop = drop)
+
+    xdim <- bin_loc(xbreaks, out$xbin)
+    out$x <- xdim$mid
+    out$width <- xdim$length
+
+    ydim <- bin_loc(ybreaks, out$ybin)
+    out$y <- ydim$mid
+    out$height <- ydim$length
+
+    out$count <- out$value
+    out$density <- out$count / sum(out$count, na.rm = TRUE)
+    out
+  }
+)
+
+dual_param <- function(x, default = list(x = NULL, y = NULL)) {
+  if (is.null(x)) {
+    default
+  } else if (length(x) == 2) {
+    if (is.list(x) && !is.null(names(x))) {
+      x
     } else {
-      stopifnot(is.list(breaks))
-      stopifnot(length(breaks) == 2)
-      stopifnot(all(sapply(breaks, is.numeric)))
+      list(x = x[[1]], y = x[[2]])
     }
-    names(breaks) <- c("x", "y")
+  } else {
+    list(x = x, y = x)
+  }
+}
 
-    xbin <- cut(data$x, sort(breaks$x), include.lowest = TRUE)
-    ybin <- cut(data$y, sort(breaks$y), include.lowest = TRUE)
+bin_breaks <- function(scale, breaks = NULL, origin = NULL, binwidth = NULL,
+                      bins = 30, right = TRUE) {
+  # Bins for categorical data should take the width of one level,
+  # and should show up centered over their tick marks. All other parameters
+  # are ignored.
+  if (scale$is_discrete()) {
+    breaks <- scale$get_breaks()
+    return(-0.5 + seq_len(length(breaks) + 1))
+  }
 
-    if (is.null(data$weight)) data$weight <- 1
+  if (!is.null(breaks))
+    return(breaks)
 
-    counts <- as.data.frame(
-      xtabs(weight ~ xbin + ybin, data), responseName = "count")
-    if (drop) counts <- subset(counts, count > 0)
+  range <- scale$get_limits()
 
-    within(counts,{
-      xint <- as.numeric(xbin)
-      xmin <- breaks$x[xint]
-      xmax <- breaks$x[xint + 1]
+  if (is.null(binwidth) || identical(binwidth, NA)) {
+    binwidth <- diff(range) / bins
+  }
+  stopifnot(is.numeric(binwidth), length(binwidth) == 1)
 
-      yint <- as.numeric(ybin)
-      ymin <- breaks$y[yint]
-      ymax <- breaks$y[yint + 1]
+  if (is.null(origin) || identical(origin, NA)) {
+    origin <- plyr::round_any(range[1], binwidth, floor)
+  }
+  stopifnot(is.numeric(origin), length(origin) == 1)
 
-      density <- count / sum(count, na.rm = TRUE)
-    })
+  breaks <- seq(origin, range[2] + binwidth, binwidth)
+  adjust_breaks(breaks, right)
+}
+
+adjust_breaks <- function(x, right = TRUE) {
+  diddle <- 1e-07 * stats::median(diff(x))
+  if (right) {
+    fuzz <- c(-diddle, rep.int(diddle, length(x) - 1))
+  } else {
+    fuzz <- c(rep.int(-diddle, length(x) - 1), diddle)
   }
-})
+  sort(x) + fuzz
+}
+
+bin_loc <- function(x, id) {
+  left <- x[-length(x)]
+  right <- x[-1]
+
+  list(
+    left = left[id],
+    right = right[id],
+    mid = ((left + right) / 2)[id],
+    length = diff(x)[id]
+  )
+}
diff --git a/R/stat-bindot.r b/R/stat-bindot.r
index e544d13..4cc40c4 100644
--- a/R/stat-bindot.r
+++ b/R/stat-bindot.r
@@ -1,66 +1,33 @@
-#' Bin data for dot plot.
-#'
-#' Missing values are currently silently dropped.
-#' If weights are used, they must be integer values.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "bindot")}
-#'
-#' @inheritParams stat_identity
-#' @param binaxis The axis to bin along, "x" (default) or "y"
-#' @param method "dotdensity" (default) for dot-density binning, or
-#'   "histodot" for fixed bin widths (like stat_bin)
-#' @param binwidth When \code{method} is "dotdensity, this specifies maximum bin width.
-#'   When \code{method} is "histodot", this specifies bin width.
-#'   Defaults to 1/30 of the range of the data
-#' @param binpositions When \code{method} is "dotdensity", "bygroup" (default)
-#'   determines positions of the bins for each group separately. "all" determines
-#'   positions of the bins with all the data taken together; this is used for
-#'   aligning dot stacks across multiple groups.
-#' @param origin When \code{method} is "histodot", origin of first bin
-#' @param right When \code{method} is "histodot", should intervals be closed
-#'   on the right (a, b], or not [a, b)
-#' @param width When \code{binaxis} is "y", the spacing of the dot stacks
-#'   for dodging.
-#' @param na.rm If \code{FALSE} (the default), removes missing values with
-#'    a warning.  If \code{TRUE} silently removes missing values.
-#' @param drop If TRUE, remove all bins with zero counts
-#'
-#' @return New data frame with additional columns:
-#'   \item{x}{center of each bin, if binaxis is "x"}
-#'   \item{y}{center of each bin, if binaxis is "x"}
-#'   \item{binwidth}{max width of each bin if method is "dotdensity";
-#'     width of each bin if method is "histodot"}
-#'   \item{count}{number of points in bin}
-#'   \item{ncount}{count, scaled to maximum of 1}
-#'   \item{density}{density of points in bin, scaled to integrate to 1,
-#'     if method is "histodot"}
-#'   \item{ndensity}{density, scaled to maximum of 1, if method is "histodot"}
-#' @seealso See \code{\link{geom_dotplot}} for examples.
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
 #' @export
-#' @examples
-#' # See geom_dotplot for examples
-#'
-stat_bindot <- function (mapping = NULL, data = NULL, geom = "dotplot", position = "identity",
-binwidth = NULL, origin = NULL, width = 0.9, binaxis = "x", method = "dotdensity",
-binpositions = "bygroup", drop = FALSE, right = TRUE, na.rm = FALSE, ...) {
-  StatBindot$new(mapping = mapping, data = data, geom = geom, position = position,
-  binwidth = binwidth, origin = origin, width = width, binaxis = binaxis,
-  method = method, binpositions = binpositions, drop = drop, right = right,
-  na.rm = na.rm, ...)
-}
-
-
-StatBindot <- proto(Stat, {
-  objname <- "bindot"
-  informed <- FALSE
-
-  calculate_groups <- function(., data, na.rm = FALSE, binwidth = NULL, binaxis = "x",
-                        method = "dotdensity", binpositions = "bygroup", ...) {
-    data <- remove_missing(data, na.rm, c(binaxis, "weight"), name="stat_bindot",
-      finite = TRUE)
-
-    .$informed <- FALSE
+StatBindot <- ggproto("StatBindot", Stat,
+  required_aes = "x",
+  non_missing_aes = "weight",
+  default_aes = aes(y = ..count..),
+
+  setup_params = function(data, params) {
+    if (is.null(params$breaks) && is.null(params$binwidth)) {
+      message("`stat_bindot()` using `bins = 30`. Pick better value with `binwidth`.")
+    }
+    params
+  },
+
+  compute_layer = function(self, data, params, panels) {
+    data <- remove_missing(data, params$na.rm,
+      params$binaxis,
+      snake_class(self),
+      finite = TRUE
+    )
+    ggproto_parent(Stat, self)$compute_layer(data, params, panels)
+  },
+
+  compute_panel = function(self, data, scales, na.rm = FALSE, binwidth = NULL,
+                           binaxis = "x", method = "dotdensity",
+                           binpositions = "bygroup", origin = NULL,
+                           breaks = NULL, width = 0.9, drop = FALSE,
+                           right = TRUE) {
 
     # If using dotdensity and binning over all, we need to find the bin centers
     # for all data before it's split into groups.
@@ -69,15 +36,15 @@ StatBindot <- proto(Stat, {
         newdata <- densitybin(x = data$x, weight = data$weight, binwidth = binwidth,
                       method = method)
 
-        data    <- arrange(data, x)
-        newdata <- arrange(newdata, x)
+        data    <- plyr::arrange(data, x)
+        newdata <- plyr::arrange(newdata, x)
 
       } else if (binaxis == "y") {
         newdata <- densitybin(x = data$y, weight = data$weight, binwidth = binwidth,
                     method = method)
 
-        data    <- arrange(data, y)
-        newdata <- arrange(newdata, x)
+        data    <- plyr::arrange(data, y)
+        newdata <- plyr::arrange(newdata, x)
       }
 
       data$bin       <- newdata$bin
@@ -87,18 +54,19 @@ StatBindot <- proto(Stat, {
 
     }
 
-    .super$calculate_groups(., data, binwidth = binwidth, binaxis = binaxis,
-            method = method, binpositions = binpositions, ...)
-  }
-
+    ggproto_parent(Stat, self)$compute_panel(data, scales, binwidth = binwidth,
+      binaxis = binaxis, method = method, binpositions = binpositions,
+      origin = origin, breaks = breaks, width = width, drop = drop,
+      right = right)
+  },
 
-  calculate <- function(., data, scales, binwidth = NULL, binaxis = "x",
-                        method = "dotdensity", binpositions = "bygroup",
-                        origin = NULL, breaks = NULL, width = 0.9, drop = FALSE,
-                        right = TRUE, ...) {
+  compute_group = function(self, data, scales, binwidth = NULL, binaxis = "x",
+                           method = "dotdensity", binpositions = "bygroup",
+                           origin = NULL, breaks = NULL, width = 0.9, drop = FALSE,
+                           right = TRUE) {
 
     # This function taken from integer help page
-    is.wholenumber <- function(x, tol = .Machine$double.eps^0.5) {
+    is.wholenumber <- function(x, tol = .Machine$double.eps ^ 0.5) {
       abs(x - round(x)) < tol
     }
 
@@ -109,25 +77,19 @@ StatBindot <- proto(Stat, {
     }
 
     if (binaxis == "x") {
-      range   <- scale_dimension(scales$x, c(0, 0))
+      range   <- scales$x$dimension()
       values  <- data$x
     } else if (binaxis == "y") {
-      range  <- scale_dimension(scales$y, c(0, 0))
+      range  <- scales$y$dimension()
       values <- data$y
       # The middle of each group, on the stack axis
       midline <- mean(range(data$x))
     }
 
-    if (is.null(breaks) && is.null(binwidth) && !is.integer(values) && !.$informed) {
-      message("stat_bindot: binwidth defaulted to range/30. Use 'binwidth = x' to adjust this.")
-      .$informed <- TRUE
-    }
-
-
-    if(method == "histodot") {
+    if (method == "histodot") {
       # Use the function from stat_bin
       data <- bin(x = values, weight = data$weight, binwidth = binwidth, origin = origin,
-                  breaks=breaks, range = range, width = width, drop = drop, right = right)
+                  breaks = breaks, range = range, width = width, drop = drop, right = right)
 
       # Change "width" column to "binwidth" for consistency
       names(data)[names(data) == "width"] <- "binwidth"
@@ -142,7 +104,7 @@ StatBindot <- proto(Stat, {
                   method = method, range = range)
 
       # Collapse each bin and get a count
-      data <- ddply(data, .(bincenter), summarise, binwidth = binwidth[1], count = sum(weight))
+      data <- plyr::ddply(data, "bincenter", plyr::summarise, binwidth = binwidth[1], count = sum(weight))
 
       if (sum(data$count, na.rm = TRUE) != 0) {
         data$count[is.na(data$count)] <- 0
@@ -162,18 +124,14 @@ StatBindot <- proto(Stat, {
     }
     return(data)
   }
+)
 
-  default_aes <- function(.) aes(y = ..count..)
-  required_aes <- c("x")
-  default_geom <- function(.) GeomDotplot
-
-})
 
 # This does density binning, but does not collapse each bin with a count.
 # It returns a data frame with the original data (x), weights, bin #, and the bin centers.
 densitybin <- function(x, weight = NULL, binwidth = NULL, method = method, range = NULL) {
 
-    if (length(na.omit(x)) == 0) return(data.frame())
+    if (length(stats::na.omit(x)) == 0) return(data.frame())
     if (is.null(weight))  weight <- rep(1, length(x))
     weight[is.na(weight)] <- 0
 
@@ -200,7 +158,7 @@ densitybin <- function(x, weight = NULL, binwidth = NULL, method = method, range
     }
 
     results <- data.frame(x, bin, binwidth, weight)
-    results <- ddply(results, .(bin), function(df) {
+    results <- plyr::ddply(results, "bin", function(df) {
                     df$bincenter = (min(df$x) + max(df$x)) / 2
                     return(df)
                   })
diff --git a/R/stat-binhex.r b/R/stat-binhex.r
index 2ed737c..8ba031c 100644
--- a/R/stat-binhex.r
+++ b/R/stat-binhex.r
@@ -1,65 +1,53 @@
-#' Bin 2d plane into hexagons.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "binhex")}
-#'
-#' @seealso \code{\link{stat_bin2d}} for rectangular binning
-#' @param bins numeric vector specifying number of bins in both x and y
-#'   directions. Set to 30 by default.
-#' @inheritParams stat_identity
-#' @param na.rm If \code{FALSE} (the default), removes missing values with
-#'    a warning.  If \code{TRUE} silently removes missing values.
 #' @export
-#' @examples
-#' \donttest{
-#' d <- ggplot(diamonds, aes(carat, price))
-#' d + stat_binhex()
-#' d + geom_hex()
-#'
-#' # You can control the size of the bins by specifying the number of
-#' # bins in each direction:
-#' d + stat_binhex(bins = 10)
-#' d + stat_binhex(bins = 30)
-#'
-#' # Or by specifying the width of the bins
-#' d + stat_binhex(binwidth = c(1, 1000))
-#' d + stat_binhex(binwidth = c(.1, 500))
-#'
-#' # With qplot
-#' qplot(x, y, data = diamonds, geom="hex", xlim = c(4, 10), ylim = c(4, 10))
-#' qplot(x, y, data = diamonds, geom="hex", xlim = c(4, 10), ylim = c(4, 10),
-#'   binwidth = c(0.1, 0.1))
-#' }
-stat_binhex <- function (mapping = NULL, data = NULL, geom = "hex", position = "identity",
-bins = 30, na.rm = FALSE, ...) {
-  StatBinhex$new(mapping = mapping, data = data, geom = geom, position = position,
-  bins = bins, na.rm = na.rm, ...)
+#' @rdname geom_hex
+#' @inheritParams stat_bin_2d
+stat_bin_hex <- function(mapping = NULL, data = NULL, geom = "hex",
+                        position = "identity", bins = 30, binwidth = NULL,
+                        na.rm = FALSE, show.legend = NA, inherit.aes = TRUE,
+                        ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatBinhex,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      bins = bins,
+      binwidth = binwidth,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-StatBinhex <- proto(Stat, {
-  objname <- "binhex"
-
-  default_aes <- function(.) aes(fill = ..count..)
-  required_aes <- c("x", "y")
-  default_geom <- function(.) GeomHex
+#' @export
+#' @rdname geom_hex
+#' @usage NULL
+stat_binhex <- stat_bin_hex
 
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatBinhex <- ggproto("StatBinhex", Stat,
+  default_aes = aes(fill = ..count..),
 
-  calculate <- function(., data, scales, binwidth = NULL, bins = 30, na.rm = FALSE, ...) {
-    try_require("hexbin")
-    data <- remove_missing(data, na.rm, c("x", "y"), name="stat_hexbin")
+  required_aes = c("x", "y"),
 
+  compute_group = function(data, scales, binwidth = NULL, bins = 30,
+                           na.rm = FALSE) {
     if (is.null(binwidth)) {
       binwidth <- c(
-        diff(scale_dimension(scales$x, c(0, 0))) / bins,
-        diff(scale_dimension(scales$y, c(0, 0))) / bins
+        diff(scales$x$dimension()) / bins,
+        diff(scales$y$dimension()) / bins
       )
     }
 
     hexBin(data$x, data$y, binwidth)
   }
-
-
-})
+)
 
 # Bin 2d plane into hexagons
 # Wrapper around \code{\link[hexbin]{hcell2xy}} that returns a data frame
@@ -69,31 +57,29 @@ StatBinhex <- proto(Stat, {
 # @param numeric vector of length 2 giving binwidth in x and y directions
 # @keyword internal
 hexBin <- function(x, y, binwidth) {
-  try_require("hexbin")
-
   # Convert binwidths into bounds + nbins
   xbnds <- c(
-    round_any(min(x), binwidth[1], floor) - 1e-6,
-    round_any(max(x), binwidth[1], ceiling) + 1e-6
+    plyr::round_any(min(x), binwidth[1], floor) - 1e-6,
+    plyr::round_any(max(x), binwidth[1], ceiling) + 1e-6
   )
   xbins <- diff(xbnds) / binwidth[1]
 
   ybnds <- c(
-    round_any(min(y), binwidth[2], floor) - 1e-6,
-    round_any(max(y), binwidth[2], ceiling) + 1e-6
+    plyr::round_any(min(y), binwidth[2], floor) - 1e-6,
+    plyr::round_any(max(y), binwidth[2], ceiling) + 1e-6
   )
   ybins <- diff(ybnds) / binwidth[2]
 
   # Call hexbin
   hb <- hexbin::hexbin(
     x, xbnds = xbnds, xbins = xbins,
-    y, ybnds = ybnds, shape = ybins / xbins,
+    y, ybnds = ybnds, shape = ybins / xbins
   )
 
   # Convert to data frame
   data.frame(
     hexbin::hcell2xy(hb),
     count = hb at count,
-    density = hb at count / sum(hb at count, na.rm=TRUE)
+    density = hb at count / sum(hb at count, na.rm = TRUE)
   )
 }
diff --git a/R/stat-boxplot.r b/R/stat-boxplot.r
index 12eb748..97c7f22 100644
--- a/R/stat-boxplot.r
+++ b/R/stat-boxplot.r
@@ -1,13 +1,8 @@
-#' Calculate components of box and whisker plot.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "boxplot")}
-#'
+#' @rdname geom_boxplot
 #' @param coef length of the whiskers as multiple of IQR.  Defaults to 1.5
-#' @param na.rm If \code{FALSE} (the default), removes missing values with
-#'    a warning.  If \code{TRUE} silently removes missing values.
 #' @inheritParams stat_identity
-#' @return A data frame with additional columns:
+#' @section Computed variables:
+#' \describe{
 #'   \item{width}{width of boxplot}
 #'   \item{ymin}{lower whisker = smallest observation greater than or equal to lower hinge - 1.5 * IQR}
 #'   \item{lower}{lower hinge, 25\% quantile}
@@ -16,69 +11,84 @@
 #'   \item{notchupper}{upper edge of notch = median + 1.58 * IQR / sqrt(n)}
 #'   \item{upper}{upper hinge, 75\% quantile}
 #'   \item{ymax}{upper whisker = largest observation less than or equal to upper hinge + 1.5 * IQR}
-#' @seealso See \code{\link{geom_boxplot}} for examples.
+#' }
 #' @export
-#' @examples
-#' # See geom_boxplot for examples
-stat_boxplot <- function (mapping = NULL, data = NULL, geom = "boxplot", position = "dodge",
-na.rm = FALSE, coef = 1.5, ...) {
-  StatBoxplot$new(mapping = mapping, data = data, geom = geom,
-  position = position, na.rm = na.rm, coef = coef, ...)
+stat_boxplot <- function(mapping = NULL, data = NULL, geom = "boxplot",
+                         position = "dodge", coef = 1.5, na.rm = FALSE,
+                         show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatBoxplot,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      coef = coef,
+      ...
+    )
+  )
 }
 
-StatBoxplot <- proto(Stat, {
-  objname <- "boxplot"
 
-  required_aes <- c("x", "y")
-  default_geom <- function(.) GeomBoxplot
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatBoxplot <- ggproto("StatBoxplot", Stat,
+  required_aes = c("x", "y"),
+  non_missing_aes = "weight",
 
-  calculate_groups <- function(., data, na.rm = FALSE, width = NULL, ...) {
-    data <- remove_missing(data, na.rm, c("y", "weight"), name="stat_boxplot",
-      finite = TRUE)
-    data$weight <- data$weight %||% 1
-    width <- width %||%  resolution(data$x) * 0.75
+  setup_params = function(data, params) {
+    params$width <- params$width %||% resolution(data$x) * 0.75
 
-    .super$calculate_groups(., data, na.rm = na.rm, width = width, ...)
-  }
+    if (is.double(data$x) && !has_groups(data) && any(data$x != data$x[1L])) {
+      warning(
+        "Continuous x aesthetic -- did you forget aes(group=...)?",
+        call. = FALSE)
+    }
+
+    params
+  },
 
-  calculate <- function(., data, scales, width=NULL, na.rm = FALSE, coef = 1.5, ...) {
-    with(data, {
-      qs <- c(0, 0.25, 0.5, 0.75, 1)
-      if (length(unique(weight)) != 1) {
-        try_require("quantreg")
-        stats <- as.numeric(coef(rq(y ~ 1, weights = weight, tau=qs)))
-      } else {
-        stats <- as.numeric(quantile(y, qs))
-      }
-      names(stats) <- c("ymin", "lower", "middle", "upper", "ymax")
+  compute_group = function(data, scales, width = NULL, na.rm = FALSE, coef = 1.5) {
+    qs <- c(0, 0.25, 0.5, 0.75, 1)
 
-      iqr <- diff(stats[c(2, 4)])
+    if (!is.null(data$weight)) {
+      mod <- quantreg::rq(y ~ 1, weights = weight, data = data, tau = qs)
+      stats <- as.numeric(stats::coef(mod))
+    } else {
+      stats <- as.numeric(stats::quantile(data$y, qs))
+    }
+    names(stats) <- c("ymin", "lower", "middle", "upper", "ymax")
+    iqr <- diff(stats[c(2, 4)])
 
-      outliers <- y < (stats[2] - coef * iqr) | y > (stats[4] + coef * iqr)
-      if (any(outliers)) {
-        stats[c(1, 5)] <- range(c(stats[2:4], y[!outliers]), na.rm=TRUE)
-      }
+    outliers <- data$y < (stats[2] - coef * iqr) | data$y > (stats[4] + coef * iqr)
+    if (any(outliers)) {
+      stats[c(1, 5)] <- range(c(stats[2:4], data$y[!outliers]), na.rm = TRUE)
+    }
 
-      if (length(unique(x)) > 1) width <- diff(range(x)) * 0.9
+    if (length(unique(data$x)) > 1)
+      width <- diff(range(data$x)) * 0.9
 
-      df <- as.data.frame(as.list(stats))
-      df$outliers <- I(list(y[outliers]))
+    df <- as.data.frame(as.list(stats))
+    df$outliers <- list(data$y[outliers])
 
-      if (is.null(weight)) {
-        n <- sum(!is.na(y))
-      } else {
-        # Sum up weights for non-NA positions of y and weight
-        n <- sum(weight[!is.na(y) & !is.na(weight)])
-      }
+    if (is.null(data$weight)) {
+      n <- sum(!is.na(data$y))
+    } else {
+      # Sum up weights for non-NA positions of y and weight
+      n <- sum(data$weight[!is.na(data$y) & !is.na(data$weight)])
+    }
 
-      df$notchupper <- df$middle + 1.58 * iqr / sqrt(n)
-      df$notchlower <- df$middle - 1.58 * iqr / sqrt(n)
+    df$notchupper <- df$middle + 1.58 * iqr / sqrt(n)
+    df$notchlower <- df$middle - 1.58 * iqr / sqrt(n)
 
-      transform(df,
-        x = if (is.factor(x)) x[1] else mean(range(x)),
-        width = width,
-        relvarwidth = sqrt(n)
-      )
-    })
+    df$x <- if (is.factor(data$x)) data$x[1] else mean(range(data$x))
+    df$width <- width
+    df$relvarwidth <- sqrt(n)
+    df
   }
-})
+)
diff --git a/R/stat-contour.r b/R/stat-contour.r
index 239c5ff..f139f71 100644
--- a/R/stat-contour.r
+++ b/R/stat-contour.r
@@ -1,69 +1,38 @@
-#' Calculate contours of 3d data.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "contour")}
-#'
 #' @inheritParams stat_identity
-#' @param na.rm If \code{FALSE} (the default), removes missing values with
-#'    a warning.  If \code{TRUE} silently removes missing values.
-#' @return A data frame with additional column:
-#'  \item{level}{height of contour}
 #' @export
-#' @examples
-#' \donttest{
-#' # Generate data
-#' library(reshape2) # for melt
-#' volcano3d <- melt(volcano)
-#' names(volcano3d) <- c("x", "y", "z")
-#'
-#' # Basic plot
-#' v <- ggplot(volcano3d, aes(x, y, z = z))
-#' v + stat_contour()
-#'
-#' # Setting bins creates evenly spaced contours in the range of the data
-#' v + stat_contour(bins = 2)
-#' v + stat_contour(bins = 10)
-#'
-#' # Setting binwidth does the same thing, parameterised by the distance
-#' # between contours
-#' v + stat_contour(binwidth = 2)
-#' v + stat_contour(binwidth = 5)
-#' v + stat_contour(binwidth = 10)
-#' v + stat_contour(binwidth = 2, size = 0.5, colour = "grey50") +
-#'   stat_contour(binwidth = 10, size = 1)
-#'
-#' # Add aesthetic mappings
-#' v + stat_contour(aes(size = ..level..))
-#' v + stat_contour(aes(colour = ..level..))
-#'
-#' # Change scale
-#' v + stat_contour(aes(colour = ..level..), size = 2) +
-#'   scale_colour_gradient(low = "brown", high = "white")
-#'
-#' # Set aesthetics to fixed value
-#' v + stat_contour(colour = "red")
-#' v + stat_contour(size = 2, linetype = 4)
-#'
-#' # Try different geoms
-#' v + stat_contour(geom="polygon", aes(fill=..level..))
-#' v + geom_tile(aes(fill = z)) + stat_contour()
-#'
-#' # Use qplot instead
-#' qplot(x, y, z = z, data = volcano3d, geom = "contour")
-#' qplot(x, y, z = z, data = volcano3d, stat = "contour", geom = "path")
+#' @section Computed variables:
+#' \describe{
+#'  \item{level}{height of contour}
 #' }
-stat_contour <- function (mapping = NULL, data = NULL, geom = "path", position = "identity",
-na.rm = FALSE, ...) {
-  StatContour$new(mapping = mapping, data = data, geom = geom,
-  position = position, na.rm = na.rm, ...)
+#' @rdname geom_contour
+stat_contour <- function(mapping = NULL, data = NULL, geom = "contour",
+                         position = "identity", na.rm = FALSE, show.legend = NA,
+                         inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatContour,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-StatContour <- proto(Stat, {
-  objname <- "contour"
-
-  calculate <- function(., data, scales, bins=NULL, binwidth=NULL, breaks = NULL, complete = FALSE, na.rm = FALSE, ...) {
-    data <- remove_missing(data, na.rm, name = "stat_contour", finite = TRUE)
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatContour <- ggproto("StatContour", Stat,
+  required_aes = c("x", "y", "z"),
+  default_aes = aes(order = ..level..),
 
+  compute_group = function(data, scales, bins = NULL, binwidth = NULL,
+                           breaks = NULL, complete = FALSE, na.rm = FALSE) {
     # If no parameters set, use pretty bins
     if (is.null(bins) && is.null(binwidth) && is.null(breaks)) {
       breaks <- pretty(range(data$z), 10)
@@ -80,23 +49,21 @@ StatContour <- proto(Stat, {
     contour_lines(data, breaks, complete = complete)
   }
 
-
-  default_geom <- function(.) GeomPath
-  default_aes <- function(.) aes(order = ..level..)
-  required_aes <- c("x", "y", "z")
-})
+)
 
 
 # v3d <- reshape2::melt(volcano)
 # names(v3d) <- c("x", "y", "z")
 #
-# breaks <- seq(95, 195, length = 10)
-# contours <- contour_lines(v3d, breaks)
-# qplot(x, y, data = contours, geom = "path") + facet_wrap(~ piece)
+# breaks <- seq(95, 195, length.out = 10)
+# contours <- contourLines(v3d, breaks)
+# ggplot(contours, aes(x, y)) +
+#   geom_path() +
+#   facet_wrap(~piece)
 contour_lines <- function(data, breaks, complete = FALSE) {
   z <- tapply(data$z, data[c("x", "y")], identity)
 
-  cl <- contourLines(
+  cl <- grDevices::contourLines(
     x = sort(unique(data$x)), y = sort(unique(data$y)), z = z,
     levels = breaks)
 
@@ -136,8 +103,8 @@ poly_dir <- function(x, y) {
 
 # To fix breaks and complete the polygons, we need to add 0-4 corner points.
 #
-# contours <- ddply(contours, "piece", mutate, dir = poly_dir(x, y))
-# qplot(x, y, data = contours, geom = "path", group = piece,
-#   colour = factor(dir))
+# contours <- ddply(contours, "piece", mutate, dir = ggplot2:::poly_dir(x, y))
+# ggplot(contours, aes(x, y)) +
+#   geom_path(aes(group = piece, colour = factor(dir)))
 # last_plot() + facet_wrap(~ level)
 
diff --git a/R/stat-count.r b/R/stat-count.r
new file mode 100644
index 0000000..eacc45f
--- /dev/null
+++ b/R/stat-count.r
@@ -0,0 +1,67 @@
+#' \code{stat_count} counts the number of cases at each x position. If you want
+#' to bin the data in ranges, you should use \code{\link{stat_bin}} instead.
+#'
+#' @section Computed variables:
+#' \describe{
+#'   \item{count}{number of points in bin}
+#'   \item{prop}{groupwise proportion}
+#' }
+#' @seealso \code{\link{stat_bin}}, which bins data in ranges and counts the
+#'   cases in each range. It differs from \code{stat_count}, which counts the
+#'   number of cases at each x position (without binning into ranges).
+#'   \code{\link{stat_bin}} requires continuous x data, whereas
+#'   \code{stat_count} can be used for both discrete and continuous x data.
+#'
+#' @export
+#' @rdname geom_bar
+stat_count <- function(mapping = NULL, data = NULL, geom = "bar",
+                     position = "stack", width = NULL, ...,
+                     na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatCount,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      width = width,
+      ...
+    )
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+#' @include stat-.r
+StatCount <- ggproto("StatCount", Stat,
+  required_aes = "x",
+  default_aes = aes(y = ..count..),
+
+  setup_params = function(data, params) {
+    if (!is.null(data$y) || !is.null(params$y)) {
+      stop("stat_count() must not be used with a y aesthetic.", call. = FALSE)
+    }
+    params
+  },
+
+  compute_group = function(self, data, scales, width = NULL) {
+    x <- data$x
+    weight <- data$weight %||% rep(1, length(x))
+    width <- width %||% (resolution(x) * 0.9)
+
+    count <- as.numeric(tapply(weight, x, sum, na.rm = TRUE))
+    count[is.na(count)] <- 0
+
+    data.frame(
+      count = count,
+      prop = count / sum(abs(count)),
+      x = sort(unique(x)),
+      width = width
+    )
+  }
+)
diff --git a/R/stat-density-2d.r b/R/stat-density-2d.r
index 88dcc42..e509ed5 100644
--- a/R/stat-density-2d.r
+++ b/R/stat-density-2d.r
@@ -1,83 +1,62 @@
-#' 2d density estimation.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "density2d")}
-#'
+#' @export
+#' @rdname geom_density_2d
 #' @param contour If \code{TRUE}, contour the results of the 2d density
 #'   estimation
 #' @param n number of grid points in each direction
-#' @param ... other arguments passed on to \code{\link{kde2d}}
-#' @param na.rm If \code{FALSE} (the default), removes missing values with
-#'    a warning.  If \code{TRUE} silently removes missing values.
-#' @inheritParams stat_identity
-#' @return A data frame in the same format as \code{\link{stat_contour}}
-#' @importFrom MASS kde2d
-#' @export
-#' @examples
-#' \donttest{
-#' library("MASS")
-#' data(geyser, "MASS")
-#'
-#' m <- ggplot(geyser, aes(x = duration, y = waiting)) +
-#'   geom_point() + xlim(0.5, 6) + ylim(40, 110)
-#' m + geom_density2d()
-#'
-#' dens <- kde2d(geyser$duration, geyser$waiting, n = 50,
-#'               lims = c(0.5, 6, 40, 110))
-#' densdf <- data.frame(expand.grid(duration = dens$x, waiting = dens$y),
-#'  z = as.vector(dens$z))
-#' m + geom_contour(aes(z=z), data=densdf)
-#'
-#' m + geom_density2d() + scale_y_log10()
-#' m + geom_density2d() + coord_trans(y="log10")
-#'
-#' m + stat_density2d(aes(fill = ..level..), geom="polygon")
-#'
-#' qplot(duration, waiting, data=geyser, geom=c("point","density2d")) +
-#'   xlim(0.5, 6) + ylim(40, 110)
-#'
-#' # If you map an aesthetic to a categorical variable, you will get a
-#' # set of contours for each value of that variable
-#' set.seed(4393)
-#' dsmall <- diamonds[sample(nrow(diamonds), 1000), ]
-#' qplot(x, y, data = dsmall, geom = "density2d", colour = cut)
-#' qplot(x, y, data = dsmall, geom = "density2d", linetype = cut)
-#' qplot(carat, price, data = dsmall, geom = "density2d", colour = cut)
-#' d <- ggplot(dsmall, aes(carat, price)) + xlim(1,3)
-#' d + geom_point() + geom_density2d()
-#'
-#' # If we turn contouring off, we can use use geoms like tiles:
-#' d + stat_density2d(geom="tile", aes(fill = ..density..), contour = FALSE)
-#' last_plot() + scale_fill_gradient(limits=c(1e-5,8e-4))
-#'
-#' # Or points:
-#' d + stat_density2d(geom="point", aes(size = ..density..), contour = FALSE)
-#' }
-stat_density2d <- function (mapping = NULL, data = NULL, geom = "density2d", position = "identity",
-na.rm = FALSE, contour = TRUE, n = 100, ...) {
-  StatDensity2d$new(mapping = mapping, data = data, geom = geom,
-  position = position, na.rm = na.rm, contour = contour, n = n, ...)
+#' @param h Bandwidth (vector of length two). If \code{NULL}, estimated
+#'   using \code{\link[MASS]{bandwidth.nrd}}.
+#' @section Computed variables:
+#' Same as \code{\link{stat_contour}}
+stat_density_2d <- function(mapping = NULL, data = NULL, geom = "density_2d",
+                           position = "identity", contour = TRUE,
+                           n = 100, h = NULL, na.rm = FALSE,
+                           show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatDensity2d,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      contour = contour,
+      n = n,
+      ...
+    )
+  )
 }
 
-StatDensity2d <- proto(Stat, {
-  objname <- "density2d"
+#' @export
+#' @rdname geom_density_2d
+#' @usage NULL
+stat_density2d <- stat_density_2d
 
-  default_geom <- function(.) GeomDensity2d
-  default_aes <- function(.) aes(colour = "#3366FF", size = 0.5)
-  required_aes <- c("x", "y")
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatDensity2d <- ggproto("StatDensity2d", Stat,
+  default_aes = aes(colour = "#3366FF", size = 0.5),
 
+  required_aes = c("x", "y"),
 
-  calculate <- function(., data, scales, na.rm = FALSE, contour = TRUE, n = 100, ...) {
-    df <- data.frame(data[, c("x", "y")])
-    df <- remove_missing(df, na.rm, name = "stat_density2d", finite = TRUE)
+  compute_group = function(data, scales, na.rm = FALSE, h = NULL,
+                           contour = TRUE, n = 100) {
+    if (is.null(h)) {
+      h <- c(MASS::bandwidth.nrd(data$x), MASS::bandwidth.nrd(data$y))
+    }
 
-    dens <- safe.call(kde2d, list(x = df$x, y = df$y, n = n,
-      lims = c(scale_dimension(scales$x), scale_dimension(scales$y)), ...))
-    df <- with(dens, data.frame(expand.grid(x = x, y = y), z = as.vector(z)))
+    dens <- MASS::kde2d(
+      data$x, data$y, h = h, n = n,
+      lims = c(scales$x$dimension(), scales$y$dimension())
+    )
+    df <- data.frame(expand.grid(x = dens$x, y = dens$y), z = as.vector(dens$z))
     df$group <- data$group[1]
 
     if (contour) {
-      StatContour$calculate(df, scales, ...)
+      StatContour$compute_panel(df, scales)
     } else {
       names(df) <- c("x", "y", "density", "group")
       df$level <- 1
@@ -85,4 +64,4 @@ StatDensity2d <- proto(Stat, {
       df
     }
   }
-})
+)
diff --git a/R/stat-density.r b/R/stat-density.r
index 3a39db6..5f6b285 100644
--- a/R/stat-density.r
+++ b/R/stat-density.r
@@ -1,124 +1,92 @@
-#' 1d kernel density estimate.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "density")}
-#'
 #' @param adjust see \code{\link{density}} for details
 #' @param kernel kernel used for density estimation, see
 #'   \code{\link{density}} for details
-#' @param trim if \code{TRUE}, the default, densities are trimmed to the
-#'   actual range of the data.  If \code{FALSE}, they are extended by the
-#'   default 3 bandwidths (as specified by the \code{cut} parameter to
-#'   \code{\link{density}})
-#' @param na.rm If \code{FALSE} (the default), removes missing values with
-#'    a warning.  If \code{TRUE} silently removes missing values.
-#' @inheritParams stat_identity
-#' @return data.frame with additional columns:
+#' @param trim This parameter only matters if you are displaying multiple
+#'   densities in one plot. If \code{FALSE}, the default, each density is
+#'   computed on the full range of the data. If \code{TRUE}, each density
+#'   is computed over the range of that group: this typically means the
+#'   estimated x values will not line-up, and hence you won't be able to
+#'   stack density values.
+#' @section Computed variables:
+#' \describe{
 #'   \item{density}{density estimate}
 #'   \item{count}{density * number of points - useful for stacked density
 #'      plots}
 #'   \item{scaled}{density estimate, scaled to maximum of 1}
-#' @seealso \code{\link{stat_bin}} for the histogram
-#' @export
-#' @examples
-#' \donttest{
-#' m <- ggplot(movies, aes(x = rating))
-#' m + geom_density()
-#'
-#' # Adjust parameters
-#' m + geom_density(kernel = "rectangular")
-#' m + geom_density(kernel = "biweight")
-#' m + geom_density(kernel = "epanechnikov")
-#' m + geom_density(adjust=1/5) # Very rough
-#' m + geom_density(adjust=5) # Very smooth
-#'
-#' # Adjust aesthetics
-#' m + geom_density(aes(fill=factor(Drama)), size=2)
-#' # Scale so peaks have same height:
-#' m + geom_density(aes(fill=factor(Drama), y = ..scaled..), size=2)
-#'
-#' m + geom_density(colour="darkgreen", size=2)
-#' m + geom_density(colour="darkgreen", size=2, fill=NA)
-#' m + geom_density(colour="darkgreen", size=2, fill="green")
-#'
-#' # Change scales
-#' (m <- ggplot(movies, aes(x=votes)) + geom_density(trim = TRUE))
-#' m + scale_x_log10()
-#' m + coord_trans(x="log10")
-#' m + scale_x_log10() + coord_trans(x="log10")
-#'
-#' # Also useful with
-#' m + stat_bin()
-#'
-#' # Make a volcano plot
-#' ggplot(diamonds, aes(x = price)) +
-#'   stat_density(aes(ymax = ..density..,  ymin = -..density..),
-#'     fill = "grey50", colour = "grey50",
-#'     geom = "ribbon", position = "identity") +
-#'   facet_grid(. ~ cut) +
-#'   coord_flip()
-#'
-#' # Stacked density plots
-#' # If you want to create a stacked density plot, you need to use
-#' # the 'count' (density * n) variable instead of the default density
-#'
-#' # Loses marginal densities
-#' qplot(rating, ..density.., data=movies, geom="density", fill=mpaa, position="stack")
-#' # Preserves marginal densities
-#' qplot(rating, ..count.., data=movies, geom="density", fill=mpaa, position="stack")
-#'
-#' # You can use position="fill" to produce a conditional density estimate
-#' qplot(rating, ..count.., data=movies, geom="density", fill=mpaa, position="fill")
-#'
-#' # Need to be careful with weighted data
-#' m <- ggplot(movies, aes(x=rating, weight=votes))
-#' m + geom_histogram(aes(y = ..count..)) + geom_density(fill=NA)
-#'
-#' m <- ggplot(movies, aes(x=rating, weight=votes/sum(votes)))
-#' m + geom_histogram(aes(y=..density..)) + geom_density(fill=NA, colour="black")
-#'
-#' library(plyr) # to access round_any
-#' movies$decade <- round_any(movies$year, 10)
-#' m <- ggplot(movies, aes(x=rating, colour=decade, group=decade))
-#' m + geom_density(fill=NA)
-#' m + geom_density(fill=NA) + aes(y = ..count..)
-#'
-#' # Use qplot instead
-#' qplot(length, data=movies, geom="density", weight=rating)
-#' qplot(length, data=movies, geom="density", weight=rating/sum(rating))
 #' }
-stat_density <- function (mapping = NULL, data = NULL, geom = "area", position = "stack",
-adjust = 1, kernel = "gaussian", trim = FALSE, na.rm = FALSE, ...) {
-  StatDensity$new(mapping = mapping, data = data, geom = geom, position = position,
-  adjust = adjust, kernel = kernel, trim = trim, na.rm = na.rm, ...)
-}
+#' @export
+#' @rdname geom_density
+stat_density <- function(mapping = NULL, data = NULL, geom = "area",
+                         position = "stack", adjust = 1, kernel = "gaussian",
+                         trim = FALSE, na.rm = FALSE,
+                         show.legend = NA, inherit.aes = TRUE, ...) {
 
-StatDensity <- proto(Stat, {
-  objname <- "density"
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatDensity,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      adjust = adjust,
+      kernel = kernel,
+      trim = trim,
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
 
-  calculate <- function(., data, scales, adjust=1, kernel="gaussian", trim=FALSE, na.rm = FALSE, ...) {
-    data <- remove_missing(data, na.rm, "x", name = "stat_density",
-      finite = TRUE)
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatDensity <- ggproto("StatDensity", Stat,
+  required_aes = "x",
+  default_aes = aes(y = ..density.., fill = NA),
 
-    n <- nrow(data)
-    if (n < 3) return(data.frame())
-    if (is.null(data$weight)) data$weight <- rep(1, n) / n
+  compute_group = function(data, scales, adjust = 1, kernel = "gaussian",
+                           trim = FALSE, na.rm = FALSE) {
+    if (trim) {
+      range <- range(data$x, na.rm = TRUE)
+    } else {
+      range <- scales$x$dimension()
+    }
 
-    range <- scale_dimension(scales$x, c(0, 0))
-    xgrid <- seq(range[1], range[2], length=200)
+    compute_density(data$x, data$weight, from = range[1], to = range[2],
+      adjust = adjust, kernel = kernel)
+  }
 
-    dens <- density(data$x, adjust=adjust, kernel=kernel, weight=data$weight, from=range[1], to=range[2])
-    densdf <- as.data.frame(dens[c("x","y")])
+)
 
-    densdf$scaled <- densdf$y / max(densdf$y, na.rm = TRUE)
-    if (trim) densdf <- subset(densdf, x > min(data$x, na.rm = TRUE) & x < max(data$x, na.rm = TRUE))
+compute_density <- function(x, w, from, to, bw = "nrd0", adjust = 1,
+                            kernel = "gaussian") {
+  n <- length(x)
+  if (is.null(w)) {
+    w <- rep(1 / n, n)
+  }
 
-    densdf$count <- densdf$y * n
-    rename(densdf, c(y = "density"), warn_missing = FALSE)
+  # if less than 3 points, spread density evenly over points
+  if (n < 3) {
+    return(data.frame(
+      x = x,
+      density = w / sum(w),
+      scaled = w / max(w),
+      count = 1,
+      n = n
+    ))
   }
 
-  default_geom <- function(.) GeomArea
-  default_aes <- function(.) aes(y = ..density.., fill=NA)
-  required_aes <- c("x")
+  dens <- stats::density(x, weights = w, bw = bw, adjust = adjust,
+    kernel = kernel, from = from, to = to)
 
-})
+  data.frame(
+    x = dens$x,
+    density = dens$y,
+    scaled =  dens$y / max(dens$y, na.rm = TRUE),
+    count =   dens$y * n,
+    n = n
+  )
+}
diff --git a/R/stat-ecdf.r b/R/stat-ecdf.r
index 792fcc6..4e0f5f3 100644
--- a/R/stat-ecdf.r
+++ b/R/stat-ecdf.r
@@ -1,29 +1,52 @@
 #' Empirical Cumulative Density Function
 #'
 #' @inheritParams stat_identity
+#' @param na.rm If \code{FALSE} (the default), removes missing values with
+#'    a warning.  If \code{TRUE} silently removes missing values.
 #' @param n if NULL, do not interpolate. If not NULL, this is the number
 #'   of points to interpolate with.
-#' @return a data.frame with additional columns:
+#' @section Computed variables:
+#' \describe{
 #'   \item{x}{x in data}
 #'   \item{y}{cumulative density corresponding x}
+#' }
 #' @export
 #' @examples
 #' \donttest{
-#' qplot(rnorm(1000), stat = "ecdf", geom = "step")
+#' df <- data.frame(x = rnorm(1000))
+#' ggplot(df, aes(x)) + stat_ecdf(geom = "step")
 #'
 #' df <- data.frame(x = c(rnorm(100, 0, 3), rnorm(100, 0, 10)),
 #'                  g = gl(2, 100))
 #'
 #' ggplot(df, aes(x, colour = g)) + stat_ecdf()
 #' }
-stat_ecdf <- function (mapping = NULL, data = NULL, geom = "step", position = "identity", n = NULL, ...) {
-  StatEcdf$new(mapping = mapping, data = data, geom = geom, position = position, n = n, ...)
+stat_ecdf <- function(mapping = NULL, data = NULL, geom = "step",
+                      position = "identity", n = NULL, na.rm = FALSE,
+                      show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatEcdf,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      n = n,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-StatEcdf <- proto(Stat, {
-  objname <- "ecdf"
 
-  calculate <- function(., data, scales, n = NULL, ...) {
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatEcdf <- ggproto("StatEcdf", Stat,
+  compute_group = function(data, scales, n = NULL) {
 
     # If n is NULL, use raw values; otherwise interpolate
     if (is.null(n)) {
@@ -48,11 +71,10 @@ StatEcdf <- proto(Stat, {
     y1 <- 1
 
     data.frame(x = c(x0, xvals, x1), y = c(y0, y, y1))
-  }
+  },
 
-  default_aes <- function(.) aes(y = ..y..)
-  required_aes <- c("x")
-  default_geom <- function(.) GeomStep
+  default_aes = aes(y = ..y..),
 
-})
+  required_aes = c("x")
+)
 
diff --git a/R/stat-ellipse.R b/R/stat-ellipse.R
index 861da58..9eb6001 100644
--- a/R/stat-ellipse.R
+++ b/R/stat-ellipse.R
@@ -1,95 +1,108 @@
 #' Plot data ellipses.
 #'
+#' The method for calculating the ellipses has been modified from
+#' \code{car::ellipse} (Fox and Weisberg, 2011)
+#'
+#' @references John Fox and Sanford Weisberg (2011). An {R} Companion to
+#'   Applied Regression, Second Edition. Thousand Oaks CA: Sage. URL:
+#'   \url{http://socserv.socsci.mcmaster.ca/jfox/Books/Companion}
 #' @param level The confidence level at which to draw an ellipse (default is 0.95),
 #'   or, if \code{type="euclid"}, the radius of the circle to be drawn.
 #' @param type The type of ellipse.
 #'   The default \code{"t"} assumes a multivariate t-distribution, and
 #'   \code{"norm"} assumes a multivariate normal distribution.
 #'   \code{"euclid"} draws a circle with the radius equal to \code{level},
-#'   representing the euclidian distance from the center.
+#'   representing the euclidean distance from the center.
 #'   This ellipse probably won't appear circular unless \code{coord_fixed()} is applied.
 #' @param segments The number of segments to be used in drawing the ellipse.
 #' @param na.rm If \code{FALSE} (the default), removes missing values with
-#'   a warning.  If \code{TRUE} silently removes missing values.
+#'    a warning.  If \code{TRUE} silently removes missing values.
 #' @inheritParams stat_identity
-#'
-#' @details The method for calculating the ellipses has been modified from car::ellipse (Fox and Weisberg, 2011)
-#'
-#' @references
-#' John Fox and Sanford Weisberg (2011). An {R} Companion to Applied Regression, Second Edition. Thousand Oaks CA: Sage. URL: http://socserv.socsci.mcmaster.ca/jfox/Books/Companion
-#'
 #' @export
-#' @importFrom MASS cov.trob
-#'
 #' @examples
-#' ggplot(faithful, aes(waiting, eruptions))+
-#'   geom_point()+
+#' ggplot(faithful, aes(waiting, eruptions)) +
+#'   geom_point() +
 #'   stat_ellipse()
 #'
-#' ggplot(faithful, aes(waiting, eruptions, color = eruptions > 3))+
-#'   geom_point()+
+#' ggplot(faithful, aes(waiting, eruptions, color = eruptions > 3)) +
+#'   geom_point() +
 #'   stat_ellipse()
 #'
-#' ggplot(faithful, aes(waiting, eruptions, color = eruptions > 3))+
-#'   geom_point()+
-#'   stat_ellipse(type = "norm", linetype = 2)+
+#' ggplot(faithful, aes(waiting, eruptions, color = eruptions > 3)) +
+#'   geom_point() +
+#'   stat_ellipse(type = "norm", linetype = 2) +
 #'   stat_ellipse(type = "t")
 #'
-#' ggplot(faithful, aes(waiting, eruptions, color = eruptions > 3))+
-#'   geom_point()+
-#'   stat_ellipse(type = "norm", linetype = 2)+
-#'   stat_ellipse(type = "euclid", level = 3)+
+#' ggplot(faithful, aes(waiting, eruptions, color = eruptions > 3)) +
+#'   geom_point() +
+#'   stat_ellipse(type = "norm", linetype = 2) +
+#'   stat_ellipse(type = "euclid", level = 3) +
 #'   coord_fixed()
 #'
-#' ggplot(faithful, aes(waiting, eruptions, color = eruptions > 3))+
+#' ggplot(faithful, aes(waiting, eruptions, fill = eruptions > 3)) +
 #'   stat_ellipse(geom = "polygon")
-
-stat_ellipse <- function(mapping = NULL, data = NULL, geom = "path", position = "identity", type = "t", level = 0.95, segments = 51, na.rm = FALSE, ...) {
-  StatEllipse$new(mapping = mapping, data = data, geom = geom, position = position, type = type, level = level, segments = segments, na.rm = na.rm, ...)
+stat_ellipse <- function(mapping = NULL, data = NULL, geom = "path",
+                         position = "identity", type = "t", level = 0.95,
+                         segments = 51, na.rm = FALSE, show.legend = NA,
+                         inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatEllipse,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      type = type,
+      level = level,
+      segments = segments,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-StatEllipse <- proto(Stat, {
-  objname <- "ellipse"
-
-  required_aes <- c("x", "y")
-  default_geom <- function(.) GeomPath
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatEllipse <- ggproto("StatEllipse", Stat,
+  required_aes = c("x", "y"),
 
-  calculate_groups <- function(., data, scales, ...){
-    .super$calculate_groups(., data, scales,...)
-  }
-  calculate <- function(., data, scales, type = "t", level = 0.95, segments = 51, na.rm = FALSE, ...){
-    data <- remove_missing(data, na.rm, vars = c("x","y"), name = "stat_ellipse", finite = TRUE)
-    ellipse <- calculate_ellipse(data=data, vars= c("x","y"), type=type, level=level, segments=segments)
-    return(ellipse)
+  compute_group = function(data, scales, type = "t", level = 0.95,
+                           segments = 51, na.rm = FALSE) {
+    calculate_ellipse(data = data, vars = c("x", "y"), type = type,
+                      level = level, segments = segments)
   }
-})
+)
 
 calculate_ellipse <- function(data, vars, type, level, segments){
   dfn <- 2
   dfd <- nrow(data) - 1
 
-  if (!type %in% c("t", "norm", "euclid")){
+  if (!type %in% c("t", "norm", "euclid")) {
     message("Unrecognized ellipse type")
     ellipse <- rbind(as.numeric(c(NA, NA)))
-  } else if (dfd < 3){
+  } else if (dfd < 3) {
     message("Too few points to calculate an ellipse")
     ellipse <- rbind(as.numeric(c(NA, NA)))
   } else {
-    if (type == "t"){
-      v <- cov.trob(data[,vars])
-    } else if (type == "norm"){
-      v <- cov.wt(data[,vars])
-    } else if (type == "euclid"){
-      v <- cov.wt(data[,vars])
+    if (type == "t") {
+      v <- MASS::cov.trob(data[,vars])
+    } else if (type == "norm") {
+      v <- stats::cov.wt(data[,vars])
+    } else if (type == "euclid") {
+      v <- stats::cov.wt(data[,vars])
       v$cov <- diag(rep(min(diag(v$cov)), 2))
     }
     shape <- v$cov
     center <- v$center
     chol_decomp <- chol(shape)
-    if (type == "euclid"){
+    if (type == "euclid") {
       radius <- level/max(chol_decomp)
     } else {
-      radius <- sqrt(dfn * qf(level, dfn, dfd))
+      radius <- sqrt(dfn * stats::qf(level, dfn, dfd))
     }
     angles <- (0:segments) * 2 * pi/segments
     unit.circle <- cbind(cos(angles), sin(angles))
@@ -98,5 +111,5 @@ calculate_ellipse <- function(data, vars, type, level, segments){
 
   ellipse <- as.data.frame(ellipse)
   colnames(ellipse) <- vars
-  return(ellipse)
+  ellipse
 }
diff --git a/R/stat-function.r b/R/stat-function.r
index db3da09..69ee89d 100644
--- a/R/stat-function.r
+++ b/R/stat-function.r
@@ -6,14 +6,22 @@
 #' @param fun function to use
 #' @param n number of points to interpolate along
 #' @param args list of additional arguments to pass to \code{fun}
+#' @param na.rm If \code{FALSE} (the default), removes missing values with
+#'    a warning.  If \code{TRUE} silently removes missing values.
 #' @inheritParams stat_identity
-#' @return a data.frame with additional columns:
+#' @section Computed variables:
+#' \describe{
 #'   \item{x}{x's along a grid}
 #'   \item{y}{value of function evaluated at corresponding x}
+#' }
 #' @export
 #' @examples
-#' x <- rnorm(100)
-#' base <- qplot(x, geom = "density")
+#' set.seed(1492)
+#' df <- data.frame(
+#'   x = rnorm(100)
+#' )
+#' x <- df$x
+#' base <- ggplot(df, aes(x)) + geom_density()
 #' base + stat_function(fun = dnorm, colour = "red")
 #' base + stat_function(fun = dnorm, colour = "red", arg = list(mean = 3))
 #'
@@ -21,14 +29,12 @@
 #' # Examples adapted from Kohske Takahashi
 #'
 #' # Specify range of x-axis
-#' qplot(c(0, 2), stat = "function", fun = exp, geom = "line")
-#' ggplot(data.frame(x = c(0, 2)), aes(x)) + stat_function(fun = exp)
+#' ggplot(data.frame(x = c(0, 2)), aes(x)) +
+#'   stat_function(fun = exp, geom = "line")
+#'
 #' # Plot a normal curve
 #' ggplot(data.frame(x = c(-5, 5)), aes(x)) + stat_function(fun = dnorm)
-#' # With qplot
-#' qplot(c(-5, 5), stat = "function", fun = dnorm, geom = "line")
-#' # Or
-#' qplot(c(-5, 5), geom = "blank") + stat_function(fun = dnorm)
+#'
 #' # To specify a different mean or sd, use the args parameter to supply new values
 #' ggplot(data.frame(x = c(-5, 5)), aes(x)) +
 #'   stat_function(fun = dnorm, args = list(mean = 2, sd = .5))
@@ -41,25 +47,42 @@
 #' # Using a custom function
 #' test <- function(x) {x ^ 2 + x + 20}
 #' f + stat_function(fun = test)
-stat_function <- function (mapping = NULL, data = NULL, geom = "path", position = "identity",
-fun, n = 101, args = list(), ...) {
-  StatFunction$new(mapping = mapping, data = data, geom = geom,
-  position = position, fun = fun, n = n, args = args, ...)
+stat_function <- function(mapping = NULL, data = NULL, geom = "path",
+                          position = "identity", fun, n = 101, args = list(),
+                          na.rm = FALSE, show.legend = NA, inherit.aes = TRUE,
+                          ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatFunction,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      fun = fun,
+      n = n,
+      args = args,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-StatFunction <- proto(Stat, {
-  objname <- "function"
-
-  default_geom <- function(.) GeomPath
-  default_aes <- function(.) aes(y = ..y..)
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatFunction <- ggproto("StatFunction", Stat,
+  default_aes = aes(y = ..y..),
 
-  calculate <- function(., data, scales, fun, n=101, args = list(), ...) {
-    range <- scale_dimension(scales$x, c(0, 0))
-    xseq <- seq(range[1], range[2], length=n)
+  compute_group = function(data, scales, fun, n = 101, args = list()) {
+    range <- scales$x$dimension()
+    xseq <- seq(range[1], range[2], length.out = n)
 
     data.frame(
       x = xseq,
-      y = do.call(fun, c(list(xseq), args))
+      y = do.call(fun, c(list(quote(scales$x$trans$inv(xseq))), args))
     )
   }
-})
+)
diff --git a/R/stat-identity.r b/R/stat-identity.r
index 95f422a..9b2781a 100644
--- a/R/stat-identity.r
+++ b/R/stat-identity.r
@@ -1,7 +1,6 @@
 #' Identity statistic.
 #'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "identity")}
+#' The identity statistic leaves the data unchanged.
 #'
 #' @param mapping The aesthetic mapping, usually constructed with
 #'    \code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
@@ -9,33 +8,46 @@
 #' @param data A layer specific dataset - only needed if you want to override
 #'    the plot defaults.
 #' @param geom The geometric object to use display the data
-#' @param position The position adjustment to use for overlappling points
+#' @param position The position adjustment to use for overlapping points
 #'    on this layer
-#' @param width The width of the tiles.
-#' @param height The height of the tiles.
+#' @param show.legend logical. Should this layer be included in the legends?
+#'   \code{NA}, the default, includes if any aesthetics are mapped.
+#'   \code{FALSE} never includes, and \code{TRUE} always includes.
+#' @param inherit.aes If \code{FALSE}, overrides the default aesthetics,
+#'   rather than combining with them. This is most useful for helper functions
+#'   that define both data and aesthetics and shouldn't inherit behaviour from
+#'   the default plot specification, e.g. \code{\link{borders}}.
 #' @param ... other arguments passed on to \code{\link{layer}}. This can
 #'   include aesthetics whose values you want to set, not map. See
 #'   \code{\link{layer}} for more details.
 #' @export
 #' @examples
-#' # Doesn't do anything, so hard to come up a useful example
-stat_identity <- function (mapping = NULL, data = NULL, geom = "point",
-  position = "identity", width = NULL, height = NULL, ...) {
-
-  StatIdentity$new(mapping = mapping, data = data, geom = geom,
-  position = position, width = width, height = height,...)
+#' p <- ggplot(mtcars, aes(wt, mpg))
+#' p + stat_identity()
+stat_identity <- function(mapping = NULL, data = NULL, geom = "point",
+                          position = "identity", show.legend = NA,
+                          inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatIdentity,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = FALSE,
+      ...
+    )
+  )
 }
 
-StatIdentity <- proto(Stat, {
-  objname <- "identity"
-
-  default_geom <- function(.) GeomPoint
-  calculate_groups <- function(., data, scales, width = NULL, height = NULL, ...) {
-    if (!is.null(width))   data$width  <- width
-    if (!is.null(height))  data$height <- height
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatIdentity <- ggproto("StatIdentity", Stat,
+  compute_layer = function(data, scales, params) {
     data
   }
-
-  desc_outputs <- list()
-
-})
+)
diff --git a/R/stat-qq.r b/R/stat-qq.r
index a1dd7a7..6647936 100644
--- a/R/stat-qq.r
+++ b/R/stat-qq.r
@@ -4,70 +4,85 @@
 #' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "qq")}
 #'
 #' @param distribution Distribution function to use, if x not specified
-#' @param dparams Parameters for distribution function
-#' @param ... Other arguments passed to distribution function
+#' @param dparams Additional parameters passed on to \code{distribution}
+#'   function.
 #' @param na.rm If \code{FALSE} (the default), removes missing values with
 #'    a warning.  If \code{TRUE} silently removes missing values.
 #' @inheritParams stat_identity
-#' @return a data.frame with additional columns:
+#' @section Computed variables:
+#' \describe{
 #'   \item{sample}{sample quantiles}
 #'   \item{theoretical}{theoretical quantiles}
+#' }
 #' @export
 #' @examples
 #' \donttest{
-#' # From ?qqplot
-#' y <- rt(200, df = 5)
-#' qplot(sample = y, stat="qq")
-#'
-#' # qplot is smart enough to use stat_qq if you use sample
-#' qplot(sample = y)
-#' qplot(sample = precip)
-#'
-#' qplot(sample = y, dist = qt, dparams = list(df = 5))
-#'
-#' df <- data.frame(y)
-#' ggplot(df, aes(sample = y)) + stat_qq()
-#' ggplot(df, aes(sample = y)) + geom_point(stat = "qq")
+#' df <- data.frame(y = rt(200, df = 5))
+#' p <- ggplot(df, aes(sample = y))
+#' p + stat_qq()
+#' p + geom_point(stat = "qq")
 #'
 #' # Use fitdistr from MASS to estimate distribution params
-#' library(MASS)
-#' params <- as.list(fitdistr(y, "t")$estimate)
-#' ggplot(df, aes(sample = y)) + stat_qq(dist = qt, dparam = params)
+#' params <- as.list(MASS::fitdistr(df$y, "t")$estimate)
+#' ggplot(df, aes(sample = y)) +
+#'   stat_qq(distribution = qt, dparams = params["df"])
 #'
 #' # Using to explore the distribution of a variable
-#' qplot(sample = mpg, data = mtcars)
-#' qplot(sample = mpg, data = mtcars, colour = factor(cyl))
+#' ggplot(mtcars) +
+#'   stat_qq(aes(sample = mpg))
+#' ggplot(mtcars) +
+#'   stat_qq(aes(sample = mpg, colour = factor(cyl)))
 #' }
-stat_qq <- function (mapping = NULL, data = NULL, geom = "point", position = "identity",
-distribution = qnorm, dparams = list(), na.rm = FALSE, ...) {
-  StatQq$new(mapping = mapping, data = data, geom = geom, position = position,
-  distribution = distribution, dparams = dparams, na.rm = na.rm, ...)
+stat_qq <- function(mapping = NULL, data = NULL, geom = "point",
+                    position = "identity", distribution = stats::qnorm,
+                    dparams = list(), na.rm = FALSE,
+                    show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatQq,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      distribution = distribution,
+      dparams = dparams,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-StatQq <- proto(Stat, {
-  objname <- "qq"
+#' @export
+#' @rdname stat_qq
+geom_qq <- stat_qq
 
-  default_geom <- function(.) GeomPoint
-  default_aes <- function(.) aes(y = ..sample.., x = ..theoretical..)
-  required_aes <- c("sample")
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatQq <- ggproto("StatQq", Stat,
+  default_aes = aes(y = ..sample.., x = ..theoretical..),
+
+  required_aes = c("sample"),
 
-  calculate <- function(., data, scales, quantiles = NULL, distribution = qnorm, dparams = list(), na.rm = FALSE) {
-    data <- remove_missing(data, na.rm, "sample", name = "stat_qq")
+  compute_group = function(data, scales, quantiles = NULL,
+                           distribution = stats::qnorm, dparams = list(),
+                           na.rm = FALSE) {
 
     sample <- sort(data$sample)
     n <- length(sample)
 
     # Compute theoretical quantiles
     if (is.null(quantiles)) {
-      quantiles <- ppoints(n)
+      quantiles <- stats::ppoints(n)
     } else {
       stopifnot(length(quantiles) == n)
     }
 
-    theoretical <- safe.call(distribution, c(list(p = quantiles), dparams))
+    theoretical <- do.call(distribution, c(list(p = quote(quantiles)), dparams))
 
     data.frame(sample, theoretical)
   }
-
-
-})
+)
diff --git a/R/stat-quantile.r b/R/stat-quantile.r
index 02f6303..d927561 100644
--- a/R/stat-quantile.r
+++ b/R/stat-quantile.r
@@ -1,72 +1,54 @@
-#' Continuous quantiles.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "quantile")}
-#'
 #' @param quantiles conditional quantiles of y to calculate and display
 #' @param formula formula relating y variables to x variables
 #' @param method Quantile regression method to use.  Currently only supports
 #'    \code{\link[quantreg]{rq}}.
-#' @param na.rm If \code{FALSE} (the default), removes missing values with
-#'    a warning.  If \code{TRUE} silently removes missing values.
 #' @inheritParams stat_identity
-#' @return a data.frame with additional columns:
+#' @section Computed variables:
+#' \describe{
 #'   \item{quantile}{quantile of distribution}
-#' @export
-#' @examples
-#' \donttest{
-#' msamp <- movies[sample(nrow(movies), 1000), ]
-#' m <- ggplot(msamp, aes(year, rating)) + geom_point()
-#' m + stat_quantile()
-#' m + stat_quantile(quantiles = 0.5)
-#' q10 <- seq(0.05, 0.95, by=0.05)
-#' m + stat_quantile(quantiles = q10)
-#'
-#' # You can also use rqss to fit smooth quantiles
-#' m + stat_quantile(method = "rqss")
-#' # Note that rqss doesn't pick a smoothing constant automatically, so
-#' # you'll need to tweak lambda yourself
-#' m + stat_quantile(method = "rqss", lambda = 10)
-#' m + stat_quantile(method = "rqss", lambda = 100)
-#'
-#' # Use 'votes' as weights for the quantile calculation
-#' m + stat_quantile(aes(weight=votes))
-#'
-#' # Change scale
-#' m + stat_quantile(aes(colour = ..quantile..), quantiles = q10)
-#' m + stat_quantile(aes(colour = ..quantile..), quantiles = q10) +
-#'   scale_colour_gradient2(midpoint = 0.5)
-#'
-#' # Set aesthetics to fixed value
-#' m + stat_quantile(colour = "red", size = 2, linetype = 2)
-#'
-#' # Use qplot instead
-#' qplot(year, rating, data=movies, geom="quantile")
 #' }
-stat_quantile <- function (mapping = NULL, data = NULL, geom = "quantile", position = "identity",
-quantiles = c(0.25, 0.5, 0.75), formula = NULL, method = "rq",
-na.rm = FALSE, ...) {
-  StatQuantile$new(mapping = mapping, data = data, geom = geom,
-  position = position, quantiles = quantiles, formula = formula,
-  method = method, na.rm = na.rm, ...)
+#' @export
+#' @rdname geom_quantile
+stat_quantile <- function(mapping = NULL, data = NULL, geom = "quantile",
+                          position = "identity", quantiles = c(0.25, 0.5, 0.75),
+                          formula = NULL, method = "rq", method.args = list(),
+                          na.rm = FALSE, show.legend = NA, inherit.aes = TRUE,
+                          ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatQuantile,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      quantiles = quantiles,
+      formula = formula,
+      method = method,
+      method.args = method.args,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-StatQuantile <- proto(Stat, {
-  objname <- "quantile"
 
-  default_geom <- function(.) GeomQuantile
-  default_aes <- function(.) aes()
-  required_aes <- c("x", "y")
-
-  calculate <- function(., data, scales, quantiles = c(0.25, 0.5, 0.75),
-    formula = NULL, xseq = NULL, method = "rq", lambda = 1, na.rm = FALSE,
-    ...) {
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatQuantile <- ggproto("StatQuantile", Stat,
+  required_aes = c("x", "y"),
 
-    try_require("quantreg")
+  compute_group = function(data, scales, quantiles = c(0.25, 0.5, 0.75),
+                           formula = NULL, xseq = NULL, method = "rq",
+                           method.args = list(), lambda = 1, na.rm = FALSE) {
+    try_require("quantreg", "stat_quantile")
 
     if (is.null(formula)) {
       if (method == "rqss") {
-        try_require("MatrixModels")
+        try_require("MatrixModels", "stat_quantile")
         formula <- eval(substitute(y ~ qss(x, lambda = lambda)),
           list(lambda = lambda))
       } else {
@@ -81,23 +63,24 @@ StatQuantile <- proto(Stat, {
     if (is.null(xseq)) {
       xmin <- min(data$x, na.rm = TRUE)
       xmax <- max(data$x, na.rm = TRUE)
-      xseq <- seq(xmin, xmax, length = 100)
+      xseq <- seq(xmin, xmax, length.out = 100)
     }
     grid <- data.frame(x = xseq)
 
-    data <- as.data.frame(data)
-    data <- remove_missing(data, na.rm, c("x", "y"), name = "stat_quantile")
     method <- match.fun(method)
 
-    ldply(quantiles, quant_pred, data = data, method = method,
-      formula = formula, weight = weight, grid = grid, ...)
+    plyr::ldply(quantiles, quant_pred, data = data, method = method,
+      formula = formula, weight = weight, grid = grid, method.args = method.args)
   }
-})
+)
 
-quant_pred <- function(quantile, data, method, formula, weight, grid, ...) {
-  model <- method(formula, data = data, tau = quantile, weight = weight, ...)
+quant_pred <- function(quantile, data, method, formula, weight, grid,
+                       method.args = method.args) {
+  args <- c(list(quote(formula), data = quote(data), tau = quote(quantile),
+    weights = quote(weight)), method.args)
+  model <- do.call(method, args)
 
-  grid$y <- predict(model, newdata = grid)
+  grid$y <- stats::predict(model, newdata = grid)
   grid$quantile <- quantile
   grid$group <- paste(data$group[1], quantile, sep = "-")
 
diff --git a/R/stat-smooth-methods.r b/R/stat-smooth-methods.r
index 36b9ea3..a7ac2a3 100644
--- a/R/stat-smooth-methods.r
+++ b/R/stat-smooth-methods.r
@@ -10,13 +10,13 @@ predictdf <- function(model, xseq, se, level) UseMethod("predictdf")
 
 #' @export
 predictdf.default <- function(model, xseq, se, level) {
-  pred <- stats::predict(model, newdata = data.frame(x = xseq), se = se,
-    level = level, interval = if(se) "confidence" else "none")
+  pred <- stats::predict(model, newdata = data.frame(x = xseq), se.fit = se,
+    level = level, interval = if (se) "confidence" else "none")
 
   if (se) {
     fit <- as.data.frame(pred$fit)
     names(fit) <- c("y", "ymin", "ymax")
-    data.frame(x = xseq, fit, se = pred$se)
+    data.frame(x = xseq, fit, se = pred$se.fit)
   } else {
     data.frame(x = xseq, y = as.vector(pred))
   }
@@ -24,11 +24,11 @@ predictdf.default <- function(model, xseq, se, level) {
 
 #' @export
 predictdf.glm <- function(model, xseq, se, level) {
-  pred <- stats::predict(model, newdata = data.frame(x = xseq), se = se,
+  pred <- stats::predict(model, newdata = data.frame(x = xseq), se.fit = se,
     type = "link")
 
   if (se) {
-    std <- qnorm(level / 2 + 0.5)
+    std <- stats::qnorm(level / 2 + 0.5)
     data.frame(
       x = xseq,
       y = model$family$linkinv(as.vector(pred$fit)),
@@ -47,7 +47,7 @@ predictdf.loess <- function(model, xseq, se, level) {
 
   if (se) {
     y = pred$fit
-    ci <- pred$se.fit * qt(level / 2 + .5, pred$df)
+    ci <- pred$se.fit * stats::qt(level / 2 + .5, pred$df)
     ymin = y - ci
     ymax = y + ci
     data.frame(x = xseq, y, ymin, ymax, se = pred$se.fit)
@@ -58,7 +58,7 @@ predictdf.loess <- function(model, xseq, se, level) {
 
 #' @export
 predictdf.locfit <- function(model, xseq, se, level) {
-  pred <- predict(model, newdata = data.frame(x = xseq), se.fit = se)
+  pred <- stats::predict(model, newdata = data.frame(x = xseq), se.fit = se)
 
   if (se) {
     y = pred$fit
diff --git a/R/stat-smooth.r b/R/stat-smooth.r
index 74a3079..22f30a3 100644
--- a/R/stat-smooth.r
+++ b/R/stat-smooth.r
@@ -1,18 +1,3 @@
-#' Add a smoother.
-#'
-#' Aids the eye in seeing patterns in the presence of overplotting.
-#'
-#' Calculation is performed by the (currently undocumented)
-#' \code{predictdf} generic function and its methods.  For most methods
-#' the confidence bounds are computed using the \code{\link{predict}}
-#' method - the exceptions are \code{loess} which uses a t-based
-#' approximation, and for \code{glm} where the normal confidence interval
-#' is constructed on the link scale, and then back-transformed to the response
-#' scale.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "smooth")}
-#'
 #' @param method smoothing method (function) to use, eg. lm, glm, gam, loess,
 #'   rlm. For datasets with n < 1000 default is \code{\link{loess}}. For datasets
 #'   with 1000 or more observations defaults to gam, see \code{\link[mgcv]{gam}}
@@ -24,127 +9,80 @@
 #' @param fullrange should the fit span the full range of the plot, or just
 #'   the data
 #' @param level level of confidence interval to use (0.95 by default)
+#' @param span Controls the amount of smoothing for the default loess smoother.
+#'   Smaller numbers produce wigglier lines, larger numbers produce smoother
+#'   lines.
 #' @param n number of points to evaluate smoother at
-#' @param na.rm If \code{FALSE} (the default), removes missing values with
-#'    a warning.  If \code{TRUE} silently removes missing values.
-#' @param ... other arguments are passed to smoothing function
-#' @inheritParams stat_identity
-#' @return a data.frame with additional columns
+#' @param method.args List of additional arguments passed on to the modelling
+#'   function defined by \code{method}.
+#' @section Computed variables:
+#' \describe{
 #'   \item{y}{predicted value}
 #'   \item{ymin}{lower pointwise confidence interval around the mean}
 #'   \item{ymax}{upper pointwise confidence interval around the mean}
 #'   \item{se}{standard error}
-#' @seealso
-#'   \code{\link{lm}} for linear smooths,
-#'   \code{\link{glm}} for generalised linear smooths,
-#'   \code{\link{loess}} for local smooths
-#' @export
-#' @examples
-#' \donttest{
-#' c <- ggplot(mtcars, aes(qsec, wt))
-#' c + stat_smooth()
-#' c + stat_smooth() + geom_point()
-#'
-#' # Adjust parameters
-#' c + stat_smooth(se = FALSE) + geom_point()
-#'
-#' c + stat_smooth(span = 0.9) + geom_point()
-#' c + stat_smooth(level = 0.99) + geom_point()
-#' c + stat_smooth(method = "lm") + geom_point()
-#'
-#' library(splines)
-#' library(MASS)
-#' c + stat_smooth(method = "lm", formula = y ~ ns(x,3)) +
-#'   geom_point()
-#' c + stat_smooth(method = rlm, formula= y ~ ns(x,3)) + geom_point()
-#'
-#' # The default confidence band uses a transparent colour.
-#' # This currently only works on a limited number of graphics devices
-#' # (including Quartz, PDF, and Cairo) so you may need to set the
-#' # fill colour to a opaque colour, as shown below
-#' c + stat_smooth(fill = "grey50", size = 2, alpha = 1)
-#' c + stat_smooth(fill = "blue", size = 2, alpha = 1)
-#'
-#' # The colour of the line can be controlled with the colour aesthetic
-#' c + stat_smooth(fill="blue", colour="darkblue", size=2)
-#' c + stat_smooth(fill="blue", colour="darkblue", size=2, alpha = 0.2)
-#' c + geom_point() +
-#'   stat_smooth(fill="blue", colour="darkblue", size=2, alpha = 0.2)
-#'
-#' # Smoothers for subsets
-#' c <- ggplot(mtcars, aes(y=wt, x=mpg)) + facet_grid(. ~ cyl)
-#' c + stat_smooth(method=lm) + geom_point()
-#' c + stat_smooth(method=lm, fullrange = TRUE) + geom_point()
-#'
-#' # Geoms and stats are automatically split by aesthetics that are factors
-#' c <- ggplot(mtcars, aes(y=wt, x=mpg, colour=factor(cyl)))
-#' c + stat_smooth(method=lm) + geom_point()
-#' c + stat_smooth(method=lm, aes(fill = factor(cyl))) + geom_point()
-#' c + stat_smooth(method=lm, fullrange=TRUE, alpha = 0.1) + geom_point()
-#'
-#' # Use qplot instead
-#' qplot(qsec, wt, data=mtcars, geom=c("smooth", "point"))
-#' }
-#'
-#' \dontrun{
-#' # Example with logistic regression
-#' data("kyphosis", package="rpart")
-#' qplot(Age, Kyphosis, data=kyphosis)
-#' qplot(Age, data=kyphosis, facets = . ~ Kyphosis, binwidth = 10)
-#' qplot(Age, Kyphosis, data=kyphosis, position="jitter")
-#' qplot(Age, Kyphosis, data=kyphosis, position=position_jitter(height=0.1))
-#'
-#' qplot(Age, as.numeric(Kyphosis) - 1, data = kyphosis) +
-#'   stat_smooth(method="glm", family="binomial")
-#' qplot(Age, as.numeric(Kyphosis) - 1, data=kyphosis) +
-#'   stat_smooth(method="glm", family="binomial", formula = y ~ ns(x, 2))
 #' }
-stat_smooth <- function (mapping = NULL, data = NULL, geom = "smooth", position = "identity",
-method = "auto", formula = y ~ x, se = TRUE, n = 80, fullrange = FALSE,
-level = 0.95, na.rm = FALSE, ...) {
-  StatSmooth$new(mapping = mapping, data = data, geom = geom, position = position,
-  method = method, formula = formula, se = se, n = n, fullrange = fullrange,
-  level = level, na.rm = na.rm, ...)
+#' @export
+#' @rdname geom_smooth
+stat_smooth <- function(mapping = NULL, data = NULL, geom = "smooth",
+                        position = "identity", method = "auto", formula = y ~ x,
+                        se = TRUE, n = 80, span = 0.75, fullrange = FALSE,
+                        level = 0.95, method.args = list(),
+                        na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatSmooth,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      method = method,
+      formula = formula,
+      se = se,
+      n = n,
+      fullrange = fullrange,
+      level = level,
+      na.rm = na.rm,
+      method.args = method.args,
+      span = span,
+      ...
+    )
+  )
 }
 
-StatSmooth <- proto(Stat, {
-  objname <- "smooth"
-
-  calculate_groups <- function(., data, scales, method="auto", formula=y~x, ...) {
-    rows <- daply(data, .(group), function(df) length(unique(df$x)))
-
-    if (all(rows == 1) && length(rows) > 1) {
-      message("geom_smooth: Only one unique x value each group.",
-        "Maybe you want aes(group = 1)?")
-      return(data.frame())
-    }
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatSmooth <- ggproto("StatSmooth", Stat,
 
+  setup_params = function(data, params) {
     # Figure out what type of smoothing to do: loess for small datasets,
     # gam with a cubic regression basis for large data
     # This is based on the size of the _largest_ group.
-    if (identical(method, "auto")) {
-      groups <- count(data, "group")
+    if (identical(params$method, "auto")) {
+      max_group <- max(table(data$group))
 
-      if (max(groups$freq) < 1000) {
-        method <- "loess"
-        message('geom_smooth: method="auto" and size of largest group is <1000,',
-                ' so using loess.',
-                ' Use \'method = x\' to change the smoothing method.')
+      if (max_group < 1000) {
+        params$method <- "loess"
       } else {
-        method <- "gam"
-        formula <- y ~ s(x, bs = "cs")
-        message('geom_smooth: method="auto" and size of largest group is >=1000,',
-                ' so using gam with formula: y ~ s(x, bs = "cs").',
-                ' Use \'method = x\' to change the smoothing method.')
+        params$method <- "gam"
+        params$formula <- y ~ s(x, bs = "cs")
       }
     }
-    if (identical(method, "gam")) try_require("mgcv")
+    if (identical(params$method, "gam")) {
+      params$method <- mgcv::gam
+    }
 
-    .super$calculate_groups(., data, scales, method = method, formula = formula, ...)
-  }
+    params
+  },
 
-  calculate <- function(., data, scales, method="auto", formula=y~x, se = TRUE, n=80, fullrange=FALSE, xseq = NULL, level=0.95, na.rm = FALSE, ...) {
-    data <- remove_missing(data, na.rm, c("x", "y"), name="stat_smooth")
+  compute_group = function(data, scales, method = "auto", formula = y~x,
+                           se = TRUE, n = 80, span = 0.75, fullrange = FALSE,
+                           xseq = NULL, level = 0.95, method.args = list(),
+                           na.rm = FALSE) {
     if (length(unique(data$x)) < 2) {
       # Not enough data to perform fit
       return(data.frame())
@@ -155,28 +93,31 @@ StatSmooth <- proto(Stat, {
     if (is.null(xseq)) {
       if (is.integer(data$x)) {
         if (fullrange) {
-          xseq <- scale_dimension(scales$x, c(0, 0))
+          xseq <- scales$x$dimension()
         } else {
           xseq <- sort(unique(data$x))
         }
       } else {
         if (fullrange) {
-          range <- scale_dimension(scales$x, c(0, 0))
+          range <- scales$x$dimension()
         } else {
-          range <- range(data$x, na.rm=TRUE)
+          range <- range(data$x, na.rm = TRUE)
         }
-        xseq <- seq(range[1], range[2], length=n)
+        xseq <- seq(range[1], range[2], length.out = n)
       }
     }
+    # Special case span because it's the most commonly used model argument
+    if (identical(method, "loess")) {
+      method.args$span <- span
+    }
+
     if (is.character(method)) method <- match.fun(method)
 
-    method.special <- function(...)
-      method(formula, data=data, weights=weight, ...)
-    model <- safe.call(method.special, list(...), names(formals(method)))
+    base.args <- list(quote(formula), data = quote(data), weights = quote(weight))
+    model <- do.call(method, c(base.args, method.args))
 
     predictdf(model, xseq, se, level)
-  }
+  },
 
-  required_aes <- c("x", "y")
-  default_geom <- function(.) GeomSmooth
-})
+  required_aes = c("x", "y")
+)
diff --git a/R/stat-spoke.r b/R/stat-spoke.r
deleted file mode 100644
index 79a11ef..0000000
--- a/R/stat-spoke.r
+++ /dev/null
@@ -1,39 +0,0 @@
-#' Convert angle and radius to xend and yend.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "spoke")}
-#'
-#' @inheritParams stat_identity
-#' @return a data.frame with additional columns
-#'   \item{xend}{x position of end of line segment}
-#'   \item{yend}{x position of end of line segment}
-#' @export
-#' @examples
-#' df <- expand.grid(x = 1:10, y=1:10)
-#' df$angle <- runif(100, 0, 2*pi)
-#' df$speed <- runif(100, 0, 0.5)
-#'
-#' qplot(x, y, data=df) + stat_spoke(aes(angle=angle), radius = 0.5)
-#' last_plot() + scale_y_reverse()
-#'
-#' qplot(x, y, data=df) + stat_spoke(aes(angle=angle, radius=speed))
-stat_spoke <- function (mapping = NULL, data = NULL, geom = "segment", position = "identity", ...) {
-  StatSpoke$new(mapping = mapping, data = data, geom = geom, position = position, ...)
-}
-
-StatSpoke <- proto(Stat, {
-  objname <- "spoke"
-
-  retransform <- FALSE
-  calculate <- function(., data, scales, radius = 1, ...) {
-    transform(data,
-      xend = x + cos(angle) * radius,
-      yend = y + sin(angle) * radius
-    )
-  }
-
-  default_aes <- function(.) aes(xend = ..xend.., yend = ..yend..)
-  required_aes <- c("x", "y", "angle", "radius")
-  default_geom <- function(.) GeomSegment
-
-})
diff --git a/R/stat-sum.r b/R/stat-sum.r
index 7de2d30..81d5c86 100644
--- a/R/stat-sum.r
+++ b/R/stat-sum.r
@@ -1,70 +1,46 @@
-#' Sum unique values.  Useful for overplotting on scatterplots.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "sum")}
-#'
-#' @seealso \code{\link{ggfluctuation}} for a fluctuation diagram,
 #' @inheritParams stat_identity
-#' @return a data.frame with additional columns
+#' @section Computed variables:
+#' \describe{
 #'  \item{n}{number of observations at position}
 #'  \item{prop}{percent of points in that panel at that position}
-#' @export
-#' @examples
-#' \donttest{
-#' d <- ggplot(diamonds, aes(x = cut, y = clarity))
-#' # By default, all categorical variables in the plot form grouping
-#' # variables, and the default behavior in stat_sum is to show the
-#' # proportion. Specifying stat_sum with no group identifier leads to
-#' # a plot which is not meaningful:
-#' d + stat_sum()
-#' # To correct this problem and achieve a more desirable plot, we need
-#' # to specify which group the proportion is to be calculated over.
-#' # There are several ways to do this:
-#'
-#' # by overall proportion
-#' d + stat_sum(aes(group = 1))
-#' d + stat_sum(aes(group = 1)) + scale_size(range = c(3, 10))
-#' d + stat_sum(aes(group = 1)) + scale_size_area(max_size = 10)
-#'
-#' # by cut
-#' d + stat_sum(aes(group = cut))
-#' d + stat_sum(aes(group = cut, colour = cut))
-#'
-#' # by clarity
-#' d + stat_sum(aes(group = clarity))
-#' d + stat_sum(aes(group = clarity, colour = cut))
-#'
-#' # Instead of proportions, can also use sums
-#' d + stat_sum(aes(size = ..n..))
-#'
-#' # Can also weight by another variable
-#' d + stat_sum(aes(group = 1, weight = price))
-#' d + stat_sum(aes(group = 1, weight = price, size = ..n..))
-#'
-#' # Or using qplot
-#' qplot(cut, clarity, data = diamonds)
-#' qplot(cut, clarity, data = diamonds, stat = "sum", group = 1)
 #' }
-stat_sum <- function (mapping = NULL, data = NULL, geom = "point", position = "identity", ...) {
-  StatSum$new(mapping = mapping, data = data, geom = geom, position = position, ...)
+#' @export
+#' @rdname geom_count
+stat_sum <- function(mapping = NULL, data = NULL, geom = "point",
+                     position = "identity", na.rm = FALSE,
+                     show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatSum,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-StatSum <- proto(Stat, {
-  objname <- "sum"
-
-  default_aes <- function(.) aes(size = ..prop..)
-  required_aes <- c("x", "y")
-  default_geom <- function(.) GeomPoint
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatSum <- ggproto("StatSum", Stat,
+  default_aes = aes(size = ..n..),
 
-  calculate_groups <- function(., data, scales, ...) {
+  required_aes = c("x", "y"),
 
+  compute_panel = function(data, scales) {
     if (is.null(data$weight)) data$weight <- 1
 
     group_by <- setdiff(intersect(names(data), .all_aesthetics), "weight")
 
-    counts <- count(data, group_by, wt_var = "weight")
-    counts <- rename(counts, c(freq = "n"), warn_missing = FALSE)
-    counts$prop <- ave(counts$n, counts$group, FUN = prop.table)
+    counts <- plyr::count(data, group_by, wt_var = "weight")
+    counts <- plyr::rename(counts, c(freq = "n"), warn_missing = FALSE)
+    counts$prop <- stats::ave(counts$n, counts$group, FUN = prop.table)
     counts
   }
-})
+)
diff --git a/R/stat-summary-2d.r b/R/stat-summary-2d.r
index ac2ff9b..1020351 100644
--- a/R/stat-summary-2d.r
+++ b/R/stat-summary-2d.r
@@ -1,116 +1,124 @@
-#' Apply function for 2D rectangular bins.
+#' Bin and summarise in 2d (rectangle & hexagons)
 #'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "summary2d")}
-#'
-#' \code{stat_summary2d} is 2D version of \code{\link{stat_summary}}. The data are devided by \code{x} and \code{y}.
-#' \code{z} in each cell is passed to arbitral summary function.
-#'
-#' \code{stat_summary2d} requires the following aesthetics:
+#' \code{stat_summary_2d} is a 2d variation of \code{\link{stat_summary}}.
+#' \code{stat_summary_hex} is a hexagonal variation of
+#' \code{\link{stat_summary_2d}}. The data are divided into bins defined
+#' by \code{x} and \code{y}, and then the values of \code{z} in each cell is
+#' are summarised with \code{fun}.
 #'
+#' @section Aesthetics:
 #' \itemize{
 #'  \item \code{x}: horizontal position
 #'  \item \code{y}: vertical position
 #'  \item \code{z}: value passed to the summary function
 #' }
 #'
-#' @seealso \code{\link{stat_summary_hex}} for hexagonal summarization. \code{\link{stat_bin2d}} for the binning options.
-#' @title Apply funciton for 2D rectangular bins.
+#' @seealso \code{\link{stat_summary_hex}} for hexagonal summarization.
+#'   \code{\link{stat_bin2d}} for the binning options.
 #' @inheritParams stat_identity
-#' @param bins see \code{\link{stat_bin2d}}
+#' @inheritParams stat_bin_2d
 #' @param drop drop if the output of \code{fun} is \code{NA}.
 #' @param fun function for summary.
-#' @param ... parameters passed to \code{fun}
+#' @param fun.args A list of extra arguments to pass to \code{fun}
 #' @export
 #' @examples
-#' \donttest{
 #' d <- ggplot(diamonds, aes(carat, depth, z = price))
-#' d + stat_summary2d()
+#' d + stat_summary_2d()
 #'
 #' # Specifying function
-#' d + stat_summary2d(fun = function(x) sum(x^2))
-#' d + stat_summary2d(fun = var)
+#' d + stat_summary_2d(fun = function(x) sum(x^2))
+#' d + stat_summary_2d(fun = var)
+#' d + stat_summary_2d(fun = "quantile", fun.args = list(probs = 0.1))
+#'
+#' if (requireNamespace("hexbin")) {
+#' d + stat_summary_hex()
 #' }
-stat_summary2d <- function (mapping = NULL, data = NULL, geom = NULL, position = "identity",
-bins = 30, drop = TRUE, fun = mean, ...) {
-
-  StatSummary2d$new(mapping = mapping, data = data, geom = geom, position = position,
-  bins = bins, drop = drop, fun = fun, ...)
+stat_summary_2d <- function(mapping = NULL, data = NULL, geom = "tile",
+                            position = "identity", bins = 30, binwidth = NULL,
+                            drop = TRUE, fun = "mean", fun.args = list(),
+                            na.rm = FALSE, show.legend = NA, inherit.aes = TRUE,
+                            ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatSummary2d,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      bins = bins,
+      binwidth = binwidth,
+      drop = drop,
+      fun = fun,
+      fun.args = fun.args,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-StatSummary2d <- proto(Stat, {
-  objname <- "Summary2d"
+#' @export
+#' @rdname stat_summary_2d
+#' @usage NULL
+stat_summary2d <- function(...) {
+  message("Please use stat_summary_2d() instead")
+  stat_summary_2d(...)
+}
 
-  default_aes <- function(.) aes(fill = ..value..)
-  required_aes <- c("x", "y", "z")
-  default_geom <- function(.) GeomRect
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatSummary2d <- ggproto("StatSummary2d", Stat,
+  default_aes = aes(fill = ..value..),
 
-  calculate <- function(., data, scales, binwidth = NULL, bins = 30, breaks = NULL, origin = NULL, drop = TRUE, fun = mean, ...) {
+  required_aes = c("x", "y", "z"),
 
-    data <- remove_missing(data, FALSE, c("x", "y", "z"), name="stat_summary2d")
+  compute_group = function(data, scales, binwidth = NULL, bins = 30,
+                           breaks = NULL, origin = NULL, drop = TRUE,
+                           fun = "mean", fun.args = list()) {
+    origin <- dual_param(origin, list(NULL, NULL))
+    binwidth <- dual_param(binwidth, list(NULL, NULL))
+    breaks <- dual_param(breaks, list(NULL, NULL))
+    bins <- dual_param(bins, list(x = 30, y = 30))
 
-    range <- list(
-      x = scale_dimension(scales$x, c(0, 0)),
-      y = scale_dimension(scales$y, c(0, 0))
-    )
+    xbreaks <- bin_breaks(scales$x, breaks$x, origin$x, binwidth$x, bins$x)
+    ybreaks <- bin_breaks(scales$y, breaks$y, origin$y, binwidth$y, bins$y)
 
-    # Determine origin, if omitted
-    if (is.null(origin)) {
-      origin <- c(NA, NA)
-    } else {
-      stopifnot(is.numeric(origin))
-      stopifnot(length(origin) == 2)
-    }
-    originf <- function(x) if (is.integer(x)) -0.5 else min(x)
-    if (is.na(origin[1])) origin[1] <- originf(data$x)
-    if (is.na(origin[2])) origin[2] <- originf(data$y)
+    xbin <- cut(data$x, xbreaks, include.lowest = TRUE, labels = FALSE)
+    ybin <- cut(data$y, ybreaks, include.lowest = TRUE, labels = FALSE)
 
-    # Determine binwidth, if omitted
-    if (is.null(binwidth)) {
-      binwidth <- c(NA, NA)
-      if (is.integer(data$x)) {
-        binwidth[1] <- 1
-      } else {
-        binwidth[1] <- diff(range$x) / bins
-      }
-      if (is.integer(data$y)) {
-        binwidth[2] <- 1
-      } else {
-        binwidth[2] <- diff(range$y) / bins
-      }
+    f <- function(x) {
+      do.call(fun, c(list(quote(x)), fun.args))
     }
-    stopifnot(is.numeric(binwidth))
-    stopifnot(length(binwidth) == 2)
+    out <- tapply_df(data$z, list(xbin = xbin, ybin = ybin), f, drop = drop)
 
-    # Determine breaks, if omitted
-    if (is.null(breaks)) {
-      breaks <- list(
-        seq(origin[1], max(range$x) + binwidth[1], binwidth[1]),
-        seq(origin[2], max(range$y) + binwidth[2], binwidth[2])
-      )
-    } else {
-      stopifnot(is.list(breaks))
-      stopifnot(length(breaks) == 2)
-      stopifnot(all(sapply(breaks, is.numeric)))
-    }
-    names(breaks) <- c("x", "y")
+    xdim <- bin_loc(xbreaks, out$xbin)
+    out$x <- xdim$mid
+    out$width <- xdim$length
 
-    xbin <- cut(data$x, sort(breaks$x), include.lowest=TRUE)
-    ybin <- cut(data$y, sort(breaks$y), include.lowest=TRUE)
+    ydim <- bin_loc(ybreaks, out$ybin)
+    out$y <- ydim$mid
+    out$height <- ydim$length
 
-    if (is.null(data$weight)) data$weight <- 1
+    out
+  }
+)
 
-    ans <- ddply(data.frame(data, xbin, ybin), .(xbin, ybin), function(d) data.frame(value = fun(d$z, ...)))
-    if (drop) ans <- na.omit(ans)
+# Adaptation of tapply that returns a data frame instead of a matrix
+tapply_df <- function(x, index, fun, ..., drop = TRUE) {
+  labels <- lapply(index, ulevels)
+  out <- expand.grid(labels, KEEP.OUT.ATTRS = FALSE, stringsAsFactors = FALSE)
 
-    within(ans,{
-      xint <- as.numeric(xbin)
-      xmin <- breaks$x[xint]
-      xmax <- breaks$x[xint + 1]
+  grps <- split(x, index)
+  names(grps) <- NULL
+  out$value <- unlist(lapply(grps, fun, ...))
 
-      yint <- as.numeric(ybin)
-      ymin <- breaks$y[yint]
-      ymax <- breaks$y[yint + 1]
-    })
+  if (drop) {
+    n <- vapply(grps, length, integer(1))
+    out <- out[n > 0, , drop = FALSE]
   }
-})
+
+  out
+}
diff --git a/R/stat-summary-bin.R b/R/stat-summary-bin.R
new file mode 100644
index 0000000..d0af6f7
--- /dev/null
+++ b/R/stat-summary-bin.R
@@ -0,0 +1,83 @@
+#' @rdname stat_summary
+#' @inheritParams stat_bin
+#' @export
+stat_summary_bin <- function(mapping = NULL, data = NULL, geom = "pointrange",
+                             fun.data = NULL, fun.y = NULL, fun.ymax = NULL,
+                             fun.ymin = NULL, fun.args = list(), na.rm = FALSE,
+                             position = "identity", show.legend = NA,
+                             inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatSummaryBin,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      fun.data = fun.data,
+      fun.y = fun.y,
+      fun.ymax = fun.ymax,
+      fun.ymin = fun.ymin,
+      fun.args = fun.args,
+      na.rm = na.rm,
+      ...
+    )
+  )
+}
+
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatSummaryBin <- ggproto("StatSummaryBin", Stat,
+  required_aes = c("x", "y"),
+
+  compute_group = function(data, scales, fun.data = NULL, fun.y = NULL,
+                           fun.ymax = NULL, fun.ymin = NULL, fun.args = list(),
+                           bins = 30, binwidth = NULL, origin = NULL, right = FALSE,
+                           na.rm = FALSE) {
+
+    fun <- make_summary_fun(fun.data, fun.y, fun.ymax, fun.ymin, fun.args)
+
+    breaks <- bin_breaks(scales$x, NULL, origin, binwidth, bins, right = right)
+
+    data$bin <- cut(data$x, breaks, include.lowest = TRUE, labels = FALSE)
+    out <- plyr::ddply(data, "bin", fun)
+
+    locs <- bin_loc(breaks, out$bin)
+    out$x <- locs$mid
+    out$width <- if (scales$x$is_discrete()) 0.9 else locs$length
+    out
+  }
+)
+
+make_summary_fun <- function(fun.data, fun.y, fun.ymax, fun.ymin, fun.args) {
+  if (!is.null(fun.data)) {
+    # Function that takes complete data frame as input
+    fun.data <- match.fun(fun.data)
+    function(df) {
+      do.call(fun.data, c(list(quote(df$y)), fun.args))
+    }
+  } else if (!is.null(fun.y) || !is.null(fun.ymax) || !is.null(fun.ymin)) {
+    # Three functions that take vectors as inputs
+
+    call_f <- function(fun, x) {
+      if (is.null(fun)) return(NA_real_)
+      do.call(fun, c(list(quote(x)), fun.args))
+    }
+
+    function(df, ...) {
+      data.frame(
+        ymin = call_f(fun.ymin, df$y),
+        y = call_f(fun.y, df$y),
+        ymax = call_f(fun.ymax, df$y)
+      )
+    }
+  } else {
+    message("No summary function supplied, defaulting to `mean_se()")
+    function(df) {
+      mean_se(df$y)
+    }
+  }
+}
diff --git a/R/stat-summary-hex.r b/R/stat-summary-hex.r
index 580650c..fe07860 100644
--- a/R/stat-summary-hex.r
+++ b/R/stat-summary-hex.r
@@ -1,89 +1,77 @@
-##' Apply function for 2D hexagonal bins.
-##'
-##' @section Aesthetics:
-##' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "summaryhex")}
-##'
-##' \code{stat_summary2d} is hexagonal version of \code{\link{stat_summary}}. The data are devided by \code{x} and \code{y}.
-##' \code{z} in each cell is passed to arbitral summary function.
-##'
-##' \code{stat_summary-hex} requires the following aesthetics:
-##'
-##' \itemize{
-##'  \item \code{x}: horizontal position
-##'  \item \code{y}: vertical position
-##'  \item \code{z}: value passed to the summary function
-##' }
-##'
-##' @seealso \code{\link{stat_summary2d}} for rectangular summarization. \code{\link{stat_bin2d}} for the hexagon-ing options.
-##' @title Apply funciton for 2D hexagonal bins.
-##' @inheritParams stat_identity
-##' @param bins see \code{\link{stat_binhex}}
-##' @param drop drop if the output of \code{fun} is \code{NA}.
-##' @param fun function for summary.
-##' @param ... parameters passed to \code{fun}
-##' @export
-##' @examples
-##' d <- ggplot(diamonds, aes(carat, depth, z = price))
-##' d + stat_summary_hex()
-##'
-##' # Specifying function
-##' d + stat_summary_hex(fun = function(x) sum(x^2))
-##' d + stat_summary_hex(fun = var, na.rm = TRUE)
-stat_summary_hex <- function (mapping = NULL, data = NULL, geom = "hex", position = "identity",
-bins = 30, drop = TRUE, fun = mean, ...) {
-
-  StatSummaryhex$new(mapping = mapping, data = data, geom = geom, position = position,
-  bins = bins, drop = drop, fun = fun, ...)
+#' @export
+#' @rdname stat_summary_2d
+#' @inheritParams stat_bin_hex
+stat_summary_hex <- function(mapping = NULL, data = NULL, geom = "hex",
+                             position = "identity", bins = 30, binwidth = NULL,
+                             drop = TRUE, fun = "mean", fun.args = list(),
+                             na.rm = FALSE, show.legend = NA, inherit.aes = TRUE,
+                             ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatSummaryHex,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      bins = bins,
+      binwidth = binwidth,
+      drop = drop,
+      fun = fun,
+      fun.args = fun.args,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-StatSummaryhex <- proto(Stat, {
-  objname <- "summaryhex"
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatSummaryHex <- ggproto("StatSummaryHex", Stat,
+  default_aes = aes(fill = ..value..),
 
-  default_aes <- function(.) aes(fill = ..value..)
-  required_aes <- c("x", "y", "z")
-  default_geom <- function(.) GeomHex
-
-  calculate <- function(., data, scales, binwidth = NULL, bins = 30, drop = TRUE, fun = mean, ...) {
-    try_require("hexbin")
-    data <- remove_missing(data, FALSE, c("x", "y", "z"), name="stat_summary_hex")
+  required_aes = c("x", "y", "z"),
 
+  compute_group = function(data, scales, binwidth = NULL, bins = 30, drop = TRUE,
+                           fun = "mean", fun.args = list()) {
     if (is.null(binwidth)) {
       binwidth <- c(
-        diff(scale_dimension(scales$x, c(0, 0))) / bins,
-        diff(scale_dimension(scales$y, c(0, 0))) / bins
+        diff(scales$x$dimension()) / bins,
+        diff(scales$y$dimension()) / bins
       )
     }
 
-    try_require("hexbin")
-
     # Convert binwidths into bounds + nbins
     x <- data$x
     y <- data$y
 
     xbnds <- c(
-      round_any(min(x), binwidth[1], floor) - 1e-6,
-      round_any(max(x), binwidth[1], ceiling) + 1e-6
+      plyr::round_any(min(x), binwidth[1], floor) - 1e-6,
+      plyr::round_any(max(x), binwidth[1], ceiling) + 1e-6
     )
     xbins <- diff(xbnds) / binwidth[1]
 
     ybnds <- c(
-      round_any(min(y), binwidth[1], floor) - 1e-6,
-      round_any(max(y), binwidth[2], ceiling) + 1e-6
+      plyr::round_any(min(y), binwidth[1], floor) - 1e-6,
+      plyr::round_any(max(y), binwidth[2], ceiling) + 1e-6
     )
     ybins <- diff(ybnds) / binwidth[2]
 
     # Call hexbin
-    hb <- hexbin(
+    hb <- hexbin::hexbin(
       x, xbnds = xbnds, xbins = xbins,
       y, ybnds = ybnds, shape = ybins / xbins,
       IDs = TRUE
     )
 
-    value <- tapply(data$z, hb at cID, fun, ...)
+    value <- do.call(tapply, c(list(quote(data$z), quote(hb at cID), quote(fun)), fun.args))
 
     # Convert to data frame
-    ret <- data.frame(hcell2xy(hb), value)
-    if (drop) ret <- na.omit(ret)
+    ret <- data.frame(hexbin::hcell2xy(hb), value)
+    if (drop) ret <- stats::na.omit(ret)
     ret
   }
-})
+)
diff --git a/R/stat-summary.r b/R/stat-summary.r
index d36d3d1..9390877 100644
--- a/R/stat-summary.r
+++ b/R/stat-summary.r
@@ -1,16 +1,9 @@
-#' Summarise y values at every unique x.
+#' Summarise y values at unique/binned x x.
 #'
-#' \code{stat_summary} allows for tremendous flexibilty in the specification
-#' of summary functions. The summary function can either supply individual
-#' summary functions for each of y, ymin and ymax (with \code{fun.y},
-#' \code{fun.ymax}, \code{fun.ymin}), or return a data frame containing any
-#' number of aesthetiics with with \code{fun.data}. All summary functions
-#' are called with a single vector of values, \code{x}.
-#'
-#' A simple vector function is easiest to work with as you can return a single
-#' number, but is somewhat less flexible.  If your summary function operates
-#' on a data.frame it should return a data frame with variables that the geom
-#' can use.
+#' \code{stat_summary} operates on unique \code{x}; \code{stat_summary_bin}
+#' operators on binned \code{x}. They are more flexible versions of
+#' \code{\link{stat_bin}}: instead of just counting, the can compute any
+#' aggregate.
 #'
 #' @section Aesthetics:
 #' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "summary")}
@@ -19,8 +12,12 @@
 #'  \code{\link{geom_linerange}}, \code{\link{geom_crossbar}} for geoms to
 #'  display summarised data
 #' @inheritParams stat_identity
-#' @return a data.frame with additional columns:
-#'   \item{fun.data}{Complete summary function. Should take data frame as
+#' @section Summary functions:
+#' You can either supply summary functions individually (\code{fun.y},
+#' \code{fun.ymax}, \code{fun.ymin}), or as a single function (\code{fun.data}):
+#'
+#' \describe{
+#'   \item{fun.data}{Complete summary function. Should take numeric vector as
 #'      input and return data frame as output}
 #'   \item{fun.ymin}{ymin summary function (should take numeric vector and
 #'     return single number)}
@@ -28,45 +25,58 @@
 #'     single number)}
 #'   \item{fun.ymax}{ymax summary function (should take numeric vector and
 #'     return single number)}
+#' }
+#'
+#' A simple vector function is easiest to work with as you can return a single
+#' number, but is somewhat less flexible. If your summary function computes
+#' multiple values at once (e.g. ymin and ymax), use \code{fun.data}.
+#'
+#' If no aggregation functions are suppled, will default to
+#' \code{\link{mean_se}}.
+#'
+#' @param fun.data A function that is given the complete data and should
+#'   return a data frame with variables \code{ymin}, \code{y}, and \code{ymax}.
+#' @param fun.ymin,fun.y,fun.ymax Alternatively, supply three individual
+#'   functions that are each passed a vector of x's and should return a
+#'   single number.
+#' @param fun.args Optional additional arguments passed on to the functions.
 #' @export
 #' @examples
-#' \donttest{
-#' # Basic operation on a small dataset
-#' d <- qplot(cyl, mpg, data=mtcars)
-#' d + stat_summary(fun.data = "mean_cl_boot", colour = "red")
-#'
-#' p <- qplot(cyl, mpg, data = mtcars, stat="summary", fun.y = "mean")
-#' p
-#' # Don't use ylim to zoom into a summary plot - this throws the
-#' # data away
-#' p + ylim(15, 30)
-#' # Instead use coord_cartesian
-#' p + coord_cartesian(ylim = c(15, 30))
+#' d <- ggplot(mtcars, aes(cyl, mpg)) + geom_point()
+#' d + stat_summary(fun.data = "mean_cl_boot", colour = "red", size = 2)
 #'
 #' # You can supply individual functions to summarise the value at
 #' # each x:
-#'
-#' stat_sum_single <- function(fun, geom="point", ...) {
-#'   stat_summary(fun.y=fun, colour="red", geom=geom, size = 3, ...)
-#' }
-#'
-#' d + stat_sum_single(mean)
-#' d + stat_sum_single(mean, geom="line")
-#' d + stat_sum_single(median)
-#' d + stat_sum_single(sd)
+#' d + stat_summary(fun.y = "median", colour = "red", size = 2)
+#' d + stat_summary(fun.y = "mean", colour = "red", size = 2)
+#' d + aes(colour = factor(vs)) + stat_summary(fun.y = mean, geom="line")
 #'
 #' d + stat_summary(fun.y = mean, fun.ymin = min, fun.ymax = max,
 #'   colour = "red")
 #'
-#' d + aes(colour = factor(vs)) + stat_summary(fun.y = mean, geom="line")
+#' #' d <- ggplot(diamonds, aes(carat, price))
+#' d + geom_smooth()
+#' d + geom_line(stat = "summary_bin", binwidth = 0.1, fun.y = "mean")
 #'
-#' # Alternatively, you can supply a function that operates on a data.frame.
+#' d <- ggplot(diamonds, aes(cut))
+#' d + geom_bar()
+#' d + stat_summary_bin(aes(y = price), fun.y = "mean", geom = "bar")
+
+#' \donttest{
 #' # A set of useful summary functions is provided from the Hmisc package:
-#'
 #' stat_sum_df <- function(fun, geom="crossbar", ...) {
 #'   stat_summary(fun.data=fun, colour="red", geom=geom, width=0.2, ...)
 #' }
 #'
+#' # Don't use ylim to zoom into a summary plot - this throws the
+#' # data away
+#' p <- ggplot(mtcars, aes(cyl, mpg)) +
+#'   stat_summary(fun.y = "mean", geom = "point")
+#' p
+#' p + ylim(15, 30)
+#' # Instead use coord_cartesian
+#' p + coord_cartesian(ylim = c(15, 30))
+#'
 #' # The crossbar geom needs grouping to be specified when used with
 #' # a continuous x axis.
 #' d + stat_sum_df("mean_cl_boot", mapping = aes(group = cyl))
@@ -90,6 +100,7 @@
 #'        xlab("cyl")
 #' m
 #' # An example with highly skewed distributions:
+#' if (require("ggplot2movies")) {
 #' set.seed(596)
 #' mov <- movies[sample(nrow(movies), 1000), ]
 #'  m2 <- ggplot(mov, aes(x= factor(round(rating)), y=votes)) + geom_point()
@@ -110,41 +121,47 @@
 #' # standard errors.
 #' m2 + coord_trans(y="log10")
 #' }
-stat_summary <- function (mapping = NULL, data = NULL, geom = "pointrange", position = "identity", ...) {
-  StatSummary$new(mapping = mapping, data = data, geom = geom, position = position, ...)
+#' }
+stat_summary <- function(mapping = NULL, data = NULL, geom = "pointrange",
+                         fun.data = NULL, fun.y = NULL, fun.ymax = NULL,
+                         fun.ymin = NULL, fun.args = list(), na.rm = FALSE,
+                         position = "identity", show.legend = NA,
+                         inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatSummary,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      fun.data = fun.data,
+      fun.y = fun.y,
+      fun.ymax = fun.ymax,
+      fun.ymin = fun.ymin,
+      fun.args = fun.args,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-StatSummary <- proto(Stat, {
-  objname <- "summary"
-
-  default_geom <- function(.) GeomPointrange
-  required_aes <- c("x", "y")
-
-  calculate_groups <- function(., data, scales, fun.data = NULL, fun.y = NULL, fun.ymax = NULL, fun.ymin = NULL, na.rm = FALSE, ...) {
-    data <- remove_missing(data, na.rm, c("x", "y"), name = "stat_summary")
-
-    if (!missing(fun.data)) {
-      # User supplied function that takes complete data frame as input
-      fun.data <- match.fun(fun.data)
-      fun <- function(df, ...) {
-        fun.data(df$y, ...)
-      }
-    } else {
-      # User supplied individual vector functions
-      fs <- compact(list(ymin = fun.ymin, y = fun.y, ymax = fun.ymax))
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatSummary <- ggproto("StatSummary", Stat,
+  required_aes = c("x", "y"),
 
-      fun <- function(df, ...) {
-        res <- llply(fs, function(f) do.call(f, list(df$y, ...)))
-        names(res) <- names(fs)
-        as.data.frame(res)
-      }
-    }
+  compute_panel = function(data, scales, fun.data = NULL, fun.y = NULL,
+                     fun.ymax = NULL, fun.ymin = NULL, fun.args = list(),
+                     na.rm = FALSE) {
 
-    summarise_by_x(data, fun, ...)
+    fun <- make_summary_fun(fun.data, fun.y, fun.ymax, fun.ymin, fun.args)
+    summarise_by_x(data, fun)
   }
-
-
-})
+)
 
 # Summarise a data.frame by parts
 # Summarise a data frame by unique value of x
@@ -159,8 +176,8 @@ StatSummary <- proto(Stat, {
 # @param other arguments passed on to summary function
 # @keyword internal
 summarise_by_x <- function(data, summary, ...) {
-  summary <- ddply(data, c("group", "x"), summary, ...)
-  unique <- ddply(data, c("group", "x"), uniquecols)
+  summary <- plyr::ddply(data, c("group", "x"), summary, ...)
+  unique <- plyr::ddply(data, c("group", "x"), uniquecols)
   unique$y <- NULL
 
   merge(summary, unique, by = c("x", "group"))
@@ -180,11 +197,15 @@ summarise_by_x <- function(data, summary, ...) {
 NULL
 
 wrap_hmisc <- function(fun) {
+
   function(x, ...) {
-    try_require("Hmisc")
+    if (!requireNamespace("Hmisc", quietly = TRUE))
+      stop("Hmisc package required for this function", call. = FALSE)
+
+    fun <- getExportedValue("Hmisc", fun)
+    result <- do.call(fun, list(x = quote(x), ...))
 
-    result <- safe.call(fun, list(x = x, ...))
-    rename(
+    plyr::rename(
       data.frame(t(result)),
       c(Median = "y", Mean = "y", Lower = "ymin", Upper = "ymax"),
       warn_missing = FALSE
@@ -211,8 +232,8 @@ median_hilow <- wrap_hmisc("smedian.hilow")
 #' @seealso for use with \code{\link{stat_summary}}
 #' @export
 mean_se <- function(x, mult = 1) {
-  x <- na.omit(x)
-  se <- mult * sqrt(var(x) / length(x))
+  x <- stats::na.omit(x)
+  se <- mult * sqrt(stats::var(x) / length(x))
   mean <- mean(x)
   data.frame(y = mean, ymin = mean - se, ymax = mean + se)
 }
diff --git a/R/stat-unique.r b/R/stat-unique.r
index a97eefa..157a6f2 100644
--- a/R/stat-unique.r
+++ b/R/stat-unique.r
@@ -5,18 +5,33 @@
 #'
 #' @export
 #' @inheritParams stat_identity
+#' @param na.rm If \code{FALSE} (the default), removes missing values with
+#'    a warning.  If \code{TRUE} silently removes missing values.
 #' @examples
 #' ggplot(mtcars, aes(vs, am)) + geom_point(alpha = 0.1)
 #' ggplot(mtcars, aes(vs, am)) + geom_point(alpha = 0.1, stat="unique")
-stat_unique <- function (mapping = NULL, data = NULL, geom = "point", position = "identity", ...) {
-  StatUnique$new(mapping = mapping, data = data, geom = geom, position = position, ...)
+stat_unique <- function(mapping = NULL, data = NULL, geom = "point",
+                        position = "identity", na.rm = FALSE,
+                        show.legend = NA, inherit.aes = TRUE, ...) {
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatUnique,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-StatUnique <- proto(Stat, {
-  objname <- "unique"
-  desc <- "Remove duplicates"
-
-  default_geom <- function(.) GeomPoint
-
-  calculate_groups <- function(., data, scales, ...) unique(data)
-})
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatUnique <- ggproto("StatUnique", Stat,
+  compute_panel = function(data, scales) unique(data)
+)
diff --git a/R/stat-vline.r b/R/stat-vline.r
deleted file mode 100644
index 69a1314..0000000
--- a/R/stat-vline.r
+++ /dev/null
@@ -1,135 +0,0 @@
-#' Add a line with slope and intercept.
-#'
-#' @keywords internal
-#' @inheritParams stat_identity
-#' @seealso \code{\link{geom_abline}} for code examples.
-#' @export
-#' @examples
-#' # see geom_abline
-stat_abline <- function (mapping = NULL, data = NULL, geom = "abline", position = "identity", ...) {
-  StatAbline$new(mapping = mapping, data = data, geom = geom, position = position, ...)
-}
-
-StatAbline <- proto(Stat, {
-  objname <- "abline"
-
-  calculate <- function(., data, scales, intercept = NULL, slope = NULL, ...) {
-    if (is.null(intercept)) {
-      if (is.null(data$intercept)) data$intercept <- 0
-    } else {
-      data <- data[rep(1, length(intercept)), , drop = FALSE]
-      data$intercept <- intercept
-    }
-    if (is.null(slope)) {
-      if (is.null(data$slope)) data$slope <- 1
-    } else {
-      data <- data[rep(1, length(slope)), , drop = FALSE]
-      data$slope <- slope
-    }
-    unique(data)
-  }
-
-  default_geom <- function(.) GeomAbline
-})
-
-#' Add a vertical line
-#'
-#' @keywords internal
-#' @inheritParams stat_identity
-#' @seealso \code{\link{geom_vline}} for code examples.
-#' @export
-#' @examples
-#' # see geom_vline
-stat_vline <- function (mapping = NULL, data = NULL, geom = "vline", position = "identity",
-xintercept, ...) {
-  StatVline$new(mapping = mapping, data = data, geom = geom, position = position,
-  xintercept = xintercept, ...)
-}
-
-StatVline <- proto(Stat, {
-  objname <- "vline"
-
-  calculate <- function(., data, scales, xintercept = NULL, intercept, ...) {
-    if (!missing(intercept)) {
-      stop("stat_vline now uses xintercept instead of intercept")
-    }
-    data <- compute_intercept(data, xintercept, "x")
-
-    unique(within(data, {
-      x    <- xintercept
-      xend <- xintercept
-    }))
-  }
-
-  required_aes <- c()
-  default_geom <- function(.) GeomVline
-})
-
-#' Add a horizontal line
-#'
-#' @keywords internal
-#' @inheritParams stat_identity
-#' @seealso \code{\link{geom_hline}} for code examples.
-#' @export
-#' @examples
-#' # see geom_hline
-stat_hline <- function (mapping = NULL, data = NULL, geom = "hline", position = "identity",
-yintercept, ...) {
-  StatHline$new(mapping = mapping, data = data, geom = geom, position = position,
-  yintercept = yintercept, ...)
-}
-
-StatHline <- proto(Stat, {
-  calculate <- function(., data, scales, yintercept = NULL, intercept, ...) {
-    if (!missing(intercept)) {
-      stop("stat_hline now uses yintercept instead of intercept")
-    }
-
-    data <- compute_intercept(data, yintercept, "y")
-
-    unique(within(data, {
-      y    <- yintercept
-      yend <- yintercept
-    }))
-  }
-
-  objname <- "hline"
-  desc <- "Add a horizontal line"
-
-  required_aes <- c()
-  default_geom <- function(.) GeomHline
-
-  examples <- function(.) {
-    # See geom_hline for examples
-  }
-})
-
-
-# Compute intercept for vline and hline from data and parameters
-#
-# @keyword internal
-compute_intercept <- function(data, intercept, var = "x") {
-  ivar <- paste(var, "intercept", sep = "")
-  if (is.null(intercept)) {
-    # Intercept comes from data, default to 0 if not set
-    if (is.null(data[[ivar]])) data[[ivar]] <- 0
-
-  } else if (is.numeric(intercept)) {
-    # Intercept is a numeric vector of positions
-    data <- data[rep(1, length(intercept)), ]
-    data[[ivar]] <- intercept
-
-  } else if (is.character(intercept) || is.function(intercept)) {
-    # Intercept is a function
-    f <- match.fun(intercept)
-    trans <- function(data) {
-      data[[ivar]] <- f(data[[var]])
-      data
-    }
-    data <- ddply(data, "group", trans)
-  } else {
-    stop("Invalid intercept type: should be a numeric vector, a function",
-         ", or a name of a function", call. = FALSE)
-  }
-  data
-}
diff --git a/R/stat-ydensity.r b/R/stat-ydensity.r
index b7b0890..a2c34c3 100644
--- a/R/stat-ydensity.r
+++ b/R/stat-ydensity.r
@@ -1,19 +1,10 @@
-#' 1d kernel density estimate along y axis, for violin plot.
-#'
-#' @section Aesthetics:
-#' \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "ydensity")}
-#'
 #' @inheritParams stat_density
 #' @inheritParams stat_identity
-#' @param trim If \code{TRUE} (default), trim the tails of the violins
-#'   to the range of the data. If \code{FALSE}, don't trim the tails.
 #' @param scale if "area" (default), all violins have the same area (before trimming
 #'   the tails). If "count", areas are scaled proportionally to the number of
 #'   observations. If "width", all violins have the same maximum width.
-#' @param na.rm If \code{FALSE} (the default), removes missing values with
-#'    a warning. If \code{TRUE} silently removes missing values.
-#'
-#' @return A data frame with additional columns:
+#' @section Computed variables:
+#' \describe{
 #'   \item{density}{density estimate}
 #'   \item{scaled}{density estimate, scaled to maximum of 1}
 #'   \item{count}{density * number of points - probably useless for violin plots}
@@ -21,95 +12,89 @@
 #'                      or to a constant maximum width}
 #'   \item{n}{number of points}
 #'   \item{width}{width of violin bounding box}
+#' }
 #' @seealso \code{\link{geom_violin}} for examples, and \code{\link{stat_density}}
 #'   for examples with data along the x axis.
 #' @export
-#' @examples
-#' # See geom_violin for examples
-#' # Also see stat_density for similar examples with data along x axis
-stat_ydensity <- function (mapping = NULL, data = NULL, geom = "violin", position = "dodge",
-adjust = 1, kernel = "gaussian", trim = TRUE, scale = "area", na.rm = FALSE, ...) {
-  StatYdensity$new(mapping = mapping, data = data, geom = geom, position = position,
-  adjust = adjust, kernel = kernel, trim = trim, scale = scale,
-  na.rm = na.rm, ...)
+#' @rdname geom_violin
+stat_ydensity <- function(mapping = NULL, data = NULL, geom = "violin",
+                          position = "dodge", adjust = 1, kernel = "gaussian",
+                          trim = TRUE, scale = "area", na.rm = FALSE,
+                          show.legend = NA, inherit.aes = TRUE, ...) {
+  scale <- match.arg(scale, c("area", "count", "width"))
+
+  layer(
+    data = data,
+    mapping = mapping,
+    stat = StatYdensity,
+    geom = geom,
+    position = position,
+    show.legend = show.legend,
+    inherit.aes = inherit.aes,
+    params = list(
+      adjust = adjust,
+      kernel = kernel,
+      trim = trim,
+      scale = scale,
+      na.rm = na.rm,
+      ...
+    )
+  )
 }
 
-StatYdensity <- proto(Stat, {
-  objname <- "ydensity"
 
-  calculate_groups <- function(., data, na.rm = FALSE, width = NULL,
-                               scale = "area", ...) {
-    data <- remove_missing(data, na.rm, "y", name = "stat_ydensity", finite = TRUE)
-    data <- .super$calculate_groups(., data, na.rm = na.rm, width = width, ...)
+#' @rdname ggplot2-ggproto
+#' @format NULL
+#' @usage NULL
+#' @export
+StatYdensity <- ggproto("StatYdensity", Stat,
+  required_aes = c("x", "y"),
+  non_missing_aes = "weight",
+
+  compute_group = function(data, scales, width = NULL, adjust = 1,
+                       kernel = "gaussian", trim = TRUE, na.rm = FALSE) {
+    if (nrow(data) < 3) return(data.frame())
 
-    # choose how violins are scaled relative to each other
-    scale <- match.arg(scale, c("area", "equal", "count", "width"))
-    if (scale == "equal") {
-      gg_dep("0.9.2", "scale=\"area\" is deprecated; in the future, use scale=\"equal\" instead.")
-      scale <- "area"
+    if (trim) {
+      range <- range(data$y, na.rm = TRUE)
+    } else {
+      range <- scales$y$dimension()
+    }
+    dens <- compute_density(data$y, data$w, from = range[1], to = range[2],
+      adjust = adjust, kernel = kernel)
+
+    dens$y <- dens$x
+    dens$x <- mean(range(data$x))
+
+    # Compute width if x has multiple values
+    if (length(unique(data$x)) > 1) {
+      width <- diff(range(data$x)) * 0.9
     }
+    dens$width <- width
 
+    dens
+  },
+
+  compute_panel = function(self, data, scales, width = NULL, adjust = 1,
+                           kernel = "gaussian", trim = TRUE, na.rm = FALSE,
+                           scale = "area") {
+    data <- ggproto_parent(Stat, self)$compute_panel(
+      data, scales, width = width, adjust = adjust, kernel = kernel,
+      trim = trim, na.rm = na.rm
+    )
+
+    # choose how violins are scaled relative to each other
     data$violinwidth <- switch(scale,
       # area : keep the original densities but scale them to a max width of 1
       #        for plotting purposes only
       area = data$density / max(data$density),
       # count: use the original densities scaled to a maximum of 1 (as above)
       #        and then scale them according to the number of observations
-      count = (data$density / max(data$density)) * data$n / max(data$n),
+      count = data$density / max(data$density) * data$n / max(data$n),
       # width: constant width (density scaled to a maximum of 1)
       width = data$scaled
     )
-
     data
   }
 
-  calculate <- function(., data, scales, width=NULL, adjust=1, kernel="gaussian",
-                        trim=TRUE, na.rm = FALSE, ...) {
-
-    n <- nrow(data)
-
-    # if less than 3 points, return a density of 1 everywhere
-    if (n < 3) {
-      return(data.frame(data, density = 1, scaled = 1, count = 1))
-    }
-
-    # initialize weights if they are not supplied by the user
-    if (is.null(data$weight)) { data$weight <- rep(1, n) / n }
-
-    # compute the density
-    dens <- density(data$y, adjust = adjust, kernel = kernel,
-      weight = data$weight, n = 200)
-
-    # NB: stat_density restricts to the scale range, here we leave that
-    # free so violins can extend the y scale
-    densdf <- data.frame(y = dens$x, density = dens$y)
-
-    # scale density to a maximum of 1
-    densdf$scaled <- densdf$density / max(densdf$density, na.rm = TRUE)
-
-    # trim density outside of the data range
-    if (trim) {
-      densdf <- subset(densdf, y > min(data$y, na.rm = TRUE) & y < max(data$y, na.rm = TRUE))
-    }
-    # NB: equivalently, we could have used these bounds in the from and
-    # to arguments of density()
-
-    # scale density by the number of observations
-    densdf$count <- densdf$density * n
-    # record the number of observations to be able to scale the density later
-    densdf$n <- n
-
-    # coordinate on the x axis
-    densdf$x <- if (is.factor(data$x)) data$x[1] else mean(range(data$x))
-
-    # width of the bounding box of the violin plot on the x axis for continuous x
-    if (length(unique(data$x)) > 1) { width <- diff(range(data$x)) * 0.9 }
-    densdf$width <- width
-
-    densdf
-  }
-
-  default_geom <- function(.) GeomViolin
-  required_aes <- c("x", "y")
-
-})
+)
diff --git a/R/summary.r b/R/summary.r
index e66a6a9..e5422f8 100644
--- a/R/summary.r
+++ b/R/summary.r
@@ -6,30 +6,24 @@
 #' @method summary ggplot
 #' @export
 #' @examples
-#' summary(qplot(mpg, wt, data=mtcars))
+#' p <- ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point()
+#' summary(p)
 summary.ggplot <- function(object, ...) {
   wrap <- function(x) paste(
     paste(strwrap(x, exdent = 2), collapse = "\n"),
-    "\n", sep =""
+    "\n", sep = ""
     )
 
-  defaults <- function() {
-    paste(mapply(function(x, n) {
-      paste(n, deparse(x), sep="=")
-    }, object$mapping, names(object$mapping)), collapse=", ")
-  }
-
-  # cat("Title:    ", object$title, "\n", sep="")
-  # cat("-----------------------------------\n")
   if (!is.null(object$data)) {
     output <- paste(
-      "data:     ", paste(names(object$data), collapse=", "),
+      "data:     ", paste(names(object$data), collapse = ", "),
       " [", nrow(object$data), "x", ncol(object$data), "] ",
-      "\n", sep="")
+      "\n", sep = "")
     cat(wrap(output))
   }
   if (length(object$mapping) > 0) {
-    cat("mapping:  ", clist(object$mapping), "\n", sep="")
+    cat("mapping:  ", clist(object$mapping), "\n", sep = "")
   }
   if (object$scales$n() > 0) {
     cat("scales:  ", paste(object$scales$input(), collapse = ", "), "\n")
@@ -40,6 +34,9 @@ summary.ggplot <- function(object, ...) {
 
   if (length(object$layers) > 0)
     cat("-----------------------------------\n")
-  invisible(lapply(object$layers, function(x) {print(x); cat("\n")}))
+  invisible(lapply(object$layers, function(x) {
+    print(x)
+    cat("\n")
+  }))
 
 }
diff --git a/R/templates.r b/R/templates.r
deleted file mode 100644
index 662193a..0000000
--- a/R/templates.r
+++ /dev/null
@@ -1,46 +0,0 @@
-#' Plot templates.
-#'
-#' These plot templates are deprecated in an attempt to make ggplot2 as
-#' streamlined as possible, and to avoid bugs in these poorly tested
-#' functions. See the \pkg{GGally} package for some alternatives.
-#'
-#' @name plot-templates
-#' @keywords internal
-NULL
-
-#' @export
-#' @rdname plot-templates
-ggpcp <- function(data, vars=names(data), ...) {
-  gg_dep("0.9.1", "ggpcp is deprecated.")
-}
-
-#' @export
-#' @rdname plot-templates
-ggfluctuation <- function(table, type="size", floor=0, ceiling=max(table$freq, na.rm=TRUE)) {
-  gg_dep("0.9.1", "ggfluctuation is deprecated.")
-}
-
-#' @export
-#' @rdname plot-templates
-ggmissing <- function(data, avoid="stack", order=TRUE, missing.only = TRUE) {
-  gg_dep("0.9.1", "ggmissing is deprecated.")
-}
-
-#' @export
-#' @rdname plot-templates
-ggstructure <- function(data) {
-  gg_dep("0.9.1", "ggstructure is deprecated.")
-}
-
-#' @export
-#' @rdname plot-templates
-ggorder <- function(data) {
-  gg_dep("0.9.1", "ggorder is deprecated.")
-}
-
-#' @export
-#' @rdname plot-templates
-plotmatrix <- function(data, mapping=aes(), colour="black") {
-  gg_dep("0.9.2", "This function is deprecated. For a replacement, see the ggpairs function in the GGally package.")
-}
-
diff --git a/R/theme-defaults.r b/R/theme-defaults.r
index f84800c..506ef1c 100644
--- a/R/theme-defaults.r
+++ b/R/theme-defaults.r
@@ -26,12 +26,18 @@
 #' A theme similar to \code{theme_linedraw} but with light grey lines and axes,
 #' to direct more attention towards the data.}
 #'
+#' \item{\code{theme_dark}}{
+#' The dark cousin of \code{theme_light}, with similar line sizes but a dark background. Useful to make thin coloured lines pop out.}
+#'
 #' \item{\code{theme_minimal}}{
 #' A minimalistic theme with no background annotations.}
 #'
 #' \item{\code{theme_classic}}{
 #' A classic-looking theme, with x and y axis lines and no gridlines.}
 #'
+#' \item{\code{theme_void}}{
+#' A completely empty theme.}
+#'
 #' }
 #'
 #' @examples
@@ -45,33 +51,43 @@
 #' p + theme_light()
 #' p + theme_minimal()
 #' p + theme_classic()
+#' p + theme_void()
 #'
 #' @name ggtheme
 NULL
 
 #' @export
 #' @rdname ggtheme
-theme_grey <- function(base_size = 12, base_family = "") {
+theme_grey <- function(base_size = 11, base_family = "") {
+  half_line <- base_size / 2
+
   theme(
     # Elements in this first block aren't used directly, but are inherited
     # by others
     line =               element_line(colour = "black", size = 0.5, linetype = 1,
                             lineend = "butt"),
-    rect =               element_rect(fill = "white", colour = "black", size = 0.5, linetype = 1),
-    text =               element_text(family = base_family, face = "plain",
+    rect =               element_rect(fill = "white", colour = "black",
+                            size = 0.5, linetype = 1),
+    text =               element_text(
+                            family = base_family, face = "plain",
                             colour = "black", size = base_size,
-                            hjust = 0.5, vjust = 0.5, angle = 0, lineheight = 0.9),
-    axis.text =          element_text(size = rel(0.8), colour = "grey50"),
-    strip.text =         element_text(size = rel(0.8)),
+                            lineheight = 0.9, hjust = 0.5, vjust = 0.5, angle = 0,
+                            margin = margin(), debug = FALSE
+                         ),
 
     axis.line =          element_blank(),
-    axis.text.x =        element_text(vjust = 1),
-    axis.text.y =        element_text(hjust = 1),
-    axis.ticks =         element_line(colour = "grey50"),
-    axis.title.x =       element_text(),
-    axis.title.y =       element_text(angle = 90),
-    axis.ticks.length =  unit(0.15, "cm"),
-    axis.ticks.margin =  unit(0.1, "cm"),
+    axis.text =          element_text(size = rel(0.8), colour = "grey30"),
+    axis.text.x =        element_text(margin = margin(t = 0.8 * half_line / 2), vjust = 1),
+    axis.text.y =        element_text(margin = margin(r = 0.8 * half_line / 2), hjust = 1),
+    axis.ticks =         element_line(colour = "grey20"),
+    axis.ticks.length =  unit(half_line / 2, "pt"),
+    axis.title.x =       element_text(
+                           margin = margin(t = 0.8 * half_line, b = 0.8 * half_line / 2)
+                         ),
+    axis.title.y =       element_text(
+                           angle = 90,
+                           margin = margin(r = 0.8 * half_line, l = 0.8 * half_line / 2),
+                         ),
 
     legend.background =  element_rect(colour = NA),
     legend.margin =      unit(0.2, "cm"),
@@ -81,28 +97,35 @@ theme_grey <- function(base_size = 12, base_family = "") {
     legend.key.width =   NULL,
     legend.text =        element_text(size = rel(0.8)),
     legend.text.align =  NULL,
-    legend.title =       element_text(size = rel(0.8), face = "bold", hjust = 0),
+    legend.title =       element_text(hjust = 0),
     legend.title.align = NULL,
     legend.position =    "right",
     legend.direction =   NULL,
     legend.justification = "center",
     legend.box =         NULL,
 
-    panel.background =   element_rect(fill = "grey90", colour = NA),
+    panel.background =   element_rect(fill = "grey92", colour = NA),
     panel.border =       element_blank(),
     panel.grid.major =   element_line(colour = "white"),
-    panel.grid.minor =   element_line(colour = "grey95", size = 0.25),
-    panel.margin =       unit(0.25, "lines"),
+    panel.grid.minor =   element_line(colour = "white", size = 0.25),
+    panel.margin =       unit(half_line, "pt"),
     panel.margin.x =     NULL,
     panel.margin.y =     NULL,
+    panel.ontop    =     FALSE,
 
-    strip.background =   element_rect(fill = "grey80", colour = NA),
-    strip.text.x =       element_text(),
-    strip.text.y =       element_text(angle = -90),
+    strip.background =   element_rect(fill = "grey85", colour = NA),
+    strip.text =         element_text(colour = "grey10", size = rel(0.8)),
+    strip.text.x =       element_text(margin = margin(t = half_line, b = half_line)),
+    strip.text.y =       element_text(angle = -90, margin = margin(l = half_line, r = half_line)),
+    strip.switch.pad.grid = unit(0.1, "cm"),
+    strip.switch.pad.wrap = unit(0.1, "cm"),
 
     plot.background =    element_rect(colour = "white"),
-    plot.title =         element_text(size = rel(1.2)),
-    plot.margin =        unit(c(1, 1, 0.5, 0.5), "lines"),
+    plot.title =         element_text(
+                           size = rel(1.2),
+                           margin = margin(b = half_line * 1.2)
+                         ),
+    plot.margin =        margin(half_line, half_line, half_line, half_line),
 
     complete = TRUE
   )
@@ -131,6 +154,7 @@ theme_bw <- function(base_size = 12, base_family = "") {
 #' @export
 #' @rdname ggtheme
 theme_linedraw <- function(base_size = 12, base_family = "") {
+  half_line <- base_size / 2
   # Starts with theme_grey and then modify some parts
   theme_grey(base_size = base_size, base_family = base_family) %+replace%
     theme(
@@ -142,14 +166,22 @@ theme_linedraw <- function(base_size = 12, base_family = "") {
       panel.grid.major  = element_line(colour = "black", size = 0.05),
       panel.grid.minor  = element_line(colour = "black", size = 0.01),
       strip.background  = element_rect(fill = "black", colour = NA),
-      strip.text.x      = element_text(colour = "white"),
-      strip.text.y      = element_text(colour = "white", angle = -90)
+      strip.text.x      = element_text(
+                            colour = "white",
+                            margin = margin(t = half_line, b = half_line)
+                          ),
+      strip.text.y      = element_text(
+                            colour = "white",
+                            angle = 90,
+                            margin = margin(l = half_line, r = half_line)
+                          )
     )
 }
 
 #' @export
 #' @rdname ggtheme
 theme_light <- function(base_size = 12, base_family = "") {
+  half_line <- base_size / 2
   # Starts with theme_grey and then modify some parts
   theme_grey(base_size = base_size, base_family = base_family) %+replace%
     theme(
@@ -160,8 +192,15 @@ theme_light <- function(base_size = 12, base_family = "") {
       panel.grid.major  = element_line(colour = "grey85", size = 0.25),
       panel.grid.minor  = element_line(colour = "grey93", size = 0.125),
       strip.background  = element_rect(fill = "grey70", colour = NA),
-      strip.text.x      = element_text(colour = "white"),
-      strip.text.y      = element_text(colour = "white", angle = -90)
+      strip.text.x      = element_text(
+        colour = "white",
+        margin = margin(t = half_line, b = half_line)
+      ),
+      strip.text.y      = element_text(
+        colour = "white",
+        angle = -90,
+        margin = margin(l = half_line, r = half_line)
+      )
     )
 
 }
@@ -177,7 +216,9 @@ theme_minimal <- function(base_size = 12, base_family = "") {
       panel.background  = element_blank(),
       panel.border      = element_blank(),
       strip.background  = element_blank(),
-      plot.background   = element_blank()
+      plot.background   = element_blank(),
+      axis.ticks        = element_blank(),
+      axis.ticks.length = unit(0, "lines")
     )
 }
 
@@ -194,3 +235,43 @@ theme_classic <- function(base_size = 12, base_family = ""){
       legend.key       = element_blank()
     )
 }
+
+#' @export
+#' @rdname ggtheme
+theme_dark <- function(base_size = 12, base_family = "") {
+  half_line <- base_size / 2
+  # Starts with theme_grey and then modify some parts
+  theme_grey(base_size = base_size, base_family = base_family) %+replace%
+    theme(
+      axis.ticks        = element_line(colour = "grey40", size = 0.25),
+      legend.key        = element_rect(fill = "grey50", colour = "grey40", size = 0.25),
+      panel.background  = element_rect(fill = "grey50", colour = NA),
+      panel.grid.major  = element_line(colour = "grey40", size = 0.25),
+      panel.grid.minor  = element_line(colour = "grey45", size = 0.125),
+      strip.background  = element_rect(fill = "grey20", colour = NA),
+      strip.text.x      = element_text(
+        colour = "white",
+        margin = margin(t = half_line, b = half_line)
+      ),
+      strip.text.y      = element_text(
+        colour = "white",
+        angle = -90,
+        margin = margin(l = half_line, r = half_line)
+      )
+    )
+}
+
+#' @export
+#' @rdname ggtheme
+theme_void <- function(base_size = 12, base_family = "") {
+  theme(
+    # Use only inherited elements and make everything blank
+    line =               element_blank(),
+    rect =               element_blank(),
+    text =               element_blank(),
+    plot.margin =        unit(c(0, 0, 0, 0), "lines"),
+
+    complete = TRUE
+  )
+}
+
diff --git a/R/theme-elements.r b/R/theme-elements.r
index 43c8fc9..13f1a28 100644
--- a/R/theme-elements.r
+++ b/R/theme-elements.r
@@ -59,29 +59,39 @@ element_line <- function(colour = NULL, size = NULL, linetype = NULL,
 #' @param angle angle (in [0, 360])
 #' @param lineheight line height
 #' @param color an alias for \code{colour}
+#' @param margin margins around the text. See \code{\link{margin}} for more
+#'   details. When creating a theme, the margins should be placed on the
+#'   side of the text facing towards the center of the plot.
+#' @param debug If \code{TRUE}, aids visual debugging by drawing a solid
+#'   rectangle behind the complete text area, and a point where each label
+#'   is anchored.
 #' @export
 element_text <- function(family = NULL, face = NULL, colour = NULL,
   size = NULL, hjust = NULL, vjust = NULL, angle = NULL, lineheight = NULL,
-  color = NULL) {
+  color = NULL, margin = NULL, debug = NULL) {
 
   if (!is.null(color))  colour <- color
   structure(
     list(family = family, face = face, colour = colour, size = size,
-      hjust = hjust, vjust = vjust, angle = angle, lineheight = lineheight),
+      hjust = hjust, vjust = vjust, angle = angle, lineheight = lineheight,
+      margin = margin, debug = debug),
     class = c("element_text", "element")
   )
 }
 
 
 #' @export
-print.element <- function(x, ...) str(x)
+print.element <- function(x, ...) utils::str(x)
 
 
 #' Relative sizing for theme elements
 #'
 #' @param x A number representing the relative size
 #' @examples
-#' qplot(1:3, 1:3) + theme(axis.title.x = element_text(size = rel(2.5)))
+#' df <- data.frame(x = 1:3, y = 1:3)
+#' ggplot(df, aes(x, y)) +
+#'   geom_point() +
+#'   theme(axis.title.x = element_text(size = rel(2.5)))
 #' @export
 rel <- function(x) {
   structure(x, class = "rel")
@@ -94,49 +104,6 @@ print.rel <- function(x, ...) print(noquote(paste(x, " *", sep = "")))
 #' @param x An object to test
 is.rel <- function(x) inherits(x, "rel")
 
-
-#' Deprecated theme_xx functions
-#'
-#' The \code{theme_xx} functions have been deprecated. They are replaced
-#' with the \code{element_xx} functions.
-#' @param ... Arguments to be passed to the appropriate \code{element_xx}
-#'   function.
-#'
-#' @export
-theme_blank <- function(...) {
-  gg_dep("0.9.1", "'theme_blank' is deprecated. Use 'element_blank' instead.")
-  element_blank(...)
-}
-
-#' @rdname theme_blank
-#' @export
-theme_rect <- function(...) {
-  gg_dep("0.9.1", "theme_rect is deprecated. Use 'element_rect' instead.")
-  element_rect(...)
-}
-
-#' @rdname theme_blank
-#' @export
-theme_line <- function(...) {
-  gg_dep("0.9.1", "theme_line is deprecated. Use 'element_line' instead.")
-  element_line(...)
-}
-
-#' @rdname theme_blank
-#' @export
-theme_segment <- function(...) {
-  gg_dep("0.9.1", "theme_segment is deprecated. Use 'element_line' instead.")
-  element_line(...)
-}
-
-#' @rdname theme_blank
-#' @export
-theme_text <- function(...) {
-  gg_dep("0.9.1", "theme_text is deprecated. Use 'element_text' instead.")
-  element_text(...)
-}
-
-
 # Given a theme object and element name, return a grob for the element
 element_render <- function(theme, element, ..., name = NULL) {
 
@@ -147,7 +114,7 @@ element_render <- function(theme, element, ..., name = NULL) {
     return(zeroGrob())
   }
 
-  ggname(ps(element, name, sep = "."), element_grob(el, ...))
+  ggname(paste(element, name, sep = "."), element_grob(el, ...))
 }
 
 
@@ -158,10 +125,16 @@ len0_null <- function(x) {
 }
 
 
-# Returns a grob for an element object
-element_grob <- function(element, ...)
+#' Generate grid grob from theme element
+#'
+#' @param element Theme element, i.e. \code{element_rect} or similar.
+#' @param ... Other arguments to control specific of rendering. This is
+#'   usually at least position. See the source code for individual methods.
+#' @keywords internal
+#' @export
+element_grob <- function(element, ...) {
   UseMethod("element_grob")
-
+}
 
 #' @export
 element_grob.element_blank <- function(element, ...)  zeroGrob()
@@ -176,7 +149,7 @@ element_grob.element_rect <- function(element, x = 0.5, y = 0.5,
   element_gp <- gpar(lwd = len0_null(element$size * .pt), col = element$colour,
     fill = element$fill, lty = element$linetype)
 
-  rectGrob(x, y, width, height, gp = modifyList(element_gp, gp), ...)
+  rectGrob(x, y, width, height, gp = utils::modifyList(element_gp, gp), ...)
 }
 
 
@@ -184,33 +157,19 @@ element_grob.element_rect <- function(element, x = 0.5, y = 0.5,
 element_grob.element_text <- function(element, label = "", x = NULL, y = NULL,
   family = NULL, face = NULL, colour = NULL, size = NULL,
   hjust = NULL, vjust = NULL, angle = NULL, lineheight = NULL,
-  default.units = "npc", ...) {
+  margin = NULL, expand_x = FALSE, expand_y = FALSE, ...) {
+
+  if (is.null(label))
+    return(zeroGrob())
 
   vj <- vjust %||% element$vjust
   hj <- hjust %||% element$hjust
+  margin <- margin %||% element$margin
 
   angle <- angle %||% element$angle
   if (is.null(angle)) {
     stop("Text element requires non-NULL value for 'angle'.")
   }
-  angle <- angle %% 360
-
-  if (angle == 90) {
-    xp <- 1 - vj
-    yp <- hj
-  } else if (angle == 180) {
-    xp <- 1 - hj
-    yp <- 1 - vj
-  } else if (angle == 270) {
-    xp <- vj
-    yp <- 1 - hj
-  } else {
-    xp <- hj
-    yp <- vj
-  }
-
-  x <- x %||% xp
-  y <- y %||% yp
 
   # The gp settings can override element_gp
   gp <- gpar(fontsize = size, col = colour,
@@ -220,28 +179,26 @@ element_grob.element_text <- function(element, label = "", x = NULL, y = NULL,
     fontfamily = element$family, fontface = element$face,
     lineheight = element$lineheight)
 
-  textGrob(
-    label, x, y, hjust = hj, vjust = vj,
-    default.units = default.units,
-    gp = modifyList(element_gp, gp),
-    rot = angle, ...
-  )
+  titleGrob(label, x, y, hjust = hj, vjust = vj, angle = angle,
+    gp = utils::modifyList(element_gp, gp), margin = margin,
+    expand_x = expand_x, expand_y = expand_y, debug = element$debug)
 }
 
 
+
 #' @export
 element_grob.element_line <- function(element, x = 0:1, y = 0:1,
   colour = NULL, size = NULL, linetype = NULL, lineend = NULL,
   default.units = "npc", id.lengths = NULL, ...) {
 
   # The gp settings can override element_gp
-  gp <- gpar(lwd=len0_null(size * .pt), col=colour, lty=linetype, lineend = lineend)
+  gp <- gpar(lwd = len0_null(size * .pt), col = colour, lty = linetype, lineend = lineend)
   element_gp <- gpar(lwd = len0_null(element$size * .pt), col = element$colour,
     lty = element$linetype, lineend = element$lineend)
 
   polylineGrob(
     x, y, default.units = default.units,
-    gp = modifyList(element_gp, gp),
+    gp = utils::modifyList(element_gp, gp),
     id.lengths = id.lengths, ...
   )
 }
@@ -286,7 +243,6 @@ el_def <- function(class = NULL, inherit = NULL, description = NULL) {
   axis.ticks.y        = el_def("element_line", "axis.ticks"),
   axis.title.x        = el_def("element_text", "axis.title"),
   axis.title.y        = el_def("element_text", "axis.title"),
-  axis.ticks.margin   = el_def("unit"),
 
   legend.background   = el_def("element_rect", "rect"),
   legend.margin       = el_def("unit"),
@@ -312,14 +268,17 @@ el_def <- function(class = NULL, inherit = NULL, description = NULL) {
   panel.grid.major.y  = el_def("element_line", "panel.grid.major"),
   panel.grid.minor.x  = el_def("element_line", "panel.grid.minor"),
   panel.grid.minor.y  = el_def("element_line", "panel.grid.minor"),
+  panel.ontop         = el_def("logical"),
 
   strip.background    = el_def("element_rect", "rect"),
   strip.text.x        = el_def("element_text", "strip.text"),
   strip.text.y        = el_def("element_text", "strip.text"),
+  strip.switch.pad.grid = el_def("unit"),
+  strip.switch.pad.wrap = el_def("unit"),
 
   plot.background     = el_def("element_rect", "rect"),
   plot.title          = el_def("element_text", "title"),
-  plot.margin         = el_def("unit"),
+  plot.margin         = el_def("margin"),
 
   aspect.ratio        = el_def("character")
 )
@@ -350,7 +309,9 @@ validate_element <- function(el, elname) {
     # but sometimes its a vector like c(0,0)
     if (!is.character(el) && !is.numeric(el))
       stop("Element ", elname, " must be a string or numeric vector.")
-
+  } else if (eldef$class == "margin") {
+    if (!is.unit(el) && length(el) == 4)
+      stop("Element ", elname, " must be a unit vector of length 4.")
   } else if (!inherits(el, eldef$class) && !inherits(el, "element_blank")) {
       stop("Element ", elname, " must be a ", eldef$class, " object.")
   }
diff --git a/R/theme.r b/R/theme.r
index 53ac718..d8be07a 100644
--- a/R/theme.r
+++ b/R/theme.r
@@ -7,24 +7,28 @@
 #' @seealso \code{\link{\%+replace\%}} and \code{\link{+.gg}}
 #' @export
 #' @examples
-#' qplot(mpg, wt, data = mtcars)
+#' p <- ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point()
+#' p
 #' old <- theme_set(theme_bw())
-#' qplot(mpg, wt, data = mtcars)
+#' p
 #' theme_set(old)
-#' qplot(mpg, wt, data = mtcars)
+#' p
 #'
 #' old <- theme_update(panel.background = element_rect(colour = "pink"))
-#' qplot(mpg, wt, data = mtcars)
+#' p
 #' theme_set(old)
 #' theme_get()
 #'
-#' qplot(mpg, wt, data=mtcars, colour=mpg) +
-#'   theme(legend.position=c(0.95, 0.95), legend.justification = c(1, 1))
+#' ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point(aes(color = mpg)) +
+#'   theme(legend.position = c(0.95, 0.95),
+#'         legend.justification = c(1, 1))
 #' last_plot() +
 #'  theme(legend.background = element_rect(fill = "white", colour = "white", size = 3))
 theme_update <- function(...) {
   # Make a call to theme, then add to theme
-  theme_set(theme_get() %+replace% do.call(theme, list(...)))
+  theme_set(theme_get() %+replace% theme(...))
 }
 
 #' Reports whether x is a theme object
@@ -33,7 +37,7 @@ theme_update <- function(...) {
 is.theme <- function(x) inherits(x, "theme")
 
 #' @export
-print.theme <- function(x, ...) str(x)
+print.theme <- function(x, ...) utils::str(x)
 
 #' Set theme elements
 #'
@@ -58,12 +62,13 @@ print.theme <- function(x, ...) str(x)
 #' \tabular{ll}{
 #'   line             \tab all line elements
 #'                    (\code{element_line}) \cr
-#'   rect             \tab all rectangluar elements
+#'   rect             \tab all rectangular elements
 #'                    (\code{element_rect}) \cr
 #'   text             \tab all text elements
 #'                    (\code{element_text}) \cr
 #'   title            \tab all title elements: plot, axes, legends
 #'                    (\code{element_text}; inherits from \code{text}) \cr
+#'   aspect.ratio     \tab aspect ratio of the panel \cr
 #'
 #'   axis.title       \tab label of axes
 #'                    (\code{element_text}; inherits from \code{text}) \cr
@@ -85,8 +90,6 @@ print.theme <- function(x, ...) str(x)
 #'                    (\code{element_line}; inherits from \code{axis.ticks}) \cr
 #'   axis.ticks.length  \tab length of tick marks
 #'                    (\code{unit}) \cr
-#'   axis.ticks.margin  \tab space between tick mark and tick label
-#'                    (\code{unit}) \cr
 #'   axis.line        \tab lines along axes
 #'                    (\code{element_line}; inherits from \code{line}) \cr
 #'   axis.line.x      \tab line along x axis
@@ -153,6 +156,9 @@ print.theme <- function(x, ...) str(x)
 #'                    (\code{element_line}; inherits from \code{panel.grid.minor}) \cr
 #'   panel.grid.minor.y \tab horizontal minor grid lines
 #'                    (\code{element_line}; inherits from \code{panel.grid.minor}) \cr
+#'   panel.ontop        \tab option to place the panel (background, gridlines)
+#'                           over the data layers.  Usually used with a transparent
+#'                           or blank \code{panel.background}. (\code{logical}) \cr
 #'
 #'   plot.background  \tab background of the entire plot
 #'                    (\code{element_rect}; inherits from \code{rect}) \cr
@@ -170,6 +176,10 @@ print.theme <- function(x, ...) str(x)
 #'                    (\code{element_text}; inherits from \code{strip.text}) \cr
 #'   strip.text.y     \tab facet labels along vertical direction
 #'                    (\code{element_text}; inherits from \code{strip.text}) \cr
+#'   strip.switch.pad.grid \tab space between strips and axes when strips are switched
+#'                    (\code{unit}) \cr
+#'   strip.switch.pad.wrap \tab space between strips and axes when strips are switched
+#'                    (\code{unit}) \cr
 #' }
 #'
 #' @param ... a list of element name, element pairings that modify the
@@ -177,6 +187,7 @@ print.theme <- function(x, ...) str(x)
 #' @param complete set this to TRUE if this is a complete theme, such as
 #'   the one returned \code{by theme_grey()}. Complete themes behave
 #'   differently when added to a ggplot object.
+#' @param validate TRUE to run validate_element, FALSE to bypass checks.
 #'
 #' @seealso \code{\link{+.gg}}
 #' @seealso \code{\link{\%+replace\%}}
@@ -188,13 +199,15 @@ print.theme <- function(x, ...) str(x)
 #' @export
 #' @examples
 #' \donttest{
-#' p <- qplot(mpg, wt, data = mtcars)
+#' p <- ggplot(mtcars, aes(mpg, wt)) +
+#'   geom_point()
 #' p
 #' p + theme(panel.background = element_rect(colour = "pink"))
 #' p + theme_bw()
 #'
 #' # Scatter plot of gas mileage by vehicle weight
-#' p <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point()
+#' p <- ggplot(mtcars, aes(wt, mpg)) +
+#'   geom_point()
 #' # Calculate slope and intercept of line of best fit
 #' coef(lm(mpg ~ wt, data = mtcars))
 #' p + geom_abline(intercept = 37, slope = -5)
@@ -207,7 +220,7 @@ print.theme <- function(x, ...) str(x)
 #' # Change the axis labels
 #' # Original plot
 #' p
-#' p + xlab("Vehicle Weight") + ylab("Miles per Gallon")
+#' p + labs(x = "Vehicle Weight", y = "Miles per Gallon")
 #' # Or
 #' p + labs(x = "Vehicle Weight", y = "Miles per Gallon")
 #'
@@ -219,14 +232,14 @@ print.theme <- function(x, ...) str(x)
 #'
 #' # Changing plot look with themes
 #' DF <- data.frame(x = rnorm(400))
-#' m <- ggplot(DF, aes(x = x)) + geom_histogram()
+#' m <- ggplot(DF, aes(x = x)) +
+#'   geom_histogram()
 #' # Default is theme_grey()
 #' m
 #' # Compare with
 #' m + theme_bw()
 #'
 #' # Manipulate Axis Attributes
-#' library(grid) # for unit
 #' m + theme(axis.line = element_line(size = 3, colour = "red", linetype = "dotted"))
 #' m + theme(axis.text = element_text(colour = "blue"))
 #' m + theme(axis.text.y = element_blank())
@@ -236,17 +249,20 @@ print.theme <- function(x, ...) str(x)
 #' m + theme(axis.ticks.length = unit(.85, "cm"))
 #'
 #' # Legend Attributes
-#' z <- ggplot(mtcars, aes(wt, mpg, colour = factor(cyl))) + geom_point()
+#' z <- ggplot(mtcars, aes(wt, mpg)) +
+#'   geom_point(aes(colour = factor(cyl)))
 #' z
 #' z + theme(legend.position = "none")
 #' z + theme(legend.position = "bottom")
 #' # Or use relative coordinates between 0 and 1
 #' z + theme(legend.position = c(.5, .5))
-#  # Add a border to the whole legend
+#' # Add a border to the whole legend
 #' z + theme(legend.background = element_rect(colour = "black"))
 #' # Legend margin controls extra space around outside of legend:
-#' z + theme(legend.background = element_rect(), legend.margin = unit(1, "cm"))
-#' z + theme(legend.background = element_rect(), legend.margin = unit(0, "cm"))
+#' z + theme(legend.background = element_rect(),
+#'           legend.margin = unit(1, "cm"))
+#' z + theme(legend.background = element_rect(),
+#'           legend.margin = unit(0, "cm"))
 #' # Or to just the keys
 #' z + theme(legend.key = element_rect(colour = "black"))
 #' z + theme(legend.key = element_rect(fill = "yellow"))
@@ -265,15 +281,17 @@ print.theme <- function(x, ...) str(x)
 #' z + theme(panel.grid.major = element_line(colour = "blue"))
 #' z + theme(panel.grid.minor = element_line(colour = "red", linetype = "dotted"))
 #' z + theme(panel.grid.major = element_line(size = 2))
-#' z + theme(panel.grid.major.y = element_blank(), panel.grid.minor.y = element_blank())
+#' z + theme(panel.grid.major.y = element_blank(),
+#'           panel.grid.minor.y = element_blank())
 #' z + theme(plot.background = element_rect())
 #' z + theme(plot.background = element_rect(fill = "green"))
 #'
 #' # Faceting Attributes
 #' set.seed(4940)
 #' dsmall <- diamonds[sample(nrow(diamonds), 1000), ]
-#' k <- ggplot(dsmall, aes(carat, ..density..)) + geom_histogram(binwidth = 0.2) +
-#' facet_grid(. ~ cut)
+#' k <- ggplot(dsmall, aes(carat, ..density..)) +
+#'   geom_histogram(binwidth = 0.2) +
+#'   facet_grid(. ~ cut)
 #' k + theme(strip.background = element_rect(colour = "purple", fill = "pink",
 #'                                           size = 3, linetype = "dashed"))
 #' k + theme(strip.text.x = element_text(colour = "red", angle = 45, size = 10,
@@ -281,6 +299,17 @@ print.theme <- function(x, ...) str(x)
 #' k + theme(panel.margin = unit(5, "lines"))
 #' k + theme(panel.margin.y = unit(0, "lines"))
 #'
+#' # Put gridlines on top
+#' meanprice <- tapply(diamonds$price, diamonds$cut, mean)
+#' cut <- factor(levels(diamonds$cut), levels = levels(diamonds$cut))
+#' df <- data.frame(meanprice, cut)
+#' g <- ggplot(df, aes(cut, meanprice)) + geom_bar(stat = "identity")
+#' g + geom_bar(stat = "identity") +
+#'     theme(panel.background = element_blank(),
+#'           panel.grid.major.x = element_blank(),
+#'           panel.grid.minor.x = element_blank(),
+#'           panel.grid.minor.y = element_blank(),
+#'           panel.ontop = TRUE)
 #'
 #' # Modify a theme and save it
 #' mytheme <- theme_grey() + theme(plot.title = element_text(colour = "red"))
@@ -301,7 +330,7 @@ print.theme <- function(x, ...) str(x)
 #'       data.frame(child = name, parent = item$inherit)
 #'   }
 #'
-#'   edges <- rbind.fill(mapply(inheritdf, names(tree), tree))
+#'   edges <- plyr::rbind.fill(mapply(inheritdf, names(tree), tree))
 #'
 #'   # Explicitly add vertices (since not all are in edge list)
 #'   vertices <- data.frame(name = names(tree))
@@ -316,43 +345,25 @@ print.theme <- function(x, ...) str(x)
 #' plot(g, layout=layout.fruchterman.reingold, vertex.size=4, vertex.label.dist=.25)
 #'
 #' }
-theme <- function(..., complete = FALSE) {
-  elements <- list(...)
-
-  # Check that all elements have the correct class (element_text, unit, etc)
-  mapply(validate_element, elements, names(elements))
-
-  structure(elements, class = c("theme", "gg"), complete = complete)
-}
-
-
-#' Build a theme (or partial theme) from theme elements
-#'
-#' \code{opts} is deprecated. See the \code{\link{theme}} function.
-#' @param ... Arguments to be passed on to the \code{theme} function.
-#'
-#' @export
-opts <- function(...) {
-  gg_dep("0.9.1", "'opts' is deprecated. Use 'theme' instead.")
-
-  # Add check for deprecated elements
-  extra <- NULL
+theme <- function(..., complete = FALSE, validate = TRUE) {
   elements <- list(...)
-  if (!is.null(elements[["title"]])) {
-    # This is kind of a hack, but fortunately it will be removed in future versions
-    gg_dep("0.9.1", paste(sep = "\n",
-      'Setting the plot title with opts(title="...") is deprecated.',
-      ' Use labs(title="...") or ggtitle("...") instead.'))
 
-    title <- elements$title
-    elements$title <- NULL
+  if (!is.null(elements$axis.ticks.margin)) {
+    warning("`axis.ticks.margin` is deprecated. Please set `margin` property ",
+      " of `axis.text` instead", call. = FALSE)
+    elements$axis.ticks.margin <- NULL
+  }
 
-    return(list(ggtitle(title), do.call(theme, elements)))
+  # Check that all elements have the correct class (element_text, unit, etc)
+  if (validate) {
+    mapply(validate_element, elements, names(elements))
   }
 
-  do.call(theme, elements)
+  structure(elements, class = c("theme", "gg"),
+            complete = complete, validate = validate)
 }
 
+
 # Combine plot defaults with current theme to get complete theme for a plot
 plot_theme <- function(x) {
   defaults(x$theme, theme_get())
@@ -425,7 +436,7 @@ add_theme <- function(t1, t2, t2name) {
       # If x is NULL or element_blank, then just assign it y
       x <- y
     } else if (is.null(y) || is.character(y) || is.numeric(y) ||
-               inherits(y, "element_blank")) {
+               is.logical(y) || inherits(y, "element_blank")) {
       # If y is NULL, or a string or numeric vector, or is element_blank, just replace x
       x <- y
     } else {
@@ -464,7 +475,8 @@ add_theme <- function(t1, t2, t2name) {
 # same name as those from newtheme, and puts them in oldtheme. Then
 # it adds elements from newtheme to oldtheme.
 # This makes it possible to do things like:
-#   qplot(1:3, 1:3) + theme(text = element_text(colour = 'red'))
+#   ggplot(data.frame(x = 1:3, y = 1:3)) +
+#   geom_point() + theme(text = element_text(colour = 'red'))
 # and have 'text' keep properties from the default theme. Otherwise
 # you would have to set all the element properties, like family, size,
 # etc.
@@ -480,7 +492,7 @@ update_theme <- function(oldtheme, newtheme) {
 
   # These are elements in newtheme that aren't already set in oldtheme.
   # They will be pulled from the default theme.
-  newitems <- ! names(newtheme) %in% names(oldtheme)
+  newitems <- !names(newtheme) %in% names(oldtheme)
   newitem_names <- names(newtheme)[newitems]
   oldtheme[newitem_names] <- theme_get()[newitem_names]
 
@@ -488,59 +500,15 @@ update_theme <- function(oldtheme, newtheme) {
   # Turn the 'theme' list into a proper theme object first, and preserve
   # the 'complete' attribute. It's possible that oldtheme is an empty
   # list, and in that case, set complete to FALSE.
+  old.validate <- isTRUE(attr(oldtheme, "validate"))
+  new.validate <- isTRUE(attr(newtheme, "validate"))
   oldtheme <- do.call(theme, c(oldtheme,
-    complete = isTRUE(attr(oldtheme, "complete"))))
+    complete = isTRUE(attr(oldtheme, "complete")),
+    validate = old.validate & new.validate))
 
   oldtheme + newtheme
 }
 
-
-##' Update contents of a theme. (Deprecated)
-##'
-##' This function is deprecated. Use \code{\link{\%+replace\%}} or
-##' \code{\link{+.gg}} instead.
-##'
-##' @title Update theme param
-##' @param name name of a theme element
-##' @param ... Pairs of name and value of theme parameters.
-##' @return Updated theme element
-##' @seealso \code{\link{\%+replace\%}} and \code{\link{+.gg}}
-##' @export
-##' @examples
-##' \dontrun{
-##' x <- element_text(size = 15)
-##' update_element(x, colour = "red")
-##' # Partial matching works
-##' update_element(x, col = "red")
-##' # So does positional
-##' update_element(x, "Times New Roman")
-##' # And it throws an error if you use an argument that doesn't exist
-##' update_element(x, noargument = 12)
-##' # Or multiple arguments with the same name
-##' update_element(x, size = 12, size = 15)
-##'
-##' # Will look up element if given name
-##' update_element("axis.text.x", colour = 20)
-##' # Throws error if incorrectly named
-##' update_element("axis.text", colour = 20)
-##' }
-update_element <- function(name, ...) {
-  gg_dep("0.9.1", "update_element is deprecated. Use '+.gg' instead.")
- if (is.character(name)) {
-   ele <- theme_get()[[name]]
-   if (is.null(ele)) {
-     stop("Could not find theme element ", name, call. = FALSE)
-   }
- } else {
-   ele <- name
- }
-
-  stopifnot(inherits(ele, "element"))
-
-  modifyList(ele, list(...))
-}
-
-
 #' Calculate the element properties, by inheriting properties from its parents
 #'
 #' @param element The name of the theme element to calculate
diff --git a/R/translate-qplot-gpl.r b/R/translate-qplot-gpl.r
deleted file mode 100644
index 8e42dab..0000000
--- a/R/translate-qplot-gpl.r
+++ /dev/null
@@ -1,56 +0,0 @@
-#' Translating between qplot and Graphics Production Library (GPL)
-#'
-#' The Grammar of Graphics uses two specifications. A concise format is used to
-#' caption figures, and a more detailed xml format stored on disk.
-#'
-#' @name translate_qplot_gpl
-#' @examples
-#'
-#' # The following example of the concise format is adapted from Figure 1.5,
-#' # page 13, of Leland Wilkinson's "The Grammar of Graphics."
-#' # Springer, 2nd edition, 2005.
-#'
-#' # DATA: source("demographics")
-#' # DATA: longitude, latitude = map(source("World"))
-#' # TRANS: bd = max(birth - death, 0)
-#' # COORD: project.mercator()
-#' # ELEMENT: point(position(lon * lat), size(bd), color(color.red))
-#' # ELEMENT: polygon(position(longitude * latitude))
-#'
-#' # This is relatively simple to adapt to the syntax of ggplot2:
-#'
-#' # ggplot() is used to specify the default data and default aesthetic mappings.
-#' # Data is provided as standard R data.frames existing in the global environment;
-#' # it does not need to be explicitly loaded. We also use a slightly
-#' # different world dataset, with columns lat and long. This lets us use the
-#' # same aesthetic mappings for both datasets. Layers can override the default
-#' # data and aesthetic mappings provided by the plot.
-#'
-#' # We replace TRANS with an explicit transformation by R code.
-#'
-#' # ELEMENTs are replaced with layers, which explicitly specify the data
-#' # source. Each geom has a default statistic which is used to transform the
-#' # data prior to plotting. For the geoms in this example, the default statistic
-#' # is the identity function. Fixed aesthetics (the colour red in this example)
-#' # are supplied as additional arguments to the layer, rather than as special
-#' # constants.
-#'
-#' # The SCALE component has been omitted from this example (so that the
-#' # defaults are used). In both the ggplot2 and GoG examples, scales are
-#' # defined by default. In ggplot you can override the defaults by adding a
-#' # scale object, e.g., scale colour or scale size.
-#'
-#' # COORD uses a slightly different format. In general, most of the components
-#' # specifications in ggplot are slightly different to those in GoG, in order to
-#' # be more familiar to R users.
-#'
-#' # Each component is added together with + to create the final plot.
-#'
-#' # Resulting ggplot2 code:
-#' # demographics <- transform(demographics, bd = pmax(birth - death, 0))
-#' # p <- ggplot(demographic, aes(lon, lat))
-#' # p <- p + geom_polyogon(data = world)
-#' # p <- p + geom_point(aes(size = bd), colour = "red")
-#' # p <- p + coord_map(projection = "mercator")
-#' # print(p)
-NULL
diff --git a/R/translate-qplot-lattice.r b/R/translate-qplot-lattice.r
index 9071e35..67f0723 100644
--- a/R/translate-qplot-lattice.r
+++ b/R/translate-qplot-lattice.r
@@ -9,6 +9,7 @@
 #' \dontrun{
 #' library(lattice)
 #'
+#' if (require("ggplot2movies")) {
 #' xyplot(rating ~ year, data=movies)
 #' qplot(year, rating, data=movies)
 #'
@@ -35,6 +36,7 @@
 #'
 #' xyplot(wt ~ mpg, mtcars, type = c("p","r"))
 #' qplot(mpg, wt, data = mtcars, geom = c("point","smooth"), method = "lm")
+#' }
 #'
 #' # The capabilities for scale manipulations are similar in both ggplot2 and
 #' # lattice, although the syntax is a little different.
@@ -46,9 +48,9 @@
 #' qplot(mpg, wt, data = mtcars, log = "xy")
 #'
 #' xyplot(wt ~ mpg | cyl, mtcars, scales = list(log = 2))
-#' library(scales)  # Load scales for log2_trans
-#' qplot(mpg, wt, data = mtcars) + scale_x_continuous(trans = log2_trans()) +
-#'   scale_y_continuous(trans = log2_trans())
+#' qplot(mpg, wt, data = mtcars) +
+#'   scale_x_continuous(trans = scales::log2_trans()) +
+#'   scale_y_continuous(trans = scales::log2_trans())
 #'
 #' xyplot(wt ~ mpg, mtcars, group = cyl, auto.key = TRUE)
 #' # Map directly to an aesthetic like colour, size, or shape.
diff --git a/R/utilities-break.r b/R/utilities-break.r
index 1ed9f9f..aa18194 100644
--- a/R/utilities-break.r
+++ b/R/utilities-break.r
@@ -1,5 +1,11 @@
-#' Cut numeric vector into intervals of equal length.
+#' Cut up numeric vector into useful groups.
 #'
+#' \code{cut_interval} makes \code{n} groups with equal range, \code{cut_number}
+#' makes \code{n} groups with (approximately) equal numbers of observations;
+#' \code{cut_width} makes groups of width \code{width}.
+#'
+#' @author Randall Prium contributed most of the implementation of
+#'    \code{cut_width}.
 #' @param x numeric vector
 #' @param n number of intervals to create, OR
 #' @param length length of each interval
@@ -7,24 +13,81 @@
 #' @seealso \code{\link{cut_number}}
 #' @export
 #' @examples
-#' table(cut_interval(1:100, n = 10))
-#' table(cut_interval(1:100, n = 11))
-#' table(cut_interval(1:100, length = 10))
+#' table(cut_interval(1:100, 10))
+#' table(cut_interval(1:100, 11))
+#'
+#' table(cut_number(runif(1000), 10))
+#'
+#' table(cut_width(runif(1000), 0.1))
+#' table(cut_width(runif(1000), 0.1, boundary = 0))
+#' table(cut_width(runif(1000), 0.1, center = 0))
 cut_interval <- function(x, n = NULL, length = NULL, ...) {
   cut(x, breaks(x, "width", n, length), include.lowest = TRUE, ...)
 }
 
-#' Cut numeric vector into intervals containing equal number of points.
-#'
-#' @param x numeric vector
-#' @param n number of intervals to create
-#' @param ... other arguments passed on to \code{\link{cut}}
-#' @seealso \code{\link{cut_interval}}
 #' @export
-#' @examples
-#' table(cut_number(runif(1000), n = 10))
+#' @rdname cut_interval
 cut_number <- function(x, n = NULL, ...) {
-  cut(x, breaks(x, "n", n), include.lowest = TRUE, ...)
+  brk <- breaks(x, "n", n)
+  if (anyDuplicated(brk))
+    stop("Insufficient data values to produce ", n, " bins.", call. = FALSE)
+  cut(x, brk , include.lowest = TRUE, ...)
+}
+
+#' @export
+#' @rdname cut_interval
+#' @param width The bin width.
+#' @param center,boundary Specify either the position of edge or the center of
+#'   a bin. Since all bins are aligned, specifying the position of a single bin
+#'   (which doesn't need to be in the range of the data) affects the location of
+#'   all bins. If not specified, uses the "tile layers algorithm", and sets
+#'   the boundary to half of the binwidth.
+#'
+#'   To center on integers, \code{width = 1} and \code{center = 0}.
+#'   \code{boundary = 0.5}.
+#' @param closed One of \code{"right"} or \code{"left"} indicating whether right
+#'   or left edges of bins are included in the bin.
+cut_width <- function(x, width, center = NULL, boundary = NULL, closed = c("right", "left")) {
+  x <- as.numeric(x)
+  width <- as.numeric(width)
+
+  closed <- match.arg(closed)
+
+  x_range <- range(x, na.rm = TRUE, finite = TRUE)
+  if (length(x_range) == 0) {
+    return(x)
+  }
+
+  # Determine boundary
+  if (!is.null(boundary) && !is.null(center)) {
+    stop("Only one of 'boundary' and 'center' may be specified.")
+  }
+  if (is.null(boundary)) {
+    if (is.null(center)) {
+      # If neither edge nor center given, compute both using tile layer's
+      # algorithm. This puts min and max of data in outer half of their bins.
+      boundary <- width / 2
+    } else {
+      # If center given but not boundary, compute boundary.
+      boundary <- center - width / 2
+    }
+  }
+  boundary <- as.numeric(boundary)
+
+  # Determine bins
+  min_x <- find_origin(x_range, width, boundary)
+  # Small correction factor so that we don't get an extra bin when, for
+  # example, origin = 0, max(x) = 20, width = 10.
+  max_x <- max(x, na.rm = TRUE) + (1 - 1e-08) * width
+
+  breaks <- seq(min_x, max_x, width)
+  cut(x, breaks, include.lowest = TRUE, right = (closed == "right"))
+}
+
+# Find the left side of left-most bin
+find_origin <- function(x_range, width, boundary) {
+  shift <- floor((x_range[1] - boundary) / width)
+  boundary + shift * width
 }
 
 breaks <- function(x, equal, nbins = NULL, binwidth = NULL) {
@@ -38,15 +101,15 @@ breaks <- function(x, equal, nbins = NULL, binwidth = NULL) {
     if (!is.null(binwidth)) {
       fullseq(rng, binwidth)
     } else {
-      seq(rng[1], rng[2], length = nbins + 1)
+      seq(rng[1], rng[2], length.out = nbins + 1)
     }
   } else {
     if (!is.null(binwidth)) {
       probs <- seq(0, 1, by = binwidth)
     } else {
-      probs <- seq(0, 1, length = nbins + 1)
+      probs <- seq(0, 1, length.out = nbins + 1)
     }
-    quantile(x, probs, na.rm = TRUE)
+    stats::quantile(x, probs, na.rm = TRUE)
   }
 
 }
diff --git a/R/utilities-grid.r b/R/utilities-grid.r
index 490478a..c0089eb 100644
--- a/R/utilities-grid.r
+++ b/R/utilities-grid.r
@@ -1,3 +1,9 @@
+#' @export
+grid::unit
+
+#' @export
+grid::arrow
+
 # Name ggplot grid object
 # Convenience function to name grid objects
 #
diff --git a/R/utilities-help.r b/R/utilities-help.r
index 884a7f1..66d16a6 100644
--- a/R/utilities-help.r
+++ b/R/utilities-help.r
@@ -1,26 +1,29 @@
 aesthetics <- function(x) {
   req_aes <- x$required_aes
-  def_aes <- names(x$default_aes())
+  def_aes <- names(x$default_aes)
   def_aes <- setdiff(def_aes, req_aes)
-  if (length(req_aes) == 0){
+  if (length(req_aes) == 0) {
     # Suppress warnings which occur when sorting NULL
-    return(suppressWarnings(sort(names(x$default_aes()))))
+    return(suppressWarnings(sort(names(x$default_aes))))
   }
-  if (length(def_aes) == 0){
+  if (length(def_aes) == 0) {
     return(paste("\\strong{", sort(x$required_aes), "}",sep = ""))
   }
   return(c(paste("\\strong{", sort(x$required_aes), "}", sep = ""), sort(def_aes)))
 }
 geom_aesthetics <- function(x) {
-  aesthetics(Geom$find(x))
+  aesthetics(find_subclass("Geom", x))
 }
 stat_aesthetics <- function(x) {
-  aesthetics(Stat$find(x))
+  aesthetics(find_subclass("Stat", x))
 }
 
 rd_aesthetics <- function(type, name) {
-  obj <- get(firstUpper(type))
-  aes <- aesthetics(obj$find(name))
+  obj <- switch(type,
+    geom = find_subclass("Geom", name),
+    stat = find_subclass("Stat", name)
+  )
+  aes <- aesthetics(obj)
 
   paste("\\code{", type, "_", name, "} ",
     "understands the following aesthetics (required aesthetics are in bold):\n\n",
diff --git a/R/utilities-layer.r b/R/utilities-layer.r
deleted file mode 100644
index fabf3d0..0000000
--- a/R/utilities-layer.r
+++ /dev/null
@@ -1,33 +0,0 @@
-# Ensure that the data frame contains a grouping variable.
-#
-# If the \code{group} variable is not present, then a new group
-# variable is generated from the interaction of all discrete (factor or
-# character) vectors, excluding \code{label}.
-#
-# @param data.frame
-# @value data.frame with group variable
-# @keyword internal
-add_group <- function(data) {
-  if (empty(data)) return(data)
-
-  if (is.null(data$group)) {
-    disc <- vapply(data, is.discrete, logical(1))
-    disc[names(disc) == "label"] <- FALSE
-
-    if (any(disc)) {
-      data$group <- id(data[disc], drop = TRUE)
-    } else {
-      data$group <- 1L
-    }
-  } else {
-    data$group <- id(data["group"], drop = TRUE)
-  }
-
-  data
-}
-
-order_groups <- function(data) {
-  if (is.null(data$order)) return(data)
-
-  data[order(data$order), ]
-}
diff --git a/R/utilities-matrix.r b/R/utilities-matrix.r
index dedf0c9..27796d3 100644
--- a/R/utilities-matrix.r
+++ b/R/utilities-matrix.r
@@ -1,29 +1,3 @@
-#' Row weave.
-#'
-#' Weave together two (or more) matrices by row.
-#'
-#' Matrices must have same dimensions.
-#'
-#' @param ... matrices to weave together
-#' @keywords internal
-#X a <- matrix(1:10 * 2, ncol = 2)
-#X b <- matrix(1:10 * 3, ncol = 2)
-#X c <- matrix(1:10 * 5, ncol = 2)
-rweave <- function(...) UseMethod("rweave")
-#' @export
-rweave.list <- function(...) do.call("rweave", ...)
-#' @export
-rweave.matrix <- function(...) {
-  matrices <- list(...)
-  stopifnot(equal_dims(matrices))
-
-  n <- nrow(matrices[[1]])
-  p <- length(matrices)
-
-  interleave <- rep(1:n, each = p) + seq(0, p - 1) * n
-  do.call("rbind", matrices)[interleave, , drop = FALSE]
-}
-
 # Col union
 # Form the union of columns in a and b.  If there are columns of the same name in both a and b, take the column from a.
 #
@@ -37,71 +11,28 @@ cunion <- function(a, b) {
   cbind(a, b[setdiff(names(b), names(a))])
 }
 
-#' Col weave
-#'
-#' Weave together two (or more) matrices by column
-#'
-#' Matrices must have same dimensions
-#'
-#' @param ... matrices to weave together
-#' @keywords internal
-cweave <- function(...) UseMethod("cweave")
-#' @export
-cweave.list <- function(...) do.call("cweave", ...)
-#' @export
-cweave.matrix <- function(...) {
-  matrices <- list(...)
-  stopifnot(equal_dims(matrices))
-
-  n <- ncol(matrices[[1]])
-  p <- length(matrices)
-
-  interleave <- rep(1:n, each = p) + seq(0, p - 1) * n
-  do.call("cbind", matrices)[, interleave, drop = FALSE]
-}
-
-#' Interleave (or zip) multiple vectors into a single vector.
-#'
-#' @param ... vectors to interleave
-#' @keywords internal
+# Interleave (or zip) multiple units into one vector
 interleave <- function(...) UseMethod("interleave")
 #' @export
-interleave.list <- function(...) do.call("interleave", ...)
-#' @export
 interleave.unit <- function(...) {
-  do.call("unit.c", do.call("interleave.default", llply(list(...), as.list)))
+  do.call("unit.c", do.call("interleave.default", plyr::llply(list(...), as.list)))
 }
 #' @export
 interleave.default <- function(...) {
   vectors <- list(...)
 
   # Check lengths
-  lengths <- unique(setdiff(laply(vectors, length), 1))
+  lengths <- unique(setdiff(plyr::laply(vectors, length), 1))
   if (length(lengths) == 0) lengths <- 1
   stopifnot(length(lengths) <= 1)
 
   # Replicate elements of length one up to correct length
-  singletons <- laply(vectors, length) == 1
-  vectors[singletons] <- llply(vectors[singletons], rep, lengths)
+  singletons <- plyr::laply(vectors, length) == 1
+  vectors[singletons] <- plyr::llply(vectors[singletons], rep, lengths)
 
   # Interleave vectors
   n <- lengths
   p <- length(vectors)
   interleave <- rep(1:n, each = p) + seq(0, p - 1) * n
-  unlist(vectors, recursive=FALSE)[interleave]
-}
-
-# Equal dims?
-# Check that a list of matrices have equal dimensions
-#
-# @param list of matrices
-# @keyword internal
-equal_dims <- function(matrices) {
-  are.matrices <- laply(matrices, is.matrix)
-  stopifnot(all(are.matrices))
-
-  cols <- laply(matrices, ncol)
-  rows <- laply(matrices, ncol)
-
-  length(unique(cols) == 1) && length(unique(rows) == 1)
+  unlist(vectors, recursive = FALSE)[interleave]
 }
diff --git a/R/utilities.r b/R/utilities.r
index 9ca25c8..7a60f8e 100644
--- a/R/utilities.r
+++ b/R/utilities.r
@@ -1,13 +1,20 @@
+#' @export
+#' @examples
+#' ggplot(mpg, aes(displ, hwy)) +
+#'   geom_point(alpha = 0.5, colour = "blue")
+#'
+#' ggplot(mpg, aes(displ, hwy)) +
+#'   geom_point(colour = alpha("blue", 0.5))
+scales::alpha
 
-# Null default
-# Analog of || from ruby
-#
-# @keyword internal
-# @name nulldefault-infix
 "%||%" <- function(a, b) {
   if (!is.null(a)) a else b
 }
 
+"%|W|%" <- function(a, b) {
+  if (!is.waive(a)) a else b
+}
+
 # Check required aesthetics are present
 # This is used by geoms and stats to give a more helpful error message
 # when required aesthetics are missing.
@@ -20,7 +27,8 @@ check_required_aesthetics <- function(required, present, name) {
   missing_aes <- setdiff(required, present)
   if (length(missing_aes) == 0) return()
 
-  stop(name, " requires the following missing aesthetics: ", paste(missing_aes, collapse=", "), call. = FALSE)
+  stop(name, " requires the following missing aesthetics: ",
+    paste(missing_aes, collapse = ", "), call. = FALSE)
 }
 
 # Concatenate a named list for output
@@ -31,32 +39,17 @@ check_required_aesthetics <- function(required, present, name) {
 #X clist(list(a=1, b=2))
 #X clist(par()[1:5])
 clist <- function(l) {
-  paste(paste(names(l), l, sep=" = ", collapse=", "), sep="")
+  paste(paste(names(l), l, sep = " = ", collapse = ", "), sep = "")
 }
 
-# Abbreviated paste
-# Alias for paste with a shorter name and convenient defaults
-#
-# @param character vectors to be concatenated
-# @param default separator
-# @param default collapser
-# @keyword internal
-ps <- function(..., sep="", collapse="") do.call(paste, compact(list(..., sep=sep, collapse=collapse)))
-
-# Quietly try to require a package
-# Queitly require a package, returning an error message if that package is not installed.
-#
-# @param name of package
-# @keyword internal
-try_require <- function(package) {
-  available <- suppressMessages(suppressWarnings(
-    require(package, character.only = TRUE)
-  ))
-
-  if (!available) {
-    stop(package, " package required for this functionality. " ,
-      "Please install and try again.", call. = FALSE)
+try_require <- function(package, fun) {
+  if (requireNamespace(package, quietly = TRUE)) {
+    library(package, character.only = TRUE)
+    return(invisible())
   }
+
+  stop("Package `", package, "` required for `", fun , "`.\n",
+    "Please install and try again.", call. = FALSE)
 }
 
 # Return unique columns
@@ -64,67 +57,49 @@ try_require <- function(package) {
 #
 # @keyword internal
 uniquecols <- function(df) {
-  df <- df[1, sapply(df, function(x) length(unique(x)) == 1), drop=FALSE]
+  df <- df[1, sapply(df, function(x) length(unique(x)) == 1), drop = FALSE]
   rownames(df) <- 1:nrow(df)
   df
 }
 
-# A "safe" version of do.call
-# \code{safe.call} works like \code{\link{do.call}} but it will only supply arguments that exist in the function specification.
-#
-# If ... is present in the param list, all parameters will be passed through
-# unless \code{ignore.dots = TRUE}.  Positional arguments are not currently
-# supported.
-#
-# @param function to call
-# @arugments named list of parameters to be supplied to function
-# @param parameter names of function
-# @param
-# @keyword internal
-safe.call <- function(f, params, f.params = names(formals(f)), ignore.dots = TRUE) {
-  if (!ignore.dots && "..." %in% f.params) {
-    safe.params <- params
-  } else {
-    safe.params <- params[intersect(f.params, names(params))]
-  }
-  do.call(f, safe.params)
-}
-
-# Convenience function to remove missing values from a data.frame
-# Remove all non-complete rows, with a warning if \code{na.rm = FALSE}.
-#
-# ggplot is somewhat more accomodating of missing values than R generally.
-# For those stats which require complete data, missing values will be
-# automatically removed with a warning.  If \code{na.rm = TRUE} is supplied
-# to the statistic, the warning will be suppressed.
-#
-# @param data.frame
-# @param suppress warning that rows are being removed?
-# @argumnets variables to check for missings in
-# @param optional function name to make warning message more informative
-# @keyword internal
-#X a <- remove_missing(movies)
-#X a <- remove_missing(movies, na.rm = TRUE)
-#X qplot(mpaa, budget, data=movies, geom="boxplot")
+#' Convenience function to remove missing values from a data.frame
+#'
+#' Remove all non-complete rows, with a warning if \code{na.rm = FALSE}.
+#' ggplot is somewhat more accommodating of missing values than R generally.
+#' For those stats which require complete data, missing values will be
+#' automatically removed with a warning. If \code{na.rm = TRUE} is supplied
+#' to the statistic, the warning will be suppressed.
+#'
+#' @param df data.frame
+#' @param na.rm If true, will suppress warning message.
+#' @param vars Character vector of variables to check for missings in
+#' @param name Optional function name to improve error message.
+#' @param finite If \code{TRUE}, will also remove non-finite values.
+#' @keywords internal
+#' @export
 remove_missing <- function(df, na.rm=FALSE, vars = names(df), name="", finite = FALSE) {
+  stopifnot(is.logical(na.rm))
+
   vars <- intersect(vars, names(df))
-  if (name != "") name <- ps(" (", name, ")")
+  if (name != "") name <- paste(" (", name, ")", sep = "")
 
   if (finite) {
     missing <- !finite.cases(df[, vars, drop = FALSE])
     str <- "non-finite"
   } else {
-    missing <- !complete.cases(df[, vars, drop = FALSE])
+    missing <- !stats::complete.cases(df[, vars, drop = FALSE])
     str <- "missing"
   }
 
   if (any(missing)) {
     df <- df[!missing, ]
-    if (!na.rm) warning("Removed ", sum(missing), " rows containing ", str,
-      " values", name, ".", call. = FALSE)
+    if (!na.rm) {
+      warning_wrap(
+        "Removed ", sum(missing), " rows containing ", str, " values", name, "."
+      )
+    }
   }
 
-
   df
 }
 
@@ -146,26 +121,6 @@ finite.cases.data.frame <- function(x) {
   }
 }
 
-
-# "Invert" a list
-# Keys become values, values become keys
-#
-# @param list to invert
-# @keyword internal
-invert <- function(L) {
-  t1 <- unlist(L)
-  names(t1) <- rep(names(L), lapply(L, length))
-  tapply(names(t1), t1, c)
-}
-
-# Inside
-# Return logical vector indicating if x is inside the interval
-#
-# @keyword internal
-"%inside%" <- function(x, interval) {
-  x >= interval[1] & x <= interval[2]
-}
-
 #' Used in examples to illustrate when errors should occur.
 #'
 #' @param expr code to evaluate.
@@ -190,7 +145,7 @@ should_stop <- function(expr) {
 #'
 #' @export
 #' @keywords internal
-waiver <- function() structure(NULL, class="waiver")
+waiver <- function() structure(NULL, class = "waiver")
 
 is.waive <- function(x) inherits(x, "waiver")
 
@@ -200,19 +155,7 @@ rescale01 <- function(x) {
   (x - rng[1]) / (rng[2] - rng[1])
 }
 
-# This is a hack for ggplot2 0.9.3 to make it compatible with both plyr 1.7.1 and
-# plyr 1.8 (and above). This should be removed for the next release of ggplot2.
-# Tag: deprecated
-if (packageVersion("plyr") <= package_version("1.7.1")) {
-  rename <- function(x, replace, warn_missing) {
-    plyr::rename(x, replace)
-  }
-} else {
-  rename <- plyr::rename
-}
-
-
-#' Give a deprecation error, warning, or messsage, depending on version number.
+#' Give a deprecation error, warning, or message, depending on version number.
 #'
 #' Version numbers have the format <major>.<minor>.<subminor>, like 0.9.2.
 #' This function compares the current version number of ggplot2 against the
@@ -240,7 +183,7 @@ if (packageVersion("plyr") <= package_version("1.7.1")) {
 #' @export
 gg_dep <- function(version, msg) {
   v <- as.package_version(version)
-  cv <- packageVersion("ggplot2")
+  cv <- utils::packageVersion("ggplot2")
 
   # If current major number is greater than last-good major number, or if
   #  current minor number is more than 1 greater than last-good minor number,
@@ -261,3 +204,78 @@ gg_dep <- function(version, msg) {
 
   invisible()
 }
+
+has_name <- function(x) {
+  nms <- names(x)
+  if (is.null(nms)) {
+    return(rep(FALSE, length(x)))
+  }
+
+  !is.na(nms) & nms != ""
+}
+
+# Convert a snake_case string to camelCase
+camelize <- function(x, first = FALSE) {
+  x <- gsub("_(.)", "\\U\\1", x, perl = TRUE)
+  if (first) x <- firstUpper(x)
+  x
+}
+
+snakeize <- function(x) {
+  x <- gsub("([A-Za-z])([A-Z])([a-z])", "\\1_\\2\\3", x)
+  x <- gsub(".", "_", x, fixed = TRUE)
+  x <- gsub("([a-z])([A-Z])", "\\1_\\2", x)
+  tolower(x)
+}
+
+firstUpper <- function(s) {
+  paste(toupper(substring(s, 1,1)), substring(s, 2), sep = "")
+}
+
+snake_class <- function(x) {
+  snakeize(class(x)[1])
+}
+
+empty <- function(df) {
+  is.null(df) || nrow(df) == 0 || ncol(df) == 0
+}
+
+is.discrete <- function(x) {
+  is.factor(x) || is.character(x) || is.logical(x)
+}
+
+compact <- function(x) {
+  null <- vapply(x, is.null, logical(1))
+  x[!null]
+}
+
+is.formula <- function(x) inherits(x, "formula")
+
+deparse2 <- function(x) {
+  y <- deparse(x, backtick = TRUE)
+  if (length(y) == 1) {
+    y
+  } else {
+    paste0(y[[1]], "...")
+  }
+}
+
+message_wrap <- function(...) {
+  msg <- paste(..., collapse = "", sep = "")
+  wrapped <- strwrap(msg, width = getOption("width") - 2)
+  message(paste0(wrapped, collapse = "\n"))
+}
+
+warning_wrap <- function(...) {
+  msg <- paste(..., collapse = "", sep = "")
+  wrapped <- strwrap(msg, width = getOption("width") - 2)
+  warning(paste0(wrapped, collapse = "\n"), call. = FALSE)
+}
+
+dispatch_args <- function(f, ...) {
+  args <- list(...)
+  formals <- formals(f)
+  formals[names(args)] <- args
+  formals(f) <- formals
+  f
+}
diff --git a/R/xxx-digest.r b/R/xxx-digest.r
deleted file mode 100644
index e4f7570..0000000
--- a/R/xxx-digest.r
+++ /dev/null
@@ -1,96 +0,0 @@
-bolus <- function(x) UseMethod("bolus")
-bolus.proto <- function(x) x$bolus()
-
-# Create a bolus object
-# A bolus is a list suitable for digesting.
-#
-# Most ggplot objects have components that should be hashed when creating
-# a digest (especially since most ggplot objects are proto objects and
-# are also self-documenting).  The bolus methods ensure that only appropriate
-# components are digested.
-#
-# @alias bolus
-# @alias bolus.proto
-# @alias digest.ggplot
-# @alias digest.proto
-# @keyword internal
-#X hash_tests <- list(
-#X   list(
-#X     ggplot() + scale_x_continuous() + scale_y_continuous(),
-#X     ggplot() + scale_y_continuous() + scale_x_continuous()
-#X   ),
-#X   list(
-#X     qplot(mpg, wt, data=mtcars, na.rm = FALSE),
-#X     ggplot(mtcars, aes(y=wt, x=mpg)) + geom_point()
-#X   ),
-#X   list(
-#X     qplot(mpg, wt, data=mtcars, xlab = "blah"),
-#X     qplot(mpg, wt, data=mtcars) + xlab("blah")
-#X   )
-#X )
-#X
-#X lapply(hash_tests, function(equal) {
-#X   hashes <- lapply(equal, digest.ggplot)
-#X
-#X   if (length(unique(hashes)) != 1) {
-#X     lapply(equal, function(x) print(str(bolus(x))))
-#X     stop("Above plots not equal")
-#X   }
-#X })
-bolus.ggplot <- function(x, ...) {
-  sort.by.name <- function(x) {
-    if (is.null(names(x))) return(x)
-    x[order(names(x))]
-  }
-
-  with(x, list(
-    data = digest::digest(data),
-    mapping = sort.by.name(mapping),
-    layers = sapply(layers, function(x) x$hash()),
-    scales = digest(scales),
-    facet = facet$hash(),
-    coord = coordinates$hash(),
-    theme = digest::digest(defaults(x$theme, theme_get()))
-  ))
-}
-
-digest.proto <- function(x, ...) x$hash(, ...)
-digest.ggplot <- function(x, ...) {
-  if (is.null(x)) return()
-  digest::digest(bolus(x), ...)
-}
-
-TopLevel$settings <- function(.) {
-  mget(setdiff(ls(., all.names=TRUE), c(".that", ".super")), .)
-}
-
-Layer$hash <- TopLevel$hash <- function(., ...) {
-  digest::digest(.$bolus(), ...)
-}
-TopLevel$bolus <- function(.) {
-  list(
-    name = .$objname,
-    settings = .$settings()
-  )
-}
-
-Layer$bolus <- function(.) {
-  params <- c(.$geom_params, .$stat_params)
-  params <- params[!duplicated(params)]
-  if (!is.null(params) && length(params) > 1) params <- params[order(names(params))]
-
-  mapping <- .$mapping
-  if (!is.null(mapping)) mapping <- mapping[order(names(mapping))]
-
-  list(
-    geom = .$geom$objname,
-    stat = .$stat$objname,
-    pos  = .$position$objname,
-    pos_parms  = .$position$settings(),
-    data = .$data,
-    mapping = mapping,
-    params = params,
-    legend = .$legend
-  )
-}
-
diff --git a/R/zxx.r b/R/zxx.r
index a0d92d7..26e4a8d 100644
--- a/R/zxx.r
+++ b/R/zxx.r
@@ -2,62 +2,77 @@
 
 #' @export
 #' @rdname scale_hue
+#' @usage NULL
 scale_colour_discrete <- scale_colour_hue
 
 #' @export
 #' @rdname scale_gradient
+#' @usage NULL
 scale_colour_continuous <- scale_colour_gradient
 
 #' @export
 #' @rdname scale_hue
+#' @usage NULL
 scale_fill_discrete <- scale_fill_hue
 
 #' @export
 #' @rdname scale_gradient
+#' @usage NULL
 scale_fill_continuous <- scale_fill_gradient
 
 # British to American spellings ----------------------------------------------
 
 #' @export
 #' @rdname scale_brewer
+#' @usage NULL
 scale_color_brewer <- scale_colour_brewer
 
 #' @export
 #' @rdname scale_brewer
+#' @usage NULL
 scale_color_distiller <- scale_colour_distiller
 
 #' @export
 #' @rdname scale_gradient
+#' @usage NULL
 scale_color_continuous <- scale_colour_gradient
 
 #' @export
 #' @rdname scale_hue
+#' @usage NULL
 scale_color_discrete <- scale_colour_hue
 
 #' @export
 #' @rdname scale_gradient
+#' @usage NULL
 scale_color_gradient <- scale_colour_gradient
 
 #' @export
-#' @rdname scale_gradient2
+#' @rdname scale_gradient
+#' @usage NULL
 scale_color_gradient2 <- scale_colour_gradient2
 
 #' @export
-#' @rdname scale_gradientn
+#' @rdname scale_gradient
+#' @usage NULL
 scale_color_gradientn <- scale_colour_gradientn
 
 #' @export
 #' @rdname scale_grey
+#' @usage NULL
 scale_color_grey <- scale_colour_grey
 
 #' @export
 #' @rdname scale_hue
+#' @usage NULL
 scale_color_hue <- scale_colour_hue
 
 #' @export
 #' @rdname scale_identity
+#' @usage NULL
 scale_color_identity <- scale_colour_identity
 
 #' @export
 #' @rdname scale_manual
+#' @usage NULL
 scale_color_manual <- scale_colour_manual
diff --git a/R/zzz.r b/R/zzz.r
index 5829976..5c50a87 100644
--- a/R/zzz.r
+++ b/R/zzz.r
@@ -3,12 +3,13 @@
 
   tips <- c(
     "Need help? Try the ggplot2 mailing list: http://groups.google.com/group/ggplot2.",
-    paste("Find out what's changed in ggplot2 with\n",
-      "news(Version == \"", utils::packageVersion("ggplot2"),
-      "\", package = \"ggplot2\")", sep = ""),
-    "Use suppressPackageStartupMessages to eliminate package startup messages."
+    "Find out what's changed in ggplot2 at http://github.com/hadley/ggplot2/releases.",
+    "Use suppressPackageStartupMessages() to eliminate package startup messages.",
+    "Stackoverflow is a great place to get help: http://stackoverflow.com/tags/ggplot2.",
+    "Need help getting started? Try the cookbook for R: http://www.cookbook-r.com/Graphs/",
+    "Want to understand how all the pieces fit together? Buy the ggplot2 book: http://ggplot2.org/book/"
   )
 
   tip <- sample(tips, 1)
-  packageStartupMessage(tip)
+  packageStartupMessage(paste(strwrap(tip), collapse = "\n"))
 }
diff --git a/README.md b/README.md
index ecfb2a3..a078edf 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,26 @@
 # ggplot2
 
 [![Build Status](https://travis-ci.org/hadley/ggplot2.png?branch=master)](https://travis-ci.org/hadley/ggplot2)
+[![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/ggplot2)](http://cran.r-project.org/package=ggplot2)
 
-ggplot2 is a plotting system for R, based on the grammar of graphics,
-which tries to take the good parts of base and lattice graphics and
-avoid bad parts. It takes care of many of the fiddly details
-that make plotting a hassle (like drawing legends) as well as
-providing a powerful model of graphics that makes it easy to produce
-complex multi-layered graphics.
+ggplot2 is a plotting system for R, based on the grammar of graphics, which tries to take the good parts of base and lattice graphics and avoid bad parts. It takes care of many of the fiddly details
+that make plotting a hassle (like drawing legends) as well as providing a powerful model of graphics that makes it easy to produce complex multi-layered graphics.
 
-To install:
+Find out more at <http://ggplot2.org>, and check out the nearly 500
+examples of ggplot in use.  If you're interested, you can also sign up to
+the [ggplot2 mailing list at](http://groups.google.com/group/ggplot2).
 
-* the latest released version: `install.packages("ggplot2")`
-* the latest development version: `install_github("hadley/ggplot2")`
+## Installation
 
-Find out more at http://ggplot2.org, and check out the nearly 500
-examples of ggplot in use.  If you're interested, you can also sign up to
-the ggplot2 mailing list at http://groups.google.com/group/ggplot2, or track
-development at http://github.com/hadley/ggplot2
+Get the released version from CRAN:
+
+```R
+install.packages("ggplot2")
+```
+
+Or the development version from github:
+
+```R
+# install.packages("devtools")
+devtools::install_github("hadley/ggplot2")
+```
diff --git a/build/partial.rdb b/build/partial.rdb
index 5c4289d..5121f70 100644
Binary files a/build/partial.rdb and b/build/partial.rdb differ
diff --git a/build/vignette.rds b/build/vignette.rds
index e6681f9..e14aa7d 100644
Binary files a/build/vignette.rds and b/build/vignette.rds differ
diff --git a/data/datalist b/data/datalist
deleted file mode 100644
index 165f9f1..0000000
--- a/data/datalist
+++ /dev/null
@@ -1,8 +0,0 @@
-diamonds
-economics
-midwest
-movies
-mpg
-msleep
-presidential
-seals
diff --git a/data/diamonds.rda b/data/diamonds.rda
index 6a2d09f..d8eb670 100644
Binary files a/data/diamonds.rda and b/data/diamonds.rda differ
diff --git a/data/economics.rda b/data/economics.rda
index 6f65a3e..083543a 100644
Binary files a/data/economics.rda and b/data/economics.rda differ
diff --git a/data/economics_long.rda b/data/economics_long.rda
new file mode 100644
index 0000000..c9756ec
Binary files /dev/null and b/data/economics_long.rda differ
diff --git a/data/faithfuld.rda b/data/faithfuld.rda
new file mode 100644
index 0000000..c40e341
Binary files /dev/null and b/data/faithfuld.rda differ
diff --git a/data/luv_colours.rda b/data/luv_colours.rda
new file mode 100644
index 0000000..cc58b44
Binary files /dev/null and b/data/luv_colours.rda differ
diff --git a/data/midwest.rda b/data/midwest.rda
index 078fc3b..190fb5e 100644
Binary files a/data/midwest.rda and b/data/midwest.rda differ
diff --git a/data/movies.rda b/data/movies.rda
deleted file mode 100644
index b7362df..0000000
Binary files a/data/movies.rda and /dev/null differ
diff --git a/data/mpg.rda b/data/mpg.rda
index 761d168..e894314 100644
Binary files a/data/mpg.rda and b/data/mpg.rda differ
diff --git a/data/msleep.rda b/data/msleep.rda
index 66994fb..1811675 100644
Binary files a/data/msleep.rda and b/data/msleep.rda differ
diff --git a/data/presidential.rda b/data/presidential.rda
index 1fb52da..6da994a 100644
Binary files a/data/presidential.rda and b/data/presidential.rda differ
diff --git a/data/seals.rda b/data/seals.rda
index 3d17729..4a54b67 100644
Binary files a/data/seals.rda and b/data/seals.rda differ
diff --git a/data/txhousing.rda b/data/txhousing.rda
new file mode 100644
index 0000000..5d2dde8
Binary files /dev/null and b/data/txhousing.rda differ
diff --git a/inst/CITATION b/inst/CITATION
index 583a56c..a70c8ab 100644
--- a/inst/CITATION
+++ b/inst/CITATION
@@ -2,10 +2,10 @@ citHeader("To cite ggplot2 in publications, please use:")
 
 citEntry(entry = "book",
   author = "Hadley Wickham",
-  title = "ggplot2: elegant graphics for data analysis",
-  publisher = "Springer New York",
+  title = "ggplot2: Elegant Graphics for Data Analysis",
+  publisher = "Springer-Verlag New York",
   year = "2009",
   isbn = "978-0-387-98140-6",
   url = "http://had.co.nz/ggplot2/book",
-  textVersion = "H. Wickham. ggplot2: elegant graphics for data analysis. Springer New York, 2009."
+  textVersion = "H. Wickham. ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York, 2009."
 )
\ No newline at end of file
diff --git a/inst/doc/development.R b/inst/doc/development.R
deleted file mode 100644
index 81329ee..0000000
--- a/inst/doc/development.R
+++ /dev/null
@@ -1,14 +0,0 @@
-## ----, echo = FALSE, message = FALSE-------------------------------------
-knitr::opts_chunk$set(
-  comment = "#>",
-  error = FALSE,
-  tidy = FALSE
-)
-
-## ----, eval = FALSE------------------------------------------------------
-#  install.packages(c("devtools", "testthat"))
-#  devtools::install_github("klutometis/roxygen")
-
-## ----, eval = FALSE------------------------------------------------------
-#  install_deps(dep = T)
-
diff --git a/inst/doc/development.Rmd b/inst/doc/development.Rmd
deleted file mode 100644
index 32ab363..0000000
--- a/inst/doc/development.Rmd
+++ /dev/null
@@ -1,263 +0,0 @@
-<!--
-%\VignetteEngine{knitr::knitr}
-%\VignetteIndexEntry{Contributing to ggplot2 development}
--->
-
-```{r, echo = FALSE, message = FALSE}
-knitr::opts_chunk$set(
-  comment = "#>",
-  error = FALSE,
-  tidy = FALSE
-)
-```
-
-# Contributing to ggplot2 development
-
-The goal of this guide is to help you get up and contributing to ggplot2 as quickly as possible. It's still a work in progress and very rough. Your feedback is much appreciated and so are pull requests :).  Rather than emailing me directly about questions, please discuss ggplot2 development issues on the [ggplot2-dev](https://groups.google.com/forum/#!forum/ggplot2-dev) mailing list. That way multiple people can learn at the same time.
-
-To contribute a change to ggplot2, you follow these steps:
-
-1. Set up a local ggplot2 development environment.
-1. Create a branch in git and make your changes.
-1. Push branch to github and issue pull request (PR).
-1. Discuss the pull request.
-1. Iterate until either we accept the PR or decide that it's not
-   a good fit for ggplot2.
-
-Each of these steps are described in more detail below. This might feel overwhelming the first time you get set up, but it gets easier with practice. If you get stuck at any point, please reach out for help on the [ggplot2-dev](https://groups.google.com/forum/#!forum/ggplot2-dev) mailing list
-
-## Basic setup
-
-If you want to do development on ggplot2 and share the changes with other people, you'll have to set up an account on GitHub. You'll make a fork of Hadley's repository and store it on GitHub. You'll also make a copy of your repository on your local machine.
-
-1.  [Join github](https://github.com/join).
-
-1.  [Set up git and github](https://help.github.com/articles/set-up-git).
-
-1.  Fork of the main repo by going to https://github.com/hadley/ggplot2/fork.
-    A fork is a copy of ggplot2 that you can work on independently.
-    See [fork a repo](https://help.github.com/articles/fork-a-repo) for
-    more details.
-
-1.  Clone your fork to your local computer (change `myname` to your account
-    name):
-
-    ```
-    git clone git at github.com:myname/ggplot2.git
-    cd ggplot2
-    ```
-
-1.  Once you've done that, add the main repository as a remote and set up
-    the master branch to track the main ggplot2 repo. This will make it
-    easier to keep up to date.
-
-    ```
-    git remote add hadley git://github.com/hadley/ggplot2.git
-    git branch --set-upstream master hadley/master
-    ```
-
-Now on your local machine you have the local repository and two remote repositories: `origin` (the default), which is your personal ggplot2 repo at GitHub, and `hadley` which is Hadley's. You'll be able to push changes to your own repository only.
-
-### Development environment
-
-You'll also need a copy of the packages I use for package development. Get them by running the following R code:
-
-```{r, eval = FALSE}
-install.packages(c("devtools", "testthat"))
-devtools::install_github("klutometis/roxygen")
-```
-
-Next, install all the suggested packages that ggplot2 needs. To do this either open the ggplot2 rstudio project, or set your working directory to the ggplot2 directory, then run:
-
-```{r, eval = FALSE}
-install_deps(dep = T)
-```
-
-The key functions you'll use when working on ggplot2:
-
-* `devtools::load_all()`: loads all code into your current environment
-* `devtools::document()`: updates the roxygen comments
-* `devtools::test()`: run all unit tests
-* `devtools::check()`: runs R CMD check on the package to check for errors.
-
-If you're using Rstudio, I highly recommend learning the keyboard shortcuts for these commands. You can find them in the `Build` menu.
-
-## Making changes
-
-When you want to make changes, you should work on a new branch. Otherwise things can get a bit confusing when it comes time to merge it into the main repo with a pull request. You probably want to start with the `master` branch.
-
-```
-# Fetch the latest version of hadley/ggplot2
-git fetch hadley
-git checkout hadley/master
-```
-
-At this point it'll give you a warning about being in "detached HEAD" state. Don't worry about it. Just start a new branch with the current state as the starting point:
-
-```
-git checkout -b myfix
-```
-
-To check what branch you're currently on, run `git branch`.
-
-Now you can make your changes and commit them to this branch on your local repository. If you decide you want to start over, you can just check out `hadley/master` again, make a new branch, and begin anew.
-
-When you feel like sharing your changes, push them to your GitHub repo:
-
-```
-git push
-```
-
-Then you can submit a pull request if you want it to be integrated in the main branch.
-
-If you've been working on your for a while, it's possible that it won't merge properly because something has changed in both the main repo and in your branch. You can test it out by checking out the main branch and merging yourself.
-
-First, make a new branch called `testmerge`, based off the main branch:
-
-```
-git fetch hadley
-git checkout hadley/master
-
-git checkout -b testmerge
-```
-
-Then try merging your branch into testmerge:
-
-```
-git merge myfix
-```
-
-If there are no errors, great. You can switch back to your `myfix` branch and delete `testmerge`:
-
-```
-git checkout myfix
-git branch -D testmerge
-```
-
-If there are any merge conflicts, you may want to rebase your changes on top of the current master version, or just resolve the conflicts and commit it to your branch. Rebasing may make for a somewhat cleaner commit history, but there is a possibility of messing things up. If you want to be safe, you can just make a new branch and rebase that on top of the current master.
-
-## What makes a good pull request?
-
-<!--
-* [ ] Motivate the change in one paragraph, and include it in NEWS.
-      In parentheses, reference your github user name and this issue:
-      `(@hadley, #1234)`
-* [ ] Check pull request only includes relevant changes.
-* [ ] Use the [official style](http://adv-r.had.co.nz/Style.html).
-* [ ] Update documentation and re-run roxygen2
-* [ ] Add test, if bug in non-graphical function
-* [ ] Add visual test, if bug in graphical function
-* [ ] Add minimal example, if new graphical feature
-
-See http://docs.ggplot2.org/dev/vignettes/development.html for more details.
---->
-
-Pull requests will be evaluated against the a seven point checklist:
-
-1.  __Motivation__. Your pull request must clearly and concisely motivates the
-   need for change. Unfortunately neither Winston nor I have much time to
-   work on ggplot2 these days, so you need to describe the problem and show
-   how your pull request solves it as concisely as possible.
-
-   Also include this motivation in `NEWS` so that when a new release of
-   ggplot2 comes out it's easy for users to see what's changed. Add your
-   item at the top of the file and use markdown for formatting. The
-   news item should end with `(@yourGithubUsername, #the_issue_number)`.
-
-1.  __Only related changes__. Before you submit your pull request, please
-    check to make sure that you haven't accidentally included any unrelated
-    changes. These make it harder to see exactly what's changed, and to
-    evaluate any unexpected side effects.
-
-    Each PR corresponds to a git branch, so if you expect to submit
-    multiple changes make sure to create multiple branches. If you have
-    multiple changes that depend on each other, start with the first one
-    and don't submit any others until the first one has been processed.
-
-1.  __Use ggplot2 coding style__. Please follow the
-    [official ggplot2 style](http://adv-r.had.co.nz/Style.html). Maintaing
-    a consistent style across the whole code base makes it much easier to
-    jump into the code.
-
-1.  If you're adding new parameters or a new function, you'll also need
-    to document them with [roxygen](https://github.com/klutometis/roxygen).
-    Make sure to re-run `devtools::document()` on the code before submitting.
-
-    Currently, ggplot2 uses the development version of roxygen2, which you
-    can get with `install_github("klutometis/roxygen")`. This will be
-    available on CRAN in the near future.
-
-1.  If fixing a bug or adding a new feature to a non-graphical function,
-    please add a [testthat](https://github.com/hadley/testthat) unit test.
-
-1.  If fixing a bug in the visual output, please add a visual test.
-    (Instructions to follow soon)
-
-1.  If you're adding a new graphical feature, please add a short example
-    to the appropriate function.
-
-This seems like a lot of work but don't worry if your pull request isn't perfect. It's a learning process and Winston and I will be on hand to help you out. A pull request is a process, and unless you've submitted a few in the past it's unlikely that your pull request will be accepted as is.
-
-Finally, remember that ggplot2 is a mature package used by thousands of people. This means that it's extremely difficult (i.e. impossible) to change any existing functionality without breaking someone's code (or another package on CRAN). Please don't submit pull requests that change existing behaviour. Instead, think about how you can add a new feature in a minimally invasive way.
-
-## Advanced techniques
-
-### Fetching a branch from someone else's repository
-
-Sometimes you will want to fetch a branch from someone's repository, but without going to the trouble of seting it up as a remote. This is handy if you just want to quickly try out a someone's work.
-
-This will fetch a branch from someone's remote repository and check it out (replace `username` and `somebranch`):
-
-```
-git fetch https://github.com/username/ggplot2.git somebranch
-git checkout FETCH_HEAD
-```
-
-Just doing the above won't create a local branch -- you'll be in "detached HEAD" state. If you'd like to create a local branch to work on, run (you can replace `somebranch` with whatever name you like):
-
-```
-git checkout -b somebranch
-```
-
-### Adding other repositories as remotes
-
-If you often work off of someone else's repository, it can be useful to add their repo as a *remote*. This makes it easier to fetch changes in their repository. If the person's GitHub account is `otherdevel`, you would do the following:
-
-```
-git remote add otherdevel git://github.com/otherdevel/ggplot2.git
-git fetch otherdevel
-
-git checkout otherdevel/somebranch
-```
-
-If you don't want to follow them any more, run:
-
-```
-git remote rm otherdevel
-```
-
-### Delete a branch from GitHub
-
-If you pushed a branch to your GitHub repo but it's no longer needed there, you can remove it with:
-
-```
-git push origin :mybranch
-```
-
-### Visualizing the development tree
-
-GitHub has a very nice [development tree view](https://github.com/hadley/ggplot2/), but it of course only shows commits that have been pushed to GitHub. You may also want to view the tree on your local machine, to see how your local changes relate to the main tree. There are a number of programs out there that will do this.
-
-Mac:
-
-* gitk: Pretty basic, included with git. Run `gitk -a` to view all branches (by default it just shows you the current branch).
-
-* [gitx](http://gitx.laullon.com/): This is a bit nicer than gitk.
-
-* [SourceTree](http://www.sourcetreeapp.com/): This is also a nice program. Normally it costs money, but it is temporarily free from the web page or the [Mac App store](http://itunes.apple.com/us/app/sourcetree/id411678673?mt=12&ls=1).
-
-Linux:
-
-* gitk: (See gitk in Mac section)
-
-* gitg: This is nicer than gitk. By default it only shows the current branch; select "Local Branches" or "All Branches" to view others.
diff --git a/inst/doc/development.html b/inst/doc/development.html
deleted file mode 100644
index 04d70d4..0000000
--- a/inst/doc/development.html
+++ /dev/null
@@ -1,446 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
-
-<title>Contributing to ggplot2 development</title>
-
-<script type="text/javascript">
-window.onload = function() {
-  var imgs = document.getElementsByTagName('img'), i, img;
-  for (i = 0; i < imgs.length; i++) {
-    img = imgs[i];
-    // center an image if it is the only element of its parent
-    if (img.parentElement.childElementCount === 1)
-      img.parentElement.style.textAlign = 'center';
-  }
-};
-</script>
-
-<!-- Styles for R syntax highlighter -->
-<style type="text/css">
-   pre .operator,
-   pre .paren {
-     color: rgb(104, 118, 135)
-   }
-
-   pre .literal {
-     color: #990073
-   }
-
-   pre .number {
-     color: #099;
-   }
-
-   pre .comment {
-     color: #998;
-     font-style: italic
-   }
-
-   pre .keyword {
-     color: #900;
-     font-weight: bold
-   }
-
-   pre .identifier {
-     color: rgb(0, 0, 0);
-   }
-
-   pre .string {
-     color: #d14;
-   }
-</style>
-
-<!-- R syntax highlighter -->
-<script type="text/javascript">
-var hljs=new function(){function m(p){return p.replace(/&/gm,"&").replace(/</gm,"<")}function f(r,q,p){return RegExp(q,"m"+(r.cI?"i":"")+(p?"g":""))}function b(r){for(var p=0;p<r.childNodes.length;p++){var q=r.childNodes[p];if(q.nodeName=="CODE"){return q}if(!(q.nodeType==3&&q.nodeValue.match(/\s+/))){break}}}function h(t,s){var p="";for(var r=0;r<t.childNodes.length;r++){if(t.childNodes[r].nodeType==3){var q=t.childNodes[r].nodeValue;if(s){q=q.replace(/\n/g,"")}p+=q}else{if(t.chi [...]
-hljs.initHighlightingOnLoad();
-</script>
-
-
-
-<style type="text/css">
-body, td {
-   font-family: sans-serif;
-   background-color: white;
-   font-size: 13px;
-}
-
-body {
-  max-width: 800px;
-  margin: auto;
-  padding: 1em;
-  line-height: 20px;
-}
-
-tt, code, pre {
-   font-family: 'DejaVu Sans Mono', 'Droid Sans Mono', 'Lucida Console', Consolas, Monaco, monospace;
-}
-
-h1 {
-   font-size:2.2em;
-}
-
-h2 {
-   font-size:1.8em;
-}
-
-h3 {
-   font-size:1.4em;
-}
-
-h4 {
-   font-size:1.0em;
-}
-
-h5 {
-   font-size:0.9em;
-}
-
-h6 {
-   font-size:0.8em;
-}
-
-a:visited {
-   color: rgb(50%, 0%, 50%);
-}
-
-pre, img {
-  max-width: 100%;
-}
-pre {
-  overflow-x: auto;
-}
-pre code {
-   display: block; padding: 0.5em;
-}
-
-code {
-  font-size: 92%;
-  border: 1px solid #ccc;
-}
-
-code[class] {
-  background-color: #F8F8F8;
-}
-
-table, td, th {
-  border: none;
-}
-
-blockquote {
-   color:#666666;
-   margin:0;
-   padding-left: 1em;
-   border-left: 0.5em #EEE solid;
-}
-
-hr {
-   height: 0px;
-   border-bottom: none;
-   border-top-width: thin;
-   border-top-style: dotted;
-   border-top-color: #999999;
-}
-
- at media print {
-   * {
-      background: transparent !important;
-      color: black !important;
-      filter:none !important;
-      -ms-filter: none !important;
-   }
-
-   body {
-      font-size:12pt;
-      max-width:100%;
-   }
-
-   a, a:visited {
-      text-decoration: underline;
-   }
-
-   hr {
-      visibility: hidden;
-      page-break-before: always;
-   }
-
-   pre, blockquote {
-      padding-right: 1em;
-      page-break-inside: avoid;
-   }
-
-   tr, img {
-      page-break-inside: avoid;
-   }
-
-   img {
-      max-width: 100% !important;
-   }
-
-   @page :left {
-      margin: 15mm 20mm 15mm 10mm;
-   }
-
-   @page :right {
-      margin: 15mm 10mm 15mm 20mm;
-   }
-
-   p, h2, h3 {
-      orphans: 3; widows: 3;
-   }
-
-   h2, h3 {
-      page-break-after: avoid;
-   }
-}
-</style>
-
-
-
-</head>
-
-<body>
-<!--
-%\VignetteEngine{knitr::knitr}
-%\VignetteIndexEntry{Contributing to ggplot2 development}
--->
-
-<h1>Contributing to ggplot2 development</h1>
-
-<p>The goal of this guide is to help you get up and contributing to ggplot2 as quickly as possible. It's still a work in progress and very rough. Your feedback is much appreciated and so are pull requests :).  Rather than emailing me directly about questions, please discuss ggplot2 development issues on the <a href="https://groups.google.com/forum/#!forum/ggplot2-dev">ggplot2-dev</a> mailing list. That way multiple people can learn at the same time.</p>
-
-<p>To contribute a change to ggplot2, you follow these steps:</p>
-
-<ol>
-<li>Set up a local ggplot2 development environment.</li>
-<li>Create a branch in git and make your changes.</li>
-<li>Push branch to github and issue pull request (PR).</li>
-<li>Discuss the pull request.</li>
-<li>Iterate until either we accept the PR or decide that it's not
-a good fit for ggplot2.</li>
-</ol>
-
-<p>Each of these steps are described in more detail below. This might feel overwhelming the first time you get set up, but it gets easier with practice. If you get stuck at any point, please reach out for help on the <a href="https://groups.google.com/forum/#!forum/ggplot2-dev">ggplot2-dev</a> mailing list</p>
-
-<h2>Basic setup</h2>
-
-<p>If you want to do development on ggplot2 and share the changes with other people, you'll have to set up an account on GitHub. You'll make a fork of Hadley's repository and store it on GitHub. You'll also make a copy of your repository on your local machine.</p>
-
-<ol>
-<li><p><a href="https://github.com/join">Join github</a>.</p></li>
-<li><p><a href="https://help.github.com/articles/set-up-git">Set up git and github</a>.</p></li>
-<li><p>Fork of the main repo by going to <a href="https://github.com/hadley/ggplot2/fork">https://github.com/hadley/ggplot2/fork</a>.
-A fork is a copy of ggplot2 that you can work on independently.
-See <a href="https://help.github.com/articles/fork-a-repo">fork a repo</a> for
-more details.</p></li>
-<li><p>Clone your fork to your local computer (change <code>myname</code> to your account
-name):</p>
-
-<pre><code>git clone git at github.com:myname/ggplot2.git
-cd ggplot2
-</code></pre></li>
-<li><p>Once you've done that, add the main repository as a remote and set up
-the master branch to track the main ggplot2 repo. This will make it
-easier to keep up to date.</p>
-
-<pre><code>git remote add hadley git://github.com/hadley/ggplot2.git
-git branch --set-upstream master hadley/master
-</code></pre></li>
-</ol>
-
-<p>Now on your local machine you have the local repository and two remote repositories: <code>origin</code> (the default), which is your personal ggplot2 repo at GitHub, and <code>hadley</code> which is Hadley's. You'll be able to push changes to your own repository only.</p>
-
-<h3>Development environment</h3>
-
-<p>You'll also need a copy of the packages I use for package development. Get them by running the following R code:</p>
-
-<pre><code class="r">install.packages(c("devtools", "testthat"))
-devtools::install_github("klutometis/roxygen")
-</code></pre>
-
-<p>Next, install all the suggested packages that ggplot2 needs. To do this either open the ggplot2 rstudio project, or set your working directory to the ggplot2 directory, then run:</p>
-
-<pre><code class="r">install_deps(dep = T)
-</code></pre>
-
-<p>The key functions you'll use when working on ggplot2:</p>
-
-<ul>
-<li><code>devtools::load_all()</code>: loads all code into your current environment</li>
-<li><code>devtools::document()</code>: updates the roxygen comments</li>
-<li><code>devtools::test()</code>: run all unit tests</li>
-<li><code>devtools::check()</code>: runs R CMD check on the package to check for errors.</li>
-</ul>
-
-<p>If you're using Rstudio, I highly recommend learning the keyboard shortcuts for these commands. You can find them in the <code>Build</code> menu.</p>
-
-<h2>Making changes</h2>
-
-<p>When you want to make changes, you should work on a new branch. Otherwise things can get a bit confusing when it comes time to merge it into the main repo with a pull request. You probably want to start with the <code>master</code> branch.</p>
-
-<pre><code># Fetch the latest version of hadley/ggplot2
-git fetch hadley
-git checkout hadley/master
-</code></pre>
-
-<p>At this point it'll give you a warning about being in “detached HEAD” state. Don't worry about it. Just start a new branch with the current state as the starting point:</p>
-
-<pre><code>git checkout -b myfix
-</code></pre>
-
-<p>To check what branch you're currently on, run <code>git branch</code>.</p>
-
-<p>Now you can make your changes and commit them to this branch on your local repository. If you decide you want to start over, you can just check out <code>hadley/master</code> again, make a new branch, and begin anew.</p>
-
-<p>When you feel like sharing your changes, push them to your GitHub repo:</p>
-
-<pre><code>git push
-</code></pre>
-
-<p>Then you can submit a pull request if you want it to be integrated in the main branch.</p>
-
-<p>If you've been working on your for a while, it's possible that it won't merge properly because something has changed in both the main repo and in your branch. You can test it out by checking out the main branch and merging yourself.</p>
-
-<p>First, make a new branch called <code>testmerge</code>, based off the main branch:</p>
-
-<pre><code>git fetch hadley
-git checkout hadley/master
-
-git checkout -b testmerge
-</code></pre>
-
-<p>Then try merging your branch into testmerge:</p>
-
-<pre><code>git merge myfix
-</code></pre>
-
-<p>If there are no errors, great. You can switch back to your <code>myfix</code> branch and delete <code>testmerge</code>:</p>
-
-<pre><code>git checkout myfix
-git branch -D testmerge
-</code></pre>
-
-<p>If there are any merge conflicts, you may want to rebase your changes on top of the current master version, or just resolve the conflicts and commit it to your branch. Rebasing may make for a somewhat cleaner commit history, but there is a possibility of messing things up. If you want to be safe, you can just make a new branch and rebase that on top of the current master.</p>
-
-<h2>What makes a good pull request?</h2>
-
-<!--
-* [ ] Motivate the change in one paragraph, and include it in NEWS.
-      In parentheses, reference your github user name and this issue:
-      `(@hadley, #1234)`
-* [ ] Check pull request only includes relevant changes.
-* [ ] Use the [official style](http://adv-r.had.co.nz/Style.html).
-* [ ] Update documentation and re-run roxygen2
-* [ ] Add test, if bug in non-graphical function
-* [ ] Add visual test, if bug in graphical function
-* [ ] Add minimal example, if new graphical feature
-
-See http://docs.ggplot2.org/dev/vignettes/development.html for more details.
---->
-
-<p>Pull requests will be evaluated against the a seven point checklist:</p>
-
-<ol>
-<li><p><strong>Motivation</strong>. Your pull request must clearly and concisely motivates the
-need for change. Unfortunately neither Winston nor I have much time to
-work on ggplot2 these days, so you need to describe the problem and show
-how your pull request solves it as concisely as possible.</p>
-
-<p>Also include this motivation in <code>NEWS</code> so that when a new release of
-ggplot2 comes out it's easy for users to see what's changed. Add your
-item at the top of the file and use markdown for formatting. The
-news item should end with <code>(@yourGithubUsername, #the_issue_number)</code>.</p></li>
-<li><p><strong>Only related changes</strong>. Before you submit your pull request, please
-check to make sure that you haven't accidentally included any unrelated
-changes. These make it harder to see exactly what's changed, and to
-evaluate any unexpected side effects.</p>
-
-<p>Each PR corresponds to a git branch, so if you expect to submit
-multiple changes make sure to create multiple branches. If you have
-multiple changes that depend on each other, start with the first one
-and don't submit any others until the first one has been processed.</p></li>
-<li><p><strong>Use ggplot2 coding style</strong>. Please follow the
-<a href="http://adv-r.had.co.nz/Style.html">official ggplot2 style</a>. Maintaing
-a consistent style across the whole code base makes it much easier to
-jump into the code.</p></li>
-<li><p>If you're adding new parameters or a new function, you'll also need
-to document them with <a href="https://github.com/klutometis/roxygen">roxygen</a>.
-Make sure to re-run <code>devtools::document()</code> on the code before submitting.</p>
-
-<p>Currently, ggplot2 uses the development version of roxygen2, which you
-can get with <code>install_github("klutometis/roxygen")</code>. This will be
-available on CRAN in the near future.</p></li>
-<li><p>If fixing a bug or adding a new feature to a non-graphical function,
-please add a <a href="https://github.com/hadley/testthat">testthat</a> unit test.</p></li>
-<li><p>If fixing a bug in the visual output, please add a visual test.
-(Instructions to follow soon)</p></li>
-<li><p>If you're adding a new graphical feature, please add a short example
-to the appropriate function.</p></li>
-</ol>
-
-<p>This seems like a lot of work but don't worry if your pull request isn't perfect. It's a learning process and Winston and I will be on hand to help you out. A pull request is a process, and unless you've submitted a few in the past it's unlikely that your pull request will be accepted as is.</p>
-
-<p>Finally, remember that ggplot2 is a mature package used by thousands of people. This means that it's extremely difficult (i.e. impossible) to change any existing functionality without breaking someone's code (or another package on CRAN). Please don't submit pull requests that change existing behaviour. Instead, think about how you can add a new feature in a minimally invasive way.</p>
-
-<h2>Advanced techniques</h2>
-
-<h3>Fetching a branch from someone else's repository</h3>
-
-<p>Sometimes you will want to fetch a branch from someone's repository, but without going to the trouble of seting it up as a remote. This is handy if you just want to quickly try out a someone's work.</p>
-
-<p>This will fetch a branch from someone's remote repository and check it out (replace <code>username</code> and <code>somebranch</code>):</p>
-
-<pre><code>git fetch https://github.com/username/ggplot2.git somebranch
-git checkout FETCH_HEAD
-</code></pre>
-
-<p>Just doing the above won't create a local branch – you'll be in “detached HEAD” state. If you'd like to create a local branch to work on, run (you can replace <code>somebranch</code> with whatever name you like):</p>
-
-<pre><code>git checkout -b somebranch
-</code></pre>
-
-<h3>Adding other repositories as remotes</h3>
-
-<p>If you often work off of someone else's repository, it can be useful to add their repo as a <em>remote</em>. This makes it easier to fetch changes in their repository. If the person's GitHub account is <code>otherdevel</code>, you would do the following:</p>
-
-<pre><code>git remote add otherdevel git://github.com/otherdevel/ggplot2.git
-git fetch otherdevel
-
-git checkout otherdevel/somebranch
-</code></pre>
-
-<p>If you don't want to follow them any more, run:</p>
-
-<pre><code>git remote rm otherdevel
-</code></pre>
-
-<h3>Delete a branch from GitHub</h3>
-
-<p>If you pushed a branch to your GitHub repo but it's no longer needed there, you can remove it with:</p>
-
-<pre><code>git push origin :mybranch
-</code></pre>
-
-<h3>Visualizing the development tree</h3>
-
-<p>GitHub has a very nice <a href="https://github.com/hadley/ggplot2/">development tree view</a>, but it of course only shows commits that have been pushed to GitHub. You may also want to view the tree on your local machine, to see how your local changes relate to the main tree. There are a number of programs out there that will do this.</p>
-
-<p>Mac:</p>
-
-<ul>
-<li><p>gitk: Pretty basic, included with git. Run <code>gitk -a</code> to view all branches (by default it just shows you the current branch).</p></li>
-<li><p><a href="http://gitx.laullon.com/">gitx</a>: This is a bit nicer than gitk.</p></li>
-<li><p><a href="http://www.sourcetreeapp.com/">SourceTree</a>: This is also a nice program. Normally it costs money, but it is temporarily free from the web page or the <a href="http://itunes.apple.com/us/app/sourcetree/id411678673?mt=12&ls=1">Mac App store</a>.</p></li>
-</ul>
-
-<p>Linux:</p>
-
-<ul>
-<li><p>gitk: (See gitk in Mac section)</p></li>
-<li><p>gitg: This is nicer than gitk. By default it only shows the current branch; select “Local Branches” or “All Branches” to view others.</p></li>
-</ul>
-
-</body>
-
-</html>
diff --git a/inst/doc/extending-ggplot2.R b/inst/doc/extending-ggplot2.R
new file mode 100644
index 0000000..af347e6
--- /dev/null
+++ b/inst/doc/extending-ggplot2.R
@@ -0,0 +1,328 @@
+## ---- include = FALSE----------------------------------------------------
+knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
+library(ggplot2)
+
+## ----ggproto-intro-------------------------------------------------------
+A <- ggproto("A", NULL,
+  x = 1,
+  inc = function(self) {
+    self$x <- self$x + 1
+  }
+)
+A$x
+A$inc()
+A$x
+A$inc()
+A$inc()
+A$x
+
+## ----chull---------------------------------------------------------------
+StatChull <- ggproto("StatChull", Stat,
+  compute_group = function(data, scales) {
+    data[chull(data$x, data$y), , drop = FALSE]
+  },
+  
+  required_aes = c("x", "y")
+)
+
+## ------------------------------------------------------------------------
+stat_chull <- function(mapping = NULL, data = NULL, geom = "polygon",
+                       position = "identity", na.rm = FALSE, show.legend = NA, 
+                       inherit.aes = TRUE, ...) {
+  layer(
+    stat = StatChull, data = data, mapping = mapping, geom = geom, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(na.rm = na.rm, ...)
+  )
+}
+
+## ------------------------------------------------------------------------
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_point() + 
+  stat_chull(fill = NA, colour = "black")
+
+## ------------------------------------------------------------------------
+ggplot(mpg, aes(displ, hwy, colour = drv)) + 
+  geom_point() + 
+  stat_chull(fill = NA)
+
+## ------------------------------------------------------------------------
+ggplot(mpg, aes(displ, hwy)) + 
+  stat_chull(geom = "point", size = 4, colour = "red") +
+  geom_point()
+
+## ------------------------------------------------------------------------
+StatLm <- ggproto("StatLm", Stat, 
+  required_aes = c("x", "y"),
+  
+  compute_group = function(data, scales) {
+    rng <- range(data$x, na.rm = TRUE)
+    grid <- data.frame(x = rng)
+    
+    mod <- lm(y ~ x, data = data)
+    grid$y <- predict(mod, newdata = grid)
+    
+    grid
+  }
+)
+
+stat_lm <- function(mapping = NULL, data = NULL, geom = "line",
+                    position = "identity", na.rm = FALSE, show.legend = NA, 
+                    inherit.aes = TRUE, ...) {
+  layer(
+    stat = StatLm, data = data, mapping = mapping, geom = geom, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_point() + 
+  stat_lm()
+
+## ------------------------------------------------------------------------
+StatLm <- ggproto("StatLm", Stat, 
+  required_aes = c("x", "y"),
+  
+  compute_group = function(data, scales, params, n = 100, formula = y ~ x) {
+    rng <- range(data$x, na.rm = TRUE)
+    grid <- data.frame(x = seq(rng[1], rng[2], length = n))
+    
+    mod <- lm(formula, data = data)
+    grid$y <- predict(mod, newdata = grid)
+    
+    grid
+  }
+)
+
+stat_lm <- function(mapping = NULL, data = NULL, geom = "line",
+                    position = "identity", na.rm = FALSE, show.legend = NA, 
+                    inherit.aes = TRUE, n = 50, formula = y ~ x, 
+                    ...) {
+  layer(
+    stat = StatLm, data = data, mapping = mapping, geom = geom, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(n = n, formula = formula, na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_point() + 
+  stat_lm(formula = y ~ poly(x, 10)) + 
+  stat_lm(formula = y ~ poly(x, 10), geom = "point", colour = "red", n = 20)
+
+## ------------------------------------------------------------------------
+#' @inheritParams ggplot2::stat_identity
+#' @param formula The modelling formula passed to \code{lm}. Should only 
+#'   involve \code{y} and \code{x}
+#' @param n Number of points used for interpolation.
+stat_lm <- function(mapping = NULL, data = NULL, geom = "line",
+                    position = "identity", na.rm = FALSE, show.legend = NA, 
+                    inherit.aes = TRUE, n = 50, formula = y ~ x, 
+                    ...) {
+  layer(
+    stat = StatLm, data = data, mapping = mapping, geom = geom, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(n = n, formula = formula, na.rm = na.rm, ...)
+  )
+}
+
+
+## ------------------------------------------------------------------------
+StatDensityCommon <- ggproto("StatDensityCommon", Stat, 
+  required_aes = "x",
+  
+  setup_params = function(data, params) {
+    if (!is.null(params$bandwidth))
+      return(params)
+    
+    xs <- split(data$x, data$group)
+    bws <- vapply(xs, bw.nrd0, numeric(1))
+    bw <- mean(bws)
+    message("Picking bandwidth of ", signif(bw, 3))
+    
+    params$bandwidth <- bw
+    params
+  },
+  
+  compute_group = function(data, scales, bandwidth = 1) {
+    d <- density(data$x, bw = bandwidth)
+    data.frame(x = d$x, y = d$y)
+  }  
+)
+
+stat_density_common <- function(mapping = NULL, data = NULL, geom = "line",
+                                position = "identity", na.rm = FALSE, show.legend = NA, 
+                                inherit.aes = TRUE, bandwidth = NULL,
+                                ...) {
+  layer(
+    stat = StatDensityCommon, data = data, mapping = mapping, geom = geom, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(bandwidth = bandwidth, na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, colour = drv)) + 
+  stat_density_common()
+
+ggplot(mpg, aes(displ, colour = drv)) + 
+  stat_density_common(bandwidth = 0.5)
+
+## ------------------------------------------------------------------------
+StatDensityCommon <- ggproto("StatDensity2", Stat, 
+  required_aes = "x",
+  default_aes = aes(y = ..density..),
+
+  compute_group = function(data, scales, bandwidth = 1) {
+    d <- density(data$x, bw = bandwidth)
+    data.frame(x = d$x, density = d$y)
+  }  
+)
+
+ggplot(mpg, aes(displ, drv, colour = ..density..)) + 
+  stat_density_common(bandwidth = 1, geom = "point")
+
+## ------------------------------------------------------------------------
+ggplot(mpg, aes(displ, fill = drv)) + 
+  stat_density_common(bandwidth = 1, geom = "area", position = "stack")
+
+## ------------------------------------------------------------------------
+StatDensityCommon <- ggproto("StatDensityCommon", Stat, 
+  required_aes = "x",
+  default_aes = aes(y = ..density..),
+
+  setup_params = function(data, params) {
+    min <- min(data$x) - 3 * params$bandwidth
+    max <- max(data$x) + 3 * params$bandwidth
+    
+    list(
+      bandwidth = params$bandwidth,
+      min = min,
+      max = max,
+      na.rm = params$na.rm
+    )
+  },
+  
+  compute_group = function(data, scales, min, max, bandwidth = 1) {
+    d <- density(data$x, bw = bandwidth, from = min, to = max)
+    data.frame(x = d$x, density = d$y)
+  }  
+)
+
+ggplot(mpg, aes(displ, fill = drv)) + 
+  stat_density_common(bandwidth = 1, geom = "area", position = "stack")
+ggplot(mpg, aes(displ, drv, fill = ..density..)) + 
+  stat_density_common(bandwidth = 1, geom = "raster")
+
+## ----GeomSimplePoint-----------------------------------------------------
+GeomSimplePoint <- ggproto("GeomSimplePoint", Geom,
+  required_aes = c("x", "y"),
+  default_aes = aes(shape = 19, colour = "black"),
+  draw_key = draw_key_point,
+
+  draw_panel = function(data, panel_scales, coord) {
+    coords <- coord$transform(data, panel_scales)
+    grid::pointsGrob(
+      coords$x, coords$y,
+      pch = coords$shape,
+      gp = grid::gpar(col = coords$colour)
+    )
+  }
+)
+
+geom_simple_point <- function(mapping = NULL, data = NULL, stat = "identity",
+                              position = "identity", na.rm = FALSE, show.legend = NA, 
+                              inherit.aes = TRUE, ...) {
+  layer(
+    geom = GeomSimplePoint, mapping = mapping,  data = data, stat = stat, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_simple_point()
+
+## ------------------------------------------------------------------------
+GeomSimplePolygon <- ggproto("GeomPolygon", Geom,
+  required_aes = c("x", "y"),
+  
+  default_aes = aes(
+    colour = NA, fill = "grey20", size = 0.5,
+    linetype = 1, alpha = 1
+  ),
+
+  draw_key = draw_key_polygon,
+
+  draw_group = function(data, panel_scales, coord) {
+    n <- nrow(data)
+    if (n <= 2) return(grid::nullGrob())
+
+    coords <- coord$transform(data, panel_scales)
+    # A polygon can only have a single colour, fill, etc, so take from first row
+    first_row <- coords[1, , drop = FALSE]
+
+    grid::polygonGrob(
+      coords$x, coords$y, 
+      default.units = "native",
+      gp = grid::gpar(
+        col = first_row$colour,
+        fill = scales::alpha(first_row$fill, first_row$alpha),
+        lwd = first_row$size * .pt,
+        lty = first_row$linetype
+      )
+    )
+  }
+)
+geom_simple_polygon <- function(mapping = NULL, data = NULL, stat = "chull",
+                                position = "identity", na.rm = FALSE, show.legend = NA, 
+                                inherit.aes = TRUE, ...) {
+  layer(
+    geom = GeomSimplePolygon, mapping = mapping, data = data, stat = stat, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_point() + 
+  geom_simple_polygon(aes(colour = class), fill = NA)
+
+## ------------------------------------------------------------------------
+GeomPolygonHollow <- ggproto("GeomPolygonHollow", GeomPolygon,
+  default_aes = aes(colour = "black", fill = NA, size = 0.5, linetype = 1,
+    alpha = NA)
+  )
+geom_chull <- function(mapping = NULL, data = NULL, 
+                       position = "identity", na.rm = FALSE, show.legend = NA, 
+                       inherit.aes = TRUE, ...) {
+  layer(
+    stat = StatChull, geom = GeomPolygonHollow, data = data, mapping = mapping,
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_point() + 
+  geom_chull()
+
+## ------------------------------------------------------------------------
+theme_grey()$legend.key
+
+new_theme <- theme_grey() + theme(legend.key = element_rect(colour = "red"))
+new_theme$legend.key
+
+## ------------------------------------------------------------------------
+new_theme <- theme_grey() %+replace% theme(legend.key = element_rect(colour = "red"))
+new_theme$legend.key
+
+## ----axis-line-ex--------------------------------------------------------
+df <- data.frame(x = 1:3, y = 1:3)
+base <- ggplot(df, aes(x, y)) + 
+  geom_point() + 
+  theme_minimal()
+
+base
+base + theme(text = element_text(colour = "red"))
+
diff --git a/inst/doc/extending-ggplot2.Rmd b/inst/doc/extending-ggplot2.Rmd
new file mode 100644
index 0000000..5040814
--- /dev/null
+++ b/inst/doc/extending-ggplot2.Rmd
@@ -0,0 +1,547 @@
+---
+title: "Extending ggplot2"
+author: "Hadley Wickham"
+date: "`r Sys.Date()`"
+output: rmarkdown::html_vignette
+vignette: >
+  %\VignetteIndexEntry{Extending ggplot2}
+  %\VignetteEngine{knitr::rmarkdown}
+  %\VignetteEncoding{UTF-8}
+---
+
+```{r, include = FALSE}
+knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
+library(ggplot2)
+```
+
+This vignette documents the official extension mechanism provided in ggplot2 1.1.0. This vignette is a high-level adjunct to the low-level details found in `?Stat`, `?Geom` and `?theme`. You'll learn how to extend ggplot2 by creating a new stat, geom, or theme.
+
+As you read this document, you'll see many things that will make you scratch your head and wonder why on earth is it designed this way? Mostly it's historical accident - I wasn't a terribly good R programmer when I started writing ggplot2 and I made a lot of questionable decisions. We cleaned up as many of those issues as possible in the 1.1.0 release, but some fixes simply weren't worth the effort.
+
+## ggproto
+
+All ggplot2 objects are built using the ggproto system of object oriented programming. This OO system is used only in one place: ggplot2. This is mostly historical accident: ggplot2 started off using [proto]( https://cran.r-project.org/package=proto) because I needed mutable objects. This was well before the creation of (the briefly lived) [mutatr](http://vita.had.co.nz/papers/mutatr.html), reference classes and R6: proto was the only game in town.
+
+But why ggproto? Well when we turned to add an official extension mechanism to ggplot2, we found a major problem that caused problems when proto objects were extended in a different package (methods were evaluated in ggplot2, not the package where the extension was added). We tried converting to R6, but it was a poor fit for the needs of ggplot2. We could've modified proto, but that would've first involved understand exactly how proto worked, and secondly making sure that the changes did [...]
+
+It's strange to say, but this is a case where inventing a new OO system was actually the right answer to the problem! Fortunately Winston is now very good at creating OO systems, so it only took him a day to come up with ggproto: it maintains all the features of proto that ggplot2 needs, while allowing cross package inheritance to work.
+
+Here's a quick demo of ggproto in action:
+
+```{r ggproto-intro}
+A <- ggproto("A", NULL,
+  x = 1,
+  inc = function(self) {
+    self$x <- self$x + 1
+  }
+)
+A$x
+A$inc()
+A$x
+A$inc()
+A$inc()
+A$x
+```
+
+The majority of ggplot2 classes are immutable and static: the methods neither use nor modify state in the class. They're mostly used as a convenient way of bundling related methods together.
+
+To create a new geom or stat, you will just create a new ggproto that inherits from `Stat`, `Geom` and override the methods described below.
+
+## Creating a new stat
+
+### The simplest stat
+
+We'll start by creating a very simple stat: one that gives the complex hull (the _c_ hull) of a set of points. First we create a new ggproto object that inherits from `Stat`:
+
+```{r chull}
+StatChull <- ggproto("StatChull", Stat,
+  compute_group = function(data, scales) {
+    data[chull(data$x, data$y), , drop = FALSE]
+  },
+  
+  required_aes = c("x", "y")
+)
+```
+
+The two most important components are the `compute_group()` method (which does the computation), and the `required_aes` field, which lists which aesthetics must be present in order to for the stat to work.
+
+Next we write a layer function. Unfortunately, due to an early design mistake I called these either `stat_()` or `geom_()`. A better decision would have been to call them `layer_()` functions: that's a more accurate description because every layer involves a stat _and_ a geom. 
+
+All layer functions follow the same form - you specify defaults in the function arguments and then call the `layer()` function, sending `...` into the `params` argument. The arguments in `...` will either be arguments for the geom (if you're making a stat wrapper), arguments for the stat (if you're making a geom wrapper), or aesthetics to be set. `layer()` takes care of teasing the different parameters apart and making sure they're stored in the right place:
+
+```{r}
+stat_chull <- function(mapping = NULL, data = NULL, geom = "polygon",
+                       position = "identity", na.rm = FALSE, show.legend = NA, 
+                       inherit.aes = TRUE, ...) {
+  layer(
+    stat = StatChull, data = data, mapping = mapping, geom = geom, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(na.rm = na.rm, ...)
+  )
+}
+```
+
+(Note that if you're writing this in your own package, you'll either need to call `ggplot2::layer()` explicitly, or import the `layer()` function into your package namespace.)
+
+Once we have a layer function we can try our new stat:
+
+```{r}
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_point() + 
+  stat_chull(fill = NA, colour = "black")
+```
+
+(We'll see later how to change the defaults of the geom so that you don't need to specify `fill = NA` every time.)
+
+Once we've written this basic object, ggplot2 gives a lot for free. For example, ggplot2 automatically preserves aesthetics that are constant within each group:
+
+```{r}
+ggplot(mpg, aes(displ, hwy, colour = drv)) + 
+  geom_point() + 
+  stat_chull(fill = NA)
+```
+
+We can also override the default geom to display the convex hull in a different way:
+
+```{r}
+ggplot(mpg, aes(displ, hwy)) + 
+  stat_chull(geom = "point", size = 4, colour = "red") +
+  geom_point()
+```
+
+### Stat parameters
+
+A more complex stat will do some computation. Let's implement a simple version of `geom_smooth()` that adds a line of best fit to a plot. We create a `StatLm` that inherits from `Stat` and a layer function, `stat_lm()`:
+
+```{r}
+StatLm <- ggproto("StatLm", Stat, 
+  required_aes = c("x", "y"),
+  
+  compute_group = function(data, scales) {
+    rng <- range(data$x, na.rm = TRUE)
+    grid <- data.frame(x = rng)
+    
+    mod <- lm(y ~ x, data = data)
+    grid$y <- predict(mod, newdata = grid)
+    
+    grid
+  }
+)
+
+stat_lm <- function(mapping = NULL, data = NULL, geom = "line",
+                    position = "identity", na.rm = FALSE, show.legend = NA, 
+                    inherit.aes = TRUE, ...) {
+  layer(
+    stat = StatLm, data = data, mapping = mapping, geom = geom, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_point() + 
+  stat_lm()
+```
+
+`StatLm` is inflexible because it has no parameters. We might want to allow the user to control the model formula and the number of points used to generate the grid. To do so, we add arguments to the `compute_group()` method and our wrapper function:
+
+```{r}
+StatLm <- ggproto("StatLm", Stat, 
+  required_aes = c("x", "y"),
+  
+  compute_group = function(data, scales, params, n = 100, formula = y ~ x) {
+    rng <- range(data$x, na.rm = TRUE)
+    grid <- data.frame(x = seq(rng[1], rng[2], length = n))
+    
+    mod <- lm(formula, data = data)
+    grid$y <- predict(mod, newdata = grid)
+    
+    grid
+  }
+)
+
+stat_lm <- function(mapping = NULL, data = NULL, geom = "line",
+                    position = "identity", na.rm = FALSE, show.legend = NA, 
+                    inherit.aes = TRUE, n = 50, formula = y ~ x, 
+                    ...) {
+  layer(
+    stat = StatLm, data = data, mapping = mapping, geom = geom, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(n = n, formula = formula, na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_point() + 
+  stat_lm(formula = y ~ poly(x, 10)) + 
+  stat_lm(formula = y ~ poly(x, 10), geom = "point", colour = "red", n = 20)
+```
+
+Note that don't _have_ to explicitly include the new parameters in the arguments for the layer, `...` will get passed to the right place anyway. But you'll need to document them somewhere so the user knows about them. Here's a brief example. Note `@inheritParams ggplot2::stat_identity`: that will automatically inherit documentation for all the parameters also defined for `stat_identity()`.
+
+```{r}
+#' @inheritParams ggplot2::stat_identity
+#' @param formula The modelling formula passed to \code{lm}. Should only 
+#'   involve \code{y} and \code{x}
+#' @param n Number of points used for interpolation.
+stat_lm <- function(mapping = NULL, data = NULL, geom = "line",
+                    position = "identity", na.rm = FALSE, show.legend = NA, 
+                    inherit.aes = TRUE, n = 50, formula = y ~ x, 
+                    ...) {
+  layer(
+    stat = StatLm, data = data, mapping = mapping, geom = geom, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(n = n, formula = formula, na.rm = na.rm, ...)
+  )
+}
+
+```
+
+### Picking defaults
+
+Sometimes you have calculations that should performed once for the complete dataset, not once for each group. This is useful for picking sensible default values. For example, if we want to do a density estimate, it's reasonable to pick one bandwidth for the whole plot. The following Stat creates a variation of the `stat_density()` that picks one bandwidth for all groups by choosing the mean of the "best" bandwidth for each group (I have no theoretical justification for this, but it doesn [...]
+
+To do this we override the `setup_params()` method. It's passed the data and a list of params, and returns an updated list.
+
+```{r}
+StatDensityCommon <- ggproto("StatDensityCommon", Stat, 
+  required_aes = "x",
+  
+  setup_params = function(data, params) {
+    if (!is.null(params$bandwidth))
+      return(params)
+    
+    xs <- split(data$x, data$group)
+    bws <- vapply(xs, bw.nrd0, numeric(1))
+    bw <- mean(bws)
+    message("Picking bandwidth of ", signif(bw, 3))
+    
+    params$bandwidth <- bw
+    params
+  },
+  
+  compute_group = function(data, scales, bandwidth = 1) {
+    d <- density(data$x, bw = bandwidth)
+    data.frame(x = d$x, y = d$y)
+  }  
+)
+
+stat_density_common <- function(mapping = NULL, data = NULL, geom = "line",
+                                position = "identity", na.rm = FALSE, show.legend = NA, 
+                                inherit.aes = TRUE, bandwidth = NULL,
+                                ...) {
+  layer(
+    stat = StatDensityCommon, data = data, mapping = mapping, geom = geom, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(bandwidth = bandwidth, na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, colour = drv)) + 
+  stat_density_common()
+
+ggplot(mpg, aes(displ, colour = drv)) + 
+  stat_density_common(bandwidth = 0.5)
+```
+
+I recommend using `NULL` as a default value. If you pick important parameters automatically, it's a good idea to `message()` to the user (and when printing a floating point parameter, using `signif()` to show only a few significant digits).
+
+### Variable names and default aesthetics
+
+This stat illustrates another important point. If we want to make this stat usable with other geoms, we should return a variable called `density` instead of `y`. Then we can set up the `default_aes` to automatically map `density` to `y`, which allows the user to override it to use with different geoms:
+
+```{r}
+StatDensityCommon <- ggproto("StatDensity2", Stat, 
+  required_aes = "x",
+  default_aes = aes(y = ..density..),
+
+  compute_group = function(data, scales, bandwidth = 1) {
+    d <- density(data$x, bw = bandwidth)
+    data.frame(x = d$x, density = d$y)
+  }  
+)
+
+ggplot(mpg, aes(displ, drv, colour = ..density..)) + 
+  stat_density_common(bandwidth = 1, geom = "point")
+```
+
+However, using this stat with the area geom doesn't work quite right. The areas don't stack on top of each other:
+
+```{r}
+ggplot(mpg, aes(displ, fill = drv)) + 
+  stat_density_common(bandwidth = 1, geom = "area", position = "stack")
+```
+
+This is because each density is computed independently, and the estimated `x`s don't line up. We can resolve that issue by computing the range of the data once in `setup_params()`.
+
+```{r}
+StatDensityCommon <- ggproto("StatDensityCommon", Stat, 
+  required_aes = "x",
+  default_aes = aes(y = ..density..),
+
+  setup_params = function(data, params) {
+    min <- min(data$x) - 3 * params$bandwidth
+    max <- max(data$x) + 3 * params$bandwidth
+    
+    list(
+      bandwidth = params$bandwidth,
+      min = min,
+      max = max,
+      na.rm = params$na.rm
+    )
+  },
+  
+  compute_group = function(data, scales, min, max, bandwidth = 1) {
+    d <- density(data$x, bw = bandwidth, from = min, to = max)
+    data.frame(x = d$x, density = d$y)
+  }  
+)
+
+ggplot(mpg, aes(displ, fill = drv)) + 
+  stat_density_common(bandwidth = 1, geom = "area", position = "stack")
+ggplot(mpg, aes(displ, drv, fill = ..density..)) + 
+  stat_density_common(bandwidth = 1, geom = "raster")
+```
+
+### Exercises
+
+1.  Extend `stat_chull` to compute the alpha hull, as from the
+    [alphahull](https://cran.r-project.org/package=alphahull) package. Your
+    new stat should take an `alpha` argument.
+
+1.  Modify the final version of `StatDensityCommon` to allow the user to 
+    specify the `min` and `max` parameters. You'll need to modify both the
+    layer function and the `compute_group()` method.
+
+1.  Compare and contrast `StatLm` to `ggplot2::StatSmooth`. What key
+    differences make `StatSmooth` more complex than `StatLm`?
+
+## Creating a new geom
+
+It's harder to create a new geom than a new stat because you also need to know some grid. ggplot2 is built on top of grid, so you'll need to know the basics of drawing with grid. If you're serious about adding a new geom, I'd recommend buying [R graphics](http://amzn.com/B00I60M26G) by Paul Murrell. It tells you everything you need to know about drawing with grid.
+
+### A simple geom
+
+It's easiest to start with a simple example. The code below is a simplified version of `geom_point()`:
+
+```{r GeomSimplePoint}
+GeomSimplePoint <- ggproto("GeomSimplePoint", Geom,
+  required_aes = c("x", "y"),
+  default_aes = aes(shape = 19, colour = "black"),
+  draw_key = draw_key_point,
+
+  draw_panel = function(data, panel_scales, coord) {
+    coords <- coord$transform(data, panel_scales)
+    grid::pointsGrob(
+      coords$x, coords$y,
+      pch = coords$shape,
+      gp = grid::gpar(col = coords$colour)
+    )
+  }
+)
+
+geom_simple_point <- function(mapping = NULL, data = NULL, stat = "identity",
+                              position = "identity", na.rm = FALSE, show.legend = NA, 
+                              inherit.aes = TRUE, ...) {
+  layer(
+    geom = GeomSimplePoint, mapping = mapping,  data = data, stat = stat, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_simple_point()
+```
+
+This is very similar to defining a new stat. You always need to provide fields/methods for the four pieces shown above:
+
+* `required_aes` is a character vector which lists all the aesthetics that
+  the user must provide.
+  
+* `default_aes` lists the aesthetics that have default values.
+
+* `draw_key` provides the function used to draw the key in the legend. 
+  You can see a list of all the build in key functions in `?draw_key`
+  
+* `draw_group()` is where the magic happens. This function takes three
+  arguments and returns a grid grob. It is called once for each panel.
+  It's the most complicated part and is described in more detail below.
+  
+`draw_group()` has three arguments:
+
+* `data`: a data frame with one column for each aesthetic.
+
+* `panel_scales`: a list containing information about the x and y scales
+  for the current panel.
+
+* `coord`: an object describing the coordinate system.
+
+Generally you won't use `panel_scales` and `coord` directly, but you will always use them to transform the data: `coords <- coord$transform(data, panel_scales)`. This creates a data frame where position variables are scaled to the range 0--1. You then take this data and call a grid grob function. (Transforming for non-Cartesian coordinate systems is quite complex - you're best of transforming your data to the form accepted by an existing ggplot2 geom and passing it.)
+
+### Collective geoms
+
+Overriding `draw_panel()` is most appropriate if there is one graphic element per row. In other cases, you want graphic element per group. For example, take polygons: each row gives one vertex of a polygon. In this case, you should instead override `draw_group()`:
+
+The following code makes a simplified version of `GeomPolygon`:
+
+```{r}
+GeomSimplePolygon <- ggproto("GeomPolygon", Geom,
+  required_aes = c("x", "y"),
+  
+  default_aes = aes(
+    colour = NA, fill = "grey20", size = 0.5,
+    linetype = 1, alpha = 1
+  ),
+
+  draw_key = draw_key_polygon,
+
+  draw_group = function(data, panel_scales, coord) {
+    n <- nrow(data)
+    if (n <= 2) return(grid::nullGrob())
+
+    coords <- coord$transform(data, panel_scales)
+    # A polygon can only have a single colour, fill, etc, so take from first row
+    first_row <- coords[1, , drop = FALSE]
+
+    grid::polygonGrob(
+      coords$x, coords$y, 
+      default.units = "native",
+      gp = grid::gpar(
+        col = first_row$colour,
+        fill = scales::alpha(first_row$fill, first_row$alpha),
+        lwd = first_row$size * .pt,
+        lty = first_row$linetype
+      )
+    )
+  }
+)
+geom_simple_polygon <- function(mapping = NULL, data = NULL, stat = "chull",
+                                position = "identity", na.rm = FALSE, show.legend = NA, 
+                                inherit.aes = TRUE, ...) {
+  layer(
+    geom = GeomSimplePolygon, mapping = mapping, data = data, stat = stat, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_point() + 
+  geom_simple_polygon(aes(colour = class), fill = NA)
+```
+
+There are a few things to note here:
+
+* We override `draw_group()` instead of `draw_layer()` because we want
+  one polygon per group, not one polygon per row. If you look at the source
+  code for the original `GeomPolygon` you'll see it actually overrides
+  `geom_layer()` because it uses some tricks to make `polygonGrob()` produce
+  multiple polygons in one call. This is considerably more complicated, but 
+  gives better performance.
+  
+* If the data contains two or fewer points, there's no point trying to draw
+  a polygon, so we return a `nullGrob()`. This is the graphical equivalent
+  of `NULL`: it's a grob that doesn't draw anything and doesn't take up
+  any space.
+  
+* Note the units: `x` and `y` should always be drawn in "native" units. 
+  (The default units for `pointGrob()` is a native, so we didn't need to 
+  change it there). `lwd` is measured in points, but ggplot2 uses mm, 
+  so we need to multiply it by the adjustment factor `.pt`.
+
+### Inheriting from an existing Geom
+
+Sometimes you just want to make a small modification to an existing geom. In this case, rather than inheriting from `Geom` you can inherit from an existing subclass. For example, we might want to change the defaults for `GeomPolygon` to work better with `StatChull`:
+
+```{r}
+GeomPolygonHollow <- ggproto("GeomPolygonHollow", GeomPolygon,
+  default_aes = aes(colour = "black", fill = NA, size = 0.5, linetype = 1,
+    alpha = NA)
+  )
+geom_chull <- function(mapping = NULL, data = NULL, 
+                       position = "identity", na.rm = FALSE, show.legend = NA, 
+                       inherit.aes = TRUE, ...) {
+  layer(
+    stat = StatChull, geom = GeomPolygonHollow, data = data, mapping = mapping,
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_point() + 
+  geom_chull()
+```
+
+This doesn't allow you to use different geoms with the stat, but that seems appropriate here since the convex hull is primarily a polygonal feature.
+
+### Exercises
+
+1. Compare and contrast `GeomPoint` with `GeomSimplePoint`.
+
+1. Compare and contract `GeomPolygon` with `GeomSimplePolygon`.
+
+## Creating your own theme
+
+If you're going to create your own complete theme, there are a few things you need to know:
+
+* Overriding existing elements, rather than modifying them
+* The four global elements that affect (almost) every other theme element
+* Complete vs. incomplete elements
+
+### Overriding elements
+
+By default, when you add a new theme element, it inherits values from the existing theme. For example, the following code sets the key colour to red, but it inherits the existing fill colour:
+
+```{r}
+theme_grey()$legend.key
+
+new_theme <- theme_grey() + theme(legend.key = element_rect(colour = "red"))
+new_theme$legend.key
+```
+
+To override it completely, use `%+replace%` instead of `+`:
+
+```{r}
+new_theme <- theme_grey() %+replace% theme(legend.key = element_rect(colour = "red"))
+new_theme$legend.key
+```
+
+### Global elements
+
+There are four elements that affect the global appearance of the plot:
+
+Element      | Theme function    | Description
+-------------|-------------------|------------------------
+line         | `element_line()`  | all line elements
+rect         | `element_rect()`  | all rectangular elements
+text         | `element_text()`  | all text
+title        | `element_text()`  | all text in title elements (plot, axes & legend)
+
+These set default properties that are inherited by more specific settings. These are most useful for setting an overall "background" colour and overall font settings (e.g. family and size).
+
+```{r axis-line-ex}
+df <- data.frame(x = 1:3, y = 1:3)
+base <- ggplot(df, aes(x, y)) + 
+  geom_point() + 
+  theme_minimal()
+
+base
+base + theme(text = element_text(colour = "red"))
+```
+
+You should generally start creating a theme by modifying these values.
+
+### Complete vs incomplete
+
+It is useful to understand the difference between complete and incomplete theme objects. A *complete* theme object is one produced by calling a theme function with the attribute `complete = TRUE`. 
+
+Theme functions `theme_grey()` and `theme_bw()` are examples of complete theme functions. Calls to `theme()` produce *incomplete* theme objects, since they represent (local) modifications to a theme object rather than returning a complete theme object per se. When adding an incomplete theme to a complete one, the result is a complete theme. 
+
+Complete and incomplete themes behave somewhat differently when added to a ggplot object:
+
+* Adding an incomplete theme augments the current theme object, replacing only 
+  those properties of elements defined in the call to `theme()`.
+  
+* Adding a complete theme wipes away the existing theme and applies the new theme.
diff --git a/inst/doc/extending-ggplot2.html b/inst/doc/extending-ggplot2.html
new file mode 100644
index 0000000..4705f0c
--- /dev/null
+++ b/inst/doc/extending-ggplot2.html
@@ -0,0 +1,556 @@
+<!DOCTYPE html>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+
+<meta charset="utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="pandoc" />
+
+<meta name="author" content="Hadley Wickham" />
+
+<meta name="date" content="2015-12-15" />
+
+<title>Extending ggplot2</title>
+
+
+
+<style type="text/css">code{white-space: pre;}</style>
+<style type="text/css">
+table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
+  margin: 0; padding: 0; vertical-align: baseline; border: none; }
+table.sourceCode { width: 100%; line-height: 100%; }
+td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
+td.sourceCode { padding-left: 5px; }
+code > span.kw { color: #007020; font-weight: bold; }
+code > span.dt { color: #902000; }
+code > span.dv { color: #40a070; }
+code > span.bn { color: #40a070; }
+code > span.fl { color: #40a070; }
+code > span.ch { color: #4070a0; }
+code > span.st { color: #4070a0; }
+code > span.co { color: #60a0b0; font-style: italic; }
+code > span.ot { color: #007020; }
+code > span.al { color: #ff0000; font-weight: bold; }
+code > span.fu { color: #06287e; }
+code > span.er { color: #ff0000; font-weight: bold; }
+</style>
+<style type="text/css">
+  pre:not([class]) {
+    background-color: white;
+  }
+</style>
+
+
+<link href="data:text/css,body%20%7B%0A%20%20background%2Dcolor%3A%20%23fff%3B%0A%20%20margin%3A%201em%20auto%3B%0A%20%20max%2Dwidth%3A%20700px%3B%0A%20%20overflow%3A%20visible%3B%0A%20%20padding%2Dleft%3A%202em%3B%0A%20%20padding%2Dright%3A%202em%3B%0A%20%20font%2Dfamily%3A%20%22Open%20Sans%22%2C%20%22Helvetica%20Neue%22%2C%20Helvetica%2C%20Arial%2C%20sans%2Dserif%3B%0A%20%20font%2Dsize%3A%2014px%3B%0A%20%20line%2Dheight%3A%201%2E35%3B%0A%7D%0A%0A%23header%20%7B%0A%20%20text%2Dalign%3A% [...]
+
+</head>
+
+<body>
+
+
+
+<div id="header">
+<h1 class="title">Extending ggplot2</h1>
+<h4 class="author"><em>Hadley Wickham</em></h4>
+<h4 class="date"><em>2015-12-15</em></h4>
+</div>
+
+
+<p>This vignette documents the official extension mechanism provided in ggplot2 1.1.0. This vignette is a high-level adjunct to the low-level details found in <code>?Stat</code>, <code>?Geom</code> and <code>?theme</code>. You’ll learn how to extend ggplot2 by creating a new stat, geom, or theme.</p>
+<p>As you read this document, you’ll see many things that will make you scratch your head and wonder why on earth is it designed this way? Mostly it’s historical accident - I wasn’t a terribly good R programmer when I started writing ggplot2 and I made a lot of questionable decisions. We cleaned up as many of those issues as possible in the 1.1.0 release, but some fixes simply weren’t worth the effort.</p>
+<div id="ggproto" class="section level2">
+<h2>ggproto</h2>
+<p>All ggplot2 objects are built using the ggproto system of object oriented programming. This OO system is used only in one place: ggplot2. This is mostly historical accident: ggplot2 started off using <a href="https://cran.r-project.org/package=proto">proto</a> because I needed mutable objects. This was well before the creation of (the briefly lived) <a href="http://vita.had.co.nz/papers/mutatr.html">mutatr</a>, reference classes and R6: proto was the only game in town.</p>
+<p>But why ggproto? Well when we turned to add an official extension mechanism to ggplot2, we found a major problem that caused problems when proto objects were extended in a different package (methods were evaluated in ggplot2, not the package where the extension was added). We tried converting to R6, but it was a poor fit for the needs of ggplot2. We could’ve modified proto, but that would’ve first involved understand exactly how proto worked, and secondly making sure that the changes  [...]
+<p>It’s strange to say, but this is a case where inventing a new OO system was actually the right answer to the problem! Fortunately Winston is now very good at creating OO systems, so it only took him a day to come up with ggproto: it maintains all the features of proto that ggplot2 needs, while allowing cross package inheritance to work.</p>
+<p>Here’s a quick demo of ggproto in action:</p>
+<pre class="sourceCode r"><code class="sourceCode r">A <-<span class="st"> </span><span class="kw">ggproto</span>(<span class="st">"A"</span>, <span class="ot">NULL</span>,
+  <span class="dt">x =</span> <span class="dv">1</span>,
+  <span class="dt">inc =</span> function(self) {
+    self$x <-<span class="st"> </span>self$x +<span class="st"> </span><span class="dv">1</span>
+  }
+)
+A$x
+<span class="co">#> [1] 1</span>
+A$<span class="kw">inc</span>()
+A$x
+<span class="co">#> [1] 2</span>
+A$<span class="kw">inc</span>()
+A$<span class="kw">inc</span>()
+A$x
+<span class="co">#> [1] 4</span></code></pre>
+<p>The majority of ggplot2 classes are immutable and static: the methods neither use nor modify state in the class. They’re mostly used as a convenient way of bundling related methods together.</p>
+<p>To create a new geom or stat, you will just create a new ggproto that inherits from <code>Stat</code>, <code>Geom</code> and override the methods described below.</p>
+</div>
+<div id="creating-a-new-stat" class="section level2">
+<h2>Creating a new stat</h2>
+<div id="the-simplest-stat" class="section level3">
+<h3>The simplest stat</h3>
+<p>We’ll start by creating a very simple stat: one that gives the complex hull (the <em>c</em> hull) of a set of points. First we create a new ggproto object that inherits from <code>Stat</code>:</p>
+<pre class="sourceCode r"><code class="sourceCode r">StatChull <-<span class="st"> </span><span class="kw">ggproto</span>(<span class="st">"StatChull"</span>, Stat,
+  <span class="dt">compute_group =</span> function(data, scales) {
+    data[<span class="kw">chull</span>(data$x, data$y), , drop =<span class="st"> </span><span class="ot">FALSE</span>]
+  },
+  
+  <span class="dt">required_aes =</span> <span class="kw">c</span>(<span class="st">"x"</span>, <span class="st">"y"</span>)
+)</code></pre>
+<p>The two most important components are the <code>compute_group()</code> method (which does the computation), and the <code>required_aes</code> field, which lists which aesthetics must be present in order to for the stat to work.</p>
+<p>Next we write a layer function. Unfortunately, due to an early design mistake I called these either <code>stat_()</code> or <code>geom_()</code>. A better decision would have been to call them <code>layer_()</code> functions: that’s a more accurate description because every layer involves a stat <em>and</em> a geom.</p>
+<p>All layer functions follow the same form - you specify defaults in the function arguments and then call the <code>layer()</code> function, sending <code>...</code> into the <code>params</code> argument. The arguments in <code>...</code> will either be arguments for the geom (if you’re making a stat wrapper), arguments for the stat (if you’re making a geom wrapper), or aesthetics to be set. <code>layer()</code> takes care of teasing the different parameters apart and making sure they’r [...]
+<pre class="sourceCode r"><code class="sourceCode r">stat_chull <-<span class="st"> </span>function(<span class="dt">mapping =</span> <span class="ot">NULL</span>, <span class="dt">data =</span> <span class="ot">NULL</span>, <span class="dt">geom =</span> <span class="st">"polygon"</span>,
+                       <span class="dt">position =</span> <span class="st">"identity"</span>, <span class="dt">na.rm =</span> <span class="ot">FALSE</span>, <span class="dt">show.legend =</span> <span class="ot">NA</span>, 
+                       <span class="dt">inherit.aes =</span> <span class="ot">TRUE</span>, ...) {
+  <span class="kw">layer</span>(
+    <span class="dt">stat =</span> StatChull, <span class="dt">data =</span> data, <span class="dt">mapping =</span> mapping, <span class="dt">geom =</span> geom, 
+    <span class="dt">position =</span> position, <span class="dt">show.legend =</span> show.legend, <span class="dt">inherit.aes =</span> inherit.aes,
+    <span class="dt">params =</span> <span class="kw">list</span>(<span class="dt">na.rm =</span> na.rm, ...)
+  )
+}</code></pre>
+<p>(Note that if you’re writing this in your own package, you’ll either need to call <code>ggplot2::layer()</code> explicitly, or import the <code>layer()</code> function into your package namespace.)</p>
+<p>Once we have a layer function we can try our new stat:</p>
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">ggplot</span>(mpg, <span class="kw">aes</span>(displ, hwy)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_point</span>() +<span class="st"> </span>
+<span class="st">  </span><span class="kw">stat_chull</span>(<span class="dt">fill =</span> <span class="ot">NA</span>, <span class="dt">colour =</span> <span class="st">"black"</span>)</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<p>(We’ll see later how to change the defaults of the geom so that you don’t need to specify <code>fill = NA</code> every time.)</p>
+<p>Once we’ve written this basic object, ggplot2 gives a lot for free. For example, ggplot2 automatically preserves aesthetics that are constant within each group:</p>
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">ggplot</span>(mpg, <span class="kw">aes</span>(displ, hwy, <span class="dt">colour =</span> drv)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_point</span>() +<span class="st"> </span>
+<span class="st">  </span><span class="kw">stat_chull</span>(<span class="dt">fill =</span> <span class="ot">NA</span>)</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<p>We can also override the default geom to display the convex hull in a different way:</p>
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">ggplot</span>(mpg, <span class="kw">aes</span>(displ, hwy)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">stat_chull</span>(<span class="dt">geom =</span> <span class="st">"point"</span>, <span class="dt">size =</span> <span class="dv">4</span>, <span class="dt">colour =</span> <span class="st">"red"</span>) +
+<span class="st">  </span><span class="kw">geom_point</span>()</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+</div>
+<div id="stat-parameters" class="section level3">
+<h3>Stat parameters</h3>
+<p>A more complex stat will do some computation. Let’s implement a simple version of <code>geom_smooth()</code> that adds a line of best fit to a plot. We create a <code>StatLm</code> that inherits from <code>Stat</code> and a layer function, <code>stat_lm()</code>:</p>
+<pre class="sourceCode r"><code class="sourceCode r">StatLm <-<span class="st"> </span><span class="kw">ggproto</span>(<span class="st">"StatLm"</span>, Stat, 
+  <span class="dt">required_aes =</span> <span class="kw">c</span>(<span class="st">"x"</span>, <span class="st">"y"</span>),
+  
+  <span class="dt">compute_group =</span> function(data, scales) {
+    rng <-<span class="st"> </span><span class="kw">range</span>(data$x, <span class="dt">na.rm =</span> <span class="ot">TRUE</span>)
+    grid <-<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">x =</span> rng)
+    
+    mod <-<span class="st"> </span><span class="kw">lm</span>(y ~<span class="st"> </span>x, <span class="dt">data =</span> data)
+    grid$y <-<span class="st"> </span><span class="kw">predict</span>(mod, <span class="dt">newdata =</span> grid)
+    
+    grid
+  }
+)
+
+stat_lm <-<span class="st"> </span>function(<span class="dt">mapping =</span> <span class="ot">NULL</span>, <span class="dt">data =</span> <span class="ot">NULL</span>, <span class="dt">geom =</span> <span class="st">"line"</span>,
+                    <span class="dt">position =</span> <span class="st">"identity"</span>, <span class="dt">na.rm =</span> <span class="ot">FALSE</span>, <span class="dt">show.legend =</span> <span class="ot">NA</span>, 
+                    <span class="dt">inherit.aes =</span> <span class="ot">TRUE</span>, ...) {
+  <span class="kw">layer</span>(
+    <span class="dt">stat =</span> StatLm, <span class="dt">data =</span> data, <span class="dt">mapping =</span> mapping, <span class="dt">geom =</span> geom, 
+    <span class="dt">position =</span> position, <span class="dt">show.legend =</span> show.legend, <span class="dt">inherit.aes =</span> inherit.aes,
+    <span class="dt">params =</span> <span class="kw">list</span>(<span class="dt">na.rm =</span> na.rm, ...)
+  )
+}
+
+<span class="kw">ggplot</span>(mpg, <span class="kw">aes</span>(displ, hwy)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_point</span>() +<span class="st"> </span>
+<span class="st">  </span><span class="kw">stat_lm</span>()</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<p><code>StatLm</code> is inflexible because it has no parameters. We might want to allow the user to control the model formula and the number of points used to generate the grid. To do so, we add arguments to the <code>compute_group()</code> method and our wrapper function:</p>
+<pre class="sourceCode r"><code class="sourceCode r">StatLm <-<span class="st"> </span><span class="kw">ggproto</span>(<span class="st">"StatLm"</span>, Stat, 
+  <span class="dt">required_aes =</span> <span class="kw">c</span>(<span class="st">"x"</span>, <span class="st">"y"</span>),
+  
+  <span class="dt">compute_group =</span> function(data, scales, params, <span class="dt">n =</span> <span class="dv">100</span>, <span class="dt">formula =</span> y ~<span class="st"> </span>x) {
+    rng <-<span class="st"> </span><span class="kw">range</span>(data$x, <span class="dt">na.rm =</span> <span class="ot">TRUE</span>)
+    grid <-<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">x =</span> <span class="kw">seq</span>(rng[<span class="dv">1</span>], rng[<span class="dv">2</span>], <span class="dt">length =</span> n))
+    
+    mod <-<span class="st"> </span><span class="kw">lm</span>(formula, <span class="dt">data =</span> data)
+    grid$y <-<span class="st"> </span><span class="kw">predict</span>(mod, <span class="dt">newdata =</span> grid)
+    
+    grid
+  }
+)
+
+stat_lm <-<span class="st"> </span>function(<span class="dt">mapping =</span> <span class="ot">NULL</span>, <span class="dt">data =</span> <span class="ot">NULL</span>, <span class="dt">geom =</span> <span class="st">"line"</span>,
+                    <span class="dt">position =</span> <span class="st">"identity"</span>, <span class="dt">na.rm =</span> <span class="ot">FALSE</span>, <span class="dt">show.legend =</span> <span class="ot">NA</span>, 
+                    <span class="dt">inherit.aes =</span> <span class="ot">TRUE</span>, <span class="dt">n =</span> <span class="dv">50</span>, <span class="dt">formula =</span> y ~<span class="st"> </span>x, 
+                    ...) {
+  <span class="kw">layer</span>(
+    <span class="dt">stat =</span> StatLm, <span class="dt">data =</span> data, <span class="dt">mapping =</span> mapping, <span class="dt">geom =</span> geom, 
+    <span class="dt">position =</span> position, <span class="dt">show.legend =</span> show.legend, <span class="dt">inherit.aes =</span> inherit.aes,
+    <span class="dt">params =</span> <span class="kw">list</span>(<span class="dt">n =</span> n, <span class="dt">formula =</span> formula, <span class="dt">na.rm =</span> na.rm, ...)
+  )
+}
+
+<span class="kw">ggplot</span>(mpg, <span class="kw">aes</span>(displ, hwy)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_point</span>() +<span class="st"> </span>
+<span class="st">  </span><span class="kw">stat_lm</span>(<span class="dt">formula =</span> y ~<span class="st"> </span><span class="kw">poly</span>(x, <span class="dv">10</span>)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">stat_lm</span>(<span class="dt">formula =</span> y ~<span class="st"> </span><span class="kw">poly</span>(x, <span class="dv">10</span>), <span class="dt">geom =</span> <span class="st">"point"</span>, <span class="dt">colour =</span> <span class="st">"red"</span>, <span class="dt">n =</span> <span class="dv">20</span>)</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<p>Note that don’t <em>have</em> to explicitly include the new parameters in the arguments for the layer, <code>...</code> will get passed to the right place anyway. But you’ll need to document them somewhere so the user knows about them. Here’s a brief example. Note <code>@inheritParams ggplot2::stat_identity</code>: that will automatically inherit documentation for all the parameters also defined for <code>stat_identity()</code>.</p>
+<pre class="sourceCode r"><code class="sourceCode r"><span class="co">#' @inheritParams ggplot2::stat_identity</span>
+<span class="co">#' @param formula The modelling formula passed to \code{lm}. Should only </span>
+<span class="co">#'   involve \code{y} and \code{x}</span>
+<span class="co">#' @param n Number of points used for interpolation.</span>
+stat_lm <-<span class="st"> </span>function(<span class="dt">mapping =</span> <span class="ot">NULL</span>, <span class="dt">data =</span> <span class="ot">NULL</span>, <span class="dt">geom =</span> <span class="st">"line"</span>,
+                    <span class="dt">position =</span> <span class="st">"identity"</span>, <span class="dt">na.rm =</span> <span class="ot">FALSE</span>, <span class="dt">show.legend =</span> <span class="ot">NA</span>, 
+                    <span class="dt">inherit.aes =</span> <span class="ot">TRUE</span>, <span class="dt">n =</span> <span class="dv">50</span>, <span class="dt">formula =</span> y ~<span class="st"> </span>x, 
+                    ...) {
+  <span class="kw">layer</span>(
+    <span class="dt">stat =</span> StatLm, <span class="dt">data =</span> data, <span class="dt">mapping =</span> mapping, <span class="dt">geom =</span> geom, 
+    <span class="dt">position =</span> position, <span class="dt">show.legend =</span> show.legend, <span class="dt">inherit.aes =</span> inherit.aes,
+    <span class="dt">params =</span> <span class="kw">list</span>(<span class="dt">n =</span> n, <span class="dt">formula =</span> formula, <span class="dt">na.rm =</span> na.rm, ...)
+  )
+}</code></pre>
+</div>
+<div id="picking-defaults" class="section level3">
+<h3>Picking defaults</h3>
+<p>Sometimes you have calculations that should performed once for the complete dataset, not once for each group. This is useful for picking sensible default values. For example, if we want to do a density estimate, it’s reasonable to pick one bandwidth for the whole plot. The following Stat creates a variation of the <code>stat_density()</code> that picks one bandwidth for all groups by choosing the mean of the “best” bandwidth for each group (I have no theoretical justification for this [...]
+<p>To do this we override the <code>setup_params()</code> method. It’s passed the data and a list of params, and returns an updated list.</p>
+<pre class="sourceCode r"><code class="sourceCode r">StatDensityCommon <-<span class="st"> </span><span class="kw">ggproto</span>(<span class="st">"StatDensityCommon"</span>, Stat, 
+  <span class="dt">required_aes =</span> <span class="st">"x"</span>,
+  
+  <span class="dt">setup_params =</span> function(data, params) {
+    if (!<span class="kw">is.null</span>(params$bandwidth))
+      <span class="kw">return</span>(params)
+    
+    xs <-<span class="st"> </span><span class="kw">split</span>(data$x, data$group)
+    bws <-<span class="st"> </span><span class="kw">vapply</span>(xs, bw.nrd0, <span class="kw">numeric</span>(<span class="dv">1</span>))
+    bw <-<span class="st"> </span><span class="kw">mean</span>(bws)
+    <span class="kw">message</span>(<span class="st">"Picking bandwidth of "</span>, <span class="kw">signif</span>(bw, <span class="dv">3</span>))
+    
+    params$bandwidth <-<span class="st"> </span>bw
+    params
+  },
+  
+  <span class="dt">compute_group =</span> function(data, scales, <span class="dt">bandwidth =</span> <span class="dv">1</span>) {
+    d <-<span class="st"> </span><span class="kw">density</span>(data$x, <span class="dt">bw =</span> bandwidth)
+    <span class="kw">data.frame</span>(<span class="dt">x =</span> d$x, <span class="dt">y =</span> d$y)
+  }  
+)
+
+stat_density_common <-<span class="st"> </span>function(<span class="dt">mapping =</span> <span class="ot">NULL</span>, <span class="dt">data =</span> <span class="ot">NULL</span>, <span class="dt">geom =</span> <span class="st">"line"</span>,
+                                <span class="dt">position =</span> <span class="st">"identity"</span>, <span class="dt">na.rm =</span> <span class="ot">FALSE</span>, <span class="dt">show.legend =</span> <span class="ot">NA</span>, 
+                                <span class="dt">inherit.aes =</span> <span class="ot">TRUE</span>, <span class="dt">bandwidth =</span> <span class="ot">NULL</span>,
+                                ...) {
+  <span class="kw">layer</span>(
+    <span class="dt">stat =</span> StatDensityCommon, <span class="dt">data =</span> data, <span class="dt">mapping =</span> mapping, <span class="dt">geom =</span> geom, 
+    <span class="dt">position =</span> position, <span class="dt">show.legend =</span> show.legend, <span class="dt">inherit.aes =</span> inherit.aes,
+    <span class="dt">params =</span> <span class="kw">list</span>(<span class="dt">bandwidth =</span> bandwidth, <span class="dt">na.rm =</span> na.rm, ...)
+  )
+}
+
+<span class="kw">ggplot</span>(mpg, <span class="kw">aes</span>(displ, <span class="dt">colour =</span> drv)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">stat_density_common</span>()
+<span class="co">#> Picking bandwidth of 0.345</span></code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<pre class="sourceCode r"><code class="sourceCode r">
+<span class="kw">ggplot</span>(mpg, <span class="kw">aes</span>(displ, <span class="dt">colour =</span> drv)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">stat_density_common</span>(<span class="dt">bandwidth =</span> <span class="fl">0.5</span>)</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<p>I recommend using <code>NULL</code> as a default value. If you pick important parameters automatically, it’s a good idea to <code>message()</code> to the user (and when printing a floating point parameter, using <code>signif()</code> to show only a few significant digits).</p>
+</div>
+<div id="variable-names-and-default-aesthetics" class="section level3">
+<h3>Variable names and default aesthetics</h3>
+<p>This stat illustrates another important point. If we want to make this stat usable with other geoms, we should return a variable called <code>density</code> instead of <code>y</code>. Then we can set up the <code>default_aes</code> to automatically map <code>density</code> to <code>y</code>, which allows the user to override it to use with different geoms:</p>
+<pre class="sourceCode r"><code class="sourceCode r">StatDensityCommon <-<span class="st"> </span><span class="kw">ggproto</span>(<span class="st">"StatDensity2"</span>, Stat, 
+  <span class="dt">required_aes =</span> <span class="st">"x"</span>,
+  <span class="dt">default_aes =</span> <span class="kw">aes</span>(<span class="dt">y =</span> ..density..),
+
+  <span class="dt">compute_group =</span> function(data, scales, <span class="dt">bandwidth =</span> <span class="dv">1</span>) {
+    d <-<span class="st"> </span><span class="kw">density</span>(data$x, <span class="dt">bw =</span> bandwidth)
+    <span class="kw">data.frame</span>(<span class="dt">x =</span> d$x, <span class="dt">density =</span> d$y)
+  }  
+)
+
+<span class="kw">ggplot</span>(mpg, <span class="kw">aes</span>(displ, drv, <span class="dt">colour =</span> ..density..)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">stat_density_common</span>(<span class="dt">bandwidth =</span> <span class="dv">1</span>, <span class="dt">geom =</span> <span class="st">"point"</span>)</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<p>However, using this stat with the area geom doesn’t work quite right. The areas don’t stack on top of each other:</p>
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">ggplot</span>(mpg, <span class="kw">aes</span>(displ, <span class="dt">fill =</span> drv)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">stat_density_common</span>(<span class="dt">bandwidth =</span> <span class="dv">1</span>, <span class="dt">geom =</span> <span class="st">"area"</span>, <span class="dt">position =</span> <span class="st">"stack"</span>)</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<p>This is because each density is computed independently, and the estimated <code>x</code>s don’t line up. We can resolve that issue by computing the range of the data once in <code>setup_params()</code>.</p>
+<pre class="sourceCode r"><code class="sourceCode r">StatDensityCommon <-<span class="st"> </span><span class="kw">ggproto</span>(<span class="st">"StatDensityCommon"</span>, Stat, 
+  <span class="dt">required_aes =</span> <span class="st">"x"</span>,
+  <span class="dt">default_aes =</span> <span class="kw">aes</span>(<span class="dt">y =</span> ..density..),
+
+  <span class="dt">setup_params =</span> function(data, params) {
+    min <-<span class="st"> </span><span class="kw">min</span>(data$x) -<span class="st"> </span><span class="dv">3</span> *<span class="st"> </span>params$bandwidth
+    max <-<span class="st"> </span><span class="kw">max</span>(data$x) +<span class="st"> </span><span class="dv">3</span> *<span class="st"> </span>params$bandwidth
+    
+    <span class="kw">list</span>(
+      <span class="dt">bandwidth =</span> params$bandwidth,
+      <span class="dt">min =</span> min,
+      <span class="dt">max =</span> max,
+      <span class="dt">na.rm =</span> params$na.rm
+    )
+  },
+  
+  <span class="dt">compute_group =</span> function(data, scales, min, max, <span class="dt">bandwidth =</span> <span class="dv">1</span>) {
+    d <-<span class="st"> </span><span class="kw">density</span>(data$x, <span class="dt">bw =</span> bandwidth, <span class="dt">from =</span> min, <span class="dt">to =</span> max)
+    <span class="kw">data.frame</span>(<span class="dt">x =</span> d$x, <span class="dt">density =</span> d$y)
+  }  
+)
+
+<span class="kw">ggplot</span>(mpg, <span class="kw">aes</span>(displ, <span class="dt">fill =</span> drv)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">stat_density_common</span>(<span class="dt">bandwidth =</span> <span class="dv">1</span>, <span class="dt">geom =</span> <span class="st">"area"</span>, <span class="dt">position =</span> <span class="st">"stack"</span>)</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">ggplot</span>(mpg, <span class="kw">aes</span>(displ, drv, <span class="dt">fill =</span> ..density..)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">stat_density_common</span>(<span class="dt">bandwidth =</span> <span class="dv">1</span>, <span class="dt">geom =</span> <span class="st">"raster"</span>)</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+</div>
+<div id="exercises" class="section level3">
+<h3>Exercises</h3>
+<ol style="list-style-type: decimal">
+<li><p>Extend <code>stat_chull</code> to compute the alpha hull, as from the <a href="https://cran.r-project.org/package=alphahull">alphahull</a> package. Your new stat should take an <code>alpha</code> argument.</p></li>
+<li><p>Modify the final version of <code>StatDensityCommon</code> to allow the user to specify the <code>min</code> and <code>max</code> parameters. You’ll need to modify both the layer function and the <code>compute_group()</code> method.</p></li>
+<li><p>Compare and contrast <code>StatLm</code> to <code>ggplot2::StatSmooth</code>. What key differences make <code>StatSmooth</code> more complex than <code>StatLm</code>?</p></li>
+</ol>
+</div>
+</div>
+<div id="creating-a-new-geom" class="section level2">
+<h2>Creating a new geom</h2>
+<p>It’s harder to create a new geom than a new stat because you also need to know some grid. ggplot2 is built on top of grid, so you’ll need to know the basics of drawing with grid. If you’re serious about adding a new geom, I’d recommend buying <a href="http://amzn.com/B00I60M26G">R graphics</a> by Paul Murrell. It tells you everything you need to know about drawing with grid.</p>
+<div id="a-simple-geom" class="section level3">
+<h3>A simple geom</h3>
+<p>It’s easiest to start with a simple example. The code below is a simplified version of <code>geom_point()</code>:</p>
+<pre class="sourceCode r"><code class="sourceCode r">GeomSimplePoint <-<span class="st"> </span><span class="kw">ggproto</span>(<span class="st">"GeomSimplePoint"</span>, Geom,
+  <span class="dt">required_aes =</span> <span class="kw">c</span>(<span class="st">"x"</span>, <span class="st">"y"</span>),
+  <span class="dt">default_aes =</span> <span class="kw">aes</span>(<span class="dt">shape =</span> <span class="dv">19</span>, <span class="dt">colour =</span> <span class="st">"black"</span>),
+  <span class="dt">draw_key =</span> draw_key_point,
+
+  <span class="dt">draw_panel =</span> function(data, panel_scales, coord) {
+    coords <-<span class="st"> </span>coord$<span class="kw">transform</span>(data, panel_scales)
+    grid::<span class="kw">pointsGrob</span>(
+      coords$x, coords$y,
+      <span class="dt">pch =</span> coords$shape,
+      <span class="dt">gp =</span> grid::<span class="kw">gpar</span>(<span class="dt">col =</span> coords$colour)
+    )
+  }
+)
+
+geom_simple_point <-<span class="st"> </span>function(<span class="dt">mapping =</span> <span class="ot">NULL</span>, <span class="dt">data =</span> <span class="ot">NULL</span>, <span class="dt">stat =</span> <span class="st">"identity"</span>,
+                              <span class="dt">position =</span> <span class="st">"identity"</span>, <span class="dt">na.rm =</span> <span class="ot">FALSE</span>, <span class="dt">show.legend =</span> <span class="ot">NA</span>, 
+                              <span class="dt">inherit.aes =</span> <span class="ot">TRUE</span>, ...) {
+  <span class="kw">layer</span>(
+    <span class="dt">geom =</span> GeomSimplePoint, <span class="dt">mapping =</span> mapping,  <span class="dt">data =</span> data, <span class="dt">stat =</span> stat, 
+    <span class="dt">position =</span> position, <span class="dt">show.legend =</span> show.legend, <span class="dt">inherit.aes =</span> inherit.aes,
+    <span class="dt">params =</span> <span class="kw">list</span>(<span class="dt">na.rm =</span> na.rm, ...)
+  )
+}
+
+<span class="kw">ggplot</span>(mpg, <span class="kw">aes</span>(displ, hwy)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_simple_point</span>()</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<p>This is very similar to defining a new stat. You always need to provide fields/methods for the four pieces shown above:</p>
+<ul>
+<li><p><code>required_aes</code> is a character vector which lists all the aesthetics that the user must provide.</p></li>
+<li><p><code>default_aes</code> lists the aesthetics that have default values.</p></li>
+<li><p><code>draw_key</code> provides the function used to draw the key in the legend. You can see a list of all the build in key functions in <code>?draw_key</code></p></li>
+<li><p><code>draw_group()</code> is where the magic happens. This function takes three arguments and returns a grid grob. It is called once for each panel. It’s the most complicated part and is described in more detail below.</p></li>
+</ul>
+<p><code>draw_group()</code> has three arguments:</p>
+<ul>
+<li><p><code>data</code>: a data frame with one column for each aesthetic.</p></li>
+<li><p><code>panel_scales</code>: a list containing information about the x and y scales for the current panel.</p></li>
+<li><p><code>coord</code>: an object describing the coordinate system.</p></li>
+</ul>
+<p>Generally you won’t use <code>panel_scales</code> and <code>coord</code> directly, but you will always use them to transform the data: <code>coords <- coord$transform(data, panel_scales)</code>. This creates a data frame where position variables are scaled to the range 0–1. You then take this data and call a grid grob function. (Transforming for non-Cartesian coordinate systems is quite complex - you’re best of transforming your data to the form accepted by an existing ggplot2 geom [...]
+</div>
+<div id="collective-geoms" class="section level3">
+<h3>Collective geoms</h3>
+<p>Overriding <code>draw_panel()</code> is most appropriate if there is one graphic element per row. In other cases, you want graphic element per group. For example, take polygons: each row gives one vertex of a polygon. In this case, you should instead override <code>draw_group()</code>:</p>
+<p>The following code makes a simplified version of <code>GeomPolygon</code>:</p>
+<pre class="sourceCode r"><code class="sourceCode r">GeomSimplePolygon <-<span class="st"> </span><span class="kw">ggproto</span>(<span class="st">"GeomPolygon"</span>, Geom,
+  <span class="dt">required_aes =</span> <span class="kw">c</span>(<span class="st">"x"</span>, <span class="st">"y"</span>),
+  
+  <span class="dt">default_aes =</span> <span class="kw">aes</span>(
+    <span class="dt">colour =</span> <span class="ot">NA</span>, <span class="dt">fill =</span> <span class="st">"grey20"</span>, <span class="dt">size =</span> <span class="fl">0.5</span>,
+    <span class="dt">linetype =</span> <span class="dv">1</span>, <span class="dt">alpha =</span> <span class="dv">1</span>
+  ),
+
+  <span class="dt">draw_key =</span> draw_key_polygon,
+
+  <span class="dt">draw_group =</span> function(data, panel_scales, coord) {
+    n <-<span class="st"> </span><span class="kw">nrow</span>(data)
+    if (n <=<span class="st"> </span><span class="dv">2</span>) <span class="kw">return</span>(grid::<span class="kw">nullGrob</span>())
+
+    coords <-<span class="st"> </span>coord$<span class="kw">transform</span>(data, panel_scales)
+    <span class="co"># A polygon can only have a single colour, fill, etc, so take from first row</span>
+    first_row <-<span class="st"> </span>coords[<span class="dv">1</span>, , drop =<span class="st"> </span><span class="ot">FALSE</span>]
+
+    grid::<span class="kw">polygonGrob</span>(
+      coords$x, coords$y, 
+      <span class="dt">default.units =</span> <span class="st">"native"</span>,
+      <span class="dt">gp =</span> grid::<span class="kw">gpar</span>(
+        <span class="dt">col =</span> first_row$colour,
+        <span class="dt">fill =</span> scales::<span class="kw">alpha</span>(first_row$fill, first_row$alpha),
+        <span class="dt">lwd =</span> first_row$size *<span class="st"> </span>.pt,
+        <span class="dt">lty =</span> first_row$linetype
+      )
+    )
+  }
+)
+geom_simple_polygon <-<span class="st"> </span>function(<span class="dt">mapping =</span> <span class="ot">NULL</span>, <span class="dt">data =</span> <span class="ot">NULL</span>, <span class="dt">stat =</span> <span class="st">"chull"</span>,
+                                <span class="dt">position =</span> <span class="st">"identity"</span>, <span class="dt">na.rm =</span> <span class="ot">FALSE</span>, <span class="dt">show.legend =</span> <span class="ot">NA</span>, 
+                                <span class="dt">inherit.aes =</span> <span class="ot">TRUE</span>, ...) {
+  <span class="kw">layer</span>(
+    <span class="dt">geom =</span> GeomSimplePolygon, <span class="dt">mapping =</span> mapping, <span class="dt">data =</span> data, <span class="dt">stat =</span> stat, 
+    <span class="dt">position =</span> position, <span class="dt">show.legend =</span> show.legend, <span class="dt">inherit.aes =</span> inherit.aes,
+    <span class="dt">params =</span> <span class="kw">list</span>(<span class="dt">na.rm =</span> na.rm, ...)
+  )
+}
+
+<span class="kw">ggplot</span>(mpg, <span class="kw">aes</span>(displ, hwy)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_point</span>() +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_simple_polygon</span>(<span class="kw">aes</span>(<span class="dt">colour =</span> class), <span class="dt">fill =</span> <span class="ot">NA</span>)</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<p>There are a few things to note here:</p>
+<ul>
+<li><p>We override <code>draw_group()</code> instead of <code>draw_layer()</code> because we want one polygon per group, not one polygon per row. If you look at the source code for the original <code>GeomPolygon</code> you’ll see it actually overrides <code>geom_layer()</code> because it uses some tricks to make <code>polygonGrob()</code> produce multiple polygons in one call. This is considerably more complicated, but gives better performance.</p></li>
+<li><p>If the data contains two or fewer points, there’s no point trying to draw a polygon, so we return a <code>nullGrob()</code>. This is the graphical equivalent of <code>NULL</code>: it’s a grob that doesn’t draw anything and doesn’t take up any space.</p></li>
+<li><p>Note the units: <code>x</code> and <code>y</code> should always be drawn in “native” units. (The default units for <code>pointGrob()</code> is a native, so we didn’t need to change it there). <code>lwd</code> is measured in points, but ggplot2 uses mm, so we need to multiply it by the adjustment factor <code>.pt</code>.</p></li>
+</ul>
+</div>
+<div id="inheriting-from-an-existing-geom" class="section level3">
+<h3>Inheriting from an existing Geom</h3>
+<p>Sometimes you just want to make a small modification to an existing geom. In this case, rather than inheriting from <code>Geom</code> you can inherit from an existing subclass. For example, we might want to change the defaults for <code>GeomPolygon</code> to work better with <code>StatChull</code>:</p>
+<pre class="sourceCode r"><code class="sourceCode r">GeomPolygonHollow <-<span class="st"> </span><span class="kw">ggproto</span>(<span class="st">"GeomPolygonHollow"</span>, GeomPolygon,
+  <span class="dt">default_aes =</span> <span class="kw">aes</span>(<span class="dt">colour =</span> <span class="st">"black"</span>, <span class="dt">fill =</span> <span class="ot">NA</span>, <span class="dt">size =</span> <span class="fl">0.5</span>, <span class="dt">linetype =</span> <span class="dv">1</span>,
+    <span class="dt">alpha =</span> <span class="ot">NA</span>)
+  )
+geom_chull <-<span class="st"> </span>function(<span class="dt">mapping =</span> <span class="ot">NULL</span>, <span class="dt">data =</span> <span class="ot">NULL</span>, 
+                       <span class="dt">position =</span> <span class="st">"identity"</span>, <span class="dt">na.rm =</span> <span class="ot">FALSE</span>, <span class="dt">show.legend =</span> <span class="ot">NA</span>, 
+                       <span class="dt">inherit.aes =</span> <span class="ot">TRUE</span>, ...) {
+  <span class="kw">layer</span>(
+    <span class="dt">stat =</span> StatChull, <span class="dt">geom =</span> GeomPolygonHollow, <span class="dt">data =</span> data, <span class="dt">mapping =</span> mapping,
+    <span class="dt">position =</span> position, <span class="dt">show.legend =</span> show.legend, <span class="dt">inherit.aes =</span> inherit.aes,
+    <span class="dt">params =</span> <span class="kw">list</span>(<span class="dt">na.rm =</span> na.rm, ...)
+  )
+}
+
+<span class="kw">ggplot</span>(mpg, <span class="kw">aes</span>(displ, hwy)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_point</span>() +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_chull</span>()</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<p>This doesn’t allow you to use different geoms with the stat, but that seems appropriate here since the convex hull is primarily a polygonal feature.</p>
+</div>
+<div id="exercises-1" class="section level3">
+<h3>Exercises</h3>
+<ol style="list-style-type: decimal">
+<li><p>Compare and contrast <code>GeomPoint</code> with <code>GeomSimplePoint</code>.</p></li>
+<li><p>Compare and contract <code>GeomPolygon</code> with <code>GeomSimplePolygon</code>.</p></li>
+</ol>
+</div>
+</div>
+<div id="creating-your-own-theme" class="section level2">
+<h2>Creating your own theme</h2>
+<p>If you’re going to create your own complete theme, there are a few things you need to know:</p>
+<ul>
+<li>Overriding existing elements, rather than modifying them</li>
+<li>The four global elements that affect (almost) every other theme element</li>
+<li>Complete vs. incomplete elements</li>
+</ul>
+<div id="overriding-elements" class="section level3">
+<h3>Overriding elements</h3>
+<p>By default, when you add a new theme element, it inherits values from the existing theme. For example, the following code sets the key colour to red, but it inherits the existing fill colour:</p>
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">theme_grey</span>()$legend.key
+<span class="co">#> List of 4</span>
+<span class="co">#>  $ fill    : chr "grey95"</span>
+<span class="co">#>  $ colour  : chr "white"</span>
+<span class="co">#>  $ size    : NULL</span>
+<span class="co">#>  $ linetype: NULL</span>
+<span class="co">#>  - attr(*, "class")= chr [1:2] "element_rect" "element"</span>
+
+new_theme <-<span class="st"> </span><span class="kw">theme_grey</span>() +<span class="st"> </span><span class="kw">theme</span>(<span class="dt">legend.key =</span> <span class="kw">element_rect</span>(<span class="dt">colour =</span> <span class="st">"red"</span>))
+new_theme$legend.key
+<span class="co">#> List of 4</span>
+<span class="co">#>  $ fill    : chr "grey95"</span>
+<span class="co">#>  $ colour  : chr "red"</span>
+<span class="co">#>  $ size    : NULL</span>
+<span class="co">#>  $ linetype: NULL</span>
+<span class="co">#>  - attr(*, "class")= chr [1:2] "element_rect" "element"</span></code></pre>
+<p>To override it completely, use <code>%+replace%</code> instead of <code>+</code>:</p>
+<pre class="sourceCode r"><code class="sourceCode r">new_theme <-<span class="st"> </span><span class="kw">theme_grey</span>() %+replace%<span class="st"> </span><span class="kw">theme</span>(<span class="dt">legend.key =</span> <span class="kw">element_rect</span>(<span class="dt">colour =</span> <span class="st">"red"</span>))
+new_theme$legend.key
+<span class="co">#> List of 4</span>
+<span class="co">#>  $ fill    : NULL</span>
+<span class="co">#>  $ colour  : chr "red"</span>
+<span class="co">#>  $ size    : NULL</span>
+<span class="co">#>  $ linetype: NULL</span>
+<span class="co">#>  - attr(*, "class")= chr [1:2] "element_rect" "element"</span></code></pre>
+</div>
+<div id="global-elements" class="section level3">
+<h3>Global elements</h3>
+<p>There are four elements that affect the global appearance of the plot:</p>
+<table>
+<thead>
+<tr class="header">
+<th align="left">Element</th>
+<th align="left">Theme function</th>
+<th align="left">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td align="left">line</td>
+<td align="left"><code>element_line()</code></td>
+<td align="left">all line elements</td>
+</tr>
+<tr class="even">
+<td align="left">rect</td>
+<td align="left"><code>element_rect()</code></td>
+<td align="left">all rectangular elements</td>
+</tr>
+<tr class="odd">
+<td align="left">text</td>
+<td align="left"><code>element_text()</code></td>
+<td align="left">all text</td>
+</tr>
+<tr class="even">
+<td align="left">title</td>
+<td align="left"><code>element_text()</code></td>
+<td align="left">all text in title elements (plot, axes & legend)</td>
+</tr>
+</tbody>
+</table>
+<p>These set default properties that are inherited by more specific settings. These are most useful for setting an overall “background” colour and overall font settings (e.g. family and size).</p>
+<pre class="sourceCode r"><code class="sourceCode r">df <-<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">x =</span> <span class="dv">1</span>:<span class="dv">3</span>, <span class="dt">y =</span> <span class="dv">1</span>:<span class="dv">3</span>)
+base <-<span class="st"> </span><span class="kw">ggplot</span>(df, <span class="kw">aes</span>(x, y)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_point</span>() +<span class="st"> </span>
+<span class="st">  </span><span class="kw">theme_minimal</span>()
+
+base</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<pre class="sourceCode r"><code class="sourceCode r">base +<span class="st"> </span><span class="kw">theme</span>(<span class="dt">text =</span> <span class="kw">element_text</span>(<span class="dt">colour =</span> <span class="st">"red"</span>))</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<p>You should generally start creating a theme by modifying these values.</p>
+</div>
+<div id="complete-vs-incomplete" class="section level3">
+<h3>Complete vs incomplete</h3>
+<p>It is useful to understand the difference between complete and incomplete theme objects. A <em>complete</em> theme object is one produced by calling a theme function with the attribute <code>complete = TRUE</code>.</p>
+<p>Theme functions <code>theme_grey()</code> and <code>theme_bw()</code> are examples of complete theme functions. Calls to <code>theme()</code> produce <em>incomplete</em> theme objects, since they represent (local) modifications to a theme object rather than returning a complete theme object per se. When adding an incomplete theme to a complete one, the result is a complete theme.</p>
+<p>Complete and incomplete themes behave somewhat differently when added to a ggplot object:</p>
+<ul>
+<li><p>Adding an incomplete theme augments the current theme object, replacing only those properties of elements defined in the call to <code>theme()</code>.</p></li>
+<li><p>Adding a complete theme wipes away the existing theme and applies the new theme.</p></li>
+</ul>
+</div>
+</div>
+
+
+
+<!-- dynamically load mathjax for compatibility with self-contained -->
+<script>
+  (function () {
+    var script = document.createElement("script");
+    script.type = "text/javascript";
+    script.src  = "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
+    document.getElementsByTagName("head")[0].appendChild(script);
+  })();
+</script>
+
+</body>
+</html>
diff --git a/inst/doc/ggplot2-specs.R b/inst/doc/ggplot2-specs.R
new file mode 100644
index 0000000..e471287
--- /dev/null
+++ b/inst/doc/ggplot2-specs.R
@@ -0,0 +1,52 @@
+## ---- include = FALSE----------------------------------------------------
+library(ggplot2)
+knitr::opts_chunk$set(fig.dpi = 96)
+
+## ------------------------------------------------------------------------
+lty <- c("blank", "solid", "dashed", "dotted", "dotdash", 
+     "longdash","twodash")
+linetypes <- data.frame(
+  y = seq_along(lty),
+  lty = lty
+) 
+ggplot(linetypes, aes(0, y)) + 
+  geom_segment(aes(xend = 5, yend = y, linetype = lty)) + 
+  scale_linetype_identity() + 
+  geom_text(aes(label = lty), hjust = 0, nudge_y = 0.2) +
+  scale_x_continuous(NULL, breaks = NULL) + 
+  scale_y_continuous(NULL, breaks = NULL)
+
+## ------------------------------------------------------------------------
+shapes <- data.frame(
+  shape = c(0:19, 22, 21, 24, 23, 20),
+  x = 0:24 %/% 5,
+  y = -(0:24 %% 5)
+)
+ggplot(shapes, aes(x, y)) + 
+  geom_point(aes(shape = shape), size = 5, fill = "red") +
+  geom_text(aes(label = shape), hjust = 0, nudge_x = 0.15) +
+  scale_shape_identity() +
+  expand_limits(x = 4.1) +
+  scale_x_continuous(NULL, breaks = NULL) + 
+  scale_y_continuous(NULL, breaks = NULL)
+
+## ------------------------------------------------------------------------
+sizes <- expand.grid(size = (0:3) * 2, stroke = (0:3) * 2)
+ggplot(sizes, aes(size, stroke, size = size, stroke = stroke)) + 
+  geom_abline(slope = -1, intercept = 6, colour = "white", size = 6) + 
+  geom_point(shape = 21, fill = "red") +
+  scale_size_identity()
+
+## ------------------------------------------------------------------------
+df <- data.frame(x = 1, y = 3:1, family = c("sans", "serif", "mono"))
+ggplot(df, aes(x, y)) + 
+  geom_text(aes(label = family, family = family))
+
+## ------------------------------------------------------------------------
+just <- expand.grid(hjust = c(0, 0.5, 1), vjust = c(0, 0.5, 1))
+just$label <- paste0(just$hjust, ", ", just$vjust)
+
+ggplot(just, aes(hjust, vjust)) +
+  geom_point(colour = "grey70", size = 5) + 
+  geom_text(aes(label = label, hjust = hjust, vjust = vjust))
+
diff --git a/inst/doc/ggplot2-specs.Rmd b/inst/doc/ggplot2-specs.Rmd
new file mode 100644
index 0000000..5c2cf0b
--- /dev/null
+++ b/inst/doc/ggplot2-specs.Rmd
@@ -0,0 +1,168 @@
+---
+title: "Aesthetic specifications"
+author: "Hadley Wickham"
+date: "`r Sys.Date()`"
+output: rmarkdown::html_vignette
+vignette: >
+  %\VignetteIndexEntry{Aesthetic specifications}
+  %\VignetteEngine{knitr::rmarkdown}
+  %\VignetteEncoding{UTF-8}
+---
+
+```{r, include = FALSE}
+library(ggplot2)
+knitr::opts_chunk$set(fig.dpi = 96)
+```
+
+This vignette summarises the various formats that grid drawing functions take.  Most of this information is available scattered throughout the R documentation.  This appendix brings it all together in one place. 
+
+## Colour
+
+Colours can be specified with: 
+
+*   A __name__, e.g., `"red"`. R has `r length(colours())` built-in named
+    colours, which can be listed with `colours()`. The Stowers Institute 
+    provides a nice printable pdf that lists all colours: 
+    <http://research.stowers-institute.org/efg/R/Color/Chart/>.
+
+*   An __rgb specification__, with a string of the form `"#RRGGBB"` where each of 
+    the pairs `RR`, `GG`, `BB` consists of two hexadecimal digits giving a value 
+    in the range `00` to `FF`
+    
+    You can optionally make the colour transparent by using the form 
+    `"#RRGGBBAA".
+
+*   An __NA__, for a completely transparent colour.
+
+*   The [munsell](https://github.com/cwickham/munsell) package, Charlotte 
+    Wickham, provides a wrapper around the colour system designed by Alfred 
+    Munsell.
+
+## Line type {#sec:line-type-spec}
+
+Line types can be specified with:
+
+*   An __integer__ or __name__: 0 = blank, 1 = solid, 2 = dashed, 3 = dotted, 
+    4 = dotdash, 5 = longdash, 6 = twodash, as shown below:
+
+    ```{r}
+    lty <- c("blank", "solid", "dashed", "dotted", "dotdash", 
+         "longdash","twodash")
+    linetypes <- data.frame(
+      y = seq_along(lty),
+      lty = lty
+    ) 
+    ggplot(linetypes, aes(0, y)) + 
+      geom_segment(aes(xend = 5, yend = y, linetype = lty)) + 
+      scale_linetype_identity() + 
+      geom_text(aes(label = lty), hjust = 0, nudge_y = 0.2) +
+      scale_x_continuous(NULL, breaks = NULL) + 
+      scale_y_continuous(NULL, breaks = NULL)
+    ```
+
+*   The lengths of on/off stretches of line. This is done with a string 
+    containing 2, 4, 6, or 8 hexadecimal digits which give the lengths of c
+    consecutive lengths. For example, the string `"33"` specifies three units 
+    on followed by three off and `"3313"` specifies three units on followed by 
+    three off followed by one on and finally three off. 
+    
+    The five standard dash-dot line types described above correspond to 44, 13, 
+    134, 73, and 2262.
+
+The `size` of a line is its width in mm.
+
+## Shape {#sec:shape-spec}
+
+Shapes take four types of values:
+
+*   An __integer__ in $[0, 25]$:
+
+    ```{r}
+    shapes <- data.frame(
+      shape = c(0:19, 22, 21, 24, 23, 20),
+      x = 0:24 %/% 5,
+      y = -(0:24 %% 5)
+    )
+    ggplot(shapes, aes(x, y)) + 
+      geom_point(aes(shape = shape), size = 5, fill = "red") +
+      geom_text(aes(label = shape), hjust = 0, nudge_x = 0.15) +
+      scale_shape_identity() +
+      expand_limits(x = 4.1) +
+      scale_x_continuous(NULL, breaks = NULL) + 
+      scale_y_continuous(NULL, breaks = NULL)
+    ```
+
+*   A __single character__, to use that character as a plotting symbol.
+
+*   A `.` to draw the smallest rectangle that is visible, usualy 1 pixel.
+   
+*   An `NA`, to draw nothing.
+
+Note that shapes 21-24 have both stroke `colour` and a `fill`. The size of the filled part is controlled by `size`, the size of the stroke is controlled by `stroke`. Each is measured in mm, and the total size of the point is the sum of the two. Note that the size is constant along the diagonal in the following figure.
+
+```{r}
+sizes <- expand.grid(size = (0:3) * 2, stroke = (0:3) * 2)
+ggplot(sizes, aes(size, stroke, size = size, stroke = stroke)) + 
+  geom_abline(slope = -1, intercept = 6, colour = "white", size = 6) + 
+  geom_point(shape = 21, fill = "red") +
+  scale_size_identity()
+```
+
+
+## Text
+
+### Font size
+
+
+### Font face
+
+There are only three fonts that are guaranteed to work everywhere: "sans" (the default), "serif", or "mono":
+
+```{r}
+df <- data.frame(x = 1, y = 3:1, family = c("sans", "serif", "mono"))
+ggplot(df, aes(x, y)) + 
+  geom_text(aes(label = family, family = family))
+```
+
+It's trickier to include a system font on a plot because text drawing is done differently by each graphics device (GD). There are five GDs in common use (`png()`, `pdf()`, on screen devices for Windows, Mac and Linux), so to have a font work everywhere you need to configure five devices in five different ways. Two packages simplify the quandary a bit: 
+
+* `showtext` makes GD-independent plots by rendering all text as polygons. 
+
+* `extrafont` converts fonts to a standard format that all devices can use. 
+
+Both approaches have pros and cons, so you will to need to try both of them and see which works best for your needs.
+
+### Family
+
+<!--
+postscriptFonts, pdfFonts, quartzFonts
+
+Find R news article
+
+\begin{itemize}
+  \item \code{face}
+  \item \code{family}
+  \item \code{lineheight}
+  \item \code{fontsize}
+\end{itemize}
+-->
+
+
+### Justification
+
+Horizontal and vertical justification have the same parameterisation, either a string ("top", "middle", "bottom", "left", "center", "right") or a number between 0 and 1:
+
+* top = 1, middle = 0.5, bottom = 0
+* left = 0, center = 0.5, right = 1
+
+
+```{r}
+just <- expand.grid(hjust = c(0, 0.5, 1), vjust = c(0, 0.5, 1))
+just$label <- paste0(just$hjust, ", ", just$vjust)
+
+ggplot(just, aes(hjust, vjust)) +
+  geom_point(colour = "grey70", size = 5) + 
+  geom_text(aes(label = label, hjust = hjust, vjust = vjust))
+```
+
+Note that you can use numbers outside the range (0, 1), but it's not recommended. 
diff --git a/inst/doc/ggplot2-specs.html b/inst/doc/ggplot2-specs.html
new file mode 100644
index 0000000..f9e09e5
--- /dev/null
+++ b/inst/doc/ggplot2-specs.html
@@ -0,0 +1,191 @@
+<!DOCTYPE html>
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+
+<meta charset="utf-8">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="pandoc" />
+
+<meta name="author" content="Hadley Wickham" />
+
+<meta name="date" content="2015-12-15" />
+
+<title>Aesthetic specifications</title>
+
+
+
+<style type="text/css">code{white-space: pre;}</style>
+<style type="text/css">
+table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
+  margin: 0; padding: 0; vertical-align: baseline; border: none; }
+table.sourceCode { width: 100%; line-height: 100%; }
+td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
+td.sourceCode { padding-left: 5px; }
+code > span.kw { color: #007020; font-weight: bold; }
+code > span.dt { color: #902000; }
+code > span.dv { color: #40a070; }
+code > span.bn { color: #40a070; }
+code > span.fl { color: #40a070; }
+code > span.ch { color: #4070a0; }
+code > span.st { color: #4070a0; }
+code > span.co { color: #60a0b0; font-style: italic; }
+code > span.ot { color: #007020; }
+code > span.al { color: #ff0000; font-weight: bold; }
+code > span.fu { color: #06287e; }
+code > span.er { color: #ff0000; font-weight: bold; }
+</style>
+<style type="text/css">
+  pre:not([class]) {
+    background-color: white;
+  }
+</style>
+
+
+<link href="data:text/css,body%20%7B%0A%20%20background%2Dcolor%3A%20%23fff%3B%0A%20%20margin%3A%201em%20auto%3B%0A%20%20max%2Dwidth%3A%20700px%3B%0A%20%20overflow%3A%20visible%3B%0A%20%20padding%2Dleft%3A%202em%3B%0A%20%20padding%2Dright%3A%202em%3B%0A%20%20font%2Dfamily%3A%20%22Open%20Sans%22%2C%20%22Helvetica%20Neue%22%2C%20Helvetica%2C%20Arial%2C%20sans%2Dserif%3B%0A%20%20font%2Dsize%3A%2014px%3B%0A%20%20line%2Dheight%3A%201%2E35%3B%0A%7D%0A%0A%23header%20%7B%0A%20%20text%2Dalign%3A% [...]
+
+</head>
+
+<body>
+
+
+
+<div id="header">
+<h1 class="title">Aesthetic specifications</h1>
+<h4 class="author"><em>Hadley Wickham</em></h4>
+<h4 class="date"><em>2015-12-15</em></h4>
+</div>
+
+
+<p>This vignette summarises the various formats that grid drawing functions take. Most of this information is available scattered throughout the R documentation. This appendix brings it all together in one place.</p>
+<div id="colour" class="section level2">
+<h2>Colour</h2>
+<p>Colours can be specified with:</p>
+<ul>
+<li><p>A <strong>name</strong>, e.g., <code>"red"</code>. R has 657 built-in named colours, which can be listed with <code>colours()</code>. The Stowers Institute provides a nice printable pdf that lists all colours: <a href="http://research.stowers-institute.org/efg/R/Color/Chart/" class="uri">http://research.stowers-institute.org/efg/R/Color/Chart/</a>.</p></li>
+<li><p>An <strong>rgb specification</strong>, with a string of the form <code>"#RRGGBB"</code> where each of the pairs <code>RR</code>, <code>GG</code>, <code>BB</code> consists of two hexadecimal digits giving a value in the range <code>00</code> to <code>FF</code></p>
+<p>You can optionally make the colour transparent by using the form `“#RRGGBBAA”.</p></li>
+<li><p>An <strong>NA</strong>, for a completely transparent colour.</p></li>
+<li><p>The <a href="https://github.com/cwickham/munsell">munsell</a> package, Charlotte Wickham, provides a wrapper around the colour system designed by Alfred Munsell.</p></li>
+</ul>
+</div>
+<div id="sec:line-type-spec" class="section level2">
+<h2>Line type</h2>
+<p>Line types can be specified with:</p>
+<ul>
+<li><p>An <strong>integer</strong> or <strong>name</strong>: 0 = blank, 1 = solid, 2 = dashed, 3 = dotted, 4 = dotdash, 5 = longdash, 6 = twodash, as shown below:</p>
+<pre class="sourceCode r"><code class="sourceCode r">lty <-<span class="st"> </span><span class="kw">c</span>(<span class="st">"blank"</span>, <span class="st">"solid"</span>, <span class="st">"dashed"</span>, <span class="st">"dotted"</span>, <span class="st">"dotdash"</span>, 
+     <span class="st">"longdash"</span>,<span class="st">"twodash"</span>)
+linetypes <-<span class="st"> </span><span class="kw">data.frame</span>(
+  <span class="dt">y =</span> <span class="kw">seq_along</span>(lty),
+  <span class="dt">lty =</span> lty
+) 
+<span class="kw">ggplot</span>(linetypes, <span class="kw">aes</span>(<span class="dv">0</span>, y)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_segment</span>(<span class="kw">aes</span>(<span class="dt">xend =</span> <span class="dv">5</span>, <span class="dt">yend =</span> y, <span class="dt">linetype =</span> lty)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">scale_linetype_identity</span>() +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_text</span>(<span class="kw">aes</span>(<span class="dt">label =</span> lty), <span class="dt">hjust =</span> <span class="dv">0</span>, <span class="dt">nudge_y =</span> <span class="fl">0.2</span>) +
+<span class="st">  </span><span class="kw">scale_x_continuous</span>(<span class="ot">NULL</span>, <span class="dt">breaks =</span> <span class="ot">NULL</span>) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">scale_y_continuous</span>(<span class="ot">NULL</span>, <span class="dt">breaks =</span> <span class="ot">NULL</span>)</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<li><p>The lengths of on/off stretches of line. This is done with a string containing 2, 4, 6, or 8 hexadecimal digits which give the lengths of c consecutive lengths. For example, the string <code>"33"</code> specifies three units on followed by three off and <code>"3313"</code> specifies three units on followed by three off followed by one on and finally three off.</p>
+<p>The five standard dash-dot line types described above correspond to 44, 13, 134, 73, and 2262.</p></li>
+</ul>
+<p>The <code>size</code> of a line is its width in mm.</p>
+</div>
+<div id="sec:shape-spec" class="section level2">
+<h2>Shape</h2>
+<p>Shapes take four types of values:</p>
+<ul>
+<li><p>An <strong>integer</strong> in <span class="math">\([0, 25]\)</span>:</p>
+<pre class="sourceCode r"><code class="sourceCode r">shapes <-<span class="st"> </span><span class="kw">data.frame</span>(
+  <span class="dt">shape =</span> <span class="kw">c</span>(<span class="dv">0</span>:<span class="dv">19</span>, <span class="dv">22</span>, <span class="dv">21</span>, <span class="dv">24</span>, <span class="dv">23</span>, <span class="dv">20</span>),
+  <span class="dt">x =</span> <span class="dv">0</span>:<span class="dv">24</span> %/%<span class="st"> </span><span class="dv">5</span>,
+  <span class="dt">y =</span> -(<span class="dv">0</span>:<span class="dv">24</span> %%<span class="st"> </span><span class="dv">5</span>)
+)
+<span class="kw">ggplot</span>(shapes, <span class="kw">aes</span>(x, y)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_point</span>(<span class="kw">aes</span>(<span class="dt">shape =</span> shape), <span class="dt">size =</span> <span class="dv">5</span>, <span class="dt">fill =</span> <span class="st">"red"</span>) +
+<span class="st">  </span><span class="kw">geom_text</span>(<span class="kw">aes</span>(<span class="dt">label =</span> shape), <span class="dt">hjust =</span> <span class="dv">0</span>, <span class="dt">nudge_x =</span> <span class="fl">0.15</span>) +
+<span class="st">  </span><span class="kw">scale_shape_identity</span>() +
+<span class="st">  </span><span class="kw">expand_limits</span>(<span class="dt">x =</span> <span class="fl">4.1</span>) +
+<span class="st">  </span><span class="kw">scale_x_continuous</span>(<span class="ot">NULL</span>, <span class="dt">breaks =</span> <span class="ot">NULL</span>) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">scale_y_continuous</span>(<span class="ot">NULL</span>, <span class="dt">breaks =</span> <span class="ot">NULL</span>)</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<li><p>A <strong>single character</strong>, to use that character as a plotting symbol.</p></li>
+<li><p>A <code>.</code> to draw the smallest rectangle that is visible, usualy 1 pixel.</p></li>
+<li><p>An <code>NA</code>, to draw nothing.</p></li>
+</ul>
+<p>Note that shapes 21-24 have both stroke <code>colour</code> and a <code>fill</code>. The size of the filled part is controlled by <code>size</code>, the size of the stroke is controlled by <code>stroke</code>. Each is measured in mm, and the total size of the point is the sum of the two. Note that the size is constant along the diagonal in the following figure.</p>
+<pre class="sourceCode r"><code class="sourceCode r">sizes <-<span class="st"> </span><span class="kw">expand.grid</span>(<span class="dt">size =</span> (<span class="dv">0</span>:<span class="dv">3</span>) *<span class="st"> </span><span class="dv">2</span>, <span class="dt">stroke =</span> (<span class="dv">0</span>:<span class="dv">3</span>) *<span class="st"> </span><span class="dv">2</span>)
+<span class="kw">ggplot</span>(sizes, <span class="kw">aes</span>(size, stroke, <span class="dt">size =</span> size, <span class="dt">stroke =</span> stroke)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_abline</span>(<span class="dt">slope =</span> -<span class="dv">1</span>, <span class="dt">intercept =</span> <span class="dv">6</span>, <span class="dt">colour =</span> <span class="st">"white"</span>, <span class="dt">size =</span> <span class="dv">6</span>) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_point</span>(<span class="dt">shape =</span> <span class="dv">21</span>, <span class="dt">fill =</span> <span class="st">"red"</span>) +
+<span class="st">  </span><span class="kw">scale_size_identity</span>()</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+</div>
+<div id="text" class="section level2">
+<h2>Text</h2>
+<div id="font-size" class="section level3">
+<h3>Font size</h3>
+</div>
+<div id="font-face" class="section level3">
+<h3>Font face</h3>
+<p>There are only three fonts that are guaranteed to work everywhere: “sans” (the default), “serif”, or “mono”:</p>
+<pre class="sourceCode r"><code class="sourceCode r">df <-<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">x =</span> <span class="dv">1</span>, <span class="dt">y =</span> <span class="dv">3</span>:<span class="dv">1</span>, <span class="dt">family =</span> <span class="kw">c</span>(<span class="st">"sans"</span>, <span class="st">"serif"</span>, <span class="st">"mono"</span>))
+<span class="kw">ggplot</span>(df, <span class="kw">aes</span>(x, y)) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_text</span>(<span class="kw">aes</span>(<span class="dt">label =</span> family, <span class="dt">family =</span> family))</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<p>It’s trickier to include a system font on a plot because text drawing is done differently by each graphics device (GD). There are five GDs in common use (<code>png()</code>, <code>pdf()</code>, on screen devices for Windows, Mac and Linux), so to have a font work everywhere you need to configure five devices in five different ways. Two packages simplify the quandary a bit:</p>
+<ul>
+<li><p><code>showtext</code> makes GD-independent plots by rendering all text as polygons.</p></li>
+<li><p><code>extrafont</code> converts fonts to a standard format that all devices can use.</p></li>
+</ul>
+<p>Both approaches have pros and cons, so you will to need to try both of them and see which works best for your needs.</p>
+</div>
+<div id="family" class="section level3">
+<h3>Family</h3>
+<!--
+postscriptFonts, pdfFonts, quartzFonts
+
+Find R news article
+
+\begin{itemize}
+  \item \code{face}
+  \item \code{family}
+  \item \code{lineheight}
+  \item \code{fontsize}
+\end{itemize}
+-->
+</div>
+<div id="justification" class="section level3">
+<h3>Justification</h3>
+<p>Horizontal and vertical justification have the same parameterisation, either a string (“top”, “middle”, “bottom”, “left”, “center”, “right”) or a number between 0 and 1:</p>
+<ul>
+<li>top = 1, middle = 0.5, bottom = 0</li>
+<li>left = 0, center = 0.5, right = 1</li>
+</ul>
+<pre class="sourceCode r"><code class="sourceCode r">just <-<span class="st"> </span><span class="kw">expand.grid</span>(<span class="dt">hjust =</span> <span class="kw">c</span>(<span class="dv">0</span>, <span class="fl">0.5</span>, <span class="dv">1</span>), <span class="dt">vjust =</span> <span class="kw">c</span>(<span class="dv">0</span>, <span class="fl">0.5</span>, <span class="dv">1</span>))
+just$label <-<span class="st"> </span><span class="kw">paste0</span>(just$hjust, <span class="st">", "</span>, just$vjust)
+
+<span class="kw">ggplot</span>(just, <span class="kw">aes</span>(hjust, vjust)) +
+<span class="st">  </span><span class="kw">geom_point</span>(<span class="dt">colour =</span> <span class="st">"grey70"</span>, <span class="dt">size =</span> <span class="dv">5</span>) +<span class="st"> </span>
+<span class="st">  </span><span class="kw">geom_text</span>(<span class="kw">aes</span>(<span class="dt">label =</span> label, <span class="dt">hjust =</span> hjust, <span class="dt">vjust =</span> vjust))</code></pre>
+<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASAAAAEgCAYAAAAUg66AAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
+<p>Note that you can use numbers outside the range (0, 1), but it’s not recommended.</p>
+</div>
+</div>
+
+
+
+<!-- dynamically load mathjax for compatibility with self-contained -->
+<script>
+  (function () {
+    var script = document.createElement("script");
+    script.type = "text/javascript";
+    script.src  = "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
+    document.getElementsByTagName("head")[0].appendChild(script);
+  })();
+</script>
+
+</body>
+</html>
diff --git a/inst/doc/release.R b/inst/doc/release.R
deleted file mode 100644
index 4fb5798..0000000
--- a/inst/doc/release.R
+++ /dev/null
@@ -1,8 +0,0 @@
-## ----, echo = FALSE, message = FALSE-------------------------------------
-knitr::opts_chunk$set(
-  comment = "#>",
-  error = FALSE,
-  tidy = FALSE
-)
-library(ggplot2)
-
diff --git a/inst/doc/release.Rmd b/inst/doc/release.Rmd
deleted file mode 100644
index 2efe4bf..0000000
--- a/inst/doc/release.Rmd
+++ /dev/null
@@ -1,107 +0,0 @@
-<!--
-%\VignetteEngine{knitr::knitr}
-%\VignetteIndexEntry{ggplot2 release process}
--->
-
-```{r, echo = FALSE, message = FALSE}
-knitr::opts_chunk$set(
-  comment = "#>",
-  error = FALSE,
-  tidy = FALSE
-)
-library(ggplot2)
-```
-
-# Releasing a new version of ggplot2
-
-## Release candidate phase
-
-After issues resolved for a given release:
-
-1.  Pass R CMD check.
-
-1.  In DESCRIPTION and NEWS, remove the .99 version suffix and increment the
-    version number. For example, 0.9.2.99 becomes 0.9.3.
-
-1.  Do the same for any packages that ggplot2 depends on, such as scales and
-    gtable.
-
-1.  Update ggplot2's Import dependency versions to use the final release numbers
-    of scales and gtable.
-
-1.  Commit these changes to a branch with `ggplot2-<version>-rc`, and push the
-    branch.
-    
-1.  Check packages that depend on ggplot2 with `devtools::revdep_check()` and
-    run visual tests.
-
-1.  Email ggplot2, ggplot2-dev, and bcc the maintainers of packages that depend 
-    on ggplot2 (`revdep_maintainers("ggplot2")`).
-    
-    ```
-    Hi all,
-    
-    We're very please to announce a release candidate for ggplot2 1.0.0! This
-    release celebrates the ggplot2 community: all improvements have been 
-    contributed via pull requests.
-    
-    We've made every effort to make sure that your existing ggplot2 graphics
-    continue to work. ggplot2 1.0.0 has passed R CMD check, all our existing 
-    visual tests, and R CMD check on all dependencies. But it's still possible 
-    that some bugs may have crept in, so we'd really appreciate it if you'd 
-    try it out. It's easy to install the development version: first install 
-    devtools, then run `devtools::install_github("hadley/ggplot2 at ggplot2-1.0.0-rc")`.
-    
-    We plan to submit ggplot2 to cran in two weeks, May 9. Please let us know if 
-    you have any problems - your feedback is much appreciated. (If you're pretty
-    sure you've discovered a new bug, please start a new thread or file
-    an issue on github, otherwise it's a bit hard to track what's going on).
-    
-    Hadley & Winston
-    ```
-
-1.  Notify cran:
-
-    ```
-    Dear CRAN maintainers,
-    
-    ggplot2 1.0.0 has entered the release candidate phase and will be
-    submitted to CRAN in two weeks.
-    
-    Included below is the email that I sent to the ggplot2 mailing and all
-    maintainers of packages that depend on ggplot2.
-    
-    Regards,
-    
-    Hadley
-    ```
-
-If problems arise during the RC period, make fixes on the branch. Those fixes
-later get merged back into master.
-
-## Release
-
-When the package is accepted on CRAN:
-
-1.  Create a new release at https://github.com/hadley/ggplot2/releases.
-    The tag name should be of the form `v1.0.0`.
-
-1.  If any Check out the new branch, or merge it into master. (Need to get off the
-    rc branch so it can be deleted):
-
-    ```
-    VERSION=1.0.0
-    git checkout v$VERSION
-    # Or
-    git checkout master
-    git merge v$VERSION
-    ```
-
-1.  Delete the `-rc` branch, with:
-
-    ```
-    git branch -d v$VERSION-rc
-    git push origin :v$VERSION-rc
-    ```
-
-1.  Once you push the tag github, travis will automatically build the website.
diff --git a/inst/doc/release.html b/inst/doc/release.html
deleted file mode 100644
index 47f572f..0000000
--- a/inst/doc/release.html
+++ /dev/null
@@ -1,257 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
-
-<title>Releasing a new version of ggplot2</title>
-
-<script type="text/javascript">
-window.onload = function() {
-  var imgs = document.getElementsByTagName('img'), i, img;
-  for (i = 0; i < imgs.length; i++) {
-    img = imgs[i];
-    // center an image if it is the only element of its parent
-    if (img.parentElement.childElementCount === 1)
-      img.parentElement.style.textAlign = 'center';
-  }
-};
-</script>
-
-
-
-
-
-<style type="text/css">
-body, td {
-   font-family: sans-serif;
-   background-color: white;
-   font-size: 13px;
-}
-
-body {
-  max-width: 800px;
-  margin: auto;
-  padding: 1em;
-  line-height: 20px;
-}
-
-tt, code, pre {
-   font-family: 'DejaVu Sans Mono', 'Droid Sans Mono', 'Lucida Console', Consolas, Monaco, monospace;
-}
-
-h1 {
-   font-size:2.2em;
-}
-
-h2 {
-   font-size:1.8em;
-}
-
-h3 {
-   font-size:1.4em;
-}
-
-h4 {
-   font-size:1.0em;
-}
-
-h5 {
-   font-size:0.9em;
-}
-
-h6 {
-   font-size:0.8em;
-}
-
-a:visited {
-   color: rgb(50%, 0%, 50%);
-}
-
-pre, img {
-  max-width: 100%;
-}
-pre {
-  overflow-x: auto;
-}
-pre code {
-   display: block; padding: 0.5em;
-}
-
-code {
-  font-size: 92%;
-  border: 1px solid #ccc;
-}
-
-code[class] {
-  background-color: #F8F8F8;
-}
-
-table, td, th {
-  border: none;
-}
-
-blockquote {
-   color:#666666;
-   margin:0;
-   padding-left: 1em;
-   border-left: 0.5em #EEE solid;
-}
-
-hr {
-   height: 0px;
-   border-bottom: none;
-   border-top-width: thin;
-   border-top-style: dotted;
-   border-top-color: #999999;
-}
-
- at media print {
-   * {
-      background: transparent !important;
-      color: black !important;
-      filter:none !important;
-      -ms-filter: none !important;
-   }
-
-   body {
-      font-size:12pt;
-      max-width:100%;
-   }
-
-   a, a:visited {
-      text-decoration: underline;
-   }
-
-   hr {
-      visibility: hidden;
-      page-break-before: always;
-   }
-
-   pre, blockquote {
-      padding-right: 1em;
-      page-break-inside: avoid;
-   }
-
-   tr, img {
-      page-break-inside: avoid;
-   }
-
-   img {
-      max-width: 100% !important;
-   }
-
-   @page :left {
-      margin: 15mm 20mm 15mm 10mm;
-   }
-
-   @page :right {
-      margin: 15mm 10mm 15mm 20mm;
-   }
-
-   p, h2, h3 {
-      orphans: 3; widows: 3;
-   }
-
-   h2, h3 {
-      page-break-after: avoid;
-   }
-}
-</style>
-
-
-
-</head>
-
-<body>
-<!--
-%\VignetteEngine{knitr::knitr}
-%\VignetteIndexEntry{ggplot2 release process}
--->
-
-<h1>Releasing a new version of ggplot2</h1>
-
-<h2>Release candidate phase</h2>
-
-<p>After issues resolved for a given release:</p>
-
-<ol>
-<li><p>Pass R CMD check.</p></li>
-<li><p>In DESCRIPTION and NEWS, remove the .99 version suffix and increment the
-version number. For example, 0.9.2.99 becomes 0.9.3.</p></li>
-<li><p>Do the same for any packages that ggplot2 depends on, such as scales and
-gtable.</p></li>
-<li><p>Update ggplot2's Import dependency versions to use the final release numbers
-of scales and gtable.</p></li>
-<li><p>Commit these changes to a branch with <code>ggplot2-<version>-rc</code>, and push the
-branch.</p></li>
-<li><p>Check packages that depend on ggplot2 with <code>devtools::revdep_check()</code> and
-run visual tests.</p></li>
-<li><p>Email ggplot2, ggplot2-dev, and bcc the maintainers of packages that depend 
-on ggplot2 (<code>revdep_maintainers("ggplot2")</code>).</p>
-
-<pre><code>Hi all,
-
-We're very please to announce a release candidate for ggplot2 1.0.0! This
-release celebrates the ggplot2 community: all improvements have been 
-contributed via pull requests.
-
-We've made every effort to make sure that your existing ggplot2 graphics
-continue to work. ggplot2 1.0.0 has passed R CMD check, all our existing 
-visual tests, and R CMD check on all dependencies. But it's still possible 
-that some bugs may have crept in, so we'd really appreciate it if you'd 
-try it out. It's easy to install the development version: first install 
-devtools, then run `devtools::install_github("hadley/ggplot2 at ggplot2-1.0.0-rc")`.
-
-We plan to submit ggplot2 to cran in two weeks, May 9. Please let us know if 
-you have any problems - your feedback is much appreciated. (If you're pretty
-sure you've discovered a new bug, please start a new thread or file
-an issue on github, otherwise it's a bit hard to track what's going on).
-
-Hadley & Winston
-</code></pre></li>
-<li><p>Notify cran:</p>
-
-<pre><code>Dear CRAN maintainers,
-
-ggplot2 1.0.0 has entered the release candidate phase and will be
-submitted to CRAN in two weeks.
-
-Included below is the email that I sent to the ggplot2 mailing and all
-maintainers of packages that depend on ggplot2.
-
-Regards,
-
-Hadley
-</code></pre></li>
-</ol>
-
-<p>If problems arise during the RC period, make fixes on the branch. Those fixes
-later get merged back into master.</p>
-
-<h2>Release</h2>
-
-<p>When the package is accepted on CRAN:</p>
-
-<ol>
-<li><p>Create a new release at <a href="https://github.com/hadley/ggplot2/releases">https://github.com/hadley/ggplot2/releases</a>.
-The tag name should be of the form <code>v1.0.0</code>.</p></li>
-<li><p>If any Check out the new branch, or merge it into master. (Need to get off the
-rc branch so it can be deleted):</p>
-
-<pre><code>VERSION=1.0.0
-git checkout v$VERSION
-# Or
-git checkout master
-git merge v$VERSION
-</code></pre></li>
-<li><p>Delete the <code>-rc</code> branch, with:</p>
-
-<pre><code>git branch -d v$VERSION-rc
-git push origin :v$VERSION-rc
-</code></pre></li>
-<li><p>Once you push the tag github, travis will automatically build the website.</p></li>
-</ol>
-
-</body>
-
-</html>
diff --git a/inst/staticdocs/icons.R b/inst/staticdocs/icons.R
index 3b951af..4897cd7 100644
--- a/inst/staticdocs/icons.R
+++ b/inst/staticdocs/icons.R
@@ -1,37 +1,52 @@
 # Coords -----------------------------------------------------------------------
 coord_cartesian  <- sd_icon({
   gTree(children = gList(
-    segmentsGrob(c(0, 0.25), c(0.25, 0), c(1, 0.25), c(0.25, 1),
-      gp=gpar(col="grey50", lwd=0.5)),
-    segmentsGrob(c(0, 0.75), c(0.75, 0), c(1, 0.75), c(0.75, 1),
-      gp=gpar(col="grey50", lwd=0.5)),
+    segmentsGrob(
+      c(0, 0.25),
+      c(0.25, 0),
+      c(1, 0.25),
+      c(0.25, 1),
+      gp = gpar(col = "grey50", lwd = 0.5)
+    ),
+    segmentsGrob(
+      c(0, 0.75),
+      c(0.75, 0),
+      c(1, 0.75),
+      c(0.75, 1),
+      gp = gpar(col = "grey50", lwd = 0.5)
+    ),
     segmentsGrob(c(0, 0.5), c(0.5, 0), c(1, 0.5), c(0.5, 1))
   ))
 })
 
+
 coord_fixed  <- sd_icon({
-  textGrob("=", gp = gpar(cex=3))
+  textGrob("=", gp = gpar(cex = 3))
 })
 
+
 coord_flip  <- sd_icon({
-  angles <- seq(0, pi/2, length=20)[-c(1, 20)]
-  gTree(children=gList(
+  angles <- seq(0, pi / 2, length.out = 20)[-c(1, 20)]
+  gTree(children = gList(
     segmentsGrob(0, 0, 0, 1),
     segmentsGrob(0, 0, 1, 0),
     linesGrob(0.9 * sin(angles), 0.9 * cos(angles),
-      arrow=arrow(length=unit(0.05, "npc"))),
-    linesGrob(0.5 * sin(angles), 0.5 * cos(angles),
-      arrow=arrow(ends="first", length= unit(0.05, "npc")))
+      arrow = arrow(length = unit(0.05, "npc"))),
+    linesGrob(
+      0.5 * sin(angles),
+      0.5 * cos(angles),
+      arrow = arrow(ends = "first", length = unit(0.05, "npc"))
+    )
   ))
 })
 
 library(maps)
 coord_map  <- sd_icon({
-  nz <- data.frame(map("nz", plot=FALSE)[c("x","y")])
-  nz$x <- nz$x - min(nz$x, na.rm=TRUE)
-  nz$y <- nz$y - min(nz$y, na.rm=TRUE)
-  nz <- nz / max(nz, na.rm=TRUE)
-  linesGrob(nz$x, nz$y, default.units="npc")
+  nz <- data.frame(map("nz", plot = FALSE)[c("x", "y")])
+  nz$x <- nz$x - min(nz$x, na.rm = TRUE)
+  nz$y <- nz$y - min(nz$y, na.rm = TRUE)
+  nz <- nz / max(nz, na.rm = TRUE)
+  linesGrob(nz$x, nz$y, default.units = "npc")
 })
 
 coord_polar  <- sd_icon({
@@ -39,7 +54,7 @@ coord_polar  <- sd_icon({
 })
 
 coord_transform  <- sd_icon({
-  breaks <- cumsum(1 / 2^(1:5))
+  breaks <- cumsum(1 / 2 ^ (1:5))
   gTree(children = gList(
     segmentsGrob(breaks, 0, breaks, 1),
     segmentsGrob(0, breaks, 1, breaks)
@@ -50,20 +65,48 @@ coord_transform  <- sd_icon({
 
 facet_grid  <- sd_icon({
   gTree(children = gList(
-    rectGrob(0, 1, width=0.95, height=0.05, hjust=0, vjust=1,
-      gp=gpar(fill="grey60", col=NA)),
-    rectGrob(0.95, 0.95, width=0.05, height=0.95, hjust=0, vjust=1,
-      gp=gpar(fill="grey60", col=NA)),
+    rectGrob(
+      0,
+      1,
+      width = 0.95,
+      height = 0.05,
+      hjust = 0,
+      vjust = 1,
+      gp = gpar(fill = "grey60", col = NA)
+    ),
+    rectGrob(
+      0.95,
+      0.95,
+      width = 0.05,
+      height = 0.95,
+      hjust = 0,
+      vjust = 1,
+      gp = gpar(fill = "grey60", col = NA)
+    ),
     segmentsGrob(c(0, 0.475), c(0.475, 0), c(1, 0.475), c(0.475, 1))
   ))
 })
 
 facet_null  <- sd_icon({
   gTree(children = gList(
-    rectGrob(0, 1, width=0.95, height=0.05, hjust=0, vjust=1,
-      gp=gpar(fill="grey60", col=NA)),
-    rectGrob(0.95, 0.95, width=0.05, height=0.95, hjust=0, vjust=1,
-      gp=gpar(fill="grey60", col=NA)),
+    rectGrob(
+      0,
+      1,
+      width = 0.95,
+      height = 0.05,
+      hjust = 0,
+      vjust = 1,
+      gp = gpar(fill = "grey60", col = NA)
+    ),
+    rectGrob(
+      0.95,
+      0.95,
+      width = 0.05,
+      height = 0.95,
+      hjust = 0,
+      vjust = 1,
+      gp = gpar(fill = "grey60", col = NA)
+    ),
     segmentsGrob(c(0, 0.475), c(0.475, 0), c(1, 0.475), c(0.475, 1))
   ))
 })
@@ -73,37 +116,66 @@ facet_null  <- sd_icon({
 geom_abline  <- sd_icon(linesGrob(c(0, 1), c(0.2, 0.8)))
 
 geom_bar  <- sd_icon({
-  rectGrob(c(0.3, 0.7), c(0.4, 0.8), height = c(0.4, 0.8), width = 0.3,
-    vjust = 1, gp = gpar(fill = "grey20", col = NA))
+  rectGrob(
+    c(0.3, 0.7),
+    c(0.4, 0.8),
+    height = c(0.4, 0.8),
+    width = 0.3,
+    vjust = 1,
+    gp = gpar(fill = "grey20", col = NA)
+  )
 })
 
 geom_histogram  <- sd_icon({
-  y <- c(0.2, 0.3, 0.5, 0.6,0.2, 0.8, 0.5, 0.3)
-  rectGrob(seq(0.1, 0.9, by = 0.1), y, height = y, width = 0.1, vjust = 1,
-    gp = gpar(fill = "grey20", col = NA))
+  y <- c(0.2, 0.3, 0.5, 0.6, 0.2, 0.8, 0.5, 0.3)
+  rectGrob(
+    seq(0.1, 0.9, by = 0.1),
+    y,
+    height = y,
+    width = 0.1,
+    vjust = 1,
+    gp = gpar(fill = "grey20", col = NA)
+  )
 })
 
 geom_boxplot  <- sd_icon({
   gTree(children = gList(
     segmentsGrob(c(0.3, 0.7), c(0.1, 0.2), c(0.3, 0.7), c(0.7, 0.95)),
-    rectGrob(c(0.3, 0.7), c(0.6, 0.8), width = 0.3, height = c(0.4, 0.4),
-      vjust = 1),
+    rectGrob(
+      c(0.3, 0.7),
+      c(0.6, 0.8),
+      width = 0.3,
+      height = c(0.4, 0.4),
+      vjust = 1
+    ),
     segmentsGrob(c(0.15, 0.55), c(0.5, 0.6), c(0.45, 0.85), c(0.5, 0.6))
   ))
 })
 
 geom_crossbar  <- sd_icon({
   gTree(children = gList(
-    rectGrob(c(0.3, 0.7), c(0.6, 0.8), width = 0.3, height = c(0.4, 0.4), vjust = 1),
+    rectGrob(
+      c(0.3, 0.7),
+      c(0.6, 0.8),
+      width = 0.3,
+      height = c(0.4, 0.4),
+      vjust = 1
+    ),
     segmentsGrob(c(0.15, 0.55), c(0.5, 0.6), c(0.45, 0.85), c(0.5, 0.6))
   ))
 })
 
 geom_dotplot  <- sd_icon({
-  xpos <- c(1,1,2,3,3,3,4,4,5,5,5,5,6,7,7,7,8,8,9)/10
-  ypos <- c(1,2,1,1,2,3,1,2,1,2,3,4,1,1,2,3,1,2,1)/10
-  pointsGrob(x = xpos, y = ypos, pch = 19, size = unit(.1, "npc"),
-    gp = gpar(col = "black", cex = 0.5), default.units = "npc")
+  xpos <- c(1, 1, 2, 3, 3, 3, 4, 4, 5, 5, 5, 5, 6, 7, 7, 7, 8, 8, 9) / 10
+  ypos <- c(1, 2, 1, 1, 2, 3, 1, 2, 1, 2, 3, 4, 1, 1, 2, 3, 1, 2, 1) / 10
+  pointsGrob(
+    x = xpos,
+    y = ypos,
+    pch = 19,
+    size = unit(.1, "npc"),
+    gp = gpar(col = "black", cex = 0.5),
+    default.units = "npc"
+  )
 })
 
 geom_errorbar  <- sd_icon({
@@ -123,7 +195,7 @@ geom_errorbarh  <- sd_icon({
 })
 
 geom_freqpoly  <- sd_icon({
-  y <- c(0.2, 0.3, 0.5, 0.6,0.2, 0.8, 0.5, 0.3)
+  y <- c(0.2, 0.3, 0.5, 0.6, 0.2, 0.8, 0.5, 0.3)
   linesGrob(seq(0.1, 0.9, by = 0.1), y, gp = gpar(col = "grey20"))
 })
 
@@ -140,101 +212,141 @@ geom_path  <- sd_icon({
 })
 
 geom_contour  <- sd_icon({
-  gTree(children = gList(
-    polygonGrob(c(0.45,0.5,0.6, 0.5), c(0.5, 0.4, 0.55, 0.6)),
-    polygonGrob(c(0.25,0.6,0.8, 0.5), c(0.5, 0.2, 0.75, 0.9),
-      gp = gpar(fill = NA))
-  ))
+  gTree(children = gList(polygonGrob(
+    c(0.45, 0.5, 0.6, 0.5), c(0.5, 0.4, 0.55, 0.6)
+  ),
+    polygonGrob(
+      c(0.25, 0.6, 0.8, 0.5), c(0.5, 0.2, 0.75, 0.9),
+      gp = gpar(fill = NA)
+    )))
 })
 
 geom_density2d  <- sd_icon(inherit = "geom_contour")
 
 geom_line  <- sd_icon({
-  pos <- seq(0, 1, length = 5)
+  pos <- seq(0, 1, length.out = 5)
   linesGrob(pos, c(0.2, 0.7, 0.4, 0.8, 0.3))
 })
 
 geom_step  <- sd_icon({
   n <- 15
-  xs <- rep(0:n, each = 2)[-2*(n + 1)] / 15
+  xs <- rep(0:n, each = 2)[-2 * (n + 1)] / 15
   ys <- c(0, rep(1:n, each = 2)) / 15
   linesGrob(xs, ys, gp = gpar(col = "grey20"))
 })
 
 geom_point  <- sd_icon({
-  pos <- seq(0.1, 0.9, length = 6)
-  pointsGrob(x = pos, y = pos, pch = 19,
-    gp = gpar(col = "black", cex = 0.5), default.units = "npc")
+  pos <- seq(0.1, 0.9, length.out = 6)
+  pointsGrob(
+    x = pos,
+    y = pos,
+    pch = 19,
+    gp = gpar(col = "black", cex = 0.5),
+    default.units = "npc"
+  )
 })
 
 geom_jitter  <- sd_icon({
-  pos <- seq(0.1, 0.9, length = 6)
-  pointsGrob(x = pos, y = jitter(pos, 3), pch = 19,
-    gp = gpar(col = "black", cex = 0.5), default.units = "npc")
+  pos <- seq(0.1, 0.9, length.out = 6)
+  pointsGrob(
+    x = pos,
+    y = jitter(pos, 3),
+    pch = 19,
+    gp = gpar(col = "black", cex = 0.5),
+    default.units = "npc"
+  )
 })
 
 geom_pointrange  <- sd_icon({
   gTree(children = gList(
     segmentsGrob(c(0.3, 0.7), c(0.1, 0.2), c(0.3, 0.7), c(0.7, 0.95)),
-    pointsGrob(c(0.3, 0.7), c(0.4, 0.6), pch = 19,
-      gp = gpar(col = "black", cex = 0.5), default.units = "npc")
+    pointsGrob(
+      c(0.3, 0.7),
+      c(0.4, 0.6),
+      pch = 19,
+      gp = gpar(col = "black", cex = 0.5),
+      default.units = "npc"
+    )
   ))
 })
 
 geom_polygon  <- sd_icon({
-  polygonGrob(c(0.1, 0.4, 0.7, 0.9, 0.6, 0.3),
-    c(0.5, 0.8, 0.9, 0.4, 0.2, 0.3), gp = gpar(fill = "grey20", col = NA))
+  polygonGrob(
+    c(0.1, 0.4, 0.7, 0.9, 0.6, 0.3),
+    c(0.5, 0.8, 0.9, 0.4, 0.2, 0.3),
+    gp = gpar(fill = "grey20", col = NA)
+  )
 })
 
 geom_quantile  <- sd_icon({
-  gTree(children = gList(
-    linesGrob(c(0, 0.3, 0.5, 0.8, 1), c(0.8, 0.65, 0.6, 0.6, 0.8)),
-    linesGrob(c(0, 0.3, 0.5, 0.8, 1), c(0.55, 0.45, 0.5, 0.45, 0.55)),
-    linesGrob(c(0, 0.3, 0.5, 0.8, 1), c(0.3, 0.25, 0.4, 0.3, 0.2))
-  ))
+  gTree(children = gList(linesGrob(
+    c(0, 0.3, 0.5, 0.8, 1), c(0.8, 0.65, 0.6, 0.6, 0.8)
+  ),
+    linesGrob(
+      c(0, 0.3, 0.5, 0.8, 1), c(0.55, 0.45, 0.5, 0.45, 0.55)
+    ),
+    linesGrob(
+      c(0, 0.3, 0.5, 0.8, 1), c(0.3, 0.25, 0.4, 0.3, 0.2)
+    )))
 })
 
 geom_raster  <- sd_icon({
-  rectGrob(c(0.25, 0.25, 0.75, 0.75), c(0.25, 0.75, 0.75, 0.25),
-    width = 0.5, height = c(0.67, 0.5, 0.67, 0.5),
-    gp = gpar(col = "grey20", fill = c('#804070', '#668040')))
+  rectGrob(
+    c(0.25, 0.25, 0.75, 0.75),
+    c(0.25, 0.75, 0.75, 0.25),
+    width = 0.5,
+    height = c(0.67, 0.5, 0.67, 0.5),
+    gp = gpar(col = "grey20", fill = c('#804070', '#668040'))
+  )
 })
 
 geom_rect  <- sd_icon({
-  rectGrob(c(0.3, 0.7), c(0.4, 0.8), height = c(0.4, 0.8), width = 0.3,
-    vjust = 1, gp = gpar(fill = "grey20", col = NA))
+  rectGrob(
+    c(0.3, 0.7),
+    c(0.4, 0.8),
+    height = c(0.4, 0.8),
+    width = 0.3,
+    vjust = 1,
+    gp = gpar(fill = "grey20", col = NA)
+  )
 })
 
 geom_ribbon  <- sd_icon({
-  polygonGrob(c(0, 0.3, 0.5, 0.8, 1, 1, 0.8, 0.5, 0.3, 0),
+  polygonGrob(
+    c(0, 0.3, 0.5, 0.8, 1, 1, 0.8, 0.5, 0.3, 0),
     c(0.5, 0.3, 0.4, 0.2, 0.3, 0.7, 0.5, 0.6, 0.5, 0.7),
-    gp = gpar(fill = "grey20", col = NA))
+    gp = gpar(fill = "grey20", col = NA)
+  )
 })
 
 geom_area  <- sd_icon({
-  polygonGrob(c(0, 0,0.3, 0.5, 0.8, 1, 1),
-    c(0, 1,0.5, 0.6, 0.3, 0.8, 0),
+  polygonGrob(c(0, 0, 0.3, 0.5, 0.8, 1, 1),
+    c(0, 1, 0.5, 0.6, 0.3, 0.8, 0),
     gp = gpar(fill = "grey20", col = NA))
 })
 
 geom_density  <- sd_icon({
-  x <- seq(0, 1, length = 80)
+  x <- seq(0, 1, length.out = 80)
   y <- dnorm(x, mean = 0.5, sd = 0.15)
-  linesGrob(x, 0.05 + y / max(y) * 0.9, default = "npc")
+  linesGrob(x, 0.05 + y / max(y) * 0.9, default.units = "npc")
 })
 
 geom_segment  <- sd_icon({
-  segmentsGrob(c(0.1, 0.3, 0.5, 0.7), c(0.3, 0.5, 0.1, 0.9),
-    c(0.2, 0.5, 0.7, 0.9), c(0.8, 0.7, 0.4, 0.3))
+  segmentsGrob(c(0.1, 0.3, 0.5, 0.7),
+    c(0.3, 0.5, 0.1, 0.9),
+    c(0.2, 0.5, 0.7, 0.9),
+    c(0.8, 0.7, 0.4, 0.3))
 })
 
 geom_smooth  <- sd_icon({
-  gTree(children = gList(
-    polygonGrob(c(0, 0.3, 0.5, 0.8, 1, 1, 0.8, 0.5, 0.3, 0),
-      c(0.5, 0.3, 0.4, 0.2, 0.3, 0.7, 0.5, 0.6, 0.5, 0.7),
-      gp = gpar(fill = "grey60", col = NA)),
-    linesGrob(c(0, 0.3, 0.5, 0.8, 1), c(0.6, 0.4, 0.5, 0.4, 0.6))
-  ))
+  gTree(children = gList(polygonGrob(
+    c(0, 0.3, 0.5, 0.8, 1, 1, 0.8, 0.5, 0.3, 0),
+    c(0.5, 0.3, 0.4, 0.2, 0.3, 0.7, 0.5, 0.6, 0.5, 0.7),
+    gp = gpar(fill = "grey60", col = NA)
+  ),
+    linesGrob(
+      c(0, 0.3, 0.5, 0.8, 1), c(0.6, 0.4, 0.5, 0.4, 0.6)
+    )))
 })
 
 geom_text  <- sd_icon({
@@ -242,25 +354,30 @@ geom_text  <- sd_icon({
 })
 
 geom_tile  <- sd_icon({
-  rectGrob(c(0.25, 0.25, 0.75, 0.75), c(0.25, 0.75, 0.75, 0.25),
-    width = 0.5, height = c(0.67, 0.5, 0.67, 0.5),
-    gp = gpar(col = "grey20", fill = c('#804070', '#668040')))
+  rectGrob(
+    c(0.25, 0.25, 0.75, 0.75),
+    c(0.25, 0.75, 0.75, 0.25),
+    width = 0.5,
+    height = c(0.67, 0.5, 0.67, 0.5),
+    gp = gpar(col = "grey20", fill = c('#804070', '#668040'))
+  )
 })
 
 geom_violin  <- sd_icon({
-  y <- seq(-.3, .3, length = 40)
+  y <- seq(-.3, .3, length.out = 40)
   x1 <- dnorm(y, mean = -.15, sd = 0.05) +
     1.5 * dnorm(y, mean = 0.1, sd = 0.1)
-  x2 <- dnorm(y, mean = -.1, sd = 0.1) + dnorm(y, mean = 0.1, sd = 0.1)
+  x2 <-
+    dnorm(y, mean = -.1, sd = 0.1) + dnorm(y, mean = 0.1, sd = 0.1)
 
   y <- c(y, rev(y))
-  x1 <- c(x1, -rev(x1)) / max(8 * x1)
-  x2 <- c(x2, -rev(x2)) / max(8 * x2)
+  x1 <- c(x1,-rev(x1)) / max(8 * x1)
+  x2 <- c(x2,-rev(x2)) / max(8 * x2)
   gp <- gpar(fill = "black")
   gTree(children = gList(
-    polygonGrob(x1 + .30, y + .35, default = "npc", gp = gp),
-    polygonGrob(x2 + .70, y + .55, default = "npc", gp = gp))
-  )
+    polygonGrob(x1 + .30, y + .35, default.units = "npc", gp = gp),
+    polygonGrob(x2 + .70, y + .55, default.units = "npc", gp = gp)
+  ))
 })
 
 geom_vline  <- sd_icon({
@@ -271,99 +388,133 @@ geom_vline  <- sd_icon({
 
 position_dodge  <- sd_icon({
   y <- c(0.5, 0.3)
-  rectGrob(c(0.25, 0.75), y, width = 0.4, height = y,
-    gp = gpar(col = "grey60", fill = c('#804070', '#668040')), vjust = 1)
+  rectGrob(
+    c(0.25, 0.75),
+    y,
+    width = 0.4,
+    height = y,
+    gp = gpar(col = "grey60", fill = c('#804070', '#668040')),
+    vjust = 1
+  )
 })
 
 position_fill  <- sd_icon({
   y <- c(0.5, 0.8)
-  rectGrob(0.5, c(0.625, 1), width = 0.4, height = c(0.625, 0.375),
-    gp = gpar(col = "grey60", fill = c('#804070', '#668040')), vjust = 1)
+  rectGrob(
+    0.5,
+    c(0.625, 1),
+    width = 0.4,
+    height = c(0.625, 0.375),
+    gp = gpar(col = "grey60", fill = c('#804070', '#668040')),
+    vjust = 1
+  )
 })
 
 position_identity  <- sd_icon({
-  rectGrob(0.5, c(0.5, 0.3), width = 0.4, height = c(0.5, 0.3),
-    gp = gpar(col = "grey60", fill = c('#804070', '#668040')), vjust = 1)
+  rectGrob(
+    0.5,
+    c(0.5, 0.3),
+    width = 0.4,
+    height = c(0.5, 0.3),
+    gp = gpar(col = "grey60", fill = c('#804070', '#668040')),
+    vjust = 1
+  )
 })
 
-position_jitter  <- sd_icon(inherit = "geom_jitter" )
+position_jitter  <- sd_icon(inherit = "geom_jitter")
 
 position_stack  <- sd_icon({
   y <- c(0.5, 0.8)
-  rectGrob(0.5, c(0.5, 0.8), width = 0.4, height = c(0.5, 0.3),
-    gp = gpar(col = "grey60", fill = c('#804070', '#668040')), vjust = 1)
+  rectGrob(
+    0.5,
+    c(0.5, 0.8),
+    width = 0.4,
+    height = c(0.5, 0.3),
+    gp = gpar(col = "grey60", fill = c('#804070', '#668040')),
+    vjust = 1
+  )
 })
 
 # Scales -----------------------------------------------------------------------
 
 scale_alpha  <- sd_icon({
   x <- c(0.1, 0.3, 0.5, 0.7, 0.9)
-  rectGrob(x, width=0.25,
-    gp=gpar(fill=scales::alpha("black", x), col=NA)
-  )
+  rectGrob(x,
+    width = 0.25,
+    gp = gpar(fill = scales::alpha("black", x), col = NA))
 })
 
 scale_colour_brewer  <- sd_icon({
-  rectGrob(c(0.1, 0.3, 0.5, 0.7, 0.9), width=0.21,
-    gp=gpar(fill=RColorBrewer::brewer.pal(5, "PuOr"), col=NA)
+  rectGrob(
+    c(0.1, 0.3, 0.5, 0.7, 0.9),
+    width = 0.21,
+    gp = gpar(fill = RColorBrewer::brewer.pal(5, "PuOr"), col = NA)
   )
 })
 
 scale_colour_gradient  <- sd_icon({
   g <- scale_fill_gradient()
-  scale_train(g, 1:5)
-  rectGrob(c(0.1, 0.3, 0.5, 0.7, 0.9), width=0.21,
-    gp=gpar(fill=scale_map(g, 1:5), col=NA)
+  g$train(1:5)
+  rectGrob(
+    c(0.1, 0.3, 0.5, 0.7, 0.9),
+    width = 0.21,
+    gp = gpar(fill = g$map(1:5), col = NA)
   )
 })
 
 scale_colour_gradient2  <- sd_icon({
   g <- scale_fill_gradient2()
-  scale_train(g, 1:5 - 3)
-  rectGrob(c(0.1, 0.3, 0.5, 0.7, 0.9), width=0.21,
-    gp=gpar(fill=scale_map(g, 1:5 - 3), col=NA)
+  g$train(1:5 - 3)
+  rectGrob(
+    c(0.1, 0.3, 0.5, 0.7, 0.9),
+    width = 0.21,
+    gp = gpar(fill = g$map(1:5 - 3), col = NA)
   )
 })
 
 scale_colour_gradientn  <- sd_icon({
   g <- scale_fill_gradientn(colours = rainbow(7))
-  scale_train(g, 1:5)
-  rectGrob(c(0.1, 0.3, 0.5, 0.7, 0.9), width=0.21,
-    gp=gpar(fill = scale_map(g, 1:5), col=NA)
+  g$train(1:5)
+  rectGrob(
+    c(0.1, 0.3, 0.5, 0.7, 0.9),
+    width = 0.21,
+    gp = gpar(fill = g$map(1:5), col = NA)
   )
 })
 
 scale_colour_grey  <- sd_icon({
-  rectGrob(c(0.1, 0.3, 0.5, 0.7, 0.9), width=0.21,
-    gp=gpar(fill=gray(seq(0, 1, length=5)), col=NA)
-  )
+  rectGrob(c(0.1, 0.3, 0.5, 0.7, 0.9),
+    width = 0.21,
+    gp = gpar(fill = gray(seq(0, 1, length.out = 5)), col = NA))
 })
 
 scale_colour_hue  <- sd_icon({
-  rectGrob(c(0.1, 0.3, 0.5, 0.7, 0.9), width=0.21,
-    gp=gpar(fill=hcl(seq(0, 360, length=6)[-6], c=100, l=65), col=NA)
-  )
+  rectGrob(c(0.1, 0.3, 0.5, 0.7, 0.9),
+    width = 0.21,
+    gp = gpar(fill = hcl(
+      seq(0, 360, length.out = 6)[-6], c = 100, l = 65
+    ), col = NA))
 })
 
 scale_identity  <- sd_icon({
-  textGrob("f(x) = x", gp=gpar(cex=1.2))
+  textGrob("f(x) = x", gp = gpar(cex = 1.2))
 })
 
 scale_linetype  <- sd_icon({
-  gTree(children=gList(
-    segmentsGrob(0, 0.25, 1, 0.25, gp=gpar(lty=1)),
-    segmentsGrob(0, 0.50, 1, 0.50, gp=gpar(lty=2)),
-    segmentsGrob(0, 0.75, 1, 0.75, gp=gpar(lty=3))
+  gTree(children = gList(
+    segmentsGrob(0, 0.25, 1, 0.25, gp = gpar(lty = 1)),
+    segmentsGrob(0, 0.50, 1, 0.50, gp = gpar(lty = 2)),
+    segmentsGrob(0, 0.75, 1, 0.75, gp = gpar(lty = 3))
   ))
 })
 
 scale_manual  <- sd_icon({
-  textGrob("DIY", gp=gpar(cex=1.2))
+  textGrob("DIY", gp = gpar(cex = 1.2))
 })
 
 scale_shape  <- sd_icon({
-  gTree(children=gList(
-    circleGrob(0.7, 0.7, r=0.1),
+  gTree(children = gList(
+    circleGrob(0.7, 0.7, r = 0.1),
     segmentsGrob(0.2, 0.3, 0.4, 0.3),
     segmentsGrob(0.3, 0.2, 0.3, 0.4),
     polygonGrob(c(0.2, 0.2, 0.4, 0.4), c(0.8, 0.6, 0.6, 0.8)),
@@ -373,50 +524,53 @@ scale_shape  <- sd_icon({
 
 scale_size  <- sd_icon({
   pos <- c(0.15, 0.3, 0.5, 0.75)
-  circleGrob(pos, pos, r=(c(0.1, 0.2, 0.3, 0.4)/2.5), gp=gpar(fill="grey50", col=NA))
+  circleGrob(pos,
+    pos,
+    r = (c(0.1, 0.2, 0.3, 0.4) / 2.5),
+    gp = gpar(fill = "grey50", col = NA))
 })
 
 scale_x_date  <- sd_icon({
-  textGrob("14/10/1979", gp=gpar(cex=1))
+  textGrob("14/10/1979", gp = gpar(cex = 1))
 })
 
 scale_x_datetime  <- sd_icon({
-  textGrob("14/10/1979\n10:14am", gp=gpar(cex=0.9))
+  textGrob("14/10/1979\n10:14am", gp = gpar(cex = 0.9))
 })
 
 # Statistics -------------------------------------------------------------------
 
-stat_bin  <- sd_icon(inherit = "geom_histogram" )
+stat_bin  <- sd_icon(inherit = "geom_histogram")
 
-stat_bindot  <- sd_icon(inherit = "geom_dotplot" )
+stat_bindot  <- sd_icon(inherit = "geom_dotplot")
 
-stat_boxplot  <- sd_icon(inherit = "geom_boxplot" )
+stat_boxplot  <- sd_icon(inherit = "geom_boxplot")
 
-stat_contour  <- sd_icon(inherit = "geom_contour" )
+stat_contour  <- sd_icon(inherit = "geom_contour")
 
-stat_density2d  <- sd_icon(inherit = "geom_density2d" )
+stat_density2d  <- sd_icon(inherit = "geom_density2d")
 
 stat_ecdf  <- sd_icon(inherit = "geom_step")
 
-stat_density  <- sd_icon(inherit = "geom_density" )
+stat_density  <- sd_icon(inherit = "geom_density")
 
 stat_identity  <- sd_icon({
   textGrob('f(x) = x', gp = gpar(cex = 1.2))
 })
 
-stat_quantile  <- sd_icon(inherit = "geom_quantile" )
+stat_quantile  <- sd_icon(inherit = "geom_quantile")
 
-stat_smooth  <- sd_icon(inherit = "geom_smooth" )
+stat_smooth  <- sd_icon(inherit = "geom_smooth")
 
 stat_sum  <- sd_icon({
   textGrob(expression(Sigma), gp = gpar(cex = 4))
 })
 
 # The line stats will be removed in the future
-stat_abline  <- sd_icon(inherit = "geom_abline" )
+stat_abline  <- sd_icon(inherit = "geom_abline")
 
-stat_vline  <- sd_icon(inherit = "geom_vline" )
+stat_vline  <- sd_icon(inherit = "geom_vline")
 
-stat_hline  <- sd_icon(inherit = "geom_hline" )
+stat_hline  <- sd_icon(inherit = "geom_hline")
 
-stat_ydensity  <- sd_icon(inherit = "geom_violin" )
+stat_ydensity  <- sd_icon(inherit = "geom_violin")
diff --git a/inst/staticdocs/index.r b/inst/staticdocs/index.r
index 9eab5b7..ff2ba23 100644
--- a/inst/staticdocs/index.r
+++ b/inst/staticdocs/index.r
@@ -8,9 +8,11 @@ sd_section("Geoms",
     "geom_blank",
     "geom_boxplot",
     "geom_contour",
+    "geom_count",
+    "geom_curve",
     "geom_crossbar",
     "geom_density",
-    "geom_density2d",
+    "geom_density_2d",
     "geom_dotplot",
     "geom_errorbar",
     "geom_errorbarh",
@@ -19,6 +21,7 @@ sd_section("Geoms",
     "geom_histogram",
     "geom_hline",
     "geom_jitter",
+    "geom_label",
     "geom_line",
     "geom_linerange",
     "geom_map",
@@ -44,27 +47,21 @@ sd_section("Geoms",
 sd_section("Statistics",
   "It's often useful to transform your data before plotting, and that's what statistical transformations do.",
   c(
-    "stat_bin",
-    "stat_bin2d",
-    "stat_bindot",
     "stat_binhex",
-    "stat_boxplot",
     "stat_contour",
     "stat_density",
-    "stat_density2d",
+    "stat_density_2d",
     "stat_ecdf",
+    "stat_ellipse",
     "stat_function",
     "stat_identity",
     "stat_qq",
-    "stat_quantile",
-    "stat_smooth",
     "stat_spoke",
     "stat_sum",
     "stat_summary",
     "stat_summary_hex",
-    "stat_summary2d",
-    "stat_unique",
-    "stat_ydensity"
+    "stat_summary_2d",
+    "stat_unique"
   )
 )
 
@@ -75,6 +72,7 @@ sd_section("Scales",
     "guides",
     "guide_legend",
     "guide_colourbar",
+    "lims",
     "scale_alpha",
     "scale_area",
     "scale_size_area",
@@ -107,6 +105,7 @@ sd_section("Coordinate systems",
     "coord_flip",
     "coord_map",
     "coord_polar",
+    "coord_quickmap",
     "coord_trans"
   )
 )
@@ -117,10 +116,12 @@ sd_section("Faceting",
     "facet_grid",
     "facet_null",
     "facet_wrap",
+    "labeller",
     "label_both",
     "label_bquote",
     "label_parsed",
-    "label_value"
+    "label_value",
+    "label_wrap_gen"
   )
 )
 
@@ -130,8 +131,10 @@ sd_section("Position adjustments",
     "position_dodge",
     "position_fill",
     "position_identity",
+    "position_nudge",
     "position_stack",
-    "position_jitter"
+    "position_jitter",
+    "position_jitterdodge"
   )
 )
 
@@ -140,8 +143,9 @@ sd_section("Data",
   c(
     "diamonds",
     "economics",
+    "faithfuld",
+    "luv_colours",
     "midwest",
-    "movies",
     "mpg",
     "msleep",
     "presidential",
@@ -149,7 +153,7 @@ sd_section("Data",
   )
 )
 
-sd_section("Anotation",
+sd_section("Annotation",
   "Specialised functions for adding annotations to a plot",
   c(
     "annotate",
@@ -183,9 +187,11 @@ sd_section("Themes",
     "element_line",
     "element_rect",
     "element_text",
+    "ggtheme",
     "is.rel",
     "is.theme",
     "opts",
+    "margin",
     "rel",
     "theme",
     "theme_blank",
@@ -213,6 +219,7 @@ sd_section("Plot creation", "",
 sd_section("Aesthetics", "",
   c(
     "aes",
+    "aes_",
     "aes_all",
     "aes_auto",
     "aes_string",
@@ -222,3 +229,12 @@ sd_section("Aesthetics", "",
     "aes_position"
   )
 )
+
+sd_section("ggproto", "",
+  c(
+    "ggproto",
+    "print.ggproto",
+    "is.ggproto",
+    "format.ggproto"
+  )
+)
diff --git a/inst/test_ns/DESCRIPTION b/inst/test_ns/DESCRIPTION
deleted file mode 100644
index 8504940..0000000
--- a/inst/test_ns/DESCRIPTION
+++ /dev/null
@@ -1,12 +0,0 @@
-Package: nstest
-Type: Package
-Title: Test ggplot2 NAMESPACE
-Version: 0.1
-Author: Hadley Wickham <h.wickham at gmail.com>
-Maintainer: Hadley Wickham <h.wickham at gmail.com>
-Description: Check to see if ggplot2 namespace set up correctly.
-Imports:
-    ggplot2
-License: GPL-2
-Collate:
-    'my-plot.r'
diff --git a/inst/test_ns/NAMESPACE b/inst/test_ns/NAMESPACE
deleted file mode 100644
index e04cabf..0000000
--- a/inst/test_ns/NAMESPACE
+++ /dev/null
@@ -1,2 +0,0 @@
-export(my_plot)
-import(ggplot2)
diff --git a/inst/test_ns/R/my-plot.r b/inst/test_ns/R/my-plot.r
deleted file mode 100644
index a826e61..0000000
--- a/inst/test_ns/R/my-plot.r
+++ /dev/null
@@ -1,12 +0,0 @@
-#' Create a plot.
-#'
-#' @export
-#' @import ggplot2
-#' @examples
-#' plot(my_plot())
-my_plot <- function() {
-  df <- data.frame(x = 1:10, y = sample(10), z = runif(1))
-
-  ggplot(df) + geom_point(aes_string(x = "x", y = "y", colour = "z"))
-
-}
diff --git a/inst/test_ns/man/my_plot.Rd b/inst/test_ns/man/my_plot.Rd
deleted file mode 100644
index b4b9715..0000000
--- a/inst/test_ns/man/my_plot.Rd
+++ /dev/null
@@ -1,13 +0,0 @@
-\name{my_plot}
-\alias{my_plot}
-\title{Create a plot.}
-\usage{
-  my_plot()
-}
-\description{
-  Create a plot.
-}
-\examples{
-plot(my_plot())
-}
-
diff --git a/inst/tests/test-aes-grouping.r b/inst/tests/test-aes-grouping.r
deleted file mode 100644
index bfa86de..0000000
--- a/inst/tests/test-aes-grouping.r
+++ /dev/null
@@ -1,71 +0,0 @@
-context("Aesthetics (grouping)")
-
-df <- data.frame(
-  x = 1:4,
-  a = c("a", "a", "b", "b"),
-  b = c("a", "b", "a", "b")
-)
-library(plyr)
-
-group <- function(x) pdata(x)[[1]]$group
-groups <- function(x) length(unique(group(x)))
-
-test_that("one group per combination of discrete vars", {
-  plot <- ggplot(df, aes(x, x)) + geom_point()
-  expect_that(group(plot), equals(c(1, 1, 1, 1)))
-
-  plot <- ggplot(df, aes(x, a)) + geom_point()
-  expect_that(group(plot), equals(c(1, 1, 2, 2)))
-  plot <- ggplot(df, aes(x, b)) + geom_point()
-  expect_that(group(plot), equals(c(1, 2, 1, 2)))
-
-  plot <- ggplot(df, aes(a, b)) + geom_point()
-  expect_that(groups(plot), equals(4))
-})
-
-test_that("label is not used as a grouping var", {
-  plot <- ggplot(df, aes(x, x, label = a)) + geom_point()
-  expect_that(group(plot), equals(c(1, 1, 1, 1)))
-
-  plot <- ggplot(df, aes(x, x, colour = a, label = b)) + geom_point()
-  expect_that(group(plot), equals(c(1, 1, 2, 2)))
-})
-
-test_that("group aesthetic overrides defaults", {
-  plot <- ggplot(df, aes(x, x, group = x)) + geom_point()
-  expect_that(groups(plot), equals(4))
-
-  plot <- ggplot(df, aes(a, b, group = 1)) + geom_point()
-  expect_that(groups(plot), equals(1))
-})
-
-# test_that("group param overrides defaults", {
-#   plot <- ggplot(df, aes(a, b)) + geom_point(group = 1)
-#   expect_that(groups(plot), equals(1))
-# })
-
-test_that("order affects plotting order of points", {
-  base <- ggplot(df, aes(a, x)) + geom_point()
-
-  ord1 <- ggplot_build(base)$data[[1]]
-  ord2 <- ggplot_build(base + aes(order = x))$data[[1]]
-  rev1 <- ggplot_build(base + aes(order = -x))$data[[1]]
-  rev2 <- ggplot_build(base + aes(order = desc(x)))$data[[1]]
-
-  expect_equal(ord1$y, 1:4)
-  expect_equal(ord2$y, 1:4)
-  expect_equal(rev1$y, 4:1)
-  expect_equal(rev2$y, 4:1)
-})
-
-test_that("order affects plotting order of bars", {
-  base <- ggplot(df, aes(a, fill = b)) + geom_bar()
-
-  ord1 <- ggplot_build(base)$data[[1]]
-  ord2 <- ggplot_build(base + aes(order = a))$data[[1]]
-  rev1 <- ggplot_build(base + aes(order = desc(b)))$data[[1]]
-
-  expect_equal(ord1$group, 1:4)
-  expect_equal(ord2$group, 1:4)
-  expect_equal(rev1$group, c(2, 1, 4, 3))
-})
diff --git a/inst/tests/test-aes-setting.r b/inst/tests/test-aes-setting.r
deleted file mode 100644
index be97da0..0000000
--- a/inst/tests/test-aes-setting.r
+++ /dev/null
@@ -1,23 +0,0 @@
-context("Aes - setting values")
-
-test_that("Aesthetic parameters must match length of data", {
-  df <- data.frame(x = 1:5, y = 1:5)
-  p <- ggplot(df, aes(x, y))
-
-  set_colours <- function(colours) {
-    pdf(file=NULL)
-    print(p + geom_point(colour = colours))
-    dev.off()
-  }
-
-  set_colours("red")
-  expect_error(set_colours(rep("red", 2)), "Incompatible lengths")
-  dev.off()  # Need to manually close device because of error
-  expect_error(set_colours(rep("red", 3)), "Incompatible lengths")
-  dev.off()
-  expect_error(set_colours(rep("red", 4)), "Incompatible lengths")
-  dev.off()
-  set_colours(rep("red", 5))
-
-
-})
diff --git a/inst/tests/test-aes.r b/inst/tests/test-aes.r
deleted file mode 100644
index 07449aa..0000000
--- a/inst/tests/test-aes.r
+++ /dev/null
@@ -1,62 +0,0 @@
-context("Creating aesthetic mappings")
-
-test_that("function aes", {
-  expect_equal(aes(x = mpg, y = wt),
-               structure(list(x = bquote(mpg), y = bquote(wt)), class = "uneval"))
-
-  expect_equal(aes(x = mpg ^ 2, y = wt / cyl),
-               structure(list(x = bquote(mpg ^ 2), y = bquote(wt / cyl)), class = "uneval"))
-
-})
-
-test_that("function aes_string", {
-  expect_equal(aes_string(x = "mpg", y = "wt"),
-               structure(list(x = bquote(mpg), y = bquote(wt)), class = "uneval"))
-
-  expect_equal(aes_string(x = "mpg ^ 2", y = "wt / cyl"),
-               structure(list(x = bquote(mpg ^ 2), y = bquote(wt / cyl)), class = "uneval"))
-})
-
-test_that("function aes_all", {
-  expect_equal(aes_all(names(mtcars)),
-               structure(
-                 list(
-                   mpg = bquote(mpg),
-                   cyl = bquote(cyl),
-                   disp = bquote(disp),
-                   hp = bquote(hp),
-                   drat = bquote(drat),
-                   wt = bquote(wt),
-                   qsec = bquote(qsec),
-                   vs = bquote(vs),
-                   am = bquote(am),
-                   gear = bquote(gear),
-                   carb = bquote(carb)),
-                 class = "uneval"))
-
-  expect_equal(aes_all(c("x", "y", "col", "pch")),
-               structure(list(x = bquote(x), y = bquote(y), colour = bquote(col), shape = bquote(pch)), class = "uneval"))
-})
-
-test_that("function aes_auto", {
-  df <- data.frame(x = 1, y = 1, colour = 1, label = 1, pch = 1)
-  expect_equal(aes_auto(df),
-               structure(list(colour = bquote(colour), label = bquote(label), shape = bquote(pch), x = bquote(x), y = bquote(y)), class = "uneval"))
-
-  expect_equal(aes_auto(names(df)),
-               structure(list(colour = bquote(colour), label = bquote(label), shape = bquote(pch), x = bquote(x), y = bquote(y)), class = "uneval"))
-
-  df <- data.frame(xp = 1:3, y = 1:3, colour = 1:3, txt = letters[1:3], foo = 1:3)
-  expect_equal(aes_auto(df, x = xp, label = txt),
-               structure(list(colour = bquote(colour), y = bquote(y), x = bquote(xp), label = bquote(txt)), class = "uneval"))
-  expect_equal(aes_auto(names(df), x = xp, label = txt),
-               structure(list(colour = bquote(colour), y = bquote(y), x = bquote(xp), label = bquote(txt)), class = "uneval"))
-  expect_equal(aes_auto(x = xp, label = txt, data = df),
-               structure(list(colour = bquote(colour), y = bquote(y), x = bquote(xp), label = bquote(txt)), class = "uneval"))
-
-  df <- data.frame(foo = 1:3)
-  expect_equal(aes_auto(df, x = xp, y = yp),
-               structure(list(x = bquote(xp), y = bquote(yp)), class = "uneval"))
-  expect_equal(aes_auto(df), structure(setNames(list(), character(0)), class = "uneval"))
-})
-
diff --git a/inst/tests/test-boxplot.r b/inst/tests/test-boxplot.r
deleted file mode 100644
index 731d4d5..0000000
--- a/inst/tests/test-boxplot.r
+++ /dev/null
@@ -1,13 +0,0 @@
-context("Boxplot")
-
-# thanks wch for providing the test code
-test_that("geom_boxplot range includes all outliers", {
-  dat <- data.frame(x=1, y=c(-(1:20)^3, (1:20)^3) )
-  p <- ggplot_build(ggplot(dat, aes(x,y)) + geom_boxplot())
-
-  miny <- p$panel$ranges[[1]]$y.range[1]
-  maxy <- p$panel$ranges[[1]]$y.range[2]
-
-  expect_true(miny <= min(dat$y))
-  expect_true(maxy >= max(dat$y))
-})
diff --git a/inst/tests/test-build.r b/inst/tests/test-build.r
deleted file mode 100644
index 7770eb1..0000000
--- a/inst/tests/test-build.r
+++ /dev/null
@@ -1,42 +0,0 @@
-# Test the complete path from plot specification to rendered data
-context("Plot building")
-
-df <- data.frame(x = 1:3, y = 3:1, z = letters[1:3])
-
-test_that("there is one data frame for each layer", {
-  l1 <- ggplot(df, aes(x, y)) + geom_point()
-  l2 <- ggplot(df, aes(x, y)) + geom_point() + geom_line()
-  l3 <- ggplot(df, aes(x, y)) + geom_point() + geom_line() + geom_point()
-
-  expect_that(length(pdata(l1)), equals(1))
-  expect_that(length(pdata(l2)), equals(2))
-  expect_that(length(pdata(l3)), equals(3))
-})
-
-test_that("position aesthetics coerced to correct type", {
-  l1 <- ggplot(df, aes(x, y)) + geom_point()
-  d1 <- pdata(l1)[[1]]
-
-  expect_that(d1$x, is_a("numeric"))
-  expect_that(d1$y, is_a("numeric"))
-
-  l2 <- ggplot(df, aes(x, z)) + geom_point() + scale_x_discrete()
-  d2 <- pdata(l2)[[1]]
-
-  expect_that(d2$x, is_a("integer"))
-  expect_that(d2$y, is_a("integer"))
-})
-
-test_that("non-position aesthetics are mapped", {
-  l1 <- ggplot(df, aes(x, y, fill = z, colour = z, shape = z, size = z)) +
-    geom_point()
-  d1 <- pdata(l1)[[1]]
-
-  expect_that(sort(names(d1)), equals(sort(c("x", "y", "fill", "group",
-    "colour", "shape", "size", "PANEL"))))
-
-  l2 <- l1 + scale_colour_manual(values = c("blue", "red", "yellow"))
-  d2 <- pdata(l2)[[1]]
-  expect_that(d2$colour, equals(c("blue", "red", "yellow")))
-})
-
diff --git a/inst/tests/test-empty-data.r b/inst/tests/test-empty-data.r
deleted file mode 100644
index 43303b9..0000000
--- a/inst/tests/test-empty-data.r
+++ /dev/null
@@ -1,131 +0,0 @@
-context('Empty data')
-
-df0 <- data.frame(mpg=numeric(0), wt=numeric(0), am=numeric(0), cyl=numeric(0))
-
-test_that("layers with empty data are silently omitted", {
-  # Empty data (no visible points)
-  d <- pdata(ggplot(df0, aes(x=mpg,y=wt)) + geom_point())
-  expect_equal(nrow(d[[1]]), 0)
-
-  d <- pdata(ggplot() + geom_point(data=df0, aes(x=mpg,y=wt)))
-  expect_equal(nrow(d[[1]]), 0)
-
-
-  # Regular mtcars data, x=mpg, y=wt, normal points and points from empty data frame
-  d <- pdata(ggplot(mtcars, aes(x=mpg, y=wt)) + geom_point() + geom_point(data=df0))
-  expect_equal(nrow(d[[1]]), nrow(mtcars))
-  expect_equal(nrow(d[[2]]), 0)
-
-  # Regular mtcars data, but points only from empty data frame
-  d <- pdata(ggplot(mtcars, aes(x=mpg, y=wt)) + geom_point(data=df0))
-  expect_equal(nrow(d[[1]]), 0)
-})
-
-
-test_that("plots with empty data and vectors for aesthetics work", {
-  # Empty data with x and y mapped to vector of values
-  d <- pdata(qplot(1:5, 1:5))
-  expect_equal(nrow(d[[1]]), 5)
-
-  d <- pdata(ggplot(mapping=aes(x=1:5, y=1:5)) + geom_point())
-  expect_equal(nrow(d[[1]]), 5)
-
-  d <- pdata(ggplot() + geom_point(aes(x=1:5, y=1:5)))
-  expect_equal(nrow(d[[1]]), 5)
-})
-
-
-test_that("layers with empty data are silently omitted with facets", {
-  # Empty data, facet_wrap, throws error
-  expect_error(ggplot_build(ggplot(df0, aes(x=mpg, y=wt)) + geom_point() + facet_wrap(~ cyl)))
-
-  # Empty data, facet_grid, throws error
-  expect_error(ggplot_build(ggplot(df0, aes(x=x, y=y)) + geom_point() + facet_grid(am ~ cyl)))
-
-
-  # points from mtcars points and points from empty data frame, facet_wrap
-  d <- pdata(ggplot(mtcars, aes(x=mpg, y=wt)) + geom_point() + geom_point(data=df0) + facet_wrap(~ cyl))
-  expect_equal(nrow(d[[1]]), nrow(mtcars))
-  expect_equal(nrow(d[[2]]), 0)
-
-  # points from mtcars points and points from empty data frame, facet_grid
-  d <- pdata(ggplot(mtcars, aes(x=mpg, y=wt)) + geom_point() + geom_point(data=df0) + facet_grid(am ~ cyl))
-  expect_equal(nrow(d[[1]]), nrow(mtcars))
-  expect_equal(nrow(d[[2]]), 0)
-})
-
-
-test_that("data is not inherited when when data=data.frame()", {
-  # Should error when totally empty data frame because there's no x and y
-  expect_error(ggplot_build(ggplot(mtcars, aes(x=mpg, y=wt)) + geom_point() +
-    geom_point(data=data.frame())))
-
-
-  # No extra points when x and y vars exist, but are empty
-  d <- pdata(ggplot(mtcars, aes(x=mpg, y=wt)) + geom_point() +
-    geom_point(data = data.frame(mpg=numeric(0), wt=numeric(0))))
-  expect_equal(nrow(d[[1]]), nrow(mtcars))
-  expect_equal(nrow(d[[2]]), 0)
-
-  # No extra points when x and y vars don't exist but are set
-  d <- pdata(ggplot(mtcars, aes(x=mpg, y=wt)) + geom_point() +
-    geom_point(data=data.frame(mpg=numeric(0), wt=numeric(0)), x = 20, y = 3, colour = "red", size = 5))
-  expect_equal(nrow(d[[1]]), nrow(mtcars))
-  expect_equal(nrow(d[[2]]), 0)
-
-  # No extra points when x and y vars exist, but are empty, even when aesthetics are set
-  d <- pdata(ggplot(mtcars, aes(x=mpg, y=wt)) + geom_point() +
-    geom_point(data=data.frame(mpg=numeric(0), wt=numeric(0)), x = 20, y = 3, colour = "red", size = 5))
-  expect_equal(nrow(d[[1]]), nrow(mtcars))
-  expect_equal(nrow(d[[2]]), 0)
-})
-
-
-test_that("data is inherited when data=NULL", {
-  # NULL should inherit data
-  d <- pdata(ggplot(mtcars, aes(x=mpg, y=wt)) + geom_point() +
-    geom_point(data=NULL))
-  expect_equal(nrow(d[[1]]), nrow(mtcars))
-  expect_equal(nrow(d[[2]]), nrow(mtcars))
-
-  # NULL should inherit data when all aesthetics are set
-  d <- pdata(ggplot(mtcars, aes(x=mpg, y=wt)) + geom_point() +
-    geom_point(data=NULL, x = 20, y = 3, colour = "red", size = 5))
-  expect_equal(nrow(d[[1]]), nrow(mtcars))
-  expect_equal(nrow(d[[2]]), nrow(mtcars))
-
-
-  # NULL should inherit data when facet_wrap is used
-  d <- pdata(ggplot(mtcars, aes(x=mpg, y=wt)) + geom_point() +
-    geom_point(data=NULL) +
-    facet_wrap(~ cyl))
-  expect_equal(nrow(d[[1]]), nrow(mtcars))
-  expect_equal(nrow(d[[2]]), nrow(mtcars))
-
-  # NULL should inherit data when all aesthetics are set and facet_wrap is used
-  d <- pdata(ggplot(mtcars, aes(x=mpg, y=wt)) + geom_point() +
-    geom_point(data=NULL, x = 20, y = 3, colour = "red", size = 5) +
-    facet_wrap(~ cyl))
-  expect_equal(nrow(d[[1]]), nrow(mtcars))
-  expect_equal(nrow(d[[2]]), nrow(mtcars))
-  expect_equal(sort(d[[1]]$PANEL), sort(d[[2]]$PANEL))
-
-
-  # NULL should inherit data when facet_grid is used
-  d <- pdata(ggplot(mtcars, aes(x=mpg, y=wt)) + geom_point() +
-    geom_point(data=NULL) +
-    facet_grid(am ~ cyl))
-  expect_equal(nrow(d[[1]]), nrow(mtcars))
-  expect_equal(nrow(d[[2]]), nrow(mtcars))
-
-  # NULL should inherit data when all aesthetics are set and facet_grid is used
-  d <- pdata(ggplot(mtcars, aes(x=mpg, y=wt)) + geom_point() +
-    geom_point(data=NULL, x = 20, y = 3, colour = "red", size = 5) +
-    facet_grid(am ~ cyl))
-  expect_equal(nrow(d[[1]]), nrow(mtcars))
-  expect_equal(nrow(d[[2]]), nrow(mtcars))
-  expect_equal(sort(d[[1]]$PANEL), sort(d[[2]]$PANEL))
-
-  # In the future, the behavior of NULL may change, and a test for waiver will
-  # also be added.
-})
diff --git a/inst/tests/test-layer.r b/inst/tests/test-layer.r
deleted file mode 100644
index 9e24f49..0000000
--- a/inst/tests/test-layer.r
+++ /dev/null
@@ -1,18 +0,0 @@
-context("Layer")
-
-test_that("Bare name surround by .. is calculated", {
-  expect_true(is_calculated_aes(aes(..density..)))
-  expect_true(is_calculated_aes(aes(..DENSITY..)))
-  expect_false(is_calculated_aes(aes(a..x..b)))
-})
-
-test_that("Calling using variable surround by .. is calculated", {
-  expect_true(is_calculated_aes(aes(mean(..density..))))
-  expect_true(is_calculated_aes(aes(mean(..DENSITY..))))
-  expect_false(is_calculated_aes(aes(x=mean(a..x..b))))
-})
-
-test_that("strip_dots remove dots around calculated aesthetics", {
-  expect_equal(strip_dots(aes(x=..density..))$x, quote(density))
-  expect_equal(strip_dots(aes(mean(..density..)))$x, quote(mean(density)))
-})
diff --git a/inst/tests/test-scales-breaks-labels.r b/inst/tests/test-scales-breaks-labels.r
deleted file mode 100644
index 845a5d0..0000000
--- a/inst/tests/test-scales-breaks-labels.r
+++ /dev/null
@@ -1,238 +0,0 @@
-context("Scales: breaks and labels")
-
-test_that("labels match breaks, even when outside limits", {
-  sc <- scale_y_continuous(breaks=1:4, labels=1:4, limits = c(1, 3))
-
-  expect_equal(scale_breaks(sc), c(1:3, NA))
-  expect_equal(scale_labels(sc), 1:4)
-  expect_equal(scale_breaks_minor(sc), c(1, 1.5, 2, 2.5, 3))
-})
-
-
-test_that("labels must match breaks", {
-  expect_that(scale_x_discrete(breaks = 1:3, labels = 1:2),
-    throws_error("unequal lengths"))
-  expect_that(scale_x_continuous(breaks = 1:3, labels = 1:2),
-    throws_error("unequal lengths"))
-})
-
-test_that("labels don't have extra spaces", {
-  labels <- c("a", "abc", "abcdef")
-
-  sc1 <- scale_x_discrete(limits = labels)
-  sc2 <- scale_fill_discrete(limits = labels)
-
-  expect_equal(scale_labels(sc1), labels)
-  expect_equal(scale_labels(sc2), labels)
-
-})
-
-
-test_that("out-of-range breaks are dropped", {
-  # Limits are explicitly specified, automatic labels
-  sc <- scale_x_continuous(breaks=1:5, limits = c(2, 4))
-  bi <- scale_break_info(sc)
-  expect_equal(bi$labels, as.character(2:4))
-  expect_equal(bi$major, c(0, 0.5, 1))
-  expect_equal(bi$major_source, 2:4)
-
-
-  # Limits and labels are explicitly specified
-  sc <- scale_x_continuous(breaks=1:5, labels=letters[1:5], limits = c(2, 4))
-  bi <- scale_break_info(sc)
-  expect_equal(bi$labels, letters[2:4])
-  expect_equal(bi$major, c(0, 0.5, 1))
-  expect_equal(bi$major_source, 2:4)
-
-
-  # Limits are specified, and all breaks are out of range
-  sc <- scale_x_continuous(breaks=c(1,5), labels=letters[c(1,5)], limits = c(2, 4))
-  bi <- scale_break_info(sc)
-  expect_equal(length(bi$labels), 0)
-  expect_equal(length(bi$major), 0)
-  expect_equal(length(bi$major_source), 0)
-
-
-  # limits aren't specified, automatic labels
-  # limits are set by the data
-  sc <- scale_x_continuous(breaks=1:5)
-  scale_train_df(sc, data.frame(x=2:4))
-  bi <- scale_break_info(sc)
-  expect_equal(bi$labels, as.character(2:4))
-  expect_equal(bi$major_source, 2:4)
-  expect_equal(bi$major, c(0, 0.5, 1))
-
-
-  # Limits and labels are specified
-  sc <- scale_x_continuous(breaks=1:5, labels=letters[1:5])
-  scale_train_df(sc, data.frame(x=2:4))
-  bi <- scale_break_info(sc)
-  expect_equal(bi$labels, letters[2:4])
-  expect_equal(bi$major_source, 2:4)
-  expect_equal(bi$major, c(0, 0.5, 1))
-
-
-  # Limits aren't specified, and all breaks are out of range of data
-  sc <- scale_x_continuous(breaks=c(1,5), labels=letters[c(1,5)])
-  scale_train_df(sc, data.frame(x=2:4))
-  bi <- scale_break_info(sc)
-  expect_equal(length(bi$labels), 0)
-  expect_equal(length(bi$major), 0)
-  expect_equal(length(bi$major_source), 0)
-})
-
-
-test_that("no minor breaks when only one break", {
-  sc1 <- scale_x_discrete(limits = "a")
-  sc2 <- scale_x_continuous(limits = 1)
-
-  expect_equal(length(scale_breaks_minor(sc1)), 0)
-  expect_equal(length(scale_breaks_minor(sc2)), 0)
-
-})
-
-init_scale <- function(...) {
-  sc <- scale_x_discrete(...)
-  scale_train(sc, factor(1:100))
-  expect_that(length(scale_limits(sc)), equals(100))
-  sc
-}
-
-test_that("discrete labels match breaks", {
-
-  sc <- init_scale(breaks = 0:5 * 10)
-  expect_equal(length(scale_breaks(sc)), 5)
-  expect_equal(length(scale_labels(sc)), 5)
-  expect_equivalent(scale_labels(sc), scale_breaks(sc))
-
-  sc <- init_scale(breaks = 0:5 * 10, labels = letters[1:6])
-  expect_equal(length(scale_breaks(sc)), 5)
-  expect_equal(length(scale_labels(sc)), 5)
-  expect_equal(scale_labels(sc), letters[2:6])
-
-  sc <- init_scale(breaks = 0:5 * 10, labels =
-    function(x) paste(x, "-", sep = ""))
-  expect_equal(scale_labels(sc), c("10-", "20-", "30-", "40-", "50-"))
-
-  pick_5 <- function(x) sample(x, 5)
-  sc <- init_scale(breaks = pick_5)
-  expect_equal(length(scale_breaks(sc)), 5)
-  expect_equal(length(scale_labels(sc)), 5)
-
-})
-
-
-test_that("scale breaks with numeric log transformation", {
-  sc <- scale_x_continuous(limits = c(1, 1e5), trans = log10_trans())
-  expect_equal(scale_breaks(sc), c(0, 2, 4)) # 1, 100, 10000
-  expect_equal(scale_breaks_minor(sc), c(0, 1, 2, 3, 4, 5))
-})
-
-test_that("continuous scales with no data have no breaks or labels", {
-  sc <- scale_x_continuous()
-
-  expect_equal(scale_breaks(sc), numeric())
-  expect_equal(scale_labels(sc), character())
-  expect_equal(scale_limits(sc), c(0, 1))
-
-})
-
-test_that("discrete scales with no data have no breaks or labels", {
-  sc <- scale_x_discrete()
-
-  expect_equal(scale_breaks(sc), numeric())
-  expect_equal(scale_labels(sc), character())
-  expect_equal(scale_limits(sc), c(0, 1))
-})
-
-test_that("suppressing breaks, minor_breask, and labels", {
-  expect_equal(scale_breaks(scale_x_continuous(breaks = NULL, limits = c(1, 3))), NULL)
-  expect_equal(scale_breaks(scale_x_discrete(breaks = NULL, limits = c(1, 3))), NULL)
-  expect_equal(scale_breaks_minor(scale_x_continuous(minor_breaks = NULL, limits = c(1, 3))), NULL)
-
-  expect_equal(scale_labels(scale_x_continuous(labels = NULL, limits = c(1, 3))), NULL)
-  expect_equal(scale_labels(scale_x_discrete(labels = NULL, limits = c(1, 3))), NULL)
-
-  # date, datetime
-  lims <- as.Date(c("2000/1/1", "2000/2/1"))
-  expect_equal(scale_breaks(scale_x_date(breaks = NULL, limits = lims)), NULL)
-  # NA is defunct, should throw error
-  expect_error(scale_breaks(scale_x_date(breaks = NA, limits = lims)))
-  expect_equal(scale_labels(scale_x_date(labels = NULL, limits = lims)), NULL)
-  expect_error(scale_labels(scale_x_date(labels = NA, limits = lims)))
-  expect_equal(scale_breaks_minor(scale_x_date(minor_breaks= NULL, limits = lims)), NULL)
-  expect_error(scale_breaks_minor(scale_x_date(minor_breaks = NA, limits = lims)))
-
-  # date, datetime
-  lims <- as.POSIXct(c("2000/1/1 0:0:0", "2010/1/1 0:0:0"))
-  expect_equal(scale_breaks(scale_x_datetime(breaks = NULL, limits = lims)), NULL)
-  expect_error(scale_breaks(scale_x_datetime(breaks = NA, limits = lims)))
-  expect_equal(scale_labels(scale_x_datetime(labels = NULL, limits = lims)), NULL)
-  expect_error(scale_labels(scale_x_datetime(labels = NA, limits = lims)))
-  expect_equal(scale_breaks_minor(scale_x_datetime(minor_breaks= NULL, limits = lims)), NULL)
-  expect_error(scale_breaks_minor(scale_x_datetime(minor_breaks= NA, limits = lims)))
-
-})
-
-test_that("scale_breaks with explicit NA options (deprecated)", {
-  # NA is defunct, should throw error
-
-  # X
-  sxc <- scale_x_continuous(breaks=NA)
-  scale_train(sxc, 1:3)
-  expect_error(scale_breaks(sxc))
-  expect_error(scale_breaks_minor(sxc))
-
-  # Y
-  syc <- scale_y_continuous(breaks=NA)
-  scale_train(syc, 1:3)
-  expect_error(scale_breaks(syc))
-  expect_error(scale_breaks_minor(syc))
-
-  # Alpha
-  sac <- scale_alpha_continuous(breaks=NA)
-  scale_train(sac,1:3)
-  expect_error(scale_breaks(sac))
-
-  # Size
-  ssc <- scale_size_continuous(breaks=NA)
-  scale_train(ssc,1:3)
-  expect_error(scale_breaks(ssc))
-
-  # Fill
-  sfc <- scale_fill_continuous(breaks=NA)
-  scale_train(sfc,1:3)
-  expect_error(scale_breaks(sfc))
-
-  # Colour
-  scc <- scale_colour_continuous(breaks=NA)
-  scale_train(scc,1:3)
-  expect_error(scale_breaks(scc))
-
-})
-
-
-test_that("breaks can be specified by names of labels", {
-  labels <- setNames(LETTERS[1:4], letters[1:4])
-
-  s <- scale_x_discrete(limits = letters[1:4], labels = labels)
-  expect_equal(as.vector(scale_breaks(s)), letters[1:4])
-  expect_equal(as.vector(scale_labels(s)), LETTERS[1:4])
-
-  s <- scale_x_discrete(limits = letters[1:4], labels = rev(labels))
-  expect_equal(as.vector(scale_breaks(s)), letters[1:4])
-  expect_equal(as.vector(scale_labels(s)), LETTERS[1:4])
-
-  s <- scale_x_discrete(limits = letters[1:4], labels = labels[1:2])
-  expect_equal(as.vector(scale_breaks(s)), letters[1:4])
-  expect_equal(as.vector(scale_labels(s)), c("A", "B", "c", "d"))
-
-  s <- scale_x_discrete(limits = letters[1:4], labels = labels[3:4])
-  expect_equal(as.vector(scale_breaks(s)), letters[1:4])
-  expect_equal(as.vector(scale_labels(s)), c("a", "b", "C", "D"))
-
-  s <- scale_x_discrete(limits = letters[1:3], labels = labels)
-  expect_equal(as.vector(scale_breaks(s)), letters[1:3])
-  expect_equal(as.vector(scale_labels(s)), LETTERS[1:3])
-
-})
diff --git a/inst/tests/test-stats.r b/inst/tests/test-stats.r
deleted file mode 100644
index faa0197..0000000
--- a/inst/tests/test-stats.r
+++ /dev/null
@@ -1,136 +0,0 @@
-context("Stats")
-
-test_that("plot succeeds even if some computation fails", {
-  p1 <- ggplot(mtcars, aes(disp, mpg)) +
-    geom_point() +
-    facet_grid(gear ~ carb)
-  p2 <- p1 + geom_smooth()
-
-  b1 <- ggplot_build(p1)
-  expect_equal(length(b1$data), 1)
-
-  expect_warning(b2 <- ggplot_build(p2))
-  expect_equal(length(b2$data), 2)
-
-})
-
-
-# helper function for stat calc tests.
-test_stat <- function(stat) {
-  stat$data <- transform(stat$data, PANEL = 1)
-  dat <- stat$compute_aesthetics(stat$data, ggplot())
-  dat <- add_group(dat)
-  stat$calc_statistic(dat, NULL)
-}
-
-context("stat-bin")
-
-test_that("stat_sum", {
-  dat <- data.frame(x = c("a", "b", "c"), y = c(1, 5, 10))
-
-  # Should get an error when mapping/setting y and also using stat_bin
-  # But errors caught by internal tryCatch :()
-#   expect_error(ggplot_build(ggplot(dat, aes(x=x, y=y)) + geom_bar()),
-#     "Mapping a variable to y and also using stat=\"bin\"")
-#   expect_error(p <- ggplot_build(ggplot(dat, aes(x=x, y=y)) + geom_bar(stat="bin")),
-#     "Mapping a variable to y and also using stat=\"bin\"")
-#
-#   expect_error(p <- ggplot_build(ggplot(dat, aes(x=x)) + geom_bar(y=5)),
-#     "Mapping a variable to y and also using stat=\"bin\"")
-
-  # This gives an error  (it would probably be OK if just one
-  # of these happened, but this test looks for both)
-  dat2 <- data.frame(x = c("a", "b", "c", "a", "b", "c"), y = c(1, 5, 10, 2, 3, 4))
-#  expect_error(
-#     p <- ggplot_build(ggplot(dat2, aes(x=x, y=y)) + geom_bar()))
-})
-
-
-context("stat-sum")
-
-test_that("stat_sum", {
-  d <- diamonds[1:1000, ]
-  all_ones <- function(x) all.equal(mean(x), 1)
-
-  ret <- test_stat(stat_sum(aes(x = cut, y = clarity), data =  d))
-  expect_equal(dim(ret), c(38, 5))
-  expect_equal(sum(ret$n), nrow(d))
-  expect_true(all_ones(ret$prop))
-
-  ret <- test_stat(stat_sum(aes(x = cut, y = clarity, group = 1), data =  d))
-  expect_equal(dim(ret), c(38, 5))
-  expect_equal(sum(ret$n), nrow(d))
-  expect_equal(sum(ret$prop), 1)
-
-  ret <- test_stat(stat_sum(aes(x = cut, y = clarity, group = cut), data =  d))
-  expect_equal(dim(ret), c(38, 5))
-  expect_equal(sum(ret$n), nrow(d))
-  expect_true(all_ones(tapply(ret$prop, ret$x, FUN = sum)))
-
-  ret <- test_stat(stat_sum(aes(x = cut, y = clarity, group = cut, colour = cut), data =  d))
-  expect_equal(dim(ret), c(38, 6))
-  expect_equal(ret$x, ret$colour)
-  expect_equal(sum(ret$n), nrow(d))
-  expect_true(all_ones(tapply(ret$prop, ret$x, FUN = sum)))
-
-  ret <- test_stat(stat_sum(aes(x = cut, y = clarity, group = clarity), data =  d))
-  expect_equal(dim(ret), c(38, 5))
-  expect_equal(sum(ret$n), nrow(d))
-  expect_true(all_ones(tapply(ret$prop, ret$y, FUN = sum)))
-
-  ret <- test_stat(stat_sum(aes(x = cut, y = clarity, group = clarity, colour = cut), data =  d))
-  expect_equal(dim(ret), c(38, 6))
-  expect_equal(ret$x, ret$colour)
-  expect_equal(sum(ret$n), nrow(d))
-  expect_true(all_ones(tapply(ret$prop, ret$y, FUN = sum)))
-
-  ret <- test_stat(stat_sum(aes(x = cut, y = clarity, group = 1, weight = price), data =  d))
-  expect_equal(dim(ret), c(38, 5))
-  expect_equal(sum(ret$n), sum(d$price))
-  expect_equal(sum(ret$prop), 1)
-})
-
-# helper function for stat calc tests.
-test_stat_scale <- function(stat, scale) {
-  stat$data <- transform(stat$data, PANEL = 1)
-  dat <- stat$compute_aesthetics(stat$data, ggplot())
-  dat <- add_group(dat)
-  stat$calc_statistic(dat, scale)
-}
-
-context("stat-bin2d")
-
-test_that("stat-bin2d", {
-  d <- diamonds[1:1000,]
-
-  full_scales <- list(x = scale_x_continuous(limits = range(d$carat, na.rm=TRUE)),
-                      y = scale_y_continuous(limits = range(d$depth, na.rm=TRUE)))
-  ret <- test_stat_scale(stat_bin2d(aes(x = carat, y = depth), data=d), full_scales)
-  expect_equal(dim(ret), c(191,12))
-
-  d$carat[1] <- NA
-  d$depth[2] <- NA
-
-  full_scales <- list(x = scale_x_continuous(limits = range(d$carat, na.rm=TRUE)),
-                      y = scale_y_continuous(limits = range(d$depth, na.rm=TRUE)))
-  ret <- test_stat_scale(stat_bin2d(aes(x = carat, y = depth), data=d), full_scales)
-  expect_equal(dim(ret), c(191,12))
-})
-
-
-context("stat-density2d")
-
-test_that("stat-density2d", {
-
-  full_scales <- list(x = scale_x_continuous(limits=c(1,6)),
-                      y = scale_y_continuous(limits=c(5,40)))
-  ret <- test_stat_scale(stat_density2d(aes(x = wt, y = mpg), data = mtcars), full_scales)
-  # Check that the contour data goes beyond data range.
-  # The specific values below are sort of arbitrary; but they go beyond the range
-  # of the data
-  expect_true(min(ret$x) < 1.2)
-  expect_true(max(ret$x) > 5.8)
-  expect_true(min(ret$y) < 8)
-  expect_true(max(ret$y) > 35)
-
-})
diff --git a/inst/tests/test-utilities.r b/inst/tests/test-utilities.r
deleted file mode 100644
index 7fc357a..0000000
--- a/inst/tests/test-utilities.r
+++ /dev/null
@@ -1,22 +0,0 @@
-context("Utilities")
-
-test_that("finite.cases.data.frame", {
-  # All finite --------------------------------------------------------------
-  expect_identical(finite.cases(data.frame(x=4)),            TRUE)          # 1x1
-  expect_identical(finite.cases(data.frame(x=4, y=11)),      TRUE)          # 1x2
-  expect_identical(finite.cases(data.frame(x=4:5)),          c(TRUE, TRUE)) # 2x1
-  expect_identical(finite.cases(data.frame(x=4:5, y=11:12)), c(TRUE, TRUE)) # 2x2
-
-  # Has one NA --------------------------------------------------------------
-  expect_identical(finite.cases(data.frame(x=NA)),                  FALSE)           # 1x1
-  expect_identical(finite.cases(data.frame(x=4, y=NA)),             FALSE)           # 1x2
-  expect_identical(finite.cases(data.frame(x=c(4,NA))),             c(TRUE,  FALSE)) # 2x1
-  expect_identical(finite.cases(data.frame(x=c(4,NA), y=c(11,NA))), c(TRUE,  FALSE)) # 2x2
-  expect_identical(finite.cases(data.frame(x=c(4,NA), y=c(NA,12))), c(FALSE, FALSE)) # 2x2
-  expect_identical(finite.cases(data.frame(x=c(4,5),  y=c(NA,12))), c(FALSE, TRUE))  # 2x2
-
-  # Testing NaN and Inf, using miscellaneous data shapes --------------------
-  expect_identical(finite.cases(data.frame(x=c(4,NaN))),              c(TRUE, FALSE))
-  expect_identical(finite.cases(data.frame(x=Inf)),                   FALSE)
-  expect_identical(finite.cases(data.frame(x=c(4,5),  y=c(-Inf,12))), c(FALSE, TRUE))
-})
diff --git a/man/absoluteGrob.Rd b/man/absoluteGrob.Rd
index 3e2d16f..dae8332 100644
--- a/man/absoluteGrob.Rd
+++ b/man/absoluteGrob.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/grob-absolute.r
 \name{absoluteGrob}
 \alias{absoluteGrob}
@@ -8,7 +8,7 @@ absoluteGrob(grob, width = NULL, height = NULL, xmin = NULL,
   ymin = NULL, vp = NULL)
 }
 \description{
-This grob has fixed dimesions and position.
+This grob has fixed dimensions and position.
 }
 \details{
 It's still experimental
diff --git a/man/add_theme.Rd b/man/add_theme.Rd
index f7a5e7e..9c3680e 100644
--- a/man/add_theme.Rd
+++ b/man/add_theme.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/theme.r
 \name{add_theme}
 \alias{add_theme}
@@ -12,7 +12,7 @@ add_theme(t1, t2, t2name)
 \item{t2}{A theme object that is to be added to \code{t1}}
 
 \item{t2name}{A name of the t2 object. This is used for printing
-  informative error messages.}
+informative error messages.}
 }
 \description{
 Modify properties of an element in a theme object
diff --git a/man/aes.Rd b/man/aes.Rd
index e753842..93787b9 100644
--- a/man/aes.Rd
+++ b/man/aes.Rd
@@ -1,31 +1,50 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/aes.r
 \name{aes}
 \alias{aes}
-\title{Generate aesthetic mappings that describe how variables in the data are
-mapped to visual properties (aesthetics) of geoms.}
+\title{Define aesthetic mappings.}
 \usage{
 aes(x, y, ...)
 }
 \arguments{
-\item{x,y,...}{List of name value pairs giving aesthetics to map.}
+\item{x, y, ...}{List of name value pairs giving aesthetics to map to
+variables. The names for x and y aesthetics can be omitted (because
+they are so common); all other aesthetics must be named.}
 }
 \description{
-\code{aes} creates a list of unevaluated expressions.  This function also
-performs partial name matching, converts color to colour, and old style R
-names to ggplot names (eg. pch to shape, cex to size)
+Generate aesthetic mappings that describe how variables in the data are
+mapped to visual properties (aesthetics) of geoms. This function also
+standardise aesthetic names by performs partial name matching, converting
+color to colour, and old style R names to ggplot names (eg. pch to shape,
+cex to size)
 }
 \examples{
 aes(x = mpg, y = wt)
+aes(mpg, wt)
+
+# You can also map aesthetics to functions of variables
 aes(x = mpg ^ 2, y = wt / cyl)
+
+# Aesthetic names are automatically standardised
+aes(col = x)
+aes(fg = x)
+aes(color = x)
+aes(colour = x)
+
+# aes is almost always used with ggplot() or a layer
+ggplot(mpg, aes(displ, hwy)) + geom_point()
+ggplot(mpg) + geom_point(aes(displ, hwy))
+
+# Aesthetics supplied to ggplot() are used as defaults for every layer
+# you can override them, or supply different aesthetics for each layer
 }
 \seealso{
+See \code{\link{aes_q}}/\code{\link{aes_string}} for standard
+  evaluation versions of \code{aes}.
+
 See
    \code{\link{aes_colour_fill_alpha}}, \code{\link{aes_group_order}},
    \code{\link{aes_linetype_size_shape}} and \code{\link{aes_position}}
    for more specific examples with different aesthetics.
-
-Other aesthetic generators: \code{\link{aes_q}},
-  \code{\link{aes_string}}
 }
 
diff --git a/man/aes_.Rd b/man/aes_.Rd
new file mode 100644
index 0000000..eeff48f
--- /dev/null
+++ b/man/aes_.Rd
@@ -0,0 +1,58 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/aes.r
+\name{aes_}
+\alias{aes_}
+\alias{aes_q}
+\alias{aes_string}
+\title{Define aesthetic mappings from strings, or quoted calls and formulas.}
+\usage{
+aes_(x, y, ...)
+
+aes_string(x, y, ...)
+
+aes_q(x, y, ...)
+}
+\arguments{
+\item{x, y, ...}{List of name value pairs. Elements must be either
+quoted calls, strings, one-sided formulas or constants.}
+}
+\description{
+Aesthetic mappings describe how variables in the data are mapped to visual
+properties (aesthetics) of geoms. \code{\link{aes}} uses non-standard
+evaluation to capture the variable names. \code{aes_} and \code{aes_string}
+require you to explicitly quote the inputs either with \code{""} for
+\code{aes_string()}, or with \code{quote} or \code{~} for \code{aes_()}.
+(\code{aes_q} is an alias to \code{aeq_})
+}
+\details{
+It's better to use \code{aes_q()}, because there's no easy way to create the
+equivalent to \code{aes(colour = "my colour")} or \code{aes{x = `X$1`}}
+with \code{aes_string()}.
+
+\code{aes_string} and \code{aes_} are particularly useful when writing
+functions that create plots because you can use strings or quoted
+names/calls to define the aesthetic mappings, rather than having to use
+\code{\link{substitute}} to generate a call to \code{aes()}.
+}
+\examples{
+# Three ways of generating the same aesthetics
+aes(mpg, wt, col = cyl)
+aes_(quote(mpg), quote(wt), col = quote(cyl))
+aes_(~mpg, ~wt, col = ~cyl)
+aes_string("mpg", "wt", col = "cyl")
+
+# You can't easily mimic these calls with aes_string
+aes(`$100`, colour = "smooth")
+aes_(~ `$100`, colour = "smooth")
+# Ok, you can, but it requires a _lot_ of quotes
+aes_string("`$100`", colour = '"smooth"')
+
+# Convert strings to names with as.name
+var <- "cyl"
+aes(col = x)
+aes_(col = as.name(var))
+}
+\seealso{
+\code{\link{aes}}
+}
+
diff --git a/man/aes_all.Rd b/man/aes_all.Rd
index c96aca3..2aba9e6 100644
--- a/man/aes_all.Rd
+++ b/man/aes_all.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/aes.r
 \name{aes_all}
 \alias{aes_all}
@@ -16,4 +16,5 @@ Given a character vector, create a set of identity mappings
 aes_all(names(mtcars))
 aes_all(c("x", "y", "col", "pch"))
 }
+\keyword{internal}
 
diff --git a/man/aes_auto.Rd b/man/aes_auto.Rd
index 60d3f10..9533ce5 100644
--- a/man/aes_auto.Rd
+++ b/man/aes_auto.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/aes.r
 \name{aes_auto}
 \alias{aes_auto}
@@ -14,17 +14,5 @@ aes_auto(data = NULL, ...)
 \description{
 Automatic aesthetic mapping
 }
-\examples{
-df <- data.frame(x = 1, y = 1, colour = 1, label = 1, pch = 1)
-aes_auto(df)
-aes_auto(names(df))
-
-df <- data.frame(xp = 1, y = 1, colour = 1, txt = 1, foo = 1)
-aes_auto(df, x = xp, label = txt)
-aes_auto(names(df), x = xp, label = txt)
-
-df <- data.frame(foo = 1:3)
-aes_auto(df, x = xp, y = yp)
-aes_auto(df)
-}
+\keyword{internal}
 
diff --git a/man/aes_colour_fill_alpha.Rd b/man/aes_colour_fill_alpha.Rd
index 3bbe3ce..d7211fb 100644
--- a/man/aes_colour_fill_alpha.Rd
+++ b/man/aes_colour_fill_alpha.Rd
@@ -1,8 +1,7 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/aes-colour-fill-alpha.r
 \name{aes_colour_fill_alpha}
 \alias{aes_colour_fill_alpha}
-\alias{alpha}
 \alias{color}
 \alias{colour}
 \alias{fill}
@@ -26,14 +25,14 @@ c + geom_bar(colour = "red")
 c + geom_bar(fill = "white", colour = "red")
 
 # The aesthetic fill also takes different colouring scales
-# setting fill equal to a factor varible uses a discrete colour scale
+# setting fill equal to a factor variable uses a discrete colour scale
 k <- ggplot(mtcars, aes(factor(cyl), fill = factor(vs)))
 k + geom_bar()
 
 # Fill aesthetic can also be used with a continuous variable
-m <- ggplot(movies, aes(x = rating))
-m + geom_histogram()
-m + geom_histogram(aes(fill = ..count..))
+m <- ggplot(faithfuld, aes(waiting, eruptions))
+m + geom_raster()
+m + geom_raster(aes(fill = density))
 
 # Some geoms don't use both aesthetics (i.e. geom_point or geom_line)
 b <- ggplot(economics, aes(x = date, y = unemploy))
@@ -50,10 +49,6 @@ h + geom_point()
 h + geom_point(alpha = 0.5)
 h + geom_point(alpha = 1/10)
 
-#If a geom uses both fill and colour, alpha will only modify the fill colour
-c + geom_bar(fill = "dark grey", colour = "black")
-c + geom_bar(fill = "dark grey", colour = "black", alpha = 1/3)
-
 # Alpha can also be used to add shading
 j <- b + geom_line()
 j
@@ -61,7 +56,6 @@ yrng <- range(economics$unemploy)
 j <- j + geom_rect(aes(NULL, NULL, xmin = start, xmax = end, fill = party),
 ymin = yrng[1], ymax = yrng[2], data = presidential)
 j
-library(scales) # to access the alpha function
 j + scale_fill_manual(values = alpha(c("blue", "red"), .3))
 }
 }
diff --git a/man/aes_group_order.Rd b/man/aes_group_order.Rd
index f558007..c54f680 100644
--- a/man/aes_group_order.Rd
+++ b/man/aes_group_order.Rd
@@ -1,12 +1,11 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/aes-group-order.r
 \name{aes_group_order}
 \alias{aes_group_order}
 \alias{group}
-\alias{order}
-\title{Aesthetics: group, order}
+\title{Aesthetics: group}
 \description{
-Aesthetics: group, order
+Aesthetics: group
 }
 \examples{
 \donttest{
@@ -35,13 +34,11 @@ a + geom_bar(aes(fill = factor(cyl)))
 a + geom_bar(aes(fill = factor(vs)))
 
 # Using linetypes
-library(reshape2) # for melt
-library(plyr) # for colwise
 rescale01 <- function(x) (x - min(x)) / diff(range(x))
 ec_scaled <- data.frame(
   date = economics$date,
-  colwise(rescale01)(economics[, -(1:2)]))
-ecm <- melt(ec_scaled, id = "date")
+  plyr::colwise(rescale01)(economics[, -(1:2)]))
+ecm <- reshape2::melt(ec_scaled, id.vars = "date")
 f <- ggplot(ecm, aes(date, value))
 f + geom_line(aes(linetype = variable))
 
@@ -56,8 +53,7 @@ k + facet_grid(. ~ cut)
 # occasions (Occasion).
 
 # Multiple groups with one aesthetic
-library(nlme)
-h <- ggplot(Oxboys, aes(age, height))
+h <- ggplot(nlme::Oxboys, aes(age, height))
 # A single line tries to connect all the observations
 h + geom_line()
 # The group aesthetic maps a different line for each subject
@@ -77,23 +73,13 @@ h + geom_smooth(aes(group = 1), size = 2, method = "lm", se = FALSE)
 # groups. This is the strategy used in interaction plots, profile plots, and parallel
 # coordinate plots, among others. For example, we draw boxplots of height at
 # each measurement occasion
-boysbox <- ggplot(Oxboys, aes(Occasion, height))
+boysbox <- ggplot(nlme::Oxboys, aes(Occasion, height))
 boysbox + geom_boxplot()
 # There is no need to specify the group aesthetic here; the default grouping
 # works because occasion is a discrete variable. To overlay individual trajectories
 # we again need to override the default grouping for that layer with aes(group = Subject)
 boysbox <- boysbox + geom_boxplot()
 boysbox + geom_line(aes(group = Subject), colour = "blue")
-
-# Use the order aesthetic to change stacking order of bar charts
-w <- ggplot(diamonds, aes(clarity, fill = cut))
-w + geom_bar()
-w + geom_bar(aes(order = desc(cut)))
-
-# Can also be used to change plot order of scatter plots
-d <- ggplot(diamonds, aes(carat, price, colour = cut))
-d + geom_point()
-d + geom_point(aes(order = sample(seq_along(carat))))
 }
 }
 
diff --git a/man/aes_linetype_size_shape.Rd b/man/aes_linetype_size_shape.Rd
index a60e118..d6025b1 100644
--- a/man/aes_linetype_size_shape.Rd
+++ b/man/aes_linetype_size_shape.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/aes-linetype-size-shape.r
 \name{aes_linetype_size_shape}
 \alias{aes_linetype_size_shape}
@@ -11,30 +11,26 @@ This page demonstrates the usage of a sub-group
 of aesthetics; linetype, size and shape.
 }
 \examples{
+
 # Line types should be specified with either an integer, a name, or with a string of
-# an even number (up to eight) of hexidecimal digits which give the lengths in
+# an even number (up to eight) of hexadecimal digits which give the lengths in
 # consecutive positions in the string.
 # 0 = blank, 1 = solid, 2 = dashed, 3 = dotted, 4 = dotdash, 5 = longdash, 6 = twodash
 
 # Data
 df <- data.frame(x = 1:10 , y = 1:10)
-f <- ggplot(df, aes(x = x, y = y))
+f <- ggplot(df, aes(x, y))
 f + geom_line(linetype = 2)
 f + geom_line(linetype = "dotdash")
+
 # An example with hex strings, the string "33" specifies three units on followed
 # by three off and "3313" specifies three units on followed by three off followed
 # by one on and finally three off.
 f + geom_line(linetype = "3313")
 
 # Mapping line type from a variable
-library(plyr)
-library(reshape2)
-rescale01 <- function(x) (x - min(x)) / diff(range(x))
-ec_scaled <- data.frame(
-  date = economics$date,
-  colwise(rescale01)(economics[, -(1:2)]))
-ecm <- melt(ec_scaled, id = "date")
-qplot(date, value, data = ecm, geom = "line", linetype = variable)
+ggplot(economics_long, aes(date, value01)) +
+  geom_line(aes(linetype = variable))
 
 # Size examples
 # Should be specified with a numerical value (in millimetres),
@@ -42,7 +38,8 @@ qplot(date, value, data = ecm, geom = "line", linetype = variable)
 p <- ggplot(mtcars, aes(wt, mpg))
 p + geom_point(size = 4)
 p + geom_point(aes(size = qsec))
-p + geom_point(size = 2.5) + geom_hline(yintercept = 25, size = 3.5)
+p + geom_point(size = 2.5) +
+  geom_hline(yintercept = 25, size = 3.5)
 
 # Shape examples
 # Shape takes four types of values: an integer in [0, 25],
@@ -60,8 +57,9 @@ p + geom_point(aes(shape = factor(cyl)))
 
 # A look at all 25 symbols
 df2 <- data.frame(x = 1:5 , y = 1:25, z = 1:25)
-s <- ggplot(df2, aes(x = x, y = y))
-s + geom_point(aes(shape = z), size = 4) + scale_shape_identity()
+s <- ggplot(df2, aes(x, y))
+s + geom_point(aes(shape = z), size = 4) +
+  scale_shape_identity()
 # While all symbols have a foreground colour, symbols 19-25 also take a
 # background colour (fill)
 s + geom_point(aes(shape = z), size = 4, colour = "Red") +
diff --git a/man/aes_position.Rd b/man/aes_position.Rd
index 4feaa90..5c9acc6 100644
--- a/man/aes_position.Rd
+++ b/man/aes_position.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/aes-position.r
 \name{aes_position}
 \alias{aes_position}
@@ -16,6 +16,7 @@ This page demonstrates the usage of a sub-group
 of aesthetics; x, y, xmin, xmax, ymin, ymax, xend, and yend.
 }
 \examples{
+
 # Generate data: means and standard errors of means for prices
 # for each type of cut
 dmod <- lm(price ~ cut, data = diamonds)
@@ -25,21 +26,12 @@ se <- ggplot(cuts, aes(x = cut, y = fit, ymin = fit - se.fit,
 ymax = fit + se.fit, colour = cut))
 se + geom_pointrange()
 
-# Boxplot with precomputed statistics
-# generate sample data
-library(plyr)
-abc <- adply(matrix(rnorm(100), ncol = 5), 2, quantile, c(0, .25, .5, .75, 1))
-b <- ggplot(abc, aes(x = X1, ymin = "0\%", lower = "25\%",
-  middle = "50\%", upper = "75\%", ymax = "100\%"))
-b + geom_boxplot(stat = "identity")
-
 # Using annotate
 p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
 p + annotate("rect", xmin = 2, xmax = 3.5, ymin = 2, ymax = 25,
   fill = "dark grey", alpha = .5)
 
 # Geom_segment examples
-library(grid)
 p + geom_segment(aes(x = 2, y = 15, xend = 2, yend = 25),
   arrow = arrow(length = unit(0.5, "cm")))
 p + geom_segment(aes(x = 2, y = 15, xend = 3, yend = 15),
@@ -52,7 +44,7 @@ counts <- as.data.frame(table(x = rpois(100, 5)))
 counts$x <- as.numeric(as.character(counts$x))
 with(counts, plot(x, Freq, type = "h", lwd = 10))
 
-qplot(x, Freq, data = counts, geom = "segment", yend = 0, xend = x,
-  size = I(10))
+ggplot(counts, aes(x, Freq)) +
+  geom_segment(aes(yend = 0, xend = x), size = 10)
 }
 
diff --git a/man/aes_string.Rd b/man/aes_string.Rd
deleted file mode 100644
index b52c3b4..0000000
--- a/man/aes_string.Rd
+++ /dev/null
@@ -1,42 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/aes.r
-\name{aes_string}
-\alias{aes_q}
-\alias{aes_string}
-\title{Generate aesthetic mappings from a string/quoted objects}
-\usage{
-aes_string(x = NULL, y = NULL, ...)
-
-aes_q(x = NULL, y = NULL, ...)
-}
-\arguments{
-\item{x,y,...}{List of name value pairs}
-}
-\description{
-Aesthetic mappings describe how variables in the data are mapped to visual
-properties (aesthetics) of geoms. \code{\link{aes}} uses non-standard
-evaluation to capture the variable names. These two variants use
-regular evaluation, which is easier to use inside functions.
-}
-\details{
-\code{aes_string} and \code{aes_q} are particularly useful when writing
-functions that create plots because you can use strings or quoted
-names/calls to define the aesthetic mappings, rather than having to use
-\code{\link{substitute}} to generate a call to \code{aes()}.
-}
-\examples{
-# Threee ways of generating the same aesthetics
-aes(mpg, wt, col = cyl, fill = NULL)
-aes_string("mpg", "wt", col = "cyl", fill = NULL)
-aes_q(quote(mpg), quote(wt), col = quote(cyl), fill = NULL)
-
-aes(col = cyl, fill = NULL)
-aes_string(col = "cyl", fill = NULL)
-aes_q(col = quote(cyl), fill = NULL)
-}
-\seealso{
-\code{\link{aes}}
-
-Other aesthetic generators: \code{\link{aes}}
-}
-
diff --git a/man/annotate.Rd b/man/annotate.Rd
index 85b4aa1..d8a0e63 100644
--- a/man/annotate.Rd
+++ b/man/annotate.Rd
@@ -1,25 +1,29 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/annotation.r
 \name{annotate}
 \alias{annotate}
 \title{Create an annotation layer.}
 \usage{
 annotate(geom, x = NULL, y = NULL, xmin = NULL, xmax = NULL,
-  ymin = NULL, ymax = NULL, ...)
+  ymin = NULL, ymax = NULL, xend = NULL, yend = NULL, ...,
+  na.rm = FALSE)
 }
 \arguments{
 \item{geom}{name of geom to use for annotation}
 
-\item{x,y,xmin,ymin,xmax,ymax}{positionining aesthetics - you must
-specify at least one of these.}
+\item{x, y, xmin, ymin, xmax, ymax, xend, yend}{positioning aesthetics -
+you must specify at least one of these.}
 
 \item{...}{other aesthetics. These are not scaled so you can do (e.g.)
 \code{colour = "red"} to get a red point.}
+
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
 }
 \description{
 This function adds geoms to a plot. Unlike typical a geom function,
 the properties of the geoms are not mapped from variables of a data frame,
-but are instead in as vectors. This is useful for adding small annotations
+but are instead passed in as vectors. This is useful for adding small annotations
 (such as text labels) or if you have your data in vectors, and for some
 reason don't want to put them in a data frame.
 }
diff --git a/man/annotation_custom.Rd b/man/annotation_custom.Rd
index cd29dbc..8378386 100644
--- a/man/annotation_custom.Rd
+++ b/man/annotation_custom.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/annotation-custom.r
 \name{annotation_custom}
 \alias{annotation_custom}
@@ -10,15 +10,15 @@ annotation_custom(grob, xmin = -Inf, xmax = Inf, ymin = -Inf,
 \arguments{
 \item{grob}{grob to display}
 
-\item{xmin,xmax}{x location (in data coordinates) giving horizontal
+\item{xmin, xmax}{x location (in data coordinates) giving horizontal
 location of raster}
 
-\item{ymin,ymax}{y location (in data coordinates) giving vertical
+\item{ymin, ymax}{y location (in data coordinates) giving vertical
 location of raster}
 }
 \description{
-This is a special geom intended for use as static annnotations
-that are the same in every panel. These anotations will not
+This is a special geom intended for use as static annotations
+that are the same in every panel. These annotations will not
 affect scales (i.e. the x and y axes will not grow to cover the range
 of the grob, and the grob will not be modified by any ggplot settings or mappings).
 }
@@ -33,7 +33,10 @@ Inf values can be used to fill the full plot panel (see examples).
 }
 \examples{
 # Dummy plot
-base <- qplot(1:10, 1:10, geom = "blank") + theme_bw()
+df <- data.frame(x = 1:10, y = 1:10)
+base <- ggplot(df, aes(x, y)) +
+  geom_blank() +
+  theme_bw()
 # Adding a table
 \dontrun{
  if (require(gridExtra)) {
@@ -45,7 +48,9 @@ base + annotation_custom(grob = roundrectGrob(),
 }
 }
 # Inset plot
-g <- ggplotGrob(qplot(1, 1) +
+df2 <- data.frame(x = 1 , y = 1)
+g <- ggplotGrob(ggplot(df2, aes(x, y)) +
+  geom_point() +
   theme(plot.background = element_rect(colour = "black")))
 base +
   annotation_custom(grob = g, xmin = 1, xmax = 10, ymin = 8, ymax = 10)
diff --git a/man/annotation_logticks.Rd b/man/annotation_logticks.Rd
index 41208e3..4a70314 100644
--- a/man/annotation_logticks.Rd
+++ b/man/annotation_logticks.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/annotation-logticks.r
 \name{annotation_logticks}
 \alias{annotation_logticks}
@@ -21,13 +21,14 @@ bottom, and left.}
 using \code{scale_y_log10}. It should be \code{FALSE} when using
 \code{coord_trans(y = "log10")}.}
 
-\item{short}{a \code{unit} object specifying the length of the short tick marks}
+\item{short}{a \code{\link[grid]{unit}} object specifying the length of the
+short tick marks}
 
-\item{mid}{a \code{unit} object specifying the length of the middle tick marks.
-In base 10, these are the "5" ticks.}
+\item{mid}{a \code{\link[grid]{unit}} object specifying the length of the
+middle tick marks. In base 10, these are the "5" ticks.}
 
-\item{long}{a \code{unit} object specifying the length of the long tick marks.
-In base 10, these are the "1" (or "10") ticks.}
+\item{long}{a \code{\link[grid]{unit}} object specifying the length of the
+long tick marks. In base 10, these are the "1" (or "10") ticks.}
 
 \item{colour}{Colour of the tick marks.}
 
@@ -47,14 +48,17 @@ These tick marks probably make sense only for base 10.
 }
 \examples{
 # Make a log-log plot (without log ticks)
-library(MASS)
-library(scales)
-a <- ggplot(Animals, aes(x = body, y = brain)) + geom_point() +
-     scale_x_log10(breaks = trans_breaks("log10", function(x) 10^x),
-                   labels = trans_format("log10", math_format(10^.x))) +
-     scale_y_log10(breaks = trans_breaks("log10", function(x) 10^x),
-                   labels = trans_format("log10", math_format(10^.x))) +
-     theme_bw()
+a <- ggplot(msleep, aes(bodywt, brainwt)) +
+ geom_point(na.rm = TRUE) +
+ scale_x_log10(
+   breaks = scales::trans_breaks("log10", function(x) 10^x),
+   labels = scales::trans_format("log10", scales::math_format(10^.x))
+ ) +
+ scale_y_log10(
+   breaks = scales::trans_breaks("log10", function(x) 10^x),
+   labels = scales::trans_format("log10", scales::math_format(10^.x))
+ ) +
+ theme_bw()
 
 a + annotation_logticks()                # Default: log ticks on bottom and left
 a + annotation_logticks(sides = "lr")    # Log ticks for y, on left and right
@@ -63,33 +67,29 @@ a + annotation_logticks(sides = "trbl")  # All four sides
 # Hide the minor grid lines because they don't align with the ticks
 a + annotation_logticks(sides = "trbl") + theme(panel.grid.minor = element_blank())
 
-
 # Another way to get the same results as 'a' above: log-transform the data before
-b <- ggplot(Animals, aes(x = log10(body), y = log10(brain))) + geom_point() +
-     scale_x_continuous(name = "body", labels = math_format(10^.x)) +
-     scale_y_continuous(name = "brain", labels = math_format(10^.x)) +
-     theme_bw()+ theme(panel.grid.minor = element_blank())
+# plotting it. Also hide the minor grid lines.
+b <- ggplot(msleep, aes(log10(bodywt), log10(brainwt))) +
+ geom_point(na.rm = TRUE) +
+ scale_x_continuous(name = "body", labels = scales::math_format(10^.x)) +
+ scale_y_continuous(name = "brain", labels = scales::math_format(10^.x)) +
+ theme_bw() + theme(panel.grid.minor = element_blank())
 
 b + annotation_logticks()
 
-
-# This shows log(x) on the axes
-d <- ggplot(Animals, aes(x = log10(body), y = log10(brain))) + geom_point() +
-     theme_bw()
-
-d + annotation_logticks()
-
-
 # Using a coordinate transform requires scaled = FALSE
-t <- ggplot(Animals, aes(x = body, y = brain)) + geom_point() +
-     coord_trans(xtrans = "log10", ytrans = "log10") + theme_bw()
-
+t <- ggplot(msleep, aes(bodywt, brainwt)) +
+  geom_point() +
+  coord_trans(x = "log10", y = "log10") +
+  theme_bw()
 t + annotation_logticks(scaled = FALSE)
 
-
 # Change the length of the ticks
-library(grid)
-a + annotation_logticks(short = unit(.5,"mm"), mid = unit(3,"mm"), long = unit(4,"mm"))
+a + annotation_logticks(
+  short = unit(.5,"mm"),
+  mid = unit(3,"mm"),
+  long = unit(4,"mm")
+)
 }
 \seealso{
 \code{\link{scale_y_continuous}}, \code{\link{scale_y_log10}} for log scale
diff --git a/man/annotation_map.Rd b/man/annotation_map.Rd
index 24292a7..2b2928a 100644
--- a/man/annotation_map.Rd
+++ b/man/annotation_map.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/annotation-map.r
 \name{annotation_map}
 \alias{annotation_map}
@@ -16,7 +16,7 @@ converted into the right format by using \code{\link{fortify}}}
 Annotation: maps.
 }
 \examples{
-library(maps)
+if (require("maps")) {
 usamap <- map_data("state")
 
 seal.sub <- subset(seals, long > -130 & lat < 45 & lat > 40)
@@ -33,4 +33,5 @@ ggplot(seal2,  aes(x = long, y = lat)) +
   geom_segment(aes(xend = long + delta_long, yend = lat + delta_lat)) +
   facet_grid(latr ~ longr, scales = "free", space = "free")
 }
+}
 
diff --git a/man/annotation_raster.Rd b/man/annotation_raster.Rd
index d153c93..c56340f 100644
--- a/man/annotation_raster.Rd
+++ b/man/annotation_raster.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/annotation-raster.r
 \name{annotation_raster}
 \alias{annotation_raster}
@@ -9,10 +9,10 @@ annotation_raster(raster, xmin, xmax, ymin, ymax, interpolate = FALSE)
 \arguments{
 \item{raster}{raster object to display}
 
-\item{xmin,xmax}{x location (in data coordinates) giving horizontal
+\item{xmin, xmax}{x location (in data coordinates) giving horizontal
 location of raster}
 
-\item{ymin,ymax}{y location (in data coordinates) giving vertical
+\item{ymin, ymax}{y location (in data coordinates) giving vertical
 location of raster}
 
 \item{interpolate}{If \code{TRUE} interpolate linearly, if \code{FALSE}
@@ -29,20 +29,21 @@ Most useful for adding bitmap images.
 }
 \examples{
 # Generate data
-rainbow <- matrix(hcl(seq(0, 360, length = 50 * 50), 80, 70), nrow = 50)
-qplot(mpg, wt, data = mtcars) +
+rainbow <- matrix(hcl(seq(0, 360, length.out = 50 * 50), 80, 70), nrow = 50)
+ggplot(mtcars, aes(mpg, wt)) +
+  geom_point() +
   annotation_raster(rainbow, 15, 20, 3, 4)
 # To fill up whole plot
-qplot(mpg, wt, data = mtcars) +
+ggplot(mtcars, aes(mpg, wt)) +
   annotation_raster(rainbow, -Inf, Inf, -Inf, Inf) +
   geom_point()
 
-rainbow2 <- matrix(hcl(seq(0, 360, length = 10), 80, 70), nrow = 1)
-qplot(mpg, wt, data = mtcars) +
+rainbow2 <- matrix(hcl(seq(0, 360, length.out = 10), 80, 70), nrow = 1)
+ggplot(mtcars, aes(mpg, wt)) +
   annotation_raster(rainbow2, -Inf, Inf, -Inf, Inf) +
   geom_point()
-rainbow2 <- matrix(hcl(seq(0, 360, length = 10), 80, 70), nrow = 1)
-qplot(mpg, wt, data = mtcars) +
+rainbow2 <- matrix(hcl(seq(0, 360, length.out = 10), 80, 70), nrow = 1)
+ggplot(mtcars, aes(mpg, wt)) +
   annotation_raster(rainbow2, -Inf, Inf, -Inf, Inf, interpolate = TRUE) +
   geom_point()
 }
diff --git a/man/as.list.ggproto.Rd b/man/as.list.ggproto.Rd
new file mode 100644
index 0000000..8b0a64e
--- /dev/null
+++ b/man/as.list.ggproto.Rd
@@ -0,0 +1,20 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/ggproto.r
+\name{as.list.ggproto}
+\alias{as.list.ggproto}
+\title{Convert a ggproto object to a list}
+\usage{
+\method{as.list}{ggproto}(x, inherit = TRUE, ...)
+}
+\arguments{
+\item{x}{A ggproto object to convert to a list.}
+
+\item{inherit}{If \code{TRUE} (the default), flatten all inherited items into
+the returned list. If \code{FALSE}, do not include any inherited items.}
+
+\item{...}{Further arguments to pass to \code{as.list.environment}.}
+}
+\description{
+This will not include the object's \code{super} member.
+}
+
diff --git a/man/as_labeller.Rd b/man/as_labeller.Rd
new file mode 100644
index 0000000..20c105b
--- /dev/null
+++ b/man/as_labeller.Rd
@@ -0,0 +1,46 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/facet-labels.r
+\name{as_labeller}
+\alias{as_labeller}
+\title{Coerce to labeller function}
+\usage{
+as_labeller(x, default = label_value, multi_line = TRUE)
+}
+\arguments{
+\item{x}{Object to coerce to a labeller function. If a named
+character vector, it is used as a lookup table before being
+passed on to \code{default}. If a non-labeller function, it is
+assumed it takes and returns character vectors and is applied to
+the labels. If a labeller, it is simply applied to the labels.}
+
+\item{default}{Default labeller to process the labels produced by
+lookup tables or modified by non-labeller functions.}
+
+\item{multi_line}{Whether to display the labels of multiple factors
+on separate lines. This is passed to the labeller function.}
+}
+\description{
+This transforms objects to labeller functions. Used internally by
+\code{\link{labeller}()}.
+}
+\examples{
+p <- ggplot(mtcars, aes(disp, drat)) + geom_point()
+p + facet_wrap(~am)
+
+# Rename labels on the fly with a lookup character vector
+to_string <- as_labeller(c(`0` = "Zero", `1` = "One"))
+p + facet_wrap(~am, labeller = to_string)
+
+# Quickly transform a function operating on character vectors to a
+# labeller function:
+appender <- function(string, suffix = "-foo") paste0(string, suffix)
+p + facet_wrap(~am, labeller = as_labeller(appender))
+
+# If you have more than one facetting variable, be sure to dispatch
+# your labeller to the right variable with labeller()
+p + facet_grid(cyl ~ am, labeller = labeller(am = to_string))
+}
+\seealso{
+\code{\link{labeller}()}, \link{labellers}
+}
+
diff --git a/man/autoplot.Rd b/man/autoplot.Rd
index ebb1873..6899d56 100644
--- a/man/autoplot.Rd
+++ b/man/autoplot.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/autoplot.r
 \name{autoplot}
 \alias{autoplot}
diff --git a/man/benchplot.Rd b/man/benchplot.Rd
index c1f079e..97f5a9f 100644
--- a/man/benchplot.Rd
+++ b/man/benchplot.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/bench.r
 \name{benchplot}
 \alias{benchplot}
@@ -15,8 +15,8 @@ Benchmark plot creation time.
 Broken down into construct, build, render and draw times.
 }
 \examples{
-benchplot(qplot(mpg, wt, data = mtcars))
-benchplot(qplot(mpg, wt, data = mtcars) + facet_grid(.~ cyl))
+benchplot(ggplot(mtcars, aes(mpg, wt)) + geom_point())
+benchplot(ggplot(mtcars, aes(mpg, wt)) + geom_point() + facet_grid(. ~ cyl))
 }
 \keyword{internal}
 
diff --git a/man/borders.Rd b/man/borders.Rd
index 2dfc59f..c54b8f9 100644
--- a/man/borders.Rd
+++ b/man/borders.Rd
@@ -1,11 +1,11 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/fortify-map.r
 \name{borders}
 \alias{borders}
 \title{Create a layer of map borders.}
 \usage{
 borders(database = "world", regions = ".", fill = NA, colour = "grey50",
-  ...)
+  xlim = NULL, ylim = NULL, ...)
 }
 \arguments{
 \item{database}{map data, see \code{\link[maps]{map}} for details}
@@ -16,6 +16,9 @@ borders(database = "world", regions = ".", fill = NA, colour = "grey50",
 
 \item{colour}{border colour}
 
+\item{xlim, ylim}{latitudinal and logitudinal range for extracting map
+polygons, see \code{\link[maps]{map}} for details.}
+
 \item{...}{other arguments passed onto \code{\link{geom_polygon}}}
 }
 \description{
@@ -26,8 +29,7 @@ if (require("maps")) {
 
 ia <- map_data("county", "iowa")
 mid_range <- function(x) mean(range(x))
-library(plyr)
-seats <- ddply(ia, .(subregion), colwise(mid_range, .(lat, long)))
+seats <- plyr::ddply(ia, "subregion", plyr::colwise(mid_range, c("lat", "long")))
 ggplot(ia, aes(long, lat)) +
   geom_polygon(aes(group = group), fill = NA, colour = "grey60") +
   geom_text(aes(label = subregion), data = seats, size = 2, angle = 45)
@@ -37,8 +39,15 @@ capitals <- subset(us.cities, capital == 2)
 ggplot(capitals, aes(long, lat)) +
   borders("state") +
   geom_point(aes(size = pop)) +
-  scale_size_area()
+  scale_size_area() +
+  coord_quickmap()
 
+# Same map, with some world context
+ggplot(capitals, aes(long, lat)) +
+  borders("world", xlim = c(-130, -60), ylim = c(20, 50)) +
+  geom_point(aes(size = pop)) +
+  scale_size_area() +
+  coord_quickmap()
 }
 }
 
diff --git a/man/calc_element.Rd b/man/calc_element.Rd
index 42d07f3..09e2a78 100644
--- a/man/calc_element.Rd
+++ b/man/calc_element.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/theme.r
 \name{calc_element}
 \alias{calc_element}
@@ -29,5 +29,6 @@ calc_element('axis.text.x', t, verbose = TRUE)
 t$axis.text.x
 t$axis.text
 t$text
+
 }
 
diff --git a/man/continuous_scale.Rd b/man/continuous_scale.Rd
index 3cd9bd7..d135fe1 100644
--- a/man/continuous_scale.Rd
+++ b/man/continuous_scale.Rd
@@ -1,14 +1,13 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/scale-.r
 \name{continuous_scale}
 \alias{continuous_scale}
 \title{Continuous scale constructor.}
 \usage{
-continuous_scale(aesthetics, scale_name, palette, name = NULL,
+continuous_scale(aesthetics, scale_name, palette, name = waiver(),
   breaks = waiver(), minor_breaks = waiver(), labels = waiver(),
-  legend = NULL, limits = NULL, rescaler = rescale, oob = censor,
-  expand = waiver(), na.value = NA_real_, trans = "identity",
-  guide = "legend")
+  limits = NULL, rescaler = rescale, oob = censor, expand = waiver(),
+  na.value = NA_real_, trans = "identity", guide = "legend")
 }
 \arguments{
 \item{aesthetics}{the names of the aesthetics that this scale works with}
@@ -19,50 +18,66 @@ continuous_scale(aesthetics, scale_name, palette, name = NULL,
 argument (the number of levels in the scale) returns the values that
 they should take}
 
-\item{name}{the name of the scale - used as the axis label or the legend
-title}
+\item{name}{The name of the scale. Used as axis or legend title. If
+\code{NULL}, the default, the name of the scale is taken from the first
+mapping used for that aesthetic.}
 
-\item{breaks}{control the breaks in the guide.  There are four possible
-types of input:
-\itemize{
-  \item \code{NULL}: don't display any breaks
-  \item a character vector giving the breaks as they should appear on the
-   axis or in the legend.
-  \item \code{waiver()} to use the default break computation.
-  \item a function, that when called with a single argument, a character
-    vector giving the limits of the scale, returns a character vector
-    specifying which breaks to display.
-}
-This parameter does not affect in any way how the data is scaled - it
-only affects the appearance of the legend.}
-
-\item{minor_breaks}{Used with date or datetime scales. Either \code{NULL} for
-no minor breaks, \code{waiver()} for the default breaks (one minor break
-between each major break), a numeric vector of positions, or a function
-that given the limits returns a vector of minor breaks.}
+\item{breaks}{One of: \itemize{
+  \item \code{NULL} for no breaks
+  \item \code{waiver()} for the default breaks computed by the
+    transformation object
+  \item A numeric vector of positions
+  \item A function that takes the limits as input and returns breaks
+    as output
+}}
 
-\item{labels}{\code{NULL} for no labels, \code{waiver()} for default
-labels (labels the same as breaks), a character vector the same length
-as breaks, or a named character vector whose names are used to match
-replacement the labels for matching breaks.}
+\item{minor_breaks}{One of: \itemize{
+  \item \code{NULL} for no minor breaks
+  \item \code{waiver()} for the default breaks (one minor break between
+    each major break)
+  \item A numeric vector of positions
+  \item A function that given the limits returns a vector of minor breaks.
+}}
 
-\item{legend}{deprecated.  Use \code{guide} instead.}
+\item{labels}{One of: \itemize{
+  \item \code{NULL} for no labels
+  \item \code{waiver()} for the default labels computed by the
+    transformation object
+  \item A character vector giving labels (must be same length as \code{breaks})
+  \item A function that takes the breaks as input and returns labels
+    as output
+}}
 
-\item{limits}{A numeric vector of length two describing the scale limits.}
+\item{limits}{A numeric vector of length two providing limits of the scale.
+Use \code{NA} to refer to the existing minimum or maximum.}
 
 \item{rescaler}{Used by diverging and n colour gradients
-(i.e. \code{\link{scale_colour_gradient2}}, \code{\link{scale_colour_gradientn}}).}
+(i.e. \code{\link{scale_colour_gradient2}}, \code{\link{scale_colour_gradientn}}).
+A function used to scale the input values to the range [0, 1].}
+
+\item{oob}{Function that handles limits outside of the scale limits
+(out of bounds). The default replaces out of bounds values with NA.}
+
+\item{expand}{A numeric vector of length two giving multiplicative and
+additive expansion constants. These constants ensure that the data is
+placed some distance away from the axes. The defaults are
+\code{c(0.05, 0)} for continuous variables, and \code{c(0, 0.6)} for
+discrete variables.}
 
-\item{oob}{What to do with values outside scale limits (out of bounds)?}
+\item{na.value}{Missing values will be replaced with this value.}
 
-\item{expand}{a numeric vector of length two, giving a multiplicative and
-additive constant used to expand the range of the scales so that there
-is a small gap between the data and the axes.}
+\item{trans}{Either the name of a transformation object, or the
+  object itself. Built-in transformations include "asn", "atanh",
+  "boxcox", "exp", "identity", "log", "log10", "log1p", "log2",
+  "logit", "probability", "probit", "reciprocal", "reverse" and "sqrt".
 
-\item{na.value}{how should missing values be displayed?}
+  A transformation object bundles together a transform, it's inverse,
+  and methods for generating breaks and labels. Transformation objects
+  are defined in the scales package, and are called \code{name_trans}, e.g.
+  \code{\link[scales]{boxcox_trans}}. You can create your own
+  transformation with \code{\link[scales]{trans_new}}.}
 
-\item{guide}{the name of, or actual function, used to create the
-guide.}
+\item{guide}{Name of guide object, or object itself.}
 }
 \description{
 Continuous scale constructor.
diff --git a/man/coord.Rd b/man/coord.Rd
deleted file mode 100644
index 9c39380..0000000
--- a/man/coord.Rd
+++ /dev/null
@@ -1,16 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/coord-.r
-\name{coord}
-\alias{coord}
-\title{New coordinate system.}
-\usage{
-coord(..., subclass = c())
-}
-\arguments{
-\item{...}{object fields}
-}
-\description{
-Internal use only.
-}
-\keyword{internal}
-
diff --git a/man/coord_cartesian.Rd b/man/coord_cartesian.Rd
index 8a8a18c..7d4a6d1 100644
--- a/man/coord_cartesian.Rd
+++ b/man/coord_cartesian.Rd
@@ -1,17 +1,17 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/coord-cartesian-.r
 \name{coord_cartesian}
 \alias{coord_cartesian}
 \title{Cartesian coordinates.}
 \usage{
-coord_cartesian(xlim = NULL, ylim = NULL, wise = NULL)
+coord_cartesian(xlim = NULL, ylim = NULL, expand = TRUE)
 }
 \arguments{
-\item{xlim}{limits for the x axis}
+\item{xlim, ylim}{Limits for the x and y axes.}
 
-\item{ylim}{limits for the y axis}
-
-\item{wise}{deprecated in 0.9.1}
+\item{expand}{If \code{TRUE}, the default, adds a small expansion factor to
+the limits to ensure that data and axes don't overlap. If \code{FALSE},
+limits are taken exactly from the data or \code{xlim}/\code{ylim}.}
 }
 \description{
 The Cartesian coordinate system is the most familiar, and common, type of
@@ -23,29 +23,38 @@ change the underlying data like setting limits on a scale will.
 # There are two ways of zooming the plot display: with scales or
 # with coordinate systems.  They work in two rather different ways.
 
-(p <- qplot(disp, wt, data=mtcars) + geom_smooth())
+p <- ggplot(mtcars, aes(disp, wt)) +
+  geom_point() +
+  geom_smooth()
+p
 
-# Setting the limits on a scale will throw away all data that's not
-# inside these limits.  This is equivalent to plotting a subset of
-# the original data
+# Setting the limits on a scale converts all values outside the range to NA.
 p + scale_x_continuous(limits = c(325, 500))
 
-# Setting the limits on the coordinate system performs a visual zoom
-# the data is unchanged, and we just view a small portion of the original
-# plot.  See how the axis labels are the same as the original data, and
-# the smooth continue past the points visible on this plot.
+# Setting the limits on the coordinate system performs a visual zoom.
+# The data is unchanged, and we just view a small portion of the original
+# plot. Note how smooth continues past the points visible on this plot.
 p + coord_cartesian(xlim = c(325, 500))
 
+# By default, the same expansion factor is applied as when setting scale
+# limits. You can set the limits precisely by setting expand = FALSE
+p + coord_cartesian(xlim = c(325, 500), expand = FALSE)
+
+# Simiarly, we can use expand = FALSE to turn off expansion with the
+# default limits
+p + coord_cartesian(expand = FALSE)
+
 # You can see the same thing with this 2d histogram
-(d <- ggplot(diamonds, aes(carat, price)) +
-  stat_bin2d(bins = 25, colour="grey50"))
+d <- ggplot(diamonds, aes(carat, price)) +
+  stat_bin2d(bins = 25, colour = "white")
+d
 
 # When zooming the scale, the we get 25 new bins that are the same
 # size on the plot, but represent smaller regions of the data space
-d + scale_x_continuous(limits = c(0, 2))
+d + scale_x_continuous(limits = c(0, 1))
 
 # When zooming the coordinate system, we see a subset of original 50 bins,
 # displayed bigger
-d + coord_cartesian(xlim = c(0, 2))
+d + coord_cartesian(xlim = c(0, 1))
 }
 
diff --git a/man/coord_expand_defaults.Rd b/man/coord_expand_defaults.Rd
deleted file mode 100644
index 238f085..0000000
--- a/man/coord_expand_defaults.Rd
+++ /dev/null
@@ -1,13 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/coord-.r
-\name{coord_expand_defaults}
-\alias{coord_expand_defaults}
-\title{Set the default expand values for the scale, if NA}
-\usage{
-coord_expand_defaults(coord, scale, aesthetic = NULL)
-}
-\description{
-Set the default expand values for the scale, if NA
-}
-\keyword{internal}
-
diff --git a/man/coord_fixed.Rd b/man/coord_fixed.Rd
index 5f7790e..1574f91 100644
--- a/man/coord_fixed.Rd
+++ b/man/coord_fixed.Rd
@@ -1,20 +1,22 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/coord-fixed.r
 \name{coord_fixed}
 \alias{coord_equal}
 \alias{coord_fixed}
 \title{Cartesian coordinates with fixed relationship between x and y scales.}
 \usage{
-coord_fixed(ratio = 1, xlim = NULL, ylim = NULL, wise = NULL)
+coord_fixed(ratio = 1, xlim = NULL, ylim = NULL, expand = TRUE)
 }
 \arguments{
 \item{ratio}{aspect ratio, expressed as \code{y / x}}
 
-\item{xlim}{limits for the x axis}
+\item{xlim}{Limits for the x and y axes.}
 
-\item{ylim}{limits for the y axis}
+\item{ylim}{Limits for the x and y axes.}
 
-\item{wise}{deprecated in 0.9.1}
+\item{expand}{If \code{TRUE}, the default, adds a small expansion factor to
+the limits to ensure that data and axes don't overlap. If \code{FALSE},
+limits are taken exactly from the data or \code{xlim}/\code{ylim}.}
 }
 \description{
 A fixed scale coordinate system forces a specified ratio between the
@@ -29,9 +31,10 @@ y axis longer than units on the x-axis, and vice versa. This is similar to
 # ensures that the ranges of axes are equal to the specified ratio by
 # adjusting the plot aspect ratio
 
-qplot(mpg, wt, data = mtcars) + coord_fixed(ratio = 1)
-qplot(mpg, wt, data = mtcars) + coord_fixed(ratio = 5)
-qplot(mpg, wt, data = mtcars) + coord_fixed(ratio = 1/5)
+p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
+p + coord_fixed(ratio = 1)
+p + coord_fixed(ratio = 5)
+p + coord_fixed(ratio = 1/5)
 
 # Resize the plot to see that the specified aspect ratio is maintained
 }
diff --git a/man/coord_flip.Rd b/man/coord_flip.Rd
index f85e475..234b0c0 100644
--- a/man/coord_flip.Rd
+++ b/man/coord_flip.Rd
@@ -1,13 +1,19 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/coord-flip.r
 \name{coord_flip}
 \alias{coord_flip}
 \title{Flipped cartesian coordinates.}
 \usage{
-coord_flip(...)
+coord_flip(xlim = NULL, ylim = NULL, expand = TRUE)
 }
 \arguments{
-\item{...}{Other arguments passed onto \code{\link{coord_cartesian}}}
+\item{xlim}{Limits for the x and y axes.}
+
+\item{ylim}{Limits for the x and y axes.}
+
+\item{expand}{If \code{TRUE}, the default, adds a small expansion factor to
+the limits to ensure that data and axes don't overlap. If \code{FALSE},
+limits are taken exactly from the data or \code{xlim}/\code{ylim}.}
 }
 \description{
 Flipped cartesian coordinates so that horizontal becomes vertical, and
@@ -15,23 +21,23 @@ vertical, horizontal. This is primarily useful for converting geoms and
 statistics which display y conditional on x, to x conditional on y.
 }
 \examples{
-\donttest{
 # Very useful for creating boxplots, and other interval
 # geoms in the horizontal instead of vertical position.
-qplot(cut, price, data=diamonds, geom="boxplot")
-last_plot() + coord_flip()
 
-qplot(cut, data=diamonds, geom="bar")
-last_plot() + coord_flip()
+ggplot(diamonds, aes(cut, price)) +
+  geom_boxplot() +
+  coord_flip()
 
-h <- qplot(carat, data=diamonds, geom="histogram")
+h <- ggplot(diamonds, aes(carat)) +
+  geom_histogram()
 h
 h + coord_flip()
 h + coord_flip() + scale_x_reverse()
 
-# You can also use it to flip lines and area plots:
-qplot(1:5, (1:5)^2, geom="area")
+# You can also use it to flip line and area plots:
+df <- data.frame(x = 1:5, y = (1:5) ^ 2)
+ggplot(df, aes(x, y)) +
+  geom_area()
 last_plot() + coord_flip()
 }
-}
 
diff --git a/man/coord_map.Rd b/man/coord_map.Rd
index d2372d3..0d6170c 100644
--- a/man/coord_map.Rd
+++ b/man/coord_map.Rd
@@ -1,11 +1,14 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/coord-map.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/coord-map.r, R/coord-quickmap.R
 \name{coord_map}
 \alias{coord_map}
+\alias{coord_quickmap}
 \title{Map projections.}
 \usage{
 coord_map(projection = "mercator", ..., orientation = NULL, xlim = NULL,
   ylim = NULL)
+
+coord_quickmap(xlim = NULL, ylim = NULL, expand = TRUE)
 }
 \arguments{
 \item{projection}{projection to use, see
@@ -19,41 +22,60 @@ coord_map(projection = "mercator", ..., orientation = NULL, xlim = NULL,
 projections, so you will have to supply your own. See
 \code{\link[mapproj]{mapproject}} for more information.}
 
-\item{xlim}{manually specific x limits (in degrees of lontitude)}
+\item{xlim}{manually specific x limits (in degrees of longitude)}
 
 \item{ylim}{manually specific y limits (in degrees of latitude)}
+
+\item{expand}{If \code{TRUE}, the default, adds a small expansion factor to
+the limits to ensure that data and axes don't overlap. If \code{FALSE},
+limits are taken exactly from the data or \code{xlim}/\code{ylim}.}
 }
 \description{
+The representation of a portion of the earth, which is approximately spherical,
+onto a flat 2D plane requires a projection. This is what
+\code{\link{coord_map}} does. These projections account for the fact that the
+actual length (in km) of one degree of longitude varies between the equator
+and the pole. Near the equator, the ratio between the lengths of one degree
+of latitude and one degree of longitude is approximately 1. Near the pole, it
+is tends towards infinity because the length of one degree of longitude tends
+towards 0. For regions that span only a few degrees and are not too close to
+the poles, setting the aspect ratio of the plot to the appropriate lat/lon
+ratio approximates the usual mercator projection. This is what
+\code{coord_quickmap} does. With \code{\link{coord_map}} all elements of the
+graphic have to be projected which is not the case here. So
+\code{\link{coord_quickmap}} has the advantage of being much faster, in
+particular for complex plots such as those using with
+\code{\link{geom_tile}}, at the expense of correctness in the projection.
 This coordinate system provides the full range of map projections available
 in the mapproj package.
 }
-\details{
-This is still experimental, and if you have any advice to offer regarding
-a better (or more correct) way to do this, please let me know
-}
 \examples{
 if (require("maps")) {
-# Create a lat-long dataframe from the maps package
 nz <- map_data("nz")
-nzmap <- ggplot(nz, aes(x=long, y=lat, group=group)) +
-  geom_polygon(fill="white", colour="black")
+# Prepare a map of NZ
+nzmap <- ggplot(nz, aes(x = long, y = lat, group = group)) +
+  geom_polygon(fill = "white", colour = "black")
 
-# Use cartesian coordinates
+# Plot it in cartesian coordinates
 nzmap
-# With default mercator projection
+# With correct mercator projection
 nzmap + coord_map()
+# With the aspect ratio approximation
+nzmap + coord_quickmap()
+
 # Other projections
 nzmap + coord_map("cylindrical")
 nzmap + coord_map("azequalarea",orientation=c(-36.92,174.6,0))
 
 states <- map_data("state")
-usamap <- ggplot(states, aes(x=long, y=lat, group=group)) +
-  geom_polygon(fill="white", colour="black")
+usamap <- ggplot(states, aes(long, lat, group = group)) +
+  geom_polygon(fill = "white", colour = "black")
 
 # Use cartesian coordinates
 usamap
 # With mercator projection
 usamap + coord_map()
+usamap + coord_quickmap()
 # See ?mapproject for coordinate systems and their parameters
 usamap + coord_map("gilbert")
 usamap + coord_map("lagrange")
@@ -70,15 +92,15 @@ usamap + coord_map("bonne", lat0 = 50)
 world <- map_data("world")
 worldmap <- ggplot(world, aes(x=long, y=lat, group=group)) +
   geom_path() +
-  scale_y_continuous(breaks=(-2:2) * 30) +
-  scale_x_continuous(breaks=(-4:4) * 45)
+  scale_y_continuous(breaks = (-2:2) * 30) +
+  scale_x_continuous(breaks = (-4:4) * 45)
 
 # Orthographic projection with default orientation (looking down at North pole)
 worldmap + coord_map("ortho")
 # Looking up up at South Pole
-worldmap + coord_map("ortho", orientation=c(-90, 0, 0))
+worldmap + coord_map("ortho", orientation = c(-90, 0, 0))
 # Centered on New York (currently has issues with closing polygons)
-worldmap + coord_map("ortho", orientation=c(41, -74, 0))
+worldmap + coord_map("ortho", orientation = c(41, -74, 0))
 }
 }
 
diff --git a/man/coord_munch.Rd b/man/coord_munch.Rd
new file mode 100644
index 0000000..9ab2bd6
--- /dev/null
+++ b/man/coord_munch.Rd
@@ -0,0 +1,25 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/coord-munch.r
+\name{coord_munch}
+\alias{coord_munch}
+\title{Munch coordinates data}
+\usage{
+coord_munch(coord, data, range, segment_length = 0.01)
+}
+\arguments{
+\item{coord}{Coordinate system definition.}
+
+\item{data}{Data set to transform - should have variables \code{x} and
+\code{y} are chopped up into small pieces (as defined by \code{group}).
+All other variables are duplicated as needed.}
+
+\item{range}{Panel range specification.}
+
+\item{segment_length}{Target segment length}
+}
+\description{
+This function "munches" lines, dividing each line into many small pieces
+so they can be transformed independently. Used inside geom functions.
+}
+\keyword{internal}
+
diff --git a/man/coord_polar.Rd b/man/coord_polar.Rd
index 61a367a..49550c9 100644
--- a/man/coord_polar.Rd
+++ b/man/coord_polar.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/coord-polar.r
 \name{coord_polar}
 \alias{coord_polar}
@@ -18,12 +18,18 @@ The polar coordinate system is most commonly used for pie charts, which
 are a stacked bar chart in polar coordinates.
 }
 \examples{
-\donttest{
 # NOTE: Use these plots with caution - polar coordinates has
 # major perceptual problems.  The main point of these examples is
 # to demonstrate how these common plots can be described in the
 # grammar.  Use with EXTREME caution.
 
+#' # A pie chart = stacked bar chart + polar coordinates
+pie <- ggplot(mtcars, aes(x = factor(1), fill = factor(cyl))) +
+ geom_bar(width = 1)
+pie + coord_polar(theta = "y")
+
+\donttest{
+
 # A coxcomb plot = bar chart + polar coordinates
 cxc <- ggplot(mtcars, aes(x = factor(cyl))) +
   geom_bar(width = 1, colour = "black")
@@ -31,18 +37,13 @@ cxc + coord_polar()
 # A new type of plot?
 cxc + coord_polar(theta = "y")
 
-# A pie chart = stacked bar chart + polar coordinates
-pie <- ggplot(mtcars, aes(x = factor(1), fill = factor(cyl))) +
- geom_bar(width = 1)
-pie + coord_polar(theta = "y")
-
 # The bullseye chart
 pie + coord_polar()
 
 # Hadley's favourite pie chart
 df <- data.frame(
-  variable = c("resembles", "does not resemble"),
-  value = c(80, 20)
+  variable = c("does not resemble", "resembles"),
+  value = c(20, 80)
 )
 ggplot(df, aes(x = "", y = value, fill = variable)) +
   geom_bar(width = 1, stat = "identity") +
@@ -51,6 +52,7 @@ ggplot(df, aes(x = "", y = value, fill = variable)) +
   labs(title = "Pac man")
 
 # Windrose + doughnut plot
+if (require("ggplot2movies")) {
 movies$rrating <- cut_interval(movies$rating, length = 1)
 movies$budgetq <- cut_number(movies$budget, 4)
 
@@ -62,4 +64,5 @@ doh + geom_bar(width = 1) + coord_polar()
 doh + geom_bar(width = 0.9, position = "fill") + coord_polar(theta = "y")
 }
 }
+}
 
diff --git a/man/coord_quickmap.Rd b/man/coord_quickmap.Rd
deleted file mode 100644
index bd2f0e5..0000000
--- a/man/coord_quickmap.Rd
+++ /dev/null
@@ -1,52 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/coord-quickmap.R
-\name{coord_quickmap}
-\alias{coord_quickmap}
-\title{Cartesian coordinates with an aspect ratio approximating Mercator projection.}
-\usage{
-coord_quickmap(xlim = NULL, ylim = NULL)
-}
-\arguments{
-\item{xlim}{limits for the x axis}
-
-\item{ylim}{limits for the y axis}
-}
-\description{
-The represenation of a portion of the earth, wich is approximately spherical,
-onto a flat 2D plane requires a projection. This is what
-\code{\link{coord_map}} does. These projections account for the fact that the
-actual length (in km) of one degree of longitude varies between the equator
-and the pole. Near the equator, the ratio between the lengths of one degree
-of latitude and one degree of longitude is approximately 1. Near the pole, it
-is tends towards infinity because the length of one degree of longitude tends
-towards 0. For regions that span only a few degrees and are not too close to
-the poles, setting the aspect ratio of the plot to the appropriate lat/lon
-ratio approximates the usual mercator projection. This is what
-\code{coord_quickmap} does. With \code{\link{coord_map}} all elements of the
-graphic have to be projected which is not the case here. So
-\code{\link{coord_quickmap}} has the advantage of being much faster, in
-particular for complex plots such as those using with
-\code{\link{geom_tile}}, at the expense of correctedness in the projection.
-}
-\examples{
-# ensures that the ranges of axes are equal to the specified ratio by
-# adjusting the plot aspect ratio
-
-if (require("maps")) {
-# Create a lat-long dataframe from the maps package
-nz <- map_data("nz")
-# Prepare a plot of the map
-nzmap <- ggplot(nz, aes(x = long, y = lat, group = group)) +
-  geom_polygon(fill = "white", colour = "black")
-
-# Plot it in cartesian coordinates
-nzmap
-# With correct mercator projection
-nzmap + coord_map()
-# With the aspect ratio approximation
-nzmap + coord_quickmap()
-}
-
-# Resize the plot to see that the specified aspect ratio is maintained
-}
-
diff --git a/man/coord_trans.Rd b/man/coord_trans.Rd
index 40f2dd2..50aa82e 100644
--- a/man/coord_trans.Rd
+++ b/man/coord_trans.Rd
@@ -1,17 +1,19 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/coord-transform.r
 \name{coord_trans}
 \alias{coord_trans}
 \title{Transformed cartesian coordinate system.}
 \usage{
-coord_trans(xtrans = "identity", ytrans = "identity", limx = NULL,
-  limy = NULL)
+coord_trans(x = "identity", y = "identity", limx = NULL, limy = NULL,
+  xtrans, ytrans)
 }
 \arguments{
-\item{xtrans,ytrans}{transformers for x and y axes}
+\item{x, y}{transformers for x and y axes}
 
-\item{limx,limy}{limits for x and y axes. (Named so for backward
-compatability)}
+\item{limx, limy}{limits for x and y axes. (Named so for backward
+compatibility)}
+
+\item{xtrans, ytrans}{Deprecated; use \code{x} and \code{y} instead.}
 }
 \description{
 \code{coord_trans} is different to scale transformations in that it occurs after
@@ -27,14 +29,19 @@ how to create your own.
 \donttest{
 # See ?geom_boxplot for other examples
 
-# Three ways of doing transformating in ggplot:
+# Three ways of doing transformation in ggplot:
 #  * by transforming the data
-qplot(log10(carat), log10(price), data=diamonds)
+ggplot(diamonds, aes(log10(carat), log10(price))) +
+  geom_point()
 #  * by transforming the scales
-qplot(carat, price, data=diamonds, log="xy")
-qplot(carat, price, data=diamonds) + scale_x_log10() + scale_y_log10()
+ggplot(diamonds, aes(carat, price)) +
+  geom_point() +
+  scale_x_log10() +
+  scale_y_log10()
 #  * by transforming the coordinate system:
-qplot(carat, price, data=diamonds) + coord_trans(x = "log10", y = "log10")
+ggplot(diamonds, aes(carat, price)) +
+  geom_point() +
+  coord_trans(x = "log10", y = "log10")
 
 # The difference between transforming the scales and
 # transforming the coordinate system is that scale
@@ -43,10 +50,16 @@ qplot(carat, price, data=diamonds) + coord_trans(x = "log10", y = "log10")
 # changes the shape of geoms:
 
 d <- subset(diamonds, carat > 0.5)
-qplot(carat, price, data = d, log="xy") +
-  geom_smooth(method="lm")
-qplot(carat, price, data = d) +
-  geom_smooth(method="lm") +
+
+ggplot(d, aes(carat, price)) +
+  geom_point() +
+  geom_smooth(method = "lm") +
+  scale_x_log10() +
+  scale_y_log10()
+
+ggplot(d, aes(carat, price)) +
+  geom_point() +
+  geom_smooth(method = "lm") +
   coord_trans(x = "log10", y = "log10")
 
 # Here I used a subset of diamonds so that the smoothed line didn't
@@ -55,12 +68,17 @@ qplot(carat, price, data = d) +
 
 # With a combination of scale and coordinate transformation, it's
 # possible to do back-transformations:
-library(scales)
-qplot(carat, price, data=diamonds, log="xy") +
-  geom_smooth(method="lm") +
-  coord_trans(x = exp_trans(10), y = exp_trans(10))
+ggplot(diamonds, aes(carat, price)) +
+  geom_point() +
+  geom_smooth(method = "lm") +
+  scale_x_log10() +
+  scale_y_log10() +
+  coord_trans(x = scales::exp_trans(10), y = scales::exp_trans(10))
+
 # cf.
-qplot(carat, price, data=diamonds) + geom_smooth(method = "lm")
+ggplot(diamonds, aes(carat, price)) +
+  geom_point() +
+  geom_smooth(method = "lm")
 
 # Also works with discrete scales
 df <- data.frame(a = abs(rnorm(26)),letters)
diff --git a/man/cut_interval.Rd b/man/cut_interval.Rd
index 6db6ef0..27ef250 100644
--- a/man/cut_interval.Rd
+++ b/man/cut_interval.Rd
@@ -1,10 +1,17 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/utilities-break.r
 \name{cut_interval}
 \alias{cut_interval}
-\title{Cut numeric vector into intervals of equal length.}
+\alias{cut_number}
+\alias{cut_width}
+\title{Cut up numeric vector into useful groups.}
 \usage{
 cut_interval(x, n = NULL, length = NULL, ...)
+
+cut_number(x, n = NULL, ...)
+
+cut_width(x, width, center = NULL, boundary = NULL, closed = c("right",
+  "left"))
 }
 \arguments{
 \item{x}{numeric vector}
@@ -14,14 +21,39 @@ cut_interval(x, n = NULL, length = NULL, ...)
 \item{length}{length of each interval}
 
 \item{...}{other arguments passed on to \code{\link{cut}}}
+
+\item{width}{The bin width.}
+
+\item{center, boundary}{Specify either the position of edge or the center of
+  a bin. Since all bins are aligned, specifying the position of a single bin
+  (which doesn't need to be in the range of the data) affects the location of
+  all bins. If not specified, uses the "tile layers algorithm", and sets
+  the boundary to half of the binwidth.
+
+  To center on integers, \code{width = 1} and \code{center = 0}.
+  \code{boundary = 0.5}.}
+
+\item{closed}{One of \code{"right"} or \code{"left"} indicating whether right
+or left edges of bins are included in the bin.}
 }
 \description{
-Cut numeric vector into intervals of equal length.
+\code{cut_interval} makes \code{n} groups with equal range, \code{cut_number}
+makes \code{n} groups with (approximately) equal numbers of observations;
+\code{cut_width} makes groups of width \code{width}.
 }
 \examples{
-table(cut_interval(1:100, n = 10))
-table(cut_interval(1:100, n = 11))
-table(cut_interval(1:100, length = 10))
+table(cut_interval(1:100, 10))
+table(cut_interval(1:100, 11))
+
+table(cut_number(runif(1000), 10))
+
+table(cut_width(runif(1000), 0.1))
+table(cut_width(runif(1000), 0.1, boundary = 0))
+table(cut_width(runif(1000), 0.1, center = 0))
+}
+\author{
+Randall Prium contributed most of the implementation of
+   \code{cut_width}.
 }
 \seealso{
 \code{\link{cut_number}}
diff --git a/man/cut_number.Rd b/man/cut_number.Rd
deleted file mode 100644
index 3aa65d9..0000000
--- a/man/cut_number.Rd
+++ /dev/null
@@ -1,25 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/utilities-break.r
-\name{cut_number}
-\alias{cut_number}
-\title{Cut numeric vector into intervals containing equal number of points.}
-\usage{
-cut_number(x, n = NULL, ...)
-}
-\arguments{
-\item{x}{numeric vector}
-
-\item{n}{number of intervals to create}
-
-\item{...}{other arguments passed on to \code{\link{cut}}}
-}
-\description{
-Cut numeric vector into intervals containing equal number of points.
-}
-\examples{
-table(cut_number(runif(1000), n = 10))
-}
-\seealso{
-\code{\link{cut_interval}}
-}
-
diff --git a/man/cweave.Rd b/man/cweave.Rd
deleted file mode 100644
index 2cffa69..0000000
--- a/man/cweave.Rd
+++ /dev/null
@@ -1,19 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/utilities-matrix.r
-\name{cweave}
-\alias{cweave}
-\title{Col weave}
-\usage{
-cweave(...)
-}
-\arguments{
-\item{...}{matrices to weave together}
-}
-\description{
-Weave together two (or more) matrices by column
-}
-\details{
-Matrices must have same dimensions
-}
-\keyword{internal}
-
diff --git a/man/diamonds.Rd b/man/diamonds.Rd
index 54c54c0..08e61e9 100644
--- a/man/diamonds.Rd
+++ b/man/diamonds.Rd
@@ -1,30 +1,29 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/ggplot2.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/data.R
 \docType{data}
 \name{diamonds}
 \alias{diamonds}
 \title{Prices of 50,000 round cut diamonds}
-\format{A data frame with 53940 rows and 10 variables}
+\format{A data frame with 53940 rows and 10 variables:
+\itemize{
+  \item price: price in US dollars (\$326--\$18,823)
+  \item carat: weight of the diamond (0.2--5.01)
+  \item cut: quality of the cut (Fair, Good, Very Good, Premium, Ideal)
+  \item color: diamond colour, from J (worst) to D (best)
+  \item clarity: a measurement of how clear the diamond is
+     (I1 (worst), SI1, SI2, VS1, VS2, VVS1, VVS2, IF (best))
+  \item x: length in mm (0--10.74)
+  \item y: width in mm (0--58.9)
+  \item z: depth in mm (0--31.8)
+  \item depth: total depth percentage = z / mean(x, y) = 2 * z / (x + y) (43--79)
+  \item table: width of top of diamond relative to widest point (43--95)
+}}
 \usage{
-data(diamonds)
+diamonds
 }
 \description{
 A dataset containing the prices and other attributes of almost 54,000
  diamonds. The variables are as follows:
 }
-\details{
-\itemize{
-  \item price. price in US dollars (\$326--\$18,823)
-  \item carat. weight of the diamond (0.2--5.01)
-  \item cut. quality of the cut (Fair, Good, Very Good, Premium, Ideal)
-  \item colour. diamond colour, from J (worst) to D (best)
-  \item clarity. a measurement of how clear the diamond is (I1 (worst), SI1, SI2, VS1, VS2, VVS1, VVS2, IF (best))
-  \item x. length in mm (0--10.74)
-  \item y. width in mm (0--58.9)
-  \item z. depth in mm (0--31.8)
-  \item depth. total depth percentage = z / mean(x, y) = 2 * z / (x + y) (43--79)
-  \item table. width of top of diamond relative to widest point (43--95)
-}
-}
 \keyword{datasets}
 
diff --git a/man/discrete_scale.Rd b/man/discrete_scale.Rd
index dd64a8f..9b4aafa 100644
--- a/man/discrete_scale.Rd
+++ b/man/discrete_scale.Rd
@@ -1,11 +1,11 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/scale-.r
 \name{discrete_scale}
 \alias{discrete_scale}
 \title{Discrete scale constructor.}
 \usage{
-discrete_scale(aesthetics, scale_name, palette, name = NULL,
-  breaks = waiver(), labels = waiver(), legend = NULL, limits = NULL,
+discrete_scale(aesthetics, scale_name, palette, name = waiver(),
+  breaks = waiver(), labels = waiver(), limits = NULL,
   expand = waiver(), na.value = NA, drop = TRUE, guide = "legend")
 }
 \arguments{
@@ -39,14 +39,13 @@ labels (labels the same as breaks), a character vector the same length
 as breaks, or a named character vector whose names are used to match
 replacement the labels for matching breaks.}
 
-\item{legend}{deprecated.  Use \code{guide} instead.}
-
 \item{limits}{A character vector specifying the data range for the scale.
 and the default order of their display in guides.}
 
 \item{expand}{a numeric vector of length two, giving a multiplicative and
 additive constant used to expand the range of the scales so that there
-is a small gap between the data and the axes.}
+is a small gap between the data and the axes. The defaults are (0,0.6)
+for discrete scales and (0.05,0) for continuous scales.}
 
 \item{na.value}{how should missing values be displayed?}
 
@@ -54,7 +53,7 @@ is a small gap between the data and the axes.}
 \code{FALSE})}
 
 \item{guide}{the name of, or actual function, used to create the
-guide.}
+guide. See \code{\link{guides}} for more info.}
 }
 \description{
 Discrete scale constructor.
diff --git a/man/draw_key.Rd b/man/draw_key.Rd
new file mode 100644
index 0000000..aa01550
--- /dev/null
+++ b/man/draw_key.Rd
@@ -0,0 +1,68 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/legend-draw.r
+\name{draw_key}
+\alias{draw_key}
+\alias{draw_key_abline}
+\alias{draw_key_blank}
+\alias{draw_key_boxplot}
+\alias{draw_key_crossbar}
+\alias{draw_key_dotplot}
+\alias{draw_key_label}
+\alias{draw_key_path}
+\alias{draw_key_point}
+\alias{draw_key_pointrange}
+\alias{draw_key_polygon}
+\alias{draw_key_rect}
+\alias{draw_key_smooth}
+\alias{draw_key_text}
+\alias{draw_key_vline}
+\alias{draw_key_vpath}
+\title{Key drawing functions}
+\usage{
+draw_key_point(data, params, size)
+
+draw_key_abline(data, params, size)
+
+draw_key_rect(data, params, size)
+
+draw_key_polygon(data, params, size)
+
+draw_key_blank(data, params, size)
+
+draw_key_boxplot(data, params, size)
+
+draw_key_crossbar(data, params, size)
+
+draw_key_path(data, params, size)
+
+draw_key_vpath(data, params, size)
+
+draw_key_dotplot(data, params, size)
+
+draw_key_pointrange(data, params, size)
+
+draw_key_smooth(data, params, size)
+
+draw_key_text(data, params, size)
+
+draw_key_label(data, params, size)
+
+draw_key_vline(data, params, size)
+}
+\arguments{
+\item{data}{A single row data frame containing the scaled aesthetics to
+display in this key}
+
+\item{params}{A list of additional parameters supplied to the geom.}
+
+\item{size}{Width and height of key in mm.}
+}
+\value{
+A grid grob.
+}
+\description{
+Each Geom has an associated function that draws the key when the geom needs
+to be displayed in a legend. These are the options built into ggplot2.
+}
+\keyword{internal}
+
diff --git a/man/economics.Rd b/man/economics.Rd
index 1127701..921a79b 100644
--- a/man/economics.Rd
+++ b/man/economics.Rd
@@ -1,27 +1,33 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/ggplot2.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/data.R
 \docType{data}
 \name{economics}
 \alias{economics}
+\alias{economics_long}
 \title{US economic time series.}
-\format{A data frame with 478 rows and 6 variables}
-\usage{
-data(economics)
-}
-\description{
-This dataset was produced from US economic time series data available from \url{http://research.stlouisfed.org/fred2}.
-}
-\details{
+\format{A data frame with 478 rows and 6 variables
 \itemize{
   \item date.  Month of data collection
+  \item psavert, personal savings rate,
+    \url{http://research.stlouisfed.org/fred2/series/PSAVERT/}
+  \item pce, personal consumption expenditures, in billions of dollars,
+    \url{http://research.stlouisfed.org/fred2/series/PCE}
+  \item unemploy, number of unemployed in thousands,
+    \url{http://research.stlouisfed.org/fred2/series/UNEMPLOY}
+  \item uempmed, median duration of unemployment, in week,
+    \url{http://research.stlouisfed.org/fred2/series/UEMPMED}
+  \item pop, total population, in thousands,
+   \url{http://research.stlouisfed.org/fred2/series/POP}
+}}
+\usage{
+economics
 
-\item psavert, personal savings rate, \url{http://research.stlouisfed.org/fred2/series/PSAVERT/}
-  \item pce, personal consumption expenditures, in billions of dollars, \url{http://research.stlouisfed.org/fred2/series/PCE}
-  \item unemploy, number of unemployed in thousands, \url{http://research.stlouisfed.org/fred2/series/UNEMPLOY}
-  \item uempmed, median duration of unemployment, in week, \url{http://research.stlouisfed.org/fred2/series/UEMPMED}
-  \item pop, total population, in thousands, \url{http://research.stlouisfed.org/fred2/series/POP}
-
+economics_long
 }
+\description{
+This dataset was produced from US economic time series data available from
+\url{http://research.stlouisfed.org/fred2}. \code{economics} is in "wide"
+format, \code{economics_long} is in "long" format.
 }
 \keyword{datasets}
 
diff --git a/man/element_blank.Rd b/man/element_blank.Rd
index 321f014..042adcb 100644
--- a/man/element_blank.Rd
+++ b/man/element_blank.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/theme-elements.r
 \name{element_blank}
 \alias{element_blank}
diff --git a/man/element_grob.Rd b/man/element_grob.Rd
new file mode 100644
index 0000000..04c6a07
--- /dev/null
+++ b/man/element_grob.Rd
@@ -0,0 +1,19 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/theme-elements.r
+\name{element_grob}
+\alias{element_grob}
+\title{Generate grid grob from theme element}
+\usage{
+element_grob(element, ...)
+}
+\arguments{
+\item{element}{Theme element, i.e. \code{element_rect} or similar.}
+
+\item{...}{Other arguments to control specific of rendering. This is
+usually at least position. See the source code for individual methods.}
+}
+\description{
+Generate grid grob from theme element
+}
+\keyword{internal}
+
diff --git a/man/element_line.Rd b/man/element_line.Rd
index deffb2b..1f2ce79 100644
--- a/man/element_line.Rd
+++ b/man/element_line.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/theme-elements.r
 \name{element_line}
 \alias{element_line}
diff --git a/man/element_rect.Rd b/man/element_rect.Rd
index 2913685..bc034f2 100644
--- a/man/element_rect.Rd
+++ b/man/element_rect.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/theme-elements.r
 \name{element_rect}
 \alias{element_rect}
diff --git a/man/element_text.Rd b/man/element_text.Rd
index 68fe8e0..55433b4 100644
--- a/man/element_text.Rd
+++ b/man/element_text.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/theme-elements.r
 \name{element_text}
 \alias{element_text}
@@ -6,7 +6,7 @@
 \usage{
 element_text(family = NULL, face = NULL, colour = NULL, size = NULL,
   hjust = NULL, vjust = NULL, angle = NULL, lineheight = NULL,
-  color = NULL)
+  color = NULL, margin = NULL, debug = NULL)
 }
 \arguments{
 \item{family}{font family}
@@ -26,6 +26,14 @@ element_text(family = NULL, face = NULL, colour = NULL, size = NULL,
 \item{lineheight}{line height}
 
 \item{color}{an alias for \code{colour}}
+
+\item{margin}{margins around the text. See \code{\link{margin}} for more
+details. When creating a theme, the margins should be placed on the
+side of the text facing towards the center of the plot.}
+
+\item{debug}{If \code{TRUE}, aids visual debugging by drawing a solid
+rectangle behind the complete text area, and a point where each label
+is anchored.}
 }
 \description{
 Theme element: text.
diff --git a/man/expand_limits.Rd b/man/expand_limits.Rd
index 5c88fc4..1759ffc 100644
--- a/man/expand_limits.Rd
+++ b/man/expand_limits.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/limits.r
 \name{expand_limits}
 \alias{expand_limits}
@@ -15,14 +15,16 @@ panels or all plots.  This function is a thin wrapper around
 \code{\link{geom_blank}} that makes it easy to add such values.
 }
 \examples{
-p <- qplot(mpg, wt, data = mtcars)
+p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
 p + expand_limits(x = 0)
 p + expand_limits(y = c(1, 9))
 p + expand_limits(x = 0, y = 0)
 
-qplot(mpg, wt, data = mtcars, colour = cyl) +
- expand_limits(colour = seq(2, 10, by = 2))
-qplot(mpg, wt, data = mtcars, colour = factor(cyl)) +
- expand_limits(colour = factor(seq(2, 10, by = 2)))
+ggplot(mtcars, aes(mpg, wt)) +
+  geom_point(aes(colour = cyl)) +
+  expand_limits(colour = seq(2, 10, by = 2))
+ggplot(mtcars, aes(mpg, wt)) +
+  geom_point(aes(colour = factor(cyl))) +
+  expand_limits(colour = factor(seq(2, 10, by = 2)))
 }
 
diff --git a/man/facet.Rd b/man/facet.Rd
index 11f81ff..da462e8 100644
--- a/man/facet.Rd
+++ b/man/facet.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/facet-.r
 \name{facet}
 \alias{facet}
diff --git a/man/facet_grid.Rd b/man/facet_grid.Rd
index 0c42473..ac22e97 100644
--- a/man/facet_grid.Rd
+++ b/man/facet_grid.Rd
@@ -1,11 +1,12 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/facet-grid-.r
 \name{facet_grid}
 \alias{facet_grid}
 \title{Lay out panels in a grid.}
 \usage{
 facet_grid(facets, margins = FALSE, scales = "fixed", space = "fixed",
-  shrink = TRUE, labeller = "label_value", as.table = TRUE, drop = TRUE)
+  shrink = TRUE, labeller = "label_value", as.table = TRUE,
+  switch = NULL, drop = TRUE)
 }
 \arguments{
 \item{facets}{a formula with the rows (of the tabular display) on the LHS
@@ -36,15 +37,26 @@ vary.  This setting has no effect unless the appropriate scales also vary.}
 statistics, not raw data. If \code{FALSE}, will be range of raw data
 before statistical summary.}
 
-\item{labeller}{A function that takes two arguments (\code{variable} and
-\code{value}) and returns a string suitable for display in the facet
-strip. See \code{\link{label_value}} for more details and pointers
-to other options.}
+\item{labeller}{A function that takes one data frame of labels and
+returns a list or data frame of character vectors. Each input
+column corresponds to one factor. Thus there will be more than
+one with formulae of the type \code{~cyl + am}. Each output
+column gets displayed as one separate line in the strip
+label. This function should inherit from the "labeller" S3 class
+for compatibility with \code{\link{labeller}()}. See
+\code{\link{label_value}} for more details and pointers to other
+options.}
 
 \item{as.table}{If \code{TRUE}, the default, the facets are laid out like
 a table with highest values at the bottom-right. If \code{FALSE}, the
 facets are laid out like a plot with the highest value at the top-right.}
 
+\item{switch}{By default, the labels are displayed on the top and
+right of the plot. If \code{"x"}, the top labels will be
+displayed to the bottom. If \code{"y"}, the right-hand side
+labels will be displayed to the left. Can also be set to
+\code{"both"}.}
+
 \item{drop}{If \code{TRUE}, the default, all factor levels not used in the
 data will automatically be dropped. If \code{FALSE}, all factor levels
 will be shown, regardless of whether or not they appear in the data.}
@@ -77,35 +89,47 @@ p <- ggplot(diamonds, aes(carat, ..density..)) +
         geom_histogram(binwidth = 1)
 p + facet_grid(. ~ cut)
 
-qplot(mpg, wt, data=mtcars, facets = . ~ vs + am)
-qplot(mpg, wt, data=mtcars, facets = vs + am ~ . )
+g <- ggplot(mtcars, aes(mpg, wt)) +
+  geom_point()
+g + facet_grid(. ~ vs + am)
+g + facet_grid(vs + am ~ .)
 
 # You can also use strings, which makes it a little easier
 # when writing functions that generate faceting specifications
-# p + facet_grid("cut ~ .")
+
+p + facet_grid("cut ~ .")
 
 # see also ?plotmatrix for the scatterplot matrix
 
 # If there isn't any data for a given combination, that panel
 # will be empty
-qplot(mpg, wt, data=mtcars) + facet_grid(cyl ~ vs)
 
-p <- qplot(mpg, wt, data=mtcars, facets = vs ~ cyl)
+g + facet_grid(cyl ~ vs)
+
+# If you combine a facetted dataset with a dataset that lacks those
+# facetting variables, the data will be repeated across the missing
+# combinations:
+
+g + facet_grid(vs ~ cyl)
 
 df <- data.frame(mpg = 22, wt = 3)
-p + geom_point(data = df, colour="red", size = 2)
+g + facet_grid(vs ~ cyl) +
+  geom_point(data = df, colour = "red", size = 2)
 
 df2 <- data.frame(mpg = c(19, 22), wt = c(2,4), vs = c(0, 1))
-p + geom_point(data = df2, colour="red", size = 2)
+g + facet_grid(vs ~ cyl) +
+  geom_point(data = df2, colour = "red", size = 2)
 
 df3 <- data.frame(mpg = c(19, 22), wt = c(2,4), vs = c(1, 1))
-p + geom_point(data = df3, colour="red", size = 2)
+g + facet_grid(vs ~ cyl) +
+  geom_point(data = df3, colour = "red", size = 2)
 
 
 # You can also choose whether the scales should be constant
 # across all panels (the default), or whether they should be allowed
 # to vary
-mt <- ggplot(mtcars, aes(mpg, wt, colour = factor(cyl))) + geom_point()
+mt <- ggplot(mtcars, aes(mpg, wt, colour = factor(cyl))) +
+  geom_point()
 
 mt + facet_grid(. ~ cyl, scales = "free")
 # If scales and space are free, then the mapping between position
@@ -115,28 +139,28 @@ mt + facet_grid(. ~ cyl, scales = "free", space = "free")
 mt + facet_grid(vs ~ am, scales = "free")
 mt + facet_grid(vs ~ am, scales = "free_x")
 mt + facet_grid(vs ~ am, scales = "free_y")
-mt + facet_grid(vs ~ am, scales = "free", space="free")
-mt + facet_grid(vs ~ am, scales = "free", space="free_x")
-mt + facet_grid(vs ~ am, scales = "free", space="free_y")
+mt + facet_grid(vs ~ am, scales = "free", space = "free")
+mt + facet_grid(vs ~ am, scales = "free", space = "free_x")
+mt + facet_grid(vs ~ am, scales = "free", space = "free_y")
 
 # You may need to set your own breaks for consistent display:
-mt + facet_grid(. ~ cyl, scales = "free_x", space="free") +
+mt + facet_grid(. ~ cyl, scales = "free_x", space = "free") +
   scale_x_continuous(breaks = seq(10, 36, by = 2))
 # Adding scale limits override free scales:
 last_plot() + xlim(10, 15)
 
 # Free scales are particularly useful for categorical variables
-qplot(cty, model, data=mpg) +
+ggplot(mpg, aes(cty, model)) +
+  geom_point() +
   facet_grid(manufacturer ~ ., scales = "free", space = "free")
 # particularly when you reorder factor levels
-mpg <- within(mpg, {
-  model <- reorder(model, cty)
-  manufacturer <- reorder(manufacturer, cty)
-})
+mpg$model <- reorder(mpg$model, mpg$cty)
+manufacturer <- reorder(mpg$manufacturer, mpg$cty)
 last_plot() \%+\% mpg + theme(strip.text.y = element_text())
 
 # Use as.table to to control direction of horizontal facets, TRUE by default
-h <- ggplot(mtcars, aes(x = mpg, y = wt)) + geom_point()
+h <- ggplot(mtcars, aes(x = mpg, y = wt)) +
+  geom_point()
 h + facet_grid(cyl ~ vs)
 h + facet_grid(cyl ~ vs, as.table = FALSE)
 
@@ -144,11 +168,13 @@ h + facet_grid(cyl ~ vs, as.table = FALSE)
 h + facet_grid(cyl ~ vs, labeller = label_both)
 # Using label_parsed, see ?plotmath for more options
 mtcars$cyl2 <- factor(mtcars$cyl, labels = c("alpha", "beta", "sqrt(x, y)"))
-k <- qplot(wt, mpg, data = mtcars)
+k <- ggplot(mtcars, aes(wt, mpg)) +
+  geom_point()
 k + facet_grid(. ~ cyl2)
 k + facet_grid(. ~ cyl2, labeller = label_parsed)
 # For label_bquote the label value is x.
-p <- qplot(wt, mpg, data = mtcars)
+p <- ggplot(mtcars, aes(wt, mpg)) +
+  geom_point()
 p + facet_grid(. ~ vs, labeller = label_bquote(alpha ^ .(x)))
 p + facet_grid(. ~ vs, labeller = label_bquote(.(x) ^ .(x)))
 
@@ -164,6 +190,20 @@ mg + facet_grid(vs + am ~ gear, margins = "am")
 mg + facet_grid(vs + am ~ gear, margins = "vs")
 mg + facet_grid(vs + am ~ gear, margins = "gear")
 mg + facet_grid(vs + am ~ gear, margins = c("gear", "am"))
+
+# The facet strips can be displayed near the axes with switch
+data <- transform(mtcars,
+  am = factor(am, levels = 0:1, c("Automatic", "Manual")),
+  gear = factor(gear, levels = 3:5, labels = c("Three", "Four", "Five"))
+)
+p <- ggplot(data, aes(mpg, disp)) + geom_point()
+p + facet_grid(am ~ gear, switch = "both") + theme_light()
+
+# It may be more aesthetic to use a theme without boxes around
+# around the strips.
+p + facet_grid(am ~ gear + vs, switch = "y") + theme_minimal()
+p + facet_grid(am ~ ., switch = "y") +
+  theme_gray() \%+replace\% theme(strip.background  = element_blank())
 }
 }
 
diff --git a/man/facet_null.Rd b/man/facet_null.Rd
index 015250b..c1b302b 100644
--- a/man/facet_null.Rd
+++ b/man/facet_null.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/facet-null.r
 \name{facet_null}
 \alias{facet_null}
@@ -18,6 +18,5 @@ Facet specification: a single panel.
 # facet_null is the default facetting specification if you
 # don't override it with facet_grid or facet_wrap
 ggplot(mtcars, aes(mpg, wt)) + geom_point()
-qplot(mpg, wt, data = mtcars)
 }
 
diff --git a/man/facet_wrap.Rd b/man/facet_wrap.Rd
index ead253d..c20baa7 100644
--- a/man/facet_wrap.Rd
+++ b/man/facet_wrap.Rd
@@ -1,81 +1,113 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/facet-wrap.r
 \name{facet_wrap}
 \alias{facet_wrap}
 \title{Wrap a 1d ribbon of panels into 2d.}
 \usage{
 facet_wrap(facets, nrow = NULL, ncol = NULL, scales = "fixed",
-  shrink = TRUE, as.table = TRUE, drop = TRUE)
+  shrink = TRUE, labeller = "label_value", as.table = TRUE,
+  switch = NULL, drop = TRUE, dir = "h")
 }
 \arguments{
-\item{facets}{formula specifying variables to facet by}
+\item{facets}{Either a formula or character vector. Use either a
+one sided formula, \code{~a + b}, or a character vector, \code{c("a", "b")}.}
 
-\item{nrow}{number of rows}
+\item{nrow, ncol}{Number of rows and columns.}
 
-\item{ncol}{number of columns}
-
-\item{scales}{should scales be fixed (\code{"fixed"}, the default),
-free (\code{"free"}), or free in one dimension  (\code{"free_x"},
-\code{"free_y"})}
+\item{scales}{should Scales be fixed (\code{"fixed"}, the default),
+free (\code{"free"}), or free in one dimension (\code{"free_x"},
+\code{"free_y"}).}
 
 \item{shrink}{If \code{TRUE}, will shrink scales to fit output of
 statistics, not raw data. If \code{FALSE}, will be range of raw data
 before statistical summary.}
 
+\item{labeller}{A function that takes one data frame of labels and
+returns a list or data frame of character vectors. Each input
+column corresponds to one factor. Thus there will be more than
+one with formulae of the type \code{~cyl + am}. Each output
+column gets displayed as one separate line in the strip
+label. This function should inherit from the "labeller" S3 class
+for compatibility with \code{\link{labeller}()}. See
+\code{\link{label_value}} for more details and pointers to other
+options.}
+
 \item{as.table}{If \code{TRUE}, the default, the facets are laid out like
 a table with highest values at the bottom-right. If \code{FALSE}, the
 facets are laid out like a plot with the highest value at the top-right.}
 
+\item{switch}{By default, the labels are displayed on the top of
+the plot. If \code{switch} is \code{"x"}, they will be displayed
+to the bottom. If \code{"y"}, they will be displayed to the
+left, near the y axis.}
+
 \item{drop}{If \code{TRUE}, the default, all factor levels not used in the
 data will automatically be dropped. If \code{FALSE}, all factor levels
 will be shown, regardless of whether or not they appear in the data.}
+
+\item{dir}{Direction: either "h" for horizontal, the default, or "v", for
+vertical.}
 }
 \description{
-Wrap a 1d ribbon of panels into 2d.
+Most displays are roughly rectangular, so if you have a categorical
+variable with many levels, it doesn't make sense to try and display them
+all in one row (or one column). To solve this dilemma, \code{facet_wrap}
+wraps a 1d sequence of panels into 2d, making best use of screen real estate.
 }
 \examples{
+ggplot(mpg, aes(displ, hwy)) +
+  geom_point() +
+  facet_wrap(~class)
+
+# Control the number of rows and columns with nrow and ncol
+ggplot(mpg, aes(displ, hwy)) +
+  geom_point() +
+  facet_wrap(~class, nrow = 4)
+
 \donttest{
-d <- ggplot(diamonds, aes(carat, price, fill = ..density..)) +
-  xlim(0, 2) + stat_binhex(na.rm = TRUE) + theme(aspect.ratio = 1)
-d + facet_wrap(~ color)
-d + facet_wrap(~ color, ncol = 1)
-d + facet_wrap(~ color, ncol = 4)
-d + facet_wrap(~ color, nrow = 1)
-d + facet_wrap(~ color, nrow = 3)
-
-# Using multiple variables continues to wrap the long ribbon of
-# plots into 2d - the ribbon just gets longer
-# d + facet_wrap(~ color + cut)
-
-# To change plot order of facet wrap,
-# change the order of varible levels with factor()
-diamonds$color <- factor(diamonds$color, levels = c("G", "J", "D", "E", "I", "F", "H"))
-# Repeat first example with new order
-d <- ggplot(diamonds, aes(carat, price, fill = ..density..)) +
-xlim(0, 2) + stat_binhex(na.rm = TRUE) + theme(aspect.ratio = 1)
-d + facet_wrap(~ color)
-
-# You can choose to keep the scales constant across all panels
-# or vary the x scale, the y scale or both:
-p <- qplot(price, data = diamonds, geom = "histogram", binwidth = 1000)
-p + facet_wrap(~ color)
-p + facet_wrap(~ color, scales = "free_y")
-
-p <- qplot(displ, hwy, data = mpg)
-p + facet_wrap(~ cyl)
-p + facet_wrap(~ cyl, scales = "free")
-
-# Use as.table to to control direction of horizontal facets, TRUE by default
-p + facet_wrap(~ cyl, as.table = FALSE)
-
-# Add data that does not contain all levels of the faceting variables
-cyl6 <- subset(mpg, cyl == 6)
-p + geom_point(data = cyl6, colour = "red", size = 1) +
-  facet_wrap(~ cyl)
-p + geom_point(data = transform(cyl6, cyl = 7), colour = "red") +
-  facet_wrap(~ cyl)
-p + geom_point(data = transform(cyl6, cyl = NULL), colour = "red") +
-  facet_wrap(~ cyl)
+# You can facet by multiple variables
+ggplot(mpg, aes(displ, hwy)) +
+  geom_point() +
+  facet_wrap(~ cyl + drv)
+# Or use a character vector:
+ggplot(mpg, aes(displ, hwy)) +
+  geom_point() +
+  facet_wrap(c("cyl", "drv"))
+
+# Use the `labeller` option to control how labels are printed:
+ggplot(mpg, aes(displ, hwy)) +
+  geom_point() +
+  facet_wrap(c("cyl", "drv"), labeller = "label_both")
+
+# To change the order in which the panels appear, change the levels
+# of the underlying factor.
+mpg$class2 <- reorder(mpg$class, mpg$displ)
+ggplot(mpg, aes(displ, hwy)) +
+  geom_point() +
+  facet_wrap(~class2)
+
+# By default, the same scales are used for all panels. You can allow
+# scales to vary across the panels with the `scales` argument.
+# Free scales make it easier to see patterns within each panel, but
+# harder to compare across panels.
+ggplot(mpg, aes(displ, hwy)) +
+  geom_point() +
+  facet_wrap(~class, scales = "free")
+
+# To repeat the same data in every panel, simply construct a data frame
+# that does not contain the facetting variable.
+ggplot(mpg, aes(displ, hwy)) +
+  geom_point(data = transform(mpg, class = NULL), colour = "grey85") +
+  geom_point() +
+  facet_wrap(~class)
+
+# Use `switch` to display the facet labels near an axis, acting as
+# a subtitle for this axis. This is typically used with free scales
+# and a theme without boxes around strip labels.
+ggplot(economics_long, aes(date, value)) +
+  geom_line() +
+  facet_wrap(~variable, scales = "free_y", nrow = 2, switch = "x") +
+  theme(strip.background = element_blank())
 }
 }
 
diff --git a/man/faithfuld.Rd b/man/faithfuld.Rd
new file mode 100644
index 0000000..1f75e91
--- /dev/null
+++ b/man/faithfuld.Rd
@@ -0,0 +1,16 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/data.R
+\docType{data}
+\name{faithfuld}
+\alias{faithfuld}
+\title{2d density estimate of Old Faithful data}
+\format{A data frame with 5,625 observations and 3 variables.}
+\usage{
+faithfuld
+}
+\description{
+A 2d density estimate of the waiting and eruptions variables data
+\link{faithful}.
+}
+\keyword{datasets}
+
diff --git a/man/format.ggproto.Rd b/man/format.ggproto.Rd
new file mode 100644
index 0000000..e2c12ec
--- /dev/null
+++ b/man/format.ggproto.Rd
@@ -0,0 +1,21 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/ggproto.r
+\name{format.ggproto}
+\alias{format.ggproto}
+\title{Format a ggproto object}
+\usage{
+\method{format}{ggproto}(x, ..., flat = TRUE)
+}
+\arguments{
+\item{x}{A ggproto object to print.}
+
+\item{...}{If the ggproto object has a \code{print} method, further arguments
+will be passed to it. Otherwise, these arguments are unused.}
+
+\item{flat}{If \code{TRUE} (the default), show a flattened list of all local
+and inherited members. If \code{FALSE}, show the inheritance hierarchy.}
+}
+\description{
+Format a ggproto object
+}
+
diff --git a/man/fortify-multcomp.Rd b/man/fortify-multcomp.Rd
index 268393f..b2174c2 100644
--- a/man/fortify-multcomp.Rd
+++ b/man/fortify-multcomp.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/fortify-multcomp.r
 \name{fortify-multcomp}
 \alias{fortify-multcomp}
@@ -20,7 +20,7 @@
 \item{model}{an object of class \code{glht}, \code{confint.glht},
 \code{summary.glht} or \code{\link[multcomp]{cld}}}
 
-\item{data,...}{other arguments to the generic ignored in this method.}
+\item{data, ...}{other arguments to the generic ignored in this method.}
 }
 \description{
 Fortify methods for objects produced by \pkg{multcomp}
diff --git a/man/fortify.Rd b/man/fortify.Rd
index 06fc25f..e80157f 100644
--- a/man/fortify.Rd
+++ b/man/fortify.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/fortify.r
 \name{fortify}
 \alias{fortify}
@@ -14,9 +14,9 @@ fortify(model, data, ...)
 \item{...}{other arguments passed to methods}
 }
 \description{
-Method to convert a generic R object into a data frame useful for plotting.
-Takes its name from the idea of fortifying the original data with model fit
-statistics, and vice versa.
+Rather than using this function, I now recomend using the \pkg{broom}
+package, which implements a much wider range of methods. \code{fortify}
+may be deprecated in the future.
 }
 \seealso{
 \code{\link{fortify.lm}}
diff --git a/man/fortify.lm.Rd b/man/fortify.lm.Rd
index b1e1869..f4e5e3f 100644
--- a/man/fortify.lm.Rd
+++ b/man/fortify.lm.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/fortify-lm.r
 \name{fortify.lm}
 \alias{fortify.lm}
@@ -33,34 +33,45 @@ head(fortify(mod))
 head(fortify(mod, mtcars))
 
 plot(mod, which = 1)
-qplot(.fitted, .resid, data = mod) +
+
+ggplot(mod, aes(.fitted, .resid)) +
+  geom_point() +
   geom_hline(yintercept = 0) +
   geom_smooth(se = FALSE)
-qplot(.fitted, .stdresid, data = mod) +
+
+ggplot(mod, aes(.fitted, .stdresid)) +
+  geom_point() +
   geom_hline(yintercept = 0) +
   geom_smooth(se = FALSE)
-qplot(.fitted, .stdresid, data = fortify(mod, mtcars),
-  colour = factor(cyl))
-qplot(mpg, .stdresid, data = fortify(mod, mtcars), colour = factor(cyl))
+
+ggplot(fortify(mod, mtcars), aes(.fitted, .stdresid)) +
+  geom_point(aes(colour = factor(cyl)))
+
+ggplot(fortify(mod, mtcars), aes(mpg, .stdresid)) +
+  geom_point(aes(colour = factor(cyl)))
 
 plot(mod, which = 2)
-# qplot(sample =.stdresid, data = mod, stat = "qq") + geom_abline()
+ggplot(mod) +
+  stat_qq(aes(sample = .stdresid)) +
+  geom_abline()
 
 plot(mod, which = 3)
-qplot(.fitted, sqrt(abs(.stdresid)), data = mod) + geom_smooth(se = FALSE)
+ggplot(mod, aes(.fitted, sqrt(abs(.stdresid)))) +
+  geom_point() +
+  geom_smooth(se = FALSE)
 
 plot(mod, which = 4)
-qplot(seq_along(.cooksd), .cooksd, data = mod, geom = "bar",
- stat="identity")
+ggplot(mod, aes(seq_along(.cooksd), .cooksd)) +
+  geom_bar(stat = "identity")
 
 plot(mod, which = 5)
-qplot(.hat, .stdresid, data = mod) + geom_smooth(se = FALSE)
 ggplot(mod, aes(.hat, .stdresid)) +
   geom_vline(size = 2, colour = "white", xintercept = 0) +
   geom_hline(size = 2, colour = "white", yintercept = 0) +
   geom_point() + geom_smooth(se = FALSE)
 
-qplot(.hat, .stdresid, data = mod, size = .cooksd) +
+ggplot(mod, aes(.hat, .stdresid)) +
+  geom_point(aes(size = .cooksd)) +
   geom_smooth(se = FALSE, size = 0.5)
 
 plot(mod, which = 6)
@@ -69,6 +80,9 @@ ggplot(mod, aes(.hat, .cooksd)) +
   geom_abline(slope = seq(0, 3, by = 0.5), colour = "white") +
   geom_smooth(se = FALSE) +
   geom_point()
-qplot(.hat, .cooksd, size = .cooksd / .hat, data = mod) + scale_size_area()
+
+ggplot(mod, aes(.hat, .cooksd)) +
+  geom_point(aes(size = .cooksd / .hat)) +
+  scale_size_area()
 }
 
diff --git a/man/fortify.map.Rd b/man/fortify.map.Rd
index 69980b9..84454ac 100644
--- a/man/fortify.map.Rd
+++ b/man/fortify.map.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/fortify-map.r
 \name{fortify.map}
 \alias{fortify.map}
@@ -21,12 +21,13 @@ plotted with ggplot2.
 if (require("maps")) {
 ca <- map("county", "ca", plot = FALSE, fill = TRUE)
 head(fortify(ca))
-qplot(long, lat, data = ca, geom = "polygon", group = group)
+ggplot(ca, aes(long, lat)) +
+  geom_polygon(aes(group = group))
 
 tx <- map("county", "texas", plot = FALSE, fill = TRUE)
 head(fortify(tx))
-qplot(long, lat, data = tx, geom = "polygon", group = group,
- colour = I("white"))
+ggplot(tx, aes(long, lat)) +
+  geom_polygon(aes(group = group), colour = "white")
 }
 }
 \seealso{
diff --git a/man/fortify.sp.Rd b/man/fortify.sp.Rd
index e85113c..211b19f 100644
--- a/man/fortify.sp.Rd
+++ b/man/fortify.sp.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/fortify-spatial.r
 \name{fortify.sp}
 \alias{fortify.Line}
diff --git a/man/geom_abline.Rd b/man/geom_abline.Rd
index 5e82d37..d5e6fc9 100644
--- a/man/geom_abline.Rd
+++ b/man/geom_abline.Rd
@@ -1,90 +1,115 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-abline.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-abline.r, R/geom-hline.r, R/geom-vline.r
 \name{geom_abline}
 \alias{geom_abline}
-\title{Line specified by slope and intercept.}
+\alias{geom_hline}
+\alias{geom_vline}
+\title{Lines: horizontal, vertical, and specified by slope and intercept.}
 \usage{
-geom_abline(mapping = NULL, data = NULL, stat = "abline",
-  position = "identity", show_guide = FALSE, ...)
+geom_abline(mapping = NULL, data = NULL, ..., slope, intercept,
+  na.rm = FALSE, show.legend = NA)
+
+geom_hline(mapping = NULL, data = NULL, ..., yintercept, na.rm = FALSE,
+  show.legend = NA)
+
+geom_vline(mapping = NULL, data = NULL, ..., xintercept, na.rm = FALSE,
+  show.legend = NA)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
+
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
 
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
 
-\item{show_guide}{should a legend be drawn? (defaults to \code{FALSE})}
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{xintercept, yintercept, slope, intercept}{Parameters that control the
+position of the line. If these are set, \code{data}, \code{mapping} and
+\code{show.legend} are overridden}
 }
 \description{
-The abline geom adds a line with specified slope and intercept to the
-plot.
+These paired geoms and stats add straight lines to a plot, either
+horizontal, vertical or specified by slope and intercept. These are useful
+for annotating plots.
 }
 \details{
-With its siblings \code{geom_hline} and \code{geom_vline}, it's useful for
-annotating plots.  You can supply the parameters for geom_abline,
-intercept and slope, in two ways: either explicitly as fixed values, or
-in a data frame.  If you specify the fixed values
-(\code{geom_abline(intercept=0, slope=1)}) then the line will be the same
-in all panels.  If the intercept and slope are stored in the data, then
-they can vary from panel to panel.  See the examples for more ideas.
+These geoms act slightly different to other geoms. You can supply the
+parameters in two ways: either as arguments to the layer function,
+or via aesthetics. If you use arguments, e.g.
+\code{geom_abline(intercept = 0, slope = 1)}, then behind the scenes
+the geom makes a new data frame containing just the data you've supplied.
+That means that the lines will be the same in all facets; if you want them
+to vary across facets, construct the data frame yourself and use aesthetics.
+
+Unlike most other geoms, these geoms do not inherit aesthetics from the plot
+default, because they do not understand x and y aesthetics which are
+commonly set in the plot. They also do not affect the x and y scales.
 }
 \section{Aesthetics}{
 
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "abline")}
+These geoms are drawn using with \code{\link{geom_line}} so support the
+same aesthetics: alpha, colour, linetype and size. They also each have
+aesthetics that control the position of the line:
+
+\itemize{
+  \item \code{geom_vline}: \code{xintercept}
+  \item \code{geom_hline}: \code{yintercept}
+  \item \code{geom_abline}: \code{slope} and \code{intercept}
+}
 }
 \examples{
-p <- qplot(wt, mpg, data = mtcars)
+p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
+
+# Fixed values
+p + geom_vline(xintercept = 5)
+p + geom_vline(xintercept = 1:5)
+p + geom_hline(yintercept = 20)
 
-# Fixed slopes and intercepts
 p + geom_abline() # Can't see it - outside the range of the data
 p + geom_abline(intercept = 20)
 
 # Calculate slope and intercept of line of best fit
 coef(lm(mpg ~ wt, data = mtcars))
 p + geom_abline(intercept = 37, slope = -5)
-p + geom_abline(intercept = 10, colour = "red", size = 2)
-
-# See ?stat_smooth for fitting smooth models to data
-p + stat_smooth(method="lm", se=FALSE)
-
-# Slopes and intercepts as data
-p <- ggplot(mtcars, aes(x = wt, y=mpg), . ~ cyl) + geom_point()
-df <- data.frame(a=rnorm(10, 25), b=rnorm(10, 0))
-p + geom_abline(aes(intercept=a, slope=b), data=df)
-
-# Slopes and intercepts from linear model
-library(plyr)
-coefs <- ddply(mtcars, .(cyl), function(df) {
-  m <- lm(mpg ~ wt, data=df)
-  data.frame(a = coef(m)[1], b = coef(m)[2])
-})
-str(coefs)
-p + geom_abline(data=coefs, aes(intercept=a, slope=b))
-
-# It's actually a bit easier to do this with stat_smooth
-p + geom_smooth(aes(group=cyl), method="lm")
-p + geom_smooth(aes(group=cyl), method="lm", fullrange=TRUE)
-
-# With coordinate transforms
-p + geom_abline(intercept = 37, slope = -5) + coord_flip()
-p + geom_abline(intercept = 37, slope = -5) + coord_polar()
+# But this is easier to do with geom_smooth:
+p + geom_smooth(method = "lm", se = FALSE)
+
+# To show different lines in different facets, use aesthetics
+p <- ggplot(mtcars, aes(mpg, wt)) +
+  geom_point() +
+  facet_wrap(~ cyl)
+
+mean_wt <- data.frame(cyl = c(4, 6, 8), wt = c(2.28, 3.11, 4.00))
+p + geom_hline(aes(yintercept = wt), mean_wt)
+
+# You can also control other aesthetics
+ggplot(mtcars, aes(mpg, wt, colour = wt)) +
+  geom_point() +
+  geom_hline(aes(yintercept = wt, colour = wt), mean_wt) +
+  facet_wrap(~ cyl)
 }
 \seealso{
-\code{\link{stat_smooth}} to add lines derived from the data,
- \code{\link{geom_hline}} for horizontal lines,
- \code{\link{geom_vline}} for vertical lines
- \code{\link{geom_segment}}
+See \code{\link{geom_segment}} for a more general approach to
+  adding straight line segments to a plot.
 }
 
diff --git a/man/geom_area.Rd b/man/geom_area.Rd
deleted file mode 100644
index d9c8d2c..0000000
--- a/man/geom_area.Rd
+++ /dev/null
@@ -1,46 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-ribbon-.r
-\name{geom_area}
-\alias{geom_area}
-\title{Area plot.}
-\usage{
-geom_area(mapping = NULL, data = NULL, stat = "identity",
-  position = "stack", na.rm = FALSE, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
-
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
-
-\item{na.rm}{If \code{FALSE} (the default), removes missing values with
-a warning.  If \code{TRUE} silently removes missing values.}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-An area plot is the continuous analog of a stacked bar chart (see
-\code{\link{geom_bar}}), and can be used to show how composition of the
-whole varies over the range of x.  Choosing the order in which different
-components is stacked is very important, as it becomes increasing hard to
-see the individual pattern as you move up the stack.
-}
-\details{
-An area plot is a special case of \code{\link{geom_ribbon}}, where the
-minimum of the range is fixed to 0, and the position adjustment defaults
-to position_stacked.
-}
-\examples{
-# see geom_ribbon
-}
-
diff --git a/man/geom_bar.Rd b/man/geom_bar.Rd
index 734aac1..fb5da7d 100644
--- a/man/geom_bar.Rd
+++ b/man/geom_bar.Rd
@@ -1,152 +1,149 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-bar-.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-bar.r, R/stat-count.r
 \name{geom_bar}
 \alias{geom_bar}
+\alias{stat_count}
 \title{Bars, rectangles with bases on x-axis}
 \usage{
-geom_bar(mapping = NULL, data = NULL, stat = "bin", position = "stack",
-  ...)
+geom_bar(mapping = NULL, data = NULL, stat = "count",
+  position = "stack", width = NULL, binwidth = NULL, ..., na.rm = FALSE,
+  show.legend = NA, inherit.aes = TRUE)
+
+stat_count(mapping = NULL, data = NULL, geom = "bar",
+  position = "stack", width = NULL, ..., na.rm = FALSE,
+  show.legend = NA, inherit.aes = TRUE)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
+
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
+
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
+
+\item{width}{Bar width. By default, set to 90\% of the resolution of the data.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{binwidth}{\code{geom_bar} no longer has a binwidth argument - if
+you use it you'll get an warning telling to you use
+\code{\link{geom_histogram}} instead.}
 
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{geom, stat}{Override the default connection between \code{geom_bar} and
+\code{stat_count}.}
 }
 \description{
-The bar geom is used to produce 1d area plots: bar charts for categorical
-x, and histograms for continuous y.  stat_bin explains the details of
-these summaries in more detail.  In particular, you can use the
-\code{weight} aesthetic to create weighted histograms and barcharts where
-the height of the bar no longer represent a count of observations, but a
-sum over some other variable.  See the examples for a practical
-example.
+There are two types of bar charts, determined by what is mapped to bar
+height. By default, \code{geom_bar} uses \code{stat="count"} which makes the
+height of the bar proportion to the number of cases in each group (or if the
+\code{weight} aethetic is supplied, the sum of the weights). If you want the
+heights of the bars to represent values in the data, use
+\code{stat="identity"} and map a variable to the \code{y} aesthetic.
+
+\code{stat_count} counts the number of cases at each x position. If you want
+to bin the data in ranges, you should use \code{\link{stat_bin}} instead.
 }
 \details{
-The heights of the bars commonly represent one of two things: either a
-count of cases in each group, or the values in a column of the data frame.
-By default, \code{geom_bar} uses \code{stat="bin"}. This makes the height
-of each bar equal to the number of cases in each group, and it is
-incompatible with mapping values to the \code{y} aesthetic. If you want
-the heights of the bars to represent values in the data, use
-\code{stat="identity"} and map a value to the \code{y} aesthetic.
-
-By default, multiple x's occuring in the same place will be stacked a top
-one another by position_stack.  If you want them to be dodged from
+A bar chart maps the height of the bar to a variable, and so the base of the
+bar must always be shown to produce a valid visual comparison. Naomi Robbins
+has a nice
+\href{http://www.b-eye-network.com/view/index.php?cid=2468}{article on this
+topic}. This is why it doesn't make sense to use a log-scaled y axis with a
+bar chart.
+
+By default, multiple x's occurring in the same place will be stacked atop one
+another by \code{\link{position_stack}}. If you want them to be dodged
 side-to-side, see \code{\link{position_dodge}}. Finally,
-\code{\link{position_fill}} shows relative propotions at each x by stacking
+\code{\link{position_fill}} shows relative proportions at each x by stacking
 the bars and then stretching or squashing to the same height.
-
-Sometimes, bar charts are used not as a distributional summary, but
-instead of a dotplot.  Generally, it's preferable to use a dotplot (see
-\code{geom_point}) as it has a better data-ink ratio.  However, if you do
-want to create this type of plot, you can set y to the value you have
-calculated, and use \code{stat='identity'}
-
-A bar chart maps the height of the bar to a variable, and so the base of
-the bar must always been shown to produce a valid visual comparison.
-Naomi Robbins has a nice
-\href{http://www.b-eye-network.com/view/index.php?cid=2468}{article on this topic}.
-This is the reason it doesn't make sense to use a log-scaled y axis with a bar chart
 }
 \section{Aesthetics}{
 
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "bar")}
+  \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "bar")}
+}
+
+\section{Computed variables}{
+
+\describe{
+  \item{count}{number of points in bin}
+  \item{prop}{groupwise proportion}
+}
 }
 \examples{
+# geom_bar is designed to make it easy to create bar charts that show
+# counts (or sums of weights)
+g <- ggplot(mpg, aes(class))
+# Number of cars in each class:
+g + geom_bar()
+# Total engine displacement of each class
+g + geom_bar(aes(weight = displ))
+
+# To show (e.g.) means, you need stat = "identity"
+df <- data.frame(trt = c("a", "b", "c"), outcome = c(2.3, 1.9, 3.2))
+ggplot(df, aes(trt, outcome)) +
+  geom_bar(stat = "identity")
+# But geom_point() display exactly the same information and doesn't
+# require the y-axis to touch zero.
+ggplot(df, aes(trt, outcome)) +
+  geom_point()
+
+# You can also use geom_bar() with continuous data, in which case
+# it will show counts at unique locations
+df <- data.frame(x = rep(c(2.9, 3.1, 4.5), c(5, 10, 4)))
+ggplot(df, aes(x)) + geom_bar()
+# cf. a histogram of the same data
+ggplot(df, aes(x)) + geom_histogram(binwidth = 0.5)
+
 \donttest{
-# Generate data
-c <- ggplot(mtcars, aes(factor(cyl)))
-
-# By default, uses stat="bin", which gives the count in each category
-c + geom_bar()
-c + geom_bar(width=.5)
-c + geom_bar() + coord_flip()
-c + geom_bar(fill="white", colour="darkgreen")
-
-# Use qplot
-qplot(factor(cyl), data=mtcars, geom="bar")
-qplot(factor(cyl), data=mtcars, geom="bar", fill=factor(cyl))
-
-# When the data contains y values in a column, use stat="identity"
-library(plyr)
-# Calculate the mean mpg for each level of cyl
-mm <- ddply(mtcars, "cyl", summarise, mmpg = mean(mpg))
-ggplot(mm, aes(x = factor(cyl), y = mmpg)) + geom_bar(stat = "identity")
-
-# Stacked bar charts
-qplot(factor(cyl), data=mtcars, geom="bar", fill=factor(vs))
-qplot(factor(cyl), data=mtcars, geom="bar", fill=factor(gear))
-
-# Stacked bar charts are easy in ggplot2, but not effective visually,
-# particularly when there are many different things being stacked
-ggplot(diamonds, aes(clarity, fill=cut)) + geom_bar()
-ggplot(diamonds, aes(color, fill=cut)) + geom_bar() + coord_flip()
-
-# Faceting is a good alternative:
-ggplot(diamonds, aes(clarity)) + geom_bar() +
-  facet_wrap(~ cut)
-# If the x axis is ordered, using a line instead of bars is another
-# possibility:
-ggplot(diamonds, aes(clarity)) +
-  geom_freqpoly(aes(group = cut, colour = cut))
-
-# Dodged bar charts
-ggplot(diamonds, aes(clarity, fill=cut)) + geom_bar(position="dodge")
-# compare with
-ggplot(diamonds, aes(cut, fill=cut)) + geom_bar() +
-  facet_grid(. ~ clarity)
-
-# But again, probably better to use frequency polygons instead:
-ggplot(diamonds, aes(clarity, colour=cut)) +
-  geom_freqpoly(aes(group = cut))
-
-# Often we don't want the height of the bar to represent the
-# count of observations, but the sum of some other variable.
-# For example, the following plot shows the number of diamonds
-# of each colour
-qplot(color, data=diamonds, geom="bar")
-# If, however, we want to see the total number of carats in each colour
-# we need to weight by the carat variable
-qplot(color, data=diamonds, geom="bar", weight=carat, ylab="carat")
-
-# A bar chart used to display means
-meanprice <- tapply(diamonds$price, diamonds$cut, mean)
-cut <- factor(levels(diamonds$cut), levels = levels(diamonds$cut))
-qplot(cut, meanprice)
-qplot(cut, meanprice, geom="bar", stat="identity")
-qplot(cut, meanprice, geom="bar", stat="identity", fill = I("grey50"))
-
-# Another stacked bar chart example
-k <- ggplot(mpg, aes(manufacturer, fill=class))
-k + geom_bar()
-# Use scales to change aesthetics defaults
-k + geom_bar() + scale_fill_brewer()
-k + geom_bar() + scale_fill_grey()
-
-# To change plot order of class varible
-# use factor() to change order of levels
-mpg$class <- factor(mpg$class, levels = c("midsize", "minivan",
-"suv", "compact", "2seater", "subcompact", "pickup"))
-m <- ggplot(mpg, aes(manufacturer, fill=class))
-m + geom_bar()
+# Bar charts are automatically stacked when multiple bars are placed
+# at the same location
+g + geom_bar(aes(fill = drv))
+
+# You can instead dodge, or fill them
+g + geom_bar(aes(fill = drv), position = "dodge")
+g + geom_bar(aes(fill = drv), position = "fill")
+
+# To change plot order of bars, change levels in underlying factor
+reorder_size <- function(x) {
+  factor(x, levels = names(sort(table(x))))
+}
+ggplot(mpg, aes(reorder_size(class))) + geom_bar()
 }
 }
 \seealso{
-\code{\link{stat_bin}} for more details of the binning alogirithm,
-  \code{\link{position_dodge}} for creating side-by-side barcharts,
-  \code{\link{position_stack}} for more info on stacking,
+\code{\link{geom_histogram}} for continuous data,
+  \code{\link{position_dodge}} for creating side-by-side barcharts.
+
+\code{\link{stat_bin}}, which bins data in ranges and counts the
+  cases in each range. It differs from \code{stat_count}, which counts the
+  number of cases at each x position (without binning into ranges).
+  \code{\link{stat_bin}} requires continuous x data, whereas
+  \code{stat_count} can be used for both discrete and continuous x data.
 }
 
diff --git a/man/geom_bin2d.Rd b/man/geom_bin2d.Rd
index b2ab638..3c0bc8b 100644
--- a/man/geom_bin2d.Rd
+++ b/man/geom_bin2d.Rd
@@ -1,42 +1,86 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-bin2d.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-bin2d.r, R/stat-bin2d.r
 \name{geom_bin2d}
 \alias{geom_bin2d}
+\alias{stat_bin2d}
+\alias{stat_bin_2d}
 \title{Add heatmap of 2d bin counts.}
 \usage{
 geom_bin2d(mapping = NULL, data = NULL, stat = "bin2d",
-  position = "identity", ...)
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+
+stat_bin_2d(mapping = NULL, data = NULL, geom = "tile",
+  position = "identity", bins = 30, binwidth = NULL, drop = TRUE,
+  na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
+
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
+
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
+
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
 
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{geom, stat}{Use to override the default connection between
+\code{geom_bin2d} and \code{stat_bin2d}.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{bins}{numeric vector giving number of bins in both vertical and
+horizontal directions. Set to 30 by default.}
+
+\item{binwidth}{Numeric vector giving bin width in both vertical and
+horizontal directions. Overrides \code{bins} if both set.}
+
+\item{drop}{if \code{TRUE} removes all cells with 0 counts.}
 }
 \description{
 Add heatmap of 2d bin counts.
 }
 \section{Aesthetics}{
 
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "bin2d")}
+\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "bin2d")}
 }
 \examples{
-d <- ggplot(diamonds, aes(x = x, y = y)) + xlim(4,10) + ylim(4,10)
+d <- ggplot(diamonds, aes(x, y)) + xlim(4, 10) + ylim(4, 10)
 d + geom_bin2d()
-d + geom_bin2d(binwidth = c(0.1, 0.1))
 
-# See ?stat_bin2d for more examples
+# You can control the size of the bins by specifying the number of
+# bins in each direction:
+d + geom_bin2d(bins = 10)
+d + geom_bin2d(bins = 30)
+
+# Or by specifying the width of the bins
+d + geom_bin2d(binwidth = c(0.1, 0.1))
+}
+\seealso{
+\code{\link{stat_binhex}} for hexagonal binning
 }
 
diff --git a/man/geom_blank.Rd b/man/geom_blank.Rd
index 32b55e7..a5ea94f 100644
--- a/man/geom_blank.Rd
+++ b/man/geom_blank.Rd
@@ -1,36 +1,54 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/geom-blank.r
 \name{geom_blank}
 \alias{geom_blank}
 \title{Blank, draws nothing.}
 \usage{
 geom_blank(mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", ...)
+  position = "identity", show.legend = NA, inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
 \item{stat}{The statistical transformation to use on the data for this
-layer.}
+layer, as a string.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
 }
 \description{
 The blank geom draws nothing, but can be a useful way of ensuring common
 scales between different plots.
 }
 \examples{
-qplot(length, rating, data = movies, geom = "blank")
+ggplot(mtcars, aes(wt, mpg)) + geom_blank()
 # Nothing to see here!
 
 # Take the following scatter plot
diff --git a/man/geom_boxplot.Rd b/man/geom_boxplot.Rd
index 8382af3..4359bb8 100644
--- a/man/geom_boxplot.Rd
+++ b/man/geom_boxplot.Rd
@@ -1,38 +1,41 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-boxplot.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-boxplot.r, R/stat-boxplot.r
 \name{geom_boxplot}
 \alias{geom_boxplot}
+\alias{stat_boxplot}
 \title{Box and whiskers plot.}
 \usage{
 geom_boxplot(mapping = NULL, data = NULL, stat = "boxplot",
-  position = "dodge", outlier.colour = NULL, outlier.shape = NULL,
-  outlier.size = NULL, notch = FALSE, notchwidth = 0.5,
-  varwidth = FALSE, ...)
+  position = "dodge", outlier.colour = NULL, outlier.shape = 19,
+  outlier.size = 1.5, outlier.stroke = 0.5, notch = FALSE,
+  notchwidth = 0.5, varwidth = FALSE, na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+
+stat_boxplot(mapping = NULL, data = NULL, geom = "boxplot",
+  position = "dodge", coef = 1.5, na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
-
-\item{outlier.colour}{colour for outlying points. Uses the default from geom_point().}
-
-\item{outlier.shape}{shape of outlying points. Uses the default from geom_point().}
-
-\item{outlier.size}{size of outlying points. Uses the default from geom_point().}
+\item{outlier.colour, outlier.shape, outlier.size, outlier.stroke}{Default
+aesthetics for outliers. Set to \code{NULL} to inherit from the aesthetics
+used for the box.}
 
 \item{notch}{if \code{FALSE} (default) make a standard box plot. If
 \code{TRUE}, make a notched box plot. Notches are used to compare groups;
-if the notches of two boxes do not overlap, this is strong evidence that
-the medians differ.}
+if the notches of two boxes do not overlap, this suggests that the medians
+are significantly different.}
 
 \item{notchwidth}{for a notched box plot, width of the notch relative to
 the body (default 0.5)}
@@ -42,12 +45,36 @@ the body (default 0.5)}
 square-roots of the number of observations in the groups (possibly
 weighted, using the \code{weight} aesthetic).}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
+
+\item{geom, stat}{Use to override the default connection between
+\code{geom_boxplot} and \code{stat_boxplot}.}
+
+\item{coef}{length of the whiskers as multiple of IQR.  Defaults to 1.5}
 }
 \description{
-The upper and lower "hinges" correspond to the first and third quartiles
+The lower and upper "hinges" correspond to the first and third quartiles
 (the 25th and 75th percentiles). This differs slightly from the method used
 by the \code{boxplot} function, and may be apparent with small samples.
 See \code{\link{boxplot.stats}} for for more information on how hinge
@@ -68,74 +95,60 @@ See McGill et al. (1978) for more details.
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "boxplot")}
 }
-\examples{
-\donttest{
-p <- ggplot(mtcars, aes(factor(cyl), mpg))
 
+\section{Computed variables}{
+
+\describe{
+  \item{width}{width of boxplot}
+  \item{ymin}{lower whisker = smallest observation greater than or equal to lower hinge - 1.5 * IQR}
+  \item{lower}{lower hinge, 25\% quantile}
+  \item{notchlower}{lower edge of notch = median - 1.58 * IQR / sqrt(n)}
+  \item{middle}{median, 50\% quantile}
+  \item{notchupper}{upper edge of notch = median + 1.58 * IQR / sqrt(n)}
+  \item{upper}{upper hinge, 75\% quantile}
+  \item{ymax}{upper whisker = largest observation less than or equal to upper hinge + 1.5 * IQR}
+}
+}
+\examples{
+p <- ggplot(mpg, aes(class, hwy))
 p + geom_boxplot()
-qplot(factor(cyl), mpg, data = mtcars, geom = "boxplot")
-
-p + geom_boxplot() + geom_jitter()
+p + geom_boxplot() + geom_jitter(width = 0.2)
 p + geom_boxplot() + coord_flip()
-qplot(factor(cyl), mpg, data = mtcars, geom = "boxplot") +
-  coord_flip()
 
 p + geom_boxplot(notch = TRUE)
-p + geom_boxplot(notch = TRUE, notchwidth = .3)
-
-p + geom_boxplot(outlier.colour = "green", outlier.size = 3)
-
-# Add aesthetic mappings
-# Note that boxplots are automatically dodged when any aesthetic is
-# a factor
-p + geom_boxplot(aes(fill = cyl))
-p + geom_boxplot(aes(fill = factor(cyl)))
-p + geom_boxplot(aes(fill = factor(vs)))
-p + geom_boxplot(aes(fill = factor(am)))
-
-# Set aesthetics to fixed value
-p + geom_boxplot(fill = "grey80", colour = "#3366FF")
-qplot(factor(cyl), mpg, data = mtcars, geom = "boxplot",
-  colour = I("#3366FF"))
-
-# Scales vs. coordinate transforms -------
-# Scale transformations occur before the boxplot statistics are computed.
-# Coordinate transformations occur afterwards.  Observe the effect on the
-# number of outliers.
-library(plyr) # to access round_any
-m <- ggplot(movies, aes(y = votes, x = rating,
-   group = round_any(rating, 0.5)))
-m + geom_boxplot()
-m + geom_boxplot() + scale_y_log10()
-m + geom_boxplot() + coord_trans(y = "log10")
-m + geom_boxplot() + scale_y_log10() + coord_trans(y = "log10")
-
-# Boxplots with continuous x:
-# Use the group aesthetic to group observations in boxplots
-qplot(year, budget, data = movies, geom = "boxplot")
-qplot(year, budget, data = movies, geom = "boxplot",
-  group = round_any(year, 10, floor))
-
-# Using precomputed statistics
-# generate sample data
-abc <- adply(matrix(rnorm(100), ncol = 5), 2, quantile, c(0, .25, .5, .75, 1))
-b <- ggplot(abc, aes(x = X1, ymin = `0\%`, lower = `25\%`,
-   middle = `50\%`, upper = `75\%`, ymax = `100\%`))
-b + geom_boxplot(stat = "identity")
-b + geom_boxplot(stat = "identity") + coord_flip()
-b + geom_boxplot(aes(fill = X1), stat = "identity")
-
-# Using varwidth
 p + geom_boxplot(varwidth = TRUE)
-qplot(factor(cyl), mpg, data = mtcars, geom = "boxplot", varwidth = TRUE)
+p + geom_boxplot(fill = "white", colour = "#3366FF")
+# By default, outlier points match the colour of the box. Use
+# outlier.colour to override
+p + geom_boxplot(outlier.colour = "red", outlier.shape = 1)
 
-# Update the defaults for the outliers by changing the defaults for geom_point
+# Boxplots are automatically dodged when any aesthetic is a factor
+p + geom_boxplot(aes(colour = drv))
 
-p <- ggplot(mtcars, aes(factor(cyl), mpg))
-p + geom_boxplot()
+# You can also use boxplots with continuous x, as long as you supply
+# a grouping variable. cut_width is particularly useful
+ggplot(diamonds, aes(carat, price)) +
+  geom_boxplot()
+ggplot(diamonds, aes(carat, price)) +
+  geom_boxplot(aes(group = cut_width(carat, 0.25)))
 
-update_geom_defaults("point", list(shape = 1, colour = "red", size = 5))
-p + geom_boxplot()
+\donttest{
+# It's possible to draw a boxplot with your own computations if you
+# use stat = "identity":
+y <- rnorm(100)
+df <- data.frame(
+  x = 1,
+  y0 = min(y),
+  y25 = quantile(y, 0.25),
+  y50 = median(y),
+  y75 = quantile(y, 0.75),
+  y100 = max(y)
+)
+ggplot(df, aes(x)) +
+  geom_boxplot(
+   aes(ymin = y0, lower = y25, middle = y50, upper = y75, ymax = y100),
+   stat = "identity"
+ )
 }
 }
 \references{
@@ -144,7 +157,7 @@ McGill, R., Tukey, J. W. and Larsen, W. A. (1978) Variations of
 }
 \seealso{
 \code{\link{stat_quantile}} to view quantiles conditioned on a
-  continuous variable,  \code{\link{geom_jitter}} for another way to look
-  at conditional distributions"
+  continuous variable, \code{\link{geom_jitter}} for another way to look
+  at conditional distributions.
 }
 
diff --git a/man/geom_contour.Rd b/man/geom_contour.Rd
index 4b675a1..aae9058 100644
--- a/man/geom_contour.Rd
+++ b/man/geom_contour.Rd
@@ -1,26 +1,34 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-path-contour.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-contour.r, R/stat-contour.r
 \name{geom_contour}
 \alias{geom_contour}
+\alias{stat_contour}
 \title{Display contours of a 3d surface in 2d.}
 \usage{
 geom_contour(mapping = NULL, data = NULL, stat = "contour",
   position = "identity", lineend = "butt", linejoin = "round",
-  linemitre = 1, na.rm = FALSE, ...)
+  linemitre = 1, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE,
+  ...)
+
+stat_contour(mapping = NULL, data = NULL, geom = "contour",
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
 \item{stat}{The statistical transformation to use on the data for this
-layer.}
+layer, as a string.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
 \item{lineend}{Line end style (round, butt, square)}
 
@@ -31,9 +39,27 @@ on this layer}
 \item{na.rm}{If \code{FALSE} (the default), removes missing values with
 a warning.  If \code{TRUE} silently removes missing values.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
+
+\item{geom}{The geometric object to use display the data}
 }
 \description{
 Display contours of a 3d surface in 2d.
@@ -42,10 +68,40 @@ Display contours of a 3d surface in 2d.
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "contour")}
 }
+
+\section{Computed variables}{
+
+\describe{
+ \item{level}{height of contour}
+}
+}
 \examples{
-# See stat_contour for examples
+#' # Basic plot
+v <- ggplot(faithfuld, aes(waiting, eruptions, z = density))
+v + geom_contour()
+
+# Or compute from raw data
+ggplot(faithful, aes(waiting, eruptions)) +
+  geom_density_2d()
+
+\donttest{
+# Setting bins creates evenly spaced contours in the range of the data
+v + geom_contour(bins = 2)
+v + geom_contour(bins = 10)
+
+# Setting binwidth does the same thing, parameterised by the distance
+# between contours
+v + geom_contour(binwidth = 0.01)
+v + geom_contour(binwidth = 0.001)
+
+# Other parameters
+v + geom_contour(aes(colour = ..level..))
+v + geom_contour(colour = "red")
+v + geom_raster(aes(fill = density)) +
+  geom_contour(colour = "white")
+}
 }
 \seealso{
-\code{\link{geom_density2d}}: 2d density contours
+\code{\link{geom_density_2d}}: 2d density contours
 }
 
diff --git a/man/geom_count.Rd b/man/geom_count.Rd
new file mode 100644
index 0000000..142087a
--- /dev/null
+++ b/man/geom_count.Rd
@@ -0,0 +1,103 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-count.r, R/stat-sum.r
+\name{geom_count}
+\alias{geom_count}
+\alias{stat_sum}
+\title{Count the number of observations at each location.}
+\usage{
+geom_count(mapping = NULL, data = NULL, stat = "sum",
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+
+stat_sum(mapping = NULL, data = NULL, geom = "point",
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+}
+\arguments{
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
+
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
+
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
+
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
+
+\item{geom, stat}{Use to override the default connection between
+\code{geom_count} and \code{stat_sum}.}
+}
+\description{
+This is a variant \code{\link{geom_point}} that counts the number of
+observations at each location, then maps the count to point size. It
+useful when you have discrete data.
+}
+\section{Aesthetics}{
+
+\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "point")}
+}
+
+\section{Computed variables}{
+
+\describe{
+ \item{n}{number of observations at position}
+ \item{prop}{percent of points in that panel at that position}
+}
+}
+\examples{
+ggplot(mpg, aes(cty, hwy)) +
+ geom_point()
+
+ggplot(mpg, aes(cty, hwy)) +
+ geom_count()
+
+# Best used in conjunction with scale_size_area which ensures that
+# counts of zero would be given size 0. Doesn't make much different
+# here because the smallest count is already close to 0.
+ggplot(mpg, aes(cty, hwy)) +
+ geom_count()
+ scale_size_area()
+
+# Display proportions instead of counts -------------------------------------
+# By default, all categorical variables in the plot form the groups.
+# Specifying geom_count without a group identifier leads to a plot which is
+# not useful:
+d <- ggplot(diamonds, aes(x = cut, y = clarity))
+d + geom_count(aes(size = ..prop..))
+# To correct this problem and achieve a more desirable plot, we need
+# to specify which group the proportion is to be calculated over.
+d + geom_count(aes(size = ..prop.., group = 1)) +
+  scale_size_area(max_size = 10)
+
+# Or group by x/y variables to have rows/columns sum to 1.
+d + geom_count(aes(size = ..prop.., group = cut)) +
+  scale_size_area(max_size = 10)
+d + geom_count(aes(size = ..prop.., group = clarity)) +
+  scale_size_area(max_size = 10)
+}
+
diff --git a/man/geom_crossbar.Rd b/man/geom_crossbar.Rd
deleted file mode 100644
index cf02947..0000000
--- a/man/geom_crossbar.Rd
+++ /dev/null
@@ -1,46 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-crossbar.r
-\name{geom_crossbar}
-\alias{geom_crossbar}
-\title{Hollow bar with middle indicated by horizontal line.}
-\usage{
-geom_crossbar(mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", fatten = 2, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
-
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
-
-\item{fatten}{a multiplicate factor to fatten middle bar by}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-Hollow bar with middle indicated by horizontal line.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "crossbar")}
-}
-\examples{
-# See geom_linerange for examples
-}
-\seealso{
-\code{\link{geom_errorbar}} for error bars,
-\code{\link{geom_pointrange}} and \code{\link{geom_linerange}} for other
-ways of showing mean + error, \code{\link{stat_summary}} to compute
-errors from the data, \code{\link{geom_smooth}} for the continuous analog.
-}
-
diff --git a/man/geom_density.Rd b/man/geom_density.Rd
index 8fea9ec..f60d327 100644
--- a/man/geom_density.Rd
+++ b/man/geom_density.Rd
@@ -1,45 +1,123 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-ribbon-density.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-density.r, R/stat-density.r
 \name{geom_density}
 \alias{geom_density}
+\alias{stat_density}
 \title{Display a smooth density estimate.}
 \usage{
 geom_density(mapping = NULL, data = NULL, stat = "density",
-  position = "identity", na.rm = FALSE, ...)
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+
+stat_density(mapping = NULL, data = NULL, geom = "area",
+  position = "stack", adjust = 1, kernel = "gaussian", trim = FALSE,
+  na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
 \item{na.rm}{If \code{FALSE} (the default), removes missing values with
 a warning.  If \code{TRUE} silently removes missing values.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
+
+\item{geom, stat}{Use to override the default connection between
+\code{geom_density} and \code{stat_density}.}
+
+\item{adjust}{see \code{\link{density}} for details}
+
+\item{kernel}{kernel used for density estimation, see
+\code{\link{density}} for details}
+
+\item{trim}{This parameter only matters if you are displaying multiple
+densities in one plot. If \code{FALSE}, the default, each density is
+computed on the full range of the data. If \code{TRUE}, each density
+is computed over the range of that group: this typically means the
+estimated x values will not line-up, and hence you won't be able to
+stack density values.}
 }
 \description{
-A smooth density estimate calculated by \code{\link{stat_density}}.
+A kernel density estimate, useful for display the distribution of variables
+with underlying smoothness.
 }
 \section{Aesthetics}{
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "density")}
 }
+
+\section{Computed variables}{
+
+\describe{
+  \item{density}{density estimate}
+  \item{count}{density * number of points - useful for stacked density
+     plots}
+  \item{scaled}{density estimate, scaled to maximum of 1}
+}
+}
 \examples{
-# See stat_density for examples
+ggplot(diamonds, aes(carat)) +
+  geom_density()
+
+ggplot(diamonds, aes(carat)) +
+  geom_density(adjust = 1/5)
+ggplot(diamonds, aes(carat)) +
+  geom_density(adjust = 5)
+
+ggplot(diamonds, aes(depth, colour = cut)) +
+  geom_density() +
+  xlim(55, 70)
+ggplot(diamonds, aes(depth, fill = cut, colour = cut)) +
+  geom_density(alpha = 0.1) +
+  xlim(55, 70)
+
+\donttest{
+# Stacked density plots: if you want to create a stacked density plot, you
+# probably want to 'count' (density * n) variable instead of the default
+# density
+
+# Loses marginal densities
+ggplot(diamonds, aes(carat, fill = cut)) +
+  geom_density(position = "stack")
+# Preserves marginal densities
+ggplot(diamonds, aes(carat, ..count.., fill = cut)) +
+  geom_density(position = "stack")
+
+# You can use position="fill" to produce a conditional density estimate
+ggplot(diamonds, aes(carat, ..count.., fill = cut)) +
+  geom_density(position = "fill")
+}
 }
 \seealso{
-\code{\link{geom_histogram}} for the histogram and
-  \code{\link{stat_density}} for examples.
+See \code{\link{geom_histogram}}, \code{\link{geom_freqpoly}} for
+  other methods of displaying continuous distribution.
+  See \code{\link{geom_violin}} for a compact density display.
 }
 
diff --git a/man/geom_density2d.Rd b/man/geom_density2d.Rd
deleted file mode 100644
index 2621813..0000000
--- a/man/geom_density2d.Rd
+++ /dev/null
@@ -1,56 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-path-density2d.r
-\name{geom_density2d}
-\alias{geom_density2d}
-\title{Contours from a 2d density estimate.}
-\usage{
-geom_density2d(mapping = NULL, data = NULL, stat = "density2d",
-  position = "identity", lineend = "butt", linejoin = "round",
-  linemitre = 1, na.rm = FALSE, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
-
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
-
-\item{lineend}{Line end style (round, butt, square)}
-
-\item{linejoin}{Line join style (round, mitre, bevel)}
-
-\item{linemitre}{Line mitre limit (number greater than 1)}
-
-\item{na.rm}{If \code{FALSE} (the default), removes missing values with
-a warning.  If \code{TRUE} silently removes missing values.}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-Perform a 2D kernel density estimatation using kde2d and display the
-results with contours.
-}
-\details{
-This can be useful for dealing with overplotting.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "density2d")}
-}
-\examples{
-# See stat_density2d for examples
-}
-\seealso{
-\code{\link{geom_contour}} for contour drawing geom,
- \code{\link{stat_sum}} for another way of dealing with overplotting
-}
-
diff --git a/man/geom_density_2d.Rd b/man/geom_density_2d.Rd
new file mode 100644
index 0000000..34d8083
--- /dev/null
+++ b/man/geom_density_2d.Rd
@@ -0,0 +1,111 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-density2d.r, R/stat-density-2d.r
+\name{geom_density_2d}
+\alias{geom_density2d}
+\alias{geom_density_2d}
+\alias{stat_density2d}
+\alias{stat_density_2d}
+\title{Contours from a 2d density estimate.}
+\usage{
+geom_density_2d(mapping = NULL, data = NULL, stat = "density2d",
+  position = "identity", lineend = "butt", linejoin = "round",
+  linemitre = 1, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE,
+  ...)
+
+stat_density_2d(mapping = NULL, data = NULL, geom = "density_2d",
+  position = "identity", contour = TRUE, n = 100, h = NULL,
+  na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...)
+}
+\arguments{
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
+
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
+
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
+
+\item{lineend}{Line end style (round, butt, square)}
+
+\item{linejoin}{Line join style (round, mitre, bevel)}
+
+\item{linemitre}{Line mitre limit (number greater than 1)}
+
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
+
+\item{geom, stat}{Use to override the default connection between
+\code{geom_density_2d} and \code{stat_density_2d}.}
+
+\item{contour}{If \code{TRUE}, contour the results of the 2d density
+estimation}
+
+\item{n}{number of grid points in each direction}
+
+\item{h}{Bandwidth (vector of length two). If \code{NULL}, estimated
+using \code{\link[MASS]{bandwidth.nrd}}.}
+}
+\description{
+Perform a 2D kernel density estimation using kde2d and display the
+results with contours. This can be useful for dealing with overplotting.
+}
+\section{Aesthetics}{
+
+\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "density_2d")}
+}
+
+\section{Computed variables}{
+
+Same as \code{\link{stat_contour}}
+}
+\examples{
+m <- ggplot(faithful, aes(x = eruptions, y = waiting)) +
+ geom_point() +
+ xlim(0.5, 6) +
+ ylim(40, 110)
+m + geom_density_2d()
+\donttest{
+m + stat_density_2d(aes(fill = ..level..), geom = "polygon")
+
+set.seed(4393)
+dsmall <- diamonds[sample(nrow(diamonds), 1000), ]
+d <- ggplot(dsmall, aes(x, y))
+# If you map an aesthetic to a categorical variable, you will get a
+# set of contours for each value of that variable
+d + geom_density_2d(aes(colour = cut))
+
+# If we turn contouring off, we can use use geoms like tiles:
+d + stat_density_2d(geom = "raster", aes(fill = ..density..), contour = FALSE)
+# Or points:
+d + stat_density_2d(geom = "point", aes(size = ..density..), n = 20, contour = FALSE)
+}
+}
+\seealso{
+\code{\link{geom_contour}} for contour drawing geom,
+ \code{\link{stat_sum}} for another way of dealing with overplotting
+}
+
diff --git a/man/geom_dotplot.Rd b/man/geom_dotplot.Rd
index d7956b7..8aca317 100644
--- a/man/geom_dotplot.Rd
+++ b/man/geom_dotplot.Rd
@@ -1,36 +1,34 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/geom-dotplot.r
 \name{geom_dotplot}
 \alias{geom_dotplot}
 \title{Dot plot}
 \usage{
-geom_dotplot(mapping = NULL, data = NULL, stat = "bindot",
-  position = "identity", na.rm = FALSE, binwidth = NULL, binaxis = "x",
-  method = "dotdensity", binpositions = "bygroup", stackdir = "up",
-  stackratio = 1, dotsize = 1, stackgroups = FALSE, ...)
+geom_dotplot(mapping = NULL, data = NULL, position = "identity",
+  binwidth = NULL, binaxis = "x", method = "dotdensity",
+  binpositions = "bygroup", stackdir = "up", stackratio = 1,
+  dotsize = 1, stackgroups = FALSE, origin = NULL, right = TRUE,
+  width = 0.9, drop = FALSE, na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
-
-\item{na.rm}{If \code{FALSE} (the default), removes missing values with
-a warning.  If \code{TRUE} silently removes missing values.}
-
-\item{binwidth}{When \code{method} is "dotdensity", this specifies maximum bin width.
- When method is "histodot", this specifies bin width.
+\item{binwidth}{When \code{method} is "dotdensity", this specifies maximum bin
+width. When \code{method} is "histodot", this specifies bin width.
 Defaults to 1/30 of the range of the data}
 
-\item{binaxis}{which axis to bin along "x" (default) or "y"}
+\item{binaxis}{The axis to bin along, "x" (default) or "y"}
 
 \item{method}{"dotdensity" (default) for dot-density binning, or
 "histodot" for fixed bin widths (like stat_bin)}
@@ -52,9 +50,38 @@ just touch. Use smaller values for closer, overlapping dots.}
 that \code{position = "stack"} should have, but can't (because this geom has
 some odd properties).}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{origin}{When \code{method} is "histodot", origin of first bin}
+
+\item{right}{When \code{method} is "histodot", should intervals be closed
+on the right (a, b], or not [a, b)}
+
+\item{width}{When \code{binaxis} is "y", the spacing of the dot stacks
+for dodging.}
+
+\item{drop}{If TRUE, remove all bins with zero counts}
+
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
 }
 \description{
 In a dot plot, the width of a dot corresponds to the bin width
@@ -78,6 +105,21 @@ to match the number of dots.
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "dotplot")}
 }
+
+\section{Computed variables}{
+
+\describe{
+  \item{x}{center of each bin, if binaxis is "x"}
+  \item{y}{center of each bin, if binaxis is "x"}
+  \item{binwidth}{max width of each bin if method is "dotdensity";
+    width of each bin if method is "histodot"}
+  \item{count}{number of points in bin}
+  \item{ncount}{count, scaled to maximum of 1}
+  \item{density}{density of points in bin, scaled to integrate to 1,
+    if method is "histodot"}
+  \item{ndensity}{density, scaled to maximum of 1, if method is "histodot"}
+}
+}
 \examples{
 ggplot(mtcars, aes(x = mpg)) + geom_dotplot()
 ggplot(mtcars, aes(x = mpg)) + geom_dotplot(binwidth = 1.5)
@@ -94,15 +136,15 @@ ggplot(mtcars, aes(x = mpg)) +
 
 # y axis isn't really meaningful, so hide it
 ggplot(mtcars, aes(x = mpg)) + geom_dotplot(binwidth = 1.5) +
-  scale_y_continuous(name = "", breaks = NULL)
+  scale_y_continuous(NULL, breaks = NULL)
 
 # Overlap dots vertically
 ggplot(mtcars, aes(x = mpg)) + geom_dotplot(binwidth = 1.5, stackratio = .7)
 
 # Expand dot diameter
-ggplot(mtcars, aes(x  =mpg)) + geom_dotplot(binwidth = 1.5, dotsize = 1.25)
-
+ggplot(mtcars, aes(x = mpg)) + geom_dotplot(binwidth = 1.5, dotsize = 1.25)
 
+\donttest{
 # Examples with stacking along y axis instead of x
 ggplot(mtcars, aes(x = 1, y = mpg)) +
   geom_dotplot(binaxis = "y", stackdir = "center")
@@ -129,9 +171,7 @@ ggplot(mtcars, aes(x = mpg, fill = factor(cyl))) +
 
 ggplot(mtcars, aes(x = 1, y = mpg, fill = factor(cyl))) +
   geom_dotplot(binaxis = "y", stackgroups = TRUE, binwidth = 1, method = "histodot")
-
-# Use qplot instead
-qplot(mpg, data = mtcars, geom = "dotplot")
+}
 }
 \references{
 Wilkinson, L. (1999) Dot plots. The American Statistician,
diff --git a/man/geom_errorbar.Rd b/man/geom_errorbar.Rd
deleted file mode 100644
index 7ead45b..0000000
--- a/man/geom_errorbar.Rd
+++ /dev/null
@@ -1,77 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-error.r
-\name{geom_errorbar}
-\alias{geom_errorbar}
-\title{Error bars.}
-\usage{
-geom_errorbar(mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
-
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-Error bars.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "errorbar")}
-}
-\examples{
-# Create a simple example dataset
-df <- data.frame(
-  trt = factor(c(1, 1, 2, 2)),
-  resp = c(1, 5, 3, 4),
-  group = factor(c(1, 2, 1, 2)),
-  se = c(0.1, 0.3, 0.3, 0.2)
-)
-df2 <- df[c(1,3),]
-
-# Define the top and bottom of the errorbars
-limits <- aes(ymax = resp + se, ymin=resp - se)
-
-p <- ggplot(df, aes(fill=group, y=resp, x=trt))
-p + geom_bar(position="dodge", stat="identity")
-
-# Because the bars and errorbars have different widths
-# we need to specify how wide the objects we are dodging are
-dodge <- position_dodge(width=0.9)
-p + geom_bar(position=dodge) + geom_errorbar(limits, position=dodge, width=0.25)
-
-p <- ggplot(df2, aes(fill=group, y=resp, x=trt))
-p + geom_bar(position=dodge)
-p + geom_bar(position=dodge) + geom_errorbar(limits, position=dodge, width=0.25)
-
-p <- ggplot(df, aes(colour=group, y=resp, x=trt))
-p + geom_point() + geom_errorbar(limits, width=0.2)
-p + geom_pointrange(limits)
-p + geom_crossbar(limits, width=0.2)
-
-# If we want to draw lines, we need to manually set the
-# groups which define the lines - here the groups in the
-# original dataframe
-p + geom_line(aes(group=group)) + geom_errorbar(limits, width=0.2)
-}
-\seealso{
-\code{\link{geom_pointrange}}: range indicated by straight line,
-  with point in the middle; \code{\link{geom_linerange}}: range indicated
-  by straight line; \code{\link{geom_crossbar}}: hollow bar with middle
-  indicated by horizontal line; \code{\link{stat_summary}}: examples of
-  these guys in use, \code{\link{geom_smooth}} for continuous analog
-}
-
diff --git a/man/geom_errorbarh.Rd b/man/geom_errorbarh.Rd
index 2687338..1f2207a 100644
--- a/man/geom_errorbarh.Rd
+++ b/man/geom_errorbarh.Rd
@@ -1,29 +1,51 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-errorh.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-errorbarh.r
 \name{geom_errorbarh}
 \alias{geom_errorbarh}
 \title{Horizontal error bars}
 \usage{
 geom_errorbarh(mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", ...)
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
 \item{stat}{The statistical transformation to use on the data for this
-layer.}
+layer, as a string.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
 }
 \description{
 Horizontal error bars
diff --git a/man/geom_freqpoly.Rd b/man/geom_freqpoly.Rd
deleted file mode 100644
index 4d32e6c..0000000
--- a/man/geom_freqpoly.Rd
+++ /dev/null
@@ -1,49 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-freqpoly.r
-\name{geom_freqpoly}
-\alias{geom_freqpoly}
-\title{Frequency polygon.}
-\usage{
-geom_freqpoly(mapping = NULL, data = NULL, stat = "bin",
-  position = "identity", ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
-
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-Frequency polygon.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "freqpoly")}
-}
-\examples{
-qplot(carat, data = diamonds, geom = "freqpoly")
-qplot(carat, data = diamonds, geom = "freqpoly", binwidth = 0.1)
-qplot(carat, data = diamonds, geom = "freqpoly", binwidth = 0.01)
-
-qplot(price, data = diamonds, geom = "freqpoly", binwidth = 1000)
-qplot(price, data = diamonds, geom = "freqpoly", binwidth = 1000,
-  colour = color)
-qplot(price, ..density.., data = diamonds, geom = "freqpoly",
-  binwidth = 1000, colour = color)
-}
-\seealso{
-\code{\link{geom_histogram}}: histograms
-}
-
diff --git a/man/geom_hex.Rd b/man/geom_hex.Rd
index 2c4e3f7..ca45583 100644
--- a/man/geom_hex.Rd
+++ b/man/geom_hex.Rd
@@ -1,38 +1,87 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-hex.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-hex.r, R/stat-binhex.r
 \name{geom_hex}
 \alias{geom_hex}
-\title{Hexagon bining.}
+\alias{stat_bin_hex}
+\alias{stat_binhex}
+\title{Hexagon binning.}
 \usage{
 geom_hex(mapping = NULL, data = NULL, stat = "binhex",
-  position = "identity", ...)
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+
+stat_bin_hex(mapping = NULL, data = NULL, geom = "hex",
+  position = "identity", bins = 30, binwidth = NULL, na.rm = FALSE,
+  show.legend = NA, inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
+
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
+
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
+
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
 
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{geom, stat}{Override the default connection between \code{geom_hex} and
+\code{stat_binhex.}}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{bins}{numeric vector giving number of bins in both vertical and
+horizontal directions. Set to 30 by default.}
+
+\item{binwidth}{Numeric vector giving bin width in both vertical and
+horizontal directions. Overrides \code{bins} if both set.}
 }
 \description{
-Hexagon bining.
+Hexagon binning.
 }
 \section{Aesthetics}{
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "hex")}
 }
 \examples{
-# See ?stat_binhex for examples
+d <- ggplot(diamonds, aes(carat, price))
+d + geom_hex()
+
+\donttest{
+# You can control the size of the bins by specifying the number of
+# bins in each direction:
+d + geom_hex(bins = 10)
+d + geom_hex(bins = 30)
+
+# Or by specifying the width of the bins
+d + geom_hex(binwidth = c(1, 1000))
+d + geom_hex(binwidth = c(.1, 500))
+}
+}
+\seealso{
+\code{\link{stat_bin2d}} for rectangular binning
 }
 
diff --git a/man/geom_histogram.Rd b/man/geom_histogram.Rd
index cd05162..929343f 100644
--- a/man/geom_histogram.Rd
+++ b/man/geom_histogram.Rd
@@ -1,34 +1,89 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-bar-histogram.r
-\name{geom_histogram}
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-freqpoly.r, R/geom-histogram.r, R/stat-bin.r
+\name{geom_freqpoly}
+\alias{geom_freqpoly}
 \alias{geom_histogram}
-\title{Histogram}
+\alias{stat_bin}
+\title{Histograms and frequency polygons.}
 \usage{
+geom_freqpoly(mapping = NULL, data = NULL, stat = "bin",
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+
 geom_histogram(mapping = NULL, data = NULL, stat = "bin",
-  position = "stack", ...)
+  binwidth = NULL, bins = NULL, origin = NULL, right = FALSE,
+  position = "stack", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+
+stat_bin(mapping = NULL, data = NULL, geom = "bar", position = "stack",
+  width = 0.9, drop = FALSE, right = FALSE, binwidth = NULL,
+  bins = NULL, origin = NULL, breaks = NULL, na.rm = FALSE,
+  show.legend = NA, inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
+
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
+
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
+
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
+
+\item{binwidth}{Bin width to use. Defaults to 1/\code{bins} of the range of
+the data}
+
+\item{bins}{Number of bins. Overridden by \code{binwidth} or \code{breaks}.
+Defaults to 30}
+
+\item{origin}{Origin of first bin}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{right}{If \code{TRUE}, right-closed, left-open, if \code{FALSE},
+the default, right-open, left-closed.}
 
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
+\item{geom, stat}{Use to override the default connection between
+\code{geom_histogram}/\code{geom_freqpoly} and \code{stat_bin}.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{width}{Width of bars when used with categorical data}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{drop}{If TRUE, remove all bins with zero counts}
+
+\item{breaks}{Actual breaks to use. Overrides bin width, bin number and
+origin}
 }
 \description{
-\code{geom_histogram} is an alias for \code{\link{geom_bar}} plus
-\code{\link{stat_bin}} so you will need to look at the documentation for
-those objects to get more information about the parameters.
+Display a 1d distribution by dividing into bins and counting the number
+of observations in each bin. Histograms use bars; frequency polygons use
+lines.
+
+\code{stat_bin} is suitable only for continuous x data. If your x data is
+  discrete, you probably want to use \code{\link{stat_count}}.
 }
 \details{
 By default, \code{stat_bin} uses 30 bins - this is not a good default,
@@ -37,108 +92,77 @@ may need to look at a few to uncover the full story behind your data.
 }
 \section{Aesthetics}{
 
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "histogram")}
+\code{geom_histogram} uses the same aesthetics as \code{geom_bar};
+\code{geom_freqpoly} uses the same aesthetics as \code{geom_line}.
 }
-\examples{
-\donttest{
-set.seed(5689)
-movies <- movies[sample(nrow(movies), 1000), ]
-# Simple examples
-qplot(rating, data=movies, geom="histogram")
-qplot(rating, data=movies, weight=votes, geom="histogram")
-qplot(rating, data=movies, weight=votes, geom="histogram", binwidth=1)
-qplot(rating, data=movies, weight=votes, geom="histogram", binwidth=0.1)
-
-# More complex
-m <- ggplot(movies, aes(x=rating))
-m + geom_histogram()
-m + geom_histogram(aes(y = ..density..)) + geom_density()
-
-m + geom_histogram(binwidth = 1)
-m + geom_histogram(binwidth = 0.5)
-m + geom_histogram(binwidth = 0.1)
-
-# Add aesthetic mappings
-m + geom_histogram(aes(weight = votes))
-m + geom_histogram(aes(y = ..count..))
-m + geom_histogram(aes(fill = ..count..))
 
-# Change scales
-m + geom_histogram(aes(fill = ..count..)) +
-  scale_fill_gradient("Count", low = "green", high = "red")
+\section{Computed variables}{
 
+\describe{
+  \item{count}{number of points in bin}
+  \item{density}{density of points in bin, scaled to integrate to 1}
+  \item{ncount}{count, scaled to maximum of 1}
+  \item{ndensity}{density, scaled to maximum of 1}
+}
+}
+\examples{
+ggplot(diamonds, aes(carat)) +
+  geom_histogram()
+ggplot(diamonds, aes(carat)) +
+  geom_histogram(binwidth = 0.01)
+ggplot(diamonds, aes(carat)) +
+  geom_histogram(bins = 200)
+
+# Rather than stacking histograms, it's easier to compare frequency
+# polygons
+ggplot(diamonds, aes(price, fill = cut)) +
+  geom_histogram(binwidth = 500)
+ggplot(diamonds, aes(price, colour = cut)) +
+  geom_freqpoly(binwidth = 500)
+
+# To make it easier to compare distributions with very different counts,
+# put density on the y axis instead of the default count
+ggplot(diamonds, aes(price, ..density.., colour = cut)) +
+  geom_freqpoly(binwidth = 500)
+
+if (require("ggplot2movies")) {
 # Often we don't want the height of the bar to represent the
 # count of observations, but the sum of some other variable.
 # For example, the following plot shows the number of movies
 # in each rating.
-qplot(rating, data=movies, geom="bar", binwidth = 0.1)
+m <- ggplot(movies, aes(rating))
+m + geom_histogram(binwidth = 0.1)
+
 # If, however, we want to see the number of votes cast in each
 # category, we need to weight by the votes variable
-qplot(rating, data=movies, geom="bar", binwidth = 0.1,
-  weight=votes, ylab = "votes")
+m + geom_histogram(aes(weight = votes), binwidth = 0.1) + ylab("votes")
 
-m <- ggplot(movies, aes(x = votes))
 # For transformed scales, binwidth applies to the transformed data.
 # The bins have constant width on the transformed scale.
 m + geom_histogram() + scale_x_log10()
-m + geom_histogram(binwidth = 1) + scale_x_log10()
-m + geom_histogram() + scale_x_sqrt()
-m + geom_histogram(binwidth = 10) + scale_x_sqrt()
+m + geom_histogram(binwidth = 0.05) + scale_x_log10()
 
 # For transformed coordinate systems, the binwidth applies to the
-# raw data.  The bins have constant width on the original scale.
+# raw data. The bins have constant width on the original scale.
 
 # Using log scales does not work here, because the first
 # bar is anchored at zero, and so when transformed becomes negative
-# infinity.  This is not a problem when transforming the scales, because
+# infinity. This is not a problem when transforming the scales, because
 # no observations have 0 ratings.
 m + geom_histogram(origin = 0) + coord_trans(x = "log10")
 # Use origin = 0, to make sure we don't take sqrt of negative values
 m + geom_histogram(origin = 0) + coord_trans(x = "sqrt")
-m + geom_histogram(origin = 0, binwidth = 1000) + coord_trans(x = "sqrt")
 
 # You can also transform the y axis.  Remember that the base of the bars
 # has value 0, so log transformations are not appropriate
 m <- ggplot(movies, aes(x = rating))
 m + geom_histogram(binwidth = 0.5) + scale_y_sqrt()
-m + geom_histogram(binwidth = 0.5) + scale_y_reverse()
-
-# Set aesthetics to fixed value
-m + geom_histogram(colour = "darkgreen", fill = "white", binwidth = 0.5)
-
-# Use facets
-m <- m + geom_histogram(binwidth = 0.5)
-m + facet_grid(Action ~ Comedy)
-
-# Often more useful to use density on the y axis when facetting
-m <- m + aes(y = ..density..)
-m + facet_grid(Action ~ Comedy)
-m + facet_wrap(~ mpaa)
-
-# Multiple histograms on the same graph
-# see ?position, ?position_fill, etc for more details.
-set.seed(6298)
-diamonds_small <- diamonds[sample(nrow(diamonds), 1000), ]
-ggplot(diamonds_small, aes(x=price)) + geom_bar()
-hist_cut <- ggplot(diamonds_small, aes(x=price, fill=cut))
-hist_cut + geom_bar() # defaults to stacking
-hist_cut + geom_bar(position="fill")
-hist_cut + geom_bar(position="dodge")
-
-# This is easy in ggplot2, but not visually effective.  It's better
-# to use a frequency polygon or density plot.  Like this:
-ggplot(diamonds_small, aes(price, ..density.., colour = cut)) +
-  geom_freqpoly(binwidth = 1000)
-# Or this:
-ggplot(diamonds_small, aes(price, colour = cut)) +
-  geom_density()
-# Or if you want to be fancy, maybe even this:
-ggplot(diamonds_small, aes(price, fill = cut)) +
-  geom_density(alpha = 0.2)
-# Which looks better when the distributions are more distinct
-ggplot(diamonds_small, aes(depth, fill = cut)) +
-  geom_density(alpha = 0.2) + xlim(55, 70)
 }
 rm(movies)
 }
+\seealso{
+\code{\link{stat_count}}, which counts the number of cases at each x
+  posotion, without binning. It is suitable for both discrete and continuous
+  x data, whereas \link{stat_bin} is suitable only for continuous x data.
+}
 
diff --git a/man/geom_hline.Rd b/man/geom_hline.Rd
deleted file mode 100644
index 6ed4743..0000000
--- a/man/geom_hline.Rd
+++ /dev/null
@@ -1,70 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-hline.r
-\name{geom_hline}
-\alias{geom_hline}
-\title{Horizontal line.}
-\usage{
-geom_hline(mapping = NULL, data = NULL, stat = "hline",
-  position = "identity", show_guide = FALSE, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
-
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
-
-\item{show_guide}{should a legend be drawn? (defaults to \code{FALSE})}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-This geom allows you to annotate the plot with horizontal lines (see
-\code{\link{geom_vline}} and \code{\link{geom_abline}} for other types of
-lines).
-}
-\details{
-There are two ways to use it. You can either specify the intercept of
-the line in the call to the geom, in which case the line will be in the
-same position in every panel. Alternatively, you can supply a different
-intercept for each panel using a data.frame. See the examples for the
-differences
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "hline")}
-}
-\examples{
-p <- ggplot(mtcars, aes(x = wt, y=mpg)) + geom_point()
-
-p + geom_hline(aes(yintercept=mpg))
-p + geom_hline(yintercept=20)
-p + geom_hline(yintercept=seq(10, 30, by=5))
-
-# With coordinate transforms
-p + geom_hline(aes(yintercept=mpg)) + coord_equal()
-p + geom_hline(aes(yintercept=mpg)) + coord_flip()
-p + geom_hline(aes(yintercept=mpg)) + coord_polar()
-
-# To display different lines in different facets, you need to
-# create a data frame.
-p <- qplot(mpg, wt, data=mtcars, facets = vs ~ am)
-
-hline.data <- data.frame(z = 1:4, vs = c(0,0,1,1), am = c(0,1,0,1))
-p + geom_hline(aes(yintercept = z), hline.data)
-}
-\seealso{
-\code{\link{geom_vline}} for vertical lines,
- \code{\link{geom_abline}} for lines defined by a slope and intercept,
- \code{\link{geom_segment}} for a more general approach
-}
-
diff --git a/man/geom_jitter.Rd b/man/geom_jitter.Rd
index 706849b..c330354 100644
--- a/man/geom_jitter.Rd
+++ b/man/geom_jitter.Rd
@@ -1,65 +1,98 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-point-jitter.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-jitter.r
 \name{geom_jitter}
 \alias{geom_jitter}
 \title{Points, jittered to reduce overplotting.}
 \usage{
-geom_jitter(mapping = NULL, data = NULL, stat = "identity",
-  position = "jitter", na.rm = FALSE, ...)
+geom_jitter(mapping = NULL, data = NULL, width = NULL, height = NULL,
+  stat = "identity", position = "jitter", na.rm = FALSE,
+  show.legend = NA, inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
+
+\item{width}{Amount of vertical and horizontal jitter. The jitter
+  is added in both positive and negative directions, so the total spread
+  is twice the value specified here.
+
+  If omitted, defaults to 40\% of the resolution of the data: this means the
+  jitter values will occupy 80\% of the implied bins. Categorical data
+  is aligned on the integers, so a width or height of 0.5 will spread the
+  data so it's not possible to see the distinction between the categories.}
+
+\item{height}{Amount of vertical and horizontal jitter. The jitter
+  is added in both positive and negative directions, so the total spread
+  is twice the value specified here.
+
+  If omitted, defaults to 40\% of the resolution of the data: this means the
+  jitter values will occupy 80\% of the implied bins. Categorical data
+  is aligned on the integers, so a width or height of 0.5 will spread the
+  data so it's not possible to see the distinction between the categories.}
 
 \item{stat}{The statistical transformation to use on the data for this
-layer.}
+layer, as a string.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
 \item{na.rm}{If \code{FALSE} (the default), removes missing values with
 a warning.  If \code{TRUE} silently removes missing values.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
 }
 \description{
 The jitter geom is a convenient default for geom_point with position =
-'jitter'.  See \code{\link{position_jitter}} to see how to adjust amount
-of jittering.
+'jitter'. It's a useful way of handling overplotting caused by discreteness
+in smaller datasets.
 }
 \section{Aesthetics}{
 
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "jitter")}
+\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "point")}
 }
 \examples{
-p <- ggplot(mpg, aes(displ, hwy))
+p <- ggplot(mpg, aes(cyl, hwy))
 p + geom_point()
-p + geom_point(position = "jitter")
+p + geom_jitter()
 
 # Add aesthetic mappings
-p + geom_jitter(aes(colour = cyl))
+p + geom_jitter(aes(colour = class))
 
-# Vary parameters
-p + geom_jitter(position = position_jitter(width = .5))
-p + geom_jitter(position = position_jitter(height = .5))
+# Use smaller width/height to emphasise categories
+ggplot(mpg, aes(cyl, hwy)) + geom_jitter()
+ggplot(mpg, aes(cyl, hwy)) + geom_jitter(width = 0.25)
 
-# Use qplot instead
-qplot(displ, hwy, data = mpg, geom = "jitter")
-qplot(class, hwy, data = mpg, geom = "jitter")
-qplot(class, hwy, data = mpg, geom = c("boxplot", "jitter"))
-qplot(class, hwy, data = mpg, geom = c("jitter", "boxplot"))
+# Use larger width/height to completely smooth away discreteness
+ggplot(mpg, aes(cty, hwy)) + geom_jitter()
+ggplot(mpg, aes(cty, hwy)) + geom_jitter(width = 0.5, height = 0.5)
 }
 \seealso{
 \code{\link{geom_point}} for regular, unjittered points,
  \code{\link{geom_boxplot}} for another way of looking at the conditional
-    distribution of a variable,
- \code{\link{position_jitter}} for examples of using jittering with other
-   geoms
+    distribution of a variable
 }
 
diff --git a/man/geom_line.Rd b/man/geom_line.Rd
deleted file mode 100644
index c0a222e..0000000
--- a/man/geom_line.Rd
+++ /dev/null
@@ -1,93 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-path-line.r
-\name{geom_line}
-\alias{geom_line}
-\title{Connect observations, ordered by x value.}
-\usage{
-geom_line(mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
-
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-Connect observations, ordered by x value.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "line")}
-}
-\examples{
-# Summarise number of movie ratings by year of movie
-mry <- do.call(rbind, by(movies, round(movies$rating), function(df) {
-  nums <- tapply(df$length, df$year, length)
-  data.frame(rating=round(df$rating[1]), year = as.numeric(names(nums)), number=as.vector(nums))
-}))
-
-p <- ggplot(mry, aes(x=year, y=number, group=rating))
-p + geom_line()
-
-# Add aesthetic mappings
-p + geom_line(aes(size = rating))
-p + geom_line(aes(colour = rating))
-
-# Change scale
-p + geom_line(aes(colour = rating)) + scale_colour_gradient(low="red")
-p + geom_line(aes(size = rating)) + scale_size(range = c(0.1, 3))
-
-# Set aesthetics to fixed value
-p + geom_line(colour = "red", size = 1)
-
-# Use qplot instead
-qplot(year, number, data=mry, group=rating, geom="line")
-
-# Using a time series
-qplot(date, pop, data=economics, geom="line")
-qplot(date, pop, data=economics, geom="line", log="y")
-qplot(date, pop, data=subset(economics, date > as.Date("2006-1-1")), geom="line")
-qplot(date, pop, data=economics, size=unemploy/pop, geom="line")
-
-# Use the arrow parameter to add an arrow to the line
-# See ?grid::arrow for more details
-c <- ggplot(economics, aes(x = date, y = pop))
-# Arrow defaults to "last"
-library(grid)
-c + geom_line(arrow = arrow())
-c + geom_line(arrow = arrow(angle = 15, ends = "both", type = "closed"))
-
-# See scale_date for examples of plotting multiple times series on
-# a single graph
-
-# A simple pcp example
-
-y2005 <- runif(300, 20, 120)
-y2010 <- y2005 * runif(300, -1.05, 1.5)
-group <- rep(LETTERS[1:3], each = 100)
-
-df <- data.frame(id = seq_along(group), group, y2005, y2010)
-library(reshape2) # for melt
-dfm <- melt(df, id.var = c("id", "group"))
-ggplot(dfm, aes(variable, value, group = id, colour = group)) +
-  geom_path(alpha = 0.5)
-}
-\seealso{
-\code{\link{geom_path}}: connect observations in data order,
- \code{\link{geom_segment}}: draw line segments,
- \code{\link{geom_ribbon}}: fill between line and x-axis
-}
-
diff --git a/man/geom_linerange.Rd b/man/geom_linerange.Rd
index 27f2338..bf248b2 100644
--- a/man/geom_linerange.Rd
+++ b/man/geom_linerange.Rd
@@ -1,65 +1,116 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-linerange.r
-\name{geom_linerange}
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-crossbar.r, R/geom-errorbar.r, R/geom-linerange.r, R/geom-pointrange.r
+\name{geom_crossbar}
+\alias{geom_crossbar}
+\alias{geom_errorbar}
 \alias{geom_linerange}
-\title{An interval represented by a vertical line.}
+\alias{geom_pointrange}
+\title{Vertical intervals: lines, crossbars & errorbars.}
 \usage{
+geom_crossbar(mapping = NULL, data = NULL, stat = "identity",
+  position = "identity", fatten = 2.5, na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+
+geom_errorbar(mapping = NULL, data = NULL, stat = "identity",
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+
 geom_linerange(mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", ...)
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+
+geom_pointrange(mapping = NULL, data = NULL, stat = "identity",
+  position = "identity", ..., fatten = 4, na.rm = FALSE,
+  show.legend = NA, inherit.aes = TRUE)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
 \item{stat}{The statistical transformation to use on the data for this
-layer.}
+layer, as a string.}
+
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
+
+\item{fatten}{A multiplicative factor used to increase the size of the
+middle bar in \code{geom_crossbar()} and the middle point in
+\code{geom_pointrange()}.}
+
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
 }
 \description{
-An interval represented by a vertical line.
+Various ways of representing a vertical interval defined by \code{x},
+\code{ymin} and \code{ymax}.
 }
 \section{Aesthetics}{
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "linerange")}
 }
 \examples{
-# Generate data: means and standard errors of means for prices
-# for each type of cut
-dmod <- lm(price ~ cut, data=diamonds)
-cuts <- data.frame(cut = unique(diamonds$cut),
-  predict(dmod, data.frame(cut = unique(diamonds$cut)), se=TRUE)[c("fit","se.fit")])
-
-qplot(cut, fit, data=cuts)
-# With a bar chart, we are comparing lengths, so the y-axis is
-# automatically extended to include 0
-qplot(cut, fit, data=cuts, geom="bar")
-
-# Display estimates and standard errors in various ways
-se <- ggplot(cuts, aes(cut, fit,
-  ymin = fit - se.fit, ymax=fit + se.fit, colour = cut))
-se + geom_linerange()
-se + geom_pointrange()
-se + geom_errorbar(width = 0.5)
-se + geom_crossbar(width = 0.5)
-
-# Use coord_flip to flip the x and y axes
-se + geom_linerange() + coord_flip()
+#' # Create a simple example dataset
+df <- data.frame(
+  trt = factor(c(1, 1, 2, 2)),
+  resp = c(1, 5, 3, 4),
+  group = factor(c(1, 2, 1, 2)),
+  upper = c(1.1, 5.3, 3.3, 4.2),
+  lower = c(0.8, 4.6, 2.4, 3.6)
+)
+
+p <- ggplot(df, aes(trt, resp, colour = group))
+p + geom_linerange(aes(ymin = lower, ymax = upper))
+p + geom_pointrange(aes(ymin = lower, ymax = upper))
+p + geom_crossbar(aes(ymin = lower, ymax = upper), width = 0.2)
+p + geom_errorbar(aes(ymin = lower, ymax = upper), width = 0.2)
+
+# Draw lines connecting group means
+p +
+  geom_line(aes(group = group)) +
+  geom_errorbar(aes(ymin = lower, ymax = upper), width = 0.2)
+
+# If you want to dodge bars and errorbars, you need to manually
+# specify the dodge width
+p <- ggplot(df, aes(trt, resp, fill = group))
+p +
+ geom_bar(position = "dodge", stat = "identity") +
+ geom_errorbar(aes(ymin = lower, ymax = upper), position = "dodge", width = 0.25)
+
+# Because the bars and errorbars have different widths
+# we need to specify how wide the objects we are dodging are
+dodge <- position_dodge(width=0.9)
+p +
+  geom_bar(position = dodge, stat = "identity") +
+  geom_errorbar(aes(ymin = lower, ymax = upper), position = dodge, width = 0.25)
 }
 \seealso{
-\code{\link{geom_errorbar}}: error bars;
-  \code{\link{geom_pointrange}}: range indicated by straight line, with
-  point in the middle; \code{\link{geom_crossbar}}: hollow bar with middle
-  indicated by horizontal line; \code{\link{stat_summary}}: examples of
-  these guys in use; \code{\link{geom_smooth}}: for continuous analog
+\code{\link{stat_summary}} for examples of these guys in use,
+ \code{\link{geom_smooth}} for continuous analog
 }
 
diff --git a/man/geom_map.Rd b/man/geom_map.Rd
index 95db160..c623ce2 100644
--- a/man/geom_map.Rd
+++ b/man/geom_map.Rd
@@ -1,18 +1,21 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/geom-map.r
 \name{geom_map}
 \alias{geom_map}
 \title{Polygons from a reference map.}
 \usage{
-geom_map(mapping = NULL, data = NULL, map, stat = "identity", ...)
+geom_map(mapping = NULL, data = NULL, map, stat = "identity",
+  na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
 \item{map}{Data frame that contains the map coordinates.  This will
 typically be created using \code{\link{fortify}} on a spatial object.
@@ -20,11 +23,30 @@ It must contain columns \code{x} or \code{long}, \code{y} or
 \code{lat}, and \code{region} or \code{id}.}
 
 \item{stat}{The statistical transformation to use on the data for this
-layer.}
+layer, as a string.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
 }
 \description{
 Does not affect position scales.
@@ -65,8 +87,7 @@ ggplot(values, aes(fill = value)) +
 
 # Better example
 crimes <- data.frame(state = tolower(rownames(USArrests)), USArrests)
-library(reshape2) # for melt
-crimesm <- melt(crimes, id = 1)
+crimesm <- reshape2::melt(crimes, id = 1)
 if (require(maps)) {
   states_map <- map_data("state")
   ggplot(crimes, aes(map_id = state)) +
diff --git a/man/geom_path.Rd b/man/geom_path.Rd
index 70d37b6..8eefff1 100644
--- a/man/geom_path.Rd
+++ b/man/geom_path.Rd
@@ -1,26 +1,39 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-path-.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-path.r
 \name{geom_path}
+\alias{geom_line}
 \alias{geom_path}
-\title{Connect observations in original order}
+\alias{geom_step}
+\title{Connect observations.}
 \usage{
 geom_path(mapping = NULL, data = NULL, stat = "identity",
   position = "identity", lineend = "butt", linejoin = "round",
-  linemitre = 1, na.rm = FALSE, arrow = NULL, ...)
+  linemitre = 1, na.rm = FALSE, arrow = NULL, show.legend = NA,
+  inherit.aes = TRUE, ...)
+
+geom_line(mapping = NULL, data = NULL, stat = "identity",
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+
+geom_step(mapping = NULL, data = NULL, stat = "identity",
+  position = "identity", direction = "hv", na.rm = FALSE,
+  show.legend = NA, inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
 \item{stat}{The statistical transformation to use on the data for this
-layer.}
+layer, as a string.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
 \item{lineend}{Line end style (round, butt, square)}
 
@@ -31,36 +44,70 @@ on this layer}
 \item{na.rm}{If \code{FALSE} (the default), removes missing values with
 a warning.  If \code{TRUE} silently removes missing values.}
 
-\item{arrow}{Arrow specification, as created by ?grid::arrow}
+\item{arrow}{Arrow specification, as created by \code{\link[grid]{arrow}}}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
+
+\item{direction}{direction of stairs: 'vh' for vertical then horizontal, or
+'hv' for horizontal then vertical}
 }
 \description{
-Connect observations in original order
+\code{geom_path()} connects the observations in the order in which they appear
+in the data. \code{geom_line()} connects them in order of the variable on the
+x axis. \code{geom_step()} creates a stairstep plot, highlighting exactly
+when changes occur.
 }
 \section{Aesthetics}{
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "path")}
 }
 \examples{
-\donttest{
-# Generate data
-library(plyr)
-myear <- ddply(movies, .(year), colwise(mean, .(length, rating)))
-p <- ggplot(myear, aes(length, rating))
-p + geom_path()
-
-# Add aesthetic mappings
-p + geom_path(aes(size = year))
-p + geom_path(aes(colour = year))
+# geom_line() is suitable for time series
+ggplot(economics, aes(date, unemploy)) + geom_line()
+ggplot(economics_long, aes(date, value01, colour = variable)) +
+  geom_line()
+
+# geom_step() is useful when you want to highlight exactly when
+# the y value chanes
+recent <- economics[economics$date > as.Date("2013-01-01"), ]
+ggplot(recent, aes(date, unemploy)) + geom_line()
+ggplot(recent, aes(date, unemploy)) + geom_step()
+
+# geom_path lets you explore how two variables are related over time,
+# e.g. unemployment and personal savings rate
+m <- ggplot(economics, aes(unemploy/pop, psavert))
+m + geom_path()
+m + geom_path(aes(colour = as.numeric(date)))
+
+# Changing parameters ----------------------------------------------
+ggplot(economics, aes(date, unemploy)) +
+  geom_line(colour = "red")
 
-# Change scale
-p + geom_path(aes(size = year)) + scale_size(range = c(1, 3))
-
-# Set aesthetics to fixed value
-p + geom_path(colour = "green")
+# Use the arrow parameter to add an arrow to the line
+# See ?arrow for more details
+c <- ggplot(economics, aes(x = date, y = pop))
+c + geom_line(arrow = arrow())
+c + geom_line(
+  arrow = arrow(angle = 15, ends = "both", type = "closed")
+)
 
 # Control line join parameters
 df <- data.frame(x = 1:3, y = c(4, 1, 9))
@@ -69,66 +116,39 @@ base + geom_path(size = 10)
 base + geom_path(size = 10, lineend = "round")
 base + geom_path(size = 10, linejoin = "mitre", lineend = "butt")
 
-# Use qplot instead
-qplot(length, rating, data=myear, geom="path")
-
-# Using economic data:
-# How is unemployment and personal savings rate related?
-qplot(unemploy/pop, psavert, data=economics)
-qplot(unemploy/pop, psavert, data=economics, geom="path")
-qplot(unemploy/pop, psavert, data=economics, geom="path", size=as.numeric(date))
-
-# How is rate of unemployment and length of unemployment?
-qplot(unemploy/pop, uempmed, data=economics)
-qplot(unemploy/pop, uempmed, data=economics, geom="path")
-qplot(unemploy/pop, uempmed, data=economics, geom="path") +
-  geom_point(data=head(economics, 1), colour="red") +
-  geom_point(data=tail(economics, 1), colour="blue")
-qplot(unemploy/pop, uempmed, data=economics, geom="path") +
-  geom_text(data=head(economics, 1), label="1967", colour="blue") +
-  geom_text(data=tail(economics, 1), label="2007", colour="blue")
-
-# geom_path removes missing values on the ends of a line.
-# use na.rm = T to suppress the warning message
+# NAs break the line. Use na.rm = T to suppress the warning message
 df <- data.frame(
   x = 1:5,
   y1 = c(1, 2, 3, 4, NA),
   y2 = c(NA, 2, 3, 4, 5),
-  y3 = c(1, 2, NA, 4, 5),
-  y4 = c(1, 2, 3, 4, 5))
-qplot(x, y1, data = df, geom = c("point","line"))
-qplot(x, y2, data = df, geom = c("point","line"))
-qplot(x, y3, data = df, geom = c("point","line"))
-qplot(x, y4, data = df, geom = c("point","line"))
+  y3 = c(1, 2, NA, 4, 5)
+)
+ggplot(df, aes(x, y1)) + geom_point() + geom_line()
+ggplot(df, aes(x, y2)) + geom_point() + geom_line()
+ggplot(df, aes(x, y3)) + geom_point() + geom_line()
 
+\donttest{
 # Setting line type vs colour/size
 # Line type needs to be applied to a line as a whole, so it can
 # not be used with colour or size that vary across a line
-
-x <- seq(0.01, .99, length=100)
-df <- data.frame(x = rep(x, 2), y = c(qlogis(x), 2 * qlogis(x)), group = rep(c("a","b"), each=100))
+x <- seq(0.01, .99, length.out = 100)
+df <- data.frame(
+  x = rep(x, 2),
+  y = c(qlogis(x), 2 * qlogis(x)),
+  group = rep(c("a","b"),
+  each = 100)
+)
 p <- ggplot(df, aes(x=x, y=y, group=group))
-
-# Should work
+# These work
 p + geom_line(linetype = 2)
 p + geom_line(aes(colour = group), linetype = 2)
 p + geom_line(aes(colour = x))
-
-# Should fail
+# But this doesn't
 should_stop(p + geom_line(aes(colour = x), linetype=2))
-
-# Use the arrow parameter to add an arrow to the line
-# See ?grid::arrow for more details
-library(grid)
-c <- ggplot(economics, aes(x = date, y = pop))
-# Arrow defaults to "last"
-c + geom_path(arrow = arrow())
-c + geom_path(arrow = arrow(angle = 15, ends = "both", length = unit(0.6, "inches")))
 }
 }
 \seealso{
-\code{\link{geom_line}}: Functional (ordered) lines;
- \code{\link{geom_polygon}}: Filled paths (polygons);
+\code{\link{geom_polygon}}: Filled paths (polygons);
  \code{\link{geom_segment}}: Line segments
 }
 
diff --git a/man/geom_point.Rd b/man/geom_point.Rd
index bae60be..87cd111 100644
--- a/man/geom_point.Rd
+++ b/man/geom_point.Rd
@@ -1,32 +1,51 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-point-.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-point.r
 \name{geom_point}
 \alias{geom_point}
 \title{Points, as for a scatterplot}
 \usage{
 geom_point(mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", na.rm = FALSE, ...)
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
 \item{stat}{The statistical transformation to use on the data for this
-layer.}
+layer, as a string.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
 \item{na.rm}{If \code{FALSE} (the default), removes missing values with
 a warning.  If \code{TRUE} silently removes missing values.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
 }
 \description{
 The point geom is used to create scatterplots.
@@ -46,74 +65,68 @@ you have more than a few points, points may be plotted on top of one
 another. This can severely distort the visual appearance of the plot.
 There is no one solution to this problem, but there are some techniques
 that can help.  You can add additional information with
-\code{\link{stat_smooth}}, \code{\link{stat_quantile}} or
-\code{\link{stat_density2d}}.  If you have few unique x values,
+\code{\link{geom_smooth}}, \code{\link{geom_quantile}} or
+\code{\link{geom_density_2d}}.  If you have few unique x values,
 \code{\link{geom_boxplot}} may also be useful.  Alternatively, you can
 summarise the number of points at each location and display that in some
 way, using \code{\link{stat_sum}}. Another technique is to use transparent
-points, \code{geom_point(alpha = 0.05)}.
+points, e.g. \code{geom_point(alpha = 0.05)}.
 }
 \section{Aesthetics}{
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "point")}
 }
 \examples{
-\donttest{
 p <- ggplot(mtcars, aes(wt, mpg))
 p + geom_point()
 
 # Add aesthetic mappings
-p + geom_point(aes(colour = qsec))
-p + geom_point(aes(alpha = qsec))
 p + geom_point(aes(colour = factor(cyl)))
 p + geom_point(aes(shape = factor(cyl)))
 p + geom_point(aes(size = qsec))
 
 # Change scales
 p + geom_point(aes(colour = cyl)) + scale_colour_gradient(low = "blue")
-p + geom_point(aes(size = qsec)) + scale_size_area()
 p + geom_point(aes(shape = factor(cyl))) + scale_shape(solid = FALSE)
 
 # Set aesthetics to fixed value
-p + geom_point(colour = "red", size = 3)
-qplot(wt, mpg, data = mtcars, colour = I("red"), size = I(3))
+ggplot(mtcars, aes(wt, mpg)) + geom_point(colour = "red", size = 3)
 
+\donttest{
 # Varying alpha is useful for large datasets
 d <- ggplot(diamonds, aes(carat, price))
 d + geom_point(alpha = 1/10)
 d + geom_point(alpha = 1/20)
 d + geom_point(alpha = 1/100)
+}
+
+# For shapes that have a border (like 21), you can colour the inside and
+# outside separately. Use the stroke aesthetic to modify the width of the
+# border
+ggplot(mtcars, aes(wt, mpg)) +
+  geom_point(shape = 21, colour = "black", fill = "white", size = 5, stroke = 5)
 
+\donttest{
 # You can create interesting shapes by layering multiple points of
 # different sizes
-p <- ggplot(mtcars, aes(mpg, wt))
-p + geom_point(colour="grey50", size = 4) + geom_point(aes(colour = cyl))
-p + aes(shape = factor(cyl)) +
-  geom_point(aes(colour = factor(cyl)), size = 4) +
-  geom_point(colour="grey90", size = 1.5)
-p + geom_point(colour="black", size = 4.5) +
-  geom_point(colour="pink", size = 4) +
+p <- ggplot(mtcars, aes(mpg, wt, shape = factor(cyl)))
+p + geom_point(aes(colour = factor(cyl)), size = 4) +
+  geom_point(colour = "grey90", size = 1.5)
+p + geom_point(colour = "black", size = 4.5) +
+  geom_point(colour = "pink", size = 4) +
   geom_point(aes(shape = factor(cyl)))
 
 # These extra layers don't usually appear in the legend, but we can
 # force their inclusion
-p + geom_point(colour="black", size = 4.5, show_guide = TRUE) +
-  geom_point(colour="pink", size = 4, show_guide = TRUE) +
+p + geom_point(colour = "black", size = 4.5, show.legend = TRUE) +
+  geom_point(colour = "pink", size = 4, show.legend = TRUE) +
   geom_point(aes(shape = factor(cyl)))
 
-# Transparent points:
-qplot(mpg, wt, data = mtcars, size = I(5), alpha = I(0.2))
-
 # geom_point warns when missing values have been dropped from the data set
 # and not plotted, you can turn this off by setting na.rm = TRUE
 mtcars2 <- transform(mtcars, mpg = ifelse(runif(32) < 0.2, NA, mpg))
-qplot(wt, mpg, data = mtcars2)
-qplot(wt, mpg, data = mtcars2, na.rm = TRUE)
-
-# Use qplot instead
-qplot(wt, mpg, data = mtcars)
-qplot(wt, mpg, data = mtcars, colour = factor(cyl))
-qplot(wt, mpg, data = mtcars, colour = I("red"))
+ggplot(mtcars2, aes(wt, mpg)) + geom_point()
+ggplot(mtcars2, aes(wt, mpg)) + geom_point(na.rm = TRUE)
 }
 }
 \seealso{
diff --git a/man/geom_pointrange.Rd b/man/geom_pointrange.Rd
deleted file mode 100644
index a48ee4c..0000000
--- a/man/geom_pointrange.Rd
+++ /dev/null
@@ -1,45 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-pointrange.r
-\name{geom_pointrange}
-\alias{geom_pointrange}
-\title{An interval represented by a vertical line, with a point in the middle.}
-\usage{
-geom_pointrange(mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
-
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-An interval represented by a vertical line, with a point in the middle.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "pointrange")}
-}
-\examples{
-# See geom_linerange for examples
-}
-\seealso{
-\code{\link{geom_errorbar}} for error bars,
- \code{\link{geom_linerange}} for range indicated by straight line, + examples,
- \code{\link{geom_crossbar}} for hollow bar with middle indicated by horizontal line,
- \code{\link{stat_summary}} for examples of these guys in use,
- \code{\link{geom_smooth}} for continuous analog"
-}
-
diff --git a/man/geom_polygon.Rd b/man/geom_polygon.Rd
index 9ece293..0065219 100644
--- a/man/geom_polygon.Rd
+++ b/man/geom_polygon.Rd
@@ -1,29 +1,51 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/geom-polygon.r
 \name{geom_polygon}
 \alias{geom_polygon}
 \title{Polygon, a filled path.}
 \usage{
 geom_polygon(mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", ...)
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
 \item{stat}{The statistical transformation to use on the data for this
-layer.}
+layer, as a string.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
 }
 \description{
 Polygon, a filled path.
diff --git a/man/geom_quantile.Rd b/man/geom_quantile.Rd
index cdf3a4b..64633c3 100644
--- a/man/geom_quantile.Rd
+++ b/man/geom_quantile.Rd
@@ -1,26 +1,32 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-quantile.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-quantile.r, R/stat-quantile.r
 \name{geom_quantile}
 \alias{geom_quantile}
+\alias{stat_quantile}
 \title{Add quantile lines from a quantile regression.}
 \usage{
 geom_quantile(mapping = NULL, data = NULL, stat = "quantile",
   position = "identity", lineend = "butt", linejoin = "round",
-  linemitre = 1, na.rm = FALSE, ...)
+  linemitre = 1, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE,
+  ...)
+
+stat_quantile(mapping = NULL, data = NULL, geom = "quantile",
+  position = "identity", quantiles = c(0.25, 0.5, 0.75), formula = NULL,
+  method = "rq", method.args = list(), na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
 \item{lineend}{Line end style (round, butt, square)}
 
@@ -31,9 +37,38 @@ on this layer}
 \item{na.rm}{If \code{FALSE} (the default), removes missing values with
 a warning.  If \code{TRUE} silently removes missing values.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
+
+\item{geom, stat}{Use to override the default connection between
+\code{geom_quantile} and \code{stat_quantile}.}
+
+\item{quantiles}{conditional quantiles of y to calculate and display}
+
+\item{formula}{formula relating y variables to x variables}
+
+\item{method}{Quantile regression method to use.  Currently only supports
+\code{\link[quantreg]{rq}}.}
+
+\item{method.args}{List of additional arguments passed on to the modelling
+function defined by \code{method}.}
 }
 \description{
 This can be used as a continuous analogue of a geom_boxplot.
@@ -42,10 +77,27 @@ This can be used as a continuous analogue of a geom_boxplot.
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "quantile")}
 }
-\examples{
-# See stat_quantile for examples
+
+\section{Computed variables}{
+
+\describe{
+  \item{quantile}{quantile of distribution}
 }
-\seealso{
-See \code{\link{stat_quantile}} for examples.
+}
+\examples{
+m <- ggplot(mpg, aes(displ, 1 / hwy)) + geom_point()
+m + geom_quantile()
+m + geom_quantile(quantiles = 0.5)
+q10 <- seq(0.05, 0.95, by = 0.05)
+m + geom_quantile(quantiles = q10)
+
+# You can also use rqss to fit smooth quantiles
+m + geom_quantile(method = "rqss")
+# Note that rqss doesn't pick a smoothing constant automatically, so
+# you'll need to tweak lambda yourself
+m + geom_quantile(method = "rqss", lambda = 0.1)
+
+# Set aesthetics to fixed value
+m + geom_quantile(colour = "red", size = 2, alpha = 0.5)
 }
 
diff --git a/man/geom_raster.Rd b/man/geom_raster.Rd
deleted file mode 100644
index 8bd52cf..0000000
--- a/man/geom_raster.Rd
+++ /dev/null
@@ -1,82 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-raster.r
-\name{geom_raster}
-\alias{geom_raster}
-\title{High-performance rectangular tiling.}
-\usage{
-geom_raster(mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", hjust = 0.5, vjust = 0.5, interpolate = FALSE,
-  ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
-
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
-
-\item{hjust,vjust}{horizontal and vertical justification of the grob.  Each
-justification value should be a number between 0 and 1.  Defaults to 0.5
-for both, centering each pixel over its data location.}
-
-\item{interpolate}{If \code{TRUE} interpolate linearly, if \code{FALSE}
-(the default) don't interpolate.}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-This is a special case of \code{\link{geom_tile}} where all tiles are
-the same size.  It is implemented highly efficiently using the internal
-\code{rasterGrob} function.
-}
-\details{
-By default, \code{geom_raster} add a vertical and horizontal padding.
-The size of padding depends on the resolution of data.
-If you want to manually set the padding (e.g. want zero-padding),
-you can change the behavior by setting \code{hpad} and \code{vpad}.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "raster")}
-}
-\examples{
-\donttest{
-# Generate data
-pp <- function (n,r=4) {
- x <- seq(-r*pi, r*pi, len=n)
- df <- expand.grid(x=x, y=x)
- df$r <- sqrt(df$x^2 + df$y^2)
- df$z <- cos(df$r^2)*exp(-df$r/6)
- df
-}
-qplot(x, y, data = pp(20), fill = z, geom = "raster")
-# Interpolation worsens the apperance of this plot, but can help when
-# rendering images.
-qplot(x, y, data = pp(20), fill = z, geom = "raster", interpolate = TRUE)
-
-# For the special cases where it is applicable, geom_raster is much
-# faster than geom_tile:
-pp200 <- pp(200)
-base <- ggplot(pp200, aes(x, y, fill = z))
-benchplot(base + geom_raster())
-benchplot(base + geom_tile())
-
-# justification
-df <- expand.grid(x = 0:5, y = 0:5)
-df$z <- runif(nrow(df))
-# default is compatible with geom_tile()
-ggplot(df, aes(x, y, fill = z)) + geom_raster()
-# zero padding
-ggplot(df, aes(x, y, fill = z)) + geom_raster(hjust = 0, vjust = 0)
-}
-}
-
diff --git a/man/geom_rect.Rd b/man/geom_rect.Rd
deleted file mode 100644
index 99609a2..0000000
--- a/man/geom_rect.Rd
+++ /dev/null
@@ -1,43 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-rect.r
-\name{geom_rect}
-\alias{geom_rect}
-\title{2d rectangles.}
-\usage{
-geom_rect(mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
-
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-2d rectangles.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "rect")}
-}
-\examples{
-df <- data.frame(
-  x = sample(10, 20, replace = TRUE),
-  y = sample(10, 20, replace = TRUE)
-)
-ggplot(df, aes(xmin = x, xmax = x + 1, ymin = y, ymax = y + 2)) +
-geom_rect()
-}
-
diff --git a/man/geom_ribbon.Rd b/man/geom_ribbon.Rd
index 2787208..74b12ea 100644
--- a/man/geom_ribbon.Rd
+++ b/man/geom_ribbon.Rd
@@ -1,76 +1,89 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-ribbon-.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-ribbon.r
 \name{geom_ribbon}
+\alias{geom_area}
 \alias{geom_ribbon}
-\title{Ribbons, y range with continuous x values.}
+\title{Ribbons and area plots.}
 \usage{
 geom_ribbon(mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", na.rm = FALSE, ...)
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+
+geom_area(mapping = NULL, data = NULL, stat = "identity",
+  position = "stack", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
 \item{stat}{The statistical transformation to use on the data for this
-layer.}
+layer, as a string.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
 \item{na.rm}{If \code{FALSE} (the default), removes missing values with
 a warning.  If \code{TRUE} silently removes missing values.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
 }
 \description{
-Ribbons, y range with continuous x values.
+For each continuous x value, \code{geom_interval} displays a y interval.
+\code{geom_area} is a special case of \code{geom_ribbon}, where the
+minimum of the range is fixed to 0.
+}
+\details{
+An area plot is the continuous analog of a stacked bar chart (see
+\code{\link{geom_bar}}), and can be used to show how composition of the
+whole varies over the range of x.  Choosing the order in which different
+components is stacked is very important, as it becomes increasing hard to
+see the individual pattern as you move up the stack.
 }
 \section{Aesthetics}{
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "ribbon")}
 }
 \examples{
-\donttest{
 # Generate data
 huron <- data.frame(year = 1875:1972, level = as.vector(LakeHuron))
-library(plyr) # to access round_any
-huron$decade <- round_any(huron$year, 10, floor)
-
-h <- ggplot(huron, aes(x=year))
+h <- ggplot(huron, aes(year))
 
 h + geom_ribbon(aes(ymin=0, ymax=level))
 h + geom_area(aes(y = level))
 
 # Add aesthetic mappings
-h + geom_ribbon(aes(ymin=level-1, ymax=level+1))
-h + geom_ribbon(aes(ymin=level-1, ymax=level+1)) + geom_line(aes(y=level))
-
-# Take out some values in the middle for an example of NA handling
-huron[huron$year > 1900 & huron$year < 1910, "level"] <- NA
-h <- ggplot(huron, aes(x=year))
-h + geom_ribbon(aes(ymin=level-1, ymax=level+1)) + geom_line(aes(y=level))
-
-# Another data set, with multiple y's for each x
-m <- ggplot(movies, aes(y=votes, x=year))
-(m <- m + geom_point())
-
-# The default summary isn't that useful
-m + stat_summary(geom="ribbon", fun.ymin="min", fun.ymax="max")
-m + stat_summary(geom="ribbon", fun.data="median_hilow")
-
-# Use qplot instead
-qplot(year, level, data=huron, geom=c("area", "line"))
-}
+h +
+  geom_ribbon(aes(ymin = level - 1, ymax = level + 1), fill = "grey70") +
+  geom_line(aes(y = level))
 }
 \seealso{
 \code{\link{geom_bar}} for discrete intervals (bars),
   \code{\link{geom_linerange}} for discrete intervals (lines),
-  \code{\link{geom_polygon}} for general polygons"
+  \code{\link{geom_polygon}} for general polygons
 }
 
diff --git a/man/geom_rug.Rd b/man/geom_rug.Rd
index 609c248..8215bd2 100644
--- a/man/geom_rug.Rd
+++ b/man/geom_rug.Rd
@@ -1,33 +1,55 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/geom-rug.r
 \name{geom_rug}
 \alias{geom_rug}
 \title{Marginal rug plots.}
 \usage{
 geom_rug(mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", sides = "bl", ...)
+  position = "identity", sides = "bl", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
 \item{stat}{The statistical transformation to use on the data for this
-layer.}
+layer, as a string.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
 \item{sides}{A string that controls which sides of the plot the rugs appear on.
 It can be set to a string containing any of \code{"trbl"}, for top, right,
 bottom, and left.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
 }
 \description{
 Marginal rug plots.
@@ -37,7 +59,7 @@ Marginal rug plots.
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "rug")}
 }
 \examples{
-p <- ggplot(mtcars, aes(x=wt, y=mpg))
+p <- ggplot(mtcars, aes(wt, mpg))
 p + geom_point()
 p + geom_point() + geom_rug()
 p + geom_point() + geom_rug(sides="b")    # Rug on bottom only
diff --git a/man/geom_segment.Rd b/man/geom_segment.Rd
index 48b9581..2811552 100644
--- a/man/geom_segment.Rd
+++ b/man/geom_segment.Rd
@@ -1,26 +1,34 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-segment.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-segment.r, R/geom-curve.r
 \name{geom_segment}
+\alias{geom_curve}
 \alias{geom_segment}
-\title{Single line segments.}
+\title{Line segments and curves.}
 \usage{
 geom_segment(mapping = NULL, data = NULL, stat = "identity",
   position = "identity", arrow = NULL, lineend = "butt", na.rm = FALSE,
-  ...)
+  show.legend = NA, inherit.aes = TRUE, ...)
+
+geom_curve(mapping = NULL, data = NULL, stat = "identity",
+  position = "identity", curvature = 0.5, angle = 90, ncp = 5,
+  arrow = NULL, lineend = "butt", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
 \item{stat}{The statistical transformation to use on the data for this
-layer.}
+layer, as a string.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
 \item{arrow}{specification for arrow heads, as created by arrow()}
 
@@ -29,54 +37,82 @@ on this layer}
 \item{na.rm}{If \code{FALSE} (the default), removes missing values with
 a warning.  If \code{TRUE} silently removes missing values.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
+
+\item{curvature}{A numeric value giving the amount of curvature.
+    Negative values produce left-hand curves, positive values
+    produce right-hand curves, and zero produces a straight line.}
+
+\item{angle}{A numeric value between 0 and 180,
+    giving an amount to skew the control
+    points of the curve.  Values less than 90 skew the curve towards
+    the start point and values greater than 90 skew the curve
+    towards the end point.}
+
+\item{ncp}{The number of control points used to draw the curve.
+    More control points creates a smoother curve.}
 }
 \description{
-Single line segments.
+\code{geom_segment} draws a straight line between points (x1, y1) and
+(x2, y2). \code{geom_curve} draws a curved line.
 }
 \section{Aesthetics}{
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "segment")}
 }
 \examples{
-library(grid) # needed for arrow function
-p <- ggplot(seals, aes(x = long, y = lat))
-(p <- p + geom_segment(aes(xend = long + delta_long, yend = lat + delta_lat),
-  arrow = arrow(length = unit(0.1,"cm"))))
-
-if (require("maps")) {
-
-xlim <- range(seals$long)
-ylim <- range(seals$lat)
-usamap <- data.frame(map("world", xlim = xlim, ylim = ylim, plot =
-FALSE)[c("x","y")])
-usamap <- rbind(usamap, NA, data.frame(map('state', xlim = xlim, ylim
-= ylim, plot = FALSE)[c("x","y")]))
-names(usamap) <- c("long", "lat")
-
-p + geom_path(data = usamap) + scale_x_continuous(limits = xlim)
-}
+b <- ggplot(mtcars, aes(wt, mpg)) +
+  geom_point()
+
+df <- data.frame(x1 = 2.62, x2 = 3.57, y1 = 21.0, y2 = 15.0)
+b +
+ geom_curve(aes(x = x1, y = y1, xend = x2, yend = y2, colour = "curve"), data = df) +
+ geom_segment(aes(x = x1, y = y1, xend = x2, yend = y2, colour = "segment"), data = df)
+
+b + geom_curve(aes(x = x1, y = y1, xend = x2, yend = y2), data = df, curvature = -0.2)
+b + geom_curve(aes(x = x1, y = y1, xend = x2, yend = y2), data = df, curvature = 1)
+b + geom_curve(
+  aes(x = x1, y = y1, xend = x2, yend = y2),
+  data = df,
+  arrow = arrow(length = unit(0.03, "npc"))
+)
+
+ggplot(seals, aes(long, lat)) +
+  geom_segment(aes(xend = long + delta_long, yend = lat + delta_lat),
+    arrow = arrow(length = unit(0.1,"cm"))) +
+  borders("state")
 
 # You can also use geom_segment to recreate plot(type = "h") :
 counts <- as.data.frame(table(x = rpois(100,5)))
 counts$x <- as.numeric(as.character(counts$x))
 with(counts, plot(x, Freq, type = "h", lwd = 10))
 
-qplot(x, Freq, data = counts, geom = "segment",
-  yend = 0, xend = x, size = I(10))
-
-# Adding line segments
-library(grid) # needed for arrow function
-b <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
-b + geom_segment(aes(x = 2, y = 15, xend = 2, yend = 25))
-b + geom_segment(aes(x = 2, y = 15, xend = 3, yend = 15))
-b + geom_segment(aes(x = 5, y = 30, xend = 3.5, yend = 25),
-   arrow = arrow(length = unit(0.5, "cm")))
+ggplot(counts, aes(x, Freq)) +
+  geom_segment(aes(xend = x, yend = 0), size = 10, lineend = "butt")
 }
 \seealso{
 \code{\link{geom_path}} and \code{\link{geom_line}} for multi-
   segment lines and paths.
+
+\code{\link{geom_spoke}} for a segment parameterised by a location
+  (x, y), and an angle and radius.
 }
 
diff --git a/man/geom_smooth.Rd b/man/geom_smooth.Rd
index 4be96b6..cbccc26 100644
--- a/man/geom_smooth.Rd
+++ b/man/geom_smooth.Rd
@@ -1,64 +1,171 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-smooth.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-smooth.r, R/stat-smooth.r
 \name{geom_smooth}
 \alias{geom_smooth}
+\alias{stat_smooth}
 \title{Add a smoothed conditional mean.}
 \usage{
 geom_smooth(mapping = NULL, data = NULL, stat = "smooth",
-  position = "identity", ...)
+  method = "auto", formula = y ~ x, se = TRUE, position = "identity",
+  na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...)
+
+stat_smooth(mapping = NULL, data = NULL, geom = "smooth",
+  position = "identity", method = "auto", formula = y ~ x, se = TRUE,
+  n = 80, span = 0.75, fullrange = FALSE, level = 0.95,
+  method.args = list(), na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
+
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
+
+\item{method}{smoothing method (function) to use, eg. lm, glm, gam, loess,
+rlm. For datasets with n < 1000 default is \code{\link{loess}}. For datasets
+with 1000 or more observations defaults to gam, see \code{\link[mgcv]{gam}}
+for more details.}
+
+\item{formula}{formula to use in smoothing function, eg. \code{y ~ x},
+\code{y ~ poly(x, 2)}, \code{y ~ log(x)}}
+
+\item{se}{display confidence interval around smooth? (TRUE by default, see
+level to control}
+
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
+
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
+
+\item{geom, stat}{Use to override the default connection between
+\code{geom_smooth} and \code{stat_smooth}.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{n}{number of points to evaluate smoother at}
 
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
+\item{span}{Controls the amount of smoothing for the default loess smoother.
+Smaller numbers produce wigglier lines, larger numbers produce smoother
+lines.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{fullrange}{should the fit span the full range of the plot, or just
+the data}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{level}{level of confidence interval to use (0.95 by default)}
+
+\item{method.args}{List of additional arguments passed on to the modelling
+function defined by \code{method}.}
 }
 \description{
-Add a smoothed conditional mean.
+Aids the eye in seeing patterns in the presence of overplotting.
+\code{geom_smooth} and \code{stat_smooth} are effectively aliases: they
+both use the same arguments. Use \code{geom_smooth} unless you want to
+display the results with a non-standard geom.
+}
+\details{
+Calculation is performed by the (currently undocumented)
+\code{predictdf} generic and its methods.  For most methods the standard
+error bounds are computed using the \code{\link{predict}} method - the
+exceptions are \code{loess} which uses a t-based approximation, and
+\code{glm} where the normal confidence interval is constructed on the link
+scale, and then back-transformed to the response scale.
 }
 \section{Aesthetics}{
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "smooth")}
 }
+
+\section{Computed variables}{
+
+\describe{
+  \item{y}{predicted value}
+  \item{ymin}{lower pointwise confidence interval around the mean}
+  \item{ymax}{upper pointwise confidence interval around the mean}
+  \item{se}{standard error}
+}
+}
 \examples{
-# See stat_smooth for examples of using built in model fitting
-# if you need some more flexible, this example shows you how to
-# plot the fits from any model of your choosing
-qplot(wt, mpg, data=mtcars, colour=factor(cyl))
+ggplot(mpg, aes(displ, hwy)) +
+  geom_point() +
+  geom_smooth()
 
-model <- lm(mpg ~ wt + factor(cyl), data=mtcars)
-grid <- with(mtcars, expand.grid(
-  wt = seq(min(wt), max(wt), length = 20),
-  cyl = levels(factor(cyl))
-))
+# Use span to control the "wiggliness" of the default loess smoother
+# The span is the fraction of points used to fit each local regression:
+# small numbers make a wigglier curve, larger numbers make a smoother curve.
+ggplot(mpg, aes(displ, hwy)) +
+  geom_point() +
+  geom_smooth(span = 0.3)
 
-grid$mpg <- stats::predict(model, newdata=grid)
+# Instead of a loess smooth, you can use any other modelling function:
+ggplot(mpg, aes(displ, hwy)) +
+  geom_point() +
+  geom_smooth(method = "lm", se = FALSE)
 
-qplot(wt, mpg, data=mtcars, colour=factor(cyl)) + geom_line(data=grid)
+ggplot(mpg, aes(displ, hwy)) +
+  geom_point() +
+  geom_smooth(method = "lm", formula = y ~ splines::bs(x, 3), se = FALSE)
 
-# or with standard errors
+# Smoothes are automatically fit to each group (defined by categorical
+# aesthetics or the group aesthetic) and for each facet
 
-err <- stats::predict(model, newdata=grid, se = TRUE)
-grid$ucl <- err$fit + 1.96 * err$se.fit
-grid$lcl <- err$fit - 1.96 * err$se.fit
+ggplot(mpg, aes(displ, hwy, colour = class)) +
+  geom_point() +
+  geom_smooth(se = FALSE, method = "lm")
+ggplot(mpg, aes(displ, hwy)) +
+  geom_point() +
+  geom_smooth(span = 0.8) +
+  facet_wrap(~drv)
 
-qplot(wt, mpg, data=mtcars, colour=factor(cyl)) +
-  geom_smooth(aes(ymin = lcl, ymax = ucl), data=grid, stat="identity")
+\dontrun{
+# To fit a logistic regression, you need to coerce the values to
+# a numeric vector lying between 0 and 1.
+binomial_smooth <- function(...) {
+  geom_smooth(method = "glm", method.args = list(family = "binomial"), ...)
+}
+
+ggplot(rpart::kyphosis, aes(Age, Kyphosis)) +
+  geom_jitter(height = 0.05) +
+  binomial_smooth()
+
+ggplot(rpart::kyphosis, aes(Age, as.numeric(Kyphosis) - 1)) +
+  geom_jitter(height = 0.05) +
+  binomial_smooth()
+
+ggplot(rpart::kyphosis, aes(Age, as.numeric(Kyphosis) - 1)) +
+  geom_jitter(height = 0.05) +
+  binomial_smooth(formula = y ~ splines::ns(x, 2))
+
+# But in this case, it's probably better to fit the model yourself
+# so you can exercise more control and see whether or not it's a good model
+}
 }
 \seealso{
-The default stat for this geom is \code{\link{stat_smooth}} see
-  that documentation for more options to control the underlying statistical transformation.
+See individual modelling functions for more details:
+  \code{\link{lm}} for linear smooths,
+  \code{\link{glm}} for generalised linear smooths,
+  \code{\link{loess}} for local smooths
 }
 
diff --git a/man/geom_spoke.Rd b/man/geom_spoke.Rd
new file mode 100644
index 0000000..b74a4ba
--- /dev/null
+++ b/man/geom_spoke.Rd
@@ -0,0 +1,71 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-spoke.r
+\name{geom_spoke}
+\alias{geom_spoke}
+\alias{stat_spoke}
+\title{A line segment parameterised by location, direction and distance.}
+\usage{
+geom_spoke(mapping = NULL, data = NULL, stat = "identity",
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+}
+\arguments{
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
+
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
+
+\item{stat}{The statistical transformation to use on the data for this
+layer, as a string.}
+
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
+
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
+}
+\description{
+A line segment parameterised by location, direction and distance.
+}
+\section{Aesthetics}{
+
+\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "spoke")}
+}
+\examples{
+df <- expand.grid(x = 1:10, y=1:10)
+df$angle <- runif(100, 0, 2*pi)
+df$speed <- runif(100, 0, sqrt(0.1 * df$x))
+
+ggplot(df, aes(x, y)) +
+  geom_point() +
+  geom_spoke(aes(angle = angle), radius = 0.5)
+
+ggplot(df, aes(x, y)) +
+  geom_point() +
+  geom_spoke(aes(angle = angle, radius = speed))
+}
+
diff --git a/man/geom_step.Rd b/man/geom_step.Rd
deleted file mode 100644
index b7000ac..0000000
--- a/man/geom_step.Rd
+++ /dev/null
@@ -1,57 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-path-step.r
-\name{geom_step}
-\alias{geom_step}
-\title{Connect observations by stairs.}
-\usage{
-geom_step(mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", direction = "hv", ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
-
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
-
-\item{direction}{direction of stairs: 'vh' for vertical then horizontal, or
-'hv' for horizontal then vertical}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-Connect observations by stairs.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "step")}
-}
-\examples{
-# Simple quantiles/ECDF from examples(plot)
-x <- sort(rnorm(47))
-qplot(seq_along(x), x, geom="step")
-
-# Steps go horizontally, then vertically (default)
-qplot(seq_along(x), x, geom="step", direction = "hv")
-plot(x, type = "s")
-# Steps go vertically, then horizontally
-qplot(seq_along(x), x, geom="step", direction = "vh")
-plot(x, type = "S")
-
-# Also works with other aesthetics
-df <- data.frame(
-  x = sort(rnorm(50)),
-  trt = sample(c("a", "b"), 50, rep = TRUE)
-)
-qplot(seq_along(x), x, data = df, geom="step", colour = trt)
-}
-
diff --git a/man/geom_text.Rd b/man/geom_text.Rd
index 177356e..1a620b5 100644
--- a/man/geom_text.Rd
+++ b/man/geom_text.Rd
@@ -1,60 +1,136 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-text.r
-\name{geom_text}
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-label.R, R/geom-text.r
+\name{geom_label}
+\alias{geom_label}
 \alias{geom_text}
 \title{Textual annotations.}
 \usage{
+geom_label(mapping = NULL, data = NULL, stat = "identity",
+  position = "identity", parse = FALSE, ..., nudge_x = 0, nudge_y = 0,
+  label.padding = unit(0.25, "lines"), label.r = unit(0.15, "lines"),
+  label.size = 0.25, na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE)
+
 geom_text(mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", parse = FALSE, ...)
+  position = "identity", parse = FALSE, ..., nudge_x = 0, nudge_y = 0,
+  check_overlap = FALSE, na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
 \item{stat}{The statistical transformation to use on the data for this
-layer.}
+layer, as a string.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
 \item{parse}{If TRUE, the labels will be parsed into expressions and
 displayed as described in ?plotmath}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
+
+\item{nudge_x, nudge_y}{Horizontal and vertical adjustment to nudge labels by.
+Useful for offsetting text from points, particularly on discrete scales.}
+
+\item{label.padding}{Amount of padding around label. Defaults to 0.25 lines.}
+
+\item{label.r}{Radius of rounded corners. Defaults to 0.15 lines.}
+
+\item{label.size}{Size of label border, in mm.}
+
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{check_overlap}{If \code{TRUE}, text that overlaps previous text in the
+same layer will not be plotted. A quick and dirty way}
 }
 \description{
-Textual annotations.
+\code{geom_text} adds text directly to the plot. \code{geom_label} draws
+a rectangle underneath the text, making it easier to read.
+}
+\details{
+Note the the "width" and "height" of a text element are 0, so stacking
+and dodging text will not work by default, and axis limits are not
+automatically expanded to include all text. Obviously, labels do have
+height and width, but they are physical units, not data units. The amount of
+space they occupy on that plot is not constant in data units: when you
+resize a plot, labels stay the same size, but the size of the axes changes.
 }
 \section{Aesthetics}{
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "text")}
 }
+
+\section{\code{geom_label}}{
+
+Currently \code{geom_label} does not support the \code{rot} parameter and
+is considerably slower than \code{geom_text}. The \code{fill} aesthetic
+controls the background colour of the label.
+}
+
+\section{Alignment}{
+
+You can modify text alignment with the \code{vjust} and \code{hjust}
+aesthetics. These can either be a number between 0 (right/bottom) and
+1 (top/left) or a character ("left", "middle", "right", "bottom", "center",
+"top"). There are two special alignments: "inward" and "outward".
+Inward always aligns text towards the center, and outward aligns
+it away from the center
+}
 \examples{
-\donttest{
-p <- ggplot(mtcars, aes(x=wt, y=mpg, label=rownames(mtcars)))
+p <- ggplot(mtcars, aes(wt, mpg, label = rownames(mtcars)))
 
 p + geom_text()
+# Avoid overlaps
+p + geom_text(check_overlap = TRUE)
+# Labels with background
+p + geom_label()
 # Change size of the label
-p + geom_text(size=10)
-p <- p + geom_point()
+p + geom_text(size = 10)
 
 # Set aesthetics to fixed value
-p + geom_text()
-p + geom_point() + geom_text(hjust=0, vjust=0)
+p + geom_point() + geom_text(hjust = 0, nudge_x = 0.05)
+p + geom_point() + geom_text(vjust = 0, nudge_y = 0.5)
 p + geom_point() + geom_text(angle = 45)
+\dontrun{
+p + geom_text(family = "Times New Roman")
+}
 
 # Add aesthetic mappings
-p + geom_text(aes(colour=factor(cyl)))
-p + geom_text(aes(colour=factor(cyl))) + scale_colour_discrete(l=40)
+p + geom_text(aes(colour = factor(cyl)))
+p + geom_text(aes(colour = factor(cyl))) +
+  scale_colour_discrete(l = 40)
+p + geom_label(aes(fill = factor(cyl)), colour = "white", fontface = "bold")
 
-p + geom_text(aes(size=wt))
-p + geom_text(aes(size=wt)) + scale_size(range=c(3,6))
+p + geom_text(aes(size = wt))
+# Scale height of text, rather than sqrt(height)
+p + geom_text(aes(size = wt)) + scale_radius(range = c(3,6))
 
 # You can display expressions by setting parse = TRUE.  The
 # details of the display are described in ?plotmath, but note that
@@ -62,23 +138,51 @@ p + geom_text(aes(size=wt)) + scale_size(range=c(3,6))
 p + geom_text(aes(label = paste(wt, "^(", cyl, ")", sep = "")),
   parse = TRUE)
 
-# Add an annotation not from a variable source
-c <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
-c + geom_text(data = NULL, x = 5, y = 30, label = "plot mpg vs. wt")
-# Or, you can use annotate
-c + annotate("text", label = "plot mpg vs. wt", x = 2, y = 15, size = 8, colour = "red")
-
-# Use qplot instead
-qplot(wt, mpg, data = mtcars, label = rownames(mtcars),
-   geom=c("point", "text"))
-qplot(wt, mpg, data = mtcars, label = rownames(mtcars), size = wt) +
-  geom_text(colour = "red")
-
-# You can specify family, fontface and lineheight
-p <- ggplot(mtcars, aes(x=wt, y=mpg, label=rownames(mtcars)))
-p + geom_text(fontface=3)
-p + geom_text(aes(fontface=am+1))
-p + geom_text(aes(family=c("serif", "mono")[am+1]))
+# Add a text annotation
+p +
+  geom_text() +
+  annotate("text", label = "plot mpg vs. wt", x = 2, y = 15, size = 8, colour = "red")
+
+\donttest{
+# Aligning labels and bars --------------------------------------------------
+df <- data.frame(
+  x = factor(c(1, 1, 2, 2)),
+  y = c(1, 3, 2, 1),
+  grp = c("a", "b", "a", "b")
+)
+
+# ggplot2 doesn't know you want to give the labels the same virtual width
+# as the bars:
+ggplot(data = df, aes(x, y, fill = grp, label = y)) +
+  geom_bar(stat = "identity", position = "dodge") +
+  geom_text(position = "dodge")
+# So tell it:
+ggplot(data = df, aes(x, y, fill = grp, label = y)) +
+  geom_bar(stat = "identity", position = "dodge") +
+  geom_text(position = position_dodge(0.9))
+# Use you can't nudge and dodge text, so instead adjust the y postion
+ggplot(data = df, aes(x, y, fill = grp, label = y)) +
+  geom_bar(stat = "identity", position = "dodge") +
+  geom_text(aes(y = y + 0.05), position = position_dodge(0.9), vjust = 0)
+
+# To place text in the middle of each bar in a stacked barplot, you
+# need to do the computation yourself
+df <- transform(df, mid_y = ave(df$y, df$x, FUN = function(val) cumsum(val) - (0.5 * val)))
+
+ggplot(data = df, aes(x, y, fill = grp, label = y)) +
+ geom_bar(stat = "identity") +
+ geom_text(aes(y = mid_y))
+
+# Justification -------------------------------------------------------------
+df <- data.frame(
+  x = c(1, 1, 2, 2, 1.5),
+  y = c(1, 2, 1, 2, 1.5),
+  text = c("bottom-left", "bottom-right", "top-left", "top-right", "center")
+)
+ggplot(df, aes(x, y)) +
+  geom_text(aes(label = text))
+ggplot(df, aes(x, y)) +
+  geom_text(aes(label = text), vjust = "inward", hjust = "inward")
 }
 }
 
diff --git a/man/geom_tile.Rd b/man/geom_tile.Rd
index 0fc8c69..b8c8eca 100644
--- a/man/geom_tile.Rd
+++ b/man/geom_tile.Rd
@@ -1,97 +1,123 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-tile.r
-\name{geom_tile}
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-raster.r, R/geom-rect.r, R/geom-tile.r
+\name{geom_raster}
+\alias{geom_raster}
+\alias{geom_rect}
 \alias{geom_tile}
-\title{Tile plane with rectangles.}
+\title{Draw rectangles.}
 \usage{
+geom_raster(mapping = NULL, data = NULL, stat = "identity",
+  position = "identity", hjust = 0.5, vjust = 0.5, interpolate = FALSE,
+  na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...)
+
+geom_rect(mapping = NULL, data = NULL, stat = "identity",
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+
 geom_tile(mapping = NULL, data = NULL, stat = "identity",
-  position = "identity", ...)
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
 \item{stat}{The statistical transformation to use on the data for this
-layer.}
+layer, as a string.}
+
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
+
+\item{hjust, vjust}{horizontal and vertical justification of the grob.  Each
+justification value should be a number between 0 and 1.  Defaults to 0.5
+for both, centering each pixel over its data location.}
+
+\item{interpolate}{If \code{TRUE} interpolate linearly, if \code{FALSE}
+(the default) don't interpolate.}
+
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
 }
 \description{
-Similar to \code{\link{levelplot}} and \code{\link{image}}.
+\code{geom_rect} and \code{geom_tile} do the same thing, but are
+parameterised differently. \code{geom_rect} uses the locations of the four
+corners (\code{xmin}, \code{xmax}, \code{ymin} and \code{ymax}).
+\code{geom_tile} uses the center of the tile and its size (\code{x},
+\code{y}, \code{width}, \code{height}). \code{geom_raster} is a high
+performance special case for when all the tiles are the same size.
 }
 \section{Aesthetics}{
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "tile")}
 }
 \examples{
-\donttest{
-# Generate data
-pp <- function (n,r=4) {
- x <- seq(-r*pi, r*pi, len=n)
- df <- expand.grid(x=x, y=x)
- df$r <- sqrt(df$x^2 + df$y^2)
- df$z <- cos(df$r^2)*exp(-df$r/6)
- df
-}
-p <- ggplot(pp(20), aes(x=x,y=y))
-
-p + geom_tile() #pretty useless!
-
-# Add aesthetic mappings
-p + geom_tile(aes(fill=z))
-
-# Change scale
-p + geom_tile(aes(fill=z)) + scale_fill_gradient(low="green", high="red")
-
-# Use qplot instead
-qplot(x, y, data=pp(20), geom="tile", fill=z)
-qplot(x, y, data=pp(100), geom="tile", fill=z)
-
-# Missing values
-p <- ggplot(pp(20)[sample(20*20, size=200),], aes(x=x,y=y,fill=z))
-p + geom_tile()
-
-# Input that works with image
-image(t(volcano)[ncol(volcano):1,])
-library(reshape2) # for melt
-ggplot(melt(volcano), aes(x=Var1, y=Var2, fill=value)) + geom_tile()
-
-# inspired by the image-density plots of Ken Knoblauch
-cars <- ggplot(mtcars, aes(y=factor(cyl), x=mpg))
-cars + geom_point()
-cars + stat_bin(aes(fill=..count..), geom="tile", binwidth=3, position="identity")
-cars + stat_bin(aes(fill=..density..), geom="tile", binwidth=3, position="identity")
-
-cars + stat_density(aes(fill=..density..), geom="tile", position="identity")
-cars + stat_density(aes(fill=..count..), geom="tile", position="identity")
-
-# Another example with with unequal tile sizes
-x.cell.boundary <- c(0, 4, 6, 8, 10, 14)
-example <- data.frame(
+# The most common use for rectangles is to draw a surface. You always want
+# to use geom_raster here because it's so much faster, and produces
+# smaller output when saving to PDF
+ggplot(faithfuld, aes(waiting, eruptions)) +
+ geom_raster(aes(fill = density))
+
+# Interpolation smooths the surface & is most helpful when rendering images.
+ggplot(faithfuld, aes(waiting, eruptions)) +
+ geom_raster(aes(fill = density), interpolate = TRUE)
+
+# If you want to draw arbitrary rectangles, use geom_tile() or geom_rect()
+df <- data.frame(
   x = rep(c(2, 5, 7, 9, 12), 2),
-  y = factor(rep(c(1,2), each=5)),
-  z = rep(1:5, each=2),
-  w = rep(diff(x.cell.boundary), 2)
+  y = rep(c(1, 2), each = 5),
+  z = factor(rep(1:5, each = 2)),
+  w = rep(diff(c(0, 4, 6, 8, 10, 14)), 2)
 )
+ggplot(df, aes(x, y)) +
+  geom_tile(aes(fill = z))
+ggplot(df, aes(x, y)) +
+  geom_tile(aes(fill = z, width = w), colour = "grey50")
+ggplot(df, aes(xmin = x - w / 2, xmax = x + w / 2, ymin = y, ymax = y + 1)) +
+  geom_rect(aes(fill = z, width = w), colour = "grey50")
 
-qplot(x, y, fill=z, data=example, geom="tile")
-qplot(x, y, fill=z, data=example, geom="tile", width=w)
-qplot(x, y, fill=factor(z), data=example, geom="tile", width=w)
+\donttest{
+# Justification controls where the cells are anchored
+df <- expand.grid(x = 0:5, y = 0:5)
+df$z <- runif(nrow(df))
+# default is compatible with geom_tile()
+ggplot(df, aes(x, y, fill = z)) + geom_raster()
+# zero padding
+ggplot(df, aes(x, y, fill = z)) + geom_raster(hjust = 0, vjust = 0)
+
+# Inspired by the image-density plots of Ken Knoblauch
+cars <- ggplot(mtcars, aes(mpg, factor(cyl)))
+cars + geom_point()
+cars + stat_bin2d(aes(fill = ..count..), binwidth = c(3,1))
+cars + stat_bin2d(aes(fill = ..density..), binwidth = c(3,1))
 
-# You can manually set the colour of the tiles using
-# scale_manual
-col <- c("darkblue", "blue", "green", "orange", "red")
-qplot(x, y, fill=col[z], data=example, geom="tile", width=w, group=1) +
-  scale_fill_identity(labels=letters[1:5], breaks=col)
+cars + stat_density(aes(fill = ..density..), geom = "raster", position = "identity")
+cars + stat_density(aes(fill = ..count..), geom = "raster", position = "identity")
 }
 }
 
diff --git a/man/geom_violin.Rd b/man/geom_violin.Rd
index 348e4cc..00b6a74 100644
--- a/man/geom_violin.Rd
+++ b/man/geom_violin.Rd
@@ -1,25 +1,35 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-violin.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-violin.r, R/stat-ydensity.r
 \name{geom_violin}
 \alias{geom_violin}
+\alias{stat_ydensity}
 \title{Violin plot.}
 \usage{
 geom_violin(mapping = NULL, data = NULL, stat = "ydensity",
-  position = "dodge", trim = TRUE, scale = "area", ...)
+  draw_quantiles = NULL, position = "dodge", trim = TRUE,
+  scale = "area", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE,
+  ...)
+
+stat_ydensity(mapping = NULL, data = NULL, geom = "violin",
+  position = "dodge", adjust = 1, kernel = "gaussian", trim = TRUE,
+  scale = "area", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE,
+  ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
 
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
+\item{draw_quantiles}{If \code{not(NULL)} (default), draw horizontal lines
+at the given quantiles of the density estimate.}
 
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
 \item{trim}{If \code{TRUE} (default), trim the tails of the violins
 to the range of the data. If \code{FALSE}, don't trim the tails.}
@@ -28,9 +38,36 @@ to the range of the data. If \code{FALSE}, don't trim the tails.}
 the tails). If "count", areas are scaled proportionally to the number of
 observations. If "width", all violins have the same maximum width.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
+
+\item{geom, stat}{Use to override the default connection between
+\code{geom_violin} and \code{stat_ydensity}.}
+
+\item{adjust}{see \code{\link{density}} for details}
+
+\item{kernel}{kernel used for density estimation, see
+\code{\link{density}} for details}
 }
 \description{
 Violin plot.
@@ -39,17 +76,26 @@ Violin plot.
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "violin")}
 }
+
+\section{Computed variables}{
+
+\describe{
+  \item{density}{density estimate}
+  \item{scaled}{density estimate, scaled to maximum of 1}
+  \item{count}{density * number of points - probably useless for violin plots}
+  \item{violinwidth}{density scaled for the violin plot, according to area, counts
+                     or to a constant maximum width}
+  \item{n}{number of points}
+  \item{width}{width of violin bounding box}
+}
+}
 \examples{
-\donttest{
 p <- ggplot(mtcars, aes(factor(cyl), mpg))
-
 p + geom_violin()
-qplot(factor(cyl), mpg, data = mtcars, geom = "violin")
 
+\donttest{
 p + geom_violin() + geom_jitter(height = 0)
 p + geom_violin() + coord_flip()
-qplot(factor(cyl), mpg, data = mtcars, geom = "violin") +
-  coord_flip()
 
 # Scale maximum width proportional to sample size:
 p + geom_violin(scale = "count")
@@ -73,16 +119,16 @@ p + geom_violin(aes(fill = factor(am)))
 
 # Set aesthetics to fixed value
 p + geom_violin(fill = "grey80", colour = "#3366FF")
-qplot(factor(cyl), mpg, data = mtcars, geom = "violin",
-  colour = I("#3366FF"))
+
+# Show quartiles
+p + geom_violin(draw_quantiles = c(0.25, 0.5, 0.75))
 
 # Scales vs. coordinate transforms -------
+if (require("ggplot2movies")) {
 # Scale transformations occur before the density statistics are computed.
 # Coordinate transformations occur afterwards.  Observe the effect on the
 # number of outliers.
-library(plyr) # to access round_any
-m <- ggplot(movies, aes(y = votes, x = rating,
-   group = round_any(rating, 0.5)))
+m <- ggplot(movies, aes(y = votes, x = rating, group = cut_width(rating, 0.5)))
 m + geom_violin()
 m + geom_violin() + scale_y_log10()
 m + geom_violin() + coord_trans(y = "log10")
@@ -90,9 +136,18 @@ m + geom_violin() + scale_y_log10() + coord_trans(y = "log10")
 
 # Violin plots with continuous x:
 # Use the group aesthetic to group observations in violins
-qplot(year, budget, data = movies, geom = "violin")
-qplot(year, budget, data = movies, geom = "violin",
-  group = round_any(year, 10, floor))
+ggplot(movies, aes(year, budget)) + geom_violin()
+ggplot(movies, aes(year, budget)) +
+  geom_violin(aes(group = cut_width(year, 10)), scale = "width")
+}
+}
+}
+\references{
+Hintze, J. L., Nelson, R. D. (1998) Violin Plots: A Box
+Plot-Density Trace Synergism. The American Statistician 52, 181-184.
 }
+\seealso{
+\code{\link{geom_violin}} for examples, and \code{\link{stat_density}}
+  for examples with data along the x axis.
 }
 
diff --git a/man/geom_vline.Rd b/man/geom_vline.Rd
deleted file mode 100644
index 0886680..0000000
--- a/man/geom_vline.Rd
+++ /dev/null
@@ -1,73 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/geom-vline.r
-\name{geom_vline}
-\alias{geom_vline}
-\title{Line, vertical.}
-\usage{
-geom_vline(mapping = NULL, data = NULL, stat = "vline",
-  position = "identity", show_guide = FALSE, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{stat}{The statistical transformation to use on the data for this
-layer.}
-
-\item{position}{The position adjustment to use for overlapping points
-on this layer}
-
-\item{show_guide}{should a legend be drawn? (defaults to \code{FALSE})}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-This geom allows you to annotate the plot with vertical lines (see
-\code{\link{geom_hline}} and \code{\link{geom_abline}} for other types of
-lines.
-}
-\details{
-There are two ways to use it.  You can either specify the intercept of the
-line in the call to the geom, in which case the line will be in the same
-position in every panel.  Alternatively, you can supply a different
-intercept for each panel using a data.frame.  See the examples for the
-differences.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("geom", "vline")}
-}
-\examples{
-# Fixed lines
-p <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point()
-p + geom_vline(xintercept = 5)
-p + geom_vline(xintercept = 1:5)
-p + geom_vline(xintercept = 1:5, colour="green", linetype = "longdash")
-p + geom_vline(aes(xintercept = wt))
-
-# With coordinate transforms
-p + geom_vline(aes(xintercept = wt)) + coord_equal()
-p + geom_vline(aes(xintercept = wt)) + coord_flip()
-p + geom_vline(aes(xintercept = wt)) + coord_polar()
-
-p2 <- p + aes(colour = factor(cyl))
-p2 + geom_vline(xintercept = 15)
-
-# To display different lines in different facets, you need to
-# create a data frame.
-p <- qplot(mpg, wt, data=mtcars, facets = vs ~ am)
-vline.data <- data.frame(z = c(15, 20, 25, 30), vs = c(0, 0, 1, 1), am = c(0, 1, 0, 1))
-p + geom_vline(aes(xintercept = z), vline.data)
-}
-\seealso{
-\code{\link{geom_hline}} for horizontal lines,
- \code{\link{geom_abline}} for lines defined by a slope and intercept,
- \code{\link{geom_segment}} for a more general approach"
-}
-
diff --git a/man/gg-add.Rd b/man/gg-add.Rd
index ee5e9e4..f7e990a 100644
--- a/man/gg-add.Rd
+++ b/man/gg-add.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/plot-construction.r, R/theme.r
 \name{+.gg}
 \alias{+.gg}
@@ -42,17 +42,22 @@ another theme object. This will return a modified theme object.
 For theme objects, the \code{+} operator and the \code{\%+replace\%}
 can be used to modify elements in themes.
 
-The \code{+} operator completely replaces elements
-with elements from e2.
+The \code{+} operator updates the elements of e1 that differ from
+elements specified (not NULL) in e2.
+Thus this operator can be used to incrementally add or modify attributes
+of a ggplot theme.
 
-In contrast, the \code{\%+replace\%} operator does not replace the
-entire element; it only updates element properties which are present
-(not NULL) in the second object.
+In contrast, the \code{\%+replace\%} operator replaces the
+entire element; any element of a theme not specified in e2 will not be
+present in the resulting theme (i.e. NULL).
+Thus this operator can be used to overwrite an entire theme.
 }
 \examples{
 ### Adding objects to a ggplot object
-p <- qplot(wt, mpg, colour = hp, data = mtcars)
+p <- ggplot(mtcars, aes(wt, mpg, colour = disp)) +
+  geom_point()
 
+p
 p + coord_cartesian(ylim = c(0, 40))
 p + scale_colour_continuous(breaks = c(100, 300))
 p + guides(colour = "colourbar")
@@ -61,7 +66,6 @@ p + guides(colour = "colourbar")
 m <- mtcars[1:10, ]
 p \%+\% m
 
-
 ### Adding objects to a theme object
 # Compare these results of adding theme objects to other theme objects
 add_el <- theme_grey() + theme(text = element_text(family = "Times"))
@@ -69,6 +73,7 @@ rep_el <- theme_grey() \%+replace\% theme(text = element_text(family = "Times"))
 
 add_el$text
 rep_el$text
+
 }
 \seealso{
 \code{\link{theme}}
diff --git a/man/gg_dep.Rd b/man/gg_dep.Rd
index 5995709..d79206f 100644
--- a/man/gg_dep.Rd
+++ b/man/gg_dep.Rd
@@ -1,8 +1,8 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/utilities.r
 \name{gg_dep}
 \alias{gg_dep}
-\title{Give a deprecation error, warning, or messsage, depending on version number.}
+\title{Give a deprecation error, warning, or message, depending on version number.}
 \usage{
 gg_dep(version, msg)
 }
diff --git a/man/ggplot.Rd b/man/ggplot.Rd
index 9376545..a6554ea 100644
--- a/man/ggplot.Rd
+++ b/man/ggplot.Rd
@@ -1,15 +1,26 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/plot.r
 \name{ggplot}
 \alias{ggplot}
-\title{Create a new ggplot plot}
+\alias{ggplot.data.frame}
+\alias{ggplot.default}
+\title{Create a new ggplot plot.}
 \usage{
-ggplot(data = NULL, ...)
+ggplot(data = NULL, mapping = aes(), ..., environment = parent.frame())
 }
 \arguments{
-\item{data}{default data set}
+\item{data}{Default dataset to use for plot. If not already a data.frame,
+will be converted to one by \code{\link{fortify}}. If not specified,
+must be suppled in each layer added to the plot.}
 
-\item{...}{other arguments passed to specific methods}
+\item{mapping}{Default list of aesthetic mappings to use for plot.
+If not specified, must be suppled in each layer added to the plot.}
+
+\item{...}{Other arguments passed on to methods. Not currently used.}
+
+\item{environment}{If an variable defined in the aesthetic mapping is not
+found in the data, ggplot will look for it in this environment. It defaults
+to using the environment in which \code{ggplot()} is called.}
 }
 \description{
 \code{ggplot()} initializes a ggplot object. It can be used to
@@ -43,17 +54,12 @@ third method initializes a skeleton \code{ggplot} object which
 is fleshed out as layers are added. This method is useful when
 multiple data frames are used to produce different layers, as
 is often the case in complex graphics.
-
-The examples below illustrate how these methods of
-invoking \code{ggplot} can be used in constructing a
-graphic.
 }
 \examples{
 df <- data.frame(gp = factor(rep(letters[1:3], each = 10)),
                  y = rnorm(30))
 # Compute sample mean and standard deviation in each group
-library(plyr)
-ds <- ddply(df, .(gp), summarise, mean = mean(y), sd = sd(y))
+ds <- plyr::ddply(df, "gp", plyr::summarise, mean = mean(y), sd = sd(y))
 
 # Declare the data frame and common aesthetics.
 # The summary data frame ds is used to plot
@@ -80,8 +86,4 @@ ggplot() +
                     ymin = mean - sd, ymax = mean + sd),
                     colour = 'red', width = 0.4)
 }
-\seealso{
-\url{http://had.co.nz/ggplot2}
-}
-\keyword{internal}
 
diff --git a/man/ggplot.data.frame.Rd b/man/ggplot.data.frame.Rd
deleted file mode 100644
index 1e204d6..0000000
--- a/man/ggplot.data.frame.Rd
+++ /dev/null
@@ -1,26 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/plot.r
-\name{ggplot.data.frame}
-\alias{ggplot.data.frame}
-\title{Create a new ggplot plot from a data frame}
-\usage{
-\method{ggplot}{data.frame}(data, mapping = aes(), ...,
-  environment = globalenv())
-}
-\arguments{
-\item{data}{default data frame for plot}
-
-\item{mapping}{default list of aesthetic mappings (these can be colour,
-size, shape, line type -- see individual geom functions for more details)}
-
-\item{...}{ignored}
-
-\item{environment}{in which evaluation of aesthetics should occur}
-}
-\description{
-Create a new ggplot plot from a data frame
-}
-\seealso{
-\url{http://had.co.nz/ggplot2}
-}
-
diff --git a/man/ggplot2-ggproto.Rd b/man/ggplot2-ggproto.Rd
new file mode 100644
index 0000000..8fb1e01
--- /dev/null
+++ b/man/ggplot2-ggproto.Rd
@@ -0,0 +1,290 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/aaa-.r, R/geom-.r, R/annotation-custom.r, R/annotation-logticks.r, R/geom-polygon.r, R/geom-map.r, R/annotation-map.r, R/geom-raster.r, R/annotation-raster.r, R/coord-.r, R/coord-cartesian-.r, R/coord-fixed.r, R/coord-flip.r, R/coord-map.r, R/coord-polar.r, R/coord-quickmap.R, R/coord-transform.r, R/stat-.r, R/geom-abline.r, R/geom-rect.r, R/geom-bar.r, R/geom-blank.r, R/geom-boxplot.r, R/geom-path.r, R/geom-contour.r, R/geom-crossbar.r, R/geom-segment.r, [...]
+\docType{data}
+\name{ggplot2-ggproto}
+\alias{Coord}
+\alias{CoordCartesian}
+\alias{CoordFixed}
+\alias{CoordFlip}
+\alias{CoordMap}
+\alias{CoordPolar}
+\alias{CoordQuickmap}
+\alias{CoordTrans}
+\alias{Geom}
+\alias{GeomAbline}
+\alias{GeomAnnotationMap}
+\alias{GeomArea}
+\alias{GeomBar}
+\alias{GeomBlank}
+\alias{GeomBoxplot}
+\alias{GeomContour}
+\alias{GeomCrossbar}
+\alias{GeomCurve}
+\alias{GeomCustomAnn}
+\alias{GeomDensity}
+\alias{GeomDensity2d}
+\alias{GeomDotplot}
+\alias{GeomErrorbar}
+\alias{GeomErrorbarh}
+\alias{GeomHex}
+\alias{GeomHline}
+\alias{GeomLabel}
+\alias{GeomLine}
+\alias{GeomLinerange}
+\alias{GeomLogticks}
+\alias{GeomMap}
+\alias{GeomPath}
+\alias{GeomPoint}
+\alias{GeomPointrange}
+\alias{GeomPolygon}
+\alias{GeomQuantile}
+\alias{GeomRaster}
+\alias{GeomRasterAnn}
+\alias{GeomRect}
+\alias{GeomRibbon}
+\alias{GeomRug}
+\alias{GeomSegment}
+\alias{GeomSmooth}
+\alias{GeomSpoke}
+\alias{GeomStep}
+\alias{GeomText}
+\alias{GeomTile}
+\alias{GeomViolin}
+\alias{GeomVline}
+\alias{Position}
+\alias{PositionDodge}
+\alias{PositionFill}
+\alias{PositionIdentity}
+\alias{PositionJitter}
+\alias{PositionJitterdodge}
+\alias{PositionNudge}
+\alias{PositionStack}
+\alias{Scale}
+\alias{ScaleContinuous}
+\alias{ScaleContinuousDate}
+\alias{ScaleContinuousDatetime}
+\alias{ScaleContinuousIdentity}
+\alias{ScaleContinuousPosition}
+\alias{ScaleDiscrete}
+\alias{ScaleDiscreteIdentity}
+\alias{ScaleDiscretePosition}
+\alias{Stat}
+\alias{StatBin}
+\alias{StatBin2d}
+\alias{StatBindot}
+\alias{StatBinhex}
+\alias{StatBoxplot}
+\alias{StatContour}
+\alias{StatCount}
+\alias{StatDensity}
+\alias{StatDensity2d}
+\alias{StatEcdf}
+\alias{StatEllipse}
+\alias{StatFunction}
+\alias{StatIdentity}
+\alias{StatQq}
+\alias{StatQuantile}
+\alias{StatSmooth}
+\alias{StatSum}
+\alias{StatSummary}
+\alias{StatSummary2d}
+\alias{StatSummaryBin}
+\alias{StatSummaryHex}
+\alias{StatUnique}
+\alias{StatYdensity}
+\alias{ggplot2-ggproto}
+\title{Base ggproto classes for ggplot2}
+\description{
+If you are creating a new geom, stat, position, or scale in another package,
+you'll need to extend from \code{ggplot2::Geom}, \code{ggplot2::Stat},
+\code{ggplot2::Position}, or \code{ggplot2::Scale}.
+}
+\section{Geoms}{
+
+
+All \code{geom_*} functions (like \code{geom_point}) return a layer that
+contains a \code{Geom*} object (like \code{GeomPoint}). The \code{Geom*}
+object is responsible for rendering the data in the plot.
+
+Each of the \code{Geom*} objects is a \code{\link{ggproto}} object, descended
+from the top-level \code{Geom}, and each implements various methods and
+fields. To create a new type of Geom object, you typically will want to
+implement one or more of the following:
+
+Compared to \code{Stat} and \code{Position}, \code{Geom} is a little
+different because the execution of the setup and compute functions is
+split up. \code{setup_data} runs before position adjustments, and
+\code{draw_layer} is not run until render time,  much later. This
+means there is no \code{setup_params} because it's hard to communicate
+the changes.
+
+\itemize{
+  \item Override either \code{draw_panel(self, data, panel_scales, coord)} or
+    \code{draw_group(self, data, panel_scales, coord)}. \code{draw_panel} is
+    called once per panel, \code{draw_group} is called once per group.
+
+    Use \code{draw_panel} if each row in the data represents a
+    single element. Use \code{draw_group} if each group represents
+    an element (e.g. a smooth, a violin).
+
+    \code{data} is a data frame of scaled aesthetics. \code{panel_scales}
+    is a list containing information about the scales in the current
+    panel. \code{coord} is a coordinate specification. You'll
+    need to call \code{coord$transform(data, panel_scales)} to work
+    with non-Cartesian coords. To work with non-linear coordinate systems,
+    you typically need to convert into a primitive geom (e.g. point, path
+    or polygon), and then pass on to the corresponding draw method
+    for munching.
+
+    Must return a grob. Use \code{\link{zeroGrob}} if there's nothing to
+    draw.
+  \item \code{draw_key}: Renders a single legend key.
+  \item \code{required_aes}: A character vector of aesthetics needed to
+    render the geom.
+  \item \code{default_aes}: A list (generated by \code{\link{aes}()} of
+    default values for aesthetics.
+  \item \code{reparameterise}: Converts width and height to xmin and xmax,
+    and ymin and ymax values. It can potentially set other values as well.
+}
+}
+
+\section{Coordinate systems}{
+
+
+All \code{coord_*} functions (like \code{coord_trans}) return a \code{Coord*}
+object (like \code{CoordTrans}). The \code{Coord*} object is responsible for
+adjusting the position of overlapping geoms.
+
+The way that the \code{coord_*} functions work is slightly different from the
+\code{geom_*} and \code{stat_*} functions, because a \code{coord_*} function
+actually "instantiates" the \code{Coord*} object by creating a descendant,
+and returns that.
+
+Each of the \code{Coord*} objects is a \code{\link{ggproto}} object,
+descended from the top-level \code{Coord}.  To create a new type of Coord
+object, you typically will want to implement one or more of the following:
+
+\itemize{
+  \item \code{aspect}: Returns the desired aspect ratio for the plot.
+  \item \code{labels}: Returns a list containing labels for x and y.
+  \item \code{render_fg}: Renders foreground elements.
+  \item \code{render_bg}: Renders background elements.
+  \item \code{render_axis_h}: Renders the horizontal axis.
+  \item \code{render_axis_v}: Renders the vertical axis.
+  \item \code{range}: Returns the x and y ranges
+  \item \code{train}: Return the trained scale ranges.
+  \item \code{transform}: Transforms x and y coordinates.
+  \item \code{distance}: Calculates distance.
+  \item \code{is_linear}: Returns \code{TRUE} if the coordinate system is
+    linear; \code{FALSE} otherwise.
+}
+}
+
+\section{Stats}{
+
+
+All \code{stat_*} functions (like \code{stat_bin}) return a layer that
+contains a \code{Stat*} object (like \code{StatBin}). The \code{Stat*}
+object is responsible for rendering the data in the plot.
+
+Each of the \code{Stat*} objects is a \code{\link{ggproto}} object, descended
+from the top-level \code{Stat}, and each implements various methods and
+fields. To create a new type of Stat object, you typically will want to
+implement one or more of the following:
+
+\itemize{
+  \item Override one of :
+    \code{compute_layer(self, data, scales, ...)},
+    \code{compute_panel(self, data, scales, ...)}, or
+    \code{compute_group(self, data, scales, ...)}.
+
+    \code{compute_layer()} is called once per layer, \code{compute_panel_()}
+    is called once per panel, and \code{compute_group()} is called once per
+    group. All must return a data frame.
+
+    It's usually best to start by overriding \code{compute_group}: if
+    you find substantial performance optimisations, override higher up.
+    You'll need to read the source code of the default methods to see
+    what else you should be doing.
+
+    \code{data} is a data frame containing the variables named according
+    to the aesthetics that they're mapped to. \code{scales} is a list
+    containing the \code{x} and \code{y} scales. There functions are called
+    before the facets are trained, so they are global scales, not local
+    to the individual panels.\code{...} contains the parameters returned by
+    \code{setup_params()}.
+  \item \code{setup_params(data, params)}: called once for each layer.
+     Used to setup defaults that need to complete dataset, and to inform
+     the user of important choices. Should return list of parameters.
+  \item \code{setup_data(data, params)}: called once for each layer,
+     after \code{setp_params()}. Should return modified \code{data}.
+     Default methods removes all rows containing a missing value in
+     required aesthetics (with a warning if \code{!na.rm}).
+  \item \code{required_aes}: A character vector of aesthetics needed to
+    render the geom.
+  \item \code{default_aes}: A list (generated by \code{\link{aes}()} of
+    default values for aesthetics.
+}
+}
+
+\section{Positions}{
+
+
+All \code{position_*} functions (like \code{position_dodge}) return a
+\code{Position*} object (like \code{PositionDodge}). The \code{Position*}
+object is responsible for adjusting the position of overlapping geoms.
+
+The way that the \code{position_*} functions work is slightly different from
+the \code{geom_*} and \code{stat_*} functions, because a \code{position_*}
+function actually "instantiates" the \code{Position*} object by creating a
+descendant, and returns that.
+
+Each of the \code{Position*} objects is a \code{\link{ggproto}} object,
+descended from the top-level \code{Position}, and each implements the
+following methods:
+
+\itemize{
+  \item \code{compute_layer(self, data, params, panel)} is called once
+    per layer. \code{panel} is currently an internal data structure, so
+    this method should not be overriden.
+
+  \item \code{compute_panel(self, data, params, panel)} is called once per
+    panel and should return a modified data frame.
+
+    \code{data} is a data frame containing the variables named according
+    to the aesthetics that they're mapped to. \code{scales} is a list
+    containing the \code{x} and \code{y} scales. There functions are called
+    before the facets are trained, so they are global scales, not local
+    to the individual panels. \code{params} contains the parameters returned by
+    \code{setup_params()}.
+  \item \code{setup_params(data, params)}: called once for each layer.
+     Used to setup defaults that need to complete dataset, and to inform
+     the user of important choices. Should return list of parameters.
+  \item \code{setup_data(data, params)}: called once for each layer,
+     after \code{setp_params()}. Should return modified \code{data}.
+     Default checks that required aesthetics are present.
+}
+
+And the following fields
+\itemize{
+  \item \code{required_aes}: a character vector giving the aesthetics
+     that must be present for this position adjustment to work.
+}
+}
+
+\section{Scales}{
+
+
+All \code{scale_*} functions (like \code{scale_x_continuous}) return a
+\code{Scale*} object (like \code{ScaleContinuous}). The \code{Scale*}
+object represents a single scale.
+
+Each of the \code{Scale*} objects is a \code{\link{ggproto}} object,
+descended from the top-level \code{Scale}.
+}
+\seealso{
+ggproto
+}
+\keyword{datasets}
+\keyword{internal}
+
diff --git a/man/ggplot2.Rd b/man/ggplot2.Rd
deleted file mode 100644
index 50fc38e..0000000
--- a/man/ggplot2.Rd
+++ /dev/null
@@ -1,11 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/ggplot2.r
-\docType{package}
-\name{ggplot2}
-\alias{ggplot2}
-\alias{ggplot2-package}
-\title{ggplot2.}
-\description{
-ggplot2.
-}
-
diff --git a/man/ggplotGrob.Rd b/man/ggplotGrob.Rd
index 78e2c68..f97e4da 100644
--- a/man/ggplotGrob.Rd
+++ b/man/ggplotGrob.Rd
@@ -1,5 +1,5 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/plot-render.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/plot-build.r
 \name{ggplotGrob}
 \alias{ggplotGrob}
 \title{Generate a ggplot2 plot grob.}
diff --git a/man/ggplot_build.Rd b/man/ggplot_build.Rd
index ff95d3b..0d6f3a6 100644
--- a/man/ggplot_build.Rd
+++ b/man/ggplot_build.Rd
@@ -1,23 +1,37 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/plot-build.r
 \name{ggplot_build}
 \alias{ggplot_build}
+\alias{layer_data}
+\alias{layer_grob}
+\alias{layer_scales}
 \title{Build ggplot for rendering.}
 \usage{
 ggplot_build(plot)
+
+layer_data(plot, i = 1L)
+
+layer_scales(plot, i = 1L, j = 1L)
+
+layer_grob(plot, i = 1L)
 }
 \arguments{
 \item{plot}{ggplot object}
 }
 \description{
-This function takes the plot object, and performs all steps necessary to
-produce an object that can be rendered.  This function outputs two pieces:
+\code{ggplot_build} takes the plot object, and performs all steps necessary
+to produce an object that can be rendered.  This function outputs two pieces:
 a list of data frames (one for each layer), and a panel object, which
 contain all information about axis limits, breaks etc.
 }
+\details{
+\code{layer_data}, \code{layer_grob}, and \code{layer_scales} are helper
+functions that returns the data, grob, or scales associated with a given
+layer. These are useful for tests.
+}
 \seealso{
-\code{\link{print.ggplot}} and \code{link{benchplot}} for
- for functions that contain the complete set of steps for generating
+\code{\link{print.ggplot}} and \code{\link{benchplot}} for
+ functions that contain the complete set of steps for generating
  a ggplot2 plot.
 }
 \keyword{internal}
diff --git a/man/ggplot_gtable.Rd b/man/ggplot_gtable.Rd
index 309aabd..6248f3a 100644
--- a/man/ggplot_gtable.Rd
+++ b/man/ggplot_gtable.Rd
@@ -1,5 +1,5 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/plot-render.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/plot-build.r
 \name{ggplot_gtable}
 \alias{ggplot_gtable}
 \title{Build a plot with all the usual bits and pieces.}
diff --git a/man/ggproto.Rd b/man/ggproto.Rd
new file mode 100644
index 0000000..a1c8cf8
--- /dev/null
+++ b/man/ggproto.Rd
@@ -0,0 +1,49 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/ggproto.r
+\name{ggproto}
+\alias{ggproto}
+\alias{ggproto_parent}
+\title{Create a new ggproto object}
+\usage{
+ggproto(`_class` = NULL, `_inherit` = NULL, ...)
+
+ggproto_parent(parent, self)
+}
+\arguments{
+\item{_class}{Class name to assign to the object. This is stored as the class
+attribute of the object. If \code{NULL} (the default), no class name will
+be added to the object.}
+
+\item{_inherit}{ggproto object to inherit from. If \code{NULL}, don't inherit
+from any object.}
+
+\item{...}{A list of members in the ggproto object.}
+
+\item{parent, self}{Access parent class \code{parent} of object \code{self}.}
+}
+\description{
+ggproto is inspired by the proto package, but it has some important
+differences. Notably, it cleanly supports cross-package inheritance, and has
+faster performance.
+}
+\section{Calling ggproto methods}{
+
+
+ggproto methods can take an optional \code{self} argument: if it is present,
+it is a regular method; if it's absent, it's a "static" method (i.e. it
+doesn't use any fields).
+
+Imagine you have a ggproto object \code{Adder}, which has a
+method \code{addx = function(self, n) n + self$x}. Then, to call this
+function, you would use \code{Adder$addx(10)} -- the \code{self} is passed
+in automatically by the wrapper function. \code{self} be located anywhere
+in the function signature, although customarily it comes first.
+}
+
+\section{Calling methods in a parent}{
+
+
+To explicitly call a methods in a parent, use
+\code{ggproto_parent(Parent, self)}.
+}
+
diff --git a/man/ggsave.Rd b/man/ggsave.Rd
index 93b379c..d2ea2ff 100644
--- a/man/ggsave.Rd
+++ b/man/ggsave.Rd
@@ -1,61 +1,65 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/save.r
 \name{ggsave}
 \alias{ggsave}
-\title{Save a ggplot with sensible defaults}
+\title{Save a ggplot (or other grid object) with sensible defaults}
 \usage{
-ggsave(filename = default_name(plot), plot = last_plot(),
-  device = default_device(filename), path = NULL, scale = 1,
-  width = par("din")[1], height = par("din")[2], units = c("in", "cm",
-  "mm"), dpi = 300, limitsize = TRUE, ...)
+ggsave(filename, plot = last_plot(), device = NULL, path = NULL,
+  scale = 1, width = NA, height = NA, units = c("in", "cm", "mm"),
+  dpi = 300, limitsize = TRUE, ...)
 }
 \arguments{
-\item{filename}{file name/filename of plot}
+\item{filename}{File name to create on disk.}
 
-\item{plot}{plot to save, defaults to last plot displayed}
+\item{plot}{Plot to save, defaults to last plot displayed.}
 
-\item{device}{device to use, automatically extract from file name extension}
+\item{device}{Device to use (function or any of the recognized extensions,
+e.g. \code{"pdf"}). By default, extracted from filename extension.
+\code{ggsave} currently recognises eps/ps, tex (pictex), pdf, jpeg, tiff,
+png, bmp, svg and wmf (windows only).}
 
-\item{path}{path to save plot to (if you just want to set path and not
-filename)}
+\item{path}{Path to save plot to (combined with filename).}
 
-\item{scale}{scaling factor}
+\item{scale}{Multiplicative scaling factor.}
 
-\item{width}{width (defaults to the width of current plotting window)}
+\item{width, height}{Plot dimensions, defaults to size of current graphics
+device.}
 
-\item{height}{height (defaults to the height of current plotting window)}
+\item{units}{Units for width and height when specified explicitly (in, cm,
+or mm)}
 
-\item{units}{units for width and height when either one is explicitly specified (in, cm, or mm)}
+\item{dpi}{Resolution used for raster outputs.}
 
-\item{dpi}{dpi to use for raster graphics}
-
-\item{limitsize}{when \code{TRUE} (the default), \code{ggsave} will not
+\item{limitsize}{When \code{TRUE} (the default), \code{ggsave} will not
 save images larger than 50x50 inches, to prevent the common error of
 specifying dimensions in pixels.}
 
-\item{...}{other arguments passed to graphics device}
+\item{...}{Other arguments passed on to graphics device}
 }
 \description{
-ggsave is a convenient function for saving a plot.  It defaults to
-saving the last plot that you displayed, and for a default size uses
-the size of the current graphics device.  It also guesses the type of
-graphics device from the extension.  This means the only argument you
-need to supply is the filename.
-}
-\details{
-\code{ggsave} currently recognises the extensions eps/ps, tex (pictex),
-pdf, jpeg, tiff, png, bmp, svg and wmf (windows only).
+\code{ggsave()} is a convenient function for saving a plot. It defaults to
+saving the last plot that you displayed, using the size of the current
+graphics device. It also guesses the type of graphics device from the
+extension.
 }
 \examples{
 \dontrun{
-ratings <- qplot(rating, data=movies, geom="histogram")
-qplot(length, data=movies, geom="histogram")
-ggsave("length-hist.pdf")
-ggsave("length-hist.png")
-ggsave("ratings.pdf", ratings)
-ggsave("ratings.pdf", ratings, width=4, height=4)
-# make twice as big as on screen
-ggsave("ratings.pdf", ratings, scale=2)
+ggplot(mtcars, aes(mpg, wt)) + geom_point()
+
+ggsave("mtcars.pdf")
+ggsave("mtcars.png")
+
+ggsave("mtcars.pdf", width = 4, height = 4)
+ggsave("mtcars.pdf", width = 20, height = 20, units = "cm")
+
+unlink("mtcars.pdf")
+unlink("mtcars.png")
+
+# specify device when saving to a file with unknown extension
+# (for example a server supplied temporary file)
+file <- tempfile()
+ggsave(file, device = "pdf")
+unlink(file)
 }
 }
 
diff --git a/man/ggscale.Rd b/man/ggscale.Rd
deleted file mode 100644
index d6410d6..0000000
--- a/man/ggscale.Rd
+++ /dev/null
@@ -1,32 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/scale-.r
-\name{ggscale}
-\alias{ggscale}
-\title{Components of a scale:}
-\description{
-Guide related:
-}
-\details{
-\itemize{
-  \item name
-  \item breaks
-  \item labels
-  \item expand
-}
-
-Mapping related:
-\itemize{
-  \item aesthetic
-  \item limits
-  \item palette
-  \item trans
-}
-
-Scales are an S3 class with a single mutable component implemented with
-a reference class - the range of the data.  This mutability makes working
-with scales much easier, because it makes it possible to distribute the
-training, without having to worry about collecting all the pieces back
-together again.
-}
-\keyword{internal}
-
diff --git a/man/ggtheme.Rd b/man/ggtheme.Rd
index c460aa8..da5ab28 100644
--- a/man/ggtheme.Rd
+++ b/man/ggtheme.Rd
@@ -1,19 +1,21 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/theme-defaults.r
 \name{ggtheme}
 \alias{ggtheme}
 \alias{theme_bw}
 \alias{theme_classic}
+\alias{theme_dark}
 \alias{theme_gray}
 \alias{theme_grey}
 \alias{theme_light}
 \alias{theme_linedraw}
 \alias{theme_minimal}
+\alias{theme_void}
 \title{ggplot2 themes}
 \usage{
-theme_grey(base_size = 12, base_family = "")
+theme_grey(base_size = 11, base_family = "")
 
-theme_gray(base_size = 12, base_family = "")
+theme_gray(base_size = 11, base_family = "")
 
 theme_bw(base_size = 12, base_family = "")
 
@@ -24,6 +26,10 @@ theme_light(base_size = 12, base_family = "")
 theme_minimal(base_size = 12, base_family = "")
 
 theme_classic(base_size = 12, base_family = "")
+
+theme_dark(base_size = 12, base_family = "")
+
+theme_void(base_size = 12, base_family = "")
 }
 \arguments{
 \item{base_size}{base font size}
@@ -55,12 +61,18 @@ may refuse.}
 A theme similar to \code{theme_linedraw} but with light grey lines and axes,
 to direct more attention towards the data.}
 
+\item{\code{theme_dark}}{
+The dark cousin of \code{theme_light}, with similar line sizes but a dark background. Useful to make thin coloured lines pop out.}
+
 \item{\code{theme_minimal}}{
 A minimalistic theme with no background annotations.}
 
 \item{\code{theme_classic}}{
 A classic-looking theme, with x and y axis lines and no gridlines.}
 
+\item{\code{theme_void}}{
+A completely empty theme.}
+
 }
 }
 \examples{
@@ -74,5 +86,7 @@ p + theme_linedraw()
 p + theme_light()
 p + theme_minimal()
 p + theme_classic()
+p + theme_void()
+
 }
 
diff --git a/man/graphical-units.Rd b/man/graphical-units.Rd
new file mode 100644
index 0000000..c6b406d
--- /dev/null
+++ b/man/graphical-units.Rd
@@ -0,0 +1,20 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/geom-.r
+\docType{data}
+\name{graphical-units}
+\alias{.pt}
+\alias{.stroke}
+\alias{graphical-units}
+\title{Graphical units}
+\format{An object of class \code{numeric} of length 1.}
+\usage{
+.pt
+
+.stroke
+}
+\description{
+Multiply size in mm by these constants in order to convert to the units
+that grid uses internally for \code{lwd} and \code{fontsize}.
+}
+\keyword{datasets}
+
diff --git a/man/guide_colourbar.Rd b/man/guide_colourbar.Rd
index ac450ae..d210244 100644
--- a/man/guide_colourbar.Rd
+++ b/man/guide_colourbar.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/guide-colorbar.r
 \name{guide_colourbar}
 \alias{guide_colorbar}
@@ -24,7 +24,7 @@ guide_colorbar(title = waiver(), title.position = NULL,
 \arguments{
 \item{title}{A character string or expression indicating a title of guide.
 If \code{NULL}, the title is not shown. By default
-(\code{\link{waiver}}), the name of the scale object or tha name
+(\code{\link{waiver}}), the name of the scale object or the name
 specified in \code{\link{labs}} is used for the title.}
 
 \item{title.position}{A character string indicating the position of a
@@ -46,7 +46,7 @@ text.}
 
 \item{label.position}{A character string indicating the position of a
 label. One of "top", "bottom" (default for horizontal guide), "left", or
-"right" (default for vertical gudie).}
+"right" (default for vertical guide).}
 
 \item{label.theme}{A theme object for rendering the label text. Usually the
 object of \code{\link{element_text}} is expected. By default, the theme is
@@ -58,12 +58,12 @@ label text.}
 \item{label.vjust}{A numeric specifying vertical justification of the label
 text.}
 
-\item{barwidth}{A numeric or a unit object specifying the width of the
-colorbar. Default value is \code{legend.key.width} or
+\item{barwidth}{A numeric or a \code{\link[grid]{unit}} object specifying
+the width of the colorbar. Default value is \code{legend.key.width} or
 \code{legend.key.size} in \code{\link{theme}} or theme.}
 
-\item{barheight}{A numeric or a unit object specifying the height of the
-colorbar. Default value is \code{legend.key.height} or
+\item{barheight}{A numeric or a \code{\link[grid]{unit}} object specifying
+the height of the colorbar. Default value is \code{legend.key.height} or
 \code{legend.key.size} in \code{\link{theme}} or theme.}
 
 \item{nbin}{A numeric specifying the number of bins for drawing colorbar. A
@@ -86,14 +86,16 @@ be visible.}
 \item{direction}{A character string indicating the direction of the guide.
 One of "horizontal" or "vertical."}
 
-\item{default.unit}{A character string indicating unit for \code{barwidth}}
+\item{default.unit}{A character string indicating \code{\link[grid]{unit}}
+for \code{barwidth} and \code{barheight}.}
 
 \item{reverse}{logical. If \code{TRUE} the colorbar is reversed. By default,
 the highest value is on the top and the lowest value is on the bottom}
 
-\item{order}{positive integer less that 99 that specify the order of
-this guide in the multiple guides. If 0 (default), the order is determined
-by a secret algorithm.}
+\item{order}{positive integer less that 99 that specifies the order of
+this guide among multiple guides. This controls the order in which
+multiple guides are displayed, not the contents of the guide itself.
+If 0 (default), the order is determined by a secret algorithm.}
 
 \item{...}{ignored.}
 }
@@ -107,15 +109,14 @@ For more information, see the inspiration for this function:
 \href{http://www.mathworks.com/help/techdoc/ref/colorbar.html}{Matlab's colorbar function}.
 }
 \details{
-Guides can be specified in each scale or in \code{\link{guides}}.
-\code{guide="legend"} in scale is syntax sugar for
-\code{guide=guide_legend()} - but the second form allows you to specify
-more options. As for how to specify the guide for each
-scales, see \code{\link{guides}}.
+Guides can be specified in each \code{scale_*} or in \code{\link{guides}}.
+\code{guide="legend"} in \code{scale_*} is syntactic sugar for
+\code{guide=guide_legend()} (e.g. \code{scale_color_manual(guide = "legend")}).
+As for how to specify the guide for each scale in more detail,
+see \code{\link{guides}}.
 }
 \examples{
-library(reshape2) # for melt
-df <- melt(outer(1:4, 1:4), varnames = c("X1", "X2"))
+df <- reshape2::melt(outer(1:4, 1:4), varnames = c("X1", "X2"))
 
 p1 <- ggplot(df, aes(X1, X2)) + geom_tile(aes(fill = value))
 p2 <- p1 + geom_point(aes(size = value))
@@ -163,7 +164,7 @@ p2 +
   scale_size(guide = guide_legend(direction = "vertical"))
 }
 \seealso{
-Other guides: \code{\link{guide_legend}};
+Other guides: \code{\link{guide_legend}},
   \code{\link{guides}}
 }
 
diff --git a/man/guide_legend.Rd b/man/guide_legend.Rd
index 9c22405..4e9f8ba 100644
--- a/man/guide_legend.Rd
+++ b/man/guide_legend.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/guide-legend.r
 \name{guide_legend}
 \alias{guide_legend}
@@ -15,7 +15,7 @@ guide_legend(title = waiver(), title.position = NULL, title.theme = NULL,
 \arguments{
 \item{title}{A character string or expression indicating a title of guide.
 If \code{NULL}, the title is not shown. By default
-(\code{\link{waiver}}), the name of the scale object or tha name
+(\code{\link{waiver}}), the name of the scale object or the name
 specified in \code{\link{labs}} is used for the title.}
 
 \item{title.position}{A character string indicating the position of a
@@ -37,7 +37,7 @@ text.}
 
 \item{label.position}{A character string indicating the position of a
 label. One of "top", "bottom" (default for horizontal guide), "left", or
-"right" (default for vertical gudie).}
+"right" (default for vertical guide).}
 
 \item{label.theme}{A theme object for rendering the label text. Usually the
 object of \code{\link{element_text}} is expected. By default, the theme is
@@ -49,19 +49,19 @@ label text.}
 \item{label.vjust}{A numeric specifying vertical justification of the label
 text.}
 
-\item{keywidth}{A numeric or a unit object specifying the width of the
-legend key. Default value is \code{legend.key.width} or
+\item{keywidth}{A numeric or a \code{\link[grid]{unit}} object specifying
+the width of the legend key. Default value is \code{legend.key.width} or
 \code{legend.key.size} in \code{\link{theme}} or theme.}
 
-\item{keyheight}{A numeric or a unit object specifying the height of the
-legend key. Default value is \code{legend.key.height} or
+\item{keyheight}{A numeric or a \code{\link[grid]{unit}} object specifying
+the height of the legend key. Default value is \code{legend.key.height} or
 \code{legend.key.size} in \code{\link{theme}} or theme.}
 
 \item{direction}{A character string indicating the direction of the guide.
 One of "horizontal" or "vertical."}
 
-\item{default.unit}{A character string indicating unit for \code{keywidth}
-and \code{keyheight}.}
+\item{default.unit}{A character string indicating \code{\link[grid]{unit}}
+for \code{keywidth} and \code{keyheight}.}
 
 \item{override.aes}{A list specifying aesthetic parameters of legend key.
 See details and examples.}
@@ -75,9 +75,10 @@ filled by columns, otherwise the legend-matrix is filled by rows.}
 
 \item{reverse}{logical. If \code{TRUE} the order of legends is reversed.}
 
-\item{order}{positive integer less that 99 that specify the order of
-this guide in the multiple guides. If 0 (default), the order is determined
-by a secret algorithm.}
+\item{order}{positive integer less that 99 that specifies the order of
+this guide among multiple guides. This controls the order in which
+multiple guides are displayed, not the contents of the guide itself.
+If 0 (default), the order is determined by a secret algorithm.}
 
 \item{...}{ignored.}
 }
@@ -89,15 +90,15 @@ Legend type guide shows key (i.e., geoms) mapped onto values.
 Legend guides for various scales are integrated if possible.
 }
 \details{
-Guides can be specified in each scale or in \code{\link{guides}}.
-\code{guide="legend"} in scale is syntactic sugar for
-\code{guide=guide_legend()}. As for how to specify the guide for each
-scales in more detail, see \code{\link{guides}}.
+Guides can be specified in each \code{scale_*} or in \code{\link{guides}}.
+\code{guide="legend"} in \code{scale_*} is syntactic sugar for
+\code{guide=guide_legend()} (e.g. \code{scale_color_manual(guide = "legend")}).
+As for how to specify the guide for each scale in more detail,
+see \code{\link{guides}}.
 }
 \examples{
 \donttest{
-library(reshape2) # for melt
-df <- melt(outer(1:4, 1:4), varnames = c("X1", "X2"))
+df <- reshape2::melt(outer(1:4, 1:4), varnames = c("X1", "X2"))
 
 p1 <- ggplot(df, aes(X1, X2)) + geom_tile(aes(fill = value))
 p2 <- p1 + geom_point(aes(size = value))
@@ -109,7 +110,6 @@ p1 + scale_fill_continuous(guide = guide_legend())
 # Guide title
 
 p1 + scale_fill_continuous(guide = guide_legend(title = "V")) # title text
-p1 + scale_fill_continuous(name = "V") # same
 p1 + scale_fill_continuous(guide = guide_legend(title = NULL)) # no title
 
 # Control styles
@@ -137,15 +137,17 @@ p1 + scale_fill_continuous(breaks = c(5, 10, 15),
 # Set aesthetic of legend key
 
 # very low alpha value make it difficult to see legend key
-p3 <- qplot(carat, price, data = diamonds, colour = color,
-  alpha = I(1/100))
+p3 <- ggplot(diamonds, aes(carat, price)) +
+  geom_point(aes(colour=color), alpha=1/100)
 p3
 
 # override.aes overwrites the alpha
 p3 + guides(colour = guide_legend(override.aes = list(alpha = 1)))
 
 # multiple row/col legends
-p <- qplot(1:20, 1:20, colour = letters[1:20])
+df <- data.frame(x = 1:20, y = 1:20, color = letters[1:20])
+p <- ggplot(df, aes(x, y)) +
+  geom_point(aes(colour = color))
 p + guides(col = guide_legend(nrow = 8))
 p + guides(col = guide_legend(ncol = 8))
 p + guides(col = guide_legend(nrow = 8, byrow = TRUE))
@@ -156,7 +158,7 @@ p + guides(col = guide_legend(reverse = TRUE))
 }
 }
 \seealso{
-Other guides: \code{\link{guide_colorbar}},
-  \code{\link{guide_colourbar}}; \code{\link{guides}}
+Other guides: \code{\link{guide_colourbar}},
+  \code{\link{guides}}
 }
 
diff --git a/man/guides.Rd b/man/guides.Rd
index 1827d4b..c4ead6b 100644
--- a/man/guides.Rd
+++ b/man/guides.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/guides-.r
 \name{guides}
 \alias{guides}
@@ -38,6 +38,10 @@ p +
  scale_size_discrete(guide = "legend") +
  scale_shape(guide = "legend")
 
+ # Remove some guides
+ p + guides(colour = "none")
+ p + guides(colour = "colorbar",size = "none")
+
 # Guides are integrated where possible
 
 p + guides(colour = guide_legend("title"), size = guide_legend("title"),
@@ -53,15 +57,17 @@ p + theme(legend.position = "bottom")
 p + theme(legend.position = "bottom", legend.box = "horizontal")
 
 # Set order for multiple guides
-
-qplot(data = mpg, x = displ, y = cty, size = hwy, colour = cyl, shape = drv) +
-  guides(colour = guide_colourbar(order = 1),
-         alpha = guide_legend(order = 2),
-         size = guide_legend(order = 3))
+ggplot(mpg, aes(displ, cty)) +
+  geom_point(aes(size = hwy, colour = cyl, shape = drv)) +
+  guides(
+   colour = guide_colourbar(order = 1),
+   shape = guide_legend(order = 2),
+   size = guide_legend(order = 3)
+ )
 }
 }
 \seealso{
-Other guides: \code{\link{guide_colorbar}},
-  \code{\link{guide_colourbar}}; \code{\link{guide_legend}}
+Other guides: \code{\link{guide_colourbar}},
+  \code{\link{guide_legend}}
 }
 
diff --git a/man/hmisc.Rd b/man/hmisc.Rd
index e09faff..8de36cd 100644
--- a/man/hmisc.Rd
+++ b/man/hmisc.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/stat-summary.r
 \name{hmisc}
 \alias{hmisc}
diff --git a/man/interleave.Rd b/man/interleave.Rd
deleted file mode 100644
index 5bba5f8..0000000
--- a/man/interleave.Rd
+++ /dev/null
@@ -1,16 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/utilities-matrix.r
-\name{interleave}
-\alias{interleave}
-\title{Interleave (or zip) multiple vectors into a single vector.}
-\usage{
-interleave(...)
-}
-\arguments{
-\item{...}{vectors to interleave}
-}
-\description{
-Interleave (or zip) multiple vectors into a single vector.
-}
-\keyword{internal}
-
diff --git a/man/is.coord.Rd b/man/is.Coord.Rd
similarity index 63%
rename from man/is.coord.Rd
rename to man/is.Coord.Rd
index fed4a61..6cb932f 100644
--- a/man/is.coord.Rd
+++ b/man/is.Coord.Rd
@@ -1,10 +1,10 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/coord-.r
-\name{is.coord}
-\alias{is.coord}
+\name{is.Coord}
+\alias{is.Coord}
 \title{Is this object a coordinate system?}
 \usage{
-is.coord(x)
+is.Coord(x)
 }
 \description{
 Is this object a coordinate system?
diff --git a/man/is.facet.Rd b/man/is.facet.Rd
index 771025d..df3b398 100644
--- a/man/is.facet.Rd
+++ b/man/is.facet.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/facet-.r
 \name{is.facet}
 \alias{is.facet}
diff --git a/man/is.ggplot.Rd b/man/is.ggplot.Rd
index cf55cc4..e4ceff6 100644
--- a/man/is.ggplot.Rd
+++ b/man/is.ggplot.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/plot.r
 \name{is.ggplot}
 \alias{is.ggplot}
@@ -12,4 +12,5 @@ is.ggplot(x)
 \description{
 Reports whether x is a ggplot object
 }
+\keyword{internal}
 
diff --git a/man/is.ggproto.Rd b/man/is.ggproto.Rd
new file mode 100644
index 0000000..49ad4ef
--- /dev/null
+++ b/man/is.ggproto.Rd
@@ -0,0 +1,15 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/ggproto.r
+\name{is.ggproto}
+\alias{is.ggproto}
+\title{Is an object a ggproto object?}
+\usage{
+is.ggproto(x)
+}
+\arguments{
+\item{x}{An object to test.}
+}
+\description{
+Is an object a ggproto object?
+}
+
diff --git a/man/is.rel.Rd b/man/is.rel.Rd
index 05c80d5..12aafc1 100644
--- a/man/is.rel.Rd
+++ b/man/is.rel.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/theme-elements.r
 \name{is.rel}
 \alias{is.rel}
diff --git a/man/is.theme.Rd b/man/is.theme.Rd
index a14e988..b8e94f5 100644
--- a/man/is.theme.Rd
+++ b/man/is.theme.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/theme.r
 \name{is.theme}
 \alias{is.theme}
diff --git a/man/label_both.Rd b/man/label_both.Rd
deleted file mode 100644
index 95d2eaa..0000000
--- a/man/label_both.Rd
+++ /dev/null
@@ -1,26 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/facet-labels.r
-\name{label_both}
-\alias{label_both}
-\title{Label facets with value and variable.}
-\usage{
-label_both(variable, value)
-}
-\arguments{
-\item{variable}{variable name passed in by facetter}
-
-\item{value}{variable value passed in by facetter}
-}
-\description{
-Label facets with value and variable.
-}
-\examples{
-p <- qplot(wt, mpg, data = mtcars)
-p + facet_grid(. ~ cyl)
-p + facet_grid(. ~ cyl, labeller = label_both)
-}
-\seealso{
-Other facet labellers: \code{\link{label_bquote}};
-  \code{\link{label_parsed}}; \code{\link{label_value}}
-}
-
diff --git a/man/label_bquote.Rd b/man/label_bquote.Rd
index b3518ef..6e0fa6e 100644
--- a/man/label_bquote.Rd
+++ b/man/label_bquote.Rd
@@ -1,27 +1,33 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/facet-labels.r
 \name{label_bquote}
 \alias{label_bquote}
-\title{Label facet with 'bquoted' expressions}
+\title{Backquoted labeller}
 \usage{
-label_bquote(expr = beta^.(x))
+label_bquote(rows = NULL, cols = NULL, default = label_value)
 }
 \arguments{
-\item{expr}{labelling expression to use}
+\item{rows}{Backquoted labelling expression for rows.}
+
+\item{cols}{Backquoted labelling expression for columns.}
+
+\item{default}{Default labeller function for the rows or the
+columns when no plotmath expression is provided.}
 }
 \description{
-See \code{\link{bquote}} for details on the syntax of the argument.  The
-label value is x.
+\code{\link{label_bquote}()} offers a flexible way of labelling
+facet rows or columns with plotmath expressions. Backquoted
+variables will be replaced with their value in the facet.
 }
 \examples{
-p <- qplot(wt, mpg, data = mtcars)
-p + facet_grid(. ~ vs, labeller = label_bquote(alpha ^ .(x)))
-p + facet_grid(. ~ vs, labeller = label_bquote(.(x) ^ .(x)))
+# The variables mentioned in the plotmath expression must be
+# backquoted and referred to by their names.
+p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
+p + facet_grid(vs ~ ., labeller = label_bquote(alpha ^ .(vs)))
+p + facet_grid(. ~ vs, labeller = label_bquote(cols = .(vs) ^ .(vs)))
+p + facet_grid(. ~ vs + am, labeller = label_bquote(cols = .(am) ^ .(vs)))
 }
 \seealso{
-\code{\link{plotmath}}
-
-Other facet labellers: \code{\link{label_both}};
-  \code{\link{label_parsed}}; \code{\link{label_value}}
+\link{labellers}, \code{\link{labeller}()},
 }
 
diff --git a/man/label_parsed.Rd b/man/label_parsed.Rd
deleted file mode 100644
index fd2319e..0000000
--- a/man/label_parsed.Rd
+++ /dev/null
@@ -1,29 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/facet-labels.r
-\name{label_parsed}
-\alias{label_parsed}
-\title{Label facets with parsed label.}
-\usage{
-label_parsed(variable, value)
-}
-\arguments{
-\item{variable}{variable name passed in by facetter}
-
-\item{value}{variable value passed in by facetter}
-}
-\description{
-Label facets with parsed label.
-}
-\examples{
-mtcars$cyl2 <- factor(mtcars$cyl, labels = c("alpha", "beta", "gamma"))
-qplot(wt, mpg, data = mtcars) + facet_grid(. ~ cyl2)
-qplot(wt, mpg, data = mtcars) + facet_grid(. ~ cyl2,
-  labeller = label_parsed)
-}
-\seealso{
-\code{\link{plotmath}}
-
-Other facet labellers: \code{\link{label_both}};
-  \code{\link{label_bquote}}; \code{\link{label_value}}
-}
-
diff --git a/man/label_value.Rd b/man/label_value.Rd
deleted file mode 100644
index 0d78c20..0000000
--- a/man/label_value.Rd
+++ /dev/null
@@ -1,28 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/facet-labels.r
-\name{label_value}
-\alias{label_value}
-\title{Label facets with their value.
-This is the default labelling scheme.}
-\usage{
-label_value(variable, value)
-}
-\arguments{
-\item{variable}{variable name passed in by facetter}
-
-\item{value}{variable value passed in by facetter}
-}
-\description{
-Label facets with their value.
-This is the default labelling scheme.
-}
-\examples{
-p <- qplot(wt, mpg, data = mtcars)
-p + facet_grid(. ~ cyl)
-p + facet_grid(. ~ cyl, labeller = label_value)
-}
-\seealso{
-Other facet labellers: \code{\link{label_both}};
-  \code{\link{label_bquote}}; \code{\link{label_parsed}}
-}
-
diff --git a/man/label_wrap_gen.Rd b/man/label_wrap_gen.Rd
deleted file mode 100644
index 6915773..0000000
--- a/man/label_wrap_gen.Rd
+++ /dev/null
@@ -1,18 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/facet-labels.r
-\name{label_wrap_gen}
-\alias{label_wrap_gen}
-\title{Label facets with a word wrapped label.}
-\usage{
-label_wrap_gen(width = 25)
-}
-\arguments{
-\item{width}{integer, target column width for output.}
-}
-\description{
-Uses \code{\link[base]{strwrap}} for line wrapping.
-}
-\seealso{
-, \code{\link{labeller}}
-}
-
diff --git a/man/labeller.Rd b/man/labeller.Rd
index 3c450f4..99bba09 100644
--- a/man/labeller.Rd
+++ b/man/labeller.Rd
@@ -1,75 +1,116 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/facet-labels.r
 \name{labeller}
 \alias{labeller}
 \title{Generic labeller function for facets}
 \usage{
-labeller(..., keep.as.numeric = FALSE)
+labeller(..., .rows = NULL, .cols = NULL, keep.as.numeric = NULL,
+  .multi_line = TRUE, .default = label_value)
 }
 \arguments{
-\item{...}{Named arguments of the form \code{variable=values},
-where \code{values} could be a vector or method.}
+\item{...}{Named arguments of the form \code{variable =
+labeller}. Each labeller is passed to \code{\link{as_labeller}()}
+and can be a lookup table, a function taking and returning
+character vectors, or simply a labeller function.}
 
-\item{keep.as.numeric}{logical, default TRUE. When FALSE, converts numeric
-values supplied as margins to the facet to characters.}
+\item{.rows, .cols}{Labeller for a whole margin (either the rows or
+the columns). It is passed to \code{\link{as_labeller}()}. When a
+margin-wide labeller is set, make sure you don't mention in
+\code{...} any variable belonging to the margin.}
+
+\item{keep.as.numeric}{Deprecated. All supplied labellers and
+on-labeller functions should be able to work with character
+labels.}
+
+\item{.multi_line}{Whether to display the labels of multiple
+factors on separate lines. This is passed to the labeller
+function.}
+
+\item{.default}{Default labeller for variables not specified. Also
+used with lookup tables or non-labeller functions.}
 }
 \value{
-Function to supply to
-  \code{\link{facet_grid}} for the argument \code{labeller}.
+A labeller function to supply to \code{\link{facet_grid}}
+  for the argument \code{labeller}.
 }
 \description{
-One-step function for providing methods or named character vectors
-for displaying labels in facets.
+This function makes it easy to assign different labellers to
+different factors. The labeller can be a function or it can be a
+named character vectors that will serve as a lookup table.
 }
 \details{
-The provided methods are checked for number of arguments.
-If the provided method takes less than two
-(e.g. \code{\link[Hmisc]{capitalize}}),
-the method is passed \code{values}.
-Else (e.g. \code{\link{label_both}}),
-it is passed \code{variable} and \code{values} (in that order).
-If you want to be certain, use e.g. an anonymous function.
-If errors are returned such as ``argument ".." is missing, with no default''
-or ``unused argument (variable)'', matching the method's arguments does not
-work as expected; make a wrapper function.
+In case of functions, if the labeller has class \code{labeller}, it
+is directly applied on the data frame of labels. Otherwise, it is
+applied to the columns of the data frame of labels. The data frame
+is then processed with the function specified in the
+\code{.default} argument. This is intended to be used with
+functions taking a character vector such as
+\code{\link[Hmisc]{capitalize}}.
 }
 \examples{
 \donttest{
-p1 <- ggplot(mpg, aes(cty, hwy)) + geom_point()
-p1 + facet_grid(cyl ~ class, labeller=label_both)
-p1 + facet_grid(cyl ~ class, labeller=labeller(cyl=label_both))
+p1 <- ggplot(mtcars, aes(x = mpg, y = wt)) + geom_point()
+
+# You can assign different labellers to variables:
+p1 + facet_grid(vs + am ~ gear,
+  labeller = labeller(vs = label_both, am = label_value))
 
-ggplot(mtcars, aes(x = mpg, y = wt)) + geom_point() +
-  facet_grid(vs + am ~ gear, margins=TRUE,
-             labeller=labeller(vs=label_both, am=label_both))
+# Or whole margins:
+p1 + facet_grid(vs + am ~ gear,
+  labeller = labeller(.rows = label_both, .cols = label_value))
 
+# You can supply functions operating on strings:
 capitalize <- function(string) {
   substr(string, 1, 1) <- toupper(substr(string, 1, 1))
   string
 }
-conservation_status <- c('cd'='Conservation Dependent',
-                         'en'='Endangered',
-                         'lc'='Least concern',
-                         'nt'='Near Threatened',
-                         'vu'='Vulnerable',
-                         'domesticated'='Domesticated')
-## Source: http://en.wikipedia.org/wiki/Wikipedia:Conservation_status
-
-p2 <- ggplot(msleep, aes(x=sleep_total, y=awake)) + geom_point()
+p2 <- ggplot(msleep, aes(x = sleep_total, y = awake)) + geom_point()
 p2 + facet_grid(vore ~ conservation, labeller = labeller(vore = capitalize))
 
-p2 + facet_grid(vore ~ conservation,
-  labeller=labeller(vore = capitalize, conservation = conservation_status ))
+# Or use character vectors as lookup tables:
+conservation_status <- c(
+  cd = "Conservation Dependent",
+  en = "Endangered",
+  lc = "Least concern",
+  nt = "Near Threatened",
+  vu = "Vulnerable",
+  domesticated = "Domesticated"
+)
+## Source: http://en.wikipedia.org/wiki/Wikipedia:Conservation_status
 
-# We could of course have renamed the levels;
-# then we can apply another nifty function
-msleep$conservation2 <- plyr::revalue(msleep$conservation, conservation_status)
+p2 + facet_grid(vore ~ conservation, labeller = labeller(
+  .default = capitalize,
+  conservation = conservation_status
+))
 
+# In the following example, we rename the levels to the long form,
+# then apply a wrap labeller to the columns to prevent cropped text
+msleep$conservation2 <- plyr::revalue(msleep$conservation,
+  conservation_status)
+
+p2 \%+\% msleep + facet_grid(vore ~ conservation2)
 p2 \%+\% msleep +
-  facet_grid(vore ~ conservation2, labeller = labeller(vore = capitalize))
-p2 \%+\% msleep +
- facet_grid(vore ~ conservation2, labeller = labeller(conservation2 =
- label_wrap_gen(10)))
+  facet_grid(vore ~ conservation2,
+    labeller = labeller(conservation2 = label_wrap_gen(10))
+  )
+
+# labeller() is especially useful to act as a global labeller. You
+# can set it up once and use it on a range of different plots with
+# different facet specifications.
+
+global_labeller <- labeller(
+  vore = capitalize,
+  conservation = conservation_status,
+  conservation2 = label_wrap_gen(10),
+  .default = label_both
+)
+
+p2 + facet_grid(vore ~ conservation, labeller = global_labeller)
+p2 + facet_wrap(~vore, labeller = global_labeller)
+p2 \%+\% msleep + facet_wrap(~conservation2, labeller = global_labeller)
+}
 }
+\seealso{
+\code{\link{as_labeller}()}, \link{labellers}
 }
 
diff --git a/man/labellers.Rd b/man/labellers.Rd
new file mode 100644
index 0000000..e006f95
--- /dev/null
+++ b/man/labellers.Rd
@@ -0,0 +1,118 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/facet-labels.r
+\name{labellers}
+\alias{label_both}
+\alias{label_context}
+\alias{label_parsed}
+\alias{label_value}
+\alias{label_wrap_gen}
+\alias{labellers}
+\title{Labeller functions}
+\usage{
+label_value(labels, multi_line = TRUE)
+
+label_both(labels, multi_line = TRUE, sep = ": ")
+
+label_context(labels, multi_line = TRUE, sep = ": ")
+
+label_parsed(labels, multi_line = TRUE)
+
+label_wrap_gen(width = 25, multi_line = TRUE)
+}
+\arguments{
+\item{labels}{Data frame of labels. Usually contains only one
+element, but facetting over multiple factors entails multiple
+label variables.}
+
+\item{multi_line}{Whether to display the labels of multiple factors
+on separate lines.}
+
+\item{sep}{String separating variables and values.}
+
+\item{width}{Maximum number of characters before wrapping the strip.}
+}
+\description{
+Labeller functions are in charge of formatting the strip labels of
+facet grids and wraps. Most of them accept a \code{multi_line}
+argument to control whether multiple factors (defined in formulae
+such as \code{~first + second}) should be displayed on a single
+line separated with commas, or each on their own line.
+}
+\details{
+\code{label_value()} only displays the value of a factor while
+\code{label_both()} displays both the variable name and the factor
+value. \code{label_context()} is context-dependent and uses
+\code{label_value()} for single factor facetting and
+\code{label_both()} when multiple factors are
+involved. \code{label_wrap_gen()} uses \code{\link[base]{strwrap}()}
+for line wrapping.
+
+\code{label_parsed()} interprets the labels as plotmath
+expressions. \code{\link{label_bquote}()} offers a more flexible
+way of constructing plotmath expressions. See examples and
+\code{\link{bquote}()} for details on the syntax of the
+argument.
+}
+\section{Writing New Labeller Functions}{
+
+
+  Note that an easy way to write a labeller function is to
+  transform a function operating on character vectors with
+  \code{\link{as_labeller}()}.
+
+  A labeller function accepts a data frame of labels (character
+  vectors) containing one column for each factor. Multiple factors
+  occur with formula of the type \code{~first + second}.
+
+  The return value must be a rectangular list where each 'row'
+  characterises a single facet. The list elements can be either
+  character vectors or lists of plotmath expressions. When multiple
+  elements are returned, they get displayed on their own new lines
+  (i.e., each facet gets a multi-line strip of labels).
+
+  To illustrate, let's say your labeller returns a list of two
+  character vectors of length 3. This is a rectangular list because
+  all elements have the same length. The first facet will get the
+  first elements of each vector and display each of them on their
+  own line. Then the second facet gets the second elements of each
+  vector, and so on.
+
+  If it's useful to your labeller, you can retrieve the \code{type}
+  attribute of the incoming data frame of labels. The value of this
+  attribute reflects the kind of strips your labeller is dealing
+  with: \code{"cols"} for columns and \code{"rows"} for rows. Note
+  that \code{\link{facet_wrap}()} has columns by default and rows
+  when the strips are switched with the \code{switch} option. The
+  \code{facet} attribute also provides metadata on the labels. It
+  takes the values \code{"grid"} or \code{"wrap"}.
+
+  For compatibility with \code{\link{labeller}()}, each labeller
+  function must have the \code{labeller} S3 class.
+}
+\examples{
+mtcars$cyl2 <- factor(mtcars$cyl, labels = c("alpha", "beta", "gamma"))
+p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
+
+# Displaying only the values
+p + facet_grid(. ~ cyl)
+p + facet_grid(. ~ cyl, labeller = label_value)
+
+\donttest{
+# Displaying both the values and the variables
+p + facet_grid(. ~ cyl, labeller = label_both)
+
+# Displaying only the values or both the values and variables
+# depending on whether multiple factors are facetted over
+p + facet_grid(am ~ vs+cyl, labeller = label_context)
+
+# Interpreting the labels as plotmath expressions
+p + facet_grid(. ~ cyl2)
+p + facet_grid(. ~ cyl2, labeller = label_parsed)
+p + facet_wrap(~vs + cyl2, labeller = label_parsed)
+}
+}
+\seealso{
+\code{\link{labeller}()}, \code{\link{as_labeller}()},
+  \code{\link{label_bquote}()}
+}
+
diff --git a/man/labs.Rd b/man/labs.Rd
index 853748e..637792e 100644
--- a/man/labs.Rd
+++ b/man/labs.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/labels.r
 \name{labs}
 \alias{ggtitle}
@@ -24,20 +24,20 @@ ggtitle(label)
 Change axis labels and legend titles
 }
 \examples{
-p <- qplot(mpg, wt, data = mtcars)
+p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
 p + labs(title = "New plot title")
 p + labs(x = "New x label")
 p + xlab("New x label")
 p + ylab("New y label")
 p + ggtitle("New plot title")
 
-# This should work indepdendently of other functions that modify the
+# This should work independently of other functions that modify the
 # the scale names
 p + ylab("New y label") + ylim(2, 4)
 p + ylim(2, 4) + ylab("New y label")
 
 # The labs function also modifies legend labels
-p <- qplot(mpg, wt, data = mtcars, colour = cyl)
+p <- ggplot(mtcars, aes(mpg, wt, colour = cyl)) + geom_point()
 p + labs(colour = "Cylinders")
 
 # Can also pass in a list, if that is more convenient
diff --git a/man/last_plot.Rd b/man/last_plot.Rd
index 5bdffa6..53590c4 100644
--- a/man/last_plot.Rd
+++ b/man/last_plot.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/plot-last.r
 \name{last_plot}
 \alias{last_plot}
diff --git a/man/layer.Rd b/man/layer.Rd
index 3535f31..4896e44 100644
--- a/man/layer.Rd
+++ b/man/layer.Rd
@@ -1,13 +1,51 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/layer.r
 \name{layer}
 \alias{layer}
 \title{Create a new layer}
 \usage{
-layer(...)
+layer(geom = NULL, stat = NULL, data = NULL, mapping = NULL,
+  position = NULL, params = list(), inherit.aes = TRUE, subset = NULL,
+  show.legend = NA)
+}
+\arguments{
+\item{geom, stat, position}{Geom, stat and position adjustment to use in
+this layer. Can either be the name of a ggproto object, or the object
+itself.}
+
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
+
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
+
+\item{params}{Additional parameters to the \code{geom} and \code{stat}.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{subset}{DEPRECATED. An older way of subsetting the dataset used in a
+layer.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
 }
 \description{
 Create a new layer
 }
-\keyword{internal}
+\examples{
+# geom calls are just a short cut for layer
+ggplot(mpg, aes(displ, hwy)) + geom_point()
+# shortcut for
+ggplot(mpg, aes(displ, hwy)) +
+  layer(geom = "point", stat = "identity", position = "identity",
+    params = list(na.rm = FALSE)
+  )
+}
 
diff --git a/man/limits.Rd b/man/limits.Rd
index 8c1510b..b236d80 100644
--- a/man/limits.Rd
+++ b/man/limits.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/limits.r
 \name{limits}
 \alias{limits}
@@ -9,7 +9,7 @@ limits(lims, var)
 \arguments{
 \item{var}{name of variable}
 
-\item{limts}{vector of limits}
+\item{limits}{vector of limits}
 }
 \description{
 Generate correct scale type for specified limits
diff --git a/man/xylim.Rd b/man/lims.Rd
similarity index 51%
rename from man/xylim.Rd
rename to man/lims.Rd
index 93e5ec7..8894f10 100644
--- a/man/xylim.Rd
+++ b/man/lims.Rd
@@ -1,17 +1,21 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/limits.r
-\name{xlim}
+\name{lims}
+\alias{lims}
 \alias{xlim}
 \alias{ylim}
-\title{Convenience functions to set the limits of the x and y axis.}
+\title{Convenience functions to set the axis limits.}
 \usage{
+lims(...)
+
 xlim(...)
 
 ylim(...)
 }
 \arguments{
-\item{...}{if numeric, will create a continuous scale, if factor or
-character, will create a discrete scale.}
+\item{...}{If numeric, will create a continuous scale, if factor or
+character, will create a discrete scale.  For \code{lims}, every
+argument must be named.}
 }
 \description{
 Observations not in this range will be dropped completely and
@@ -24,17 +28,19 @@ xlim(15, 20)
 xlim(20, 15)
 xlim(c(10, 20))
 xlim("a", "b", "c")
-qplot(mpg, wt, data=mtcars) + xlim(15, 20)
+
+ggplot(mtcars, aes(mpg, wt)) +
+  geom_point() +
+  xlim(15, 20)
 # with automatic lower limit
-qplot(mpg, wt, data=mtcars) + xlim(NA, 20)
+ggplot(mtcars, aes(mpg, wt)) +
+  geom_point() +
+  xlim(NA, 20)
 
-# ylim
-ylim(15, 20)
-ylim(c(10, 20))
-ylim("a", "b", "c")
-qplot(mpg, wt, data=mtcars) + ylim(0, 4)
-# with automatic upper limit
-qplot(mpg, wt, data=mtcars) + ylim(0, NA)
+# Change both xlim and ylim
+ggplot(mtcars, aes(mpg, wt)) +
+  geom_point() +
+  lims(x = c(10, 20), y = c(3, 5))
 }
 \seealso{
 For changing x or y axis limits \strong{without} dropping data
diff --git a/man/luv_colours.Rd b/man/luv_colours.Rd
new file mode 100644
index 0000000..f36ca05
--- /dev/null
+++ b/man/luv_colours.Rd
@@ -0,0 +1,19 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/data.R
+\docType{data}
+\name{luv_colours}
+\alias{luv_colours}
+\title{\code{colors()} in Luv space.}
+\format{A data frame with 657 observations and 4 variables:
+\itemize{
+\item{L,u,v}{Position in Luv colour space}
+\item{col}{Colour name}
+}}
+\usage{
+luv_colours
+}
+\description{
+All built-in \code{\link{colors}()} translated into Luv colour space.
+}
+\keyword{datasets}
+
diff --git a/man/map_data.Rd b/man/map_data.Rd
index 7115c38..f73b6ae 100644
--- a/man/map_data.Rd
+++ b/man/map_data.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/fortify-map.r
 \name{map_data}
 \alias{map_data}
@@ -34,10 +34,13 @@ arrests$region <- tolower(rownames(USArrests))
 
 choro <- merge(states, arrests, sort = FALSE, by = "region")
 choro <- choro[order(choro$order), ]
-qplot(long, lat, data = choro, group = group, fill = assault,
-  geom = "polygon")
-qplot(long, lat, data = choro, group = group, fill = assault / murder,
-  geom = "polygon")
+ggplot(choro, aes(long, lat)) +
+  geom_polygon(aes(group = group, fill = assault)) +
+  coord_map("albers",  at0 = 45.5, lat1 = 29.5)
+
+ggplot(choro, aes(long, lat)) +
+  geom_polygon(aes(group = group, fill = assault / murder)) +
+  coord_map("albers",  at0 = 45.5, lat1 = 29.5)
 }
 }
 
diff --git a/man/margin.Rd b/man/margin.Rd
new file mode 100644
index 0000000..ed5dc1c
--- /dev/null
+++ b/man/margin.Rd
@@ -0,0 +1,24 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/margins.R
+\name{margin}
+\alias{margin}
+\title{Define margins.}
+\usage{
+margin(t = 0, r = 0, b = 0, l = 0, unit = "pt")
+}
+\arguments{
+\item{t, b, r, l}{Dimensions of each margin. (To remember order, think trouble).}
+
+\item{unit}{Default units of dimensions. Defaults to "pt" so it
+can be most easily scaled with the text.}
+}
+\description{
+This is a convenience function that creates a grid unit object of the
+correct length to use for setting margins.
+}
+\examples{
+margin(4)
+margin(4, 2)
+margin(4, 3, 2, 1)
+}
+
diff --git a/man/mean_se.Rd b/man/mean_se.Rd
index 6acd71b..b0a0d25 100644
--- a/man/mean_se.Rd
+++ b/man/mean_se.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/stat-summary.r
 \name{mean_se}
 \alias{mean_se}
diff --git a/man/midwest.Rd b/man/midwest.Rd
index 4e83983..adce5e7 100644
--- a/man/midwest.Rd
+++ b/man/midwest.Rd
@@ -1,19 +1,10 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/ggplot2.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/data.R
 \docType{data}
 \name{midwest}
 \alias{midwest}
 \title{Midwest demographics.}
-\format{A data frame with 437 rows and 28 variables}
-\usage{
-data(midwest)
-}
-\description{
-Demographic information of midwest counties
-}
-\details{
-The variables are as follows:
-
+\format{A data frame with 437 rows and 28 variables
 \itemize{
  \item PID
  \item county
@@ -43,7 +34,12 @@ The variables are as follows:
  \item percelderlypoverty
  \item inmetro.  In a metro area.
  \item category'
+}}
+\usage{
+midwest
 }
+\description{
+Demographic information of midwest counties
 }
 \keyword{datasets}
 
diff --git a/man/movies.Rd b/man/movies.Rd
deleted file mode 100644
index b69b8c1..0000000
--- a/man/movies.Rd
+++ /dev/null
@@ -1,39 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/ggplot2.r
-\docType{data}
-\name{movies}
-\alias{movies}
-\title{Movie information and user ratings from IMDB.com.}
-\format{A data frame with 28819 rows and 24 variables}
-\usage{
-data(movies)
-}
-\description{
-The internet movie database, \url{http://imdb.com/}, is a website devoted
-to collecting movie data supplied by studios and fans.  It claims to be the
-biggest movie database on the web and is run by amazon.  More about
-information imdb.com can be found online,
-\url{http://imdb.com/help/show_leaf?about}, including information about
-the data collection process,
-\url{http://imdb.com/help/show_leaf?infosource}.
-}
-\details{
-Movies were selected for inclusion if they had a known length and had been rated by at least one imdb user.  The data set contains the following fields:
-
-\itemize{
-  \item title.  Title of the movie.
-  \item year.  Year of release.
-  \item budget.  Total budget (if known) in US dollars
-  \item length.  Length in minutes.
-  \item rating.  Average IMDB user rating.
-  \item votes.  Number of IMDB users who rated this movie.
-  \item r1-10.  Multiplying by ten gives percentile (to nearest 10\%) of users who rated this movie a 1.
-  \item mpaa.  MPAA rating.
-  \item action, animation, comedy, drama, documentary, romance, short.  Binary variables representing if movie was classified as belonging to that genre.
-}
-}
-\references{
-\url{http://had.co.nz/data/movies/}
-}
-\keyword{datasets}
-
diff --git a/man/mpg.Rd b/man/mpg.Rd
index 51b3936..5cd4935 100644
--- a/man/mpg.Rd
+++ b/man/mpg.Rd
@@ -1,20 +1,10 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/ggplot2.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/data.R
 \docType{data}
 \name{mpg}
 \alias{mpg}
 \title{Fuel economy data from 1999 and 2008 for 38 popular models of car}
-\format{A data frame with 234 rows and 11 variables}
-\usage{
-data(mpg)
-}
-\description{
-This dataset contains a subset of the fuel economy data that the EPA makes
-available on \url{http://fueleconomy.gov}.  It contains only models which
-had a new release every year between 1999 and 2008 - this was used as a
-proxy for the popularity of the car.
-}
-\details{
+\format{A data frame with 234 rows and 11 variables
 \itemize{
   \item manufacturer.
   \item model.
@@ -27,7 +17,15 @@ proxy for the popularity of the car.
   \item hwy. highway miles per gallon
   \item fl.
   \item class.
+}}
+\usage{
+mpg
 }
+\description{
+This dataset contains a subset of the fuel economy data that the EPA makes
+available on \url{http://fueleconomy.gov}. It contains only models which
+had a new release every year between 1999 and 2008 - this was used as a
+proxy for the popularity of the car.
 }
 \keyword{datasets}
 
diff --git a/man/msleep.Rd b/man/msleep.Rd
index 2ca1404..b453719 100644
--- a/man/msleep.Rd
+++ b/man/msleep.Rd
@@ -1,24 +1,10 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/ggplot2.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/data.R
 \docType{data}
 \name{msleep}
 \alias{msleep}
 \title{An updated and expanded version of the mammals sleep dataset.}
-\format{A data frame with 83 rows and 11 variables}
-\usage{
-data(msleep)
-}
-\description{
-This is an updated and expanded version of the mammals sleep dataset.
-Updated sleep times and weights were taken from V. M. Savage and G. B.
-West. A quantitative, theoretical framework for understanding mammalian
-sleep. Proceedings of the National Academy of Sciences, 104 (3):1051-1056,
-2007.
-}
-\details{
-Additional variables order, conservation status and vore were added from
-wikipedia.
-
+\format{A data frame with 83 rows and 11 variables
 \itemize{
   \item name. common name
   \item genus.
@@ -31,7 +17,20 @@ wikipedia.
   \item awake. amount of time spent awake, in hours
   \item brainwt. brain weight in kilograms
   \item bodywt. body weight in kilograms
+}}
+\usage{
+msleep
+}
+\description{
+This is an updated and expanded version of the mammals sleep dataset.
+Updated sleep times and weights were taken from V. M. Savage and G. B.
+West. A quantitative, theoretical framework for understanding mammalian
+sleep. Proceedings of the National Academy of Sciences, 104 (3):1051-1056,
+2007.
 }
+\details{
+Additional variables order, conservation status and vore were added from
+wikipedia.
 }
 \keyword{datasets}
 
diff --git a/man/opts.Rd b/man/opts.Rd
deleted file mode 100644
index 7fe4054..0000000
--- a/man/opts.Rd
+++ /dev/null
@@ -1,15 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/theme.r
-\name{opts}
-\alias{opts}
-\title{Build a theme (or partial theme) from theme elements}
-\usage{
-opts(...)
-}
-\arguments{
-\item{...}{Arguments to be passed on to the \code{theme} function.}
-}
-\description{
-\code{opts} is deprecated. See the \code{\link{theme}} function.
-}
-
diff --git a/man/plot-templates.Rd b/man/plot-templates.Rd
deleted file mode 100644
index 34dc09c..0000000
--- a/man/plot-templates.Rd
+++ /dev/null
@@ -1,32 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/templates.r
-\name{plot-templates}
-\alias{ggfluctuation}
-\alias{ggmissing}
-\alias{ggorder}
-\alias{ggpcp}
-\alias{ggstructure}
-\alias{plot-templates}
-\alias{plotmatrix}
-\title{Plot templates.}
-\usage{
-ggpcp(data, vars = names(data), ...)
-
-ggfluctuation(table, type = "size", floor = 0, ceiling = max(table$freq,
-  na.rm = TRUE))
-
-ggmissing(data, avoid = "stack", order = TRUE, missing.only = TRUE)
-
-ggstructure(data)
-
-ggorder(data)
-
-plotmatrix(data, mapping = aes(), colour = "black")
-}
-\description{
-These plot templates are deprecated in an attempt to make ggplot2 as
-streamlined as possible, and to avoid bugs in these poorly tested
-functions. See the \pkg{GGally} package for some alternatives.
-}
-\keyword{internal}
-
diff --git a/man/position_dodge.Rd b/man/position_dodge.Rd
index 1ef7858..10c8466 100644
--- a/man/position_dodge.Rd
+++ b/man/position_dodge.Rd
@@ -1,50 +1,54 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/position-dodge.r
 \name{position_dodge}
 \alias{position_dodge}
 \title{Adjust position by dodging overlaps to the side.}
 \usage{
-position_dodge(width = NULL, height = NULL)
+position_dodge(width = NULL)
 }
 \arguments{
-\item{width}{Manually specify width (does not affect all position
-adjustments)}
-
-\item{height}{Manually specify height (does not affect all position
-adjustments)}
+\item{width}{Dodging width, when different to the width of the individual
+elements. This is useful when you want to align narrow geoms with wider
+geoms. See the examples for a use case.}
 }
 \description{
 Adjust position by dodging overlaps to the side.
 }
 \examples{
+ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) +
+  geom_bar(position = "dodge")
 \donttest{
-ggplot(mtcars, aes(x=factor(cyl), fill=factor(vs))) +
-  geom_bar(position="dodge")
-ggplot(diamonds, aes(x=price, fill=cut)) + geom_bar(position="dodge")
+ggplot(diamonds, aes(price, fill = cut)) +
+  geom_histogram(position="dodge")
 # see ?geom_boxplot and ?geom_bar for more examples
 
-# Dodging things with different widths is tricky
-df <- data.frame(x=c("a","a","b","b"), y=1:4, g = rep(1:2, 2))
-(p <- qplot(x, y, data=df, group=g, position="dodge", geom="bar",
-  stat="identity"))
+# To dodge items with different widths, you need to be explicit
+df <- data.frame(x=c("a","a","b","b"), y=2:5, g = rep(1:2, 2))
+p <- ggplot(df, aes(x, y, group = g)) +
+  geom_bar(
+    stat = "identity", position = "dodge",
+    fill = "grey50", colour = "black"
+  )
+p
 
-p + geom_linerange(aes(ymin = y-1, ymax = y+1), position="dodge")
+# A line range has no width:
+p + geom_linerange(aes(ymin = y-1, ymax = y+1), position = "dodge")
 # You need to explicitly specify the width for dodging
 p + geom_linerange(aes(ymin = y-1, ymax = y+1),
   position = position_dodge(width = 0.9))
 
 # Similarly with error bars:
 p + geom_errorbar(aes(ymin = y-1, ymax = y+1), width = 0.2,
-  position="dodge")
+  position = "dodge")
 p + geom_errorbar(aes(ymin = y-1, ymax = y+1, width = 0.2),
   position = position_dodge(width = 0.90))
 }
 }
 \seealso{
-Other position adjustments: \code{\link{position_fill}};
-  \code{\link{position_identity}};
-  \code{\link{position_jitterdodge}};
-  \code{\link{position_jitter}};
-  \code{\link{position_stack}}
+Other position adjustments: \code{\link{position_fill}},
+  \code{\link{position_identity}},
+  \code{\link{position_jitterdodge}},
+  \code{\link{position_jitter}},
+  \code{\link{position_nudge}}
 }
 
diff --git a/man/position_fill.Rd b/man/position_fill.Rd
deleted file mode 100644
index 7e6b5cb..0000000
--- a/man/position_fill.Rd
+++ /dev/null
@@ -1,45 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/position-fill.r
-\name{position_fill}
-\alias{position_fill}
-\title{Stack overlapping objects on top of one another, and standardise to have
-equal height.}
-\usage{
-position_fill(width = NULL, height = NULL)
-}
-\arguments{
-\item{width}{Manually specify width (does not affect all position
-adjustments)}
-
-\item{height}{Manually specify height (does not affect all position
-adjustments)}
-}
-\description{
-Stack overlapping objects on top of one another, and standardise to have
-equal height.
-}
-\examples{
-\donttest{
-# See ?geom_bar and ?geom_area for more examples
-ggplot(mtcars, aes(x=factor(cyl), fill=factor(vs))) +
-  geom_bar(position="fill")
-
-cde <- geom_histogram(position="fill", binwidth = 500)
-
-ggplot(diamonds, aes(x=price)) + cde
-ggplot(diamonds, aes(x=price, fill=cut)) + cde
-ggplot(diamonds, aes(x=price, fill=clarity)) + cde
-ggplot(diamonds, aes(x=price, fill=color)) + cde
-}
-}
-\seealso{
-See \code{\link{geom_bar}} and \code{\link{geom_area}} for
-  more examples.
-
-Other position adjustments: \code{\link{position_dodge}};
-  \code{\link{position_identity}};
-  \code{\link{position_jitterdodge}};
-  \code{\link{position_jitter}};
-  \code{\link{position_stack}}
-}
-
diff --git a/man/position_identity.Rd b/man/position_identity.Rd
index eb2d4b1..d15fe2c 100644
--- a/man/position_identity.Rd
+++ b/man/position_identity.Rd
@@ -1,26 +1,19 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/position-identity.r
 \name{position_identity}
 \alias{position_identity}
 \title{Don't adjust position}
 \usage{
-position_identity(width = NULL, height = NULL)
-}
-\arguments{
-\item{width}{Manually specify width (does not affect all position
-adjustments)}
-
-\item{height}{Manually specify height (does not affect all position
-adjustments)}
+position_identity()
 }
 \description{
 Don't adjust position
 }
 \seealso{
-Other position adjustments: \code{\link{position_dodge}};
-  \code{\link{position_fill}};
-  \code{\link{position_jitterdodge}};
-  \code{\link{position_jitter}};
-  \code{\link{position_stack}}
+Other position adjustments: \code{\link{position_dodge}},
+  \code{\link{position_fill}},
+  \code{\link{position_jitterdodge}},
+  \code{\link{position_jitter}},
+  \code{\link{position_nudge}}
 }
 
diff --git a/man/position_jitter.Rd b/man/position_jitter.Rd
index ec755e6..8676fbd 100644
--- a/man/position_jitter.Rd
+++ b/man/position_jitter.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/position-jitter.r
 \name{position_jitter}
 \alias{position_jitter}
@@ -7,37 +7,42 @@
 position_jitter(width = NULL, height = NULL)
 }
 \arguments{
-\item{width}{degree of jitter in x direction. Defaults to 40\% of the
-resolution of the data.}
+\item{width, height}{Amount of vertical and horizontal jitter. The jitter
+  is added in both positive and negative directions, so the total spread
+  is twice the value specified here.
 
-\item{height}{degree of jitter in y direction. Defaults to 40\% of the
-resolution of the data}
+  If omitted, defaults to 40\% of the resolution of the data: this means the
+  jitter values will occupy 80\% of the implied bins. Categorical data
+  is aligned on the integers, so a width or height of 0.5 will spread the
+  data so it's not possible to see the distinction between the categories.}
 }
 \description{
 Jitter points to avoid overplotting.
 }
 \examples{
-qplot(am, vs, data = mtcars)
+ggplot(mtcars, aes(am, vs)) + geom_point()
 
 # Default amount of jittering will generally be too much for
 # small datasets:
-qplot(am, vs, data = mtcars, position = "jitter")
-# Control the amount as follows
-qplot(am, vs, data = mtcars, position = position_jitter(w = 0.1, h = 0.1))
+ggplot(mtcars, aes(am, vs)) + geom_jitter()
 
-# With ggplot
-ggplot(mtcars, aes(x = am, y = vs)) + geom_point(position = "jitter")
-ggplot(mtcars, aes(x = am, y = vs)) + geom_point(position = position_jitter(w = 0.1, h = 0.1))
+# Two ways to override
+ggplot(mtcars, aes(am, vs)) +
+  geom_jitter(width = 0.1, height = 0.1)
+ggplot(mtcars, aes(am, vs)) +
+  geom_jitter(position = position_jitter(width = 0.1, height = 0.1))
 
 # The default works better for large datasets, where it will
 # take up as much space as a boxplot or a bar
-qplot(class, hwy, data = mpg, geom = c("boxplot", "jitter"))
+ggplot(mpg, aes(class, hwy)) +
+  geom_jitter() +
+  geom_boxplot()
 }
 \seealso{
-Other position adjustments: \code{\link{position_dodge}};
-  \code{\link{position_fill}};
-  \code{\link{position_identity}};
-  \code{\link{position_jitterdodge}};
-  \code{\link{position_stack}}
+Other position adjustments: \code{\link{position_dodge}},
+  \code{\link{position_fill}},
+  \code{\link{position_identity}},
+  \code{\link{position_jitterdodge}},
+  \code{\link{position_nudge}}
 }
 
diff --git a/man/position_jitterdodge.Rd b/man/position_jitterdodge.Rd
index 6134366..c792ccf 100644
--- a/man/position_jitterdodge.Rd
+++ b/man/position_jitterdodge.Rd
@@ -1,11 +1,11 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/position-jitterdodge.R
 \name{position_jitterdodge}
 \alias{position_jitterdodge}
 \title{Adjust position by simultaneously dodging and jittering}
 \usage{
-position_jitterdodge(jitter.width = NULL, jitter.height = NULL,
-  dodge.width = NULL)
+position_jitterdodge(jitter.width = NULL, jitter.height = 0,
+  dodge.width = 0.75)
 }
 \arguments{
 \item{jitter.width}{degree of jitter in x direction. Defaults to 40\% of the
@@ -28,10 +28,10 @@ ggplot(dsub, aes(x = cut, y = carat, fill = clarity)) +
   geom_point(pch = 21, position = position_jitterdodge())
 }
 \seealso{
-Other position adjustments: \code{\link{position_dodge}};
-  \code{\link{position_fill}};
-  \code{\link{position_identity}};
-  \code{\link{position_jitter}};
-  \code{\link{position_stack}}
+Other position adjustments: \code{\link{position_dodge}},
+  \code{\link{position_fill}},
+  \code{\link{position_identity}},
+  \code{\link{position_jitter}},
+  \code{\link{position_nudge}}
 }
 
diff --git a/man/position_nudge.Rd b/man/position_nudge.Rd
new file mode 100644
index 0000000..fee17cd
--- /dev/null
+++ b/man/position_nudge.Rd
@@ -0,0 +1,37 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/position-nudge.R
+\name{position_nudge}
+\alias{position_nudge}
+\title{Nudge points.}
+\usage{
+position_nudge(x = 0, y = 0)
+}
+\arguments{
+\item{x, y}{Amount of vertical and horizontal distance to move.}
+}
+\description{
+This is useful if you want to nudge labels a little ways from their
+points.
+}
+\examples{
+df <- data.frame(
+  x = c(1,3,2,5),
+  y = c("a","c","d","c")
+)
+
+ggplot(df, aes(x, y)) +
+  geom_point() +
+  geom_text(aes(label = y))
+
+ggplot(df, aes(x, y)) +
+  geom_point() +
+  geom_text(aes(label = y), position = position_nudge(y = -0.1))
+}
+\seealso{
+Other position adjustments: \code{\link{position_dodge}},
+  \code{\link{position_fill}},
+  \code{\link{position_identity}},
+  \code{\link{position_jitterdodge}},
+  \code{\link{position_jitter}}
+}
+
diff --git a/man/position_stack.Rd b/man/position_stack.Rd
index a655a34..6bbde03 100644
--- a/man/position_stack.Rd
+++ b/man/position_stack.Rd
@@ -1,31 +1,35 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/position-stack.r
-\name{position_stack}
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/position-fill.r, R/position-stack.r
+\name{position_fill}
+\alias{position_fill}
 \alias{position_stack}
 \title{Stack overlapping objects on top of one another.}
 \usage{
-position_stack(width = NULL, height = NULL)
-}
-\arguments{
-\item{width}{Manually specify width (does not affect all position
-adjustments)}
+position_fill()
 
-\item{height}{Manually specify height (does not affect all position
-adjustments)}
+position_stack()
 }
 \description{
-Stack overlapping objects on top of one another.
+\code{position_fill} additionally standardises each stack to have unit
+height.
 }
 \examples{
 # Stacking is the default behaviour for most area plots:
 ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) + geom_bar()
+# Fill makes it easier to compare proportions
+ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) +
+  geom_bar(position = "fill")
 
 # To change stacking order, use factor() to change order of levels
 mtcars$vs <- factor(mtcars$vs, levels = c(1,0))
 ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) + geom_bar()
 
-ggplot(diamonds, aes(price)) + geom_histogram(binwidth=500)
-ggplot(diamonds, aes(price, fill = cut)) + geom_histogram(binwidth=500)
+ggplot(diamonds, aes(price, fill = cut)) +
+  geom_histogram(binwidth = 500)
+# When used with a histogram, position_fill creates a conditional density
+# estimate
+ggplot(diamonds, aes(price, fill = cut)) +
+  geom_histogram(binwidth = 500, position = "fill")
 
 # Stacking is also useful for time series
 data.set <- data.frame(
@@ -34,19 +38,24 @@ data.set <- data.frame(
   Value = rpois(16, 10)
 )
 
-qplot(Time, Value, data = data.set, fill = Type, geom = "area")
+ggplot(data.set, aes(Time, Value)) + geom_area(aes(fill = Type))
+
 # If you want to stack lines, you need to say so:
-qplot(Time, Value, data = data.set, colour = Type, geom = "line")
-qplot(Time, Value, data = data.set, colour = Type, geom = "line",
-  position = "stack")
+ggplot(data.set, aes(Time, Value)) + geom_line(aes(colour = Type))
+ggplot(data.set, aes(Time, Value)) +
+  geom_line(position = "stack", aes(colour = Type))
+
 # But realise that this makes it *much* harder to compare individual
 # trends
 }
 \seealso{
-Other position adjustments: \code{\link{position_dodge}};
-  \code{\link{position_fill}};
-  \code{\link{position_identity}};
-  \code{\link{position_jitterdodge}};
-  \code{\link{position_jitter}}
+See \code{\link{geom_bar}} and \code{\link{geom_area}} for
+  more examples.
+
+Other position adjustments: \code{\link{position_dodge}},
+  \code{\link{position_identity}},
+  \code{\link{position_jitterdodge}},
+  \code{\link{position_jitter}},
+  \code{\link{position_nudge}}
 }
 
diff --git a/man/presidential.Rd b/man/presidential.Rd
index a9b1bcb..53f5243 100644
--- a/man/presidential.Rd
+++ b/man/presidential.Rd
@@ -1,12 +1,12 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/ggplot2.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/data.R
 \docType{data}
 \name{presidential}
 \alias{presidential}
 \title{Terms of 10 presidents from Eisenhower to Bush W.}
 \format{A data frame with 10 rows and 4 variables}
 \usage{
-data(presidential)
+presidential
 }
 \description{
 The names of each president, the start and end date of their term, and
diff --git a/man/print.ggplot.Rd b/man/print.ggplot.Rd
index 55c5b40..ce6a8f1 100644
--- a/man/print.ggplot.Rd
+++ b/man/print.ggplot.Rd
@@ -1,5 +1,5 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/plot-render.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/plot.r
 \name{print.ggplot}
 \alias{plot.ggplot}
 \alias{print.ggplot}
@@ -18,6 +18,11 @@
 
 \item{...}{other arguments not used by this method}
 }
+\value{
+Invisibly returns the result of \code{\link{ggplot_build}}, which
+  is a list with components that contain the plot itself, the data,
+  information about the scales, panels etc.
+}
 \description{
 Draw plot on current graphics device.
 }
diff --git a/man/print.ggproto.Rd b/man/print.ggproto.Rd
new file mode 100644
index 0000000..273236d
--- /dev/null
+++ b/man/print.ggproto.Rd
@@ -0,0 +1,23 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/ggproto.r
+\name{print.ggproto}
+\alias{print.ggproto}
+\title{Print a ggproto object}
+\usage{
+\method{print}{ggproto}(x, ..., flat = TRUE)
+}
+\arguments{
+\item{x}{A ggproto object to print.}
+
+\item{...}{If the ggproto object has a \code{print} method, further arguments
+will be passed to it. Otherwise, these arguments are unused.}
+
+\item{flat}{If \code{TRUE} (the default), show a flattened list of all local
+and inherited members. If \code{FALSE}, show the inheritance hierarchy.}
+}
+\description{
+If a ggproto object has a \code{$print} method, this will call that method.
+Otherwise, it will print out the members of the object, and optionally, the
+members of the inherited objects.
+}
+
diff --git a/man/qplot.Rd b/man/qplot.Rd
index 54db5a8..dbe1241 100644
--- a/man/qplot.Rd
+++ b/man/qplot.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/quick-plot.r
 \name{qplot}
 \alias{qplot}
@@ -6,80 +6,59 @@
 \title{Quick plot}
 \usage{
 qplot(x, y = NULL, ..., data, facets = NULL, margins = FALSE,
-  geom = "auto", stat = list(NULL), position = list(NULL), xlim = c(NA,
-  NA), ylim = c(NA, NA), log = "", main = NULL,
-  xlab = deparse(substitute(x)), ylab = deparse(substitute(y)), asp = NA)
+  geom = "auto", xlim = c(NA, NA), ylim = c(NA, NA), log = "",
+  main = NULL, xlab = deparse(substitute(x)),
+  ylab = deparse(substitute(y)), asp = NA, stat = NULL, position = NULL)
+
+quickplot(x, y = NULL, ..., data, facets = NULL, margins = FALSE,
+  geom = "auto", xlim = c(NA, NA), ylim = c(NA, NA), log = "",
+  main = NULL, xlab = deparse(substitute(x)),
+  ylab = deparse(substitute(y)), asp = NA, stat = NULL, position = NULL)
 }
 \arguments{
-\item{x}{x values}
+\item{x, y, ...}{Aesthetics passed into each layer}
 
-\item{y}{y values}
-
-\item{...}{other aesthetics passed for each layer}
-
-\item{data}{data frame to use (optional).  If not specified, will create
+\item{data}{Data frame to use (optional).  If not specified, will create
 one, extracting vectors from the current environment.}
 
-\item{facets}{faceting formula to use.  Picks \code{\link{facet_wrap}} or
-\code{\link{facet_grid}} depending on whether the formula is one sided
+\item{facets}{faceting formula to use. Picks \code{\link{facet_wrap}} or
+\code{\link{facet_grid}} depending on whether the formula is one-
 or two-sided}
 
-\item{margins}{whether or not margins will be displayed}
+\item{margins}{See \code{facet_grid}: display marginal facets?}
 
-\item{geom}{character vector specifying geom to use.  Defaults to
+\item{geom}{Character vector specifying geom(s) to draw. Defaults to
 "point" if x and y are specified, and "histogram" if only x is specified.}
 
-\item{stat}{character vector specifying statistics to use}
-
-\item{position}{character vector giving position adjustment to use}
-
-\item{xlim}{limits for x axis}
-
-\item{ylim}{limits for y axis}
+\item{xlim, ylim}{X and y axis limits}
 
-\item{log}{which variables to log transform ("x", "y", or "xy")}
+\item{log}{Which variables to log transform ("x", "y", or "xy")}
 
-\item{main}{character vector or expression for plot title}
+\item{main, xlab, ylab}{Character vector (or expression) giving plot title,
+x axis label, and y axis label respectively.}
 
-\item{xlab}{character vector or expression for x axis label}
+\item{asp}{The y/x aspect ratio}
 
-\item{ylab}{character vector or expression for y axis label}
-
-\item{asp}{the y/x aspect ratio}
+\item{stat, position}{DEPRECATED.}
 }
 \description{
 \code{qplot} is the basic plotting function in the ggplot2 package,
-designed to be familiar if you're used to \code{\link{plot}}
-from the base package. It is a convenient wrapper for creating
-a number of different types of plots using a consistent
-calling scheme. See \url{http://had.co.nz/ggplot2/book/qplot.pdf}
-for the chapter in the \code{ggplot2} book which describes the usage
-of \code{qplot} in detail.
+designed to be familiar if you're used to base \code{\link{plot}()}.
+It's a convenient wrapper for creating a number of different types of plots
+using a consistent calling scheme.
 }
 \examples{
-\donttest{
 # Use data from data.frame
-qplot(mpg, wt, data=mtcars)
-qplot(mpg, wt, data=mtcars, colour=cyl)
-qplot(mpg, wt, data=mtcars, size=cyl)
-qplot(mpg, wt, data=mtcars, facets=vs ~ am)
-
-# It will use data from local environment
-hp <- mtcars$hp
-wt <- mtcars$wt
-cyl <- mtcars$cyl
-vs <- mtcars$vs
-am <- mtcars$am
-qplot(hp, wt)
-qplot(hp, wt, colour=cyl)
-qplot(hp, wt, size=cyl)
-qplot(hp, wt, facets=vs ~ am)
+qplot(mpg, wt, data = mtcars)
+qplot(mpg, wt, data = mtcars, colour = cyl)
+qplot(mpg, wt, data = mtcars, size = cyl)
+qplot(mpg, wt, data = mtcars, facets = vs ~ am)
 
+\donttest{
 qplot(1:10, rnorm(10), colour = runif(10))
 qplot(1:10, letters[1:10])
 mod <- lm(mpg ~ wt, data=mtcars)
 qplot(resid(mod), fitted(mod))
-qplot(resid(mod), fitted(mod), facets = . ~ vs)
 
 f <- function() {
    a <- 1:10
@@ -88,6 +67,9 @@ f <- function() {
 }
 f()
 
+# To set aesthetics, wrap in I()
+qplot(mpg, wt, data = mtcars, colour = I("red"))
+
 # qplot will attempt to guess what geom you want depending on the input
 # both x and y supplied = scatterplot
 qplot(mpg, wt, data = mtcars)
@@ -97,8 +79,8 @@ qplot(mpg, data = mtcars)
 qplot(y = mpg, data = mtcars)
 
 # Use different geoms
-qplot(mpg, wt, data = mtcars, geom="path")
-qplot(factor(cyl), wt, data = mtcars, geom=c("boxplot", "jitter"))
+qplot(mpg, wt, data = mtcars, geom = "path")
+qplot(factor(cyl), wt, data = mtcars, geom = c("boxplot", "jitter"))
 qplot(mpg, data = mtcars, geom = "dotplot")
 }
 }
diff --git a/man/reexports.Rd b/man/reexports.Rd
new file mode 100644
index 0000000..d83c0f6
--- /dev/null
+++ b/man/reexports.Rd
@@ -0,0 +1,27 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/utilities.r, R/utilities-grid.r
+\docType{import}
+\name{reexports}
+\alias{alpha}
+\alias{arrow}
+\alias{reexports}
+\alias{unit}
+\title{Objects exported from other packages}
+\description{
+These objects are imported from other packages. Follow the links
+below to see their documentation.
+
+\describe{
+  \item{grid}{\code{\link[grid]{unit}}, \code{\link[grid]{arrow}}}
+
+  \item{scales}{\code{\link[scales]{alpha}}}
+}}
+\examples{
+ggplot(mpg, aes(displ, hwy)) +
+  geom_point(alpha = 0.5, colour = "blue")
+
+ggplot(mpg, aes(displ, hwy)) +
+  geom_point(colour = alpha("blue", 0.5))
+}
+\keyword{internal}
+
diff --git a/man/rel.Rd b/man/rel.Rd
index 6e7ae30..8728154 100644
--- a/man/rel.Rd
+++ b/man/rel.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/theme-elements.r
 \name{rel}
 \alias{rel}
@@ -13,6 +13,9 @@ rel(x)
 Relative sizing for theme elements
 }
 \examples{
-qplot(1:3, 1:3) + theme(axis.title.x = element_text(size = rel(2.5)))
+df <- data.frame(x = 1:3, y = 1:3)
+ggplot(df, aes(x, y)) +
+  geom_point() +
+  theme(axis.title.x = element_text(size = rel(2.5)))
 }
 
diff --git a/man/remove_missing.Rd b/man/remove_missing.Rd
new file mode 100644
index 0000000..4748e78
--- /dev/null
+++ b/man/remove_missing.Rd
@@ -0,0 +1,29 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/utilities.r
+\name{remove_missing}
+\alias{remove_missing}
+\title{Convenience function to remove missing values from a data.frame}
+\usage{
+remove_missing(df, na.rm = FALSE, vars = names(df), name = "",
+  finite = FALSE)
+}
+\arguments{
+\item{df}{data.frame}
+
+\item{na.rm}{If true, will suppress warning message.}
+
+\item{vars}{Character vector of variables to check for missings in}
+
+\item{name}{Optional function name to improve error message.}
+
+\item{finite}{If \code{TRUE}, will also remove non-finite values.}
+}
+\description{
+Remove all non-complete rows, with a warning if \code{na.rm = FALSE}.
+ggplot is somewhat more accommodating of missing values than R generally.
+For those stats which require complete data, missing values will be
+automatically removed with a warning. If \code{na.rm = TRUE} is supplied
+to the statistic, the warning will be suppressed.
+}
+\keyword{internal}
+
diff --git a/man/resolution.Rd b/man/resolution.Rd
index 32f5fb3..be2e1dd 100644
--- a/man/resolution.Rd
+++ b/man/resolution.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/utilities-resolution.r
 \name{resolution}
 \alias{resolution}
diff --git a/man/rweave.Rd b/man/rweave.Rd
deleted file mode 100644
index 76c6b48..0000000
--- a/man/rweave.Rd
+++ /dev/null
@@ -1,19 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/utilities-matrix.r
-\name{rweave}
-\alias{rweave}
-\title{Row weave.}
-\usage{
-rweave(...)
-}
-\arguments{
-\item{...}{matrices to weave together}
-}
-\description{
-Weave together two (or more) matrices by row.
-}
-\details{
-Matrices must have same dimensions.
-}
-\keyword{internal}
-
diff --git a/man/scale_alpha.Rd b/man/scale_alpha.Rd
index b956708..8da57a0 100644
--- a/man/scale_alpha.Rd
+++ b/man/scale_alpha.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/scale-alpha.r
 \name{scale_alpha}
 \alias{scale_alpha}
@@ -24,13 +24,15 @@ breaks, labels and so forth.}
 that is the most common use of alpha, and it saves a bit of typing.
 }
 \examples{
-(p <- qplot(mpg, cyl, data = mtcars, alpha = cyl))
+(p <- ggplot(mtcars, aes(mpg, cyl)) +
+  geom_point(aes(alpha = cyl)))
 p + scale_alpha("cylinders")
 p + scale_alpha("number\\nof\\ncylinders")
 
 p + scale_alpha(range = c(0.4, 0.8))
 
-(p <- qplot(mpg, cyl, data=mtcars, alpha = factor(cyl)))
+(p <- ggplot(mtcars, aes(mpg, cyl)) +
+  geom_point(aes(alpha = factor(cyl))))
 p + scale_alpha_discrete(range = c(0.4, 0.8))
 }
 
diff --git a/man/scale_area.Rd b/man/scale_area.Rd
deleted file mode 100644
index 009a715..0000000
--- a/man/scale_area.Rd
+++ /dev/null
@@ -1,21 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/scale-area.r
-\name{scale_area}
-\alias{scale_area}
-\title{Scale area instead of radius (for size).}
-\usage{
-scale_area(..., range = c(1, 6))
-}
-\arguments{
-\item{...}{Other arguments passed on to \code{\link{continuous_scale}}
-to control name, limits, breaks, labels and so forth.}
-
-\item{range}{Range of output sizes.  Should be greater than 0.}
-}
-\description{
-\code{\link{scale_area}} is deprecated and will be removed in a future
-version of ggplot2. Use \code{\link{scale_size_area}} instead. Note that the
-default behavir of \code{\link{scale_size_area}} is slightly different: by
-default, it makes the area proportional to the numeric value.
-}
-
diff --git a/man/scale_brewer.Rd b/man/scale_brewer.Rd
index c0b0d7b..8814fb7 100644
--- a/man/scale_brewer.Rd
+++ b/man/scale_brewer.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/scale-brewer.r, R/zxx.r
 \name{scale_colour_brewer}
 \alias{scale_color_brewer}
@@ -9,20 +9,17 @@
 \alias{scale_fill_distiller}
 \title{Sequential, diverging and qualitative colour scales from colorbrewer.org}
 \usage{
-scale_colour_brewer(..., type = "seq", palette = 1)
+scale_colour_brewer(..., type = "seq", palette = 1, direction = 1)
 
-scale_fill_brewer(..., type = "seq", palette = 1)
+scale_fill_brewer(..., type = "seq", palette = 1, direction = 1)
 
-scale_colour_distiller(..., type = "seq", palette = 1, values = NULL,
-  space = "Lab", na.value = "grey50")
+scale_colour_distiller(..., type = "seq", palette = 1, direction = -1,
+  values = NULL, space = "Lab", na.value = "grey50",
+  guide = "colourbar")
 
-scale_fill_distiller(..., type = "seq", palette = 1, values = NULL,
-  space = "Lab", na.value = "grey50")
-
-scale_color_brewer(..., type = "seq", palette = 1)
-
-scale_color_distiller(..., type = "seq", palette = 1, values = NULL,
-  space = "Lab", na.value = "grey50")
+scale_fill_distiller(..., type = "seq", palette = 1, direction = -1,
+  values = NULL, space = "Lab", na.value = "grey50",
+  guide = "colourbar")
 }
 \arguments{
 \item{...}{Other arguments passed on to \code{\link{discrete_scale}}
@@ -33,15 +30,22 @@ to control name, limits, breaks, labels and so forth.}
 \item{palette}{If a string, will use that named palette.  If a number, will
 index into the list of palettes of appropriate \code{type}}
 
+\item{direction}{Sets the order of colors in the scale. If 1, the default,
+colors are as output by \code{\link[RColorBrewer]{brewer.pal}}. If -1, the
+order of colors is reversed.}
+
 \item{values}{if colours should not be evenly positioned along the gradient
 this vector gives the position (between 0 and 1) for each colour in the
 \code{colours} vector. See \code{\link{rescale}} for a convience function
 to map an arbitrary range to between 0 and 1.}
 
-\item{space}{colour space in which to calculate gradient.  "Lab" usually
-best unless gradient goes through white.}
+\item{space}{colour space in which to calculate gradient. Must be "Lab" -
+other values are deprecated.}
 
 \item{na.value}{Colour to use for missing values}
+
+\item{guide}{Type of legend. Use \code{"colourbar"} for continuous
+colour bar, or \code{"legend"} for discrete colour legend.}
 }
 \description{
 ColorBrewer provides sequential, diverging and qualitative colour schemes
@@ -52,69 +56,54 @@ continuous scale (6 colours per palette gives nice gradients; more results in
 more saturated colours which do not look as good). However, the original
 colour schemes (particularly the qualitative ones) were not intended for this
 and the perceptual result is left to the appreciation of the user.
-}
-\details{
 See \url{http://colorbrewer2.org} for more information.
 }
+\section{Palettes}{
+
+The following palettes are available for use with these scales:
+\describe{
+  \item{Diverging}{BrBG, PiYG, PRGn, PuOr, RdBu, RdGy, RdYlBu, RdYlGn, Spectral}
+  \item{Qualitative}{Accent, Dark2, Paired, Pastel1, Pastel2, Set1, Set2, Set3}
+  \item{Sequential}{Blues, BuGn, BuPu, GnBu, Greens, Greys, Oranges,
+     OrRd, PuBu, PuBuGn, PuRd, Purples, RdPu, Reds, YlGn, YlGnBu, YlOrBr, YlOrRd}
+}
+}
 \examples{
 dsamp <- diamonds[sample(nrow(diamonds), 1000), ]
-(d <- qplot(carat, price, data = dsamp, colour = clarity))
+(d <- ggplot(dsamp, aes(carat, price)) +
+  geom_point(aes(colour = clarity)))
 
 # Change scale label
 d + scale_colour_brewer()
-d + scale_colour_brewer("clarity")
-d + scale_colour_brewer(expression(clarity[beta]))
+d + scale_colour_brewer("Diamond\\nclarity")
 
 # Select brewer palette to use, see ?scales::brewer_pal for more details
-d + scale_colour_brewer(type = "seq")
-d + scale_colour_brewer(type = "seq", palette = 3)
-
-d + scale_colour_brewer(palette = "Blues")
+d + scale_colour_brewer(palette = "Greens")
 d + scale_colour_brewer(palette = "Set1")
 
+\donttest{
 # scale_fill_brewer works just the same as
 # scale_colour_brewer but for fill colours
-ggplot(diamonds, aes(x = price, fill = cut)) +
-  geom_histogram(position = "dodge", binwidth = 1000) +
-  scale_fill_brewer()
-
-# Generate map data
-library(reshape2) # for melt
-volcano3d <- melt(volcano)
-names(volcano3d) <- c("x", "y", "z")
+p <- ggplot(diamonds, aes(x = price, fill = cut)) +
+  geom_histogram(position = "dodge", binwidth = 1000)
+p + scale_fill_brewer()
+# the order of colour can be reversed
+p + scale_fill_brewer(direction = -1)
+# the brewer scales look better on a darker background
+p + scale_fill_brewer(direction = -1) + theme_dark()
+}
 
-# Basic plot
-v <- ggplot() + geom_tile(aes(x = x, y = y, fill = z), data = volcano3d)
+# Use distiller variant with continous data
+v <- ggplot(faithfuld) +
+  geom_tile(aes(waiting, eruptions, fill = density))
 v
 v + scale_fill_distiller()
-v + scale_fill_distiller(palette = 2)
-v + scale_fill_distiller(type = "div")
 v + scale_fill_distiller(palette = "Spectral")
-v + scale_fill_distiller(palette = "Spectral", trans = "reverse")
-v + scale_fill_distiller(type = "qual")
-# Not appropriate for continuous data, issues a warning
 }
 \seealso{
-Other colour scales: \code{\link{scale_color_continuous}},
-  \code{\link{scale_color_gradient}},
-  \code{\link{scale_colour_continuous}},
+Other colour scales:
   \code{\link{scale_colour_gradient}},
-  \code{\link{scale_fill_continuous}},
-  \code{\link{scale_fill_gradient}};
-  \code{\link{scale_color_discrete}},
-  \code{\link{scale_color_hue}},
-  \code{\link{scale_colour_discrete}},
-  \code{\link{scale_colour_hue}},
-  \code{\link{scale_fill_discrete}},
-  \code{\link{scale_fill_hue}};
-  \code{\link{scale_color_gradient2}},
-  \code{\link{scale_colour_gradient2}},
-  \code{\link{scale_fill_gradient2}};
-  \code{\link{scale_color_gradientn}},
-  \code{\link{scale_colour_gradientn}},
-  \code{\link{scale_fill_gradientn}};
-  \code{\link{scale_color_grey}},
   \code{\link{scale_colour_grey}},
-  \code{\link{scale_fill_grey}}
+  \code{\link{scale_colour_hue}}
 }
 
diff --git a/man/scale_continuous.Rd b/man/scale_continuous.Rd
index 8c4d2f5..9602800 100644
--- a/man/scale_continuous.Rd
+++ b/man/scale_continuous.Rd
@@ -1,6 +1,7 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/scale-continuous.r
-\name{scale_x_continuous}
+\name{scale_continuous}
+\alias{scale_continuous}
 \alias{scale_x_continuous}
 \alias{scale_x_log10}
 \alias{scale_x_reverse}
@@ -11,9 +12,15 @@
 \alias{scale_y_sqrt}
 \title{Continuous position scales (x & y).}
 \usage{
-scale_x_continuous(..., expand = waiver())
+scale_x_continuous(name = waiver(), breaks = waiver(),
+  minor_breaks = waiver(), labels = waiver(), limits = NULL,
+  expand = waiver(), oob = censor, na.value = NA_real_,
+  trans = "identity")
 
-scale_y_continuous(..., expand = waiver())
+scale_y_continuous(name = waiver(), breaks = waiver(),
+  minor_breaks = waiver(), labels = waiver(), limits = NULL,
+  expand = waiver(), oob = censor, na.value = NA_real_,
+  trans = "identity")
 
 scale_x_log10(...)
 
@@ -28,32 +35,85 @@ scale_x_sqrt(...)
 scale_y_sqrt(...)
 }
 \arguments{
-\item{...}{common continuous scale parameters: \code{name}, \code{breaks},
-\code{labels}, \code{na.value}, \code{limits} and \code{trans}.  See
-\code{\link{continuous_scale}} for more details}
-
-\item{expand}{a numeric vector of length two giving multiplicative and
+\item{name}{The name of the scale. Used as axis or legend title. If
+\code{NULL}, the default, the name of the scale is taken from the first
+mapping used for that aesthetic.}
+
+\item{breaks}{One of: \itemize{
+  \item \code{NULL} for no breaks
+  \item \code{waiver()} for the default breaks computed by the
+    transformation object
+  \item A numeric vector of positions
+  \item A function that takes the limits as input and returns breaks
+    as output
+}}
+
+\item{minor_breaks}{One of: \itemize{
+  \item \code{NULL} for no minor breaks
+  \item \code{waiver()} for the default breaks (one minor break between
+    each major break)
+  \item A numeric vector of positions
+  \item A function that given the limits returns a vector of minor breaks.
+}}
+
+\item{labels}{One of: \itemize{
+  \item \code{NULL} for no labels
+  \item \code{waiver()} for the default labels computed by the
+    transformation object
+  \item A character vector giving labels (must be same length as \code{breaks})
+  \item A function that takes the breaks as input and returns labels
+    as output
+}}
+
+\item{limits}{A numeric vector of length two providing limits of the scale.
+Use \code{NA} to refer to the existing minimum or maximum.}
+
+\item{expand}{A numeric vector of length two giving multiplicative and
 additive expansion constants. These constants ensure that the data is
-placed some distance away from the axes.}
+placed some distance away from the axes. The defaults are
+\code{c(0.05, 0)} for continuous variables, and \code{c(0, 0.6)} for
+discrete variables.}
+
+\item{oob}{Function that handles limits outside of the scale limits
+(out of bounds). The default replaces out of bounds values with NA.}
+
+\item{na.value}{Missing values will be replaced with this value.}
+
+\item{trans}{Either the name of a transformation object, or the
+  object itself. Built-in transformations include "asn", "atanh",
+  "boxcox", "exp", "identity", "log", "log10", "log1p", "log2",
+  "logit", "probability", "probit", "reciprocal", "reverse" and "sqrt".
+
+  A transformation object bundles together a transform, it's inverse,
+  and methods for generating breaks and labels. Transformation objects
+  are defined in the scales package, and are called \code{name_trans}, e.g.
+  \code{\link[scales]{boxcox_trans}}. You can create your own
+  transformation with \code{\link[scales]{trans_new}}.}
+
+\item{...}{Other arguments passed on to \code{scale_(x|y)_continuous}}
 }
 \description{
-Continuous position scales (x & y).
+\code{scale_x_continuous} and \code{scale_y_continuous} are the key functions.
+The others, \code{scale_x_log10}, \code{scale_y_sqrt} etc, are aliases
+that set the \code{trans} argument to commonly used transformations.
 }
 \examples{
 \donttest{
-(m <- qplot(rating, votes, data=subset(movies, votes > 1000),
-  na.rm = TRUE))
+if (require(ggplot2movies)) {
+m <- ggplot(subset(movies, votes > 1000), aes(rating, votes)) +
+  geom_point(na.rm = TRUE)
+m
 
 # Manipulating the default position scales lets you:
 
 #  * change the axis labels
 m + scale_y_continuous("number of votes")
-m + scale_y_continuous(expression(votes^alpha))
+m + scale_y_continuous(quote(votes ^ alpha))
 
 #  * modify the axis limits
-m + scale_y_continuous(limits=c(0, 5000))
-m + scale_y_continuous(limits=c(1000, 10000))
-m + scale_x_continuous(limits=c(7, 8))
+m + scale_y_continuous(limits = c(0, 5000))
+m + scale_y_continuous(limits = c(1000, 10000))
+m + scale_x_continuous(limits = c(7, 8))
 
 # you can also use the short hand functions xlim and ylim
 m + ylim(0, 5000)
@@ -61,45 +121,49 @@ m + ylim(1000, 10000)
 m + xlim(7, 8)
 
 #  * choose where the ticks appear
-m + scale_x_continuous(breaks=1:10)
-m + scale_x_continuous(breaks=c(1,3,7,9))
+m + scale_x_continuous(breaks = 1:10)
+m + scale_x_continuous(breaks = c(1,3,7,9))
 
 #  * manually label the ticks
-m + scale_x_continuous(breaks=c(2,5,8), labels=c("two", "five", "eight"))
-m + scale_x_continuous(breaks=c(2,5,8), labels=c("horrible", "ok", "awesome"))
-m + scale_x_continuous(breaks=c(2,5,8), labels=expression(Alpha, Beta, Omega))
+m + scale_x_continuous(breaks = c(2,5,8), labels = c("two", "five", "eight"))
+m + scale_x_continuous(breaks = c(2,5,8), labels = c("horrible", "ok", "awesome"))
+m + scale_x_continuous(breaks = c(2,5,8), labels = expression(Alpha, Beta, Omega))
 
 # There are a few built in transformation that you can use:
 m + scale_y_log10()
 m + scale_y_sqrt()
 m + scale_y_reverse()
 # You can also create your own and supply them to the trans argument.
-# See ?scale::trans_new
+# See ?scales::trans_new
 
 # You can control the formatting of the labels with the formatter
 # argument.  Some common formats are built into the scales package:
-x <- rnorm(10) * 100000
-y <- seq(0, 1, length = 10)
-p <- qplot(x, y)
-library(scales)
-p + scale_y_continuous(labels = percent)
-p + scale_y_continuous(labels = dollar)
-p + scale_x_continuous(labels = comma)
-
-# qplot allows you to do some of this with a little less typing:
-#   * axis limits
-qplot(rating, votes, data=movies, ylim=c(1e4, 5e4))
+df <- data.frame(
+  x = rnorm(10) * 100000,
+  y = seq(0, 1, length.out = 10)
+)
+p <- ggplot(df, aes(x, y)) + geom_point()
+p + scale_y_continuous(labels = scales::percent)
+p + scale_y_continuous(labels = scales::dollar)
+p + scale_x_continuous(labels = scales::comma)
+
+# Other shortcut functions
+ggplot(movies, aes(rating, votes)) +
+  geom_point() +
+  ylim(1e4, 5e4)
 #   * axis labels
-qplot(rating, votes, data=movies, xlab="My x axis", ylab="My y axis")
+ggplot(movies, aes(rating, votes)) +
+  geom_point() +
+  labs(x = "My x axis", y = "My y axis")
 #   * log scaling
-qplot(rating, votes, data=movies, log="xy")
+ggplot(movies, aes(rating, votes)) +
+  geom_point() +
+  scale_x_log10() +
+  scale_y_log10()
+}
 }
 }
 \seealso{
-Other position scales: \code{\link{scale_x_datetime}},
-  \code{\link{scale_y_datetime}};
-  \code{\link{scale_x_date}}, \code{\link{scale_y_date}};
-  \code{\link{scale_x_discrete}},
-  \code{\link{scale_y_discrete}}
+\code{\link{scale_date}} for date/time position scales.
 }
 
diff --git a/man/scale_date.Rd b/man/scale_date.Rd
index b208f36..cc75964 100644
--- a/man/scale_date.Rd
+++ b/man/scale_date.Rd
@@ -1,110 +1,107 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/scale-date.r
-\name{scale_x_date}
+\name{scale_date}
+\alias{scale_date}
 \alias{scale_x_date}
+\alias{scale_x_datetime}
 \alias{scale_y_date}
-\title{Position scale, date}
+\alias{scale_y_datetime}
+\title{Position scale, date & date times}
 \usage{
-scale_x_date(..., expand = waiver(), breaks = pretty_breaks(),
-  minor_breaks = waiver())
+scale_x_date(name = waiver(), breaks = waiver(), date_breaks = waiver(),
+  labels = waiver(), date_labels = waiver(), minor_breaks = waiver(),
+  date_minor_breaks = waiver(), limits = NULL, expand = waiver())
 
-scale_y_date(..., expand = waiver(), breaks = pretty_breaks(),
-  minor_breaks = waiver())
+scale_y_date(name = waiver(), breaks = waiver(), date_breaks = waiver(),
+  labels = waiver(), date_labels = waiver(), minor_breaks = waiver(),
+  date_minor_breaks = waiver(), limits = NULL, expand = waiver())
+
+scale_x_datetime(name = waiver(), breaks = waiver(),
+  date_breaks = waiver(), labels = waiver(), date_labels = waiver(),
+  minor_breaks = waiver(), date_minor_breaks = waiver(), limits = NULL,
+  expand = waiver())
+
+scale_y_datetime(name = waiver(), breaks = waiver(),
+  date_breaks = waiver(), labels = waiver(), date_labels = waiver(),
+  minor_breaks = waiver(), date_minor_breaks = waiver(), limits = NULL,
+  expand = waiver())
 }
 \arguments{
-\item{...}{common continuous scale parameters: \code{name}, \code{breaks},
-\code{labels}, \code{na.value}, \code{limits} and \code{trans}.  See
-\code{\link{continuous_scale}} for more details}
+\item{name}{The name of the scale. Used as axis or legend title. If
+\code{NULL}, the default, the name of the scale is taken from the first
+mapping used for that aesthetic.}
 
-\item{expand}{a numeric vector of length two giving multiplicative and
-additive expansion constants. These constants ensure that the data is
-placed some distance away from the axes.}
+\item{breaks}{One of: \itemize{
+  \item \code{NULL} for no breaks
+  \item \code{waiver()} for the default breaks computed by the
+    transformation object
+  \item A numeric vector of positions
+  \item A function that takes the limits as input and returns breaks
+    as output
+}}
 
-\item{breaks}{A vector of breaks, a function that given the scale limits
-returns a vector of breaks, or a character vector, specifying the width
-between breaks. For more information about the first two, see
-\code{\link{continuous_scale}}, for more information about the last,
-see \code{\link[scales]{date_breaks}}`.}
+\item{date_breaks}{A string giving the distance between breaks like "2
+weeks", or "10 years". If both \code{breaks} and \code{date_breaks} are
+specified, \code{date_breaks} wins.}
 
-\item{minor_breaks}{Either \code{NULL} for no minor breaks, \code{waiver()}
-for the default breaks (one minor break between each major break), a
-numeric vector of positions, or a function that given the limits returns
-a vector of minor breaks.}
-}
-\description{
-Position scale, date
-}
-\examples{
-# We'll start by creating some nonsense data with dates
-df <- data.frame(
-  date = seq(Sys.Date(), len=100, by="1 day")[sample(100, 50)],
-  price = runif(50)
-)
-df <- df[order(df$date), ]
-dt <- qplot(date, price, data=df, geom="line") + theme(aspect.ratio = 1/4)
+\item{labels}{One of: \itemize{
+  \item \code{NULL} for no labels
+  \item \code{waiver()} for the default labels computed by the
+    transformation object
+  \item A character vector giving labels (must be same length as \code{breaks})
+  \item A function that takes the breaks as input and returns labels
+    as output
+}}
 
-# We can control the format of the labels, and the frequency of
-# the major and minor tickmarks.  See ?format.Date and ?seq.Date
-# for more details.
-library(scales) # to access breaks/formatting functions
-dt + scale_x_date()
-dt + scale_x_date(labels = date_format("\%m/\%d"))
-dt + scale_x_date(labels = date_format("\%W"))
-dt + scale_x_date(labels = date_format("\%W"), breaks = date_breaks("week"))
+\item{date_labels}{A string giving the formatting specification for the
+labels. Codes are defined in \code{\link{strftime}}. If both \code{labels}
+and \code{date_labels} are specified, \code{date_labels} wins.}
 
-dt + scale_x_date(breaks = date_breaks("months"),
-  labels = date_format("\%b"))
-dt + scale_x_date(breaks = date_breaks("4 weeks"),
-  labels = date_format("\%d-\%b"))
+\item{minor_breaks}{One of: \itemize{
+  \item \code{NULL} for no minor breaks
+  \item \code{waiver()} for the default breaks (one minor break between
+    each major break)
+  \item A numeric vector of positions
+  \item A function that given the limits returns a vector of minor breaks.
+}}
 
-# We can use character string for breaks.
-# See \\code{\\link{by}} argument in \\code{\\link{seq.Date}}.
-dt + scale_x_date(breaks = "2 weeks")
-dt + scale_x_date(breaks = "1 month", minor_breaks = "1 week")
+\item{date_minor_breaks}{A string giving the distance between minor breaks
+like "2 weeks", or "10 years". If both \code{minor_breaks} and
+\code{date_minor_breaks} are specified, \code{date_minor_breaks} wins.}
 
-# The date scale will attempt to pick sensible defaults for
-# major and minor tick marks
-qplot(date, price, data=df[1:10,], geom="line")
-qplot(date, price, data=df[1:4,], geom="line")
+\item{limits}{A numeric vector of length two providing limits of the scale.
+Use \code{NA} to refer to the existing minimum or maximum.}
 
+\item{expand}{A numeric vector of length two giving multiplicative and
+additive expansion constants. These constants ensure that the data is
+placed some distance away from the axes. The defaults are
+\code{c(0.05, 0)} for continuous variables, and \code{c(0, 0.6)} for
+discrete variables.}
+}
+\description{
+Use \code{scale_*_date} with \code{Date} variables, and
+\code{scale_*_datetime} with \code{POSIXct} variables.
+}
+\examples{
+last_month <- Sys.Date() - 0:29
 df <- data.frame(
-  date = seq(Sys.Date(), len=1000, by="1 day"),
-  price = runif(500)
+  date = last_month,
+  price = runif(30)
 )
-qplot(date, price, data=df, geom="line")
-
-# A real example using economic time series data
-qplot(date, psavert, data=economics)
-qplot(date, psavert, data=economics, geom="path")
+base <- ggplot(df, aes(date, price)) +
+  geom_line()
 
-end <- max(economics$date)
-last_plot() + scale_x_date(limits = c(as.Date("2000-1-1"), end))
-last_plot() + scale_x_date(limits = c(as.Date("2005-1-1"), end))
-last_plot() + scale_x_date(limits = c(as.Date("2006-1-1"), end))
-
-# If we want to display multiple series, one for each variable
-# it's easiest to first change the data from a "wide" to a "long"
-# format:
-library(reshape2) # for melt
-em <- melt(economics, id = "date")
+# The date scale will attempt to pick sensible defaults for
+# major and minor tick marks. Override with date_breaks, date_labels
+# date_minor_breaks arguments.
+base + scale_x_date(date_labels = "\%b \%d")
+base + scale_x_date(date_breaks = "1 week", date_labels = "\%W")
+base + scale_x_date(date_minor_breaks = "1 day")
 
-# Then we can group and facet by the new "variable" variable
-qplot(date, value, data = em, geom = "line", group = variable)
-qplot(date, value, data = em, geom = "line", group = variable) +
-  facet_grid(variable ~ ., scale = "free_y")
+# Set limits
+base + scale_x_date(limits = c(Sys.Date() - 7, NA))
 }
 \seealso{
-Other position scales: \code{\link{scale_x_continuous}},
-  \code{\link{scale_x_log10}},
-  \code{\link{scale_x_reverse}},
-  \code{\link{scale_x_sqrt}},
-  \code{\link{scale_y_continuous}},
-  \code{\link{scale_y_log10}},
-  \code{\link{scale_y_reverse}},
-  \code{\link{scale_y_sqrt}};
-  \code{\link{scale_x_datetime}},
-  \code{\link{scale_y_datetime}};
-  \code{\link{scale_x_discrete}},
-  \code{\link{scale_y_discrete}}
+\code{\link{scale_continuous}} for continuous position scales.
 }
 
diff --git a/man/scale_datetime.Rd b/man/scale_datetime.Rd
deleted file mode 100644
index cbde57e..0000000
--- a/man/scale_datetime.Rd
+++ /dev/null
@@ -1,88 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/scale-datetime.r
-\name{scale_x_datetime}
-\alias{scale_x_datetime}
-\alias{scale_y_datetime}
-\title{Position scale, date}
-\usage{
-scale_x_datetime(..., expand = waiver(), breaks = pretty_breaks(),
-  minor_breaks = waiver())
-
-scale_y_datetime(..., expand = waiver(), breaks = pretty_breaks(),
-  minor_breaks = waiver())
-}
-\arguments{
-\item{...}{common continuous scale parameters: \code{name}, \code{breaks},
-\code{labels}, \code{na.value}, \code{limits} and \code{trans}.  See
-\code{\link{continuous_scale}} for more details}
-
-\item{expand}{a numeric vector of length two giving multiplicative and
-additive expansion constants. These constants ensure that the data is
-placed some distance away from the axes.}
-
-\item{breaks}{A vector of breaks, a function that given the scale limits
-returns a vector of breaks, or a character vector, specifying the width
-between breaks. For more information about the first two, see
-\code{\link{continuous_scale}}, for more information about the last,
-see \code{\link[scales]{date_breaks}}.}
-
-\item{minor_breaks}{Either \code{NULL} for no minor breaks, \code{waiver()}
-for the default breaks (one minor break between each major break), a
-numeric vector of positions, or a function that given the limits returns
-a vector of minor breaks.}
-}
-\description{
-Position scale, date
-}
-\examples{
-start <- ISOdate(2001, 1, 1, tz = "")
-df <- data.frame(
-  day30  = start + round(runif(100, max = 30 * 86400)),
-  day7  = start + round(runif(100, max = 7 * 86400)),
-  day   = start + round(runif(100, max = 86400)),
-  hour10 = start + round(runif(100, max = 10 * 3600)),
-  hour5 = start + round(runif(100, max = 5 * 3600)),
-  hour  = start + round(runif(100, max = 3600)),
-  min10 = start + round(runif(100, max = 10 * 60)),
-  min5  = start + round(runif(100, max = 5 * 60)),
-  min   = start + round(runif(100, max = 60)),
-  sec10 = start + round(runif(100, max = 10)),
-  y = runif(100)
-)
-
-# Automatic scale selection
-qplot(sec10, y, data = df)
-qplot(min, y, data = df)
-qplot(min5, y, data = df)
-qplot(min10, y, data = df)
-qplot(hour, y, data = df)
-qplot(hour5, y, data = df)
-qplot(hour10, y, data = df)
-qplot(day, y, data = df)
-qplot(day30, y, data = df)
-
-# Manual scale selection
-qplot(day30, y, data = df)
-library(scales) # to access breaks/formatting functions
-last_plot() + scale_x_datetime(breaks = date_breaks("2 weeks"))
-last_plot() + scale_x_datetime(breaks = date_breaks("10 days"))
-library(scales) # to access breaks/formatting functions
-last_plot() + scale_x_datetime(breaks = date_breaks("10 days"),
-  labels = date_format("\%d/\%m"))
-last_plot() + scale_x_datetime(breaks = date_breaks("1 day"),
-  minor_breaks = date_breaks("2 hour"))
-}
-\seealso{
-Other position scales: \code{\link{scale_x_continuous}},
-  \code{\link{scale_x_log10}},
-  \code{\link{scale_x_reverse}},
-  \code{\link{scale_x_sqrt}},
-  \code{\link{scale_y_continuous}},
-  \code{\link{scale_y_log10}},
-  \code{\link{scale_y_reverse}},
-  \code{\link{scale_y_sqrt}}; \code{\link{scale_x_date}},
-  \code{\link{scale_y_date}};
-  \code{\link{scale_x_discrete}},
-  \code{\link{scale_y_discrete}}
-}
-
diff --git a/man/scale_discrete.Rd b/man/scale_discrete.Rd
index fee3a05..79c7f45 100644
--- a/man/scale_discrete.Rd
+++ b/man/scale_discrete.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/scale-discrete-.r
 \name{scale_x_discrete}
 \alias{scale_x_discrete}
@@ -27,13 +27,14 @@ at integer positions).  This is what allows jittering to work.
 }
 \examples{
 \donttest{
-qplot(cut, data=diamonds, stat="bin")
-qplot(cut, data=diamonds, geom="bar")
+ggplot(diamonds, aes(cut)) + stat_bin()
+ggplot(diamonds, aes(cut)) + geom_bar()
 
 # The discrete position scale is added automatically whenever you
 # have a discrete position.
 
-(d <- qplot(cut, clarity, data=subset(diamonds, carat > 1), geom="jitter"))
+(d <- ggplot(subset(diamonds, carat > 1), aes(cut, clarity)) +
+      geom_jitter())
 
 d + scale_x_discrete("Cut")
 d + scale_x_discrete("Cut", labels = c("Fair" = "F","Good" = "G",
@@ -51,26 +52,14 @@ d + xlim("Fair","Ideal", "Good")
 d + ylim("I1", "IF")
 
 # See ?reorder to reorder based on the values of another variable
-qplot(manufacturer, cty, data=mpg)
-qplot(reorder(manufacturer, cty), cty, data=mpg)
-qplot(reorder(manufacturer, displ), cty, data=mpg)
+ggplot(mpg, aes(manufacturer, cty)) + geom_point()
+ggplot(mpg, aes(reorder(manufacturer, cty), cty)) + geom_point()
+ggplot(mpg, aes(reorder(manufacturer, displ), cty)) + geom_point()
 
 # Use abbreviate as a formatter to reduce long names
-qplot(reorder(manufacturer, cty), cty, data=mpg) +
+ggplot(mpg, aes(reorder(manufacturer, displ), cty)) +
+  geom_point() +
   scale_x_discrete(labels = abbreviate)
 }
 }
-\seealso{
-Other position scales: \code{\link{scale_x_continuous}},
-  \code{\link{scale_x_log10}},
-  \code{\link{scale_x_reverse}},
-  \code{\link{scale_x_sqrt}},
-  \code{\link{scale_y_continuous}},
-  \code{\link{scale_y_log10}},
-  \code{\link{scale_y_reverse}},
-  \code{\link{scale_y_sqrt}};
-  \code{\link{scale_x_datetime}},
-  \code{\link{scale_y_datetime}};
-  \code{\link{scale_x_date}}, \code{\link{scale_y_date}}
-}
 
diff --git a/man/scale_gradient.Rd b/man/scale_gradient.Rd
index fdd15d2..38a3ee0 100644
--- a/man/scale_gradient.Rd
+++ b/man/scale_gradient.Rd
@@ -1,12 +1,18 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/scale-gradient.r, R/zxx.r
 \name{scale_colour_gradient}
 \alias{scale_color_continuous}
 \alias{scale_color_gradient}
+\alias{scale_color_gradient2}
+\alias{scale_color_gradientn}
 \alias{scale_colour_continuous}
 \alias{scale_colour_gradient}
+\alias{scale_colour_gradient2}
+\alias{scale_colour_gradientn}
 \alias{scale_fill_continuous}
 \alias{scale_fill_gradient}
+\alias{scale_fill_gradient2}
+\alias{scale_fill_gradientn}
 \title{Smooth gradient between two colours}
 \usage{
 scale_colour_gradient(..., low = "#132B43", high = "#56B1F7",
@@ -15,35 +21,52 @@ scale_colour_gradient(..., low = "#132B43", high = "#56B1F7",
 scale_fill_gradient(..., low = "#132B43", high = "#56B1F7", space = "Lab",
   na.value = "grey50", guide = "colourbar")
 
-scale_colour_continuous(..., low = "#132B43", high = "#56B1F7",
-  space = "Lab", na.value = "grey50", guide = "colourbar")
+scale_colour_gradient2(..., low = muted("red"), mid = "white",
+  high = muted("blue"), midpoint = 0, space = "Lab",
+  na.value = "grey50", guide = "colourbar")
 
-scale_fill_continuous(..., low = "#132B43", high = "#56B1F7",
-  space = "Lab", na.value = "grey50", guide = "colourbar")
+scale_fill_gradient2(..., low = muted("red"), mid = "white",
+  high = muted("blue"), midpoint = 0, space = "Lab",
+  na.value = "grey50", guide = "colourbar")
 
-scale_color_continuous(..., low = "#132B43", high = "#56B1F7",
-  space = "Lab", na.value = "grey50", guide = "colourbar")
+scale_colour_gradientn(..., colours, values = NULL, space = "Lab",
+  na.value = "grey50", guide = "colourbar", colors)
 
-scale_color_gradient(..., low = "#132B43", high = "#56B1F7",
-  space = "Lab", na.value = "grey50", guide = "colourbar")
+scale_fill_gradientn(..., colours, values = NULL, space = "Lab",
+  na.value = "grey50", guide = "colourbar", colors)
 }
 \arguments{
 \item{...}{Other arguments passed on to \code{\link{discrete_scale}}
 to control name, limits, breaks, labels and so forth.}
 
-\item{low}{colour for low end of gradient.}
-
-\item{high}{colour for high end of gradient.}
+\item{low, high}{Colours for low and high ends of the gradient.}
 
-\item{space}{colour space in which to calculate gradient.  "Lab" usually
-best unless gradient goes through white.}
+\item{space}{colour space in which to calculate gradient. Must be "Lab" -
+other values are deprecated.}
 
 \item{na.value}{Colour to use for missing values}
 
 \item{guide}{Type of legend. Use \code{"colourbar"} for continuous
 colour bar, or \code{"legend"} for discrete colour legend.}
+
+\item{mid}{colour for mid point}
+
+\item{midpoint}{The midpoint (in data value) of the diverging scale.
+Defaults to 0.}
+
+\item{colours, colors}{Vector of colours to use for n-colour gradient.}
+
+\item{values}{if colours should not be evenly positioned along the gradient
+this vector gives the position (between 0 and 1) for each colour in the
+\code{colours} vector. See \code{\link{rescale}} for a convience function
+to map an arbitrary range to between 0 and 1.}
 }
 \description{
+\code{scale_*_gradient} creates a two colour gradient (low-high),
+\code{scale_*_gradient2} creates a diverging colour gradient (low-mid-high),
+\code{scale_*_gradientn} creats a n-colour gradient.
+}
+\details{
 Default colours are generated with \pkg{munsell} and
 \code{mnsl(c("2.5PB 2/4", "2.5PB 7/10")}. Generally, for continuous
 colour scales you want to keep hue constant, but vary chroma and
@@ -51,72 +74,46 @@ luminance. The \pkg{munsell} package makes this easy to do using the
 Munsell colour system.
 }
 \examples{
-\donttest{
-# It's hard to see, but look for the bright yellow dot
-# in the bottom right hand corner
-dsub <- subset(diamonds, x > 5 & x < 6 & y > 5 & y < 6)
-(d <- qplot(x, y, data=dsub, colour=z))
-# That one point throws our entire scale off.  We could
-# remove it, or manually tweak the limits of the scale
-
-# Tweak scale limits.  Any points outside these limits will not be
-# plotted, and will not affect the calculation of statistics, etc
-d + scale_colour_gradient(limits=c(3, 10))
-d + scale_colour_gradient(limits=c(3, 4))
-# Setting the limits manually is also useful when producing
-# multiple plots that need to be comparable
-
-# Alternatively we could try transforming the scale:
-d + scale_colour_gradient(trans = "log")
-d + scale_colour_gradient(trans = "sqrt")
-
-# Other more trivial manipulations, including changing the name
-# of the scale and the colours.
-
-d + scale_colour_gradient("Depth")
-d + scale_colour_gradient(expression(Depth[mm]))
-
-d + scale_colour_gradient(limits=c(3, 4), low="red")
-d + scale_colour_gradient(limits=c(3, 4), low="red", high="white")
-# Much slower
-d + scale_colour_gradient(limits=c(3, 4), low="red", high="white", space="Lab")
-d + scale_colour_gradient(limits=c(3, 4), space="Lab")
-
-# scale_fill_continuous works similarly, but for fill colours
-(h <- qplot(x - y, data=dsub, geom="histogram", binwidth=0.01, fill=..count..))
-h + scale_fill_continuous(low="black", high="pink", limits=c(0,3100))
-
-# Colour of missing values is controlled with na.value:
-miss <- sample(c(NA, 1:5), nrow(mtcars), rep = TRUE)
-qplot(mpg, wt, data = mtcars, colour = miss)
-qplot(mpg, wt, data = mtcars, colour = miss) +
-  scale_colour_gradient(na.value = "black")
-}
+df <- data.frame(
+  x = runif(100),
+  y = runif(100),
+  z1 = rnorm(100),
+  z2 = abs(rnorm(100))
+)
+
+# Default colour scale colours from light blue to dark blue
+ggplot(df, aes(x, y)) +
+  geom_point(aes(colour = z2))
+
+# For diverging colour scales use gradient2
+ggplot(df, aes(x, y)) +
+  geom_point(aes(colour = z1)) +
+  scale_colour_gradient2()
+
+# Use your own colour scale with gradientn
+ggplot(df, aes(x, y)) +
+  geom_point(aes(colour = z1)) +
+  scale_colour_gradientn(colours = terrain.colors(10))
+
+# Equivalent fill scales do the same job for the fill aesthetic
+ggplot(faithfuld, aes(waiting, eruptions)) +
+  geom_raster(aes(fill = density)) +
+  scale_fill_gradientn(colours = terrain.colors(10))
+
+# Adjust colour choices with low and high
+ggplot(df, aes(x, y)) +
+  geom_point(aes(colour = z2)) +
+  scale_colour_gradient(low = "white", high = "black")
+# Avoid red-green colour contrasts because ~10\% of men have difficulty
+# seeing them
 }
 \seealso{
 \code{\link[scales]{seq_gradient_pal}} for details on underlying
   palette
 
-Other colour scales: \code{\link{scale_color_brewer}},
-  \code{\link{scale_color_distiller}},
+Other colour scales:
   \code{\link{scale_colour_brewer}},
-  \code{\link{scale_colour_distiller}},
-  \code{\link{scale_fill_brewer}},
-  \code{\link{scale_fill_distiller}};
-  \code{\link{scale_color_discrete}},
-  \code{\link{scale_color_hue}},
-  \code{\link{scale_colour_discrete}},
-  \code{\link{scale_colour_hue}},
-  \code{\link{scale_fill_discrete}},
-  \code{\link{scale_fill_hue}};
-  \code{\link{scale_color_gradient2}},
-  \code{\link{scale_colour_gradient2}},
-  \code{\link{scale_fill_gradient2}};
-  \code{\link{scale_color_gradientn}},
-  \code{\link{scale_colour_gradientn}},
-  \code{\link{scale_fill_gradientn}};
-  \code{\link{scale_color_grey}},
   \code{\link{scale_colour_grey}},
-  \code{\link{scale_fill_grey}}
+  \code{\link{scale_colour_hue}}
 }
 
diff --git a/man/scale_gradient2.Rd b/man/scale_gradient2.Rd
deleted file mode 100644
index 468658a..0000000
--- a/man/scale_gradient2.Rd
+++ /dev/null
@@ -1,114 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/scale-gradient2.r, R/zxx.r
-\name{scale_colour_gradient2}
-\alias{scale_color_gradient2}
-\alias{scale_colour_gradient2}
-\alias{scale_fill_gradient2}
-\title{Diverging colour gradient}
-\usage{
-scale_colour_gradient2(..., low = muted("red"), mid = "white",
-  high = muted("blue"), midpoint = 0, space = "rgb",
-  na.value = "grey50", guide = "colourbar")
-
-scale_fill_gradient2(..., low = muted("red"), mid = "white",
-  high = muted("blue"), midpoint = 0, space = "rgb",
-  na.value = "grey50", guide = "colourbar")
-
-scale_color_gradient2(..., low = muted("red"), mid = "white",
-  high = muted("blue"), midpoint = 0, space = "rgb",
-  na.value = "grey50", guide = "colourbar")
-}
-\arguments{
-\item{...}{Other arguments passed on to \code{\link{discrete_scale}}
-to control name, limits, breaks, labels and so forth.}
-
-\item{low}{colour for low end of gradient.}
-
-\item{mid}{colour for mid point}
-
-\item{high}{colour for high end of gradient.}
-
-\item{midpoint}{The midpoint (in data value) of the diverging scale.
-Defaults to 0.}
-
-\item{space}{colour space in which to calculate gradient.  "Lab" usually
-best unless gradient goes through white.}
-
-\item{na.value}{Colour to use for missing values}
-
-\item{guide}{Type of legend. Use \code{"colourbar"} for continuous
-colour bar, or \code{"legend"} for discrete colour legend.}
-}
-\description{
-Diverging colour gradient
-}
-\examples{
-\donttest{
-dsub <- subset(diamonds, x > 5 & x < 6 & y > 5 & y < 6)
-dsub$diff <- with(dsub, sqrt(abs(x-y))* sign(x-y))
-(d <- qplot(x, y, data=dsub, colour=diff))
-
-d + scale_colour_gradient2()
-# Change scale name
-d + scale_colour_gradient2(expression(sqrt(abs(x - y))))
-d + scale_colour_gradient2("Difference\\nbetween\\nwidth and\\nheight")
-
-# Change limits and colours
-d + scale_colour_gradient2(limits=c(-0.2, 0.2))
-
-# Using "muted" colours makes for pleasant graphics
-# (and they have better perceptual properties too)
-library(scales) # for muted
-d + scale_colour_gradient2(low="red", high="blue")
-d + scale_colour_gradient2(low=muted("red"), high=muted("blue"))
-
-# Using the Lab colour space also improves perceptual properties
-# at the price of slightly slower operation
-d + scale_colour_gradient2(space="Lab")
-
-# About 5\% of males are red-green colour blind, so it's a good
-# idea to avoid that combination
-d + scale_colour_gradient2(high=muted("green"))
-
-# We can also make the middle stand out
-d + scale_colour_gradient2(mid=muted("green"), high="white", low="white")
-
-# or use a non zero mid point
-(d <- qplot(carat, price, data=diamonds, colour=price/carat))
-d + scale_colour_gradient2(midpoint=mean(diamonds$price / diamonds$carat))
-
-# Fill gradients work much the same way
-p <- qplot(letters[1:5], 1:5, fill= c(-3, 3, 5, 2, -2), geom = "bar",
-  stat = "identity")
-p + scale_fill_gradient2("fill")
-# Note how positive and negative values of the same magnitude
-# have similar intensity
-}
-}
-\seealso{
-Other colour scales: \code{\link{scale_color_brewer}},
-  \code{\link{scale_color_distiller}},
-  \code{\link{scale_colour_brewer}},
-  \code{\link{scale_colour_distiller}},
-  \code{\link{scale_fill_brewer}},
-  \code{\link{scale_fill_distiller}};
-  \code{\link{scale_color_continuous}},
-  \code{\link{scale_color_gradient}},
-  \code{\link{scale_colour_continuous}},
-  \code{\link{scale_colour_gradient}},
-  \code{\link{scale_fill_continuous}},
-  \code{\link{scale_fill_gradient}};
-  \code{\link{scale_color_discrete}},
-  \code{\link{scale_color_hue}},
-  \code{\link{scale_colour_discrete}},
-  \code{\link{scale_colour_hue}},
-  \code{\link{scale_fill_discrete}},
-  \code{\link{scale_fill_hue}};
-  \code{\link{scale_color_gradientn}},
-  \code{\link{scale_colour_gradientn}},
-  \code{\link{scale_fill_gradientn}};
-  \code{\link{scale_color_grey}},
-  \code{\link{scale_colour_grey}},
-  \code{\link{scale_fill_grey}}
-}
-
diff --git a/man/scale_gradientn.Rd b/man/scale_gradientn.Rd
deleted file mode 100644
index eda947d..0000000
--- a/man/scale_gradientn.Rd
+++ /dev/null
@@ -1,93 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/scale-gradientn.r, R/zxx.r
-\name{scale_colour_gradientn}
-\alias{scale_color_gradientn}
-\alias{scale_colour_gradientn}
-\alias{scale_fill_gradientn}
-\title{Smooth colour gradient between n colours}
-\usage{
-scale_colour_gradientn(..., colours, values = NULL, space = "Lab",
-  na.value = "grey50", guide = "colourbar")
-
-scale_fill_gradientn(..., colours, values = NULL, space = "Lab",
-  na.value = "grey50", guide = "colourbar")
-
-scale_color_gradientn(..., colours, values = NULL, space = "Lab",
-  na.value = "grey50", guide = "colourbar")
-}
-\arguments{
-\item{...}{Other arguments passed on to \code{\link{discrete_scale}}
-to control name, limits, breaks, labels and so forth.}
-
-\item{colours}{vector of colours}
-
-\item{values}{if colours should not be evenly positioned along the gradient
-this vector gives the position (between 0 and 1) for each colour in the
-\code{colours} vector. See \code{\link{rescale}} for a convience function
-to map an arbitrary range to between 0 and 1.}
-
-\item{space}{colour space in which to calculate gradient.  "Lab" usually
-best unless gradient goes through white.}
-
-\item{na.value}{Colour to use for missing values}
-
-\item{guide}{Type of legend. Use \code{"colourbar"} for continuous
-colour bar, or \code{"legend"} for discrete colour legend.}
-}
-\description{
-Smooth colour gradient between n colours
-}
-\examples{
-\donttest{
-# scale_colour_gradient make it easy to use existing colour palettes
-
-dsub <- subset(diamonds, x > 5 & x < 6 & y > 5 & y < 6)
-dsub$diff <- with(dsub, sqrt(abs(x-y))* sign(x-y))
-(d <- qplot(x, y, data=dsub, colour=diff))
-
-d + scale_colour_gradientn(colours = rainbow(7))
-breaks <- c(-0.5, 0, 0.5)
-d + scale_colour_gradientn(colours = rainbow(7),
-  breaks = breaks, labels = format(breaks))
-
-d + scale_colour_gradientn(colours = topo.colors(10))
-d + scale_colour_gradientn(colours = terrain.colors(10))
-
-# You can force them to be symmetric by supplying a vector of
-# values, and turning rescaling off
-max_val <- max(abs(dsub$diff))
-values <- seq(-max_val, max_val, length = 11)
-
-d + scale_colour_gradientn(colours = topo.colors(10),
-  values = values, rescaler = function(x, ...) x, oob = identity)
-d + scale_colour_gradientn(colours = terrain.colors(10),
-  values = values, rescaler = function(x, ...) x, oob = identity)
-}
-}
-\seealso{
-Other colour scales: \code{\link{scale_color_brewer}},
-  \code{\link{scale_color_distiller}},
-  \code{\link{scale_colour_brewer}},
-  \code{\link{scale_colour_distiller}},
-  \code{\link{scale_fill_brewer}},
-  \code{\link{scale_fill_distiller}};
-  \code{\link{scale_color_continuous}},
-  \code{\link{scale_color_gradient}},
-  \code{\link{scale_colour_continuous}},
-  \code{\link{scale_colour_gradient}},
-  \code{\link{scale_fill_continuous}},
-  \code{\link{scale_fill_gradient}};
-  \code{\link{scale_color_discrete}},
-  \code{\link{scale_color_hue}},
-  \code{\link{scale_colour_discrete}},
-  \code{\link{scale_colour_hue}},
-  \code{\link{scale_fill_discrete}},
-  \code{\link{scale_fill_hue}};
-  \code{\link{scale_color_gradient2}},
-  \code{\link{scale_colour_gradient2}},
-  \code{\link{scale_fill_gradient2}};
-  \code{\link{scale_color_grey}},
-  \code{\link{scale_colour_grey}},
-  \code{\link{scale_fill_grey}}
-}
-
diff --git a/man/scale_grey.Rd b/man/scale_grey.Rd
index 8ba3b2a..7b9cf75 100644
--- a/man/scale_grey.Rd
+++ b/man/scale_grey.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/scale-grey.r, R/zxx.r
 \name{scale_colour_grey}
 \alias{scale_color_grey}
@@ -8,9 +8,7 @@
 \usage{
 scale_colour_grey(..., start = 0.2, end = 0.8, na.value = "red")
 
-scale_fill_grey(..., start = 0.2, end = 0.8, na.value = "grey50")
-
-scale_color_grey(..., start = 0.2, end = 0.8, na.value = "red")
+scale_fill_grey(..., start = 0.2, end = 0.8, na.value = "red")
 }
 \arguments{
 \item{...}{Other arguments passed on to \code{\link{discrete_scale}}
@@ -26,7 +24,7 @@ to control name, limits, breaks, labels and so forth.}
 Based on \code{\link{gray.colors}}
 }
 \examples{
-p <- qplot(mpg, wt, data=mtcars, colour=factor(cyl))
+p <- ggplot(mtcars, aes(mpg, wt)) + geom_point(aes(colour = factor(cyl)))
 p + scale_colour_grey()
 p + scale_colour_grey(end = 0)
 
@@ -34,35 +32,18 @@ p + scale_colour_grey(end = 0)
 p + scale_colour_grey() + theme_bw()
 
 # Colour of missing values is controlled with na.value:
-miss <- factor(sample(c(NA, 1:5), nrow(mtcars), rep = TRUE))
-qplot(mpg, wt, data = mtcars, colour = miss) + scale_colour_grey()
-qplot(mpg, wt, data = mtcars, colour = miss) +
+miss <- factor(sample(c(NA, 1:5), nrow(mtcars), replace = TRUE))
+ggplot(mtcars, aes(mpg, wt)) +
+  geom_point(aes(colour = miss)) +
+  scale_colour_grey()
+ggplot(mtcars, aes(mpg, wt)) +
+  geom_point(aes(colour = miss)) +
   scale_colour_grey(na.value = "green")
 }
 \seealso{
-Other colour scales: \code{\link{scale_color_brewer}},
-  \code{\link{scale_color_distiller}},
+Other colour scales:
   \code{\link{scale_colour_brewer}},
-  \code{\link{scale_colour_distiller}},
-  \code{\link{scale_fill_brewer}},
-  \code{\link{scale_fill_distiller}};
-  \code{\link{scale_color_continuous}},
-  \code{\link{scale_color_gradient}},
-  \code{\link{scale_colour_continuous}},
   \code{\link{scale_colour_gradient}},
-  \code{\link{scale_fill_continuous}},
-  \code{\link{scale_fill_gradient}};
-  \code{\link{scale_color_discrete}},
-  \code{\link{scale_color_hue}},
-  \code{\link{scale_colour_discrete}},
-  \code{\link{scale_colour_hue}},
-  \code{\link{scale_fill_discrete}},
-  \code{\link{scale_fill_hue}};
-  \code{\link{scale_color_gradient2}},
-  \code{\link{scale_colour_gradient2}},
-  \code{\link{scale_fill_gradient2}};
-  \code{\link{scale_color_gradientn}},
-  \code{\link{scale_colour_gradientn}},
-  \code{\link{scale_fill_gradientn}}
+  \code{\link{scale_colour_hue}}
 }
 
diff --git a/man/scale_hue.Rd b/man/scale_hue.Rd
index 45c6508..7cc572e 100644
--- a/man/scale_hue.Rd
+++ b/man/scale_hue.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/scale-hue.r, R/zxx.r
 \name{scale_colour_hue}
 \alias{scale_color_discrete}
@@ -14,18 +14,6 @@ scale_colour_hue(..., h = c(0, 360) + 15, c = 100, l = 65, h.start = 0,
 
 scale_fill_hue(..., h = c(0, 360) + 15, c = 100, l = 65, h.start = 0,
   direction = 1, na.value = "grey50")
-
-scale_colour_discrete(..., h = c(0, 360) + 15, c = 100, l = 65,
-  h.start = 0, direction = 1, na.value = "grey50")
-
-scale_fill_discrete(..., h = c(0, 360) + 15, c = 100, l = 65,
-  h.start = 0, direction = 1, na.value = "grey50")
-
-scale_color_discrete(..., h = c(0, 360) + 15, c = 100, l = 65,
-  h.start = 0, direction = 1, na.value = "grey50")
-
-scale_color_hue(..., h = c(0, 360) + 15, c = 100, l = 65, h.start = 0,
-  direction = 1, na.value = "grey50")
 }
 \arguments{
 \item{...}{Other arguments passed on to \code{\link{discrete_scale}}
@@ -33,7 +21,8 @@ to control name, limits, breaks, labels and so forth.}
 
 \item{h}{range of hues to use, in [0, 360]}
 
-\item{c}{chroma (intensity of colour), maximum value varies depending on}
+\item{c}{chroma (intensity of colour), maximum value varies depending on
+combination of hue and luminance.}
 
 \item{l}{luminance (lightness), in [0, 100]}
 
@@ -50,7 +39,7 @@ Qualitative colour scale with evenly spaced hues.
 \examples{
 \donttest{
 dsamp <- diamonds[sample(nrow(diamonds), 1000), ]
-(d <- qplot(carat, price, data=dsamp, colour=clarity))
+(d <- ggplot(dsamp, aes(carat, price)) + geom_point(aes(colour = clarity)))
 
 # Change scale label
 d + scale_colour_hue()
@@ -77,33 +66,17 @@ d + geom_point(alpha = 0.5)
 d + geom_point(alpha = 0.2)
 
 # Colour of missing values is controlled with na.value:
-miss <- factor(sample(c(NA, 1:5), nrow(mtcars), rep = TRUE))
-qplot(mpg, wt, data = mtcars, colour = miss)
-qplot(mpg, wt, data = mtcars, colour = miss) +
+miss <- factor(sample(c(NA, 1:5), nrow(mtcars), replace = TRUE))
+ggplot(mtcars, aes(mpg, wt)) + geom_point(aes(colour = miss))
+ggplot(mtcars, aes(mpg, wt)) +
+  geom_point(aes(colour = miss)) +
   scale_colour_hue(na.value = "black")
 }
 }
 \seealso{
-Other colour scales: \code{\link{scale_color_brewer}},
-  \code{\link{scale_color_distiller}},
+Other colour scales:
   \code{\link{scale_colour_brewer}},
-  \code{\link{scale_colour_distiller}},
-  \code{\link{scale_fill_brewer}},
-  \code{\link{scale_fill_distiller}};
-  \code{\link{scale_color_continuous}},
-  \code{\link{scale_color_gradient}},
-  \code{\link{scale_colour_continuous}},
   \code{\link{scale_colour_gradient}},
-  \code{\link{scale_fill_continuous}},
-  \code{\link{scale_fill_gradient}};
-  \code{\link{scale_color_gradient2}},
-  \code{\link{scale_colour_gradient2}},
-  \code{\link{scale_fill_gradient2}};
-  \code{\link{scale_color_gradientn}},
-  \code{\link{scale_colour_gradientn}},
-  \code{\link{scale_fill_gradientn}};
-  \code{\link{scale_color_grey}},
-  \code{\link{scale_colour_grey}},
-  \code{\link{scale_fill_grey}}
+  \code{\link{scale_colour_grey}}
 }
 
diff --git a/man/scale_identity.Rd b/man/scale_identity.Rd
index e35cad6..8b63754 100644
--- a/man/scale_identity.Rd
+++ b/man/scale_identity.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/scale-identity.r, R/zxx.r
 \name{scale_identity}
 \alias{scale_alpha_identity}
@@ -22,8 +22,6 @@ scale_linetype_identity(..., guide = "none")
 scale_alpha_identity(..., guide = "none")
 
 scale_size_identity(..., guide = "none")
-
-scale_color_identity(..., guide = "none")
 }
 \arguments{
 \item{...}{Other arguments passed on to \code{\link{discrete_scale}} or
@@ -35,22 +33,37 @@ scale_color_identity(..., guide = "none")
 Use values without scaling.
 }
 \examples{
-colour <- c("red", "green", "blue", "yellow")
-qplot(1:4, 1:4, fill = colour, geom = "tile")
-qplot(1:4, 1:4, fill = colour, geom = "tile") + scale_fill_identity()
+ggplot(luv_colours, aes(u, v)) +
+  geom_point(aes(colour = col), size = 3) +
+  scale_color_identity() +
+  coord_equal()
+
+df <- data.frame(
+  x = 1:4,
+  y = 1:4,
+  colour = c("red", "green", "blue", "yellow")
+)
+ggplot(df, aes(x, y)) + geom_tile(aes(fill = colour))
+ggplot(df, aes(x, y)) +
+  geom_tile(aes(fill = colour)) +
+  scale_fill_identity()
 
 # To get a legend guide, specify guide = "legend"
-qplot(1:4, 1:4, fill = colour, geom = "tile") +
+ggplot(df, aes(x, y)) +
+  geom_tile(aes(fill = colour)) +
   scale_fill_identity(guide = "legend")
 # But you'll typically also need to supply breaks and labels:
-qplot(1:4, 1:4, fill = colour, geom = "tile") +
-  scale_fill_identity("trt", labels = letters[1:4], breaks = colour,
+ggplot(df, aes(x, y)) +
+  geom_tile(aes(fill = colour)) +
+  scale_fill_identity("trt", labels = letters[1:4], breaks = df$colour,
   guide = "legend")
 
 # cyl scaled to appropriate size
-qplot(mpg, wt, data = mtcars, size = cyl)
+ggplot(mtcars, aes(mpg, wt)) + geom_point(aes(size = cyl))
 
 # cyl used as point size
-qplot(mpg, wt, data = mtcars, size = cyl) + scale_size_identity()
+ggplot(mtcars, aes(mpg, wt)) +
+  geom_point(aes(size = cyl)) +
+  scale_size_identity()
 }
 
diff --git a/man/scale_linetype.Rd b/man/scale_linetype.Rd
index 53b8033..35f5b31 100644
--- a/man/scale_linetype.Rd
+++ b/man/scale_linetype.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/scale-linetype.r
 \name{scale_linetype}
 \alias{scale_linetype}
@@ -25,15 +25,9 @@ University of Manchester.  Line types can not be mapped to continuous
 values.
 }
 \examples{
-library(reshape2) # for melt
-library(plyr) # for ddply
-ecm <- melt(economics, id = "date")
-rescale01 <- function(x) (x - min(x)) / diff(range(x))
-ecm <- ddply(ecm, "variable", transform, value = rescale01(value))
-
-qplot(date, value, data=ecm, geom="line", group=variable)
-qplot(date, value, data=ecm, geom="line", linetype=variable)
-qplot(date, value, data=ecm, geom="line", colour=variable)
+base <- ggplot(economics_long, aes(date, value01))
+base + geom_line(aes(group = variable))
+base + geom_line(aes(linetype = variable))
 
 # See scale_manual for more flexibility
 }
diff --git a/man/scale_manual.Rd b/man/scale_manual.Rd
index aac831f..06e7786 100644
--- a/man/scale_manual.Rd
+++ b/man/scale_manual.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/scale-manual.r, R/zxx.r
 \name{scale_manual}
 \alias{scale_alpha_manual}
@@ -22,8 +22,6 @@ scale_shape_manual(..., values)
 scale_linetype_manual(..., values)
 
 scale_alpha_manual(..., values)
-
-scale_color_manual(..., values)
 }
 \arguments{
 \item{...}{common discrete scale parameters: \code{name}, \code{breaks},
@@ -41,7 +39,8 @@ Create your own discrete scale.
 }
 \examples{
 \donttest{
-p <- qplot(mpg, wt, data = mtcars, colour = factor(cyl))
+p <- ggplot(mtcars, aes(mpg, wt)) +
+  geom_point(aes(colour = factor(cyl)))
 
 p + scale_colour_manual(values = c("red","blue", "green"))
 p + scale_colour_manual(
diff --git a/man/scale_shape.Rd b/man/scale_shape.Rd
index 157f3d6..19ecbea 100644
--- a/man/scale_shape.Rd
+++ b/man/scale_shape.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/scale-shape.r
 \name{scale_shape}
 \alias{scale_shape}
@@ -25,18 +25,18 @@ A continuous variable can not be mapped to shape.
 \examples{
 dsmall <- diamonds[sample(nrow(diamonds), 100), ]
 
-(d <- qplot(carat, price, data=dsmall, shape=cut))
+(d <- ggplot(dsmall, aes(carat, price)) + geom_point(aes(shape = cut)))
 d + scale_shape(solid = TRUE) # the default
 d + scale_shape(solid = FALSE)
-d + scale_shape(name="Cut of diamond")
-d + scale_shape(name="Cut of\\ndiamond")
+d + scale_shape(name = "Cut of diamond")
+d + scale_shape(name = "Cut of\\ndiamond")
 
 # To change order of levels, change order of
 # underlying factor
 levels(dsmall$cut) <- c("Fair", "Good", "Very Good", "Premium", "Ideal")
 
 # Need to recreate plot to pick up new data
-qplot(price, carat, data=dsmall, shape=cut)
+ggplot(dsmall, aes(price, carat)) + geom_point(aes(shape = cut))
 
 # Or for short:
 d \%+\% dsmall
diff --git a/man/scale_size.Rd b/man/scale_size.Rd
index 668f2b9..b1ef060 100644
--- a/man/scale_size.Rd
+++ b/man/scale_size.Rd
@@ -1,49 +1,95 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/scale-size.r
 \name{scale_size}
+\alias{scale_radius}
 \alias{scale_size}
+\alias{scale_size_area}
 \alias{scale_size_continuous}
 \alias{scale_size_discrete}
-\title{Size scale.}
+\title{Scale size (area or radius).}
 \usage{
-scale_size_continuous(..., range = c(1, 6))
+scale_radius(name = waiver(), breaks = waiver(), labels = waiver(),
+  limits = NULL, range = c(1, 6), trans = "identity", guide = "legend")
 
-scale_size(..., range = c(1, 6))
+scale_size(name = waiver(), breaks = waiver(), labels = waiver(),
+  limits = NULL, range = c(1, 6), trans = "identity", guide = "legend")
 
-scale_size_discrete(..., range = c(1, 6))
+scale_size_area(..., max_size = 6)
 }
 \arguments{
-\item{...}{common continuous scale parameters: \code{name}, \code{breaks},
-\code{labels}, \code{na.value}, \code{limits} and \code{trans}.  See
-\code{\link{continuous_scale}} for more details}
+\item{name}{The name of the scale. Used as axis or legend title. If
+\code{NULL}, the default, the name of the scale is taken from the first
+mapping used for that aesthetic.}
+
+\item{breaks}{One of: \itemize{
+  \item \code{NULL} for no breaks
+  \item \code{waiver()} for the default breaks computed by the
+    transformation object
+  \item A numeric vector of positions
+  \item A function that takes the limits as input and returns breaks
+    as output
+}}
+
+\item{labels}{One of: \itemize{
+  \item \code{NULL} for no labels
+  \item \code{waiver()} for the default labels computed by the
+    transformation object
+  \item A character vector giving labels (must be same length as \code{breaks})
+  \item A function that takes the breaks as input and returns labels
+    as output
+}}
+
+\item{limits}{A numeric vector of length two providing limits of the scale.
+Use \code{NA} to refer to the existing minimum or maximum.}
 
 \item{range}{a numeric vector of length 2 that specifies the minimum and
 maximum size of the plotting symbol after transformation.}
+
+\item{trans}{Either the name of a transformation object, or the
+  object itself. Built-in transformations include "asn", "atanh",
+  "boxcox", "exp", "identity", "log", "log10", "log1p", "log2",
+  "logit", "probability", "probit", "reciprocal", "reverse" and "sqrt".
+
+  A transformation object bundles together a transform, it's inverse,
+  and methods for generating breaks and labels. Transformation objects
+  are defined in the scales package, and are called \code{name_trans}, e.g.
+  \code{\link[scales]{boxcox_trans}}. You can create your own
+  transformation with \code{\link[scales]{trans_new}}.}
+
+\item{guide}{Name of guide object, or object itself.}
+
+\item{...}{Other arguments passed on to \code{\link{continuous_scale}}
+to control name, limits, breaks, labels and so forth.}
+
+\item{max_size}{Size of largest points.}
 }
 \description{
-Size scale.
+\code{scale_size} scales area, \code{scale_radius} scales radius. The size
+aesthetic is most commonly used for points and text, and humans perceive
+the area of points (not their radius), so this provides for optimal
+perception. \code{scale_size_area} ensures that a value of 0 is mapped
+to a size of 0.
 }
 \examples{
-\donttest{
-(p <- qplot(mpg, cyl, data=mtcars, size=cyl))
-p + scale_size("cylinders")
-p + scale_size("number\\nof\\ncylinders")
-
+p <- ggplot(mpg, aes(displ, hwy, size = hwy)) +
+   geom_point()
+p
+p + scale_size("Highway mpg")
 p + scale_size(range = c(0, 10))
-p + scale_size(range = c(1, 2))
 
-# Map area, instead of width/radius
-# Perceptually, this is a little better
+# If you want zero value to have zero size, use scale_size_area:
 p + scale_size_area()
-p + scale_size_area(max_size = 25)
 
-# Also works with factors, but not a terribly good
-# idea, unless your factor is ordered, as in this example
-qplot(mpg, cyl, data=mtcars, size=factor(cyl))
+# This is most useful when size is a count
+ggplot(mpg, aes(class, cyl)) +
+  geom_count() +
+  scale_size_area()
 
-# To control the size mapping for discrete variable, use
-# scale_size_manual:
-last_plot() + scale_size_manual(values=c(2,4,6))
+# If you want to map size to radius (usually bad idea), use scale_radius
+p + scale_radius()
 }
+\seealso{
+\code{\link{scale_size_area}} if you want 0 values to be mapped
+  to points with size 0.
 }
 
diff --git a/man/scale_size_area.Rd b/man/scale_size_area.Rd
deleted file mode 100644
index 0b0ca2e..0000000
--- a/man/scale_size_area.Rd
+++ /dev/null
@@ -1,24 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/scale-size.r
-\name{scale_size_area}
-\alias{scale_size_area}
-\title{Scale area instead of radius, for size.}
-\usage{
-scale_size_area(..., max_size = 6)
-}
-\arguments{
-\item{...}{Other arguments passed on to \code{\link{continuous_scale}}
-to control name, limits, breaks, labels and so forth.}
-
-\item{max_size}{Size of largest points.}
-}
-\description{
-When \code{scale_size_area} is used, the default behavior is to scale the
-area of points to be proportional to the value.
-}
-\details{
-Note that this controls the size scale, so it will also control
-the thickness of lines. Line thickness will be proportional to the square
-root of the value, which is probably undesirable in most cases.
-}
-
diff --git a/man/seals.Rd b/man/seals.Rd
index 8f143d5..1e9d475 100644
--- a/man/seals.Rd
+++ b/man/seals.Rd
@@ -1,12 +1,12 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/ggplot2.r
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/data.R
 \docType{data}
 \name{seals}
 \alias{seals}
 \title{Vector field of seal movements.}
 \format{A data frame with 1155 rows and 4 variables}
 \usage{
-data(seals)
+seals
 }
 \description{
 This vector field was produced from the data described in Brillinger, D.R.,
@@ -14,7 +14,7 @@ Preisler, H.K., Ager, A.A. and Kie, J.G. "An exploratory data analysis
 (EDA) of the paths of moving animals". J. Statistical Planning and
 Inference 122 (2004), 43-63, using the methods of Brillinger, D.R.,
 "Learning a potential function from a trajectory", Signal Processing
- Letters. December (2007).
+Letters. December (2007).
 }
 \references{
 \url{http://www.stat.berkeley.edu/~brill/Papers/jspifinal.pdf}
diff --git a/man/should_stop.Rd b/man/should_stop.Rd
index 0a29e2d..e0113c9 100644
--- a/man/should_stop.Rd
+++ b/man/should_stop.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/utilities.r
 \name{should_stop}
 \alias{should_stop}
diff --git a/man/stat_abline.Rd b/man/stat_abline.Rd
deleted file mode 100644
index 2830251..0000000
--- a/man/stat_abline.Rd
+++ /dev/null
@@ -1,37 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-vline.r
-\name{stat_abline}
-\alias{stat_abline}
-\title{Add a line with slope and intercept.}
-\usage{
-stat_abline(mapping = NULL, data = NULL, geom = "abline",
-  position = "identity", ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-Add a line with slope and intercept.
-}
-\examples{
-# see geom_abline
-}
-\seealso{
-\code{\link{geom_abline}} for code examples.
-}
-\keyword{internal}
-
diff --git a/man/stat_bin.Rd b/man/stat_bin.Rd
deleted file mode 100644
index 81d593f..0000000
--- a/man/stat_bin.Rd
+++ /dev/null
@@ -1,81 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-bin.r
-\name{stat_bin}
-\alias{stat_bin}
-\title{Bin data.}
-\usage{
-stat_bin(mapping = NULL, data = NULL, geom = "bar", position = "stack",
-  width = 0.9, drop = FALSE, right = FALSE, binwidth = NULL,
-  origin = NULL, breaks = NULL, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{width}{Width of bars when used with categorical data}
-
-\item{drop}{If TRUE, remove all bins with zero counts}
-
-\item{right}{If \code{TRUE}, right-closed, left-open, if \code{FALSE},
-the default, right-open, left-closed.}
-
-\item{binwidth}{Bin width to use. Defaults to 1/30 of the range of the
-data}
-
-\item{origin}{Origin of first bin}
-
-\item{breaks}{Actual breaks to use.  Overrides bin width and origin}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\value{
-New data frame with additional columns:
-  \item{count}{number of points in bin}
-  \item{density}{density of points in bin, scaled to integrate to 1}
-  \item{ncount}{count, scaled to maximum of 1}
-  \item{ndensity}{density, scaled to maximum of 1}
-}
-\description{
-Missing values are currently silently dropped.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "bin")}
-}
-\examples{
-\donttest{
-simple <- data.frame(x = rep(1:10, each = 2))
-base <- ggplot(simple, aes(x))
-# By default, right = FALSE intervals are of the form [a, b)
-base + stat_bin(binwidth = 1, drop = FALSE, right = FALSE, col = "black")
-# If right = TRUE, and intervals are of the form (a, b]
-base + stat_bin(binwidth = 1, drop = FALSE, right = TRUE, col = "black")
-
-m <- ggplot(movies, aes(x=rating))
-m + stat_bin()
-m + stat_bin(binwidth=0.1)
-m + stat_bin(breaks=seq(4,6, by=0.1))
-# See geom_histogram for more histogram examples
-
-# To create a unit area histogram, use aes(y = ..density..)
-(linehist <- m + stat_bin(aes(y = ..density..), binwidth=0.1,
-  geom="line", position="identity"))
-linehist + stat_density(colour="blue", fill=NA)
-
-# Also works with categorical variables
-ggplot(movies, aes(x=mpaa)) + stat_bin()
-qplot(mpaa, data=movies, stat="bin")
-}
-}
-
diff --git a/man/stat_bin2d.Rd b/man/stat_bin2d.Rd
deleted file mode 100644
index 22526b4..0000000
--- a/man/stat_bin2d.Rd
+++ /dev/null
@@ -1,69 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-bin2d.r
-\name{stat_bin2d}
-\alias{stat_bin2d}
-\title{Count number of observation in rectangular bins.}
-\usage{
-stat_bin2d(mapping = NULL, data = NULL, geom = NULL,
-  position = "identity", bins = 30, drop = TRUE, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{bins}{numeric vector giving number of bins in both vertical and
-horizontal directions. Set to 30 by default.}
-
-\item{drop}{if \code{TRUE} removes all cells with 0 counts.}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-Count number of observation in rectangular bins.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "bin2d")}
-}
-\examples{
-\donttest{
-d <- ggplot(diamonds, aes(carat, price))
-d + stat_bin2d()
-d + geom_bin2d()
-
-# You can control the size of the bins by specifying the number of
-# bins in each direction:
-d + stat_bin2d(bins = 10)
-d + stat_bin2d(bins = 30)
-
-# Or by specifying the width of the bins
-d + stat_bin2d(binwidth = c(1, 1000))
-d + stat_bin2d(binwidth = c(.1, 500))
-
-# Or with a list of breaks
-x <- seq(min(diamonds$carat), max(diamonds$carat), by = 0.1)
-y <- seq(min(diamonds$price), max(diamonds$price), length = 50)
-d + stat_bin2d(breaks = list(x = x, y = y))
-
-# With qplot
-qplot(x, y, data = diamonds, geom="bin2d",
-  xlim = c(4, 10), ylim = c(4, 10))
-qplot(x, y, data = diamonds, geom="bin2d", binwidth = c(0.1, 0.1),
-  xlim = c(4, 10), ylim = c(4, 10))
-}
-}
-\seealso{
-\code{\link{stat_binhex}} for hexagonal binning
-}
-
diff --git a/man/stat_bindot.Rd b/man/stat_bindot.Rd
deleted file mode 100644
index 915cbb1..0000000
--- a/man/stat_bindot.Rd
+++ /dev/null
@@ -1,82 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-bindot.r
-\name{stat_bindot}
-\alias{stat_bindot}
-\title{Bin data for dot plot.}
-\usage{
-stat_bindot(mapping = NULL, data = NULL, geom = "dotplot",
-  position = "identity", binwidth = NULL, origin = NULL, width = 0.9,
-  binaxis = "x", method = "dotdensity", binpositions = "bygroup",
-  drop = FALSE, right = TRUE, na.rm = FALSE, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{binwidth}{When \code{method} is "dotdensity, this specifies maximum bin width.
-When \code{method} is "histodot", this specifies bin width.
-Defaults to 1/30 of the range of the data}
-
-\item{origin}{When \code{method} is "histodot", origin of first bin}
-
-\item{width}{When \code{binaxis} is "y", the spacing of the dot stacks
-for dodging.}
-
-\item{binaxis}{The axis to bin along, "x" (default) or "y"}
-
-\item{method}{"dotdensity" (default) for dot-density binning, or
-"histodot" for fixed bin widths (like stat_bin)}
-
-\item{binpositions}{When \code{method} is "dotdensity", "bygroup" (default)
-determines positions of the bins for each group separately. "all" determines
-positions of the bins with all the data taken together; this is used for
-aligning dot stacks across multiple groups.}
-
-\item{drop}{If TRUE, remove all bins with zero counts}
-
-\item{right}{When \code{method} is "histodot", should intervals be closed
-on the right (a, b], or not [a, b)}
-
-\item{na.rm}{If \code{FALSE} (the default), removes missing values with
-a warning.  If \code{TRUE} silently removes missing values.}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\value{
-New data frame with additional columns:
-  \item{x}{center of each bin, if binaxis is "x"}
-  \item{y}{center of each bin, if binaxis is "x"}
-  \item{binwidth}{max width of each bin if method is "dotdensity";
-    width of each bin if method is "histodot"}
-  \item{count}{number of points in bin}
-  \item{ncount}{count, scaled to maximum of 1}
-  \item{density}{density of points in bin, scaled to integrate to 1,
-    if method is "histodot"}
-  \item{ndensity}{density, scaled to maximum of 1, if method is "histodot"}
-}
-\description{
-Missing values are currently silently dropped.
-If weights are used, they must be integer values.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "bindot")}
-}
-\examples{
-# See geom_dotplot for examples
-}
-\seealso{
-See \code{\link{geom_dotplot}} for examples.
-}
-
diff --git a/man/stat_binhex.Rd b/man/stat_binhex.Rd
deleted file mode 100644
index 9c8eea5..0000000
--- a/man/stat_binhex.Rd
+++ /dev/null
@@ -1,64 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-binhex.r
-\name{stat_binhex}
-\alias{stat_binhex}
-\title{Bin 2d plane into hexagons.}
-\usage{
-stat_binhex(mapping = NULL, data = NULL, geom = "hex",
-  position = "identity", bins = 30, na.rm = FALSE, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{bins}{numeric vector specifying number of bins in both x and y
-directions. Set to 30 by default.}
-
-\item{na.rm}{If \code{FALSE} (the default), removes missing values with
-a warning.  If \code{TRUE} silently removes missing values.}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-Bin 2d plane into hexagons.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "binhex")}
-}
-\examples{
-\donttest{
-d <- ggplot(diamonds, aes(carat, price))
-d + stat_binhex()
-d + geom_hex()
-
-# You can control the size of the bins by specifying the number of
-# bins in each direction:
-d + stat_binhex(bins = 10)
-d + stat_binhex(bins = 30)
-
-# Or by specifying the width of the bins
-d + stat_binhex(binwidth = c(1, 1000))
-d + stat_binhex(binwidth = c(.1, 500))
-
-# With qplot
-qplot(x, y, data = diamonds, geom="hex", xlim = c(4, 10), ylim = c(4, 10))
-qplot(x, y, data = diamonds, geom="hex", xlim = c(4, 10), ylim = c(4, 10),
-  binwidth = c(0.1, 0.1))
-}
-}
-\seealso{
-\code{\link{stat_bin2d}} for rectangular binning
-}
-
diff --git a/man/stat_boxplot.Rd b/man/stat_boxplot.Rd
deleted file mode 100644
index f456773..0000000
--- a/man/stat_boxplot.Rd
+++ /dev/null
@@ -1,56 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-boxplot.r
-\name{stat_boxplot}
-\alias{stat_boxplot}
-\title{Calculate components of box and whisker plot.}
-\usage{
-stat_boxplot(mapping = NULL, data = NULL, geom = "boxplot",
-  position = "dodge", na.rm = FALSE, coef = 1.5, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{na.rm}{If \code{FALSE} (the default), removes missing values with
-a warning.  If \code{TRUE} silently removes missing values.}
-
-\item{coef}{length of the whiskers as multiple of IQR.  Defaults to 1.5}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\value{
-A data frame with additional columns:
-  \item{width}{width of boxplot}
-  \item{ymin}{lower whisker = smallest observation greater than or equal to lower hinge - 1.5 * IQR}
-  \item{lower}{lower hinge, 25\% quantile}
-  \item{notchlower}{lower edge of notch = median - 1.58 * IQR / sqrt(n)}
-  \item{middle}{median, 50\% quantile}
-  \item{notchupper}{upper edge of notch = median + 1.58 * IQR / sqrt(n)}
-  \item{upper}{upper hinge, 75\% quantile}
-  \item{ymax}{upper whisker = largest observation less than or equal to upper hinge + 1.5 * IQR}
-}
-\description{
-Calculate components of box and whisker plot.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "boxplot")}
-}
-\examples{
-# See geom_boxplot for examples
-}
-\seealso{
-See \code{\link{geom_boxplot}} for examples.
-}
-
diff --git a/man/stat_contour.Rd b/man/stat_contour.Rd
deleted file mode 100644
index 3bbb8c7..0000000
--- a/man/stat_contour.Rd
+++ /dev/null
@@ -1,85 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-contour.r
-\name{stat_contour}
-\alias{stat_contour}
-\title{Calculate contours of 3d data.}
-\usage{
-stat_contour(mapping = NULL, data = NULL, geom = "path",
-  position = "identity", na.rm = FALSE, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{na.rm}{If \code{FALSE} (the default), removes missing values with
-a warning.  If \code{TRUE} silently removes missing values.}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\value{
-A data frame with additional column:
- \item{level}{height of contour}
-}
-\description{
-Calculate contours of 3d data.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "contour")}
-}
-\examples{
-\donttest{
-# Generate data
-library(reshape2) # for melt
-volcano3d <- melt(volcano)
-names(volcano3d) <- c("x", "y", "z")
-
-# Basic plot
-v <- ggplot(volcano3d, aes(x, y, z = z))
-v + stat_contour()
-
-# Setting bins creates evenly spaced contours in the range of the data
-v + stat_contour(bins = 2)
-v + stat_contour(bins = 10)
-
-# Setting binwidth does the same thing, parameterised by the distance
-# between contours
-v + stat_contour(binwidth = 2)
-v + stat_contour(binwidth = 5)
-v + stat_contour(binwidth = 10)
-v + stat_contour(binwidth = 2, size = 0.5, colour = "grey50") +
-  stat_contour(binwidth = 10, size = 1)
-
-# Add aesthetic mappings
-v + stat_contour(aes(size = ..level..))
-v + stat_contour(aes(colour = ..level..))
-
-# Change scale
-v + stat_contour(aes(colour = ..level..), size = 2) +
-  scale_colour_gradient(low = "brown", high = "white")
-
-# Set aesthetics to fixed value
-v + stat_contour(colour = "red")
-v + stat_contour(size = 2, linetype = 4)
-
-# Try different geoms
-v + stat_contour(geom="polygon", aes(fill=..level..))
-v + geom_tile(aes(fill = z)) + stat_contour()
-
-# Use qplot instead
-qplot(x, y, z = z, data = volcano3d, geom = "contour")
-qplot(x, y, z = z, data = volcano3d, stat = "contour", geom = "path")
-}
-}
-
diff --git a/man/stat_density.Rd b/man/stat_density.Rd
deleted file mode 100644
index 3abd787..0000000
--- a/man/stat_density.Rd
+++ /dev/null
@@ -1,126 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-density.r
-\name{stat_density}
-\alias{stat_density}
-\title{1d kernel density estimate.}
-\usage{
-stat_density(mapping = NULL, data = NULL, geom = "area",
-  position = "stack", adjust = 1, kernel = "gaussian", trim = FALSE,
-  na.rm = FALSE, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{adjust}{see \code{\link{density}} for details}
-
-\item{kernel}{kernel used for density estimation, see
-\code{\link{density}} for details}
-
-\item{trim}{if \code{TRUE}, the default, densities are trimmed to the
-actual range of the data.  If \code{FALSE}, they are extended by the
-default 3 bandwidths (as specified by the \code{cut} parameter to
-\code{\link{density}})}
-
-\item{na.rm}{If \code{FALSE} (the default), removes missing values with
-a warning.  If \code{TRUE} silently removes missing values.}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\value{
-data.frame with additional columns:
-  \item{density}{density estimate}
-  \item{count}{density * number of points - useful for stacked density
-     plots}
-  \item{scaled}{density estimate, scaled to maximum of 1}
-}
-\description{
-1d kernel density estimate.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "density")}
-}
-\examples{
-\donttest{
-m <- ggplot(movies, aes(x = rating))
-m + geom_density()
-
-# Adjust parameters
-m + geom_density(kernel = "rectangular")
-m + geom_density(kernel = "biweight")
-m + geom_density(kernel = "epanechnikov")
-m + geom_density(adjust=1/5) # Very rough
-m + geom_density(adjust=5) # Very smooth
-
-# Adjust aesthetics
-m + geom_density(aes(fill=factor(Drama)), size=2)
-# Scale so peaks have same height:
-m + geom_density(aes(fill=factor(Drama), y = ..scaled..), size=2)
-
-m + geom_density(colour="darkgreen", size=2)
-m + geom_density(colour="darkgreen", size=2, fill=NA)
-m + geom_density(colour="darkgreen", size=2, fill="green")
-
-# Change scales
-(m <- ggplot(movies, aes(x=votes)) + geom_density(trim = TRUE))
-m + scale_x_log10()
-m + coord_trans(x="log10")
-m + scale_x_log10() + coord_trans(x="log10")
-
-# Also useful with
-m + stat_bin()
-
-# Make a volcano plot
-ggplot(diamonds, aes(x = price)) +
-  stat_density(aes(ymax = ..density..,  ymin = -..density..),
-    fill = "grey50", colour = "grey50",
-    geom = "ribbon", position = "identity") +
-  facet_grid(. ~ cut) +
-  coord_flip()
-
-# Stacked density plots
-# If you want to create a stacked density plot, you need to use
-# the 'count' (density * n) variable instead of the default density
-
-# Loses marginal densities
-qplot(rating, ..density.., data=movies, geom="density", fill=mpaa, position="stack")
-# Preserves marginal densities
-qplot(rating, ..count.., data=movies, geom="density", fill=mpaa, position="stack")
-
-# You can use position="fill" to produce a conditional density estimate
-qplot(rating, ..count.., data=movies, geom="density", fill=mpaa, position="fill")
-
-# Need to be careful with weighted data
-m <- ggplot(movies, aes(x=rating, weight=votes))
-m + geom_histogram(aes(y = ..count..)) + geom_density(fill=NA)
-
-m <- ggplot(movies, aes(x=rating, weight=votes/sum(votes)))
-m + geom_histogram(aes(y=..density..)) + geom_density(fill=NA, colour="black")
-
-library(plyr) # to access round_any
-movies$decade <- round_any(movies$year, 10)
-m <- ggplot(movies, aes(x=rating, colour=decade, group=decade))
-m + geom_density(fill=NA)
-m + geom_density(fill=NA) + aes(y = ..count..)
-
-# Use qplot instead
-qplot(length, data=movies, geom="density", weight=rating)
-qplot(length, data=movies, geom="density", weight=rating/sum(rating))
-}
-}
-\seealso{
-\code{\link{stat_bin}} for the histogram
-}
-
diff --git a/man/stat_density2d.Rd b/man/stat_density2d.Rd
deleted file mode 100644
index a5b0de1..0000000
--- a/man/stat_density2d.Rd
+++ /dev/null
@@ -1,84 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-density-2d.r
-\name{stat_density2d}
-\alias{stat_density2d}
-\title{2d density estimation.}
-\usage{
-stat_density2d(mapping = NULL, data = NULL, geom = "density2d",
-  position = "identity", na.rm = FALSE, contour = TRUE, n = 100, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{na.rm}{If \code{FALSE} (the default), removes missing values with
-a warning.  If \code{TRUE} silently removes missing values.}
-
-\item{contour}{If \code{TRUE}, contour the results of the 2d density
-estimation}
-
-\item{n}{number of grid points in each direction}
-
-\item{...}{other arguments passed on to \code{\link{kde2d}}}
-}
-\value{
-A data frame in the same format as \code{\link{stat_contour}}
-}
-\description{
-2d density estimation.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "density2d")}
-}
-\examples{
-\donttest{
-library("MASS")
-data(geyser, "MASS")
-
-m <- ggplot(geyser, aes(x = duration, y = waiting)) +
-  geom_point() + xlim(0.5, 6) + ylim(40, 110)
-m + geom_density2d()
-
-dens <- kde2d(geyser$duration, geyser$waiting, n = 50,
-              lims = c(0.5, 6, 40, 110))
-densdf <- data.frame(expand.grid(duration = dens$x, waiting = dens$y),
- z = as.vector(dens$z))
-m + geom_contour(aes(z=z), data=densdf)
-
-m + geom_density2d() + scale_y_log10()
-m + geom_density2d() + coord_trans(y="log10")
-
-m + stat_density2d(aes(fill = ..level..), geom="polygon")
-
-qplot(duration, waiting, data=geyser, geom=c("point","density2d")) +
-  xlim(0.5, 6) + ylim(40, 110)
-
-# If you map an aesthetic to a categorical variable, you will get a
-# set of contours for each value of that variable
-set.seed(4393)
-dsmall <- diamonds[sample(nrow(diamonds), 1000), ]
-qplot(x, y, data = dsmall, geom = "density2d", colour = cut)
-qplot(x, y, data = dsmall, geom = "density2d", linetype = cut)
-qplot(carat, price, data = dsmall, geom = "density2d", colour = cut)
-d <- ggplot(dsmall, aes(carat, price)) + xlim(1,3)
-d + geom_point() + geom_density2d()
-
-# If we turn contouring off, we can use use geoms like tiles:
-d + stat_density2d(geom="tile", aes(fill = ..density..), contour = FALSE)
-last_plot() + scale_fill_gradient(limits=c(1e-5,8e-4))
-
-# Or points:
-d + stat_density2d(geom="point", aes(size = ..density..), contour = FALSE)
-}
-}
-
diff --git a/man/stat_ecdf.Rd b/man/stat_ecdf.Rd
index 505d52b..28db7ab 100644
--- a/man/stat_ecdf.Rd
+++ b/man/stat_ecdf.Rd
@@ -1,11 +1,12 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/stat-ecdf.r
 \name{stat_ecdf}
 \alias{stat_ecdf}
 \title{Empirical Cumulative Density Function}
 \usage{
 stat_ecdf(mapping = NULL, data = NULL, geom = "step",
-  position = "identity", n = NULL, ...)
+  position = "identity", n = NULL, na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
 }
 \arguments{
 \item{mapping}{The aesthetic mapping, usually constructed with
@@ -17,27 +18,42 @@ the plot defaults.}
 
 \item{geom}{The geometric object to use display the data}
 
-\item{position}{The position adjustment to use for overlappling points
+\item{position}{The position adjustment to use for overlapping points
 on this layer}
 
 \item{n}{if NULL, do not interpolate. If not NULL, this is the number
 of points to interpolate with.}
 
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
 \item{...}{other arguments passed on to \code{\link{layer}}. This can
 include aesthetics whose values you want to set, not map. See
 \code{\link{layer}} for more details.}
 }
-\value{
-a data.frame with additional columns:
+\description{
+Empirical Cumulative Density Function
+}
+\section{Computed variables}{
+
+\describe{
   \item{x}{x in data}
   \item{y}{cumulative density corresponding x}
 }
-\description{
-Empirical Cumulative Density Function
 }
 \examples{
 \donttest{
-qplot(rnorm(1000), stat = "ecdf", geom = "step")
+df <- data.frame(x = rnorm(1000))
+ggplot(df, aes(x)) + stat_ecdf(geom = "step")
 
 df <- data.frame(x = c(rnorm(100, 0, 3), rnorm(100, 0, 10)),
                  g = gl(2, 100))
diff --git a/man/stat_ellipse.Rd b/man/stat_ellipse.Rd
index 28bb759..5abfd3e 100644
--- a/man/stat_ellipse.Rd
+++ b/man/stat_ellipse.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/stat-ellipse.R
 \name{stat_ellipse}
 \alias{stat_ellipse}
@@ -6,7 +6,7 @@
 \usage{
 stat_ellipse(mapping = NULL, data = NULL, geom = "path",
   position = "identity", type = "t", level = 0.95, segments = 51,
-  na.rm = FALSE, ...)
+  na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...)
 }
 \arguments{
 \item{mapping}{The aesthetic mapping, usually constructed with
@@ -18,14 +18,14 @@ the plot defaults.}
 
 \item{geom}{The geometric object to use display the data}
 
-\item{position}{The position adjustment to use for overlappling points
+\item{position}{The position adjustment to use for overlapping points
 on this layer}
 
 \item{type}{The type of ellipse.
 The default \code{"t"} assumes a multivariate t-distribution, and
 \code{"norm"} assumes a multivariate normal distribution.
 \code{"euclid"} draws a circle with the radius equal to \code{level},
-representing the euclidian distance from the center.
+representing the euclidean distance from the center.
 This ellipse probably won't appear circular unless \code{coord_fixed()} is applied.}
 
 \item{level}{The confidence level at which to draw an ellipse (default is 0.95),
@@ -36,40 +36,49 @@ or, if \code{type="euclid"}, the radius of the circle to be drawn.}
 \item{na.rm}{If \code{FALSE} (the default), removes missing values with
 a warning.  If \code{TRUE} silently removes missing values.}
 
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
 \item{...}{other arguments passed on to \code{\link{layer}}. This can
 include aesthetics whose values you want to set, not map. See
 \code{\link{layer}} for more details.}
 }
 \description{
-Plot data ellipses.
-}
-\details{
-The method for calculating the ellipses has been modified from car::ellipse (Fox and Weisberg, 2011)
+The method for calculating the ellipses has been modified from
+\code{car::ellipse} (Fox and Weisberg, 2011)
 }
 \examples{
-ggplot(faithful, aes(waiting, eruptions))+
-  geom_point()+
+ggplot(faithful, aes(waiting, eruptions)) +
+  geom_point() +
   stat_ellipse()
 
-ggplot(faithful, aes(waiting, eruptions, color = eruptions > 3))+
-  geom_point()+
+ggplot(faithful, aes(waiting, eruptions, color = eruptions > 3)) +
+  geom_point() +
   stat_ellipse()
 
-ggplot(faithful, aes(waiting, eruptions, color = eruptions > 3))+
-  geom_point()+
-  stat_ellipse(type = "norm", linetype = 2)+
+ggplot(faithful, aes(waiting, eruptions, color = eruptions > 3)) +
+  geom_point() +
+  stat_ellipse(type = "norm", linetype = 2) +
   stat_ellipse(type = "t")
 
-ggplot(faithful, aes(waiting, eruptions, color = eruptions > 3))+
-  geom_point()+
-  stat_ellipse(type = "norm", linetype = 2)+
-  stat_ellipse(type = "euclid", level = 3)+
+ggplot(faithful, aes(waiting, eruptions, color = eruptions > 3)) +
+  geom_point() +
+  stat_ellipse(type = "norm", linetype = 2) +
+  stat_ellipse(type = "euclid", level = 3) +
   coord_fixed()
 
-ggplot(faithful, aes(waiting, eruptions, color = eruptions > 3))+
+ggplot(faithful, aes(waiting, eruptions, fill = eruptions > 3)) +
   stat_ellipse(geom = "polygon")
 }
 \references{
-John Fox and Sanford Weisberg (2011). An {R} Companion to Applied Regression, Second Edition. Thousand Oaks CA: Sage. URL: http://socserv.socsci.mcmaster.ca/jfox/Books/Companion
+John Fox and Sanford Weisberg (2011). An {R} Companion to
+  Applied Regression, Second Edition. Thousand Oaks CA: Sage. URL:
+  \url{http://socserv.socsci.mcmaster.ca/jfox/Books/Companion}
 }
 
diff --git a/man/stat_function.Rd b/man/stat_function.Rd
index 195eb80..f9548db 100644
--- a/man/stat_function.Rd
+++ b/man/stat_function.Rd
@@ -1,11 +1,12 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/stat-function.r
 \name{stat_function}
 \alias{stat_function}
 \title{Superimpose a function.}
 \usage{
 stat_function(mapping = NULL, data = NULL, geom = "path",
-  position = "identity", fun, n = 101, args = list(), ...)
+  position = "identity", fun, n = 101, args = list(), na.rm = FALSE,
+  show.legend = NA, inherit.aes = TRUE, ...)
 }
 \arguments{
 \item{mapping}{The aesthetic mapping, usually constructed with
@@ -17,7 +18,7 @@ the plot defaults.}
 
 \item{geom}{The geometric object to use display the data}
 
-\item{position}{The position adjustment to use for overlappling points
+\item{position}{The position adjustment to use for overlapping points
 on this layer}
 
 \item{fun}{function to use}
@@ -26,15 +27,22 @@ on this layer}
 
 \item{args}{list of additional arguments to pass to \code{fun}}
 
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
 \item{...}{other arguments passed on to \code{\link{layer}}. This can
 include aesthetics whose values you want to set, not map. See
 \code{\link{layer}} for more details.}
 }
-\value{
-a data.frame with additional columns:
-  \item{x}{x's along a grid}
-  \item{y}{value of function evaluated at corresponding x}
-}
 \description{
 Superimpose a function.
 }
@@ -42,9 +50,21 @@ Superimpose a function.
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "function")}
 }
+
+\section{Computed variables}{
+
+\describe{
+  \item{x}{x's along a grid}
+  \item{y}{value of function evaluated at corresponding x}
+}
+}
 \examples{
-x <- rnorm(100)
-base <- qplot(x, geom = "density")
+set.seed(1492)
+df <- data.frame(
+  x = rnorm(100)
+)
+x <- df$x
+base <- ggplot(df, aes(x)) + geom_density()
 base + stat_function(fun = dnorm, colour = "red")
 base + stat_function(fun = dnorm, colour = "red", arg = list(mean = 3))
 
@@ -52,14 +72,12 @@ base + stat_function(fun = dnorm, colour = "red", arg = list(mean = 3))
 # Examples adapted from Kohske Takahashi
 
 # Specify range of x-axis
-qplot(c(0, 2), stat = "function", fun = exp, geom = "line")
-ggplot(data.frame(x = c(0, 2)), aes(x)) + stat_function(fun = exp)
+ggplot(data.frame(x = c(0, 2)), aes(x)) +
+  stat_function(fun = exp, geom = "line")
+
 # Plot a normal curve
 ggplot(data.frame(x = c(-5, 5)), aes(x)) + stat_function(fun = dnorm)
-# With qplot
-qplot(c(-5, 5), stat = "function", fun = dnorm, geom = "line")
-# Or
-qplot(c(-5, 5), geom = "blank") + stat_function(fun = dnorm)
+
 # To specify a different mean or sd, use the args parameter to supply new values
 ggplot(data.frame(x = c(-5, 5)), aes(x)) +
   stat_function(fun = dnorm, args = list(mean = 2, sd = .5))
diff --git a/man/stat_hline.Rd b/man/stat_hline.Rd
deleted file mode 100644
index 719aedb..0000000
--- a/man/stat_hline.Rd
+++ /dev/null
@@ -1,37 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-vline.r
-\name{stat_hline}
-\alias{stat_hline}
-\title{Add a horizontal line}
-\usage{
-stat_hline(mapping = NULL, data = NULL, geom = "hline",
-  position = "identity", yintercept, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-Add a horizontal line
-}
-\examples{
-# see geom_hline
-}
-\seealso{
-\code{\link{geom_hline}} for code examples.
-}
-\keyword{internal}
-
diff --git a/man/stat_identity.Rd b/man/stat_identity.Rd
index 1a63af0..ca50612 100644
--- a/man/stat_identity.Rd
+++ b/man/stat_identity.Rd
@@ -1,11 +1,11 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/stat-identity.r
 \name{stat_identity}
 \alias{stat_identity}
 \title{Identity statistic.}
 \usage{
 stat_identity(mapping = NULL, data = NULL, geom = "point",
-  position = "identity", width = NULL, height = NULL, ...)
+  position = "identity", show.legend = NA, inherit.aes = TRUE, ...)
 }
 \arguments{
 \item{mapping}{The aesthetic mapping, usually constructed with
@@ -17,25 +17,27 @@ the plot defaults.}
 
 \item{geom}{The geometric object to use display the data}
 
-\item{position}{The position adjustment to use for overlappling points
+\item{position}{The position adjustment to use for overlapping points
 on this layer}
 
-\item{width}{The width of the tiles.}
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
 
-\item{height}{The height of the tiles.}
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
 
 \item{...}{other arguments passed on to \code{\link{layer}}. This can
 include aesthetics whose values you want to set, not map. See
 \code{\link{layer}} for more details.}
 }
 \description{
-Identity statistic.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "identity")}
+The identity statistic leaves the data unchanged.
 }
 \examples{
-# Doesn't do anything, so hard to come up a useful example
+p <- ggplot(mtcars, aes(wt, mpg))
+p + stat_identity()
 }
 
diff --git a/man/stat_qq.Rd b/man/stat_qq.Rd
index afbb2b2..897d8a3 100644
--- a/man/stat_qq.Rd
+++ b/man/stat_qq.Rd
@@ -1,12 +1,17 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/stat-qq.r
 \name{stat_qq}
+\alias{geom_qq}
 \alias{stat_qq}
 \title{Calculation for quantile-quantile plot.}
 \usage{
 stat_qq(mapping = NULL, data = NULL, geom = "point",
-  position = "identity", distribution = qnorm, dparams = list(),
-  na.rm = FALSE, ...)
+  position = "identity", distribution = stats::qnorm, dparams = list(),
+  na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...)
+
+geom_qq(mapping = NULL, data = NULL, geom = "point",
+  position = "identity", distribution = stats::qnorm, dparams = list(),
+  na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...)
 }
 \arguments{
 \item{mapping}{The aesthetic mapping, usually constructed with
@@ -18,22 +23,29 @@ the plot defaults.}
 
 \item{geom}{The geometric object to use display the data}
 
-\item{position}{The position adjustment to use for overlappling points
+\item{position}{The position adjustment to use for overlapping points
 on this layer}
 
 \item{distribution}{Distribution function to use, if x not specified}
 
-\item{dparams}{Parameters for distribution function}
+\item{dparams}{Additional parameters passed on to \code{distribution}
+function.}
 
 \item{na.rm}{If \code{FALSE} (the default), removes missing values with
 a warning.  If \code{TRUE} silently removes missing values.}
 
-\item{...}{Other arguments passed to distribution function}
-}
-\value{
-a data.frame with additional columns:
-  \item{sample}{sample quantiles}
-  \item{theoretical}{theoretical quantiles}
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. This can
+include aesthetics whose values you want to set, not map. See
+\code{\link{layer}} for more details.}
 }
 \description{
 Calculation for quantile-quantile plot.
@@ -42,30 +54,31 @@ Calculation for quantile-quantile plot.
 
 \Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "qq")}
 }
-\examples{
-\donttest{
-# From ?qqplot
-y <- rt(200, df = 5)
-qplot(sample = y, stat="qq")
 
-# qplot is smart enough to use stat_qq if you use sample
-qplot(sample = y)
-qplot(sample = precip)
+\section{Computed variables}{
 
-qplot(sample = y, dist = qt, dparams = list(df = 5))
-
-df <- data.frame(y)
-ggplot(df, aes(sample = y)) + stat_qq()
-ggplot(df, aes(sample = y)) + geom_point(stat = "qq")
+\describe{
+  \item{sample}{sample quantiles}
+  \item{theoretical}{theoretical quantiles}
+}
+}
+\examples{
+\donttest{
+df <- data.frame(y = rt(200, df = 5))
+p <- ggplot(df, aes(sample = y))
+p + stat_qq()
+p + geom_point(stat = "qq")
 
 # Use fitdistr from MASS to estimate distribution params
-library(MASS)
-params <- as.list(fitdistr(y, "t")$estimate)
-ggplot(df, aes(sample = y)) + stat_qq(dist = qt, dparam = params)
+params <- as.list(MASS::fitdistr(df$y, "t")$estimate)
+ggplot(df, aes(sample = y)) +
+  stat_qq(distribution = qt, dparams = params["df"])
 
 # Using to explore the distribution of a variable
-qplot(sample = mpg, data = mtcars)
-qplot(sample = mpg, data = mtcars, colour = factor(cyl))
+ggplot(mtcars) +
+  stat_qq(aes(sample = mpg))
+ggplot(mtcars) +
+  stat_qq(aes(sample = mpg, colour = factor(cyl)))
 }
 }
 
diff --git a/man/stat_quantile.Rd b/man/stat_quantile.Rd
deleted file mode 100644
index cc78ab1..0000000
--- a/man/stat_quantile.Rd
+++ /dev/null
@@ -1,80 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-quantile.r
-\name{stat_quantile}
-\alias{stat_quantile}
-\title{Continuous quantiles.}
-\usage{
-stat_quantile(mapping = NULL, data = NULL, geom = "quantile",
-  position = "identity", quantiles = c(0.25, 0.5, 0.75), formula = NULL,
-  method = "rq", na.rm = FALSE, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{quantiles}{conditional quantiles of y to calculate and display}
-
-\item{formula}{formula relating y variables to x variables}
-
-\item{method}{Quantile regression method to use.  Currently only supports
-\code{\link[quantreg]{rq}}.}
-
-\item{na.rm}{If \code{FALSE} (the default), removes missing values with
-a warning.  If \code{TRUE} silently removes missing values.}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\value{
-a data.frame with additional columns:
-  \item{quantile}{quantile of distribution}
-}
-\description{
-Continuous quantiles.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "quantile")}
-}
-\examples{
-\donttest{
-msamp <- movies[sample(nrow(movies), 1000), ]
-m <- ggplot(msamp, aes(year, rating)) + geom_point()
-m + stat_quantile()
-m + stat_quantile(quantiles = 0.5)
-q10 <- seq(0.05, 0.95, by=0.05)
-m + stat_quantile(quantiles = q10)
-
-# You can also use rqss to fit smooth quantiles
-m + stat_quantile(method = "rqss")
-# Note that rqss doesn't pick a smoothing constant automatically, so
-# you'll need to tweak lambda yourself
-m + stat_quantile(method = "rqss", lambda = 10)
-m + stat_quantile(method = "rqss", lambda = 100)
-
-# Use 'votes' as weights for the quantile calculation
-m + stat_quantile(aes(weight=votes))
-
-# Change scale
-m + stat_quantile(aes(colour = ..quantile..), quantiles = q10)
-m + stat_quantile(aes(colour = ..quantile..), quantiles = q10) +
-  scale_colour_gradient2(midpoint = 0.5)
-
-# Set aesthetics to fixed value
-m + stat_quantile(colour = "red", size = 2, linetype = 2)
-
-# Use qplot instead
-qplot(year, rating, data=movies, geom="quantile")
-}
-}
-
diff --git a/man/stat_smooth.Rd b/man/stat_smooth.Rd
deleted file mode 100644
index d0dc5ee..0000000
--- a/man/stat_smooth.Rd
+++ /dev/null
@@ -1,136 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-smooth.r
-\name{stat_smooth}
-\alias{stat_smooth}
-\title{Add a smoother.}
-\usage{
-stat_smooth(mapping = NULL, data = NULL, geom = "smooth",
-  position = "identity", method = "auto", formula = y ~ x, se = TRUE,
-  n = 80, fullrange = FALSE, level = 0.95, na.rm = FALSE, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{method}{smoothing method (function) to use, eg. lm, glm, gam, loess,
-rlm. For datasets with n < 1000 default is \code{\link{loess}}. For datasets
-with 1000 or more observations defaults to gam, see \code{\link[mgcv]{gam}}
-for more details.}
-
-\item{formula}{formula to use in smoothing function, eg. \code{y ~ x},
-\code{y ~ poly(x, 2)}, \code{y ~ log(x)}}
-
-\item{se}{display confidence interval around smooth? (TRUE by default, see
-level to control}
-
-\item{n}{number of points to evaluate smoother at}
-
-\item{fullrange}{should the fit span the full range of the plot, or just
-the data}
-
-\item{level}{level of confidence interval to use (0.95 by default)}
-
-\item{na.rm}{If \code{FALSE} (the default), removes missing values with
-a warning.  If \code{TRUE} silently removes missing values.}
-
-\item{...}{other arguments are passed to smoothing function}
-}
-\value{
-a data.frame with additional columns
-  \item{y}{predicted value}
-  \item{ymin}{lower pointwise confidence interval around the mean}
-  \item{ymax}{upper pointwise confidence interval around the mean}
-  \item{se}{standard error}
-}
-\description{
-Aids the eye in seeing patterns in the presence of overplotting.
-}
-\details{
-Calculation is performed by the (currently undocumented)
-\code{predictdf} generic function and its methods.  For most methods
-the confidence bounds are computed using the \code{\link{predict}}
-method - the exceptions are \code{loess} which uses a t-based
-approximation, and for \code{glm} where the normal confidence interval
-is constructed on the link scale, and then back-transformed to the response
-scale.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "smooth")}
-}
-\examples{
-\donttest{
-c <- ggplot(mtcars, aes(qsec, wt))
-c + stat_smooth()
-c + stat_smooth() + geom_point()
-
-# Adjust parameters
-c + stat_smooth(se = FALSE) + geom_point()
-
-c + stat_smooth(span = 0.9) + geom_point()
-c + stat_smooth(level = 0.99) + geom_point()
-c + stat_smooth(method = "lm") + geom_point()
-
-library(splines)
-library(MASS)
-c + stat_smooth(method = "lm", formula = y ~ ns(x,3)) +
-  geom_point()
-c + stat_smooth(method = rlm, formula= y ~ ns(x,3)) + geom_point()
-
-# The default confidence band uses a transparent colour.
-# This currently only works on a limited number of graphics devices
-# (including Quartz, PDF, and Cairo) so you may need to set the
-# fill colour to a opaque colour, as shown below
-c + stat_smooth(fill = "grey50", size = 2, alpha = 1)
-c + stat_smooth(fill = "blue", size = 2, alpha = 1)
-
-# The colour of the line can be controlled with the colour aesthetic
-c + stat_smooth(fill="blue", colour="darkblue", size=2)
-c + stat_smooth(fill="blue", colour="darkblue", size=2, alpha = 0.2)
-c + geom_point() +
-  stat_smooth(fill="blue", colour="darkblue", size=2, alpha = 0.2)
-
-# Smoothers for subsets
-c <- ggplot(mtcars, aes(y=wt, x=mpg)) + facet_grid(. ~ cyl)
-c + stat_smooth(method=lm) + geom_point()
-c + stat_smooth(method=lm, fullrange = TRUE) + geom_point()
-
-# Geoms and stats are automatically split by aesthetics that are factors
-c <- ggplot(mtcars, aes(y=wt, x=mpg, colour=factor(cyl)))
-c + stat_smooth(method=lm) + geom_point()
-c + stat_smooth(method=lm, aes(fill = factor(cyl))) + geom_point()
-c + stat_smooth(method=lm, fullrange=TRUE, alpha = 0.1) + geom_point()
-
-# Use qplot instead
-qplot(qsec, wt, data=mtcars, geom=c("smooth", "point"))
-}
-
-\dontrun{
-# Example with logistic regression
-data("kyphosis", package="rpart")
-qplot(Age, Kyphosis, data=kyphosis)
-qplot(Age, data=kyphosis, facets = . ~ Kyphosis, binwidth = 10)
-qplot(Age, Kyphosis, data=kyphosis, position="jitter")
-qplot(Age, Kyphosis, data=kyphosis, position=position_jitter(height=0.1))
-
-qplot(Age, as.numeric(Kyphosis) - 1, data = kyphosis) +
-  stat_smooth(method="glm", family="binomial")
-qplot(Age, as.numeric(Kyphosis) - 1, data=kyphosis) +
-  stat_smooth(method="glm", family="binomial", formula = y ~ ns(x, 2))
-}
-}
-\seealso{
-\code{\link{lm}} for linear smooths,
-  \code{\link{glm}} for generalised linear smooths,
-  \code{\link{loess}} for local smooths
-}
-
diff --git a/man/stat_spoke.Rd b/man/stat_spoke.Rd
deleted file mode 100644
index 0b52805..0000000
--- a/man/stat_spoke.Rd
+++ /dev/null
@@ -1,49 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-spoke.r
-\name{stat_spoke}
-\alias{stat_spoke}
-\title{Convert angle and radius to xend and yend.}
-\usage{
-stat_spoke(mapping = NULL, data = NULL, geom = "segment",
-  position = "identity", ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\value{
-a data.frame with additional columns
-  \item{xend}{x position of end of line segment}
-  \item{yend}{x position of end of line segment}
-}
-\description{
-Convert angle and radius to xend and yend.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "spoke")}
-}
-\examples{
-df <- expand.grid(x = 1:10, y=1:10)
-df$angle <- runif(100, 0, 2*pi)
-df$speed <- runif(100, 0, 0.5)
-
-qplot(x, y, data=df) + stat_spoke(aes(angle=angle), radius = 0.5)
-last_plot() + scale_y_reverse()
-
-qplot(x, y, data=df) + stat_spoke(aes(angle=angle, radius=speed))
-}
-
diff --git a/man/stat_sum.Rd b/man/stat_sum.Rd
deleted file mode 100644
index c8f5804..0000000
--- a/man/stat_sum.Rd
+++ /dev/null
@@ -1,79 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-sum.r
-\name{stat_sum}
-\alias{stat_sum}
-\title{Sum unique values.  Useful for overplotting on scatterplots.}
-\usage{
-stat_sum(mapping = NULL, data = NULL, geom = "point",
-  position = "identity", ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\value{
-a data.frame with additional columns
- \item{n}{number of observations at position}
- \item{prop}{percent of points in that panel at that position}
-}
-\description{
-Sum unique values.  Useful for overplotting on scatterplots.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "sum")}
-}
-\examples{
-\donttest{
-d <- ggplot(diamonds, aes(x = cut, y = clarity))
-# By default, all categorical variables in the plot form grouping
-# variables, and the default behavior in stat_sum is to show the
-# proportion. Specifying stat_sum with no group identifier leads to
-# a plot which is not meaningful:
-d + stat_sum()
-# To correct this problem and achieve a more desirable plot, we need
-# to specify which group the proportion is to be calculated over.
-# There are several ways to do this:
-
-# by overall proportion
-d + stat_sum(aes(group = 1))
-d + stat_sum(aes(group = 1)) + scale_size(range = c(3, 10))
-d + stat_sum(aes(group = 1)) + scale_size_area(max_size = 10)
-
-# by cut
-d + stat_sum(aes(group = cut))
-d + stat_sum(aes(group = cut, colour = cut))
-
-# by clarity
-d + stat_sum(aes(group = clarity))
-d + stat_sum(aes(group = clarity, colour = cut))
-
-# Instead of proportions, can also use sums
-d + stat_sum(aes(size = ..n..))
-
-# Can also weight by another variable
-d + stat_sum(aes(group = 1, weight = price))
-d + stat_sum(aes(group = 1, weight = price, size = ..n..))
-
-# Or using qplot
-qplot(cut, clarity, data = diamonds)
-qplot(cut, clarity, data = diamonds, stat = "sum", group = 1)
-}
-}
-\seealso{
-\code{\link{ggfluctuation}} for a fluctuation diagram,
-}
-
diff --git a/man/stat_summary.Rd b/man/stat_summary.Rd
index 8b83b3d..731f907 100644
--- a/man/stat_summary.Rd
+++ b/man/stat_summary.Rd
@@ -1,32 +1,86 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-summary.r
-\name{stat_summary}
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/stat-summary-bin.R, R/stat-summary.r
+\name{stat_summary_bin}
 \alias{stat_summary}
-\title{Summarise y values at every unique x.}
+\alias{stat_summary_bin}
+\title{Summarise y values at unique/binned x x.}
 \usage{
+stat_summary_bin(mapping = NULL, data = NULL, geom = "pointrange",
+  fun.data = NULL, fun.y = NULL, fun.ymax = NULL, fun.ymin = NULL,
+  fun.args = list(), na.rm = FALSE, position = "identity",
+  show.legend = NA, inherit.aes = TRUE, ...)
+
 stat_summary(mapping = NULL, data = NULL, geom = "pointrange",
-  position = "identity", ...)
+  fun.data = NULL, fun.y = NULL, fun.ymax = NULL, fun.ymin = NULL,
+  fun.args = list(), na.rm = FALSE, position = "identity",
+  show.legend = NA, inherit.aes = TRUE, ...)
 }
 \arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
+\item{mapping}{Set of aesthetic mappings created by \code{\link{aes}} or
+\code{\link{aes_}}. If specified and \code{inherit.aes = TRUE} (the
+default), is combined with the default mapping at the top level of the
+plot. You only need to supply \code{mapping} if there isn't a mapping
+defined for the plot.}
+
+\item{data}{A data frame. If specified, overrides the default data frame
+defined at the top level of the plot.}
+
+\item{geom}{Use to override the default connection between
+\code{geom_histogram}/\code{geom_freqpoly} and \code{stat_bin}.}
+
+\item{fun.data}{A function that is given the complete data and should
+return a data frame with variables \code{ymin}, \code{y}, and \code{ymax}.}
+
+\item{fun.ymin, fun.y, fun.ymax}{Alternatively, supply three individual
+functions that are each passed a vector of x's and should return a
+single number.}
+
+\item{fun.args}{Optional additional arguments passed on to the functions.}
 
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
 
-\item{geom}{The geometric object to use display the data}
+\item{position}{Position adjustment, either as a string, or the result of
+a call to a position adjustment function.}
 
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
 
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. There are
+  three types of arguments you can use here:
+
+  \itemize{
+  \item Aesthetics: to set an aesthetic to a fixed value, like
+     \code{color = "red"} or \code{size = 3}.
+  \item Other arguments to the layer, for example you override the
+    default \code{stat} associated with the layer.
+  \item Other arguments passed on to the stat.
+  }}
+}
+\description{
+\code{stat_summary} operates on unique \code{x}; \code{stat_summary_bin}
+operators on binned \code{x}. They are more flexible versions of
+\code{\link{stat_bin}}: instead of just counting, the can compute any
+aggregate.
 }
-\value{
-a data.frame with additional columns:
-  \item{fun.data}{Complete summary function. Should take data frame as
+\section{Aesthetics}{
+
+\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "summary")}
+}
+
+\section{Summary functions}{
+
+You can either supply summary functions individually (\code{fun.y},
+\code{fun.ymax}, \code{fun.ymin}), or as a single function (\code{fun.data}):
+
+\describe{
+  \item{fun.data}{Complete summary function. Should take numeric vector as
      input and return data frame as output}
   \item{fun.ymin}{ymin summary function (should take numeric vector and
     return single number)}
@@ -35,62 +89,49 @@ a data.frame with additional columns:
   \item{fun.ymax}{ymax summary function (should take numeric vector and
     return single number)}
 }
-\description{
-\code{stat_summary} allows for tremendous flexibilty in the specification
-of summary functions. The summary function can either supply individual
-summary functions for each of y, ymin and ymax (with \code{fun.y},
-\code{fun.ymax}, \code{fun.ymin}), or return a data frame containing any
-number of aesthetiics with with \code{fun.data}. All summary functions
-are called with a single vector of values, \code{x}.
-}
-\details{
+
 A simple vector function is easiest to work with as you can return a single
-number, but is somewhat less flexible.  If your summary function operates
-on a data.frame it should return a data frame with variables that the geom
-can use.
-}
-\section{Aesthetics}{
+number, but is somewhat less flexible. If your summary function computes
+multiple values at once (e.g. ymin and ymax), use \code{fun.data}.
 
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "summary")}
+If no aggregation functions are suppled, will default to
+\code{\link{mean_se}}.
 }
 \examples{
-\donttest{
-# Basic operation on a small dataset
-d <- qplot(cyl, mpg, data=mtcars)
-d + stat_summary(fun.data = "mean_cl_boot", colour = "red")
-
-p <- qplot(cyl, mpg, data = mtcars, stat="summary", fun.y = "mean")
-p
-# Don't use ylim to zoom into a summary plot - this throws the
-# data away
-p + ylim(15, 30)
-# Instead use coord_cartesian
-p + coord_cartesian(ylim = c(15, 30))
+d <- ggplot(mtcars, aes(cyl, mpg)) + geom_point()
+d + stat_summary(fun.data = "mean_cl_boot", colour = "red", size = 2)
 
 # You can supply individual functions to summarise the value at
 # each x:
-
-stat_sum_single <- function(fun, geom="point", ...) {
-  stat_summary(fun.y=fun, colour="red", geom=geom, size = 3, ...)
-}
-
-d + stat_sum_single(mean)
-d + stat_sum_single(mean, geom="line")
-d + stat_sum_single(median)
-d + stat_sum_single(sd)
+d + stat_summary(fun.y = "median", colour = "red", size = 2)
+d + stat_summary(fun.y = "mean", colour = "red", size = 2)
+d + aes(colour = factor(vs)) + stat_summary(fun.y = mean, geom="line")
 
 d + stat_summary(fun.y = mean, fun.ymin = min, fun.ymax = max,
   colour = "red")
 
-d + aes(colour = factor(vs)) + stat_summary(fun.y = mean, geom="line")
+#' d <- ggplot(diamonds, aes(carat, price))
+d + geom_smooth()
+d + geom_line(stat = "summary_bin", binwidth = 0.1, fun.y = "mean")
 
-# Alternatively, you can supply a function that operates on a data.frame.
+d <- ggplot(diamonds, aes(cut))
+d + geom_bar()
+d + stat_summary_bin(aes(y = price), fun.y = "mean", geom = "bar")
+\donttest{
 # A set of useful summary functions is provided from the Hmisc package:
-
 stat_sum_df <- function(fun, geom="crossbar", ...) {
   stat_summary(fun.data=fun, colour="red", geom=geom, width=0.2, ...)
 }
 
+# Don't use ylim to zoom into a summary plot - this throws the
+# data away
+p <- ggplot(mtcars, aes(cyl, mpg)) +
+  stat_summary(fun.y = "mean", geom = "point")
+p
+p + ylim(15, 30)
+# Instead use coord_cartesian
+p + coord_cartesian(ylim = c(15, 30))
+
 # The crossbar geom needs grouping to be specified when used with
 # a continuous x axis.
 d + stat_sum_df("mean_cl_boot", mapping = aes(group = cyl))
@@ -114,6 +155,7 @@ m <- ggplot(mpg2, aes(x=cyl, y=hwy)) +
        xlab("cyl")
 m
 # An example with highly skewed distributions:
+if (require("ggplot2movies")) {
 set.seed(596)
 mov <- movies[sample(nrow(movies), 1000), ]
  m2 <- ggplot(mov, aes(x= factor(round(rating)), y=votes)) + geom_point()
@@ -135,6 +177,7 @@ m2 + scale_y_log10()
 m2 + coord_trans(y="log10")
 }
 }
+}
 \seealso{
 \code{\link{geom_errorbar}}, \code{\link{geom_pointrange}},
  \code{\link{geom_linerange}}, \code{\link{geom_crossbar}} for geoms to
diff --git a/man/stat_summary2d.Rd b/man/stat_summary2d.Rd
deleted file mode 100644
index 82b9b0a..0000000
--- a/man/stat_summary2d.Rd
+++ /dev/null
@@ -1,62 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-summary-2d.r
-\name{stat_summary2d}
-\alias{stat_summary2d}
-\title{Apply funciton for 2D rectangular bins.}
-\usage{
-stat_summary2d(mapping = NULL, data = NULL, geom = NULL,
-  position = "identity", bins = 30, drop = TRUE, fun = mean, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{bins}{see \code{\link{stat_bin2d}}}
-
-\item{drop}{drop if the output of \code{fun} is \code{NA}.}
-
-\item{fun}{function for summary.}
-
-\item{...}{parameters passed to \code{fun}}
-}
-\description{
-Apply function for 2D rectangular bins.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "summary2d")}
-
-\code{stat_summary2d} is 2D version of \code{\link{stat_summary}}. The data are devided by \code{x} and \code{y}.
-\code{z} in each cell is passed to arbitral summary function.
-
-\code{stat_summary2d} requires the following aesthetics:
-
-\itemize{
- \item \code{x}: horizontal position
- \item \code{y}: vertical position
- \item \code{z}: value passed to the summary function
-}
-}
-\examples{
-\donttest{
-d <- ggplot(diamonds, aes(carat, depth, z = price))
-d + stat_summary2d()
-
-# Specifying function
-d + stat_summary2d(fun = function(x) sum(x^2))
-d + stat_summary2d(fun = var)
-}
-}
-\seealso{
-\code{\link{stat_summary_hex}} for hexagonal summarization. \code{\link{stat_bin2d}} for the binning options.
-}
-
diff --git a/man/stat_summary_2d.Rd b/man/stat_summary_2d.Rd
new file mode 100644
index 0000000..c7c0877
--- /dev/null
+++ b/man/stat_summary_2d.Rd
@@ -0,0 +1,92 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/stat-summary-2d.r, R/stat-summary-hex.r
+\name{stat_summary_2d}
+\alias{stat_summary2d}
+\alias{stat_summary_2d}
+\alias{stat_summary_hex}
+\title{Bin and summarise in 2d (rectangle & hexagons)}
+\usage{
+stat_summary_2d(mapping = NULL, data = NULL, geom = "tile",
+  position = "identity", bins = 30, binwidth = NULL, drop = TRUE,
+  fun = "mean", fun.args = list(), na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+
+stat_summary_hex(mapping = NULL, data = NULL, geom = "hex",
+  position = "identity", bins = 30, binwidth = NULL, drop = TRUE,
+  fun = "mean", fun.args = list(), na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
+}
+\arguments{
+\item{mapping}{The aesthetic mapping, usually constructed with
+\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
+at the layer level if you are overriding the plot defaults.}
+
+\item{data}{A layer specific dataset - only needed if you want to override
+the plot defaults.}
+
+\item{geom}{The geometric object to use display the data}
+
+\item{position}{The position adjustment to use for overlapping points
+on this layer}
+
+\item{bins}{numeric vector giving number of bins in both vertical and
+horizontal directions. Set to 30 by default.}
+
+\item{binwidth}{Numeric vector giving bin width in both vertical and
+horizontal directions. Overrides \code{bins} if both set.}
+
+\item{drop}{drop if the output of \code{fun} is \code{NA}.}
+
+\item{fun}{function for summary.}
+
+\item{fun.args}{A list of extra arguments to pass to \code{fun}}
+
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
+\item{...}{other arguments passed on to \code{\link{layer}}. This can
+include aesthetics whose values you want to set, not map. See
+\code{\link{layer}} for more details.}
+}
+\description{
+\code{stat_summary_2d} is a 2d variation of \code{\link{stat_summary}}.
+\code{stat_summary_hex} is a hexagonal variation of
+\code{\link{stat_summary_2d}}. The data are divided into bins defined
+by \code{x} and \code{y}, and then the values of \code{z} in each cell is
+are summarised with \code{fun}.
+}
+\section{Aesthetics}{
+
+\itemize{
+ \item \code{x}: horizontal position
+ \item \code{y}: vertical position
+ \item \code{z}: value passed to the summary function
+}
+}
+\examples{
+d <- ggplot(diamonds, aes(carat, depth, z = price))
+d + stat_summary_2d()
+
+# Specifying function
+d + stat_summary_2d(fun = function(x) sum(x^2))
+d + stat_summary_2d(fun = var)
+d + stat_summary_2d(fun = "quantile", fun.args = list(probs = 0.1))
+
+if (requireNamespace("hexbin")) {
+d + stat_summary_hex()
+}
+}
+\seealso{
+\code{\link{stat_summary_hex}} for hexagonal summarization.
+  \code{\link{stat_bin2d}} for the binning options.
+}
+
diff --git a/man/stat_summary_hex.Rd b/man/stat_summary_hex.Rd
deleted file mode 100644
index 6089a3d..0000000
--- a/man/stat_summary_hex.Rd
+++ /dev/null
@@ -1,60 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-summary-hex.r
-\name{stat_summary_hex}
-\alias{stat_summary_hex}
-\title{Apply funciton for 2D hexagonal bins.}
-\usage{
-stat_summary_hex(mapping = NULL, data = NULL, geom = "hex",
-  position = "identity", bins = 30, drop = TRUE, fun = mean, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{bins}{see \code{\link{stat_binhex}}}
-
-\item{drop}{drop if the output of \code{fun} is \code{NA}.}
-
-\item{fun}{function for summary.}
-
-\item{...}{parameters passed to \code{fun}}
-}
-\description{
-Apply function for 2D hexagonal bins.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "summaryhex")}
-
-\code{stat_summary2d} is hexagonal version of \code{\link{stat_summary}}. The data are devided by \code{x} and \code{y}.
-\code{z} in each cell is passed to arbitral summary function.
-
-\code{stat_summary-hex} requires the following aesthetics:
-
-\itemize{
- \item \code{x}: horizontal position
- \item \code{y}: vertical position
- \item \code{z}: value passed to the summary function
-}
-}
-\examples{
-d <- ggplot(diamonds, aes(carat, depth, z = price))
-d + stat_summary_hex()
-
-# Specifying function
-d + stat_summary_hex(fun = function(x) sum(x^2))
-d + stat_summary_hex(fun = var, na.rm = TRUE)
-}
-\seealso{
-\code{\link{stat_summary2d}} for rectangular summarization. \code{\link{stat_bin2d}} for the hexagon-ing options.
-}
-
diff --git a/man/stat_unique.Rd b/man/stat_unique.Rd
index cb7fa55..223594c 100644
--- a/man/stat_unique.Rd
+++ b/man/stat_unique.Rd
@@ -1,11 +1,12 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/stat-unique.r
 \name{stat_unique}
 \alias{stat_unique}
 \title{Remove duplicates.}
 \usage{
 stat_unique(mapping = NULL, data = NULL, geom = "point",
-  position = "identity", ...)
+  position = "identity", na.rm = FALSE, show.legend = NA,
+  inherit.aes = TRUE, ...)
 }
 \arguments{
 \item{mapping}{The aesthetic mapping, usually constructed with
@@ -17,9 +18,21 @@ the plot defaults.}
 
 \item{geom}{The geometric object to use display the data}
 
-\item{position}{The position adjustment to use for overlappling points
+\item{position}{The position adjustment to use for overlapping points
 on this layer}
 
+\item{na.rm}{If \code{FALSE} (the default), removes missing values with
+a warning.  If \code{TRUE} silently removes missing values.}
+
+\item{show.legend}{logical. Should this layer be included in the legends?
+\code{NA}, the default, includes if any aesthetics are mapped.
+\code{FALSE} never includes, and \code{TRUE} always includes.}
+
+\item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
+rather than combining with them. This is most useful for helper functions
+that define both data and aesthetics and shouldn't inherit behaviour from
+the default plot specification, e.g. \code{\link{borders}}.}
+
 \item{...}{other arguments passed on to \code{\link{layer}}. This can
 include aesthetics whose values you want to set, not map. See
 \code{\link{layer}} for more details.}
diff --git a/man/stat_vline.Rd b/man/stat_vline.Rd
deleted file mode 100644
index abf6835..0000000
--- a/man/stat_vline.Rd
+++ /dev/null
@@ -1,37 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-vline.r
-\name{stat_vline}
-\alias{stat_vline}
-\title{Add a vertical line}
-\usage{
-stat_vline(mapping = NULL, data = NULL, geom = "vline",
-  position = "identity", xintercept, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\description{
-Add a vertical line
-}
-\examples{
-# see geom_vline
-}
-\seealso{
-\code{\link{geom_vline}} for code examples.
-}
-\keyword{internal}
-
diff --git a/man/stat_ydensity.Rd b/man/stat_ydensity.Rd
deleted file mode 100644
index 72aaa78..0000000
--- a/man/stat_ydensity.Rd
+++ /dev/null
@@ -1,68 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stat-ydensity.r
-\name{stat_ydensity}
-\alias{stat_ydensity}
-\title{1d kernel density estimate along y axis, for violin plot.}
-\usage{
-stat_ydensity(mapping = NULL, data = NULL, geom = "violin",
-  position = "dodge", adjust = 1, kernel = "gaussian", trim = TRUE,
-  scale = "area", na.rm = FALSE, ...)
-}
-\arguments{
-\item{mapping}{The aesthetic mapping, usually constructed with
-\code{\link{aes}} or \code{\link{aes_string}}. Only needs to be set
-at the layer level if you are overriding the plot defaults.}
-
-\item{data}{A layer specific dataset - only needed if you want to override
-the plot defaults.}
-
-\item{geom}{The geometric object to use display the data}
-
-\item{position}{The position adjustment to use for overlappling points
-on this layer}
-
-\item{adjust}{see \code{\link{density}} for details}
-
-\item{kernel}{kernel used for density estimation, see
-\code{\link{density}} for details}
-
-\item{trim}{If \code{TRUE} (default), trim the tails of the violins
-to the range of the data. If \code{FALSE}, don't trim the tails.}
-
-\item{scale}{if "area" (default), all violins have the same area (before trimming
-the tails). If "count", areas are scaled proportionally to the number of
-observations. If "width", all violins have the same maximum width.}
-
-\item{na.rm}{If \code{FALSE} (the default), removes missing values with
-   a warning. If \code{TRUE} silently removes missing values.}
-
-\item{...}{other arguments passed on to \code{\link{layer}}. This can
-include aesthetics whose values you want to set, not map. See
-\code{\link{layer}} for more details.}
-}
-\value{
-A data frame with additional columns:
-  \item{density}{density estimate}
-  \item{scaled}{density estimate, scaled to maximum of 1}
-  \item{count}{density * number of points - probably useless for violin plots}
-  \item{violinwidth}{density scaled for the violin plot, according to area, counts
-                     or to a constant maximum width}
-  \item{n}{number of points}
-  \item{width}{width of violin bounding box}
-}
-\description{
-1d kernel density estimate along y axis, for violin plot.
-}
-\section{Aesthetics}{
-
-\Sexpr[results=rd,stage=build]{ggplot2:::rd_aesthetics("stat", "ydensity")}
-}
-\examples{
-# See geom_violin for examples
-# Also see stat_density for similar examples with data along x axis
-}
-\seealso{
-\code{\link{geom_violin}} for examples, and \code{\link{stat_density}}
-  for examples with data along the x axis.
-}
-
diff --git a/man/summary.ggplot.Rd b/man/summary.ggplot.Rd
index 70447af..0e841d4 100644
--- a/man/summary.ggplot.Rd
+++ b/man/summary.ggplot.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/summary.r
 \name{summary.ggplot}
 \alias{summary.ggplot}
@@ -15,7 +15,9 @@
 Displays a useful description of a ggplot object
 }
 \examples{
-summary(qplot(mpg, wt, data=mtcars))
+p <- ggplot(mtcars, aes(mpg, wt)) +
+  geom_point()
+summary(p)
 }
 \keyword{internal}
 
diff --git a/man/theme.Rd b/man/theme.Rd
index 9b3abbd..bf024c5 100644
--- a/man/theme.Rd
+++ b/man/theme.Rd
@@ -1,18 +1,20 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/theme.r
 \name{theme}
 \alias{theme}
 \title{Set theme elements}
 \usage{
-theme(..., complete = FALSE)
+theme(..., complete = FALSE, validate = TRUE)
 }
 \arguments{
 \item{...}{a list of element name, element pairings that modify the
 existing theme.}
 
 \item{complete}{set this to TRUE if this is a complete theme, such as
-  the one returned \code{by theme_grey()}. Complete themes behave
-  differently when added to a ggplot object.}
+the one returned \code{by theme_grey()}. Complete themes behave
+differently when added to a ggplot object.}
+
+\item{validate}{TRUE to run validate_element, FALSE to bypass checks.}
 }
 \description{
 Use this function to modify theme settings.
@@ -37,12 +39,13 @@ The individual theme elements are:
 \tabular{ll}{
   line             \tab all line elements
                    (\code{element_line}) \cr
-  rect             \tab all rectangluar elements
+  rect             \tab all rectangular elements
                    (\code{element_rect}) \cr
   text             \tab all text elements
                    (\code{element_text}) \cr
   title            \tab all title elements: plot, axes, legends
                    (\code{element_text}; inherits from \code{text}) \cr
+  aspect.ratio     \tab aspect ratio of the panel \cr
 
   axis.title       \tab label of axes
                    (\code{element_text}; inherits from \code{text}) \cr
@@ -64,8 +67,6 @@ The individual theme elements are:
                    (\code{element_line}; inherits from \code{axis.ticks}) \cr
   axis.ticks.length  \tab length of tick marks
                    (\code{unit}) \cr
-  axis.ticks.margin  \tab space between tick mark and tick label
-                   (\code{unit}) \cr
   axis.line        \tab lines along axes
                    (\code{element_line}; inherits from \code{line}) \cr
   axis.line.x      \tab line along x axis
@@ -132,6 +133,9 @@ The individual theme elements are:
                    (\code{element_line}; inherits from \code{panel.grid.minor}) \cr
   panel.grid.minor.y \tab horizontal minor grid lines
                    (\code{element_line}; inherits from \code{panel.grid.minor}) \cr
+  panel.ontop        \tab option to place the panel (background, gridlines)
+                          over the data layers.  Usually used with a transparent
+                          or blank \code{panel.background}. (\code{logical}) \cr
 
   plot.background  \tab background of the entire plot
                    (\code{element_rect}; inherits from \code{rect}) \cr
@@ -149,17 +153,23 @@ The individual theme elements are:
                    (\code{element_text}; inherits from \code{strip.text}) \cr
   strip.text.y     \tab facet labels along vertical direction
                    (\code{element_text}; inherits from \code{strip.text}) \cr
+  strip.switch.pad.grid \tab space between strips and axes when strips are switched
+                   (\code{unit}) \cr
+  strip.switch.pad.wrap \tab space between strips and axes when strips are switched
+                   (\code{unit}) \cr
 }
 }
 \examples{
 \donttest{
-p <- qplot(mpg, wt, data = mtcars)
+p <- ggplot(mtcars, aes(mpg, wt)) +
+  geom_point()
 p
 p + theme(panel.background = element_rect(colour = "pink"))
 p + theme_bw()
 
 # Scatter plot of gas mileage by vehicle weight
-p <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point()
+p <- ggplot(mtcars, aes(wt, mpg)) +
+  geom_point()
 # Calculate slope and intercept of line of best fit
 coef(lm(mpg ~ wt, data = mtcars))
 p + geom_abline(intercept = 37, slope = -5)
@@ -172,7 +182,7 @@ geom_text(data = data.frame(), aes(4.5, 30, label = "Pearson-R = -.87"))
 # Change the axis labels
 # Original plot
 p
-p + xlab("Vehicle Weight") + ylab("Miles per Gallon")
+p + labs(x = "Vehicle Weight", y = "Miles per Gallon")
 # Or
 p + labs(x = "Vehicle Weight", y = "Miles per Gallon")
 
@@ -184,14 +194,14 @@ p + theme(plot.title = element_text(size = rel(2), colour = "blue"))
 
 # Changing plot look with themes
 DF <- data.frame(x = rnorm(400))
-m <- ggplot(DF, aes(x = x)) + geom_histogram()
+m <- ggplot(DF, aes(x = x)) +
+  geom_histogram()
 # Default is theme_grey()
 m
 # Compare with
 m + theme_bw()
 
 # Manipulate Axis Attributes
-library(grid) # for unit
 m + theme(axis.line = element_line(size = 3, colour = "red", linetype = "dotted"))
 m + theme(axis.text = element_text(colour = "blue"))
 m + theme(axis.text.y = element_blank())
@@ -201,16 +211,20 @@ m + theme(axis.title.x = element_blank())
 m + theme(axis.ticks.length = unit(.85, "cm"))
 
 # Legend Attributes
-z <- ggplot(mtcars, aes(wt, mpg, colour = factor(cyl))) + geom_point()
+z <- ggplot(mtcars, aes(wt, mpg)) +
+  geom_point(aes(colour = factor(cyl)))
 z
 z + theme(legend.position = "none")
 z + theme(legend.position = "bottom")
 # Or use relative coordinates between 0 and 1
 z + theme(legend.position = c(.5, .5))
+# Add a border to the whole legend
 z + theme(legend.background = element_rect(colour = "black"))
 # Legend margin controls extra space around outside of legend:
-z + theme(legend.background = element_rect(), legend.margin = unit(1, "cm"))
-z + theme(legend.background = element_rect(), legend.margin = unit(0, "cm"))
+z + theme(legend.background = element_rect(),
+          legend.margin = unit(1, "cm"))
+z + theme(legend.background = element_rect(),
+          legend.margin = unit(0, "cm"))
 # Or to just the keys
 z + theme(legend.key = element_rect(colour = "black"))
 z + theme(legend.key = element_rect(fill = "yellow"))
@@ -229,15 +243,17 @@ z + theme(panel.border = element_rect(linetype = "dashed", colour = "black"))
 z + theme(panel.grid.major = element_line(colour = "blue"))
 z + theme(panel.grid.minor = element_line(colour = "red", linetype = "dotted"))
 z + theme(panel.grid.major = element_line(size = 2))
-z + theme(panel.grid.major.y = element_blank(), panel.grid.minor.y = element_blank())
+z + theme(panel.grid.major.y = element_blank(),
+          panel.grid.minor.y = element_blank())
 z + theme(plot.background = element_rect())
 z + theme(plot.background = element_rect(fill = "green"))
 
 # Faceting Attributes
 set.seed(4940)
 dsmall <- diamonds[sample(nrow(diamonds), 1000), ]
-k <- ggplot(dsmall, aes(carat, ..density..)) + geom_histogram(binwidth = 0.2) +
-facet_grid(. ~ cut)
+k <- ggplot(dsmall, aes(carat, ..density..)) +
+  geom_histogram(binwidth = 0.2) +
+  facet_grid(. ~ cut)
 k + theme(strip.background = element_rect(colour = "purple", fill = "pink",
                                           size = 3, linetype = "dashed"))
 k + theme(strip.text.x = element_text(colour = "red", angle = 45, size = 10,
@@ -245,6 +261,17 @@ k + theme(strip.text.x = element_text(colour = "red", angle = 45, size = 10,
 k + theme(panel.margin = unit(5, "lines"))
 k + theme(panel.margin.y = unit(0, "lines"))
 
+# Put gridlines on top
+meanprice <- tapply(diamonds$price, diamonds$cut, mean)
+cut <- factor(levels(diamonds$cut), levels = levels(diamonds$cut))
+df <- data.frame(meanprice, cut)
+g <- ggplot(df, aes(cut, meanprice)) + geom_bar(stat = "identity")
+g + geom_bar(stat = "identity") +
+    theme(panel.background = element_blank(),
+          panel.grid.major.x = element_blank(),
+          panel.grid.minor.x = element_blank(),
+          panel.grid.minor.y = element_blank(),
+          panel.ontop = TRUE)
 
 # Modify a theme and save it
 mytheme <- theme_grey() + theme(plot.title = element_text(colour = "red"))
@@ -265,7 +292,7 @@ build_element_graph <- function(tree) {
       data.frame(child = name, parent = item$inherit)
   }
 
-  edges <- rbind.fill(mapply(inheritdf, names(tree), tree))
+  edges <- plyr::rbind.fill(mapply(inheritdf, names(tree), tree))
 
   # Explicitly add vertices (since not all are in edge list)
   vertices <- data.frame(name = names(tree))
diff --git a/man/theme_blank.Rd b/man/theme_blank.Rd
deleted file mode 100644
index f9b0b9e..0000000
--- a/man/theme_blank.Rd
+++ /dev/null
@@ -1,29 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/theme-elements.r
-\name{theme_blank}
-\alias{theme_blank}
-\alias{theme_line}
-\alias{theme_rect}
-\alias{theme_segment}
-\alias{theme_text}
-\title{Deprecated theme_xx functions}
-\usage{
-theme_blank(...)
-
-theme_rect(...)
-
-theme_line(...)
-
-theme_segment(...)
-
-theme_text(...)
-}
-\arguments{
-\item{...}{Arguments to be passed to the appropriate \code{element_xx}
-  function.}
-}
-\description{
-The \code{theme_xx} functions have been deprecated. They are replaced
-with the \code{element_xx} functions.
-}
-
diff --git a/man/theme_update.Rd b/man/theme_update.Rd
index e99821a..6cabafe 100644
--- a/man/theme_update.Rd
+++ b/man/theme_update.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/theme.r
 \name{theme_update}
 \alias{theme_get}
@@ -22,19 +22,23 @@ Use \code{theme_update} to modify a small number of elements of the current
 theme or use \code{theme_set} to completely override it.
 }
 \examples{
-qplot(mpg, wt, data = mtcars)
+p <- ggplot(mtcars, aes(mpg, wt)) +
+  geom_point()
+p
 old <- theme_set(theme_bw())
-qplot(mpg, wt, data = mtcars)
+p
 theme_set(old)
-qplot(mpg, wt, data = mtcars)
+p
 
 old <- theme_update(panel.background = element_rect(colour = "pink"))
-qplot(mpg, wt, data = mtcars)
+p
 theme_set(old)
 theme_get()
 
-qplot(mpg, wt, data=mtcars, colour=mpg) +
-  theme(legend.position=c(0.95, 0.95), legend.justification = c(1, 1))
+ggplot(mtcars, aes(mpg, wt)) +
+  geom_point(aes(color = mpg)) +
+  theme(legend.position = c(0.95, 0.95),
+        legend.justification = c(1, 1))
 last_plot() +
  theme(legend.background = element_rect(fill = "white", colour = "white", size = 3))
 }
diff --git a/man/transform_position.Rd b/man/transform_position.Rd
new file mode 100644
index 0000000..b549ad5
--- /dev/null
+++ b/man/transform_position.Rd
@@ -0,0 +1,19 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/position-.r
+\name{transform_position}
+\alias{transform_position}
+\title{Convenience function to transform all position variables.}
+\usage{
+transform_position(df, trans_x = NULL, trans_y = NULL, ...)
+}
+\arguments{
+\item{trans_x, trans_y}{Transformation functions for x and y aesthetics.
+(will transform x, xmin, xmax, xend etc)}
+
+\item{...}{Additional arguments passed to \code{trans_x} and \code{trans_y}.}
+}
+\description{
+Convenience function to transform all position variables.
+}
+\keyword{internal}
+
diff --git a/man/translate_qplot_base.Rd b/man/translate_qplot_base.Rd
index 085f8a1..7a3328d 100644
--- a/man/translate_qplot_base.Rd
+++ b/man/translate_qplot_base.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/translate-qplot-base.r
 \name{translate_qplot_base}
 \alias{translate_qplot_base}
diff --git a/man/translate_qplot_ggplot.Rd b/man/translate_qplot_ggplot.Rd
index 83a6d3f..7c705af 100644
--- a/man/translate_qplot_ggplot.Rd
+++ b/man/translate_qplot_ggplot.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/translate-qplot-ggplot.r
 \name{translate_qplot_ggplot}
 \alias{translate_qplot_ggplot}
@@ -12,6 +12,7 @@ describes what those defaults are, and how they map to the fuller ggplot()
 syntax.
 }
 \examples{
+
 # By default, qplot() assumes that you want a scatterplot,
 # i.e., you want to use geom_point()
 # qplot(x, y, data = data)
diff --git a/man/translate_qplot_gpl.Rd b/man/translate_qplot_gpl.Rd
deleted file mode 100644
index 105ed43..0000000
--- a/man/translate_qplot_gpl.Rd
+++ /dev/null
@@ -1,59 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/translate-qplot-gpl.r
-\name{translate_qplot_gpl}
-\alias{translate_qplot_gpl}
-\title{Translating between qplot and Graphics Production Library (GPL)}
-\description{
-The Grammar of Graphics uses two specifications. A concise format is used to
-caption figures, and a more detailed xml format stored on disk.
-}
-\examples{
-# The following example of the concise format is adapted from Figure 1.5,
-# page 13, of Leland Wilkinson's "The Grammar of Graphics."
-# Springer, 2nd edition, 2005.
-
-# DATA: source("demographics")
-# DATA: longitude, latitude = map(source("World"))
-# TRANS: bd = max(birth - death, 0)
-# COORD: project.mercator()
-# ELEMENT: point(position(lon * lat), size(bd), color(color.red))
-# ELEMENT: polygon(position(longitude * latitude))
-
-# This is relatively simple to adapt to the syntax of ggplot2:
-
-# ggplot() is used to specify the default data and default aesthetic mappings.
-# Data is provided as standard R data.frames existing in the global environment;
-# it does not need to be explicitly loaded. We also use a slightly
-# different world dataset, with columns lat and long. This lets us use the
-# same aesthetic mappings for both datasets. Layers can override the default
-# data and aesthetic mappings provided by the plot.
-
-# We replace TRANS with an explicit transformation by R code.
-
-# ELEMENTs are replaced with layers, which explicitly specify the data
-# source. Each geom has a default statistic which is used to transform the
-# data prior to plotting. For the geoms in this example, the default statistic
-# is the identity function. Fixed aesthetics (the colour red in this example)
-# are supplied as additional arguments to the layer, rather than as special
-# constants.
-
-# The SCALE component has been omitted from this example (so that the
-# defaults are used). In both the ggplot2 and GoG examples, scales are
-# defined by default. In ggplot you can override the defaults by adding a
-# scale object, e.g., scale colour or scale size.
-
-# COORD uses a slightly different format. In general, most of the components
-# specifications in ggplot are slightly different to those in GoG, in order to
-# be more familiar to R users.
-
-# Each component is added together with + to create the final plot.
-
-# Resulting ggplot2 code:
-# demographics <- transform(demographics, bd = pmax(birth - death, 0))
-# p <- ggplot(demographic, aes(lon, lat))
-# p <- p + geom_polyogon(data = world)
-# p <- p + geom_point(aes(size = bd), colour = "red")
-# p <- p + coord_map(projection = "mercator")
-# print(p)
-}
-
diff --git a/man/translate_qplot_lattice.Rd b/man/translate_qplot_lattice.Rd
index b93b8e7..dff1ba0 100644
--- a/man/translate_qplot_lattice.Rd
+++ b/man/translate_qplot_lattice.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/translate-qplot-lattice.r
 \name{translate_qplot_lattice}
 \alias{translate_qplot_lattice}
@@ -12,6 +12,7 @@ to more complicated situations.
 \dontrun{
 library(lattice)
 
+if (require("ggplot2movies")) {
 xyplot(rating ~ year, data=movies)
 qplot(year, rating, data=movies)
 
@@ -38,6 +39,7 @@ qplot(mpg, wt, data = mtcars, geom = c("point","smooth"))
 
 xyplot(wt ~ mpg, mtcars, type = c("p","r"))
 qplot(mpg, wt, data = mtcars, geom = c("point","smooth"), method = "lm")
+}
 
 # The capabilities for scale manipulations are similar in both ggplot2 and
 # lattice, although the syntax is a little different.
@@ -49,9 +51,9 @@ xyplot(wt ~ mpg | cyl, mtcars, scales = list(log = 10))
 qplot(mpg, wt, data = mtcars, log = "xy")
 
 xyplot(wt ~ mpg | cyl, mtcars, scales = list(log = 2))
-library(scales)  # Load scales for log2_trans
-qplot(mpg, wt, data = mtcars) + scale_x_continuous(trans = log2_trans()) +
-  scale_y_continuous(trans = log2_trans())
+qplot(mpg, wt, data = mtcars) +
+  scale_x_continuous(trans = scales::log2_trans()) +
+  scale_y_continuous(trans = scales::log2_trans())
 
 xyplot(wt ~ mpg, mtcars, group = cyl, auto.key = TRUE)
 # Map directly to an aesthetic like colour, size, or shape.
diff --git a/man/txhousing.Rd b/man/txhousing.Rd
new file mode 100644
index 0000000..54de48b
--- /dev/null
+++ b/man/txhousing.Rd
@@ -0,0 +1,26 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/data.R
+\docType{data}
+\name{txhousing}
+\alias{txhousing}
+\title{Housing sales in TX.}
+\format{A data frame with 8602 observations and 9 variables:
+\itemize{
+\item{city}{Name of MLS area}
+\item{year,month,date}{Date}
+\item{sales}{Number of sales}
+\item{volume}{Total value of sales}
+\item{median}{Median sale price}
+\item{listings}{Total active listings}
+\item{inventory}{"Months inventory": amount of time it would take to sell
+  all current listings at current pace of sales.}
+}}
+\usage{
+txhousing
+}
+\description{
+Information about the housing market in Texas provided by the TAMU
+real estate center, \url{http://recenter.tamu.edu/}.
+}
+\keyword{datasets}
+
diff --git a/man/update_defaults.Rd b/man/update_defaults.Rd
index 8227a95..f97f003 100644
--- a/man/update_defaults.Rd
+++ b/man/update_defaults.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/geom-defaults.r
 \name{update_geom_defaults}
 \alias{update_geom_defaults}
@@ -10,16 +10,18 @@ update_geom_defaults(geom, new)
 update_stat_defaults(stat, new)
 }
 \arguments{
-\item{new}{named list of aesthetics}
+\item{new}{Named list of aesthetics.}
 
-\item{stat,geom}{name of geom/stat to modify}
+\item{stat, geom}{Name of geom/stat to modify (like \code{"point"} or
+\code{"bin"}), or a Geom/Stat object (like \code{GeomPoint} or
+\code{StatBin}).}
 }
 \description{
 Modify geom/stat aesthetic defaults for future plots
 }
 \examples{
 update_geom_defaults("point", list(colour = "darkblue"))
-qplot(mpg, wt, data = mtcars)
+ggplot(mtcars, aes(mpg, wt)) + geom_point()
 update_geom_defaults("point", list(colour = "black"))
 }
 
diff --git a/man/update_element.Rd b/man/update_element.Rd
deleted file mode 100644
index 22fbd3d..0000000
--- a/man/update_element.Rd
+++ /dev/null
@@ -1,46 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/theme.r
-\name{update_element}
-\alias{update_element}
-\title{Update theme param}
-\usage{
-update_element(name, ...)
-}
-\arguments{
-\item{name}{name of a theme element}
-
-\item{...}{Pairs of name and value of theme parameters.}
-}
-\value{
-Updated theme element
-}
-\description{
-Update contents of a theme. (Deprecated)
-}
-\details{
-This function is deprecated. Use \code{\link{\%+replace\%}} or
-\code{\link{+.gg}} instead.
-}
-\examples{
-\dontrun{
-x <- element_text(size = 15)
-update_element(x, colour = "red")
-# Partial matching works
-update_element(x, col = "red")
-# So does positional
-update_element(x, "Times New Roman")
-# And it throws an error if you use an argument that doesn't exist
-update_element(x, noargument = 12)
-# Or multiple arguments with the same name
-update_element(x, size = 12, size = 15)
-
-# Will look up element if given name
-update_element("axis.text.x", colour = 20)
-# Throws error if incorrectly named
-update_element("axis.text", colour = 20)
-}
-}
-\seealso{
-\code{\link{\%+replace\%}} and \code{\link{+.gg}}
-}
-
diff --git a/man/update_labels.Rd b/man/update_labels.Rd
index 598083b..7c4363e 100644
--- a/man/update_labels.Rd
+++ b/man/update_labels.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/labels.r
 \name{update_labels}
 \alias{update_labels}
@@ -15,7 +15,7 @@ update_labels(p, labels)
 Update axis/legend labels
 }
 \examples{
-p <- qplot(mpg, wt, data = mtcars)
+p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
 update_labels(p, list(x = "New x"))
 update_labels(p, list(x = expression(x / y ^ 2)))
 update_labels(p, list(x = "New x", y = "New Y"))
diff --git a/man/waiver.Rd b/man/waiver.Rd
index 2208823..e17f00b 100644
--- a/man/waiver.Rd
+++ b/man/waiver.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/utilities.r
 \name{waiver}
 \alias{waiver}
diff --git a/man/zeroGrob.Rd b/man/zeroGrob.Rd
index b54a2ed..0de1127 100644
--- a/man/zeroGrob.Rd
+++ b/man/zeroGrob.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/grob-null.r
 \name{zeroGrob}
 \alias{zeroGrob}
diff --git a/tests/test-all.R b/tests/testthat.R
similarity index 60%
rename from tests/test-all.R
rename to tests/testthat.R
index 3050235..8954463 100644
--- a/tests/test-all.R
+++ b/tests/testthat.R
@@ -1,4 +1,4 @@
 library(testthat)
 library(ggplot2)
 
-test_package("ggplot2")
+test_check("ggplot2")
diff --git a/inst/tests/helper-plot-data.r b/tests/testthat/helper-plot-data.r
similarity index 50%
rename from inst/tests/helper-plot-data.r
rename to tests/testthat/helper-plot-data.r
index 1a242c6..69e8717 100644
--- a/inst/tests/helper-plot-data.r
+++ b/tests/testthat/helper-plot-data.r
@@ -1,14 +1,12 @@
-pdata <- function(x) ggplot_build(x)$data
-
 # Transform the data as the coordinate system does
 cdata <- function(plot) {
   pieces <- ggplot_build(plot)
 
   lapply(pieces$data, function(d) {
-    ddply(d, "PANEL", function(panel_data) {
+    plyr::ddply(d, "PANEL", function(panel_data) {
       scales <- panel_scales(pieces$panel, panel_data$PANEL[1])
-      details <- coord_train(plot$coord, scales)
-      coord_transform(plot$coord, panel_data, details)
+      details <- plot$coordinates$train(scales)
+      plot$coordinates$transform(panel_data, details)
     })
   })
 }
@@ -16,12 +14,12 @@ cdata <- function(plot) {
 pranges <- function(plot) {
   panels <- ggplot_build(plot)$panel
 
-  x_ranges <- lapply(panels$x_scales, scale_limits)
-  y_ranges <- lapply(panels$y_scales, scale_limits)
+  x_ranges <- lapply(panels$x_scales, function(scale) scale$get_limits())
+  y_ranges <- lapply(panels$y_scales, function(scale) scale$get_limits())
 
 
   npscales <- plot$scales$non_position_scales()
-  npranges <- lapply(npscales$scales$scales, scale_limits)
+  npranges <- lapply(npscales$scales$scales, function(scale) scale$get_limits())
 
 
   c(list(x = x_ranges, y = y_ranges), npranges)
diff --git a/tests/testthat/test-aes-grouping.r b/tests/testthat/test-aes-grouping.r
new file mode 100644
index 0000000..aec0500
--- /dev/null
+++ b/tests/testthat/test-aes-grouping.r
@@ -0,0 +1,44 @@
+context("Aesthetics (grouping)")
+
+df <- data.frame(
+  x = 1:4,
+  a = c("a", "a", "b", "b"),
+  b = c("a", "b", "a", "b")
+)
+
+group <- function(x) as.vector(layer_data(x, 1)$group)
+groups <- function(x) length(unique(group(x)))
+
+test_that("one group per combination of discrete vars", {
+  plot <- ggplot(df, aes(x, x)) + geom_point()
+  expect_equal(group(plot), rep(NO_GROUP, 4))
+
+  plot <- ggplot(df, aes(x, a)) + geom_point()
+  expect_equal(group(plot), c(1, 1, 2, 2))
+  plot <- ggplot(df, aes(x, b)) + geom_point()
+  expect_equal(group(plot), c(1, 2, 1, 2))
+
+  plot <- ggplot(df, aes(a, b)) + geom_point()
+  expect_equal(groups(plot), 4)
+})
+
+test_that("label is not used as a grouping var", {
+  plot <- ggplot(df, aes(x, x, label = a)) + geom_point()
+  expect_equal(group(plot), rep(NO_GROUP, 4))
+
+  plot <- ggplot(df, aes(x, x, colour = a, label = b)) + geom_point()
+  expect_equal(group(plot), c(1, 1, 2, 2))
+})
+
+test_that("group aesthetic overrides defaults", {
+  plot <- ggplot(df, aes(x, x, group = x)) + geom_point()
+  expect_equal(groups(plot), 4)
+
+  plot <- ggplot(df, aes(a, b, group = 1)) + geom_point()
+  expect_equal(groups(plot), 1)
+})
+
+test_that("group param overrides defaults", {
+  plot <- ggplot(df, aes(a, b)) + geom_point(group = 1)
+  expect_equal(groups(plot), 1)
+})
diff --git a/tests/testthat/test-aes-setting.r b/tests/testthat/test-aes-setting.r
new file mode 100644
index 0000000..575cccb
--- /dev/null
+++ b/tests/testthat/test-aes-setting.r
@@ -0,0 +1,17 @@
+context("Aes - setting values")
+
+test_that("Aesthetic parameters must match length of data", {
+  df <- data.frame(x = 1:5, y = 1:5)
+  p <- ggplot(df, aes(x, y))
+
+  set_colours <- function(colours) {
+    layer_data(p + geom_point(colour = colours))
+  }
+
+  set_colours("red")
+  expect_error(set_colours(rep("red", 2)), "must be either length 1")
+  expect_error(set_colours(rep("red", 3)), "must be either length 1")
+  expect_error(set_colours(rep("red", 4)), "must be either length 1")
+  set_colours(rep("red", 5))
+
+})
diff --git a/tests/testthat/test-aes.r b/tests/testthat/test-aes.r
new file mode 100644
index 0000000..10396a6
--- /dev/null
+++ b/tests/testthat/test-aes.r
@@ -0,0 +1,60 @@
+context("Creating aesthetic mappings")
+
+test_that("aes() captures input expressions", {
+  out <- aes(mpg, wt + 1)
+  expect_equal(out$x, quote(mpg))
+  expect_equal(out$y, quote(wt + 1))
+})
+
+test_that("aes_q() uses quoted calls and formulas", {
+  out <- aes_q(quote(mpg), ~ wt + 1)
+  expect_equal(out$x, quote(mpg))
+  expect_equal(out$y, quote(wt + 1))
+})
+
+test_that("aes_string() parses strings", {
+  expect_equal(aes_string("a + b")$x, quote(a + b))
+})
+
+test_that("aes_string() doesn't parse non-strings", {
+  old <- options(OutDec = ",")
+  on.exit(options(old))
+
+  expect_equal(aes_string(0.4)$x, 0.4)
+})
+
+test_that("aes_q() & aes_string() preserves explicit NULLs", {
+  expect_equal(aes_q(NULL), aes(NULL))
+  expect_equal(aes_q(x = NULL), aes(NULL))
+  expect_equal(aes_q(colour = NULL), aes(colour = NULL))
+
+  expect_equal(aes_string(NULL), aes(NULL))
+  expect_equal(aes_string(x = NULL), aes(NULL))
+  expect_equal(aes_string(colour = NULL), aes(colour = NULL))
+})
+
+test_that("aes_all() converts strings into mappings", {
+  expect_equal(
+    aes_all(c("x", "y", "col", "pch")),
+    aes(x, y, colour = col, shape = pch)
+  )
+})
+
+test_that("aes evaluated in environment where plot created", {
+  df <- data.frame(x = 1, y = 1)
+  p <- ggplot(df, aes(foo, y)) + geom_point()
+
+  # Accessing an undefined variable should result in error
+  expect_error(layer_data(p), "'foo' not found")
+
+  # Once it's defined we should get it back
+  foo <- 0
+  expect_equal(layer_data(p)$x, 0)
+
+  # And regular variable shadowing should work
+  f <- function() {
+    foo <- 10
+    ggplot(df, aes(foo, y)) + geom_point()
+  }
+  expect_equal(layer_data(f())$x, 10)
+})
diff --git a/tests/testthat/test-annotate.r b/tests/testthat/test-annotate.r
new file mode 100644
index 0000000..4308fdf
--- /dev/null
+++ b/tests/testthat/test-annotate.r
@@ -0,0 +1,28 @@
+context("annotate")
+
+test_that("dates in segment annotation work", {
+  dt <- structure(list(month = structure(c(1364774400, 1377993600),
+      class = c("POSIXct", "POSIXt"), tzone = "UTC"), total = c(-10.3,
+      11.7)), .Names = c("month", "total"), row.names = c(NA, -2L), class =
+      "data.frame")
+
+  p <- ggplot(dt, aes(month, total)) +
+    geom_point() +
+    annotate("segment",
+      x = as.POSIXct("2013-04-01"),
+      xend = as.POSIXct("2013-07-01"),
+      y = -10,
+      yend = 10
+    )
+
+  expect_true(all(c("xend", "yend") %in% names(layer_data(p, 2))))
+})
+
+test_that("segment annotations transform with scales", {
+  # This should be a visual test, but contriubtion documentation does not
+  # explain how to make one
+  ggplot(mtcars, aes(wt, mpg)) +
+    geom_point() +
+    annotate("segment", x = 2, y = 10, xend = 5, yend = 30, colour = "red") +
+    scale_y_reverse()
+})
diff --git a/tests/testthat/test-boxplot.r b/tests/testthat/test-boxplot.r
new file mode 100644
index 0000000..f220b71
--- /dev/null
+++ b/tests/testthat/test-boxplot.r
@@ -0,0 +1,40 @@
+context("Boxplot")
+
+# thanks wch for providing the test code
+test_that("geom_boxplot range includes all outliers", {
+  dat <- data.frame(x = 1, y = c(-(1:20) ^ 3, (1:20) ^ 3) )
+  p <- ggplot_build(ggplot(dat, aes(x,y)) + geom_boxplot())
+
+  miny <- p$panel$ranges[[1]]$y.range[1]
+  maxy <- p$panel$ranges[[1]]$y.range[2]
+
+  expect_true(miny <= min(dat$y))
+  expect_true(maxy >= max(dat$y))
+})
+
+test_that("geom_boxplot for continuous x gives warning if more than one x (#992)", {
+  dat <- expand.grid(x=1:2, y=c(-(1:20)^3, (1:20)^3) )
+  expect_that(ggplot_build(ggplot(dat, aes(x,y)) + geom_boxplot()),
+              gives_warning("Continuous x aesthetic"))
+
+  expect_that(ggplot_build(ggplot(dat, aes(x=as.Date(x,origin=Sys.Date()),y)) + geom_boxplot()),
+              gives_warning("Continuous x aesthetic"))
+
+  expect_that(ggplot_build(ggplot(dat, aes(x,y,group=x)) + geom_boxplot()),
+              not(gives_warning("Continuous x aesthetic")))
+
+  expect_that(ggplot_build(ggplot(dat, aes(x=1,y)) + geom_boxplot()),
+              not(gives_warning("Continuous x aesthetic")))
+
+  expect_that(ggplot_build(ggplot(dat, aes(x=factor(x),y)) + geom_boxplot()),
+              not(gives_warning("Continuous x aesthetic")))
+
+  expect_that(ggplot_build(ggplot(dat, aes(x=(x == 1),y)) + geom_boxplot()),
+              not(gives_warning("Continuous x aesthetic")))
+
+  expect_that(ggplot_build(ggplot(dat, aes(x=as.character(x),y)) + geom_boxplot()),
+              not(gives_warning("Continuous x aesthetic")))
+
+  expect_that(ggplot_build(ggplot(dat, aes(x,y)) + geom_boxplot() + facet_wrap(~y)),
+              gives_warning("Continuous x aesthetic"))
+})
diff --git a/tests/testthat/test-build.r b/tests/testthat/test-build.r
new file mode 100644
index 0000000..b6082cd
--- /dev/null
+++ b/tests/testthat/test-build.r
@@ -0,0 +1,51 @@
+# Test the complete path from plot specification to rendered data
+context("Plot building")
+
+df <- data.frame(x = 1:3, y = 3:1, z = letters[1:3])
+
+test_that("there is one data frame for each layer", {
+  nlayers <- function(x) length(ggplot_build(x)$data)
+
+  l1 <- ggplot(df, aes(x, y)) + geom_point()
+  l2 <- ggplot(df, aes(x, y)) + geom_point() + geom_line()
+  l3 <- ggplot(df, aes(x, y)) + geom_point() + geom_line() + geom_point()
+
+  expect_equal(nlayers(l1), 1)
+  expect_equal(nlayers(l2), 2)
+  expect_equal(nlayers(l3), 3)
+})
+
+test_that("position aesthetics coerced to correct type", {
+  l1 <- ggplot(df, aes(x, y)) + geom_point()
+  d1 <- layer_data(l1, 1)
+
+  expect_is(d1$x, "numeric")
+  expect_is(d1$y, "numeric")
+
+  l2 <- ggplot(df, aes(x, z)) + geom_point() + scale_x_discrete()
+  d2 <- layer_data(l2, 1)
+
+  expect_is(d2$x, "integer")
+  expect_is(d2$y, "integer")
+})
+
+test_that("non-position aesthetics are mapped", {
+  l1 <- ggplot(df, aes(x, y, fill = z, colour = z, shape = z, size = z)) +
+    geom_point()
+  d1 <- layer_data(l1, 1)
+
+  expect_equal(sort(names(d1)), sort(c("x", "y", "fill", "group",
+    "colour", "shape", "size", "PANEL", "alpha", "stroke")))
+
+  l2 <- l1 + scale_colour_manual(values = c("blue", "red", "yellow"))
+  d2 <- layer_data(l2, 1)
+  expect_equal(d2$colour, c("blue", "red", "yellow"))
+})
+
+test_that("strings are not converted to factors", {
+  df <- data.frame(x = 1:2, y = 2:1, label = c("alpha", "beta"), stringsAsFactors = FALSE)
+  p <- ggplot(df, aes(x, y)) +
+    geom_text(aes(label = label), parse = TRUE)
+
+  expect_is(layer_data(p)$label, "character")
+})
diff --git a/inst/tests/test-coord-polar.r b/tests/testthat/test-coord-polar.r
similarity index 87%
rename from inst/tests/test-coord-polar.r
rename to tests/testthat/test-coord-polar.r
index cdef6ea..7cb3d9b 100644
--- a/inst/tests/test-coord-polar.r
+++ b/tests/testthat/test-coord-polar.r
@@ -5,11 +5,12 @@ test_that("Polar distance calculation", {
     theta = c(0, 2*pi,   2,   6, 6, 1,    1,  0),
     r     = c(0,    0, 0.5, 0.5, 1, 1, 0.75, .5))
 
-  scales <- list(x = scale_x_continuous(limits=c(0, 2*pi)),
-                 y = scale_y_continuous(limits=c(0, 1)))
-  coord <- coord_train(coord_polar(), scales)
-
-  dists <- coord_distance(coord_polar(), dat$theta, dat$r, coord)
+  scales <- list(
+    x = scale_x_continuous(limits = c(0, 2*pi)),
+    y = scale_y_continuous(limits = c(0, 1))
+  )
+  coord <- coord_polar()
+  dists <- coord$distance(dat$theta, dat$r, coord$train(scales))
 
   # dists is normalized by dividing by this value, so we'll add it back
   # The maximum length of a spiral arc, from (t,r) = (0,0) to (2*pi,1)
diff --git a/inst/tests/test-coord-train.r b/tests/testthat/test-coord-train.r
similarity index 56%
rename from inst/tests/test-coord-train.r
rename to tests/testthat/test-coord-train.r
index f5f2842..81d0b14 100644
--- a/inst/tests/test-coord-train.r
+++ b/tests/testthat/test-coord-train.r
@@ -14,20 +14,22 @@ test_that("NA's don't appear in breaks", {
     return(FALSE)
   }
 
-  scales <- list(x = scale_x_continuous(limits=c(1, 12)),
-                 y = scale_y_continuous(limits=c(1, 12)))
+  scales <- list(
+    x = scale_x_continuous(limits = c(1, 12)),
+    y = scale_y_continuous(limits = c(1, 12))
+  )
 
   # First have to test that scale_breaks_positions will return a vector with NA
   # This is a test to make sure the later tests will be useful!
   # It's possible that changes to the the way that breaks are calculated will
   # make it so that scale_break_positions will no longer give NA for range 1, 12
-  expect_true(any(is.na(scale_break_positions(scales$x))))
-  expect_true(any(is.na(scale_break_positions(scales$y))))
+  expect_true(any(is.na((scales$x$break_positions()))))
+  expect_true(any(is.na((scales$y$break_positions()))))
 
   # Check the various types of coords to make sure they don't have NA breaks
-  expect_false(any_NA_major_minor(coord_train(coord_polar(), scales)))
-  expect_false(any_NA_major_minor(coord_train(coord_cartesian(), scales)))
-  expect_false(any_NA_major_minor(coord_train(coord_trans(), scales)))
-  expect_false(any_NA_major_minor(coord_train(coord_fixed(), scales)))
-  expect_false(any_NA_major_minor(coord_train(coord_map(), scales)))
+  expect_false(any_NA_major_minor(coord_polar()$train(scales)))
+  expect_false(any_NA_major_minor(coord_cartesian()$train(scales)))
+  expect_false(any_NA_major_minor(coord_trans()$train(scales)))
+  expect_false(any_NA_major_minor(coord_fixed()$train(scales)))
+  expect_false(any_NA_major_minor(coord_map()$train(scales)))
 })
diff --git a/inst/tests/test-data.r b/tests/testthat/test-data.r
similarity index 53%
rename from inst/tests/test-data.r
rename to tests/testthat/test-data.r
index 8226be2..d295088 100644
--- a/inst/tests/test-data.r
+++ b/tests/testthat/test-data.r
@@ -3,10 +3,10 @@ context("Data")
 test_that("stringsAsFactors doesn't affect results", {
 
     sAF <- getOption("stringsAsFactors")
-    dat.character <- data.frame(x=letters[5:1], y=1:5, stringsAsFactors=FALSE)
-    dat.factor <- data.frame(x=letters[5:1], y=1:5, stringsAsFactors=TRUE)
+    dat.character <- data.frame(x = letters[5:1], y = 1:5, stringsAsFactors = FALSE)
+    dat.factor <- data.frame(x = letters[5:1], y = 1:5, stringsAsFactors = TRUE)
 
-    base <- ggplot(, aes(x, y)) + geom_point()
+    base <- ggplot(mapping = aes(x, y)) + geom_point()
     xlabels <- function(x) x$panel$ranges[[1]]$x.labels
 
     options(stringsAsFactors = TRUE)
@@ -19,8 +19,8 @@ test_that("stringsAsFactors doesn't affect results", {
 
     options(stringsAsFactors = sAF)
 
-    expect_that(xlabels(char_true), equals(letters[1:5]))
-    expect_that(xlabels(char_false), equals(letters[1:5]))
-    expect_that(xlabels(factor_true), equals(letters[1:5]))
-    expect_that(xlabels(factor_false), equals(letters[1:5]))
+    expect_equal(xlabels(char_true), letters[1:5])
+    expect_equal(xlabels(char_false), letters[1:5])
+    expect_equal(xlabels(factor_true), letters[1:5])
+    expect_equal(xlabels(factor_false), letters[1:5])
 })
diff --git a/inst/tests/test-dotplot.r b/tests/testthat/test-dotplot.r
similarity index 69%
rename from inst/tests/test-dotplot.r
rename to tests/testthat/test-dotplot.r
index 89c3bfd..d92456b 100644
--- a/inst/tests/test-dotplot.r
+++ b/tests/testthat/test-dotplot.r
@@ -4,13 +4,14 @@ set.seed(111)
 dat <- data.frame(x = LETTERS[1:2], y = rnorm(30), g = LETTERS[3:5])
 
 test_that("Dodging works", {
-
   p <- ggplot(dat, aes(x = x, y = y, fill = g)) +
-       geom_dotplot(binwidth=.2, binaxis="y", position="dodge", stackdir="center")
-
-  bp <- ggplot_build(p)
-
-  df <- bp$data[[1]]
+    geom_dotplot(
+      binwidth = 0.2,
+      binaxis = "y",
+      position = "dodge",
+      stackdir = "center"
+    )
+  df <- layer_data(p)
 
   # Number of levels in the dodged variable
   ndodge <- 3
@@ -22,7 +23,7 @@ test_that("Dodging works", {
   xbase <- ceiling(df$group / ndodge)
 
   # This is the offset from dodging
-  xoffset <- (df$group-1) %% ndodge - (ndodge-1) / 2
+  xoffset <- (df$group - 1) %% ndodge - (ndodge - 1) / 2
   xoffset <- xoffset * dwidth
 
   # Check actual x locations equal predicted x locations
@@ -35,17 +36,17 @@ test_that("Dodging works", {
 
 
 test_that("Binning works", {
-
-  bp <- ggplot_build(ggplot(dat, aes(x=y)) + geom_dotplot(binwidth=.4, method="histodot"))
-  x <- bp$data[[1]]$x
+  bp <- ggplot(dat, aes(y)) +
+    geom_dotplot(binwidth = .4, method = "histodot")
+  x <- layer_data(bp)$x
 
   # Need ugly hack to make sure mod function doesn't give values like -3.99999
   # due to floating point error
   expect_true(all(abs((x - min(x) + 1e-7) %% .4) < 1e-6))
 
-
-  bp <- ggplot_build(ggplot(dat, aes(x=y)) + geom_dotplot(binwidth=.4, method="dotdensity"))
-  x <- bp$data[[1]]$x
+  bp <- ggplot(dat, aes(x = y)) +
+    geom_dotplot(binwidth = .4, method = "dotdensity")
+  x <- layer_data(bp)$x
 
   # This one doesn't ensure that dotdensity works, but it does check that it's not
   # doing fixed bin sizes
@@ -55,10 +56,10 @@ test_that("Binning works", {
 
 test_that("NA's result in warning from stat_bindot", {
   set.seed(122)
-  dat <- data.frame(x=rnorm(20))
+  dat <- data.frame(x = rnorm(20))
   dat$x[c(2,10)] <- NA
 
   # Need to assign it to a var here so that it doesn't automatically print
-  expect_that(bp <- ggplot_build(ggplot(dat, aes(x)) + geom_dotplot(binwidth=.2)),
-    gives_warning("Removed 2 rows.*stat_bindot"))
+  expect_warning(ggplot_build(ggplot(dat, aes(x)) + geom_dotplot(binwidth = .2)),
+    "Removed 2 rows.*stat_bindot")
 })
diff --git a/tests/testthat/test-empty-data.r b/tests/testthat/test-empty-data.r
new file mode 100644
index 0000000..666b056
--- /dev/null
+++ b/tests/testthat/test-empty-data.r
@@ -0,0 +1,97 @@
+context('Empty data')
+
+df0 <- data.frame(mpg = numeric(0), wt = numeric(0), am = numeric(0), cyl = numeric(0))
+
+test_that("layers with empty data are silently omitted", {
+  # Empty data (no visible points)
+  d <- ggplot(df0, aes(mpg,wt)) + geom_point()
+  expect_equal(nrow(layer_data(d)), 0)
+
+  d <- ggplot() + geom_point(data = df0, aes(mpg,wt))
+  expect_equal(nrow(layer_data(d)), 0)
+
+  # Regular mtcars data, x=mpg, y=wt, normal points and points from empty data frame
+  d <- ggplot(mtcars, aes(mpg, wt)) + geom_point() + geom_point(data = df0)
+  expect_equal(nrow(layer_data(d, 1)), nrow(mtcars))
+  expect_equal(nrow(layer_data(d, 2)), 0)
+
+  # Regular mtcars data, but points only from empty data frame
+  d <- ggplot(mtcars, aes(mpg, wt)) + geom_point(data = df0)
+  expect_equal(nrow(layer_data(d, 1)), 0)
+})
+
+
+test_that("plots with empty data and vectors for aesthetics work", {
+  d <- ggplot(NULL, aes(1:5, 1:5)) + geom_point()
+  expect_equal(nrow(layer_data(d)), 5)
+
+  d <- ggplot(data.frame(), aes(1:5, 1:5)) + geom_point()
+  expect_equal(nrow(layer_data(d)), 5)
+
+  d <- ggplot() + geom_point(aes(1:5, 1:5))
+  expect_equal(nrow(layer_data(d)), 5)
+})
+
+
+test_that("layers with empty data are silently omitted with facet_wrap", {
+  # Empty data, facet_wrap, throws error
+  d <- ggplot(df0, aes(mpg, wt)) +
+    geom_point() +
+    facet_wrap(~cyl)
+  expect_error(layer_data(d), "must have at least one value")
+
+  d <- d + geom_point(data = mtcars)
+  expect_equal(nrow(layer_data(d, 1)), 0)
+  expect_equal(nrow(layer_data(d, 2)), nrow(mtcars))
+})
+
+test_that("layers with empty data are silently omitted with facet_grid", {
+  d <- ggplot(df0, aes(mpg, wt)) +
+    geom_point() +
+    facet_grid(am ~ cyl)
+  expect_error(layer_data(d), "must have at least one value")
+
+  d <- d + geom_point(data = mtcars)
+  expect_equal(nrow(layer_data(d, 1)), 0)
+  expect_equal(nrow(layer_data(d, 2)), nrow(mtcars))
+})
+
+
+test_that("empty data overrides plot defaults", {
+  # Should error when totally empty data frame because there's no x and y
+  d <- ggplot(mtcars, aes(mpg, wt)) +
+    geom_point() +
+    geom_point(data = data.frame())
+  expect_error(layer_data(d), "not found")
+
+  # No extra points when x and y vars don't exist but are set
+  d <- ggplot(mtcars, aes(mpg, wt)) +
+    geom_point() +
+    geom_point(data = data.frame(), x = 20, y = 3)
+  expect_equal(nrow(layer_data(d, 1)), nrow(mtcars))
+  expect_equal(nrow(layer_data(d, 2)), 0)
+
+  # No extra points when x and y vars are empty, even when aesthetics are set
+  d <- ggplot(mtcars, aes(mpg, wt)) +
+    geom_point() +
+    geom_point(data = df0, x = 20, y = 3)
+  expect_equal(nrow(layer_data(d, 1)), nrow(mtcars))
+  expect_equal(nrow(layer_data(d, 2)), 0)
+})
+
+test_that("layer inherits data from plot when data = NULL", {
+  d <- ggplot(mtcars, aes(mpg, wt)) +
+    geom_point(data = NULL)
+  expect_equal(nrow(layer_data(d)), nrow(mtcars))
+})
+
+test_that("empty layers still generate one grob per panel", {
+  df <- data.frame(x = 1:3, y = c("a", "b", "c"))
+
+  d <- ggplot(df, aes(x, y)) +
+    geom_point(data = df[0, ]) +
+    geom_point() +
+    facet_wrap(~y)
+
+  expect_equal(length(layer_grob(d)), 3)
+})
diff --git a/inst/tests/test-facet-.r b/tests/testthat/test-facet-.r
similarity index 52%
rename from inst/tests/test-facet-.r
rename to tests/testthat/test-facet-.r
index 0054d01..e41decf 100644
--- a/inst/tests/test-facet-.r
+++ b/tests/testthat/test-facet-.r
@@ -3,41 +3,37 @@ context("Facetting")
 df <- data.frame(x = 1:3, y = 3:1, z = letters[1:3])
 
 test_that("facets split up the data", {
-  l1 <- ggplot(df, aes(x, y)) + geom_point() + facet_wrap(~ z)
-  d1 <- pdata(l1)[[1]]
-
-  expect_that(d1$PANEL, equals(factor(1:3)))
-
+  l1 <- ggplot(df, aes(x, y)) + geom_point() + facet_wrap(~z)
   l2 <- ggplot(df, aes(x, y)) + geom_point() + facet_grid(. ~ z)
   l3 <- ggplot(df, aes(x, y)) + geom_point() + facet_grid(z ~ .)
 
-  d2 <- pdata(l2)[[1]]
-  d3 <- pdata(l3)[[1]]
+  d1 <- layer_data(l1)
+  d2 <- layer_data(l2)
+  d3 <- layer_data(l3)
 
-  expect_that(d2, equals(d3))
-  expect_that(sort(names(d2)), equals(sort(c("x", "y", "group", "PANEL"))))
-  expect_that(d2$PANEL, equals(factor(1:3)))
+  expect_equal(d1, d2)
+  expect_equal(d1, d3)
+  expect_equal(d1$PANEL, factor(1:3))
 })
 
-
 test_that("facets with free scales scale independently", {
   l1 <- ggplot(df, aes(x, y)) + geom_point() +
-    facet_wrap(~ z, scales = "free")
+    facet_wrap(~z, scales = "free")
   d1 <- cdata(l1)[[1]]
-  expect_that(length(unique(d1$x)), equals(1))
-  expect_that(length(unique(d1$y)), equals(1))
+  expect_true(sd(d1$x) < 1e-10)
+  expect_true(sd(d1$y) < 1e-10)
 
   l2 <- ggplot(df, aes(x, y)) + geom_point() +
     facet_grid(. ~ z, scales = "free")
   d2 <- cdata(l2)[[1]]
-  expect_that(length(unique(d2$x)), equals(1))
-  expect_that(length(unique(d2$y)), equals(3))
+  expect_true(sd(d2$x) < 1e-10)
+  expect_equal(length(unique(d2$y)), 3)
 
   l3 <- ggplot(df, aes(x, y)) + geom_point() +
     facet_grid(z ~ ., scales = "free")
   d3 <- cdata(l3)[[1]]
-  expect_that(length(unique(d3$x)), equals(3))
-  expect_that(length(unique(d3$y)), equals(1))
+  expect_equal(length(unique(d3$x)), 3)
+  expect_true(sd(d3$y) < 1e-10)
 })
 
 
@@ -45,15 +41,15 @@ test_that("shrink parameter affects scaling", {
   l1 <- ggplot(df, aes(1, y)) + geom_point()
   r1 <- pranges(l1)
 
-  expect_that(r1$x[[1]], equals(c(1, 1)))
-  expect_that(r1$y[[1]], equals(c(1, 3)))
+  expect_equal(r1$x[[1]], c(1, 1))
+  expect_equal(r1$y[[1]], c(1, 3))
 
   l2 <- ggplot(df, aes(1, y)) + stat_summary(fun.y = "mean")
   r2 <- pranges(l2)
-  expect_that(r2$y[[1]], equals(c(2, 2)))
+  expect_equal(r2$y[[1]], c(2, 2))
 
   l3 <- ggplot(df, aes(1, y)) + stat_summary(fun.y = "mean") +
     facet_null(shrink = FALSE)
   r3 <- pranges(l3)
-  expect_that(r3$y[[1]], equals(c(1, 3)))
+  expect_equal(r3$y[[1]], c(1, 3))
 })
diff --git a/tests/testthat/test-facet-labels.r b/tests/testthat/test-facet-labels.r
new file mode 100644
index 0000000..9abf3a9
--- /dev/null
+++ b/tests/testthat/test-facet-labels.r
@@ -0,0 +1,149 @@
+context("Facet Labels")
+
+get_labels_matrix <- function(plot, ...) {
+  data <- ggplot_build(plot)
+  facet <- data$plot$facet
+  panel <- data$panel
+
+  labels <- get_labels_info(facet, panel, ...)
+  labeller <- match.fun(facet$labeller)
+
+  # Create matrix of labels
+  matrix <- lapply(labeller(labels), cbind)
+  matrix <- do.call("cbind", matrix)
+  matrix
+}
+
+get_labels_info <- function(facet, panel, ...) {
+  UseMethod("get_labels_info")
+}
+
+get_labels_info.grid <- function(facet, panel, type) {
+  if (type == "rows") {
+    labels <- unique(panel$layout[names(facet$rows)])
+    attr(labels, "type") <- "rows"
+    attr(labels, "facet") <- "grid"
+  } else {
+    labels <- unique(panel$layout[names(facet$cols)])
+    attr(labels, "type") <- "cols"
+    attr(labels, "facet") <- "grid"
+  }
+  labels
+}
+
+get_labels_info.wrap <- function(facet, panel) {
+  labels <- panel$layout[names(facet$facets)]
+  attr(labels, "facet") <- "wrap"
+  if (!is.null(facet$switch) && facet$switch == "x") {
+    attr(labels, "type") <- "rows"
+  } else {
+    attr(labels, "type") <- "cols"
+  }
+  labels
+}
+
+
+test_that("labellers handle facet labels properly", {
+  labels <- list(var1 = letters[1:2], var2 = letters[3:4])
+
+  expect_identical(label_value(labels), labels)
+  expect_identical(label_value(labels, FALSE), list(c("a, c", "b, d")))
+
+  expect_identical(label_both(labels), list(c("var1: a", "var1: b"), c("var2: c", "var2: d")))
+  expect_identical(label_both(labels, FALSE), list(c("var1, var2: a, c", "var1, var2: b, d")))
+})
+
+test_that("labellers handle plotmath expressions", {
+  labels <- list(var1 = c("alpha", "beta"), var2 = letters[3:4])
+
+  expected_parsed <- list(
+    list(expression(alpha), expression(beta)),
+    list(expression(c), expression(d))
+  )
+  expect_identical(label_parsed(labels), expected_parsed)
+
+  expected_parsed_multi <- list(list(
+    expression(list(alpha, c)),
+    expression(list(beta, d))
+  ))
+  expect_identical(label_parsed(labels, FALSE), expected_parsed_multi)
+})
+
+test_that("label_value() handles factors", {
+  labels_chr <- list(var1 = letters[1:2], var2 = letters[3:4])
+  labels <- lapply(labels_chr, factor)
+
+  expect_identical(label_value(labels), labels_chr)
+})
+
+test_that("labeller() dispatches labellers", {
+  p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
+  expected_cyl_both <- cbind(paste("cyl:", c(4, 6, 8)))
+  expected_am_both <- cbind(paste("am:", 0:1))
+
+  # Rows and cols dispatch with facet_wrap()
+  p1 <- p + facet_wrap(~cyl, labeller = labeller(.rows = label_both))
+  p2 <- p + facet_wrap(~cyl, labeller = labeller(.cols = label_both))
+  expect_equal(get_labels_matrix(p1), expected_cyl_both)
+  expect_equal(get_labels_matrix(p2), expected_cyl_both)
+
+  # facet_wrap() shouldn't get both rows and cols
+  p3 <- p + facet_wrap(~cyl, labeller = labeller(
+    .cols = label_both, .rows = label_both))
+  expect_error(ggplotGrob(p3))
+
+  # facet_grid() can get both rows and cols
+  p4 <- p + facet_grid(am ~ cyl, labeller = labeller(
+    .cols = label_both, .rows = label_both))
+  expect_equal(get_labels_matrix(p4, "rows"), expected_am_both)
+  expect_equal(get_labels_matrix(p4, "cols"), expected_cyl_both)
+
+  # Cannot have a specific labeller for a variable which already has a
+  # margin-wide labeller
+  p5 <- p + facet_wrap(~cyl, labeller = labeller(
+    .rows = label_both, cyl = label_value))
+  expect_error(ggplotGrob(p5))
+
+  # Variables can be attributed labellers
+  p6 <- p + facet_grid(am + cyl ~ ., labeller = labeller(
+     am = label_both, cyl = label_both))
+  expect_equal(
+    get_labels_matrix(p6, "rows"),
+    cbind(
+      paste("am:", rep(0:1, each = 3)),
+      paste("cyl:", rep(c(4, 6, 8), 2))
+    )
+  )
+
+  # Default labeller is used for other variables
+  p7 <- p + facet_grid(am ~ cyl, labeller = labeller(.default = label_both))
+  expect_equal(get_labels_matrix(p7, "rows"), expected_am_both)
+  expect_equal(get_labels_matrix(p7, "cols"), expected_cyl_both)
+})
+
+test_that("as_labeller() deals with non-labellers", {
+  p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
+  lookup <- c(`0` = "zero", `1` = "one")
+
+  # Lookup table
+  p1 <- p + facet_wrap(~am, labeller = labeller(am = lookup))
+  expect_equal(get_labels_matrix(p1), cbind(c("zero", "one")))
+
+  # Non-labeller function taking character vectors
+  p2 <- p + facet_wrap(~am, labeller = labeller(am = function(x) paste0(x, "-foo")))
+  expect_equal(get_labels_matrix(p2), cbind(c("0-foo", "1-foo")))
+})
+
+test_that("old school labellers still work", {
+  my_labeller <- function(variable, value) {
+    paste0("var = ", as.character(value))
+  }
+
+  expect_warning(p <-
+    ggplot(mtcars, aes(disp, drat)) +
+    geom_point() +
+    facet_grid(~cyl, labeller = my_labeller))
+
+  expected_labels <- cbind(paste("var =", c(4, 6, 8)))
+  expect_identical(get_labels_matrix(p, "cols"), expected_labels)
+})
diff --git a/inst/tests/test-facet-layout.r b/tests/testthat/test-facet-layout.r
similarity index 70%
rename from inst/tests/test-facet-layout.r
rename to tests/testthat/test-facet-layout.r
index 7613099..9e91120 100644
--- a/inst/tests/test-facet-layout.r
+++ b/tests/testthat/test-facet-layout.r
@@ -6,87 +6,85 @@ c <- data.frame(b = 3)
 empty <- data.frame()
 
 test_that("all: no rows and cols gives null layout", {
-  expect_that(layout_grid(list(a)), equals(layout_null()))
-  expect_that(layout_wrap(list(a)), equals(layout_null()))
+  expect_equal(layout_grid(list(a)), layout_null())
+  expect_equal(layout_wrap(list(a)), layout_null())
 })
 
 test_that("grid: single row and single col equivalent", {
-  row <- layout_grid(list(a), row = "a")
-  col <- layout_grid(list(a), col = "a")
+  row <- layout_grid(list(a), rows = "a")
+  col <- layout_grid(list(a), cols = "a")
 
-  expect_that(row$ROW, equals(1:2))
-  expect_that(row$ROW, equals(col$COL))
-  expect_that(row[c("PANEL", "a")], equals(col[c("PANEL", "a")]))
+  expect_equal(row$ROW, 1:2)
+  expect_equal(row$ROW, col$COL)
+  expect_equal(row[c("PANEL", "a")], col[c("PANEL", "a")])
 
-  row <- layout_grid(list(a, b), row = "a")
-  col <- layout_grid(list(a, b), col = "a")
+  row <- layout_grid(list(a, b), rows = "a")
+  col <- layout_grid(list(a, b), cols = "a")
 
-  expect_that(row$ROW, equals(1:3))
-  expect_that(row$ROW, equals(col$COL))
-  expect_that(row[c("PANEL", "a")], equals(col[c("PANEL", "a")]))
+  expect_equal(row$ROW, 1:3)
+  expect_equal(row$ROW, col$COL)
+  expect_equal(row[c("PANEL", "a")], col[c("PANEL", "a")])
 })
 
 test_that("grid: includes all combinations", {
   d <- data.frame(a = c(1, 2), b = c(2, 1))
-  all <- layout_grid(list(d), row = "a", col = "b")
+  all <- layout_grid(list(d), rows = "a", cols = "b")
 
-  expect_that(nrow(all), equals(4))
+  expect_equal(nrow(all), 4)
 })
 
 test_that("wrap and grid equivalent for 1d data", {
-  rowg <- layout_grid(list(a), row = "a")
+  rowg <- layout_grid(list(a), rows = "a")
   roww <- layout_wrap(list(a), "a", ncol = 1)
-  expect_that(roww, equals(rowg))
+  expect_equal(roww, rowg)
 
-  colg <- layout_grid(list(a), col = "a")
+  colg <- layout_grid(list(a), cols = "a")
   colw <- layout_wrap(list(a), "a", nrow = 1)
-  expect_that(colw, equals(colg))
+  expect_equal(colw, colg)
 })
 
 test_that("grid: crossed rows/cols create no more combinations than necessary", {
   one <- layout_grid(list(a), "a", "b")
-  expect_that(nrow(one), equals(4))
+  expect_equal(nrow(one), 4)
 
   one_a <- layout_grid(list(a, empty), "a", "b")
-  expect_that(nrow(one_a), equals(4))
+  expect_equal(nrow(one_a), 4)
 
   two <- layout_grid(list(a, b), "a", "b")
-  expect_that(nrow(two), equals(4 + 2))
+  expect_equal(nrow(two), 4 + 2)
 
   three <- layout_grid(list(a, b, c), "a", "b")
-  expect_that(nrow(three), equals(9))
+  expect_equal(nrow(three), 9)
 
   four <- layout_grid(list(b, c), "a", "b")
-  expect_that(nrow(four), equals(1))
+  expect_equal(nrow(four), 1)
 })
 
 test_that("grid: nested rows/cols create no more combinations than necessary", {
   one <- layout_grid(list(mpg), c("drv", "cyl"))
-  expect_that(one$PANEL, equals(factor(1:9)))
-  expect_that(one$ROW, equals(1:9))
+  expect_equal(one$PANEL, factor(1:9))
+  expect_equal(one$ROW, 1:9)
 })
 
 test_that("grid: margins add correct combinations", {
   one <- layout_grid(list(a), "a", "b", margins = TRUE)
-  expect_that(nrow(one), equals(4 + 2 + 2 + 1))
+  expect_equal(nrow(one), 4 + 2 + 2 + 1)
 })
 
 test_that("wrap: as.table reverses rows", {
   one <- layout_wrap(list(a), "a", ncol = 1, as.table = FALSE)
-  expect_that(one$ROW, equals(c(2, 1)))
+  expect_equal(one$ROW, c(2, 1))
 
   two <- layout_wrap(list(a), "a", nrow = 1, as.table = FALSE)
-  expect_that(two$ROW, equals(c(1, 1)))
-
+  expect_equal(two$ROW, c(1, 1))
 })
 
 test_that("grid: as.table reverses rows", {
   one <- layout_grid(list(a), "a", as.table = FALSE)
-  expect_that(as.character(one$a), equals(c("2", "1")))
+  expect_equal(as.character(one$a), c("2", "1"))
 
   two <- layout_grid(list(a), "a", as.table = TRUE)
-  expect_that(as.character(two$a), equals(c("1", "2")))
-
+  expect_equal(as.character(two$a), c("1", "2"))
 })
 
 # Drop behaviour -------------------------------------------------------------
diff --git a/inst/tests/test-facet-locate.r b/tests/testthat/test-facet-locate.r
similarity index 79%
rename from inst/tests/test-facet-locate.r
rename to tests/testthat/test-facet-locate.r
index ecf8789..a2b0628 100644
--- a/inst/tests/test-facet-locate.r
+++ b/tests/testthat/test-facet-locate.r
@@ -10,11 +10,11 @@ test_that("two col cases with no missings adds single extra column", {
   vscyl <- layout_grid(list(mtcars), "cyl", "vs")
   loc <- locate_grid(mtcars, vscyl, "cyl", "vs")
 
-  expect_that(nrow(loc), equals(nrow(mtcars)))
-  expect_that(ncol(loc), equals(ncol(mtcars) + 1))
+  expect_equal(nrow(loc), nrow(mtcars))
+  expect_equal(ncol(loc), ncol(mtcars) + 1)
 
   match <- unique(loc[c("cyl", "vs", "PANEL")])
-  expect_that(nrow(match), equals(5))
+  expect_equal(nrow(match), 5)
 
 })
 
@@ -22,7 +22,7 @@ test_that("margins add extra data", {
   panel <- layout_grid(list(df), "a", "b", margins = "b")
   loc <- locate_grid(df, panel, "a", "b", margins = "b")
 
-  expect_that(nrow(loc), equals(nrow(df) * 2))
+  expect_equal(nrow(loc), nrow(df) * 2)
 })
 
 
@@ -30,33 +30,33 @@ test_that("grid: missing facet columns are duplicated", {
   panel <- layout_grid(list(df), "a", "b")
 
   loc_a <- locate_grid(df_a, panel, "a", "b")
-  expect_that(nrow(loc_a), equals(4))
-  expect_that(loc_a$PANEL, equals(factor(1:4)))
+  expect_equal(nrow(loc_a), 4)
+  expect_equal(loc_a$PANEL, factor(1:4))
 
   loc_b <- locate_grid(df_b, panel, "a", "b")
-  expect_that(nrow(loc_b), equals(4))
-  expect_that(loc_b$PANEL, equals(factor(1:4)))
+  expect_equal(nrow(loc_b), 4)
+  expect_equal(loc_b$PANEL, factor(1:4))
 
   loc_c <- locate_grid(df_c, panel, "a", "b")
-  expect_that(nrow(loc_c), equals(4))
-  expect_that(loc_c$PANEL, equals(factor(1:4)))
+  expect_equal(nrow(loc_c), 4)
+  expect_equal(loc_c$PANEL, factor(1:4))
 })
 
 test_that("wrap: missing facet columns are duplicated", {
   panel <- layout_wrap(list(df), c("a", "b"), ncol = 1)
 
   loc_a <- locate_wrap(df_a, panel, c("a", "b"))
-  expect_that(nrow(loc_a), equals(4))
-  expect_that(loc_a$PANEL, equals(factor(1:4)))
-  expect_that(loc_a$a, equals(c(1, 1, 2, 2)))
+  expect_equal(nrow(loc_a), 4)
+  expect_equal(loc_a$PANEL, factor(1:4))
+  expect_equal(loc_a$a, c(1, 1, 2, 2))
 
   loc_b <- locate_wrap(df_b, panel, c("a", "b"))
-  expect_that(nrow(loc_b), equals(4))
-  expect_that(loc_b$PANEL, equals(factor(1:4)))
+  expect_equal(nrow(loc_b), 4)
+  expect_equal(loc_b$PANEL, factor(1:4))
 
   loc_c <- locate_wrap(df_c, panel, c("a", "b"))
-  expect_that(nrow(loc_c), equals(4))
-  expect_that(loc_c$PANEL, equals(factor(1:4)))
+  expect_equal(nrow(loc_c), 4)
+  expect_equal(loc_c$PANEL, factor(1:4))
 
 })
 
@@ -122,7 +122,7 @@ test_that("grid: facet order follows default data frame order", {
   # BCA for rows 1:3
   # acb for cols 1:3
   lay <- get_layout(ggplot(mapping = aes(x, y)) + facet_grid(fy ~ fx) +
-    geom_blank(data = d2) + geom_point(data=d))
+    geom_blank(data = d2) + geom_point(data = d))
   expect_equal(as.character(lay$fy), c("B","C","A")[lay$ROW])
   expect_equal(as.character(lay$fx), c("a","c","b")[lay$COL])
 
@@ -138,24 +138,24 @@ test_that("grid: facet order follows default data frame order", {
 test_that("wrap: facet order follows default data frame order", {
   # Facets should be in order:
   # cba for panels 1:3
-  lay <- get_layout(ggplot(d, aes(x, y)) + facet_wrap(~ fx) + geom_point())
+  lay <- get_layout(ggplot(d, aes(x, y)) + facet_wrap(~fx) + geom_point())
   expect_equal(as.character(lay$fx), c("c","b","a")[lay$PANEL])
 
   # When adding d2, facets should still be in order:
   # cba for panels 1:3
-  lay <- get_layout(ggplot(d, aes(x, y)) + facet_wrap(~ fx) +
+  lay <- get_layout(ggplot(d, aes(x, y)) + facet_wrap(~fx) +
     geom_blank(data = d2) + geom_point())
   expect_equal(as.character(lay$fx), c("c","b","a")[lay$PANEL])
 
   # With no default data: should search each layer in order
   # acb for panels 1:3
-  lay <- get_layout(ggplot(mapping = aes(x, y)) + facet_wrap(~ fx) +
-    geom_blank(data = d2) + geom_point(data=d))
+  lay <- get_layout(ggplot(mapping = aes(x, y)) + facet_wrap(~fx) +
+    geom_blank(data = d2) + geom_point(data = d))
   expect_equal(as.character(lay$fx), c("a","c","b")[lay$PANEL])
 
   # Same as previous, but different layer order.
   # cba for panels 1:3
-  lay <- get_layout(ggplot(mapping = aes(x, y)) + facet_wrap(~ fx) +
+  lay <- get_layout(ggplot(mapping = aes(x, y)) + facet_wrap(~fx) +
     geom_point(data = d) + geom_blank(data = d2))
   expect_equal(as.character(lay$fx), c("c","b","a")[lay$PANEL])
 
diff --git a/inst/tests/test-fortify.r b/tests/testthat/test-fortify.r
similarity index 93%
rename from inst/tests/test-fortify.r
rename to tests/testthat/test-fortify.r
index efc4735..5265fa4 100644
--- a/inst/tests/test-fortify.r
+++ b/tests/testthat/test-fortify.r
@@ -32,6 +32,6 @@ test_that("Spatial polygons have correct ordering", {
   polys2_sp <- SpatialPolygons(polys2)
   fake_sp2 <- SpatialPolygonsDataFrame(polys2_sp, fake_data)
 
-  expect_equivalent(fortify(fake_sp), arrange(fortify(fake_sp2), id, order))
+  expect_equivalent(fortify(fake_sp), plyr::arrange(fortify(fake_sp2), id, order))
 
 })
diff --git a/tests/testthat/test-function-args.r b/tests/testthat/test-function-args.r
new file mode 100644
index 0000000..eeaf682
--- /dev/null
+++ b/tests/testthat/test-function-args.r
@@ -0,0 +1,71 @@
+context("function-args")
+
+filter_args <- function(x) {
+  all_names <- names(x)
+  all_names <- setdiff(all_names, c("self", "data", "scales", "coordinates", "..."))
+  x[all_names]
+}
+
+test_that("geom_xxx and GeomXxx$draw arg defaults match", {
+  ggplot2_ns <- asNamespace("ggplot2")
+  objs <- ls(ggplot2_ns)
+  geom_fun_names <- objs[grepl("^(geom|annotation)_", objs)]
+  # These aren't actually geoms, or need special parameters and can't be tested this way.
+  geom_fun_names <- setdiff(
+    geom_fun_names,
+    c("geom_aesthetics", "geom_map", "annotation_custom", "annotation_map",
+      "annotation_raster", "annotation_id")
+  )
+
+  # For each geom_xxx function and the corresponding GeomXxx$draw and
+  # GeomXxx$draw_groups functions, make sure that if they have same args, that
+  # the args have the same default values.
+  lapply(geom_fun_names, function(geom_fun_name) {
+    geom_fun    <- ggplot2_ns[[geom_fun_name]]
+    draw        <- geom_fun()$geom$draw_layer
+    draw_groups <- geom_fun()$geom$draw_group
+
+    fun_args <- formals(geom_fun)
+    draw_args <- c(ggproto_formals(draw), ggproto_formals(draw_groups))
+    draw_args <- filter_args(draw_args)
+
+    common_names <- intersect(names(fun_args), names(draw_args))
+
+    expect_identical(fun_args[common_names], draw_args[common_names],
+      info = paste0("Mismatch between arg defaults for ", geom_fun_name,
+        " and ", class(geom_fun()$geom)[1], "'s $draw and/or $draw_group functions.")
+    )
+  })
+})
+
+
+test_that("stat_xxx and StatXxx$draw arg defaults match", {
+  ggplot2_ns <- asNamespace("ggplot2")
+  objs <- ls(ggplot2_ns)
+  stat_fun_names <- objs[grepl("^stat_", objs)]
+  # These aren't actually stats, or need special parameters and can't be tested this way.
+  stat_fun_names <- setdiff(
+    stat_fun_names,
+    c("stat_aesthetics", "stat_function")
+  )
+
+  # For each geom_xxx function and the corresponding GeomXxx$draw and
+  # GeomXxx$draw_groups functions, make sure that if they have same args, that
+  # the args have the same default values.
+  lapply(stat_fun_names, function(stat_fun_name) {
+    stat_fun         <- ggplot2_ns[[stat_fun_name]]
+    calculate        <- stat_fun()$stat$compute
+    calculate_groups <- stat_fun()$stat$compute_group
+
+    fun_args <- formals(stat_fun)
+    calc_args <- c(ggproto_formals(calculate), ggproto_formals(calculate_groups))
+    calc_args <- filter_args(calc_args)
+
+    common_names <- intersect(names(fun_args), names(calc_args))
+
+    expect_identical(fun_args[common_names], calc_args[common_names],
+      info = paste0("Mismatch between arg defaults for ", stat_fun_name,
+        " and ", class(stat_fun()$stat)[1], "'s $compute and/or $compute_groups functions.")
+    )
+  })
+})
diff --git a/tests/testthat/test-geom-rule.R b/tests/testthat/test-geom-rule.R
new file mode 100644
index 0000000..109916f
--- /dev/null
+++ b/tests/testthat/test-geom-rule.R
@@ -0,0 +1,34 @@
+context("geom_rule")
+# tests for geom_vline, geom_hline & geom_abline
+
+df <- data.frame(x = 1:3, y = 3:1)
+p <- ggplot(df, aes(x, y)) + geom_point()
+p_col <- ggplot(df, aes(x, y, colour = factor(x))) + geom_point()
+
+test_that("setting parameters makes one row df", {
+  b <- p + geom_hline(yintercept = 1.5)
+  expect_equal(layer_data(b, 2)$yintercept, 1.5)
+
+  b <- p + geom_vline(xintercept = 1.5)
+  expect_equal(layer_data(b, 2)$xintercept, 1.5)
+
+  b <- p + geom_abline()
+  expect_equal(layer_data(b, 2)$intercept, 0)
+  expect_equal(layer_data(b, 2)$slope, 1)
+
+  b <- p + geom_abline(slope = 0, intercept = 1)
+  expect_equal(layer_data(b, 2)$intercept, 1)
+  expect_equal(layer_data(b, 2)$slope, 0)
+})
+
+test_that("setting aesthetics generates one row for each input row", {
+  b <- p + geom_hline(aes(yintercept = 1.5))
+  expect_equal(layer_data(b, 2)$yintercept, rep(1.5, 3))
+
+  b <- p + geom_vline(aes(xintercept = 1.5))
+  expect_equal(layer_data(b, 2)$xintercept, rep(1.5, 3))
+
+  b <- p + geom_abline(aes(slope = 0, intercept = 1))
+  expect_equal(layer_data(b, 2)$intercept, rep(1, 3))
+  expect_equal(layer_data(b, 2)$slope, rep(0, 3))
+})
diff --git a/tests/testthat/test-geom-text.R b/tests/testthat/test-geom-text.R
new file mode 100644
index 0000000..ffc3a71
--- /dev/null
+++ b/tests/testthat/test-geom-text.R
@@ -0,0 +1,33 @@
+context("geom_text")
+
+# compute_just ------------------------------------------------------------
+
+test_that("vertical and horizontal positions are equivalent", {
+  horiz <- compute_just(c("left", "middle", "right"), c(0, 0, 0))
+  vert <- compute_just(c("bottom", "center", "top"), c(0, 0, 0))
+
+  expect_equal(horiz, vert)
+})
+
+test_that("inward moves text towards center", {
+  expect_equal(
+    compute_just(c("inward", "inward", "inward"), c(0, 0.5, 1)),
+    c(0, 0.5, 1.0)
+  )
+})
+
+test_that("outwards moves text away from center", {
+  expect_equal(
+    compute_just(c("outward", "outward", "outward"), c(0, 0.5, 1)),
+    c(1.0, 0.5, 0)
+  )
+})
+
+test_that("inward points close to center are centered", {
+  expect_equal(
+    compute_just(c("inward", "inward", "inward"), c(0.5 - 1e-3, 0.5, 0.5 + 1e-3)),
+    c(0.5, 0.5, 0.5)
+  )
+
+})
+
diff --git a/tests/testthat/test-geom-violin.R b/tests/testthat/test-geom-violin.R
new file mode 100644
index 0000000..2f5208b
--- /dev/null
+++ b/tests/testthat/test-geom-violin.R
@@ -0,0 +1,27 @@
+context("geom_violin")
+
+test_that("", {
+  df <- rbind(
+    data.frame(x = "a", y = c(0, runif(10), 1)),
+    data.frame(x = "b", y = c(0, runif(10), 2))
+  )
+
+  p <- ggplot(df, aes(1, y)) +
+    geom_violin() +
+    facet_grid(x ~ ., scales = "free") +
+    coord_cartesian(expand = FALSE)
+
+  expect_equal(layer_scales(p, 1)$y$dimension(), c(0, 1))
+  expect_equal(layer_scales(p, 2)$y$dimension(), c(0, 2))
+})
+
+# create_quantile_segment_frame -------------------------------------------------
+
+test_that("create_quantile_segment_frame functions for 3 quantiles", {
+  density.data <- data.frame(y=(1:256)/256, density=1/256) # uniform density
+
+  qs <- c(0.25, 0.5, 0.75) # 3 quantiles
+  expect_equal(create_quantile_segment_frame(density.data, qs)$y,
+               rep(qs, each=2))
+})
+
diff --git a/tests/testthat/test-ggsave.R b/tests/testthat/test-ggsave.R
new file mode 100644
index 0000000..0aac88c
--- /dev/null
+++ b/tests/testthat/test-ggsave.R
@@ -0,0 +1,59 @@
+context("ggsave")
+
+test_that("ggsave creates file", {
+  path <- tempfile()
+  on.exit(unlink(path))
+
+  p <- ggplot(mpg, aes(displ, hwy)) + geom_point()
+
+  expect_false(file.exists(path))
+  ggsave(path, p, device = "pdf", width = 5, height = 5)
+  expect_true(file.exists(path))
+})
+
+
+# plot_dim ---------------------------------------------------------------
+
+test_that("guesses and informs if dim not specified", {
+  png(width = 10, height = 10, units = "in", res = 300)
+  on.exit(capture.output(dev.off()))
+
+  expect_message(out <- plot_dim(), "10 x 10")
+  expect_equal(out, c(10, 10))
+})
+
+test_that("uses 7x7 if no graphics device open", {
+  expect_equal(plot_dim(), c(7, 7))
+})
+
+test_that("warned about large plot unless limitsize = FALSE", {
+  expect_error(plot_dim(c(50, 50)), "exceed 50 inches")
+  expect_equal(plot_dim(c(50, 50), limitsize = FALSE), c(50, 50))
+})
+
+test_that("scale multiplies height & width", {
+  expect_equal(plot_dim(c(10, 10), scale = 1), c(10, 10))
+  expect_equal(plot_dim(c(5, 5), scale = 2), c(10, 10))
+})
+
+
+# plot_dev ---------------------------------------------------------------------
+
+test_that("function passed back unchanged", {
+  expect_equal(plot_dev(png), png)
+})
+
+test_that("unknown device triggers error", {
+  expect_error(plot_dev("xyz"), "Unknown graphics device")
+  expect_error(plot_dev(NULL, "test.xyz"), "Unknown graphics device")
+})
+
+
+test_that("text converted to function", {
+  expect_identical(body(plot_dev("png"))[[1]], quote(grDevices::png))
+  expect_identical(body(plot_dev("pdf"))[[1]], quote(grDevices::pdf))
+})
+
+test_that("if device is NULL, guess from extension", {
+  expect_identical(body(plot_dev(NULL, "test.png"))[[1]], quote(grDevices::png))
+})
diff --git a/tests/testthat/test-guides.R b/tests/testthat/test-guides.R
new file mode 100644
index 0000000..0a1aa6d
--- /dev/null
+++ b/tests/testthat/test-guides.R
@@ -0,0 +1,10 @@
+context("Guides")
+
+test_that("colourbar trains without labels", {
+  g <- guide_colorbar()
+  sc <- scale_colour_continuous(limits = c(0, 4), labels = NULL)
+
+  out <- guide_train(g, sc)
+  expect_equal(names(out$key), c("colour", ".value"))
+})
+
diff --git a/inst/tests/test-labels.r b/tests/testthat/test-labels.r
similarity index 100%
rename from inst/tests/test-labels.r
rename to tests/testthat/test-labels.r
diff --git a/tests/testthat/test-layer.r b/tests/testthat/test-layer.r
new file mode 100644
index 0000000..80887ce
--- /dev/null
+++ b/tests/testthat/test-layer.r
@@ -0,0 +1,34 @@
+context("Layer")
+
+
+# Parameters --------------------------------------------------------------
+
+test_that("aesthetics go in aes_params", {
+  l <- geom_point(size = "red")
+  expect_equal(l$aes_params, list(size = "red"))
+})
+
+test_that("unknown params create error", {
+  expect_error(geom_point(blah = "red"), "Unknown parameters")
+})
+
+# Calculated aesthetics ---------------------------------------------------
+
+test_that("Bare name surround by .. is calculated", {
+  expect_true(is_calculated_aes(aes(..density..)))
+  expect_true(is_calculated_aes(aes(..DENSITY..)))
+  expect_false(is_calculated_aes(aes(a..x..b)))
+})
+
+test_that("Calling using variable surround by .. is calculated", {
+  expect_true(is_calculated_aes(aes(mean(..density..))))
+  expect_true(is_calculated_aes(aes(mean(..DENSITY..))))
+  expect_false(is_calculated_aes(aes(mean(a..x..b))))
+})
+
+test_that("strip_dots remove dots around calculated aesthetics", {
+  expect_equal(strip_dots(aes(..density..))$x, quote(density))
+  expect_equal(strip_dots(aes(mean(..density..)))$x, quote(mean(density)))
+  expect_equal(strip_dots(aes(sapply(..density.., function(x) mean(x)))$x),
+               quote(sapply(density, function(x) mean(x))))
+})
diff --git a/tests/testthat/test-munch.r b/tests/testthat/test-munch.r
new file mode 100644
index 0000000..a765b69
--- /dev/null
+++ b/tests/testthat/test-munch.r
@@ -0,0 +1,51 @@
+context("Munch")
+
+test_that("interp works", {
+    single_interp_test <- function(start, end, n) {
+        i <- interp(start, end, n)
+        info <- paste0("start: ", start, "; end: ", end, "; n: ", n)
+        expect_equal(length(i), n, info = info)
+        expect_true(start %in% i, info = info)
+        expect_false(end %in% i, info = info)
+        expect_true(all(i >= start), info = info)
+        expect_true(all(i <= end), info = info)
+    }
+    single_interp_test(0, 1, 1)
+    single_interp_test(0, 1, 2)
+    single_interp_test(0, 1, 7)
+    single_interp_test(-23, 56, 1)
+    single_interp_test(-23, 56, 4)
+    single_interp_test(31.276, 34.443, 1)
+    single_interp_test(31.276, 34.443, 100)
+})
+
+test_that("munch_data works", {
+    single_munch_test <- function(data, dist=NULL, segment_length = 0.01) {
+        md <- munch_data(data, dist, segment_length)
+        # all rows of dat are in md
+        expect_equal(nrow(merge(md, dat)), nrow(dat))
+        expect_true(nrow(md) >= nrow(dat))
+    }
+    dat <- data.frame(x =     c(0,  60, 30, 20, 40, 45),
+                      y =     c(1,  1,  2,  2,  2,  2),
+                      group = c(1L, 1L, 1L, 2L, 2L, 2L))
+    dist <- dist_euclidean(dat$x, dat$y)
+    dist[dat$group[-1] != dat$group[-nrow(dat)]] <- NA
+    single_munch_test(dat, dist)
+    single_munch_test(dat, dist, segment_length = 10)
+    single_munch_test(dat, dist, segment_length = 100)
+    dist <- coord_polar(theta = "x")$distance(dat$x, dat$y,
+                           list(r.range = range(c(0,dat$y)),
+                                theta.range = range(dat$x)))
+    dist[dat$group[-1] != dat$group[-nrow(dat)]] <- NA
+    single_munch_test(dat, dist)
+    single_munch_test(dat, dist, segment_length = 10)
+    single_munch_test(dat, dist, segment_length = 100)
+    dist <- coord_polar(theta = "y")$distance(dat$x, dat$y,
+                           list(r.range = range(c(0,dat$x)),
+                                theta.range = range(dat$y)))
+    dist[dat$group[-1] != dat$group[-nrow(dat)]] <- NA
+    single_munch_test(dat, dist)
+    single_munch_test(dat, dist, segment_length = 10)
+    single_munch_test(dat, dist, segment_length = 100)
+})
diff --git a/inst/tests/test-qplot.r b/tests/testthat/test-qplot.r
similarity index 100%
rename from inst/tests/test-qplot.r
rename to tests/testthat/test-qplot.r
diff --git a/tests/testthat/test-range.r b/tests/testthat/test-range.r
new file mode 100644
index 0000000..8cb0e53
--- /dev/null
+++ b/tests/testthat/test-range.r
@@ -0,0 +1,24 @@
+context("range")
+
+test_that("continuous ranges expands as expected", {
+  r <- continuous_range()
+
+  r$train(1)
+  expect_equal(r$range, c(1, 1))
+
+  r$train(10)
+  expect_equal(r$range, c(1, 10))
+})
+
+test_that("discrete ranges expands as expected", {
+  r <- discrete_range()
+
+  r$train("a")
+  expect_equal(r$range, "a")
+
+  r$train("b")
+  expect_equal(r$range, c("a", "b"))
+
+  r$train(letters)
+  expect_equal(r$range, letters)
+})
diff --git a/tests/testthat/test-sanitise-dim.r b/tests/testthat/test-sanitise-dim.r
new file mode 100644
index 0000000..375c434
--- /dev/null
+++ b/tests/testthat/test-sanitise-dim.r
@@ -0,0 +1,34 @@
+context("sanitise_dim")
+
+test_that("sanitise_dim returns NULL for zero-length inputs, with appropriate warnings", {
+  expect_identical(sanitise_dim(NULL), NULL)
+  n <- integer()
+  y <- expect_identical(suppressWarnings(sanitise_dim(n)), NULL)
+  expect_warning(sanitise_dim(n), "`n` has length zero and will be treated as NULL.")
+})
+
+test_that("sanitise_dim returns the first element or NULL for non-positive integer inputs, with appropriate warnings", {
+  n <- 1:2
+  expect_identical(suppressWarnings(sanitise_dim(n)), 1L)
+  expect_warning(sanitise_dim(n), "Only the first value of `n` will be used.")
+  n2 <- 0:1
+  expect_identical(suppressWarnings(sanitise_dim(n2)), NULL)
+  expect_warning(sanitise_dim(n2), "Only the first value of `n2` will be used.")
+  expect_warning(sanitise_dim(n2), "`n2` is missing or less than 1 and will be treated as NULL.")
+})
+
+test_that("sanitise_dim returns a NULL for missing inputs, with appropriate warnings", {
+  n <- NA_integer_
+  expect_identical(suppressWarnings(sanitise_dim(n)), NULL)
+  expect_warning(sanitise_dim(n), "`n` is missing or less than 1 and will be treated as NULL.")
+})
+
+test_that("sanitise_dim returns a positive integer or NULL for non-integer inputs, with appropriate warnings", {
+  n <- 1.5
+  expect_identical(suppressWarnings(sanitise_dim(n)), 1L)
+  expect_warning(sanitise_dim(n), "Coercing `n` to be an integer.")
+  n2 <- 0.9999999
+  expect_identical(suppressWarnings(sanitise_dim(n2)), NULL)
+  expect_warning(sanitise_dim(n2), "Coercing `n2` to be an integer.")
+  expect_warning(sanitise_dim(n2), "`n2` is missing or less than 1 and will be treated as NULL.")
+})
diff --git a/inst/tests/test-scale-manual.r b/tests/testthat/test-scale-manual.r
similarity index 83%
rename from inst/tests/test-scale-manual.r
rename to tests/testthat/test-scale-manual.r
index 45fcbe6..1013c83 100644
--- a/inst/tests/test-scale-manual.r
+++ b/tests/testthat/test-scale-manual.r
@@ -3,8 +3,8 @@ context("scale_manual")
 
 test_that("names of values used in manual scales", {
    s <- scale_colour_manual(values = c("8" = "c","4" = "a","6" = "b"))
-   scale_train(s, c("4", "6", "8"))
-   expect_equal(scale_map(s, c("4", "6", "8")), c("a", "b", "c"))
+   s$train(c("4", "6", "8"))
+   expect_equal(s$map(c("4", "6", "8")), c("a", "b", "c"))
 })
 
 
@@ -29,10 +29,11 @@ test_that("named values work regardless of order", {
 
 test_that("missing values replaced with na.value", {
   df <- data.frame(x = 1, y = 1:3, z = factor(c(1:2, NA), exclude = NULL))
-  pdata <- ggplot_build(qplot(x, y, data = df, colour = z) +
-    scale_colour_manual(values = c("black", "black"), na.value = "red"))
+  p <- ggplot(df, aes(x, y, colour = z)) +
+    geom_point() +
+    scale_colour_manual(values = c("black", "black"), na.value = "red")
 
-  expect_equal(pdata$data[[1]]$colour, c("black", "black", "red"))
+  expect_equal(layer_data(p)$colour, c("black", "black", "red"))
 })
 
 test_that("insufficient values raise an error", {
@@ -50,7 +51,7 @@ test_that("insufficient values raise an error", {
 test_that("values are matched when scale contains more unique valuesthan are in the data", {
   s <- scale_colour_manual(values = c("8" = "c", "4" = "a",
     "22" = "d", "6"  = "b"))
-  scale_train(s, c("4", "6", "8"))
-  expect_equal(scale_map(s, c("4", "6", "8")), c("a", "b", "c"))
+  s$train(c("4", "6", "8"))
+  expect_equal(s$map(c("4", "6", "8")), c("a", "b", "c"))
 })
 
diff --git a/tests/testthat/test-scales-breaks-labels.r b/tests/testthat/test-scales-breaks-labels.r
new file mode 100644
index 0000000..5e0c21e
--- /dev/null
+++ b/tests/testthat/test-scales-breaks-labels.r
@@ -0,0 +1,257 @@
+context("Scales: breaks and labels")
+
+test_that("labels match breaks, even when outside limits", {
+  sc <- scale_y_continuous(breaks = 1:4, labels = 1:4, limits = c(1, 3))
+
+  expect_equal(sc$get_breaks(), c(1:3, NA))
+  expect_equal(sc$get_labels(), 1:4)
+  expect_equal(sc$get_breaks_minor(), c(1, 1.5, 2, 2.5, 3))
+})
+
+test_that("labels must match breaks", {
+  expect_error(scale_x_discrete(breaks = 1:3, labels = 1:2),
+    "must have the same length")
+  expect_error(scale_x_continuous(breaks = 1:3, labels = 1:2),
+    "must have the same length")
+})
+
+test_that("labels don't have to match null breaks", {
+  expect_true(check_breaks_labels(breaks = 1:3, labels = NULL))
+  expect_true(check_breaks_labels(breaks = NULL, labels = 1:2))
+})
+
+
+test_that("labels don't have extra spaces", {
+  labels <- c("a", "abc", "abcdef")
+
+  sc1 <- scale_x_discrete(limits = labels)
+  sc2 <- scale_fill_discrete(limits = labels)
+
+  expect_equal(sc1$get_labels(), labels)
+  expect_equal(sc2$get_labels(), labels)
+
+})
+
+
+test_that("out-of-range breaks are dropped", {
+  # Limits are explicitly specified, automatic labels
+  sc <- scale_x_continuous(breaks = 1:5, limits = c(2, 4))
+  bi <- sc$break_info()
+  expect_equal(bi$labels, as.character(2:4))
+  expect_equal(bi$major, c(0, 0.5, 1))
+  expect_equal(bi$major_source, 2:4)
+
+
+  # Limits and labels are explicitly specified
+  sc <- scale_x_continuous(breaks = 1:5, labels = letters[1:5], limits = c(2, 4))
+  bi <- sc$break_info()
+  expect_equal(bi$labels, letters[2:4])
+  expect_equal(bi$major, c(0, 0.5, 1))
+  expect_equal(bi$major_source, 2:4)
+
+
+  # Limits are specified, and all breaks are out of range
+  sc <- scale_x_continuous(breaks = c(1,5), labels = letters[c(1,5)], limits = c(2, 4))
+  bi <- sc$break_info()
+  expect_equal(length(bi$labels), 0)
+  expect_equal(length(bi$major), 0)
+  expect_equal(length(bi$major_source), 0)
+
+
+  # limits aren't specified, automatic labels
+  # limits are set by the data
+  sc <- scale_x_continuous(breaks = 1:5)
+  sc$train_df(data.frame(x = 2:4))
+  bi <- sc$break_info()
+  expect_equal(bi$labels, as.character(2:4))
+  expect_equal(bi$major_source, 2:4)
+  expect_equal(bi$major, c(0, 0.5, 1))
+
+
+  # Limits and labels are specified
+  sc <- scale_x_continuous(breaks = 1:5, labels = letters[1:5])
+  sc$train_df(data.frame(x = 2:4))
+  bi <- sc$break_info()
+  expect_equal(bi$labels, letters[2:4])
+  expect_equal(bi$major_source, 2:4)
+  expect_equal(bi$major, c(0, 0.5, 1))
+
+
+  # Limits aren't specified, and all breaks are out of range of data
+  sc <- scale_x_continuous(breaks = c(1,5), labels = letters[c(1,5)])
+  sc$train_df(data.frame(x = 2:4))
+  bi <- sc$break_info()
+  expect_equal(length(bi$labels), 0)
+  expect_equal(length(bi$major), 0)
+  expect_equal(length(bi$major_source), 0)
+})
+
+
+test_that("no minor breaks when only one break", {
+  sc1 <- scale_x_discrete(limits = "a")
+  sc2 <- scale_x_continuous(limits = 1)
+
+  expect_equal(length(sc1$get_breaks_minor()), 0)
+  expect_equal(length(sc2$get_breaks_minor()), 0)
+
+})
+
+init_scale <- function(...) {
+  sc <- scale_x_discrete(...)
+  sc$train(factor(1:100))
+  expect_equal(length(sc$get_limits()), 100)
+  sc
+}
+
+test_that("discrete labels match breaks", {
+
+  sc <- init_scale(breaks = 0:5 * 10)
+  expect_equal(length(sc$get_breaks()), 5)
+  expect_equal(length(sc$get_labels()), 5)
+  expect_equivalent(sc$get_labels(), sc$get_breaks())
+
+  sc <- init_scale(breaks = 0:5 * 10, labels = letters[1:6])
+  expect_equal(length(sc$get_breaks()), 5)
+  expect_equal(length(sc$get_labels()), 5)
+  expect_equal(sc$get_labels(), letters[2:6])
+
+  sc <- init_scale(breaks = 0:5 * 10, labels =
+    function(x) paste(x, "-", sep = ""))
+  expect_equal(sc$get_labels(), c("10-", "20-", "30-", "40-", "50-"))
+
+  pick_5 <- function(x) sample(x, 5)
+  sc <- init_scale(breaks = pick_5)
+  expect_equal(length(sc$get_breaks()), 5)
+  expect_equal(length(sc$get_labels()), 5)
+
+})
+
+
+test_that("scale breaks with numeric log transformation", {
+  sc <- scale_x_continuous(limits = c(1, 1e5), trans = log10_trans())
+  expect_equal(sc$get_breaks(), c(0, 2, 4)) # 1, 100, 10000
+  expect_equal(sc$get_breaks_minor(), c(0, 1, 2, 3, 4, 5))
+})
+
+test_that("continuous scales with no data have no breaks or labels", {
+  sc <- scale_x_continuous()
+
+  expect_equal(sc$get_breaks(), numeric())
+  expect_equal(sc$get_labels(), character())
+  expect_equal(sc$get_limits(), c(0, 1))
+
+})
+
+test_that("discrete scales with no data have no breaks or labels", {
+  sc <- scale_x_discrete()
+
+  expect_equal(sc$get_breaks(), numeric())
+  expect_equal(sc$get_labels(), character())
+  expect_equal(sc$get_limits(), c(0, 1))
+})
+
+test_that("suppressing breaks, minor_breask, and labels", {
+  expect_equal(scale_x_continuous(breaks = NULL, limits = c(1, 3))$get_breaks(), NULL)
+  expect_equal(scale_x_discrete(breaks = NULL, limits = c(1, 3))$get_breaks(), NULL)
+  expect_equal(scale_x_continuous(minor_breaks = NULL, limits = c(1, 3))$get_breaks_minor(), NULL)
+
+  expect_equal(scale_x_continuous(labels = NULL, limits = c(1, 3))$get_labels(), NULL)
+  expect_equal(scale_x_discrete(labels = NULL, limits = c(1, 3))$get_labels(), NULL)
+
+  # date, datetime
+  lims <- as.Date(c("2000/1/1", "2000/2/1"))
+  expect_equal(scale_x_date(breaks = NULL, limits = lims)$get_breaks(), NULL)
+  # NA is defunct, should throw error
+  expect_error(scale_x_date(breaks = NA, limits = lims)$get_breaks())
+  expect_equal(scale_x_date(labels = NULL, limits = lims)$get_labels(), NULL)
+  expect_error(scale_x_date(labels = NA, limits = lims)$get_labels())
+  expect_equal(scale_x_date(minor_breaks = NULL, limits = lims)$get_breaks_minor(), NULL)
+  expect_error(scale_x_date(minor_breaks = NA, limits = lims)$get_breaks_minor())
+
+  # date, datetime
+  lims <- as.POSIXct(c("2000/1/1 0:0:0", "2010/1/1 0:0:0"))
+  expect_equal(scale_x_datetime(breaks = NULL, limits = lims)$get_breaks(), NULL)
+  expect_error(scale_x_datetime(breaks = NA, limits = lims)$get_breaks())
+  expect_equal(scale_x_datetime(labels = NULL, limits = lims)$get_labels(), NULL)
+  expect_error(scale_x_datetime(labels = NA, limits = lims)$get_labels())
+  expect_equal(scale_x_datetime(minor_breaks = NULL, limits = lims)$get_breaks_minor(), NULL)
+  expect_error(scale_x_datetime(minor_breaks = NA, limits = lims)$get_breaks_minor())
+
+})
+
+test_that("scale_breaks with explicit NA options (deprecated)", {
+  # NA is defunct, should throw error
+
+  # X
+  sxc <- scale_x_continuous(breaks = NA)
+  sxc$train(1:3)
+  expect_error(sxc$get_breaks())
+  expect_error(sxc$get_breaks_minor())
+
+  # Y
+  syc <- scale_y_continuous(breaks = NA)
+  syc$train(1:3)
+  expect_error(syc$get_breaks())
+  expect_error(syc$get_breaks_minor())
+
+  # Alpha
+  sac <- scale_alpha_continuous(breaks = NA)
+  sac$train(1:3)
+  expect_error(sac$get_breaks())
+
+  # Size
+  ssc <- scale_size_continuous(breaks = NA)
+  ssc$train(1:3)
+  expect_error(ssc$get_breaks())
+
+  # Fill
+  sfc <- scale_fill_continuous(breaks = NA)
+  sfc$train(1:3)
+  expect_error(sfc$get_breaks())
+
+  # Colour
+  scc <- scale_colour_continuous(breaks = NA)
+  scc$train(1:3)
+  expect_error(scc$get_breaks())
+
+})
+
+
+test_that("breaks can be specified by names of labels", {
+  labels <- setNames(LETTERS[1:4], letters[1:4])
+
+  s <- scale_x_discrete(limits = letters[1:4], labels = labels)
+  expect_equal(as.vector(s$get_breaks()), letters[1:4])
+  expect_equal(as.vector(s$get_labels()), LETTERS[1:4])
+
+  s <- scale_x_discrete(limits = letters[1:4], labels = rev(labels))
+  expect_equal(as.vector(s$get_breaks()), letters[1:4])
+  expect_equal(as.vector(s$get_labels()), LETTERS[1:4])
+
+  s <- scale_x_discrete(limits = letters[1:4], labels = labels[1:2])
+  expect_equal(as.vector(s$get_breaks()), letters[1:4])
+  expect_equal(as.vector(s$get_labels()), c("A", "B", "c", "d"))
+
+  s <- scale_x_discrete(limits = letters[1:4], labels = labels[3:4])
+  expect_equal(as.vector(s$get_breaks()), letters[1:4])
+  expect_equal(as.vector(s$get_labels()), c("a", "b", "C", "D"))
+
+  s <- scale_x_discrete(limits = letters[1:3], labels = labels)
+  expect_equal(as.vector(s$get_breaks()), letters[1:3])
+  expect_equal(as.vector(s$get_labels()), LETTERS[1:3])
+
+})
+
+test_that("only finite or NA values for breaks for transformed scales (#871)", {
+  sc <- scale_y_continuous(limits = c(0.01, 0.99), trans = "probit",
+                           breaks = seq(0, 1, 0.2))
+  breaks <- sc$get_breaks()
+  expect_true(all(is.finite(breaks) | is.na(breaks)))
+})
+
+test_that("minor breaks are transformed by scales", {
+  sc <- scale_y_continuous(limits = c(1, 100), trans = "log10",
+    minor_breaks = c(1, 10, 100))
+
+  expect_equal(sc$get_breaks_minor(), c(0, 1, 2))
+})
diff --git a/inst/tests/test-scales.r b/tests/testthat/test-scales.r
similarity index 77%
rename from inst/tests/test-scales.r
rename to tests/testthat/test-scales.r
index fece760..5a205b0 100644
--- a/inst/tests/test-scales.r
+++ b/tests/testthat/test-scales.r
@@ -13,32 +13,33 @@ test_that("buidling a plot does not affect its scales", {
 test_that("ranges update only for variables listed in aesthetics", {
   sc <- scale_alpha()
 
-  scale_train_df(sc, data.frame(alpha = 1:10))
+  sc$train_df(data.frame(alpha = 1:10))
   expect_equal(sc$range$range, c(1, 10))
 
-  scale_train_df(sc, data.frame(alpha = 50))
+  sc$train_df(data.frame(alpha = 50))
   expect_equal(sc$range$range, c(1, 50))
 
-  scale_train_df(sc, data.frame(beta = 100))
+  sc$train_df(data.frame(beta = 100))
   expect_equal(sc$range$range, c(1, 50))
 
-  scale_train_df(sc, data.frame())
+  sc$train_df(data.frame())
   expect_equal(sc$range$range, c(1, 50))
 
 })
 
 test_that("mapping works", {
   sc <- scale_alpha(range = c(0, 1), na.value = 0)
-  scale_train_df(sc, data.frame(alpha = 1:10))
+  sc$train_df(data.frame(alpha = 1:10))
 
   expect_equal(
-    scale_map_df(sc, data.frame(alpha = 1:10))[[1]],
-    round_any(seq(0, 1, length = 10), 1 / 500))
+    sc$map_df(data.frame(alpha = 1:10))[[1]],
+    seq(0, 1, length.out = 10)
+  )
 
-  expect_equal(scale_map_df(sc, data.frame(alpha = NA))[[1]], 0)
+  expect_equal(sc$map_df(data.frame(alpha = NA))[[1]], 0)
 
   expect_equal(
-    scale_map_df(sc, data.frame(alpha = c(-10, 11)))[[1]],
+    sc$map_df(data.frame(alpha = c(-10, 11)))[[1]],
     c(0, 0))
 })
 
@@ -53,15 +54,13 @@ test_that("identity scale preserves input values", {
     scale_shape_identity() +
     scale_size_identity() +
     scale_alpha_identity()
-  d1 <- pdata(p1)[[1]]
-
-  expect_that(d1$colour, equals(as.character(df$z)))
-  expect_that(d1$fill, equals(as.character(df$z)))
-  expect_that(d1$shape, equals(as.character(df$z)))
-  expect_that(d1$size, equals(as.numeric(df$z)))
-  expect_that(d1$alpha, equals(as.numeric(df$z)))
-
+  d1 <- layer_data(p1)
 
+  expect_equal(d1$colour, as.character(df$z))
+  expect_equal(d1$fill, as.character(df$z))
+  expect_equal(d1$shape, as.character(df$z))
+  expect_equal(d1$size, as.numeric(df$z))
+  expect_equal(d1$alpha, as.numeric(df$z))
 })
 
 test_that("position scales updated by all position aesthetics", {
@@ -79,8 +78,8 @@ test_that("position scales updated by all position aesthetics", {
   ranges <- lapply(plots, pranges)
 
   lapply(ranges, function(range) {
-    expect_that(range$x[[1]], equals(c(1, 3)))
-    expect_that(range$y[[1]], equals(c(1, 3)))
+    expect_equal(range$x[[1]], c(1, 3))
+    expect_equal(range$y[[1]], c(1, 3))
   })
 
 })
@@ -90,21 +89,21 @@ test_that("position scales generate after stats", {
   plot <- ggplot(df, aes(x)) + geom_bar()
   ranges <- pranges(plot)
 
-  expect_that(ranges$x[[1]], equals(c("1")))
-  expect_that(ranges$y[[1]], equals(c(0, 3)))
+  expect_equal(ranges$x[[1]], c("1"))
+  expect_equal(ranges$y[[1]], c(0, 3))
 
 })
 
 test_that("oob affects position values", {
-  dat <- data.frame(x=c("a", "b", "c"), y=c(1, 5, 10))
-  base <- ggplot(dat, aes(x=x, y=y)) +
-    geom_bar(stat="identity") +
+  dat <- data.frame(x = c("a", "b", "c"), y = c(1, 5, 10))
+  base <- ggplot(dat, aes(x, y)) +
+    geom_bar(stat = "identity") +
     annotate("point", x = "a", y = c(-Inf, Inf))
 
   y_scale <- function(limits, oob = censor) {
     scale_y_continuous(limits = limits, oob = oob, expand = c(0, 0))
   }
-  base + scale_y_continuous(limits=c(-0,5))
+  base + scale_y_continuous(limits = c(-0,5))
 
   expect_warning(low_censor <- cdata(base + y_scale(c(0, 5), censor)),
     "Removed 1 rows containing missing values")
@@ -147,7 +146,7 @@ test_that("scales looked for in appropriate place", {
 
   rm(scale_x_continuous)
   p4 <- qplot(mpg, wt, data = mtcars)
-  expect_equal(xlabel(p4), NULL)
+  expect_equal(xlabel(p4), waiver())
 })
 
 test_that("find_global searches in the right places", {
diff --git a/tests/testthat/test-stat-bin.R b/tests/testthat/test-stat-bin.R
new file mode 100644
index 0000000..7990101
--- /dev/null
+++ b/tests/testthat/test-stat-bin.R
@@ -0,0 +1,41 @@
+context("stat_bin/stat_count")
+
+test_that("stat_bin throws error when y aesthetic present", {
+  dat <- data.frame(x = c("a", "b", "c"), y = c(1, 5, 10))
+
+  expect_error(ggplot_build(ggplot(dat, aes(x, y)) + stat_bin()),
+    "must not be used with a y aesthetic.")
+
+  expect_error(p <- ggplot_build(ggplot(dat, aes(x)) + stat_bin(y = 5)),
+    "Unknown parameters: y")
+})
+
+test_that("stat_count throws error when y aesthetic present", {
+  dat <- data.frame(x = c("a", "b", "c"), y = c(1, 5, 10))
+
+  expect_error(ggplot_build(ggplot(dat, aes(x, y)) + stat_count()),
+    "must not be used with a y aesthetic.")
+
+  expect_error(p <- ggplot_build(ggplot(dat, aes(x)) + stat_count(y = 5)),
+    "Unknown parameters: y")
+})
+
+test_that("stat_count preserves x order for continuous and discrete", {
+  # x is numeric
+  b <- ggplot_build(ggplot(mtcars, aes(carb)) + geom_bar())
+  expect_identical(b$data[[1]]$x, c(1,2,3,4,6,8))
+  expect_identical(b$data[[1]]$y, c(7,10,3,10,1,1))
+
+  # x is factor where levels match numeric order
+  mtcars$carb2 <- factor(mtcars$carb)
+  b <- ggplot_build(ggplot(mtcars, aes(carb2)) + geom_bar())
+  expect_identical(b$data[[1]]$x, 1:6)
+  expect_identical(b$data[[1]]$y, c(7,10,3,10,1,1))
+
+  # x is factor levels differ from numeric order
+  mtcars$carb3 <- factor(mtcars$carb, levels = c(4,1,2,3,6,8))
+  b <- ggplot_build(ggplot(mtcars, aes(carb3)) + geom_bar())
+  expect_identical(b$data[[1]]$x, 1:6)
+  expect_identical(b$panel$ranges[[1]]$x.labels, c("4","1","2","3","6","8"))
+  expect_identical(b$data[[1]]$y, c(10,7,10,3,1,1))
+})
diff --git a/tests/testthat/test-stat-bin2d.R b/tests/testthat/test-stat-bin2d.R
new file mode 100644
index 0000000..7c80974
--- /dev/null
+++ b/tests/testthat/test-stat-bin2d.R
@@ -0,0 +1,31 @@
+context("stat_bin2d")
+
+test_that("binwidth is respected", {
+  df <- data.frame(x = c(1, 1, 1, 2), y = c(1, 1, 1, 2))
+  base <- ggplot(df, aes(x, y)) +
+    stat_bin2d(geom = "tile", binwidth = 0.25)
+
+  out <- layer_data(base)
+  expect_equal(nrow(out), 2)
+  # Adjust tolerance to account for fuzzy breaks adjustment
+  expect_equal(out$xmin, c(1, 1.75), tol = 1e-7)
+  expect_equal(out$xmax, c(1.25, 2), tol = 1e-7)
+})
+
+test_that("breaks override binwidth", {
+  # Test explicitly setting the breaks for x, overriding
+  # the binwidth.
+  integer_breaks <- (0:4) - 0.5  # Will use for x
+  half_breaks <- seq(0, 3.5, 0.5)  # Will test against this for y
+
+  df <- data.frame(x = 0:3, y = 0:3)
+  base <- ggplot(df, aes(x, y)) +
+    stat_bin2d(
+      breaks = list(x = integer_breaks, y = NULL),
+      binwidth = c(0.5, 0.5)
+    )
+
+  out <- layer_data(base)
+  expect_equal(out$xbin, cut(df$x, adjust_breaks(integer_breaks), include.lowest = TRUE, labels = FALSE))
+  expect_equal(out$ybin, cut(df$y, adjust_breaks(half_breaks), include.lowest = TRUE, labels = FALSE))
+})
diff --git a/tests/testthat/test-stat-density.R b/tests/testthat/test-stat-density.R
new file mode 100644
index 0000000..13847d2
--- /dev/null
+++ b/tests/testthat/test-stat-density.R
@@ -0,0 +1,13 @@
+context("stat_density") # and stat_ydensity
+
+test_that("compute_density succeeds when variance is zero", {
+  dens <- compute_density(rep(0, 10), NULL, from = 0.5, to = 0.5)
+  expect_equal(dens$n, rep(10, 512))
+})
+
+test_that("compute_density returns useful df when <3 values", {
+  dens <- compute_density(c(1, 2), NULL, from = 0, to = 0)
+
+  expect_equal(nrow(dens), 2)
+  expect_equal(names(dens), c("x", "density", "scaled", "count", "n"))
+})
diff --git a/tests/testthat/test-stat-density2d.R b/tests/testthat/test-stat-density2d.R
new file mode 100644
index 0000000..2eb8b35
--- /dev/null
+++ b/tests/testthat/test-stat-density2d.R
@@ -0,0 +1,17 @@
+context("stat_density_2d")
+
+test_that("uses scale limits, not data limits", {
+  base <- ggplot(mtcars, aes(wt, mpg)) +
+    stat_density_2d() +
+    scale_x_continuous(limits = c(1, 6)) +
+    scale_y_continuous(limits = c(5, 40))
+
+  ret <- layer_data(base)
+  # Check that the contour data goes beyond data range.
+  # The specific values below are sort of arbitrary; but they go beyond the range
+  # of the data
+  expect_true(min(ret$x) < 1.2)
+  expect_true(max(ret$x) > 5.8)
+  expect_true(min(ret$y) < 8)
+  expect_true(max(ret$y) > 35)
+})
diff --git a/tests/testthat/test-stat-sum.R b/tests/testthat/test-stat-sum.R
new file mode 100644
index 0000000..4150a10
--- /dev/null
+++ b/tests/testthat/test-stat-sum.R
@@ -0,0 +1,43 @@
+context("stat_sum")
+
+test_that("handles grouping correctly", {
+  d <- diamonds[1:1000, ]
+  all_ones <- function(x) all.equal(mean(x), 1)
+
+  base <- ggplot(d, aes(cut, clarity))
+
+  ret <- layer_data(base + stat_sum())
+  expect_equal(nrow(ret), 38)
+  expect_equal(sum(ret$n), nrow(d))
+  expect_true(all_ones(ret$prop))
+
+  ret <- layer_data(base + stat_sum(aes(group = 1)))
+  expect_equal(nrow(ret), 38)
+  expect_equal(sum(ret$n), nrow(d))
+  expect_equal(sum(ret$prop), 1)
+
+  ret <- layer_data(base + stat_sum(aes(group = cut)))
+  expect_equal(nrow(ret), 38)
+  expect_equal(sum(ret$n), nrow(d))
+  expect_true(all_ones(tapply(ret$prop, ret$x, FUN = sum)))
+
+  ret <- layer_data(base + stat_sum(aes(group = cut, colour = cut)))
+  expect_equal(nrow(ret), 38)
+  expect_equal(sum(ret$n), nrow(d))
+  expect_true(all_ones(tapply(ret$prop, ret$x, FUN = sum)))
+
+  ret <- layer_data(base + stat_sum(aes(group = clarity)))
+  expect_equal(nrow(ret), 38)
+  expect_equal(sum(ret$n), nrow(d))
+  expect_true(all_ones(tapply(ret$prop, ret$y, FUN = sum)))
+
+  ret <- layer_data(base + stat_sum(aes(group = clarity, colour = cut)))
+  expect_equal(nrow(ret), 38)
+  expect_equal(sum(ret$n), nrow(d))
+  expect_true(all_ones(tapply(ret$prop, ret$y, FUN = sum)))
+
+  ret <- layer_data(base + stat_sum(aes(group = 1, weight = price)))
+  expect_equal(nrow(ret), 38)
+  expect_equal(sum(ret$n), sum(d$price))
+  expect_equal(sum(ret$prop), 1)
+})
diff --git a/tests/testthat/test-stats-function.r b/tests/testthat/test-stats-function.r
new file mode 100644
index 0000000..47cb02a
--- /dev/null
+++ b/tests/testthat/test-stats-function.r
@@ -0,0 +1,25 @@
+context("stat_function")
+
+test_that("uses scale limits, not data limits", {
+  dat <- data.frame(x = c(0.1, 1:100))
+  dat$y <- dexp(dat$x)
+
+  base <- ggplot(dat, aes(x, y)) +
+    stat_function(fun = dexp)
+
+  full <- base +
+    scale_x_continuous(limits = c(0.1, 100)) +
+    scale_y_continuous()
+  ret <- layer_data(full)
+
+  full_log <- base +
+    scale_x_log10(limits = c(0.1, 100)) +
+    scale_y_continuous()
+  ret_log <- layer_data(full_log)
+
+  expect_equal(ret$y[c(1, 101)], ret_log$y[c(1, 101)])
+  expect_equal(range(ret$x), c(0.1, 100))
+  expect_equal(range(ret_log$x), c(-1, 2))
+  expect_false(any(is.na(ret$y)))
+  expect_false(any(is.na(ret_log$y)))
+})
diff --git a/tests/testthat/test-stats.r b/tests/testthat/test-stats.r
new file mode 100644
index 0000000..3de4e17
--- /dev/null
+++ b/tests/testthat/test-stats.r
@@ -0,0 +1,13 @@
+context("Stats")
+
+test_that("plot succeeds even if some computation fails", {
+  df <- data.frame(x = 1:2, y = 1)
+  p1 <- ggplot(df, aes(x, y)) + geom_point()
+
+  b1 <- ggplot_build(p1)
+  expect_equal(length(b1$data), 1)
+
+  p2 <- p1 + geom_smooth()
+  expect_warning(b2 <- ggplot_build(p2), "Computation failed")
+  expect_equal(length(b2$data), 2)
+})
diff --git a/inst/tests/test-theme.r b/tests/testthat/test-theme.r
similarity index 66%
rename from inst/tests/test-theme.r
rename to tests/testthat/test-theme.r
index 8d1cb2d..e3aac62 100644
--- a/inst/tests/test-theme.r
+++ b/tests/testthat/test-theme.r
@@ -1,9 +1,10 @@
 context("Themes")
 
 test_that("Modifying theme element properties with + operator", {
+
   # Changing a "leaf node" works
-  t <- theme_grey() + theme(axis.title.x = element_text(colour='red'))
-  expect_identical(t$axis.title.x, element_text(colour='red'))
+  t <- theme_grey() + theme(axis.title.x = element_text(colour = 'red', margin = margin()))
+  expect_identical(t$axis.title.x, element_text(colour = 'red', margin = margin()))
   # Make sure the theme class didn't change or get dropped
   expect_true(is.theme(t))
   # Make sure the element class didn't change or get dropped
@@ -11,11 +12,11 @@ test_that("Modifying theme element properties with + operator", {
   expect_true(inherits(t$axis.title.x, "element_text"))
 
   # Modifying an intermediate node works
-  t <- theme_grey() + theme(axis.title = element_text(colour='red'))
-  expect_identical(t$axis.title, element_text(colour='red'))
+  t <- theme_grey() + theme(axis.title = element_text(colour = 'red'))
+  expect_identical(t$axis.title, element_text(colour = 'red'))
 
   # Modifying a root node changes only the specified properties
-  t <- theme_grey() + theme(text = element_text(colour='red'))
+  t <- theme_grey() + theme(text = element_text(colour = 'red'))
   expect_identical(t$text$colour, 'red')
   expect_identical(t$text$family, theme_grey()$text$family)
   expect_identical(t$text$face,   theme_grey()$text$face)
@@ -28,8 +29,8 @@ test_that("Modifying theme element properties with + operator", {
   expect_identical(t$axis.text.y, element_blank())
 
   # Adding a non-blank element to an element_blank() replaces it
-  t <- t + theme(axis.text.y = element_text(colour='red'))
-  expect_identical(t$axis.text.y, element_text(colour='red'))
+  t <- t + theme(axis.text.y = element_text(colour = 'red'))
+  expect_identical(t$axis.text.y, element_text(colour = 'red'))
 
   # Adding empty theme() has no effect
   t <- theme_grey() + theme()
@@ -46,7 +47,7 @@ test_that("Adding theme object to ggplot object with + operator", {
   expect_true(p$theme$axis.title$size == 20)
 
   # Should update specified properties, but not reset other properties
-  p <- p + theme(text = element_text(colour='red'))
+  p <- p + theme(text = element_text(colour = 'red'))
   expect_true(p$theme$text$colour == 'red')
   tt <- theme_grey()$text
   tt$colour <- 'red'
@@ -57,14 +58,14 @@ test_that("Adding theme object to ggplot object with + operator", {
 
 test_that("Replacing theme elements with %+replace% operator", {
   # Changing a "leaf node" works
-  t <- theme_grey() %+replace% theme(axis.title.x = element_text(colour='red'))
-  expect_identical(t$axis.title.x, element_text(colour='red'))
+  t <- theme_grey() %+replace% theme(axis.title.x = element_text(colour = 'red'))
+  expect_identical(t$axis.title.x, element_text(colour = 'red'))
   # Make sure the class didn't change or get dropped
   expect_true(is.theme(t))
 
   # Changing an intermediate node works
-  t <- theme_grey() %+replace% theme(axis.title = element_text(colour='red'))
-  expect_identical(t$axis.title, element_text(colour='red'))
+  t <- theme_grey() %+replace% theme(axis.title = element_text(colour = 'red'))
+  expect_identical(t$axis.title, element_text(colour = 'red'))
   # Descendent is unchanged
   expect_identical(t$axis.title.x, theme_grey()$axis.title.x)
 
@@ -77,7 +78,7 @@ test_that("Replacing theme elements with %+replace% operator", {
 
 
 test_that("Calculating theme element inheritance", {
-  t <- theme_grey() + theme(axis.title = element_text(colour='red'))
+  t <- theme_grey() + theme(axis.title = element_text(colour = 'red'))
 
   # Check that properties are passed along from axis.title to axis.title.x
   e <- calc_element('axis.title.x', t)
@@ -88,9 +89,9 @@ test_that("Calculating theme element inheritance", {
 
 
   # Check that rel() works for relative sizing, and is applied at each level
-  t <- theme_grey(base_size=12) +
-    theme(axis.title   = element_text(size=rel(0.5))) +
-    theme(axis.title.x = element_text(size=rel(0.5)))
+  t <- theme_grey(base_size = 12) +
+    theme(axis.title   = element_text(size = rel(0.5))) +
+    theme(axis.title.x = element_text(size = rel(0.5)))
   e <- calc_element('axis.title', t)
   expect_identical(e$size, 6)
   ex <- calc_element('axis.title.x', t)
@@ -107,18 +108,18 @@ test_that("Complete and non-complete themes interact correctly with each other",
   # The 'complete' attribute of t1 + t2 is the OR of their 'complete' attributes.
 
   # But for _element properties_, the one on the right modifies the one on the left.
-  t <- theme_bw() + theme(text = element_text(colour='red'))
+  t <- theme_bw() + theme(text = element_text(colour = 'red'))
   expect_true(attr(t, "complete"))
   expect_equal(t$text$colour, 'red')
 
   # A complete theme object (like theme_bw) always trumps a non-complete theme object
-  t <- theme(text = element_text(colour='red')) + theme_bw()
+  t <- theme(text = element_text(colour = 'red')) + theme_bw()
   expect_true(attr(t, "complete"))
   expect_equal(t$text$colour, theme_bw()$text$colour)
 
   # Adding two non-complete themes: the one on the right modifies the one on the left.
-  t <- theme(text = element_text(colour='blue')) +
-    theme(text = element_text(colour='red'))
+  t <- theme(text = element_text(colour = 'blue')) +
+    theme(text = element_text(colour = 'red'))
   expect_false(attr(t, "complete"))
   expect_equal(t$text$colour, 'red')
 })
@@ -127,35 +128,36 @@ test_that("Complete and non-complete themes interact correctly with each other",
 test_that("Complete and non-complete themes interact correctly with ggplot objects", {
   # Check that adding two theme successive theme objects to a ggplot object
   # works like adding the two theme object to each other
-  p <- ggplot_build(qplot(1:3, 1:3) + theme_bw() + theme(text=element_text(colour='red')))
+  p <- ggplot_build(qplot(1:3, 1:3) + theme_bw() + theme(text = element_text(colour = 'red')))
   expect_true(attr(p$plot$theme, "complete"))
 
   # Compare the theme objects, after sorting the items, because item order can differ
   pt <- p$plot$theme
-  tt <- theme_bw() + theme(text=element_text(colour='red'))
+  tt <- theme_bw() + theme(text = element_text(colour = 'red'))
   pt <- pt[order(names(pt))]
   tt <- tt[order(names(tt))]
   expect_identical(pt, tt)
 
 
-  p <- ggplot_build(qplot(1:3, 1:3) + theme(text=element_text(colour='red')) + theme_bw())
+  p <- ggplot_build(qplot(1:3, 1:3) + theme(text = element_text(colour = 'red')) + theme_bw())
   expect_true(attr(p$plot$theme, "complete"))
   # Compare the theme objects, after sorting the items, because item order can differ
   pt <- p$plot$theme
-  tt <- theme(text=element_text(colour='red')) + theme_bw()
+  tt <- theme(text = element_text(colour = 'red')) + theme_bw()
   pt <- pt[order(names(pt))]
   tt <- tt[order(names(tt))]
   expect_identical(pt, tt)
 
 
-  p <- ggplot_build(qplot(1:3, 1:3) + theme(text=element_text(colour='red', face='italic')))
+  p <- ggplot_build(qplot(1:3, 1:3) + theme(text = element_text(colour = 'red', face = 'italic')))
   expect_false(attr(p$plot$theme, "complete"))
   expect_equal(p$plot$theme$text$colour, "red")
   expect_equal(p$plot$theme$text$face, "italic")
 
 
-  p <- ggplot_build(qplot(1:3, 1:3) + theme(text=element_text(colour='red')) +
-    theme(text=element_text(face='italic')))
+  p <- ggplot_build(qplot(1:3, 1:3) +
+    theme(text = element_text(colour = 'red')) +
+    theme(text = element_text(face = 'italic')))
   expect_false(attr(p$plot$theme, "complete"))
   expect_equal(p$plot$theme$text$colour, "red")
   expect_equal(p$plot$theme$text$face, "italic")
@@ -164,8 +166,25 @@ test_that("Complete and non-complete themes interact correctly with ggplot objec
   # Only gets red property; because of the way lists are processed in R, the
   # the second item doesn't get used properly. But I think that's OK.
   p <- ggplot_build(qplot(1:3, 1:3) +
-    theme(text=element_text(colour='red'), text=element_text(face='italic')))
+    theme(text = element_text(colour = 'red'), text = element_text(face = 'italic')))
   expect_false(attr(p$plot$theme, "complete"))
   expect_equal(p$plot$theme$text$colour, "red")
   expect_equal(p$plot$theme$text$face, "plain")
 })
+
+test_that("theme(validate=FALSE) means do not validate_element", {
+  p <- qplot(1:3, 1:3)
+  bw <- p + theme_bw()
+  red.text <- theme(text = element_text(colour = "red"))
+  bw.before <- bw + theme(animint.width = 500, validate = FALSE)
+  expect_equal(bw.before$theme$animint.width, 500)
+
+  bw.after <- p + theme(animint.width = 500, validate = FALSE) + theme_bw()
+  expect_null(bw.after$theme$animint.width)
+
+  red.after <- p + theme(animint.width = 500, validate = FALSE) + red.text
+  expect_equal(red.after$theme$animint.width, 500)
+
+  red.before <- p + red.text + theme(animint.width = 500, validate = FALSE)
+  expect_equal(red.before$theme$animint.width, 500)
+})
diff --git a/tests/testthat/test-utilities.r b/tests/testthat/test-utilities.r
new file mode 100644
index 0000000..9d4ecc4
--- /dev/null
+++ b/tests/testthat/test-utilities.r
@@ -0,0 +1,29 @@
+context("Utilities")
+
+test_that("finite.cases.data.frame", {
+  # All finite --------------------------------------------------------------
+  expect_identical(finite.cases(data.frame(x = 4)),              TRUE)          # 1x1
+  expect_identical(finite.cases(data.frame(x = 4, y = 11)),      TRUE)          # 1x2
+  expect_identical(finite.cases(data.frame(x = 4:5)),            c(TRUE, TRUE)) # 2x1
+  expect_identical(finite.cases(data.frame(x = 4:5, y = 11:12)), c(TRUE, TRUE)) # 2x2
+
+  # Has one NA --------------------------------------------------------------
+  expect_identical(finite.cases(data.frame(x = NA)),                      FALSE)           # 1x1
+  expect_identical(finite.cases(data.frame(x = 4, y = NA)),               FALSE)           # 1x2
+  expect_identical(finite.cases(data.frame(x = c(4, NA))),                c(TRUE,  FALSE)) # 2x1
+  expect_identical(finite.cases(data.frame(x = c(4, NA), y = c(11, NA))), c(TRUE,  FALSE)) # 2x2
+  expect_identical(finite.cases(data.frame(x = c(4, NA), y = c(NA, 12))), c(FALSE, FALSE)) # 2x2
+  expect_identical(finite.cases(data.frame(x = c(4, 5),  y = c(NA, 12))), c(FALSE, TRUE))  # 2x2
+
+  # Testing NaN and Inf, using miscellaneous data shapes --------------------
+  expect_identical(finite.cases(data.frame(x = c(4, NaN))),                c(TRUE, FALSE))
+  expect_identical(finite.cases(data.frame(x = Inf)),                      FALSE)
+  expect_identical(finite.cases(data.frame(x = c(4, 5), y = c(-Inf, 12))), c(FALSE, TRUE))
+})
+
+test_that("add_group", {
+  data <- data.frame(f=letters[7:9], x=1:3, y=4:6, group=c(1, -1, 1))
+  expect_true(has_groups(add_group(data[2:4])))  # explicit group column
+  expect_true(has_groups(add_group(data[1:3])))  # discrete column
+  expect_false(has_groups(add_group(data[2:3]))) # no group or discrete column
+})
diff --git a/vignettes/car.png b/vignettes/car.png
new file mode 100644
index 0000000..fbc5974
Binary files /dev/null and b/vignettes/car.png differ
diff --git a/vignettes/development.Rmd b/vignettes/development.Rmd
deleted file mode 100644
index 32ab363..0000000
--- a/vignettes/development.Rmd
+++ /dev/null
@@ -1,263 +0,0 @@
-<!--
-%\VignetteEngine{knitr::knitr}
-%\VignetteIndexEntry{Contributing to ggplot2 development}
--->
-
-```{r, echo = FALSE, message = FALSE}
-knitr::opts_chunk$set(
-  comment = "#>",
-  error = FALSE,
-  tidy = FALSE
-)
-```
-
-# Contributing to ggplot2 development
-
-The goal of this guide is to help you get up and contributing to ggplot2 as quickly as possible. It's still a work in progress and very rough. Your feedback is much appreciated and so are pull requests :).  Rather than emailing me directly about questions, please discuss ggplot2 development issues on the [ggplot2-dev](https://groups.google.com/forum/#!forum/ggplot2-dev) mailing list. That way multiple people can learn at the same time.
-
-To contribute a change to ggplot2, you follow these steps:
-
-1. Set up a local ggplot2 development environment.
-1. Create a branch in git and make your changes.
-1. Push branch to github and issue pull request (PR).
-1. Discuss the pull request.
-1. Iterate until either we accept the PR or decide that it's not
-   a good fit for ggplot2.
-
-Each of these steps are described in more detail below. This might feel overwhelming the first time you get set up, but it gets easier with practice. If you get stuck at any point, please reach out for help on the [ggplot2-dev](https://groups.google.com/forum/#!forum/ggplot2-dev) mailing list
-
-## Basic setup
-
-If you want to do development on ggplot2 and share the changes with other people, you'll have to set up an account on GitHub. You'll make a fork of Hadley's repository and store it on GitHub. You'll also make a copy of your repository on your local machine.
-
-1.  [Join github](https://github.com/join).
-
-1.  [Set up git and github](https://help.github.com/articles/set-up-git).
-
-1.  Fork of the main repo by going to https://github.com/hadley/ggplot2/fork.
-    A fork is a copy of ggplot2 that you can work on independently.
-    See [fork a repo](https://help.github.com/articles/fork-a-repo) for
-    more details.
-
-1.  Clone your fork to your local computer (change `myname` to your account
-    name):
-
-    ```
-    git clone git at github.com:myname/ggplot2.git
-    cd ggplot2
-    ```
-
-1.  Once you've done that, add the main repository as a remote and set up
-    the master branch to track the main ggplot2 repo. This will make it
-    easier to keep up to date.
-
-    ```
-    git remote add hadley git://github.com/hadley/ggplot2.git
-    git branch --set-upstream master hadley/master
-    ```
-
-Now on your local machine you have the local repository and two remote repositories: `origin` (the default), which is your personal ggplot2 repo at GitHub, and `hadley` which is Hadley's. You'll be able to push changes to your own repository only.
-
-### Development environment
-
-You'll also need a copy of the packages I use for package development. Get them by running the following R code:
-
-```{r, eval = FALSE}
-install.packages(c("devtools", "testthat"))
-devtools::install_github("klutometis/roxygen")
-```
-
-Next, install all the suggested packages that ggplot2 needs. To do this either open the ggplot2 rstudio project, or set your working directory to the ggplot2 directory, then run:
-
-```{r, eval = FALSE}
-install_deps(dep = T)
-```
-
-The key functions you'll use when working on ggplot2:
-
-* `devtools::load_all()`: loads all code into your current environment
-* `devtools::document()`: updates the roxygen comments
-* `devtools::test()`: run all unit tests
-* `devtools::check()`: runs R CMD check on the package to check for errors.
-
-If you're using Rstudio, I highly recommend learning the keyboard shortcuts for these commands. You can find them in the `Build` menu.
-
-## Making changes
-
-When you want to make changes, you should work on a new branch. Otherwise things can get a bit confusing when it comes time to merge it into the main repo with a pull request. You probably want to start with the `master` branch.
-
-```
-# Fetch the latest version of hadley/ggplot2
-git fetch hadley
-git checkout hadley/master
-```
-
-At this point it'll give you a warning about being in "detached HEAD" state. Don't worry about it. Just start a new branch with the current state as the starting point:
-
-```
-git checkout -b myfix
-```
-
-To check what branch you're currently on, run `git branch`.
-
-Now you can make your changes and commit them to this branch on your local repository. If you decide you want to start over, you can just check out `hadley/master` again, make a new branch, and begin anew.
-
-When you feel like sharing your changes, push them to your GitHub repo:
-
-```
-git push
-```
-
-Then you can submit a pull request if you want it to be integrated in the main branch.
-
-If you've been working on your for a while, it's possible that it won't merge properly because something has changed in both the main repo and in your branch. You can test it out by checking out the main branch and merging yourself.
-
-First, make a new branch called `testmerge`, based off the main branch:
-
-```
-git fetch hadley
-git checkout hadley/master
-
-git checkout -b testmerge
-```
-
-Then try merging your branch into testmerge:
-
-```
-git merge myfix
-```
-
-If there are no errors, great. You can switch back to your `myfix` branch and delete `testmerge`:
-
-```
-git checkout myfix
-git branch -D testmerge
-```
-
-If there are any merge conflicts, you may want to rebase your changes on top of the current master version, or just resolve the conflicts and commit it to your branch. Rebasing may make for a somewhat cleaner commit history, but there is a possibility of messing things up. If you want to be safe, you can just make a new branch and rebase that on top of the current master.
-
-## What makes a good pull request?
-
-<!--
-* [ ] Motivate the change in one paragraph, and include it in NEWS.
-      In parentheses, reference your github user name and this issue:
-      `(@hadley, #1234)`
-* [ ] Check pull request only includes relevant changes.
-* [ ] Use the [official style](http://adv-r.had.co.nz/Style.html).
-* [ ] Update documentation and re-run roxygen2
-* [ ] Add test, if bug in non-graphical function
-* [ ] Add visual test, if bug in graphical function
-* [ ] Add minimal example, if new graphical feature
-
-See http://docs.ggplot2.org/dev/vignettes/development.html for more details.
---->
-
-Pull requests will be evaluated against the a seven point checklist:
-
-1.  __Motivation__. Your pull request must clearly and concisely motivates the
-   need for change. Unfortunately neither Winston nor I have much time to
-   work on ggplot2 these days, so you need to describe the problem and show
-   how your pull request solves it as concisely as possible.
-
-   Also include this motivation in `NEWS` so that when a new release of
-   ggplot2 comes out it's easy for users to see what's changed. Add your
-   item at the top of the file and use markdown for formatting. The
-   news item should end with `(@yourGithubUsername, #the_issue_number)`.
-
-1.  __Only related changes__. Before you submit your pull request, please
-    check to make sure that you haven't accidentally included any unrelated
-    changes. These make it harder to see exactly what's changed, and to
-    evaluate any unexpected side effects.
-
-    Each PR corresponds to a git branch, so if you expect to submit
-    multiple changes make sure to create multiple branches. If you have
-    multiple changes that depend on each other, start with the first one
-    and don't submit any others until the first one has been processed.
-
-1.  __Use ggplot2 coding style__. Please follow the
-    [official ggplot2 style](http://adv-r.had.co.nz/Style.html). Maintaing
-    a consistent style across the whole code base makes it much easier to
-    jump into the code.
-
-1.  If you're adding new parameters or a new function, you'll also need
-    to document them with [roxygen](https://github.com/klutometis/roxygen).
-    Make sure to re-run `devtools::document()` on the code before submitting.
-
-    Currently, ggplot2 uses the development version of roxygen2, which you
-    can get with `install_github("klutometis/roxygen")`. This will be
-    available on CRAN in the near future.
-
-1.  If fixing a bug or adding a new feature to a non-graphical function,
-    please add a [testthat](https://github.com/hadley/testthat) unit test.
-
-1.  If fixing a bug in the visual output, please add a visual test.
-    (Instructions to follow soon)
-
-1.  If you're adding a new graphical feature, please add a short example
-    to the appropriate function.
-
-This seems like a lot of work but don't worry if your pull request isn't perfect. It's a learning process and Winston and I will be on hand to help you out. A pull request is a process, and unless you've submitted a few in the past it's unlikely that your pull request will be accepted as is.
-
-Finally, remember that ggplot2 is a mature package used by thousands of people. This means that it's extremely difficult (i.e. impossible) to change any existing functionality without breaking someone's code (or another package on CRAN). Please don't submit pull requests that change existing behaviour. Instead, think about how you can add a new feature in a minimally invasive way.
-
-## Advanced techniques
-
-### Fetching a branch from someone else's repository
-
-Sometimes you will want to fetch a branch from someone's repository, but without going to the trouble of seting it up as a remote. This is handy if you just want to quickly try out a someone's work.
-
-This will fetch a branch from someone's remote repository and check it out (replace `username` and `somebranch`):
-
-```
-git fetch https://github.com/username/ggplot2.git somebranch
-git checkout FETCH_HEAD
-```
-
-Just doing the above won't create a local branch -- you'll be in "detached HEAD" state. If you'd like to create a local branch to work on, run (you can replace `somebranch` with whatever name you like):
-
-```
-git checkout -b somebranch
-```
-
-### Adding other repositories as remotes
-
-If you often work off of someone else's repository, it can be useful to add their repo as a *remote*. This makes it easier to fetch changes in their repository. If the person's GitHub account is `otherdevel`, you would do the following:
-
-```
-git remote add otherdevel git://github.com/otherdevel/ggplot2.git
-git fetch otherdevel
-
-git checkout otherdevel/somebranch
-```
-
-If you don't want to follow them any more, run:
-
-```
-git remote rm otherdevel
-```
-
-### Delete a branch from GitHub
-
-If you pushed a branch to your GitHub repo but it's no longer needed there, you can remove it with:
-
-```
-git push origin :mybranch
-```
-
-### Visualizing the development tree
-
-GitHub has a very nice [development tree view](https://github.com/hadley/ggplot2/), but it of course only shows commits that have been pushed to GitHub. You may also want to view the tree on your local machine, to see how your local changes relate to the main tree. There are a number of programs out there that will do this.
-
-Mac:
-
-* gitk: Pretty basic, included with git. Run `gitk -a` to view all branches (by default it just shows you the current branch).
-
-* [gitx](http://gitx.laullon.com/): This is a bit nicer than gitk.
-
-* [SourceTree](http://www.sourcetreeapp.com/): This is also a nice program. Normally it costs money, but it is temporarily free from the web page or the [Mac App store](http://itunes.apple.com/us/app/sourcetree/id411678673?mt=12&ls=1).
-
-Linux:
-
-* gitk: (See gitk in Mac section)
-
-* gitg: This is nicer than gitk. By default it only shows the current branch; select "Local Branches" or "All Branches" to view others.
diff --git a/vignettes/extending-ggplot2.Rmd b/vignettes/extending-ggplot2.Rmd
new file mode 100644
index 0000000..5040814
--- /dev/null
+++ b/vignettes/extending-ggplot2.Rmd
@@ -0,0 +1,547 @@
+---
+title: "Extending ggplot2"
+author: "Hadley Wickham"
+date: "`r Sys.Date()`"
+output: rmarkdown::html_vignette
+vignette: >
+  %\VignetteIndexEntry{Extending ggplot2}
+  %\VignetteEngine{knitr::rmarkdown}
+  %\VignetteEncoding{UTF-8}
+---
+
+```{r, include = FALSE}
+knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
+library(ggplot2)
+```
+
+This vignette documents the official extension mechanism provided in ggplot2 1.1.0. This vignette is a high-level adjunct to the low-level details found in `?Stat`, `?Geom` and `?theme`. You'll learn how to extend ggplot2 by creating a new stat, geom, or theme.
+
+As you read this document, you'll see many things that will make you scratch your head and wonder why on earth is it designed this way? Mostly it's historical accident - I wasn't a terribly good R programmer when I started writing ggplot2 and I made a lot of questionable decisions. We cleaned up as many of those issues as possible in the 1.1.0 release, but some fixes simply weren't worth the effort.
+
+## ggproto
+
+All ggplot2 objects are built using the ggproto system of object oriented programming. This OO system is used only in one place: ggplot2. This is mostly historical accident: ggplot2 started off using [proto]( https://cran.r-project.org/package=proto) because I needed mutable objects. This was well before the creation of (the briefly lived) [mutatr](http://vita.had.co.nz/papers/mutatr.html), reference classes and R6: proto was the only game in town.
+
+But why ggproto? Well when we turned to add an official extension mechanism to ggplot2, we found a major problem that caused problems when proto objects were extended in a different package (methods were evaluated in ggplot2, not the package where the extension was added). We tried converting to R6, but it was a poor fit for the needs of ggplot2. We could've modified proto, but that would've first involved understand exactly how proto worked, and secondly making sure that the changes did [...]
+
+It's strange to say, but this is a case where inventing a new OO system was actually the right answer to the problem! Fortunately Winston is now very good at creating OO systems, so it only took him a day to come up with ggproto: it maintains all the features of proto that ggplot2 needs, while allowing cross package inheritance to work.
+
+Here's a quick demo of ggproto in action:
+
+```{r ggproto-intro}
+A <- ggproto("A", NULL,
+  x = 1,
+  inc = function(self) {
+    self$x <- self$x + 1
+  }
+)
+A$x
+A$inc()
+A$x
+A$inc()
+A$inc()
+A$x
+```
+
+The majority of ggplot2 classes are immutable and static: the methods neither use nor modify state in the class. They're mostly used as a convenient way of bundling related methods together.
+
+To create a new geom or stat, you will just create a new ggproto that inherits from `Stat`, `Geom` and override the methods described below.
+
+## Creating a new stat
+
+### The simplest stat
+
+We'll start by creating a very simple stat: one that gives the complex hull (the _c_ hull) of a set of points. First we create a new ggproto object that inherits from `Stat`:
+
+```{r chull}
+StatChull <- ggproto("StatChull", Stat,
+  compute_group = function(data, scales) {
+    data[chull(data$x, data$y), , drop = FALSE]
+  },
+  
+  required_aes = c("x", "y")
+)
+```
+
+The two most important components are the `compute_group()` method (which does the computation), and the `required_aes` field, which lists which aesthetics must be present in order to for the stat to work.
+
+Next we write a layer function. Unfortunately, due to an early design mistake I called these either `stat_()` or `geom_()`. A better decision would have been to call them `layer_()` functions: that's a more accurate description because every layer involves a stat _and_ a geom. 
+
+All layer functions follow the same form - you specify defaults in the function arguments and then call the `layer()` function, sending `...` into the `params` argument. The arguments in `...` will either be arguments for the geom (if you're making a stat wrapper), arguments for the stat (if you're making a geom wrapper), or aesthetics to be set. `layer()` takes care of teasing the different parameters apart and making sure they're stored in the right place:
+
+```{r}
+stat_chull <- function(mapping = NULL, data = NULL, geom = "polygon",
+                       position = "identity", na.rm = FALSE, show.legend = NA, 
+                       inherit.aes = TRUE, ...) {
+  layer(
+    stat = StatChull, data = data, mapping = mapping, geom = geom, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(na.rm = na.rm, ...)
+  )
+}
+```
+
+(Note that if you're writing this in your own package, you'll either need to call `ggplot2::layer()` explicitly, or import the `layer()` function into your package namespace.)
+
+Once we have a layer function we can try our new stat:
+
+```{r}
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_point() + 
+  stat_chull(fill = NA, colour = "black")
+```
+
+(We'll see later how to change the defaults of the geom so that you don't need to specify `fill = NA` every time.)
+
+Once we've written this basic object, ggplot2 gives a lot for free. For example, ggplot2 automatically preserves aesthetics that are constant within each group:
+
+```{r}
+ggplot(mpg, aes(displ, hwy, colour = drv)) + 
+  geom_point() + 
+  stat_chull(fill = NA)
+```
+
+We can also override the default geom to display the convex hull in a different way:
+
+```{r}
+ggplot(mpg, aes(displ, hwy)) + 
+  stat_chull(geom = "point", size = 4, colour = "red") +
+  geom_point()
+```
+
+### Stat parameters
+
+A more complex stat will do some computation. Let's implement a simple version of `geom_smooth()` that adds a line of best fit to a plot. We create a `StatLm` that inherits from `Stat` and a layer function, `stat_lm()`:
+
+```{r}
+StatLm <- ggproto("StatLm", Stat, 
+  required_aes = c("x", "y"),
+  
+  compute_group = function(data, scales) {
+    rng <- range(data$x, na.rm = TRUE)
+    grid <- data.frame(x = rng)
+    
+    mod <- lm(y ~ x, data = data)
+    grid$y <- predict(mod, newdata = grid)
+    
+    grid
+  }
+)
+
+stat_lm <- function(mapping = NULL, data = NULL, geom = "line",
+                    position = "identity", na.rm = FALSE, show.legend = NA, 
+                    inherit.aes = TRUE, ...) {
+  layer(
+    stat = StatLm, data = data, mapping = mapping, geom = geom, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_point() + 
+  stat_lm()
+```
+
+`StatLm` is inflexible because it has no parameters. We might want to allow the user to control the model formula and the number of points used to generate the grid. To do so, we add arguments to the `compute_group()` method and our wrapper function:
+
+```{r}
+StatLm <- ggproto("StatLm", Stat, 
+  required_aes = c("x", "y"),
+  
+  compute_group = function(data, scales, params, n = 100, formula = y ~ x) {
+    rng <- range(data$x, na.rm = TRUE)
+    grid <- data.frame(x = seq(rng[1], rng[2], length = n))
+    
+    mod <- lm(formula, data = data)
+    grid$y <- predict(mod, newdata = grid)
+    
+    grid
+  }
+)
+
+stat_lm <- function(mapping = NULL, data = NULL, geom = "line",
+                    position = "identity", na.rm = FALSE, show.legend = NA, 
+                    inherit.aes = TRUE, n = 50, formula = y ~ x, 
+                    ...) {
+  layer(
+    stat = StatLm, data = data, mapping = mapping, geom = geom, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(n = n, formula = formula, na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_point() + 
+  stat_lm(formula = y ~ poly(x, 10)) + 
+  stat_lm(formula = y ~ poly(x, 10), geom = "point", colour = "red", n = 20)
+```
+
+Note that don't _have_ to explicitly include the new parameters in the arguments for the layer, `...` will get passed to the right place anyway. But you'll need to document them somewhere so the user knows about them. Here's a brief example. Note `@inheritParams ggplot2::stat_identity`: that will automatically inherit documentation for all the parameters also defined for `stat_identity()`.
+
+```{r}
+#' @inheritParams ggplot2::stat_identity
+#' @param formula The modelling formula passed to \code{lm}. Should only 
+#'   involve \code{y} and \code{x}
+#' @param n Number of points used for interpolation.
+stat_lm <- function(mapping = NULL, data = NULL, geom = "line",
+                    position = "identity", na.rm = FALSE, show.legend = NA, 
+                    inherit.aes = TRUE, n = 50, formula = y ~ x, 
+                    ...) {
+  layer(
+    stat = StatLm, data = data, mapping = mapping, geom = geom, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(n = n, formula = formula, na.rm = na.rm, ...)
+  )
+}
+
+```
+
+### Picking defaults
+
+Sometimes you have calculations that should performed once for the complete dataset, not once for each group. This is useful for picking sensible default values. For example, if we want to do a density estimate, it's reasonable to pick one bandwidth for the whole plot. The following Stat creates a variation of the `stat_density()` that picks one bandwidth for all groups by choosing the mean of the "best" bandwidth for each group (I have no theoretical justification for this, but it doesn [...]
+
+To do this we override the `setup_params()` method. It's passed the data and a list of params, and returns an updated list.
+
+```{r}
+StatDensityCommon <- ggproto("StatDensityCommon", Stat, 
+  required_aes = "x",
+  
+  setup_params = function(data, params) {
+    if (!is.null(params$bandwidth))
+      return(params)
+    
+    xs <- split(data$x, data$group)
+    bws <- vapply(xs, bw.nrd0, numeric(1))
+    bw <- mean(bws)
+    message("Picking bandwidth of ", signif(bw, 3))
+    
+    params$bandwidth <- bw
+    params
+  },
+  
+  compute_group = function(data, scales, bandwidth = 1) {
+    d <- density(data$x, bw = bandwidth)
+    data.frame(x = d$x, y = d$y)
+  }  
+)
+
+stat_density_common <- function(mapping = NULL, data = NULL, geom = "line",
+                                position = "identity", na.rm = FALSE, show.legend = NA, 
+                                inherit.aes = TRUE, bandwidth = NULL,
+                                ...) {
+  layer(
+    stat = StatDensityCommon, data = data, mapping = mapping, geom = geom, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(bandwidth = bandwidth, na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, colour = drv)) + 
+  stat_density_common()
+
+ggplot(mpg, aes(displ, colour = drv)) + 
+  stat_density_common(bandwidth = 0.5)
+```
+
+I recommend using `NULL` as a default value. If you pick important parameters automatically, it's a good idea to `message()` to the user (and when printing a floating point parameter, using `signif()` to show only a few significant digits).
+
+### Variable names and default aesthetics
+
+This stat illustrates another important point. If we want to make this stat usable with other geoms, we should return a variable called `density` instead of `y`. Then we can set up the `default_aes` to automatically map `density` to `y`, which allows the user to override it to use with different geoms:
+
+```{r}
+StatDensityCommon <- ggproto("StatDensity2", Stat, 
+  required_aes = "x",
+  default_aes = aes(y = ..density..),
+
+  compute_group = function(data, scales, bandwidth = 1) {
+    d <- density(data$x, bw = bandwidth)
+    data.frame(x = d$x, density = d$y)
+  }  
+)
+
+ggplot(mpg, aes(displ, drv, colour = ..density..)) + 
+  stat_density_common(bandwidth = 1, geom = "point")
+```
+
+However, using this stat with the area geom doesn't work quite right. The areas don't stack on top of each other:
+
+```{r}
+ggplot(mpg, aes(displ, fill = drv)) + 
+  stat_density_common(bandwidth = 1, geom = "area", position = "stack")
+```
+
+This is because each density is computed independently, and the estimated `x`s don't line up. We can resolve that issue by computing the range of the data once in `setup_params()`.
+
+```{r}
+StatDensityCommon <- ggproto("StatDensityCommon", Stat, 
+  required_aes = "x",
+  default_aes = aes(y = ..density..),
+
+  setup_params = function(data, params) {
+    min <- min(data$x) - 3 * params$bandwidth
+    max <- max(data$x) + 3 * params$bandwidth
+    
+    list(
+      bandwidth = params$bandwidth,
+      min = min,
+      max = max,
+      na.rm = params$na.rm
+    )
+  },
+  
+  compute_group = function(data, scales, min, max, bandwidth = 1) {
+    d <- density(data$x, bw = bandwidth, from = min, to = max)
+    data.frame(x = d$x, density = d$y)
+  }  
+)
+
+ggplot(mpg, aes(displ, fill = drv)) + 
+  stat_density_common(bandwidth = 1, geom = "area", position = "stack")
+ggplot(mpg, aes(displ, drv, fill = ..density..)) + 
+  stat_density_common(bandwidth = 1, geom = "raster")
+```
+
+### Exercises
+
+1.  Extend `stat_chull` to compute the alpha hull, as from the
+    [alphahull](https://cran.r-project.org/package=alphahull) package. Your
+    new stat should take an `alpha` argument.
+
+1.  Modify the final version of `StatDensityCommon` to allow the user to 
+    specify the `min` and `max` parameters. You'll need to modify both the
+    layer function and the `compute_group()` method.
+
+1.  Compare and contrast `StatLm` to `ggplot2::StatSmooth`. What key
+    differences make `StatSmooth` more complex than `StatLm`?
+
+## Creating a new geom
+
+It's harder to create a new geom than a new stat because you also need to know some grid. ggplot2 is built on top of grid, so you'll need to know the basics of drawing with grid. If you're serious about adding a new geom, I'd recommend buying [R graphics](http://amzn.com/B00I60M26G) by Paul Murrell. It tells you everything you need to know about drawing with grid.
+
+### A simple geom
+
+It's easiest to start with a simple example. The code below is a simplified version of `geom_point()`:
+
+```{r GeomSimplePoint}
+GeomSimplePoint <- ggproto("GeomSimplePoint", Geom,
+  required_aes = c("x", "y"),
+  default_aes = aes(shape = 19, colour = "black"),
+  draw_key = draw_key_point,
+
+  draw_panel = function(data, panel_scales, coord) {
+    coords <- coord$transform(data, panel_scales)
+    grid::pointsGrob(
+      coords$x, coords$y,
+      pch = coords$shape,
+      gp = grid::gpar(col = coords$colour)
+    )
+  }
+)
+
+geom_simple_point <- function(mapping = NULL, data = NULL, stat = "identity",
+                              position = "identity", na.rm = FALSE, show.legend = NA, 
+                              inherit.aes = TRUE, ...) {
+  layer(
+    geom = GeomSimplePoint, mapping = mapping,  data = data, stat = stat, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_simple_point()
+```
+
+This is very similar to defining a new stat. You always need to provide fields/methods for the four pieces shown above:
+
+* `required_aes` is a character vector which lists all the aesthetics that
+  the user must provide.
+  
+* `default_aes` lists the aesthetics that have default values.
+
+* `draw_key` provides the function used to draw the key in the legend. 
+  You can see a list of all the build in key functions in `?draw_key`
+  
+* `draw_group()` is where the magic happens. This function takes three
+  arguments and returns a grid grob. It is called once for each panel.
+  It's the most complicated part and is described in more detail below.
+  
+`draw_group()` has three arguments:
+
+* `data`: a data frame with one column for each aesthetic.
+
+* `panel_scales`: a list containing information about the x and y scales
+  for the current panel.
+
+* `coord`: an object describing the coordinate system.
+
+Generally you won't use `panel_scales` and `coord` directly, but you will always use them to transform the data: `coords <- coord$transform(data, panel_scales)`. This creates a data frame where position variables are scaled to the range 0--1. You then take this data and call a grid grob function. (Transforming for non-Cartesian coordinate systems is quite complex - you're best of transforming your data to the form accepted by an existing ggplot2 geom and passing it.)
+
+### Collective geoms
+
+Overriding `draw_panel()` is most appropriate if there is one graphic element per row. In other cases, you want graphic element per group. For example, take polygons: each row gives one vertex of a polygon. In this case, you should instead override `draw_group()`:
+
+The following code makes a simplified version of `GeomPolygon`:
+
+```{r}
+GeomSimplePolygon <- ggproto("GeomPolygon", Geom,
+  required_aes = c("x", "y"),
+  
+  default_aes = aes(
+    colour = NA, fill = "grey20", size = 0.5,
+    linetype = 1, alpha = 1
+  ),
+
+  draw_key = draw_key_polygon,
+
+  draw_group = function(data, panel_scales, coord) {
+    n <- nrow(data)
+    if (n <= 2) return(grid::nullGrob())
+
+    coords <- coord$transform(data, panel_scales)
+    # A polygon can only have a single colour, fill, etc, so take from first row
+    first_row <- coords[1, , drop = FALSE]
+
+    grid::polygonGrob(
+      coords$x, coords$y, 
+      default.units = "native",
+      gp = grid::gpar(
+        col = first_row$colour,
+        fill = scales::alpha(first_row$fill, first_row$alpha),
+        lwd = first_row$size * .pt,
+        lty = first_row$linetype
+      )
+    )
+  }
+)
+geom_simple_polygon <- function(mapping = NULL, data = NULL, stat = "chull",
+                                position = "identity", na.rm = FALSE, show.legend = NA, 
+                                inherit.aes = TRUE, ...) {
+  layer(
+    geom = GeomSimplePolygon, mapping = mapping, data = data, stat = stat, 
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_point() + 
+  geom_simple_polygon(aes(colour = class), fill = NA)
+```
+
+There are a few things to note here:
+
+* We override `draw_group()` instead of `draw_layer()` because we want
+  one polygon per group, not one polygon per row. If you look at the source
+  code for the original `GeomPolygon` you'll see it actually overrides
+  `geom_layer()` because it uses some tricks to make `polygonGrob()` produce
+  multiple polygons in one call. This is considerably more complicated, but 
+  gives better performance.
+  
+* If the data contains two or fewer points, there's no point trying to draw
+  a polygon, so we return a `nullGrob()`. This is the graphical equivalent
+  of `NULL`: it's a grob that doesn't draw anything and doesn't take up
+  any space.
+  
+* Note the units: `x` and `y` should always be drawn in "native" units. 
+  (The default units for `pointGrob()` is a native, so we didn't need to 
+  change it there). `lwd` is measured in points, but ggplot2 uses mm, 
+  so we need to multiply it by the adjustment factor `.pt`.
+
+### Inheriting from an existing Geom
+
+Sometimes you just want to make a small modification to an existing geom. In this case, rather than inheriting from `Geom` you can inherit from an existing subclass. For example, we might want to change the defaults for `GeomPolygon` to work better with `StatChull`:
+
+```{r}
+GeomPolygonHollow <- ggproto("GeomPolygonHollow", GeomPolygon,
+  default_aes = aes(colour = "black", fill = NA, size = 0.5, linetype = 1,
+    alpha = NA)
+  )
+geom_chull <- function(mapping = NULL, data = NULL, 
+                       position = "identity", na.rm = FALSE, show.legend = NA, 
+                       inherit.aes = TRUE, ...) {
+  layer(
+    stat = StatChull, geom = GeomPolygonHollow, data = data, mapping = mapping,
+    position = position, show.legend = show.legend, inherit.aes = inherit.aes,
+    params = list(na.rm = na.rm, ...)
+  )
+}
+
+ggplot(mpg, aes(displ, hwy)) + 
+  geom_point() + 
+  geom_chull()
+```
+
+This doesn't allow you to use different geoms with the stat, but that seems appropriate here since the convex hull is primarily a polygonal feature.
+
+### Exercises
+
+1. Compare and contrast `GeomPoint` with `GeomSimplePoint`.
+
+1. Compare and contract `GeomPolygon` with `GeomSimplePolygon`.
+
+## Creating your own theme
+
+If you're going to create your own complete theme, there are a few things you need to know:
+
+* Overriding existing elements, rather than modifying them
+* The four global elements that affect (almost) every other theme element
+* Complete vs. incomplete elements
+
+### Overriding elements
+
+By default, when you add a new theme element, it inherits values from the existing theme. For example, the following code sets the key colour to red, but it inherits the existing fill colour:
+
+```{r}
+theme_grey()$legend.key
+
+new_theme <- theme_grey() + theme(legend.key = element_rect(colour = "red"))
+new_theme$legend.key
+```
+
+To override it completely, use `%+replace%` instead of `+`:
+
+```{r}
+new_theme <- theme_grey() %+replace% theme(legend.key = element_rect(colour = "red"))
+new_theme$legend.key
+```
+
+### Global elements
+
+There are four elements that affect the global appearance of the plot:
+
+Element      | Theme function    | Description
+-------------|-------------------|------------------------
+line         | `element_line()`  | all line elements
+rect         | `element_rect()`  | all rectangular elements
+text         | `element_text()`  | all text
+title        | `element_text()`  | all text in title elements (plot, axes & legend)
+
+These set default properties that are inherited by more specific settings. These are most useful for setting an overall "background" colour and overall font settings (e.g. family and size).
+
+```{r axis-line-ex}
+df <- data.frame(x = 1:3, y = 1:3)
+base <- ggplot(df, aes(x, y)) + 
+  geom_point() + 
+  theme_minimal()
+
+base
+base + theme(text = element_text(colour = "red"))
+```
+
+You should generally start creating a theme by modifying these values.
+
+### Complete vs incomplete
+
+It is useful to understand the difference between complete and incomplete theme objects. A *complete* theme object is one produced by calling a theme function with the attribute `complete = TRUE`. 
+
+Theme functions `theme_grey()` and `theme_bw()` are examples of complete theme functions. Calls to `theme()` produce *incomplete* theme objects, since they represent (local) modifications to a theme object rather than returning a complete theme object per se. When adding an incomplete theme to a complete one, the result is a complete theme. 
+
+Complete and incomplete themes behave somewhat differently when added to a ggplot object:
+
+* Adding an incomplete theme augments the current theme object, replacing only 
+  those properties of elements defined in the call to `theme()`.
+  
+* Adding a complete theme wipes away the existing theme and applies the new theme.
diff --git a/vignettes/ggplot2-specs.Rmd b/vignettes/ggplot2-specs.Rmd
new file mode 100644
index 0000000..5c2cf0b
--- /dev/null
+++ b/vignettes/ggplot2-specs.Rmd
@@ -0,0 +1,168 @@
+---
+title: "Aesthetic specifications"
+author: "Hadley Wickham"
+date: "`r Sys.Date()`"
+output: rmarkdown::html_vignette
+vignette: >
+  %\VignetteIndexEntry{Aesthetic specifications}
+  %\VignetteEngine{knitr::rmarkdown}
+  %\VignetteEncoding{UTF-8}
+---
+
+```{r, include = FALSE}
+library(ggplot2)
+knitr::opts_chunk$set(fig.dpi = 96)
+```
+
+This vignette summarises the various formats that grid drawing functions take.  Most of this information is available scattered throughout the R documentation.  This appendix brings it all together in one place. 
+
+## Colour
+
+Colours can be specified with: 
+
+*   A __name__, e.g., `"red"`. R has `r length(colours())` built-in named
+    colours, which can be listed with `colours()`. The Stowers Institute 
+    provides a nice printable pdf that lists all colours: 
+    <http://research.stowers-institute.org/efg/R/Color/Chart/>.
+
+*   An __rgb specification__, with a string of the form `"#RRGGBB"` where each of 
+    the pairs `RR`, `GG`, `BB` consists of two hexadecimal digits giving a value 
+    in the range `00` to `FF`
+    
+    You can optionally make the colour transparent by using the form 
+    `"#RRGGBBAA".
+
+*   An __NA__, for a completely transparent colour.
+
+*   The [munsell](https://github.com/cwickham/munsell) package, Charlotte 
+    Wickham, provides a wrapper around the colour system designed by Alfred 
+    Munsell.
+
+## Line type {#sec:line-type-spec}
+
+Line types can be specified with:
+
+*   An __integer__ or __name__: 0 = blank, 1 = solid, 2 = dashed, 3 = dotted, 
+    4 = dotdash, 5 = longdash, 6 = twodash, as shown below:
+
+    ```{r}
+    lty <- c("blank", "solid", "dashed", "dotted", "dotdash", 
+         "longdash","twodash")
+    linetypes <- data.frame(
+      y = seq_along(lty),
+      lty = lty
+    ) 
+    ggplot(linetypes, aes(0, y)) + 
+      geom_segment(aes(xend = 5, yend = y, linetype = lty)) + 
+      scale_linetype_identity() + 
+      geom_text(aes(label = lty), hjust = 0, nudge_y = 0.2) +
+      scale_x_continuous(NULL, breaks = NULL) + 
+      scale_y_continuous(NULL, breaks = NULL)
+    ```
+
+*   The lengths of on/off stretches of line. This is done with a string 
+    containing 2, 4, 6, or 8 hexadecimal digits which give the lengths of c
+    consecutive lengths. For example, the string `"33"` specifies three units 
+    on followed by three off and `"3313"` specifies three units on followed by 
+    three off followed by one on and finally three off. 
+    
+    The five standard dash-dot line types described above correspond to 44, 13, 
+    134, 73, and 2262.
+
+The `size` of a line is its width in mm.
+
+## Shape {#sec:shape-spec}
+
+Shapes take four types of values:
+
+*   An __integer__ in $[0, 25]$:
+
+    ```{r}
+    shapes <- data.frame(
+      shape = c(0:19, 22, 21, 24, 23, 20),
+      x = 0:24 %/% 5,
+      y = -(0:24 %% 5)
+    )
+    ggplot(shapes, aes(x, y)) + 
+      geom_point(aes(shape = shape), size = 5, fill = "red") +
+      geom_text(aes(label = shape), hjust = 0, nudge_x = 0.15) +
+      scale_shape_identity() +
+      expand_limits(x = 4.1) +
+      scale_x_continuous(NULL, breaks = NULL) + 
+      scale_y_continuous(NULL, breaks = NULL)
+    ```
+
+*   A __single character__, to use that character as a plotting symbol.
+
+*   A `.` to draw the smallest rectangle that is visible, usualy 1 pixel.
+   
+*   An `NA`, to draw nothing.
+
+Note that shapes 21-24 have both stroke `colour` and a `fill`. The size of the filled part is controlled by `size`, the size of the stroke is controlled by `stroke`. Each is measured in mm, and the total size of the point is the sum of the two. Note that the size is constant along the diagonal in the following figure.
+
+```{r}
+sizes <- expand.grid(size = (0:3) * 2, stroke = (0:3) * 2)
+ggplot(sizes, aes(size, stroke, size = size, stroke = stroke)) + 
+  geom_abline(slope = -1, intercept = 6, colour = "white", size = 6) + 
+  geom_point(shape = 21, fill = "red") +
+  scale_size_identity()
+```
+
+
+## Text
+
+### Font size
+
+
+### Font face
+
+There are only three fonts that are guaranteed to work everywhere: "sans" (the default), "serif", or "mono":
+
+```{r}
+df <- data.frame(x = 1, y = 3:1, family = c("sans", "serif", "mono"))
+ggplot(df, aes(x, y)) + 
+  geom_text(aes(label = family, family = family))
+```
+
+It's trickier to include a system font on a plot because text drawing is done differently by each graphics device (GD). There are five GDs in common use (`png()`, `pdf()`, on screen devices for Windows, Mac and Linux), so to have a font work everywhere you need to configure five devices in five different ways. Two packages simplify the quandary a bit: 
+
+* `showtext` makes GD-independent plots by rendering all text as polygons. 
+
+* `extrafont` converts fonts to a standard format that all devices can use. 
+
+Both approaches have pros and cons, so you will to need to try both of them and see which works best for your needs.
+
+### Family
+
+<!--
+postscriptFonts, pdfFonts, quartzFonts
+
+Find R news article
+
+\begin{itemize}
+  \item \code{face}
+  \item \code{family}
+  \item \code{lineheight}
+  \item \code{fontsize}
+\end{itemize}
+-->
+
+
+### Justification
+
+Horizontal and vertical justification have the same parameterisation, either a string ("top", "middle", "bottom", "left", "center", "right") or a number between 0 and 1:
+
+* top = 1, middle = 0.5, bottom = 0
+* left = 0, center = 0.5, right = 1
+
+
+```{r}
+just <- expand.grid(hjust = c(0, 0.5, 1), vjust = c(0, 0.5, 1))
+just$label <- paste0(just$hjust, ", ", just$vjust)
+
+ggplot(just, aes(hjust, vjust)) +
+  geom_point(colour = "grey70", size = 5) + 
+  geom_text(aes(label = label, hjust = hjust, vjust = vjust))
+```
+
+Note that you can use numbers outside the range (0, 1), but it's not recommended. 
diff --git a/vignettes/release.Rmd b/vignettes/release.Rmd
deleted file mode 100644
index 2efe4bf..0000000
--- a/vignettes/release.Rmd
+++ /dev/null
@@ -1,107 +0,0 @@
-<!--
-%\VignetteEngine{knitr::knitr}
-%\VignetteIndexEntry{ggplot2 release process}
--->
-
-```{r, echo = FALSE, message = FALSE}
-knitr::opts_chunk$set(
-  comment = "#>",
-  error = FALSE,
-  tidy = FALSE
-)
-library(ggplot2)
-```
-
-# Releasing a new version of ggplot2
-
-## Release candidate phase
-
-After issues resolved for a given release:
-
-1.  Pass R CMD check.
-
-1.  In DESCRIPTION and NEWS, remove the .99 version suffix and increment the
-    version number. For example, 0.9.2.99 becomes 0.9.3.
-
-1.  Do the same for any packages that ggplot2 depends on, such as scales and
-    gtable.
-
-1.  Update ggplot2's Import dependency versions to use the final release numbers
-    of scales and gtable.
-
-1.  Commit these changes to a branch with `ggplot2-<version>-rc`, and push the
-    branch.
-    
-1.  Check packages that depend on ggplot2 with `devtools::revdep_check()` and
-    run visual tests.
-
-1.  Email ggplot2, ggplot2-dev, and bcc the maintainers of packages that depend 
-    on ggplot2 (`revdep_maintainers("ggplot2")`).
-    
-    ```
-    Hi all,
-    
-    We're very please to announce a release candidate for ggplot2 1.0.0! This
-    release celebrates the ggplot2 community: all improvements have been 
-    contributed via pull requests.
-    
-    We've made every effort to make sure that your existing ggplot2 graphics
-    continue to work. ggplot2 1.0.0 has passed R CMD check, all our existing 
-    visual tests, and R CMD check on all dependencies. But it's still possible 
-    that some bugs may have crept in, so we'd really appreciate it if you'd 
-    try it out. It's easy to install the development version: first install 
-    devtools, then run `devtools::install_github("hadley/ggplot2 at ggplot2-1.0.0-rc")`.
-    
-    We plan to submit ggplot2 to cran in two weeks, May 9. Please let us know if 
-    you have any problems - your feedback is much appreciated. (If you're pretty
-    sure you've discovered a new bug, please start a new thread or file
-    an issue on github, otherwise it's a bit hard to track what's going on).
-    
-    Hadley & Winston
-    ```
-
-1.  Notify cran:
-
-    ```
-    Dear CRAN maintainers,
-    
-    ggplot2 1.0.0 has entered the release candidate phase and will be
-    submitted to CRAN in two weeks.
-    
-    Included below is the email that I sent to the ggplot2 mailing and all
-    maintainers of packages that depend on ggplot2.
-    
-    Regards,
-    
-    Hadley
-    ```
-
-If problems arise during the RC period, make fixes on the branch. Those fixes
-later get merged back into master.
-
-## Release
-
-When the package is accepted on CRAN:
-
-1.  Create a new release at https://github.com/hadley/ggplot2/releases.
-    The tag name should be of the form `v1.0.0`.
-
-1.  If any Check out the new branch, or merge it into master. (Need to get off the
-    rc branch so it can be deleted):
-
-    ```
-    VERSION=1.0.0
-    git checkout v$VERSION
-    # Or
-    git checkout master
-    git merge v$VERSION
-    ```
-
-1.  Delete the `-rc` branch, with:
-
-    ```
-    git branch -d v$VERSION-rc
-    git push origin :v$VERSION-rc
-    ```
-
-1.  Once you push the tag github, travis will automatically build the website.

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/r-cran-ggplot2.git



More information about the debian-med-commit mailing list