Skip to content

Commit

Permalink
fix: unescape paths in binned timeUnits to allow for fields with pe…
Browse files Browse the repository at this point in the history
…riods in name (vega#9088)

Co-authored-by: GitHub Actions Bot <vega-actions-bot@users.noreply.github.com>
  • Loading branch information
2 people authored and BradyJ27 committed Oct 19, 2023
1 parent 23ba8af commit e7bf27a
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 1 deletion.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
159 changes: 159 additions & 0 deletions examples/compiled/bar_simple_binned_timeunit_special_chars.vg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"background": "white",
"padding": 5,
"width": 200,
"height": 200,
"title": {
"text": "A Simple Bar Chart with Lines at Extents",
"frame": "group"
},
"style": "cell",
"data": [
{
"name": "source_0",
"values": [
{"a.b": "2022-01-01", "b": 28},
{"a.b": "2022-01-04", "b.b": 55},
{"a.b": "2022-01-07", "b": 43},
{"a.b": "2022-01-02", "b": 91},
{"a.b": "2022-01-05", "b.b": 81},
{"a.b": "2022-01-08", "b": 53},
{"a.b": "2022-01-03", "b": 19},
{"a.b": "2022-01-06", "b.b": 87},
{"a.b": "2022-01-09", "b": 52}
]
},
{
"name": "data_0",
"source": "source_0",
"transform": [
{"type": "formula", "expr": "toDate(datum[\"a.b\"])", "as": "a.b"},
{
"type": "formula",
"expr": "timeOffset('date', datum['a.b'], 1)",
"as": "a.b_end"
},
{
"type": "stack",
"groupby": ["a\\.b"],
"field": "b",
"sort": {"field": [], "order": []},
"as": ["b_start", "b_end"],
"offset": "zero"
},
{
"type": "filter",
"expr": "isValid(datum[\"b\"]) && isFinite(+datum[\"b\"]) && (isDate(datum[\"a.b\"]) || (isValid(datum[\"a.b\"]) && isFinite(+datum[\"a.b\"])))"
}
]
}
],
"marks": [
{
"name": "marks",
"type": "rect",
"style": ["bar"],
"from": {"data": "data_0"},
"encode": {
"update": {
"fill": {"value": "#4c78a8"},
"ariaRoleDescription": {"value": "bar"},
"description": {
"signal": "\"b: \" + (format(datum[\"b\"], \"\")) + \"; a.b: \" + (timeFormat(datum[\"a.b\"], timeUnitSpecifier([\"year\",\"month\",\"date\"], {\"year-month\":\"%b %Y \",\"year-month-date\":\"%b %d, %Y \"})))"
},
"x": {"scale": "x", "field": "b_end"},
"x2": {"scale": "x", "field": "b_start"},
"y2": {
"scale": "y",
"field": "a\\.b",
"offset": {
"signal": "0.5 + (abs(scale(\"y\", datum[\"a.b_end\"]) - scale(\"y\", datum[\"a.b\"])) < 0.25 ? 0.5 * (0.25 - (abs(scale(\"y\", datum[\"a.b_end\"]) - scale(\"y\", datum[\"a.b\"])))) : -0.5)"
}
},
"y": {
"scale": "y",
"field": "a\\.b_end",
"offset": {
"signal": "0.5 + (abs(scale(\"y\", datum[\"a.b_end\"]) - scale(\"y\", datum[\"a.b\"])) < 0.25 ? -0.5 * (0.25 - (abs(scale(\"y\", datum[\"a.b_end\"]) - scale(\"y\", datum[\"a.b\"])))) : 0.5)"
}
}
}
}
}
],
"scales": [
{
"name": "x",
"type": "linear",
"domain": {"data": "data_0", "fields": ["b_start", "b_end"]},
"range": [0, {"signal": "width"}],
"nice": true,
"zero": true
},
{
"name": "y",
"type": "utc",
"domain": {"data": "data_0", "fields": ["a\\.b", "a\\.b_end"]},
"range": [{"signal": "height"}, 0]
}
],
"axes": [
{
"scale": "x",
"orient": "bottom",
"gridScale": "y",
"grid": true,
"tickCount": {"signal": "ceil(width/40)"},
"domain": false,
"labels": false,
"aria": false,
"maxExtent": 0,
"minExtent": 0,
"ticks": false,
"zindex": 0
},
{
"scale": "y",
"orient": "left",
"gridScale": "x",
"grid": true,
"tickCount": {"signal": "ceil(height/40)"},
"tickMinStep": {
"signal": "datetime(2001, 0, 2, 0, 0, 0, 0) - datetime(2001, 0, 1, 0, 0, 0, 0)"
},
"domain": false,
"labels": false,
"aria": false,
"maxExtent": 0,
"minExtent": 0,
"ticks": false,
"zindex": 0
},
{
"scale": "x",
"orient": "bottom",
"grid": false,
"title": "b",
"labelFlush": true,
"labelOverlap": true,
"tickCount": {"signal": "ceil(width/40)"},
"zindex": 0
},
{
"scale": "y",
"orient": "left",
"grid": false,
"title": "a.b",
"format": {
"signal": "timeUnitSpecifier([\"year\",\"month\",\"date\"], {\"year-month\":\"%b %Y \",\"year-month-date\":\"%b %d, %Y \"})"
},
"labelOverlap": true,
"tickCount": {"signal": "ceil(height/40)"},
"tickMinStep": {
"signal": "datetime(2001, 0, 2, 0, 0, 0, 0) - datetime(2001, 0, 1, 0, 0, 0, 0)"
},
"zindex": 0
}
]
}
27 changes: 27 additions & 0 deletions examples/specs/bar_simple_binned_timeunit_special_chars.vl.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"title": "A Simple Bar Chart with Lines at Extents",
"data": {
"values": [
{"a.b": "2022-01-01", "b": 28},
{"a.b": "2022-01-04", "b.b": 55},
{"a.b": "2022-01-07", "b": 43},
{"a.b": "2022-01-02", "b": 91},
{"a.b": "2022-01-05", "b.b": 81},
{"a.b": "2022-01-08", "b": 53},
{"a.b": "2022-01-03", "b": 19},
{"a.b": "2022-01-06", "b.b": 87},
{"a.b": "2022-01-09", "b": 52}
]
},
"mark": "bar",
"encoding": {
"y": {
"field": "a\\.b",
"type": "temporal",
"timeUnit": "binnedutcyearmonthdate",
"title": "a.b"
},
"x": {"field": "b", "type": "quantitative"}
}
}
4 changes: 3 additions & 1 deletion src/compile/data/timeunit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,9 @@ export class TimeUnitNode extends DataFlowNode {
as: [as, `${as}_end`]
});
} else if (f) {
const {field, timeUnit} = f;
const {field: escapedField, timeUnit} = f;
// since this is a expression, we want the unescaped field name
const field = escapedField.replaceAll('\\.', '.');
const smallestUnit = getSmallestTimeUnitPart(timeUnit?.unit);
const {part, step} = getDateTimePartAndStep(smallestUnit, timeUnit.step);
transforms.push({
Expand Down
18 changes: 18 additions & 0 deletions test/compile/data/timeunit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,24 @@ describe('compile/data/timeunit', () => {
]);
});

it('should return the proper field escaping with binnedyearmonth', () => {
const model = parseUnitModel({
data: {values: []},
mark: 'bar',
encoding: {
x: {field: 'a\\.b', type: 'temporal', timeUnit: 'binnedyearmonth'}
}
});

expect(assembleFromEncoding(model)).toEqual([
{
type: 'formula',
expr: `timeOffset('month', datum['a.b'], 1)`,
as: 'a.b_end'
}
]);
});

it('should return a unit offset transforms for text with bandPosition', () => {
const model = parseUnitModel({
data: {values: []},
Expand Down

0 comments on commit e7bf27a

Please sign in to comment.