-
Notifications
You must be signed in to change notification settings - Fork 55
Explicit aesthetics / scales #505
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
Merged
Merged
Conversation
This file contains hidden or 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
HLineshas only one argument but it relates to the Y axis.BarPlot,RainCloud,Density,Violin,Errorbars,Rangebarsand probably others have two different orientations, and what scales the arguments relate to is dependent on an attribute such asdirectionororientation.The only color attribute that's handled is
color, but not others like scatter'sstrokecolor. This is also because thecolorhandling assumed the related existence of attributes likecolormapandcolorrangewhich help transform numbers to colors on Makie's side. For better or worse, these often do not exist for other color attributes likestrokecolorthough. 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
mappings 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,AesMarkerand 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 ofHLineshas an effect on theAesYaesthetic.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 theorientationattribute. (Note that another new functionmandatory_attributesis 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
Violinnow 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
scalefunction 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 theHLinescolor is mapped to the:second_colorscale 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
palettekeyword, keyed by plotting function arguments, cannot handle this problem. Therefore, a new option todrawcalledscalesis 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 likecolorbut rather relate to abstract aesthetics).Here we pass a one-element palette containing only the color red for our new
second_colorscale: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
ylabelhere, 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 theAesColoraesthetic, this also required to rewrite the pipeline to avoid early rescaling of input data. WhileAesColorcolumns will by default be converted to aVector{RGBAf},Heatmapcan currently not handle this input so the conversion has to be handled instead by passingcolormapandcolorrangekeywords. Each plot type can define customto_entrymethods 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 usestrokecolorin amappingforScatter, 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
sorterandrenamerinmappingto 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
categoryproperty with which one can override domain, ordering and labels in one go, while also accessing more flexible label types likeLaTeXStrings orrichtext: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 therecontourfdoesn't fit into the current scheme