Assorted scale fixes and improvements#90
Merged
Conversation
- Renamed all scale type `new` methods that return `ConfiguredScale` to `configured` - Renamed LinearScale::new_color to LinearScale::configured_color for consistency - Removed #[allow(clippy::new_ret_no_self)] attributes as they're no longer needed - Updated all usage sites including examples, tests, and internal macros - Applied consistent naming convention across all scale types: - LinearScale::configured() - QuantizeScale::configured() - ThresholdScale::configured() - QuantileScale::configured() - BandScale::configured() - PointScale::configured() - SymlogScale::configured() - OrdinalScale::configured() - LogScale::configured() - PowScale::configured() This change improves API clarity by making it explicit that these methods return a configured scale instance rather than the scale type itself. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Added comprehensive documentation as docstrings on each scale struct describing all available configuration options, their types, defaults, and behavior: - LinearScale: clamp, range_offset, round, nice - QuantizeScale: nice - ThresholdScale: no options - QuantileScale: no options - BandScale: align, band, padding_inner, padding_outer, round, range_offset - PointScale: align, padding, round, range_offset - SymlogScale: constant, clamp, range_offset, round, nice - OrdinalScale: no options - LogScale: base, clamp, range_offset, round, nice - PowScale: exponent, clamp, range_offset, round, nice This documentation makes the scale configuration options discoverable through IDE tooltips and generated documentation, improving the developer experience. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Implement scale_type() method for all scale types, returning Vega-compatible scale type names in lowercase: - linear, pow, symlog, log - quantize, quantile, threshold - band, point, ordinal This provides a standard way to identify scale types programmatically. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Implement invert() method on ScaleImpl trait and ConfiguredScale that: - Accepts ArrayRef input and returns ArrayRef output - Parallels the scale() method pattern for consistency - Provides efficient array-based inverse transformations - Handles type conversions internally (casts to Float32) This addresses the feature request for VegaFusion's DataFusion UDF implementation, eliminating the need for scalar loops and dependency on avenger_common::ScalarOrArray. Implemented for scales that support inversion: - LinearScale - PowScale - LogScale - SymlogScale Added comprehensive tests to verify the new functionality works correctly with different input types and scale configurations. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…ansformations This commit adds a new normalize() method to ConfiguredScale that applies the nice domain transformation and returns a new scale with the nice option disabled. Changes: - Add compute_nice_domain() method to ScaleImpl trait with default implementation - Implement compute_nice_domain() for LinearScale, LogScale, PowScale, SymlogScale, and QuantizeScale - Add normalize() method to ConfiguredScale that applies nice transformation and disables nice option - Add comprehensive tests for normalize() method with different nice option values - Update doctest imports to use correct module paths The normalize() method enables callers to easily retrieve nice domain extents by calling scale.normalize()?.numeric_interval_domain(), providing a scale with the nice domain applied and the nice option disabled to avoid repeated calculations. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add zero boolean option to all scale configurations (linear, log, pow, symlog, quantize) - Implement apply_normalization methods that handle both zero and nice transformations - Zero extension applied before nice calculations for proper ordering - Zero behavior: both positive → set min to zero, both negative → set max to zero - LogScale ignores zero option (invalid in logarithmic space) - Power and Symlog scales delegate to LinearScale for normalization - Update normalize() method to apply both zero and nice transformations - Add comprehensive tests for zero functionality and combined zero+nice behavior - Update documentation to include zero option for all scale types 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Create TimeScale struct implementing ScaleImpl trait - Support Date32, Date64, and Timestamp Arrow types - Implement temporal to numeric scaling with proper null handling - Add timezone configuration option (not yet connected) - Include basic tests for Date32 and Timestamp scaling - Add new error types for temporal operations This is the foundation for time scale support in avenger-scales, addressing limitations in Vega's local/UTC-only approach by preparing for configurable timezone support. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Implement timezone configuration and parsing (IANA timezones, UTC, local) - Add nice interval generation with calendar-aware boundaries - Implement tick generation algorithm with D3-inspired interval hierarchy - Add comprehensive time interval system (millisecond to year) - Support calendar arithmetic (month/year offsets, DST handling) - Add tests for nice domains, tick generation, and timezone parsing Calendar features: - Interval hierarchy: ms, sec, min, hour, day, week, month, year - Smart interval selection based on domain span and target tick count - Floor/ceil operations to interval boundaries - Proper handling of variable month lengths and leap years - Week start configuration support (future enhancement) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add numeric to temporal inversion for all supported types - Handle null values properly in inversion - Support Date32, Date64, and all Timestamp variants - Add comprehensive test for scale inversion - Create helper function for optional millisecond arrays The invert method reverses the scale operation, converting numeric range values back to temporal domain values. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add safe time construction wrappers that never panic - Handle spring-forward gaps by jumping to next valid hour - Handle fall-back overlaps with configurable strategies - Update interval operations (floor, offset) for DST safety - Fix tick generation to avoid duplicates during fall-back - Add DST transition detection utilities - Ensure nice domain calculations are DST-safe DST handling features: - DstTransition enum to detect spring-forward/fall-back - DstStrategy enum for ambiguous time resolution - safe_with_hour() for DST-aware hour setting - safe_and_hms() for creating times during transitions - Actual duration calculation for intervals Tests added: - Spring forward transition (2:00 AM -> 3:00 AM) - Fall back transition (repeated 1:00 AM hour) - Tick generation across DST boundaries - Non-DST timezone verification This ensures TimeScale operations never panic due to DST transitions and provides predictable behavior for all edge cases. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add compute_actual_duration_millis() to calculate true duration across DST transitions - Update scale() method to use actual duration when DST transitions occur in domain - Update invert() method with iterative refinement for accurate DST-aware inversion - Update scale_timestamp_values() to handle all timestamp types with DST awareness - Add comprehensive tests for spring-forward and fall-back scaling scenarios - Ensure visual accuracy: 3-hour actual duration during spring-forward, 5-hour during fall-back All DST tests passing. Scale operations now correctly handle domains spanning DST transitions. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…mpletion - Mark DST Phase 5 as complete (scale operations now DST-aware) - Update checkboxes for completed calendar-aware algorithms - Add summary of remaining work organized by priority - Update status to reflect low risk level now that core functionality is complete Remaining high priority work: - Implement tick_format() method for formatting - Handle remaining edge cases (leap years, month lengths) - Add tests for European and Southern hemisphere DST 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
The plan should remain in the ignored tasks/ directory, not tracked in git.
- Create TemporalTickFormatter that adapts format based on tick interval - Override scale_to_string() to use custom formatter for temporal values - Format strings change based on interval: years show %Y, days show %b %d, hours show %H:%M - Handle all temporal types: Date32, Date64, Timestamp with/without timezone - Add comprehensive test for tick formatting at different time scales - Integrate with existing coerce/format system by implementing DateFormatter, TimestampFormatter, and TimestamptzFormatter traits The formatter automatically selects appropriate format strings: - Milliseconds: %H:%M:%S%.3f - Seconds: %H:%M:%S - Minutes/Hours: %H:%M - Days/Weeks: %b %d - Months: %B - Years: %Y 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Fix band scale rounding to match Vega's behavior for pixel-perfect rendering - When round=true and range starts at 0 with no padding, keep start position at 0 to avoid sub-pixel shifts - Update bandwidth calculation to use floored step value when rounding is enabled - Add comprehensive tests to verify rounding behavior across various ranges and with padding - Update existing test to reflect the new Vega-matching behavior This fixes pixel-diff discrepancies between Vega and VegaFusion when using band scales with the round option enabled. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Remove special case that forced start position to 0 when round=true - Apply alignment offset consistently for all ranges, matching Vega's implementation - Fix 2-pixel offset and bandwidth discrepancy (38px vs 37px) reported in bug - Update tests to reflect correct Vega-matching positions - Add test case that verifies exact position match with Vega for 8-band scenario This fully resolves the pixel-diff discrepancies between Vega and VegaFusion band scales with round option enabled.
- Remove camelCase support from band scale (paddingInner, paddingOuter) - Add comprehensive option validation infrastructure: - OptionConstraint enum for various validation rules (Boolean, Float, ranges, etc.) - OptionDefinition struct to define valid options with constraints - Required trait method option_definitions() returning valid options - Default validate_options() implementation using definitions - Implement option_definitions() for all scale types with proper constraints: - band: align, band, padding, padding_inner, padding_outer, round, range_offset - linear: clamp, range_offset, round, nice, zero, default - log: base (custom validator), clamp, range_offset, round, nice, zero, default - point: align, padding, round, range_offset - pow: exponent, clamp, range_offset, round, nice, zero, default - symlog: constant, clamp, range_offset, round, nice, zero, default - quantile: default - quantize: nice, zero, default - ordinal: default - threshold: default - time: timezone, nice, interval, week_start, locale, default - Add detailed documentation for validation system - Fix clippy warnings and formatting issues 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Implements Vega-compatible padding for linear, log, pow, and symlog scales.
Padding expands the scale domain by the specified number of pixels on each
side of the range, applied before zero and nice transformations.
- Add padding option (NonNegativeFloat) to all quantitative scales
- Implement scale-specific padding algorithms:
- Linear: Direct domain expansion from center
- Log: Transform to log space, apply padding, transform back
- Pow: Transform to power space, apply padding, transform back
- Symlog: Transform to symlog space, apply padding, transform back
- Update symlog transforms to use ln_1p/exp_m1 for numerical stability
- Reset padding to 0 in normalized scales to prevent double application
- Handle non-numeric ranges gracefully by ignoring padding
- Add comprehensive tests for all scale types
The implementation matches Vega's behavior where padding expands the domain
to accommodate pixel margins before other domain adjustments.
- Modified normalize() to check scale's supported options before adding - Only sets 'zero', 'nice', and 'padding' if they're in option_definitions() - Prevents validation errors for scales that don't support these options - Added comprehensive tests to verify correct behavior for different scale types This fixes the issue where point, band, and ordinal scales were receiving unsupported options like 'zero' and 'nice' during normalization, which caused validation errors in VegaFusion. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Modified normalize() to check scale's supported options before adding - Only sets 'zero', 'nice', and 'padding' if they're in option_definitions() - Prevents validation errors for scales that don't support these options - Added comprehensive tests to verify correct behavior for different scale types This fixes the issue where point, band, and ordinal scales were receiving unsupported options like 'zero' and 'nice' during normalization, which caused validation errors in VegaFusion. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Replace individual directory builds with workspace build - Remove references to non-existent directories (avenger-vega, scatter-panning) - Use standard cargo build --workspace command 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Replace format!("Unsupported image URL: {}", s) with
format!("Unsupported image URL: {s}") to satisfy
clippy::uninlined_format_args lint
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace all format!() calls to use inline variable syntax
(e.g., format!("{}", var) -> format!("{var}")) to satisfy
clippy::uninlined_format_args lint in newer Rust versions.
Changes made in:
- avenger-scales: format_num, scalar, band, coerce, time, mod
- avenger-app: app.rs
- avenger-winit-wgpu: file_watcher.rs, lib.rs
- examples/wgpu-winit: util.rs
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Fix remaining clippy::uninlined_format_args warnings in: - examples/wgpu-scales/src/util.rs - examples/iris-pan-zoom/src/util.rs 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
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
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.
Assorted scale updates and improvements I made while working on integrating avenger-scales with vegafusion. Didn't get all the way there, but these are generally useful updates.