Skip to content

Rectangles#168

Open
teunbrand wants to merge 16 commits intoposit-dev:mainfrom
teunbrand:rectangles
Open

Rectangles#168
teunbrand wants to merge 16 commits intoposit-dev:mainfrom
teunbrand:rectangles

Conversation

@teunbrand
Copy link
Collaborator

This PR implements the rect rectangle layer and removes the tile layer.

It harmonises the center/size with the min/max parametrisation: users only have to declare 2 and the layer will use its stat to figure out the rest.
It does this by casting continuous axes to the min/max and discrete axes to the center/size parametrisation. Due to constraints on discrete scales, the discrete variant will not accept min or max parameters. Alternatively, if only the center is given, the size will be fixed to 1 and the rest unfolds as expected.

teunbrand and others added 15 commits February 27, 2026 13:51
Implements a new rect geom that supports flexible rectangle specification:
- X-direction: any 2 of {x (center), width, xmin, xmax}
- Y-direction: any 2 of {y (center), height, ymin, ymax}

Key features:
- Stat-based parameter consolidation via SQL generation
- Automatic discrete vs continuous scale detection using Schema
- Validates exactly 2 params per direction
- Generates appropriate SQL for all 6 parameter combinations per axis
- Returns different stat columns based on scale type:
  - Continuous: pos1min, pos1max, pos2min, pos2max
  - Discrete: pos1, pos2 (for band-based rendering)

Implementation follows existing patterns from histogram and bar geoms.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add 'rect' to tree-sitter grammar geom_type rule
- Add "rect" case to parser builder geom type mapping

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changes:
- Remove width/height from default_params() (use trait default)
- Treat width/height as aesthetics (columns or literals), not parameters
- RectRenderer handles x and y directions independently
- For discrete scales: extract literal width/height from encoding or default to 0.9
- Error if width/height are mapped to variable columns on discrete scales
- Support mixed continuous/discrete (e.g., continuous x + discrete y)
- Extract band size logic into helper function with early returns
- Early return from modify_spec when both directions are continuous

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Key changes:
- Add width/height to gets_default_scale() so they get proper scales with domains
  instead of Identity scales (which have scale: null)
- Simplify rect.rs stat transform using get_column_name() directly
- Merge discrete checking blocks to build SELECT and stat_columns together
- Refactor RectRenderer to avoid Result<Option<>> anti-pattern
- Flatten nesting with early exits and error closure for DRY

This fixes discrete rect layers with literal width/height (e.g., 0.7 AS width)
by ensuring scales are trained and domains are available for constant detection.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add 10 parameterized tests covering:
- All 6 x-direction parameter combinations (continuous)
- All 6 y-direction parameter combinations (continuous)
- Discrete scales with width/height
- Validation errors (param count, discrete+min/max)
- Group by filtering for width/height

Tests use a grid/loop approach to systematically verify all
rect parameter combinations and error cases.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The rect stat transform was only including group_by columns in its
SELECT list, causing non-positional aesthetics like fill and color
to be dropped unless they were literal values.

Now uses the schema to determine which columns to pass through:
- Defines consumed aesthetics once (positional params that get transformed)
- Iterates through schema and includes all non-consumed columns
- Eliminates duplicate "consumed columns" logic

Also increases default rect opacity from 0.5 to 0.8 for better visibility.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Allow rect to work with just x (or y) specified, defaulting width (or
height) to 1.0 for both discrete and continuous scales.

Changes:
- Split position expression generation into discrete and continuous variants
  - generate_discrete_position_expressions: returns (center, size) with
    size defaulting to "1.0" when not provided
  - generate_continuous_position_expressions: returns (min_expr, max_expr)
    with 7 valid parameter combinations including center-only
- Discrete scales: center-only specification defaults to 1.0 bandwidth
- Continuous scales: center-only specification defaults to width=1.0
  (xmin = x - 0.5, xmax = x + 0.5)
- Improved variable naming: x_expr_1/x_expr_2 instead of x_expr_min/x_expr_max
  to reflect dual usage (center/size for discrete, min/max for continuous)
- Updated tests to verify default behavior

All 18 rect tests passing.
Add support for specifying width/height via SETTING clause in addition to
MAPPING. Implements precedence: MAPPING > SETTING > default 1.0.

Changes:
- stat_rect now checks both aesthetics (MAPPING) and parameters (SETTING)
  for width/height values
- Uses ParameterValue::to_string() to convert SETTING values to SQL literals
- Precedence order ensures MAPPING columns take priority over SETTING literals,
  which take priority over default 1.0
- Stat transform happens before resolve_aesthetics(), so we check parameters
  directly rather than relying on aesthetic resolution

Example usage:
  DRAW rect MAPPING x AS x, ymin AS ymin, ymax AS ymax SETTING width => 0.8

All 19 rect tests passing.
Extract duplicated x and y direction logic into a single process_direction
helper function that handles both axes.

Changes:
- New process_direction() function processes a single direction
  - Takes only axis ("x" or "y"), derives all aesthetic names from it
  - Returns SELECT parts and stat column names
  - Handles both discrete and continuous cases
- Determine stat_cols first, then format SELECT parts outside if-block
  to eliminate duplication of format! calls
- stat_rect() now calls process_direction() twice (once for x, once for y)
- Eliminates ~100 lines of duplicated logic

Call sites simplified from:
  process_direction("pos1", "pos1min", "pos1max", "width", "width", "x", ...)
to:
  process_direction("x", aesthetics, parameters, schema)

Net reduction: 26 lines (114 deletions, 88 additions)
All 19 rect tests passing.
@teunbrand teunbrand mentioned this pull request Mar 4, 2026
24 tasks
@teunbrand teunbrand marked this pull request as ready for review March 4, 2026 14:58
@teunbrand teunbrand requested a review from thomasp85 March 4, 2026 14:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant