Commit c1979cc
Defaults for aesthetics (#142)
* Centralize aesthetic metadata in unified DefaultAesthetics structure
Restructure GeomAesthetics to prepare for centralized default aesthetic values.
Each geom now defines all aesthetic metadata (required, optional, delayed) in a
single defaults field, enabling future control over visual appearance defaults.
Key changes:
- Rename GeomAesthetics to DefaultAesthetics with unified defaults field
- Add Required, Null, Delayed variants to DefaultAestheticValue enum
- Derive supported/required lists via helper methods instead of separate fields
- Update all 22 geom implementations with new structure
- Fix semantic bugs where MAPPING validation incorrectly included Delayed aesthetics
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Apply default aesthetic values from geom definitions in writer
Implement Step 4 of the plan: writer now applies default aesthetic values
from each geom's DefaultAesthetics when building encodings. Defaults are
applied with lowest priority (after MAPPING and SETTING).
Key changes:
- Add logic in build_layer_encoding() to iterate over geom defaults
- Skip if encoding already set by MAPPING or SETTING
- Convert DefaultAestheticValue to AestheticValue via to_aesthetic_value()
- Reuse existing build_encoding_channel() for unit conversions
- Skip Required, Null, and Delayed variants (no literal defaults to apply)
Precedence order: MAPPING > SETTING > defaults (geom)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Remove hardcoded aesthetic defaults from all renderers
Remove redundant hardcoded defaults from BoxplotRenderer and PolygonRenderer.
These defaults are now handled by the centralized default aesthetics system
in build_layer_encoding().
Changes:
- BoxplotRenderer: removed default_stroke, default_fill, default_linewidth
- PolygonRenderer: removed hardcoded fill and stroke ("#888888")
Encoding-level properties (from geom defaults) override mark-level properties,
so the hardcoded values were redundant. All defaults now come from each geom's
DefaultAesthetics definition.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Add comprehensive tests for default aesthetic system
Add unit and integration tests to verify default aesthetic behavior:
Unit tests (types.rs):
- test_default_aesthetics_methods: Comprehensive test of all helper methods
(get, names, supported, required, is_supported, contains, is_required)
on a DefaultAesthetics instance with various value types
Integration tests (vegalite/mod.rs):
- test_default_aesthetics_applied: Verify defaults appear in Vega-Lite output
(stroke="black", opacity=1.0)
- test_setting_overrides_default: Verify SETTING takes precedence over defaults
- test_mapping_overrides_default: Verify MAPPING takes precedence over defaults
- test_null_defaults_not_applied: Verify Null variants don't create encodings
Also adds get() helper method to DefaultAesthetics for cleaner test code.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Translate linetype strings to strokeDash arrays in writer.
Use existing linetype_to_stroke_dash() function to convert linetype
strings to Vega-Lite strokeDash arrays in two places:
- SETTING parameters (e.g., SETTING linetype => 'dashed')
- Default aesthetic values (e.g., line geom's default "solid")
Named patterns like "solid", "dashed", "dotted" are converted to
numeric arrays ([6,4] for dashed), while unrecognized patterns
pass through as strings.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Adjust some aesthetics to taste
* Refactor SETTING and defaults processing in Vega-Lite writer
Unify SETTING parameter and default aesthetic processing into a single
loop to eliminate code duplication and clarify precedence order.
Changes:
- Merge separate SETTING and defaults loops into unified loop
- Use build_encoding_channel() for both (eliminates conversion duplication)
- Make precedence explicit: SETTING > defaults (both checked per aesthetic)
- Remove linetype_to_stroke_dash import (now only used in encoding.rs)
Benefits:
- Single source of truth for SETTING/defaults precedence logic
- All conversions (size, linewidth, linetype) go through same code path
- Reduced code: ~40 lines → ~28 lines
- Prepares for future writers (ggplot2, plotters) to reuse precedence logic
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Centralize SETTING/defaults precedence logic in Layer
Add Layer::get_aesthetic_value() to centralize SETTING > defaults
precedence logic, preparing for multiple writers (ggplot2, plotters).
Changes:
- Add DefaultAestheticValue::to_parameter_value() to extract literal values
(returns ParameterValue, not Option - uses Null for non-literals)
- Refactor to_aesthetic_value() to reuse to_parameter_value() (eliminates duplication)
- Add Layer::get_aesthetic_value() for SETTING > defaults resolution
- Update Vega-Lite writer to use get_aesthetic_value() (28 lines → 18 lines)
Benefits:
- Precedence logic centralized in Layer (not duplicated per writer)
- Future writers can reuse get_aesthetic_value() for consistent behavior
- Conversions (size, linewidth, linetype) remain writer-specific
- Cleaner, more maintainable code with simpler signatures
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* remove dangling test & cargo fmt
* It turns out the unreachable statement did in fact become reachable
* review area/density opacity
* Move aesthetic resolution from writer to execution phase
Aesthetic harmonization (MAPPING > SETTING > defaults) now happens
once during execution rather than per-writer. This creates a single
source of truth for aesthetic values.
Changes:
- Add resolved_aesthetics field to Layer (HashMap of resolved values)
- Add Layer::resolve_aesthetics() method called during execution
- Remove Layer::get_aesthetic_value() (logic now inlined)
- Simplify Vega-Lite writer to use resolved_aesthetics directly
- Add comprehensive tests for resolution logic
This ensures all writers handle aesthetics consistently and reduces
duplication across writer implementations.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Merge resolved_aesthetics into mappings for single source of truth
Consolidate aesthetic resolution by removing the separate resolved_aesthetics
field and inserting SETTING/defaults directly into mappings as Literal values.
The key insight is timing: resolve_aesthetics() now runs AFTER query literals
have been converted to columns, ensuring proper distinction.
Changes:
- Remove resolved_aesthetics field from Layer struct
- Update resolve_aesthetics() to insert into mappings as AestheticValue::Literal
- Move resolve_aesthetics() call to after remappings (line 733)
- Simplify Vega-Lite writer to single loop over mappings
- Update all tests to check mappings instead of resolved_aesthetics
- Add comprehensive documentation explaining query literal vs SETTING/default distinction
Flow:
1. Query literals ('foo' AS color) → parsed as Literal in mappings
2. build_layer_select_list() → converts to SQL columns
3. update_mappings_for_aesthetic_columns() → Literal → Column in mappings
4. resolve_aesthetics() → adds SETTING/defaults as NEW Literals (key change)
5. Writer → Column gets scales, Literal renders as constant value
This ensures:
- Query literals can have scales applied (they're columns)
- SETTING/defaults remain constant values (they're Literals)
- Single source of truth for all aesthetic values
- Correct precedence: MAPPING > REMAPPING > SETTING > defaults
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Fix broken test expectation
* cargo fmt
* set opaque default fill for area/density
* retarget opacity to fillOpacity when fill is supported
* Don't bake in opacity into the fill colour
* update expectations based on new defaults
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>1 parent 850a362 commit c1979cc
33 files changed
Lines changed: 899 additions & 355 deletions
File tree
- doc/syntax/layer
- src
- execute
- plot
- layer
- geom
- reader
- writer/vegalite
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
73 | 73 | | |
74 | 74 | | |
75 | 75 | | |
76 | | - | |
| 76 | + | |
77 | 77 | | |
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
81 | 81 | | |
82 | 82 | | |
83 | | - | |
| 83 | + | |
84 | 84 | | |
85 | 85 | | |
86 | 86 | | |
| |||
94 | 94 | | |
95 | 95 | | |
96 | 96 | | |
97 | | - | |
98 | | - | |
99 | | - | |
| 97 | + | |
100 | 98 | | |
101 | 99 | | |
102 | 100 | | |
| |||
114 | 112 | | |
115 | 113 | | |
116 | 114 | | |
117 | | - | |
118 | | - | |
119 | | - | |
| 115 | + | |
120 | 116 | | |
121 | 117 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
38 | | - | |
39 | 38 | | |
40 | 39 | | |
41 | 40 | | |
| |||
52 | 51 | | |
53 | 52 | | |
54 | 53 | | |
55 | | - | |
56 | 54 | | |
57 | 55 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
53 | | - | |
| 53 | + | |
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
| |||
97 | 97 | | |
98 | 98 | | |
99 | 99 | | |
100 | | - | |
| 100 | + | |
101 | 101 | | |
102 | 102 | | |
103 | | - | |
104 | | - | |
105 | | - | |
106 | | - | |
107 | | - | |
| 103 | + | |
108 | 104 | | |
109 | 105 | | |
110 | 106 | | |
| |||
157 | 153 | | |
158 | 154 | | |
159 | 155 | | |
160 | | - | |
| 156 | + | |
161 | 157 | | |
162 | 158 | | |
163 | 159 | | |
| |||
180 | 176 | | |
181 | 177 | | |
182 | 178 | | |
183 | | - | |
| 179 | + | |
184 | 180 | | |
185 | | - | |
| 181 | + | |
186 | 182 | | |
187 | 183 | | |
188 | 184 | | |
189 | 185 | | |
190 | | - | |
| 186 | + | |
191 | 187 | | |
192 | 188 | | |
193 | 189 | | |
| |||
228 | 224 | | |
229 | 225 | | |
230 | 226 | | |
231 | | - | |
| 227 | + | |
232 | 228 | | |
233 | 229 | | |
234 | | - | |
| 230 | + | |
235 | 231 | | |
236 | 232 | | |
237 | 233 | | |
| |||
248 | 244 | | |
249 | 245 | | |
250 | 246 | | |
251 | | - | |
| 247 | + | |
252 | 248 | | |
253 | 249 | | |
254 | | - | |
| 250 | + | |
255 | 251 | | |
256 | 252 | | |
257 | 253 | | |
| |||
1127 | 1123 | | |
1128 | 1124 | | |
1129 | 1125 | | |
| 1126 | + | |
| 1127 | + | |
| 1128 | + | |
| 1129 | + | |
| 1130 | + | |
1130 | 1131 | | |
1131 | 1132 | | |
1132 | 1133 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
| 4 | + | |
4 | 5 | | |
5 | 6 | | |
6 | 7 | | |
| |||
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
14 | | - | |
15 | | - | |
16 | | - | |
17 | | - | |
18 | | - | |
19 | | - | |
20 | | - | |
21 | | - | |
22 | | - | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
23 | 24 | | |
24 | | - | |
25 | | - | |
26 | 25 | | |
27 | 26 | | |
28 | 27 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
17 | | - | |
18 | | - | |
19 | | - | |
20 | | - | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
26 | 26 | | |
27 | | - | |
28 | | - | |
29 | 27 | | |
30 | 28 | | |
31 | 29 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
| 4 | + | |
4 | 5 | | |
5 | 6 | | |
6 | 7 | | |
| |||
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
14 | | - | |
15 | | - | |
16 | | - | |
17 | | - | |
18 | | - | |
19 | | - | |
20 | | - | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
25 | 27 | | |
26 | | - | |
27 | | - | |
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
7 | | - | |
| 7 | + | |
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
23 | | - | |
24 | | - | |
| 23 | + | |
| 24 | + | |
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
29 | | - | |
30 | | - | |
31 | | - | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
32 | 40 | | |
33 | 41 | | |
34 | 42 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | | - | |
34 | | - | |
35 | | - | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
36 | 39 | | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
| |||
547 | 547 | | |
548 | 548 | | |
549 | 549 | | |
550 | | - | |
551 | | - | |
552 | | - | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
553 | 553 | | |
554 | 554 | | |
555 | 555 | | |
556 | 556 | | |
557 | 557 | | |
558 | 558 | | |
559 | 559 | | |
560 | | - | |
561 | | - | |
562 | | - | |
563 | | - | |
564 | | - | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
565 | 565 | | |
566 | 566 | | |
567 | 567 | | |
| |||
0 commit comments