Skip to content

Circumventing scales #5142

Closed
Closed
@teunbrand

Description

@teunbrand

To recap the discussion of #4821, passing (unmapped) aesthetics with length > 1 outside aes() is not ideal. However, it is currently necessary to bypass mapping values to a scale. Hence, there seems to be a need to pass values parallel to the data that circumvent scales, that isn't passed outside aes().

This brings us to a discussion about what we can do to more formally support circumventing scales. In #4821 (comment), I suggested that scales should ignore AsIs objects / I() input.

The current state is that the scale type for AsIs objects default to scale_*_identity(). In simple situations, the AsIs class already does what we want: we don't want to map it to a scale, so we use the identity scale to keep the values verbatim. The problem with this situation arises when another mapping, in another layer, does require a non-identity scale. There are no solutions for this problem in vanilla ggplot2.

Because there is a need to pass verbatim values, doing so outside aes() is discouraged, and the identity scale solution has unacceptable drawbacks, I think it might make sense to have scales explicitly ignore AsIs objects.

Here are the upsides:

  • The semantic meaning of I() would change very little. It still means 'pass these values verbatim'.
  • They are proper aesthetics, so data parallelism would be ensured (Mismatched fill colour with geom_dotplot #4821) because they're evaluated during Layer$compute_aesthetics() and not Geom$use_defaults().
  • No need for scale_*_identity() to get involved, so no clashes with other scales.

The drawbacks are:

  • Need to rewrite scale methods to ignore AsIs objects on purpose, which might have some small overhead.
  • There might be a rare case in which people redundantly specificy e.g. aes(size = I(value)) and use scale_size_identity() simultaneously in order to construct a legend. While I'm not certain it poses a problem, but we might discourage this by having scale_*_identity() explicitly warn when it sees AsIs objects.

Ambiguities:

  • There is no scale_{x/y}_identity(), so what should happen if people use aes(x = I(var))? Should they be interpreted as npc units between 0-1, just like after coord transformation? Should they just behave as regular positions?
  • What should the effect of AsIs objects be on automatic grouping? Intuitively, I think it should be inert.

I'd be happy to discuss, and, if people see some merit in this, prepare a PR to explore implementation.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions