Commit fcc07d1
Variable width/color/opacity lines (#298)
* let claude manage writer details somewhere
* Add automatic line segmentation for variable material aesthetics
Automatically detects when material aesthetics (stroke, linetype) vary
within partition groups and converts to segmented rendering. Uses Vega-Lite
transforms (window, flatten, calculate) instead of data restructuring.
Implementation uses efficient vectorized Polars operations for group
boundary detection and preserves the unified dataset architecture with
proper source filter integration.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Unify change detection logic for line segmentation and text RLE
Extract common `find_change_starts()` function that finds row indices
where any specified column changes value. Uses efficient slice-based
comparison instead of shift() to avoid allocation and null handling.
Both line segmentation and text font run-length encoding now use the
same underlying implementation. Inline former `find_group_boundaries()`
stub at its single call site.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Simplify line segmentation using partition_by for discrete/continuous detection
Key changes:
- Use layer.partition_by to distinguish discrete vs continuous material aesthetics
- Discrete aesthetics (linetype, discrete stroke/linewidth) already in partition_by
from execute phase - define groups naturally, no action needed
- Continuous aesthetics (numeric stroke/linewidth) checked for within-group variation
and trigger segmentation if they vary, but never added to partition columns
- Remove linetype from material aesthetics check (always discrete, already handled)
- Remove LineSegmentMetadata struct - use layer.partition_by directly in finalize()
This leverages existing information computed during execute phase rather than
re-inferring or passing through metadata.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Also let `PreparedData::Single` have metadata field
* Add metadata to PreparedData::Single and use trail marks for varying linewidth
Key changes:
1. Add metadata field to PreparedData::Single (matching Composite structure)
2. Refactor LineRenderer to use Single with metadata instead of Composite hack
3. Pass varying_aesthetics vector as metadata to communicate segmentation needs
Trail mark support:
4. Use Vega-Lite trail mark when linewidth varies (native variable-width support)
5. Translate line encodings to trail: strokeWidth→size, stroke→fill, opacity→fillOpacity
6. Set stroke:null on trail mark to disable border
Segmentation logic:
7. Only linewidth varies → trail mark, no segmentation
8. Only stroke varies → line mark, segmented
9. Both vary → trail mark, segmented (with varying width per segment)
Implementation:
10. Build segment_fields vector: [x, y] + conditionally [size]
11. Loop over segment_fields to create window/calculate transforms and update encodings
12. Capture next row's size value in window transform for smooth width transitions
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Add opacity as material aesthetic requiring segmentation
Treat opacity like stroke: varying opacity within partition groups triggers
segmentation. This ensures each segment can have its own opacity value.
Behavior:
- Only opacity varies → line mark, segmented
- Opacity + linewidth → trail mark, segmented
- Opacity + stroke → line mark, segmented
- All three → trail mark, segmented
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Unify line and path renderers into single PathRenderer
Remove LineRenderer and consolidate all line/path rendering logic into
PathRenderer. Both geom types were already functionally identical:
- Both map to "line" mark in Vega-Lite
- Both add order encoding to preserve data order
- Both need identical material aesthetic handling
Changes:
- Remove LineRenderer struct
- PathRenderer now handles both line and path geoms
- Updated get_renderer() to return PathRenderer for both GeomType::Line and GeomType::Path
- Updated documentation to reflect unified renderer
This eliminates code duplication while maintaining all functionality. The actual
sorting/ordering happens in the execute phase via SQL ORDER BY, and both geoms
preserve that order through the __ggsql_row_index__ column.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Add tests for PathRenderer line segmentation and trail mark conversion.
Tests cover: (1) metadata detection of varying material aesthetics,
(2) trail mark conversion for varying linewidth, and (3) segmentation
transforms for varying stroke/opacity.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* cargo fmt
* pay obeisance to clippy
* add examples
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>1 parent fd4e8c9 commit fcc07d1
6 files changed
Lines changed: 982 additions & 133 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
569 | 569 | | |
570 | 570 | | |
571 | 571 | | |
572 | | - | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
573 | 575 | | |
574 | 576 | | |
575 | 577 | | |
| |||
578 | 580 | | |
579 | 581 | | |
580 | 582 | | |
581 | | - | |
582 | | - | |
583 | | - | |
584 | | - | |
585 | | - | |
586 | | - | |
587 | | - | |
588 | | - | |
589 | | - | |
590 | | - | |
591 | | - | |
592 | | - | |
593 | | - | |
594 | | - | |
| 583 | + | |
595 | 584 | | |
596 | | - | |
597 | | - | |
598 | | - | |
599 | | - | |
600 | | - | |
601 | | - | |
602 | | - | |
603 | | - | |
604 | | - | |
605 | | - | |
606 | | - | |
607 | | - | |
608 | | - | |
609 | | - | |
610 | | - | |
611 | | - | |
612 | | - | |
613 | | - | |
614 | | - | |
615 | | - | |
616 | | - | |
617 | | - | |
618 | | - | |
619 | | - | |
620 | | - | |
621 | | - | |
622 | | - | |
623 | | - | |
624 | | - | |
625 | | - | |
626 | | - | |
627 | | - | |
628 | | - | |
629 | | - | |
630 | | - | |
631 | | - | |
632 | | - | |
633 | | - | |
634 | | - | |
635 | | - | |
636 | | - | |
637 | | - | |
638 | | - | |
639 | | - | |
640 | | - | |
641 | | - | |
642 | | - | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
643 | 590 | | |
644 | 591 | | |
645 | 592 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
18 | | - | |
19 | | - | |
20 | | - | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
29 | | - | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
30 | 32 | | |
31 | 33 | | |
32 | 34 | | |
| |||
50 | 52 | | |
51 | 53 | | |
52 | 54 | | |
53 | | - | |
| 55 | + | |
| 56 | + | |
54 | 57 | | |
55 | 58 | | |
56 | 59 | | |
57 | 60 | | |
58 | | - | |
| 61 | + | |
| 62 | + | |
59 | 63 | | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
18 | | - | |
19 | | - | |
20 | | - | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
26 | | - | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
27 | 29 | | |
28 | 30 | | |
29 | 31 | | |
| |||
87 | 89 | | |
88 | 90 | | |
89 | 91 | | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
0 commit comments