Repository navigation
fix: Make ranged marks compatible with offset channels - #9823
Conversation
71504f8 to
fea9988
Compare
Deploying vega-lite with Β
|
| Latest commit: |
1247b65
|
| Status: | Β β Β Deploy successful! |
| Preview URL: | https://de600e1b.vega-lite.pages.dev |
| Branch Preview URL: | https://feat-ranged-marks-offsets.vega-lite.pages.dev |
β¦anged mark in offset channel
What was going wrong: - area with discrete y + continuous yOffset was compiling as a point-path (like line), not a ranged area. - So it had y but no y2, which can make it effectively invisible depending on fill geometry. What changed: - In src/compile/mark/area.ts, I made area use range geometry when the base channel is discrete and the corresponding offset channel is continuous (same condition family as bar/ranged offset work). - Result: area now compiles with both y and y2, where: - y = data offset endpoint - y2 = offset-zero baseline within the band
- Added a default axis bandPosition rule for ranged-offset cases in src/compile/axis/properties.ts: - For discrete y + continuous yOffset on ranged marks (bar/area), default y axis bandPosition = 1 (bottom of band). - For discrete x + continuous xOffset, default x axis bandPosition = 0 (left of band). - It only applies when user has not set axis.bandPosition. - Explicit user values still win via axis.bandPosition ?? inferredDefault.
- Added default/inferred label positioning for axis labels in src/compile/axis/encode.ts:
- For the same ranged-offset cases, labels get explicit position refs with band:
- y: {scale:'y', signal:'datum.value', band: 1}
- x: {scale:'x', signal:'datum.value', band: 0}
- This uses defaultBandPosition(...) from src/compile/axis/properties.ts, and still respects user overrides:
- if user sets axis.bandPosition, that value is used.
- if user provides explicit label position via axis.encode.labels.update.x/y, we do not override.
β¦channel" This reverts commit 253d531.
Previously, with area + aggregated yOffset and no y, area could compile without y2, so nothing meaningful was filled. Now the area mark treats this as ranged geometry even when y is omitted, as long as a continuous offset channel is present and no secondary range is explicitly defined.
Previously:
- Bar used top-origin style (value: 0 + offset, with y2 = height).
- Area was using bottom-origin style (group height + offset), which is why it looked lower than others.
Now:
- Updated area in src/compile/mark/area.ts so in the yOffset-only ranged case it uses the same top-origin side as bar:
- y: {value: 0, offset: ...}
- y2: {field:{group:'height'}}
- This makes area and bar consistent with each other for the same yOffset-only spec.
Note:
- For yOffset without y, line/point use center baseline (height * 0.5) + offset, so line/point still wonβt numerically align with bar/area in yOffset-only specs because they intentionally use midpoint positioning for non-ranged marks.
β¦in offset channels
Previously:
- bar/area were getting default x-stacking inferred, which created value_start/value_end behavior (or equivalent range semantics) that made them look like they were connecting/anchoring on the wrong axis.
- bar orientation was inferred as horizontal (because only x was quantitative), which made bars extend along x toward zero.
Now:
- Stacking was disabled when:
- stacking channel is x and there is no y, but there is a continuous yOffset, or
- stacking channel is y and there is no x, but there is a continuous xOffset.
- Explicit stacking still works
- Orientation was also changed:
- if only yOffset is quantitative and y is absent β infer orient: 'vertical'
- if only xOffset is quantitative and x is absent β infer orient: 'horizontal'
fea9988 to
37e55da
Compare
Replace the invalid density mark type with a density transform plus an area mark. The example now emits custom output fields via transform.as and encodes them directly, which fixes examples/examples.test.ts failures in CI.
β¦ged-marks-offsets
β¦l, no auto-grouping)
ec2c727 to
e5e80f9
Compare
β¦sets # Conflicts: # src/compile/mark/encode/position-rect.ts
β¦feat/ranged-marks-offsets
|
I wonder whether you still want this pull request. offset isn't really designed for ranged marks where maybe using row and column makes more sense. Now that we don't automatically group by the range mark (for reasons explained in the other prs), I wonder what you think about this pull request. The zero: true default applies to all quantitative offset scales, not just ranged marks. We definitely want to be careful with that before merging. {
"$schema": "https://vega.github.io/schema/vega-lite/v6.json",
"description": "Points spread within each band by a meaningful field",
"data": {"url": "data/cars.json"},
"height": {"step": 50},
"mark": "point",
"encoding": {
"x": {"field": "Horsepower", "type": "quantitative"},
"y": {"field": "Cylinders", "type": "ordinal"},
"yOffset": {"field": "Miles_per_Gallon", "type": "quantitative"}
}
}On main, the yOffset domain fits the data (around [9, 47]), so points use the full bandwidth. With this PR the domain becomes [0, 47], compressing all points into the upper ~80% of each band and leaving the bottom fifth empty β and the further the data sits from zero, the worse the compression (a field with values 100 to 200 would squeeze everything into half the band). For random() jitter the change is invisible (domain is already around [0, 1]), but offset-as-secondary-encoding regresses. |
|
I changed that zero is only used for ranged marks. This should avoid regressions while still enabling the feature you aimed for. What do you think? |
|
Thanks for having a look and for improving the PR! Good call on applying In terms of this feature in general, it does seem grammatically intuitive to me that it is possible to use ranged marks in offset channels since it works for non-ranged marks. I think the use case for this is faster access to more "sparkline"-like charts than with facetting (even if they can look similar with styling) and that this also gives an additional grouping dimension since it can be used with facetting. The ability to use density areas in offset channels could potentially make it easier to create e.g. ridgeline charts (I believe some additional tweak was needed to make densities work in offline channel, but I don't quite remember atm). All that to say that unless we see some harm/regressions from supporting this, I think it would be a "nice to have" (but not a "must have"). One observation: the requirement to specify the |
In short, this PR changes ranged marks in offset channels so that they compile as true ranged marks with consistent baseline, grouping, and axis alignment. There are still some things to fix with the examples but it would be helpful with high level comments on the overall approach even before then. (Note that all the screenshot are including #9817, otherwise they would be upside down)
Details
Currently, ranged marks are not working well in offset channels. For example, a bar mark simply places a rectangle of fixed size at the location of the offset. I think that the desired behavior should mimic how bars work across other quantitative channel, ie start from a baseline and extent to the data value, which is what I have tried to implement here:
Open the Chart in the Vega Editor
Similarly, area marks display unusual behavior currently and don't show up at all. With the changes in this PR, they will show similar to how the line mark from #9819 display:
Open the Chart in the Vega Editor
I also chose to align axis/tick/label behavior with the new baseline semantics, anchoring them at the bottom of the bar/area, because I thought it looked odd when they were in the middle of the band:

I think that a case could be made for including a grid line by default as a baseline, but I was unsure if this was too automagical, so I left it out in this implementation. It is quite helpful, particularly when the marks have different range, but maybe it should be added manually for consistency:
Checklist
npm testruns successfullysite/docs/+ examples.Tips: