Skip to content

fix: strip disallowed properties from secondary encoding channels#169

Open
cpsievert wants to merge 2 commits intoposit-dev:mainfrom
cpsievert:fix/vegalite-secondary-channel-encoding
Open

fix: strip disallowed properties from secondary encoding channels#169
cpsievert wants to merge 2 commits intoposit-dev:mainfrom
cpsievert:fix/vegalite-secondary-channel-encoding

Conversation

@cpsievert
Copy link
Collaborator

Summary

  • Vega-Lite secondary channels (x2, y2, theta2, radius2) only allow a restricted set of properties (field, aggregate, bandPosition, bin, timeUnit, title, value)
  • The VegaLiteWriter was emitting type, scale, and axis on these channels (e.g., y2 for bar chart baselines), causing Altair schema validation errors like: Additional properties are not allowed ('axis', 'scale' were unexpected)
  • Added is_secondary_channel() to detect internal *end aesthetics (pos1end, pos2end) that map to secondary channels
  • Added early return in build_column_encoding() that emits only field and title for these channels

Test plan

  • Added Python test: TestSecondaryChannelEncoding::test_bar_y2_has_no_disallowed_properties — verifies bar chart y2 encoding has no axis, scale, or type properties
  • All 991 Rust tests pass
  • All Python tests pass (40 passed, 2 skipped)

🤖 Generated with Claude Code

…, y2)

Vega-Lite secondary channels (x2, y2, theta2, radius2) only allow a
restricted set of properties (field, aggregate, bandPosition, bin,
timeUnit, title, value). The VegaLiteWriter was emitting type, scale,
and axis on these channels, causing Altair schema validation errors.

Added is_secondary_channel() to detect internal aesthetics (pos1end,
pos2end) that map to secondary channels, and an early return in
build_column_encoding() that emits only the allowed properties.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cpsievert cpsievert force-pushed the fix/vegalite-secondary-channel-encoding branch from 9dd54f8 to b211de7 Compare March 4, 2026 20:58
@cpsievert cpsievert requested a review from thomasp85 March 5, 2026 20:54
@cpsievert cpsievert marked this pull request as ready for review March 5, 2026 20:54
Copy link
Collaborator

@teunbrand teunbrand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Carson, I think this mostly looks good with a few nits to pick

/// Matches internal names like `pos1end`, `pos2end`, etc.
#[inline]
pub fn is_secondary_channel(name: &str) -> bool {
name.starts_with("pos") && name.ends_with("end") && {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this may miss pos1max.
This should be double checked, but I think you could do something like the following:

name != self.primary_internal_positional(name)

This avoids having to introduce new naming parsing/logic

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure min/max are an issue here... they aren't mapped to the "2" versions in vegalite...

Since this is all in the service of vegalite, can we move this function there?

assert "layer" in spec_dict


class TestSecondaryChannelEncoding:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the intent of this test is good, but it should live in the vegalite writer part of the repo

Address PR review feedback:
- Remove is_secondary_channel() from src/plot/aesthetic.rs (VL-specific
  logic doesn't belong in the general aesthetic module)
- Remove early-exit from encoding.rs build_column_encoding()
- Add early-exit in mod.rs build_layer_encoding() that intercepts by
  VL channel name (x2, y2, theta2, radius2) before build_encoding_channel
  is called — handles both column and literal values in one place
- Move Python test to Rust vegalite writer test using segment geom

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cpsievert
Copy link
Collaborator Author

I think 0679762 should address the feedback -- let me know if I've missed anything.

@cpsievert
Copy link
Collaborator Author

cpsievert commented Mar 6, 2026

Also, this makes me wonder if the rust package should do more to verify that the Vega spec that we're producing adheres to the actual schema, not just our expectations of what the schema are.

Any opinions on if or how that should be done? If not, maybe I just let Claude rip on this idea?

When in doubt, just let Claude rip #175

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.

3 participants