User facing
Breaking changes
- The S3 parts of ggplot2 have been replaced with S7 bits (#6352).
- (breaking)
geom_violin(quantiles)now has actual quantiles based on
the data, rather than inferred quantiles based on the computed density. The
quantilesparameter that replacesdraw_quantilesnow belongs to
stat_ydensity()instead ofgeom_violin()(@teunbrand, #4120). - (Breaking) The defaults for all geoms can be set at one in the theme.
(@teunbrand based on pioneering work by @dpseidel, #2239)- A new
theme(geom)argument is used to track these defaults. - The
element_geom()function can be used to populate that argument. - The
from_theme()function allows access to the theme default fields from
inside theaes()function.
- A new
- Moved the following packages in the description. If your package depended on
ggplot2 to install these dependencies, you may need to list these in your
own DESCRIPTION file now (#5986).- Moved mgcv from Imports to Suggests
- Moved tibble from Imports to Suggests
- Removed glue dependency
- Default labels are derived in
build_ggplot()(previouslyggplot_build())
rather than in the layer method ofupdate_ggplot()
(previouslyggplot_add.Layer()). This may affect code that accessed the
plot$labelsproperty (@teunbrand, #5894). - In binning stats, the default
boundaryis now chosen to better adhere to
thenbinargument. This may affect plots that use default binning
(@teunbrand, #5882, #5036)
Lifecycle changes
-
Deprecated functions and arguments prior to ggplot2 3.0.0 throw errors instead
of warnings. -
Functions and arguments that were soft-deprecated up to ggplot2 3.4.0 now
throw warnings. -
annotation_borders()replaces the now-deprecatedborders()
(@teunbrand, #6392) -
Turned off fallback for
sizetolinewidthtranslation in
geom_bar()/geom_col()(#4848). -
The
fattenargument has been deprecated ingeom_boxplot(),
geom_crossbar()andgeom_pointrange()(@teunbrand, #4881). -
The following methods have been deprecated:
fortify.lm(),fortify.glht(),
fortify.confint.glht(),fortify.summary.glht()andfortify.cld(). It
is recommend to usebroom::augment()andbroom::tidy()instead
(@teunbrand, #3816). -
geom_errorbarh()is deprecated in favour of
geom_errorbar(orientation = "y")(@teunbrand, #5961). -
Special getter and setter functions have been renamed for consistency, allowing
for better tab-completion withget_*- andset_*-prefixes. The old names
remain available for backward compatibility (@teunbrand, #5568).New name Old name get_theme()theme_get()set_theme()theme_set()replace_theme()theme_replace()update_theme()theme_update()get_last_plot()last_plot()get_layer_data()layer_data()get_layer_grob()layer_grob()get_panel_scales()layer_scales() -
facet_wrap()has new options for thedirargument for additional control
over panel directions. They absorb interactions with the now-deprecated
as.tableargument. Internallydir = "h"ordir = "v"is deprecated
(@teunbrand, #5212). -
coord_trans()was renamed tocoord_transform()(@nmercadeb, #5825).
Improvements
Themes
- The
theme()function offers new arguments:geomto set defaults for layer aesthetics (#2239).spacing/marginsas root elements that are inherited by all other
spacings and (non-text) margins (@teunbrand, #5622).palette.{aes}.discreteandpalette.{aes}.continuouswhich determine
the palettes used when scales havepalette = NULL. This is the new
default for generic scales likescale_colour_discrete()or
scale_fill_continuous(), see also the 'Scales' section (#4696).panel.widthsandpanel.heightsto control the (absolute) size of the
panels (#5338, @teunbrand).legend.key.justificationto control the alignment of legend keys
(@teunbrand, #3669)
- Built-in
theme_*()functions have new arguments:ink/paper/accentto control foreground, background and highlight
colours respectively of the whole plot (@teunbrand, #6063, @EvaMaeRey, #6438).header_familyto easily set the font for headers and titles (#5886)- To accommodate,
plot.subtitle,plot.captionandplot.tagnow
inherit from the roottextelement instead of thetitleelement.
- To accommodate,
- New function family for setting parts of a theme. For example, you can now use
theme_sub_axis(line, text, ticks, ticks.length, line)as a substitute for
theme(axis.line, axis.text, axis.ticks, axis.ticks.length, axis.line). This
should allow slightly terser and more organised theme declarations
(@teunbrand, #5301). - Adjustments to margins (#6115):
- They can have NA-units, which indicate that the value should be inherited
from the parent element. - New
margin_part()function that comes pre-populated with NA-units, so
you can change a single margin without worrying that the others look off. - New
margin_auto()that recycles arguments in a CSS like fashion.
- They can have NA-units, which indicate that the value should be inherited
- The
fillof thepanel.bordertheme setting is ignored and forced to be
transparent (#5782). theme_classic()has the following changes (@teunbrand, #5978 & #6320):- Axis ticks are now black (
ink-coloured) instead of dark gray. - Axis line ends are now
"square". - The panel grid is now blank at the
panel.gridhierarchy level instead of
thepanel.grid.majorandpanel.grid.minorlevels.
- Axis ticks are now black (
- The
theme(legend.spacing.{x/y})setting now acceptsnull-units
(@teunbrand, #6417).
Scales
- The default colour and fill scales have a new
paletteargument. The default,
palette = NULLwill retrieve palettes from the theme (see the Themes section).
This replaces the old options-basedtypesystem, with some limited backward
compatibility (@teunbrand, #6064). - All scales now expose the
aestheticsparameter (@teunbrand, #5841) - All position scales now use the same definition of
xandyaesthetics.
This lets uncommon aesthetics likexinterceptexpand scales as usual.
(#3342, #4966, @teunbrand) - In continuous scales, when
breaksis a function andn.breaksis set, the
n.breakswill be passed to thebreaksfunction. Previously,n.breaks
only applied to the default break calculation (@teunbrand, #5972). - Changes in discrete scales:
- Added
paletteargument, which can be used to customise spacings between
levels (@teunbrand, #5770) - Added
continuous.limitsargument to control the display range
(@teunbrand, #4174, #6259). - Added
minor_breaksargument. This only makes sense in position scales,
where it affects the placement of minor ticks and minor gridlines (#5434). - Added
sec.axisargument. Discrete scales don't support transformations
so it is recommended to usedup_axis()to set custom breaks or labels.
Secondary discrete axes work with the continuous analogues of discrete
breaks (@teunbrand, #3171) - When
breaksyields a named vector, the names will be used aslabels
by default (@teunbrand, #6147).
- Added
- Changes in date/time scales:
- is silently cast to in date scales. Vice versa,
is cast to in datetime scales (@laurabrianna, #3533) - Bare numeric provided to date or datetime scales get inversely transformed
(i.e. cast to /) with a warning (@teunbrand) - The
date_breaks,date_minor_breaksanddate_labelsarguments have
been copied over toscale_{x/y}_time()(@teunbrand, #4335).
- is silently cast to in date scales. Vice versa,
- More stability for vctrs-based palettes (@teunbrand, #6117).
- Scale names, guide titles and aesthetic labels can now accept functions
(@teunbrand, #4313)
Coords
- Reversal of a dimension, typically 'x' or 'y', is now controlled by the
reverseargument incoord_cartesian(),coord_fixed(),coord_radial()
andcoord_sf(). Incoord_radial(), this replaces the olderdirection
argument (#4021, @teunbrand). coord_*(expand)can now take a logical vector to control expansion at any
side of the panel (top, right, bottom, left) (@teunbrand, #6020)- New
coord_cartesian(ratio)argument that absorbs the aspect ratio
functionality fromcoord_equal()andcoord_fixed(), which are now
wrappers forcoord_cartesian(). - In non-orthogonal coordinate systems (
coord_sf(),coord_polar()and
coord_radial()), using 'AsIs' variables escape transformation when
bothxandyis an 'AsIs' variable (@teunbrand, #6205). - Axis labels are now preserved better when using
coord_sf(expand = TRUE)and
graticule lines are straight but do not meet the edge (@teunbrand, #2985). coord_radial(clip = "on")clips to the panel area when the graphics device
supports clipping paths (@teunbrand, #5952).coord_radial(r.axis.inside)can now take a numeric value to control
placement of internally placed radius axes (@teunbrand, #5805).- Munching in
coord_polar()andcoord_radial()now adds more detail,
particularly for data-points with a low radius near the center
(@teunbrand, #5023).
Layers
- Position adjustments can now have auxiliary aesthetics (@teunbrand).
- New
stat_connect()to connect points via steps or other shapes
(@teunbrand, #6228) - New stat:
stat_manual()for arbitrary computations (@teunbrand, #3501) geom_boxplot()gains additional arguments to style the colour, linetype and
linewidths of the box, whiskers, median line and staples (@teunbrand, #5126).geom_violin()gains additional arguments to style the colour, linetype and
linewidths of the quantiles, which replace the now-deprecateddraw_quantiles
argument (#5912).- New parameters for
geom_label()(@teunbrand and @steveharoz, #5365):- The
linewidthaesthetic is now applied and replaces thelabel.size
argument. - The
linetypeaesthetic is now applied. - New
border.colourargument to set the colour of borders. - New
text.colourargument to set the colour of text.
- The
- New
layer(layout)argument to interact with facets (@teunbrand, #3062) - New default
geom_qq_line(geom = "abline")for better clipping in the
vertical direction. In addition,slopeandinterceptare new computed
variables instat_qq_line()(@teunbrand, #6087). stat_ecdf()now has an optionalweightaesthetic (@teunbrand, #5058).stat_ellipsenow has an optionalweight(@teunbrand, #5272)stat_density()has the new computed variable:wdensity, which is
calculated as the density times the sum of weights (@teunbrand, #4176).linetype = NAis now interpreted to mean 'no line' instead of raising errors
(@teunbrand, #6269).
position_dodge()andposition_jitterdodge()now have areverseargument
(@teunbrand, #3610)position_jitterdodge()now dodges bygroup(@teunbrand, #3656)geom_rect()can now derive the required corners positions fromx/width
ory/heightparameterisation (@teunbrand, #5861).position_dodge(preserve = "single")now handles multi-row geoms better,
such asgeom_violin()(@teunbrand based on @clauswilke's work, #2801).geom_point()can be dodged vertically by using
position_dodge(..., orientation = "y")(@teunbrand, #5809).- The
arrow.fillparameter is now applied to more line-based functions:
geom_path(),geom_line(),geom_step()geom_function(), line
geometries ingeom_sf()andelement_line(). geom_raster()now falls back to rendering asgeom_rect()when coordinates
are not linear (#5503).geom_ribbon()can have varyingfilloralphain linear coordinate
systems (@teunbrand, #4690).- Standardised the calculation of
width, which are now implemented as
aesthetics (@teunbrand, #2800, #3142, #5740, #3722). - All binning stats now use the
boundary/centerparametrisation rather
thanorigin, following instat_bin()'s footsteps (@teunbrand). - Reintroduced
dropargument tostat_bin()(@teunbrand, #3449) stat_bin()now accepts functions for argumentbreaks(@aijordan, #4561)after_stat()andafter_scale()throw warnings when the computed aesthetics
are not of the correct length (#5901).geom_hline()andgeom_vline()now havepositionargument
(@yutannihilation, #4285).geom_contour()should be able to recognise a rotated grid of points
(@teunbrand, #4320)
Other
- An attempt is made to use a variable's label attribute as default label
(@teunbrand, #4631) guide_*()can now accept two inside legend theme elements:
legend.position.insideandlegend.justification.inside, allowing inside
legends to be placed at different positions. Only inside legends with the same
position and justification will be merged (@Yunuuuu, #6210).guide_bins(),guide_colourbar()andguide_coloursteps()gain anangle
argument to overrule theme settings, similar toguide_axis(angle)
(@teunbrand, #4594).- New argument
labs(dictionary)to label based on variable name rather than
based on aesthetic (@teunbrand, #5178) - The
summary()method for ggplots is now more terse about facets
(@teunbrand, #5989). facet_wrap()can havespace = "free_x"with 1-row layouts and
space = "free_y"with 1-column layouts (@teunbrand)- Layers can have names (@teunbrand, #4066).
- Axis labels are now justified across facet panels (@teunbrand, #5820)
facet_grid(space = "free")can now be combined withcoord_fixed()
(@teunbrand, #4584).- The ellipsis argument is now checked in
fortify(),get_alt_text(),
labs()and several guides. (@teunbrand, #3196). ggsave()can write a multi-page pdf file when provided with a list of plots
(@teunbrand, #5093).
Bug fixes
- Fixed a bug where the
guide_custom(order)wasn't working (@teunbrand, #6195) - Fixed bug in
guide_custom()that would throw error withtheme_void()
(@teunbrand, #5856). guide_colourbar()now correctly hands offpositionandavailable_aes
parameters downstream (@teunbrand, #5930).guide_axis()no longer reserves space for blank ticks
(@teunbrand, #4722, #6069).- Fixed regression in axes where
breaks = NULLcaused the axes to disappear
instead of just rendering the axis line (@teunbrand, #5816). - Better handling of the
guide_axis_logticks(negative.small)parameter when
scale limits have small maximum (@teunbrand, #6121). - Fixed regression in
guide_bins(reverse = TRUE)(@teunbrand, #6183). - Binned guides now accept expressions as labels (@teunbrand, #6005)
- Fixed bug where binned scales wouldn't simultaneously accept transformations
and function-limits (@teunbrand, #6144). - Fixed bug in out-of-bounds binned breaks (@teunbrand, #6054)
- Fixed bug where binned guides would keep out-of-bounds breaks
(@teunbrand, #5870) - Binned scales with zero-width data expand the default limits by 0.1
(@teunbrand, #5066) - Date(time) scales now throw appropriate errors when
date_breaks,
date_minor_breaksordate_labelsare not strings (@RodDalBen, #5880) - Secondary axes respect
n.breakssetting in continuous scales (@teunbrand, #4483). - The size of the
draw_key_polygon()glyph now reflects thelinewidth
aesthetic which internally defaults to 0 (#4852). draw_key_rect()replaces aNAfill by thecolouraesthetic
(@teunbrand, #5385, #5756).- Fixed bug where
na.valuewas incorrectly mapped to non-NAvalues
(@teunbrand, #5756). - Missing values from discrete palettes are no longer inappropriately translated
(@teunbrand, #5929). - Fixed bug where empty discrete scales weren't recognised as such
(@teunbrand, #5945). - Fixed regression with incorrectly drawn gridlines when using
coord_flip()
(@teunbrand, #6293). coord_radial()now displays no axis instead of throwing an error when
a scale has no breaks (@teunbrand, #6271).coord_radial()displays minor gridlines now (@teunbrand).- Position scales combined with
coord_sf()can now use functions in the
breaksargument. In addition,n.breaksworks as intended and
breaks = NULLremoves grid lines and axes (@teunbrand, #4622). coord_sf()no longer errors when dealing with empty graticules (@teunbrand, #6052)position_fill()avoids stacking observations of zero (@teunbrand, #6338)- Fix a bug in
position_jitterdodge()where different jitters would be applied
to different position aesthetics of the same axis (@teunbrand, #5818). - Fixed bug in
position_dodge2()'s identification of range overlaps
(@teunbrand, #5938, #4327). geom_ribbon()now appropriately warns about, and removes, missing values
(@teunbrand, #6243).- Custom and raster annotation now respond to scale transformations, and can
use AsIs variables for relative placement (@teunbrand based on
@yutannihilation's prior work, #3120) geom_sf()now accepts shape names for point geometries (@sierrajohnson, #5808)geom_step()now supports theorientationargument (@teunbrand, #5936).geom_rug()prints a warning whenna.rm = FALSE, as per documentation (@pn317, #5905)geom_curve()now appropriately removes missing data instead of throwing
errors (@teunbrand, #5831).- Improved consistency of curve direction in
geom_curve()(@teunbrand, #5069). geom_abline()clips to the panel range in the vertical direction too
(@teunbrand, #6086).- The default
separameter in layers withgeom = "smooth"will beTRUE
when the data hasyminandymaxparameters andFALSEif these are
absent. Note that this does not affect the default ofgeom_smooth()or
stat_smooth()(@teunbrand, #5572). - The bounded density option in
stat_density()uses a wider range to
prevent discontinuities (#5641). - Fixed bug in
stat_function()so x-axis title now produced automatically
when no data added. (@phispu, #5647). stat_summary_2d()andstat_bin_2d()now deal with zero-range data
more elegantly (@teunbrand, #6207).stat_summary_bin()no longer ignoreswidthparameter (@teunbrand, #4647).- Fixed bug where the
ggplot2::-prefix did not work withstage()
(@teunbrand, #6104). - Passing empty unmapped aesthetics to layers raises a warning instead of
throwing an error (@teunbrand, #6009). - Staged expressions are handled more gracefully if legends cannot resolve them
(@teunbrand, #6264). theme(strip.clip)now defaults to"on"and is independent of Coord
clipping (@teunbrand, 5952).- Fixed bug in
facet_grid(margins = TRUE)when using expresssions
(@teunbrand, #1864). - Prevented
facet_wrap(..., drop = FALSE)from throwing spurious errors when
a character facetting variable containedNAs (@teunbrand, #5485).
Developer facing
Utilities
- New helper function
gg_par()to translate ggplot2's interpretation of
graphical parameters to {grid}'s interpretation (@teunbrand, #5866). - New roxygen tag
@aestheticsthat takes a Geom, Stat or Position class and
generates an 'Aesthetics' section. - New
make_constructor()function that builds a standard constructor for
Geom and Stat classes (@teunbrand, #6142). - New
element_point()andelement_polygon()that can be given to
theme(point, polygon)as an extension point (@teunbrand, #6248). - The helper function
is_waiver()is now exported to help extensions to work
withwaiver()objects (@arcresu, #6173). update_geom_defaults()andupdate_stat_defaults()have a reset mechanism
when usingnew = NULLand invisible return the previous defaults (#4993).- New
reset_geom_defaults()andreset_stat_defaults()to restore all geom or
stat default aesthetics at once (@teunbrand, #5975). - New function
complete_theme()to replicate how themes are handled during
plot building (#5801). - New function
get_strip_labels()to retrieve facet labels (@teunbrand, #4979) - The ViewScale class has a
make_fixed_copy()method to permit
copying trained position scales (#3441).
Internal changes
- Facet gains a new method
setup_panel_paramsto interact with the
panel_params setted by Coord object (@Yunuuuu, #6397, #6380) continuous_scale()andbinned_scale()sort thelimits
argument internally (@teunbrand).Scale$get_labels()format expressions as lists.- Using
after_scale()in theGeom*$default_aesfield is now
evaluated in the context of data (@teunbrand, #6135) - Improvements to
pal_qualitative()(@teunbrand, #5013) - Panel clipping responsibility moved from Facet class to Coord class through
newCoord$draw_panel()method. - Rearranged the code of
Facet$draw_panels()method (@teunbrand). - Added
ggclass tolabs()(@phispu, #5553). - The plot's layout now has a coord parameter that is used to prevent setting
up identical panel parameters more than once (#5427) - Applying defaults in
geom_sf()has moved from the internalsf_grob()to
GeomSf$use_defaults()(@teunbrand). - New
Facet$draw_panel_content()method for delegating panel
assembly (@Yunuuuu, #6406). - Layer data can be attenuated with parameter attributes (@teunbrand, #3175).
- When facets coerce the faceting variables to factors, the 'ordered' class
is dropped (@teunbrand, #5666). stat_align()skips computation when there is only 1 group and therefore
alignment is not necessary (#5788).position_stack()skips computation when allxvalues are unique and
therefore stacking is not necessary (#5788).- The summary function of
stat_summary()andstat_summary_bin()is setup
once in total instead of once per group (@teunbrand, #5971) - Removed barriers for using 2D structures as aesthetics (@teunbrand, #4189).
- Stricter check on
register_theme_elements(element_tree)(@teunbrand, #6162) - The
legend.key.widthandlegend.key.heightcalculations are no
longer precomputed before guides are drawn (@teunbrand, #6339) - When
validate_subclass()fails to find a class directly, it tries
to retrieve the class via constructor functions (@teunbrand).