ggplot2 3.0.0

  tidyverse, ggplot2

  Mara Averick

We’re extremely pleased to announce the release of ggplot2 3.0.0. This is a major release: it was previously announced as ggplot2 2.3.0, but we decided to increment the version number because there are some big changes under the hood. Most importantly ggplot2 now supports tidy evaluation, which makes it easier to programmatically build plots with ggplot2 in the same way you can programmatically build data manipulation pipelines with dplyr.

Install ggplot2 with:


Breaking changes

In stable, long-standing packages like ggplot2, we put in a lot of effort to make sure that we don’t introduce backward incompatible changes. For this release, that involved testing on five versions of R (3.1 - 3.5) writing a new visual testing package ( vdiffr), running R CMD check on downstream packages (over 6,000 times!), and widely advertising the release to get the community’s help. However, sometimes we do decide that it’s worth breaking a small amount of existing code in the interests of improving future code.

The changes should affect relatively little user code, but have required developers to make changes. A separate post will address developer-facing changes in further detail, however, common errors and ways to work around them can be found in the Breaking changes section of ggplot2’s NEWS. If you discover something missing, please let us know so we can add it.

Tidy evaluation

You can now use quasiquotation in aes(), facet_wrap(), and facet_grid(). To support quasiquotation in facetting we’ve added a new helper that works similarly to aes(): vars(), short for variables, so instead of facet_grid(x + y ~ a + b) you can now write facet_grid(vars(x, y), vars(a, b)). The formula interface won’t go away; but the new vars() interface is much easier to program with.

x_var <- quo(wt)
y_var <- quo(mpg)
group_var <- quo(cyl)

ggplot(mtcars, aes(!!x_var, !!y_var)) + 
  geom_point() + 

New features

We only touch on a few of the new features in ggplot2 — there are many many more. For a full account of these improvements, please see NEWS. If there’s a feature you particularly like, and you write a blog post about, please share it with us using this form, and we’ll include in a round up post in a month’s time.


Thanks to the help of Edzer Pebesma and the r-spatial team, ggplot2 now has full support for simple features through sf using geom_sf() and coord_sf(); it now automatically aligns CRS across layers, sets up the correct aspect ratio, and draws a graticule.

nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"))
#> Reading layer `nc' from data source `/Users/hadley/R/sf/shape/nc.shp' using driver `ESRI Shapefile'
#> Simple feature collection with 100 features and 14 fields
#> geometry type:  MULTIPOLYGON
#> dimension:      XY
#> bbox:           xmin: -84.32385 ymin: 33.88199 xmax: -75.45698 ymax: 36.58965
#> epsg (SRID):    4267
#> proj4string:    +proj=longlat +datum=NAD27 +no_defs
ggplot(nc) +
  geom_sf() +
  annotate("point", x = -80, y = 35, colour = "red", size = 4)

Calculated aesthetics

The new stat() function offers a cleaner, and better-documented syntax for calculated-aesthetic variables. This replaces the older approach of surrounding the variable name with ... Instead of using aes(y = ..count..), you can use aes(y = stat(count)).

This is particularly nice for more complex calculations, as stat() only needs to be specified once; e.g. aes(y = stat(count / max(count))) rather than aes(y = ..count.. / max(..count..)).


In addition to title, subtitle, and caption, a new tag label has been added, for identifying plots. Add a tag with labs(tag = "A"), style it with the plot.tag theme element, and control position with the plot.tag.position theme.

ggplot(mtcars) +
  geom_point(aes(disp, mpg)) + 
  labs(tag = 'A', title = 'Title of this plot')

Layers: geoms, stats, and position adjustments

The new position_dodge2() allows you to arrange the horizontal position of plots with variable widths (i.e. bars and rectangles, in addition to box plots). By default, position_dodge2() preserves the width of each element. You can choose to preserve the total width by setting the preserve argument to "total". Thank you to Kara Woo for all of her work on this.

ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) +
  geom_bar(position = position_dodge2(preserve = "single"))

ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) +
  geom_bar(position = position_dodge2(preserve = "total"))

Scales and guides

Several new functions have been added to make it easy to use Viridis colour scales: scale_colour_viridis_c() and scale_fill_viridis_c() for continuous, and scale_colour_viridis_d() and scale_fill_viridis_d() for discrete. Viridis is also now used as the default colour and fill scale for ordered factors.

dsamp <- diamonds[sample(nrow(diamonds), 1000), ]
d <- ggplot(dsamp, aes(carat, price)) +
  geom_point(aes(colour = clarity))
d + scale_colour_viridis_d()

scale_colour_continuous() and scale_colour_gradient() are now controlled by global options ggplot2.continuous.colour and ggplot2.continuous.fill. You can set them to "viridis" to use the viridis colour scale by default:

  ggplot2.continuous.colour = "viridis",
  ggplot2.continuous.fill = "viridis"
v <- ggplot(faithfuld) +
  geom_tile(aes(waiting, eruptions, fill = density))
v + scale_fill_continuous()

guide_colorbar() is more configurable: tick marks and color bar frame can now by styled with arguments ticks.colour, ticks.linewidth, frame.colour, frame.linewidth, and frame.linetype.

p <- ggplot(mtcars, aes(wt, mpg))

p + geom_point(aes(colour = cyl)) +
    low = "white", high = "red",
    guide = guide_colorbar(
      frame.colour = "black",
      ticks.colour = "black"

Nonstandard aesthetics

Thanks to Claus Wilke, there is significantly improved support for nonstandard aesthetics.

Aesthetics can now be specified independent of the scale name.

ggplot(iris, aes(x = Sepal.Length, fill = Species)) +
  geom_density(alpha = 0.7) +
  scale_colour_brewer(type = "qual", aesthetics = "fill")


This release includes a change to the ggplot2 authors, which now includes Claus Wilke (new), and Lionel Henry, Kara Woo, Thomas Lin Pedersen, and Kohske Takahashi in recognition of their past contributions.

We’re grateful to the 391 people who contributed issues, code and comments: @achalaacharya, @adambajguz, @AdeelH, @adrfantini, @aelwan, @aetiologicCanada, @ajay-d, @alberthkcheng, @alchenist, @alexconingham, @alexgenin, @alistaire47, @andbarker, @andrewdolman, @andrewjpfeiffer, @andzandz11, @aornugent, @aosmith16, @aphalo, @arthur-st, @aschersleben, @awgymer, @Ax3man, @baderstine, @baffelli, @baptiste, @BarkleyBG, @basille, @batpigandme, @batuff, @bbolker, @bbrewington, @beansprout88, @behrman, @ben519, @benediktclaus, @berkorbay, @bfgray3, @bhaskarvk, @billdenney, @bjreisman, @boshek, @botanize, @botaspablo, @bouch-ra, @brianwdavis, @briencj, @brodieG, @bsaul, @bschneidr, @burchill, @buyske, @byapparov, @caijun, @cankutcubuk, @CharlesCara, @Chavelior, @christianhomberg, @cinkova, @ckuenne, @clauswilke, @cooknl, @corytu, @cpsievert, @cregouby, @crsh, @cryanking, @cseveren, @daattali, @danfulop, @daniel-barnett, @dantonnoriega, @DarioBoh, @DarioS, @darrkj, @DarwinAwardWinner, @DasHammett, @datalorax, @davharris, @DavidNash1, @DavyLandman, @dbo99, @ddiez, @delferts, @Demetrio92, @DesiQuintans, @dietrichson, @Dilini-Sewwandi-Rajapaksha, @dipenpatel235, @diplodata, @dirkschumacher, @djrajdev, @dl7631, @dmenne, @DocOfi, @domiden, @dongzhuoer, @dpastoor, @dpmcsuss, @dpprdan, @dpseidel, @DSLituiev, @dvcv, @dylan-stark, @eamoncaddigan, @econandrew, @edgararuiz, @edmundesterbauer, @EdwinTh, @edzer, @eeenilsson, @ekatko1, @elbamos, @elina800, @elinw, @eliocamp, @Emaasit, @emilelatour, @Enchufa2, @erocoar, @espinielli, @everydayduffy, @ewallace, @FabianRoger, @FelixMailoa, @FlordeAzahar, @flying-sheep, @fmassicano, @foldager, @foo-bar-baz-qux, @francoisturcot, @Freguglia, @frostell, @gfiumara, @GG786, @ggrothendieck, @ghost, @gilleschapron, @GillesSanMartin, @gjabel, @glennstone, @gmbecker, @GoodluckH, @gordocabron, @goyalmunish, @grantmcdermott, @GreenStat, @gregmacfarlane, @gregrs-uk, @GuangchuangYu, @gwarnes-mdsol, @ha0ye, @hadley, @hannes101, @hansvancalster, @hardeepsjohar, @has2k1, @heckendorfc, @hedjour, @Henrik-P, @henrikmidtiby, @hrabel, @hrbrmstr, @huangl07, @HughParsonage, @ibiris, @idavydov, @idemockle, @igordot, @Ilia-Kosenkov, @IndrajeetPatil, @irudnyts, @izahn, @jan-glx, @janvanoeveren, @jarrod-dalton, @jcrada, @jdagilliland, @jemus42, @jenitivecase, @jennybc, @jentjr, @jflycn, @jgoad, @jimdholland, @jimhester, @jnaber, @jnolis, @joacorapela, @joergtrojan, @JoFAM, @johngoldin, @JohnMount, @jonocarroll, @joojala, @jorgher, @josephuses, @joshkehn, @jpilorget, @jrnold, @jrvianna, @jsams, @jsta, @JTapper, @juliasilge, @jvcasillas, @jwdink, @jwhendy, @JWilb, @jzadra, @kamilsi, @karawoo, @karldw, @katrinleinweber, @kaybenleroll, @kenbeek, @kent37, @kevinushey, @kimchpekr, @klmr, @kmace, @krlmlr, @kylebmetrum, @landesbergn, @laurareads, @ldecicco-USGS, @Leoloh, @likanzhan, @lindeloev, @lionel-, @liuwell, @llrs, @LSanselme, @luisDVA, @luwei0917, @MagicForrest, @malcolmbarrett, @mallerhand, @ManuelNeumann, @manuelreif, @MarauderPixie, @mariellep, @Maschette, @mattwilliamson13, @mbergins, @mcol, @mdsumner, @melohr, @mentalplex, @mfoos, @mgacc0, @mgruebsch, @MichaelChirico, @MichaelRatajczak, @mikgh, @mikmart, @MilesMcBain, @mine-cetinkaya-rundel, @mitchelloharawild, @mjbock, @mkoohafkan, @mkuhn, @monikav, @mpancia, @mrtns, @mruessler, @mundl, @mvkorpel, @mwaldstein, @ndphillips, @Nekochef, @nhamilton1980, @nicksolomon, @nipunbatra, @noamross, @Nowosad, @nteetor, @nzxwang, @oneilsh, @ozgen92, @patr1ckm, @pbreheny, @pelotom, @petersorensen, @philstraforelli, @pkq, @pnolain, @Pomido, @powestermark, @pscheid92, @pschloss, @ptoche, @qinzhu, @QuentinRoy, @R180, @ractingmatrix, @RafaRafa, @randomgambit, @raubreywhite, @RawanRadi, @ray-p144, @RegalPlatypus, @Rekyt, @RemmyGuo, @ReneMalenfant, @renozao, @restonslacker, @rlionheart92, @rmatev, @rmatkins, @rmheiberger, @RMHogervorst, @Robinlovelace, @RoelVerbelen, @rohan-shah, @rpruim, @ruaridhw, @Ryo-N7, @sabinfos, @sachinbanugariya, @sahirbhatnagar, @salauer, @sathishsrinivasank, @saudiwin, @schloerke, @seancaodo, @setempler, @sfirke, @sgoodm8, @shippy, @skanskan, @slowkow, @smouksassi, @SomeUser999, @space-echo, @statkclee, @statsandthings, @statsccpr, @sTeamTraen, @stefanedwards, @stephankraut, @SteveMillard, @stla, @svannoy, @swimmingsand, @taraskaduk, @tbradley1013, @tdhock, @Thieffen, @ThierryO, @thjwong, @thk686, @thomashauner, @thomaskvalnes, @thomasp85, @thvasilo, @tiernanmartin, @timgoodman, @timothyslau, @tingtingben, @tjmahr, @toouggy, @topepo, @traversc, @truemoid, @tungmilan, @Tutuchan, @tzoltak, @ulo, @UweBlock, @vadimus202, @VectorPosse, @VikrantDogra, @vnijs, @wch, @wdsteck, @WHMan, @wibeasley, @wkristan, @woodwards, @wpetry, @wxlu718, @xhdong-umd, @yeedle, @yonicd, @yutannihilation, @zeehio, @zhenglei-gao, @zlskidmore, @ZoidbergIII, and @zz77zz.