Minimal PR for unit support in positional aesthetics #5690
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Following discussion on #5609 and helpful feedback from @teunbrand, @pmur002, and @thomasp85 (thanks!), this is a second proof-of-concept PR for unit support in positional aesthetics in ggplot2. This PR focuses on being a minimal implementation without hacking on the unit type system.
The basic idea here is to instead add another aesthetic evaluation stage,
after_coord
, which is akin toafter_stat
orafter_scale
. It is implemented by passing aesthetic mappings withstage()
orafter_coord()
through toCoord$transform()
via thepanel_params
argument, which is already passed through to that function.Coord$transform()
can then apply theafter_coord
mappings after it does its ownCoord
-specific transformations.Some demos:
With polar coordinates:
Some notes:
The main workhorse here is
compute_staged_aes()
, which is based on a chunk of code I factored out ofGeom$use_defaults()
for computingafter_scale
aesthetics.after_coord()
is a bit different fromafter_scale()
in that it provides the placeholder valueInf
to earlier parts of the pipeline, because it needed a non-unit()
value that would not affect scales (see the comment on that function). There should probably be a better way to do this.the implementation moves current
Coord$transform()
implementations intoCoord$transform_numeric()
. This was done so thatGeom
s (which already callCoord$transform()
) would not have to opt in to supportingunit()
s; instead,Coord
s in extension packages can opt-in simply by renaming theirtransform()
methods totransform_numeric()
. An alternative might be to leaveCoord$transform()
as-is but add aCoord$transform_unit()
method, and then haveGeom
s opt-in to unit support instead of havingCoord
s opt-in to it. I think havingCoord
s opt-in is better since it requires fewer changes in extension packages and propagates support more easily, but I could be wrong.No hacking on
unit()
is required for this implementation, nor any upstream changes to {grid}. A small set of compatibility functions would need to be added to {vctrs}, akin to how {vctrs} supplies compatibility functions for other base-R types, like Dates. These are confined toR/utilities-unit.R
, which could be turned into a PR on {vctrs}.In exchange for less "magic", this approach is a little more verbose than my original proposal and requires a little more understanding of the ggplot2 pipeline for users. Something like this in the current proposal:
could be written as this in the original proposal:
However, this new proposal has more consistent semantics and no heuristic hacking of the
unit()
datatype :). Aggunit()
subtype ofunit()
with consistent coercion rules for numerics could still be created to improve the syntax a bit (also without heuristic hacking ofunit()
); allowing something like this to work:Adding shortcuts like
as_pt()
could shorten this still, to:The
ggunit()
subtype could be added to ggplot2, or if that is not desired, I'd be happy to create a small extension package with that capability.