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_statorafter_scale. It is implemented by passing aesthetic mappings withstage()orafter_coord()through toCoord$transform()via thepanel_paramsargument, which is already passed through to that function.Coord$transform()can then apply theafter_coordmappings 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_scaleaesthetics.after_coord()is a bit different fromafter_scale()in that it provides the placeholder valueInfto 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 thatGeoms (which already callCoord$transform()) would not have to opt in to supportingunit()s; instead,Coords 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 haveGeoms opt-in to unit support instead of havingCoords opt-in to it. I think havingCoords 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.