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
quantiles
parameter that replacesdraw_quantiles
now 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$labels
property (@teunbrand, #5894). - In binning stats, the default
boundary
is now chosen to better adhere to
thenbin
argument. 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
size
tolinewidth
translation in
geom_bar()
/geom_col()
(#4848). -
The
fatten
argument 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 thedir
argument for additional control
over panel directions. They absorb interactions with the now-deprecated
as.table
argument. Internallydir = "h"
ordir = "v"
is deprecated
(@teunbrand, #5212). -
coord_trans()
was renamed tocoord_transform()
(@nmercadeb, #5825).
Improvements
Themes
- The
theme()
function offers new arguments:geom
to set defaults for layer aesthetics (#2239).spacing
/margins
as root elements that are inherited by all other
spacings and (non-text) margins (@teunbrand, #5622).palette.{aes}.discrete
andpalette.{aes}.continuous
which 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.widths
andpanel.heights
to control the (absolute) size of the
panels (#5338, @teunbrand).legend.key.justification
to control the alignment of legend keys
(@teunbrand, #3669)
- Built-in
theme_*()
functions have new arguments:ink
/paper
/accent
to control foreground, background and highlight
colours respectively of the whole plot (@teunbrand, #6063, @EvaMaeRey, #6438).header_family
to easily set the font for headers and titles (#5886)- To accommodate,
plot.subtitle
,plot.caption
andplot.tag
now
inherit from the roottext
element instead of thetitle
element.
- 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
fill
of thepanel.border
theme 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.grid
hierarchy level instead of
thepanel.grid.major
andpanel.grid.minor
levels.
- 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
palette
argument. The default,
palette = NULL
will retrieve palettes from the theme (see the Themes section).
This replaces the old options-basedtype
system, with some limited backward
compatibility (@teunbrand, #6064). - All scales now expose the
aesthetics
parameter (@teunbrand, #5841) - All position scales now use the same definition of
x
andy
aesthetics.
This lets uncommon aesthetics likexintercept
expand scales as usual.
(#3342, #4966, @teunbrand) - In continuous scales, when
breaks
is a function andn.breaks
is set, the
n.breaks
will be passed to thebreaks
function. Previously,n.breaks
only applied to the default break calculation (@teunbrand, #5972). - Changes in discrete scales:
- Added
palette
argument, which can be used to customise spacings between
levels (@teunbrand, #5770) - Added
continuous.limits
argument to control the display range
(@teunbrand, #4174, #6259). - Added
minor_breaks
argument. This only makes sense in position scales,
where it affects the placement of minor ticks and minor gridlines (#5434). - Added
sec.axis
argument. 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
breaks
yields 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_breaks
anddate_labels
arguments 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
reverse
argument 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
bothx
andy
is 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
linewidth
aesthetic is now applied and replaces thelabel.size
argument. - The
linetype
aesthetic is now applied. - New
border.colour
argument to set the colour of borders. - New
text.colour
argument 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,slope
andintercept
are new computed
variables instat_qq_line()
(@teunbrand, #6087). stat_ecdf()
now has an optionalweight
aesthetic (@teunbrand, #5058).stat_ellipse
now 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 = NA
is now interpreted to mean 'no line' instead of raising errors
(@teunbrand, #6269).
position_dodge()
andposition_jitterdodge()
now have areverse
argument
(@teunbrand, #3610)position_jitterdodge()
now dodges bygroup
(@teunbrand, #3656)geom_rect()
can now derive the required corners positions fromx
/width
ory
/height
parameterisation (@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.fill
parameter 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 varyingfill
oralpha
in 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
/center
parametrisation rather
thanorigin
, following instat_bin()
's footsteps (@teunbrand). - Reintroduced
drop
argument 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 haveposition
argument
(@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.inside
andlegend.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 offposition
andavailable_aes
parameters downstream (@teunbrand, #5930).guide_axis()
no longer reserves space for blank ticks
(@teunbrand, #4722, #6069).- Fixed regression in axes where
breaks = NULL
caused 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_breaks
ordate_labels
are not strings (@RodDalBen, #5880) - Secondary axes respect
n.breaks
setting 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 aNA
fill by thecolour
aesthetic
(@teunbrand, #5385, #5756).- Fixed bug where
na.value
was incorrectly mapped to non-NA
values
(@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
breaks
argument. In addition,n.breaks
works as intended and
breaks = NULL
removes 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 theorientation
argument (@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
se
parameter in layers withgeom = "smooth"
will beTRUE
when the data hasymin
andymax
parameters andFALSE
if 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 ignoreswidth
parameter (@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 containedNA
s (@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
@aesthetics
that 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 = NULL
and 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_params
to 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_aes
field 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
gg
class 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 allx
values 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.width
andlegend.key.height
calculations 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).