Skip to content

Annotations#172

Draft
teunbrand wants to merge 10 commits intoposit-dev:mainfrom
teunbrand:annotate
Draft

Annotations#172
teunbrand wants to merge 10 commits intoposit-dev:mainfrom
teunbrand:annotate

Conversation

@teunbrand
Copy link
Collaborator

@teunbrand teunbrand commented Mar 6, 2026

This PR aims to fix #115.

It introduces a variant for DRAW called PLACE (name is up for debate), which only supports the SETTING clause.
After building the AST, these are just regular layer with DataSource::Annotation(n).

Here is how it treats variables.

  • Position aesthetics -> Incorporate via SQL into new data source.
    • Regardless of whether they are required, since layers may have conditional requirements.
  • Other required aesthetics -> Incorporate via SQL into new data source.
  • Aesthetics declared as array -> Incorporate via SQL into new data source, but mark that these columns are not scaled.
  • Scalar aesthetics -> Just treat like all other SETTING in DRAW clauses.
  • Mappings declared in VISUALISE -> Ignored

Once text/rectangle PRs are in, we can use this in examples for these layers

teunbrand and others added 10 commits March 4, 2026 16:51
Introduces PLACE as a new top-level clause for creating annotation
layers with literal values, similar to ggplot2's annotate() function.

Changes:
- Grammar: Add place_clause accepting geom and optional SETTING
- DataSource: Add Annotation variant to mark annotation layers
- Builder: Handle place_clause and set DataSource::Annotation
- Execution: Add stub for annotation data source generation
- Tests: Add parser test for PLACE clause

PLACE layers use DataSource::Annotation as a marker and don't inherit
global mappings. All aesthetic values come from SETTING parameters.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Completes the execution pipeline for PLACE layers:

Changes:
- Skip annotation layers in merge_global_mappings_into_layers()
  to prevent inheritance of global mappings from VISUALISE
- Clarify annotation data source comment: 1-row dummy satisfies
  execution pipeline requirements (schema detection, type resolution)
  even though SETTING literals render as Vega-Lite datum values

Annotation layers now properly isolated from global mappings while
still working with the existing execution infrastructure.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Enables annotation layers to participate in scale training and coordinate
transformation pipeline by moving positional/required aesthetics from
SETTING parameters to mappings.

Changes:
- Transform parameter keys to internal space (x → pos1, y → pos2)
- Move positional and required aesthetics from parameters to mappings
  for annotation layers in transform_aesthetics_to_internal()
- Refactor place_clause handling in builder.rs into build_place_layer()
- Add comprehensive test coverage: parser, execution, validation, and
  rendering tests verifying field vs value encoding

Annotation position aesthetics now materialize as columns, enabling them
to affect scale ranges and be properly encoded in Vega-Lite output as
field encodings (not datum values).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Change DataSource::Annotation from a unit variant to a tuple variant
containing the number of rows to generate (usize). This prepares for
array expansion support in PLACE annotation layers.

Changes:
- DataSource::Annotation becomes DataSource::Annotation(usize)
- Initialize annotation layers with length 1 in build_place_layer()
- Generate multi-row VALUES clause in determine_layer_source() when n > 1
- Update all matches!() checks to use DataSource::Annotation(_)
- Update test assertions to use pattern matching

The length will be updated in process_annotation_layers() when arrays
are present (to be implemented next).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit implements array parameter recycling for annotation layers,
allowing scalars and length-1 arrays to be automatically recycled to match
the length of the longest array parameter.

Changes:
- Updated DataSource::Annotation to store row count: Annotation(usize)
- Added recycle_value_to_length() helper in plot/main.rs
- Implemented process_annotation_layers() to handle array recycling
- Updated schema inference to handle arrays in literal aesthetic mappings
- Modified literal_to_sql() to generate CASE WHEN statements for arrays
- Fixed SQL generation for multi-row VALUES clause in annotation layers
- Added tests for array recycling and mismatched length validation

Recycling Rules:
- Scalars recycle to max array length
- Length-1 arrays recycle to max array length
- All non-1 arrays must have same length (error on mismatch)
- Only required/positional aesthetics get recycled when moved to mappings

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit fixes a bug where PLACE text annotation layers with array
parameters (e.g., label => [1, 'foo']) displayed incorrectly.

Changes:
- Add ArrayElement::homogenize() to coerce mixed-type arrays to a common type
- Process annotation layers to move array parameters to mappings
- Skip non-positional aesthetics for annotation layers in scale training
- Remove string-to-number parsing in JSON serialization to preserve types

The fix ensures that arrays like [1, 'foo'] are homogenized to ["1", "foo"]
and rendered correctly as separate labels in the visualization.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Extract standalone functions into methods on their respective types for better
encapsulation and API design:

- Add ArrayElement::to_sql() for SQL literal conversion
- Add ParameterValue::to_sql() for SQL literal conversion (including CASE
  statements for arrays)
- Add ParameterValue::rep(n) for array recycling (replaces recycle_value_to_length)
- Add ParameterValue::to_array_element() helper for scalar conversion

Key improvements:
- Simplified rep() to only homogenize arrays when arr.len() == n
- Unified scalar handling through to_array_element() catch-all
- Removed literal_to_sql() standalone function
- Removed recycle_value_to_length() standalone function

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixes issue where PLACE layer literals (e.g., stroke => ['red', 'blue'])
would incorrectly use scales from other layers.

Changes:
- Add is_scaled field to AestheticValue::Column
- Add identity_column() helper for creating unscaled columns
- Mark annotation layer non-positional literals with is_scaled: false
- Use identity_scale when is_scaled is false in encoding

Example: PLACE text with stroke => ['red', 'blue'] now renders with literal
colors instead of being transformed by scales from other layers.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
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.

Drawing annotations

1 participant