-
Notifications
You must be signed in to change notification settings - Fork 46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Explicit aesthetics / scales #505
Merged
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
… it using `visual`
This was
linked to
issues
Jul 16, 2024
This was
linked to
issues
Jul 16, 2024
Open
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Problem description
Currently, AlgebraOfGraphics does not really have a concept of "aesthetics" as in ggplot, the logic is rather based around shared keyword arguments and conventional use of positional arguments. Arguments 1, 2 and 3 are expected to relate to the X, Y or Z axis. This is not true for lots of plots however, for example
HLines
has only one argument but it relates to the Y axis.BarPlot
,RainCloud
,Density
,Violin
,Errorbars
,Rangebars
and probably others have two different orientations, and what scales the arguments relate to is dependent on an attribute such asdirection
ororientation
.The only color attribute that's handled is
color
, but not others like scatter'sstrokecolor
. This is also because thecolor
handling assumed the related existence of attributes likecolormap
andcolorrange
which help transform numbers to colors on Makie's side. For better or worse, these often do not exist for other color attributes likestrokecolor
though. The only way to currently set these to colors is to pass a vector of them manually.Another problem with the current implementation is that all layers sharing some variable in their
mapping
s are assumed to be connected. So if you have a line plot withmapping(color = :A)
but also a scatter plot withmapping(color = :B)
, then you will always get a merged legend with lines and scatters overlaid, even if the two are plotting disjoint sets of data and you'd rather prefer to have a separate legend for scatters and lines.Related issues
These issues are either fixed directly by this PR, or this PR introduces a new way of solving the problems described therein:
#75
#97
#262
#329
#365
#385
#427
#434
#463
#469
#473
#487
#491
#504
Implemented solution
This PR internally introduces the notion of an
Aesthetic
, examples areAesX
,AesY
,AesColor
,AesMarker
and so on. These are decoupled from any specific keywords or argument positions and abstractly represent the visual effect of some plotting function argument. For example, the only argument ofHLines
has an effect on theAesY
aesthetic.Each plotting function now has to have a declared
aesthetic_mapping
. Here's an example forViolin
, which flips the mapping of its positional arguments depending on the value of theorientation
attribute. (Note that another new functionmandatory_attributes
is used to declare attributes that are strictly necessary to resolve the aesthetic mapping, so AlgebraOfGraphics requires these to be set statically and not pulled in via the theme, as the theme should not semantically change the plots.)Internally, the fitting of categorical or continuous scales is now routed through these aesthetics. This means the orientation keyword for
Violin
now has the expected effect on the x and y axes:We can further combine the Violin plot with an HLine plot to mark certain positions of interest, however when we add a color mapping to get a legend entry, the categories of Violin and HLine merge:
This can now be handled by separating the two color scales. For this purpose, the
scale
function can be used to define an identifier, which can then be associated with a mapped variable by extending the=>
mechanism with a fourth possible option. Note how the legend splits now that theHLines
color is mapped to the:second_color
scale identifier:While the legend is now adequately split, both color scales use the same default colormap. The old system which relied on passing palettes to the
palette
keyword, keyed by plotting function arguments, cannot handle this problem. Therefore, a new option todraw
calledscales
is introduced, which allows to pass certain options keyed by the default or custom identifiers for each scale (default identifiers areX
,Y
,Color
, and others, capitalized to show that they are not directly mirroring the keywords likecolor
but rather relate to abstract aesthetics).Here we pass a one-element palette containing only the color red for our new
second_color
scale:Note that this mechanism also allows to change other attributes like scale labels. We can make use of that to define a label for the y axis, which is unlabelled because Violin and HLines plot different columns there (in principle we could have overridden the axis attribute
ylabel
here, but this new mechanism works the same across all scales, so it is preferable) .The new implementation removes some hacks around the handling of unusual plot types like
Heatmap
, which uses its third positional argument for color. Aside from an aesthetic mapping which maps argument 3 to theAesColor
aesthetic, this also required to rewrite the pipeline to avoid early rescaling of input data. WhileAesColor
columns will by default be converted to aVector{RGBAf}
,Heatmap
can currently not handle this input so the conversion has to be handled instead by passingcolormap
andcolorrange
keywords. Each plot type can define customto_entry
methods in order to compute the plot specification given the raw input data and fitted scales. By default, entries will be passed the aesthetic-converted columns which now makes it possible to usestrokecolor
in amapping
forScatter
, for example:Another benefit of being able to address scales directly, is the ability to override category values and labels. Currently, one can only use
sorter
andrenamer
inmapping
to bring categorical values into a certain order and change their labels. However, this is more difficult if multiple mappings are merged where the merged categories cannot be sorted together, or for the case where not all categories that are supposed to be shown are present in the data.Now, there's a
category
property with which one can override domain, ordering and labels in one go, while also accessing more flexible label types likeLaTeXString
s orrich
text:For the x and y axes, the "palette" can be overridden, too, in order to introduce visual groupings:
Discussion points
It's maybe a bit confusing thatscales = (; color = (; ...
does not meanmapping(color = ...)
but it meansAesColor
(there's a lookup happening internally from symbol toAesthetic
. The problem is that I wanted to keep the generic dict-like configuration structure, so symbols as keys. Maybe it could bescales = (; Color = ...
to signify that it's something different.What about multiple signatures for plotting functions, like errorbars having either symmetrical or asymmetrical bars?TODOs
scales
, currently invalid keywords will be ignored therecontourf
doesn't fit into the current scheme