diff --git a/examples/compiled/area_overlay_with_y2.png b/examples/compiled/area_overlay_with_y2.png
new file mode 100644
index 00000000000..8e489363d69
Binary files /dev/null and b/examples/compiled/area_overlay_with_y2.png differ
diff --git a/examples/compiled/area_overlay_with_y2.svg b/examples/compiled/area_overlay_with_y2.svg
new file mode 100644
index 00000000000..0ac6b6cde0c
--- /dev/null
+++ b/examples/compiled/area_overlay_with_y2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/compiled/area_overlay_with_y2.vg.json b/examples/compiled/area_overlay_with_y2.vg.json
new file mode 100644
index 00000000000..1f3b7fd7fa3
--- /dev/null
+++ b/examples/compiled/area_overlay_with_y2.vg.json
@@ -0,0 +1,166 @@
+{
+ "$schema": "https://vega.github.io/schema/vega/v5.json",
+ "description": "Google's stock price over time.",
+ "background": "white",
+ "padding": 5,
+ "width": 200,
+ "height": 200,
+ "style": "cell",
+ "data": [
+ {
+ "name": "source_0",
+ "url": "data/stocks.csv",
+ "format": {"type": "csv", "parse": {"date": "date"}},
+ "transform": [{"type": "filter", "expr": "datum.symbol==='GOOG'"}]
+ },
+ {
+ "name": "data_0",
+ "source": "source_0",
+ "transform": [
+ {
+ "type": "filter",
+ "expr": "(isDate(datum[\"date\"]) || (isValid(datum[\"date\"]) && isFinite(+datum[\"date\"]))) && isValid(datum[\"price\"]) && isFinite(+datum[\"price\"])"
+ }
+ ]
+ }
+ ],
+ "marks": [
+ {
+ "name": "layer_0_marks",
+ "type": "area",
+ "style": ["area"],
+ "sort": {"field": "datum[\"date\"]"},
+ "from": {"data": "source_0"},
+ "encode": {
+ "update": {
+ "opacity": {"value": 0.7},
+ "orient": {"value": "vertical"},
+ "fill": {"value": "#4c78a8"},
+ "description": {
+ "signal": "\"date: \" + (timeFormat(datum[\"date\"], '%b %d, %Y')) + \"; price: \" + (format(datum[\"price\"], \"\"))"
+ },
+ "x": {"scale": "x", "field": "date"},
+ "y": {"scale": "y", "field": "price"},
+ "y2": {"scale": "y", "value": 0},
+ "defined": {
+ "signal": "isValid(datum[\"date\"]) && isFinite(+datum[\"date\"]) && isValid(datum[\"price\"]) && isFinite(+datum[\"price\"])"
+ }
+ }
+ }
+ },
+ {
+ "name": "layer_1_marks",
+ "type": "line",
+ "style": ["line"],
+ "sort": {"field": "datum[\"date\"]"},
+ "from": {"data": "source_0"},
+ "encode": {
+ "update": {
+ "stroke": {"value": "#4c78a8"},
+ "description": {
+ "signal": "\"date: \" + (timeFormat(datum[\"date\"], '%b %d, %Y')) + \"; price: \" + (format(datum[\"price\"], \"\"))"
+ },
+ "x": {"scale": "x", "field": "date"},
+ "y": {"scale": "y", "field": "price"},
+ "defined": {
+ "signal": "isValid(datum[\"date\"]) && isFinite(+datum[\"date\"]) && isValid(datum[\"price\"]) && isFinite(+datum[\"price\"])"
+ }
+ }
+ }
+ },
+ {
+ "name": "layer_2_marks",
+ "type": "symbol",
+ "style": ["point"],
+ "from": {"data": "data_0"},
+ "encode": {
+ "update": {
+ "opacity": {"value": 1},
+ "fill": {"value": "#4c78a8"},
+ "ariaRoleDescription": {"value": "point"},
+ "description": {
+ "signal": "\"date: \" + (timeFormat(datum[\"date\"], '%b %d, %Y')) + \"; price: \" + (format(datum[\"price\"], \"\"))"
+ },
+ "x": {"scale": "x", "field": "date"},
+ "y": {"scale": "y", "field": "price"}
+ }
+ }
+ }
+ ],
+ "scales": [
+ {
+ "name": "x",
+ "type": "time",
+ "domain": {
+ "fields": [
+ {"data": "source_0", "field": "date"},
+ {"data": "data_0", "field": "date"}
+ ]
+ },
+ "range": [0, {"signal": "width"}]
+ },
+ {
+ "name": "y",
+ "type": "linear",
+ "domain": {
+ "fields": [
+ {"data": "source_0", "field": "price"},
+ [0],
+ {"data": "data_0", "field": "price"}
+ ]
+ },
+ "range": [{"signal": "height"}, 0],
+ "nice": true,
+ "zero": true
+ }
+ ],
+ "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)"},
+ "domain": false,
+ "labels": false,
+ "aria": false,
+ "maxExtent": 0,
+ "minExtent": 0,
+ "ticks": false,
+ "zindex": 0
+ },
+ {
+ "scale": "x",
+ "orient": "bottom",
+ "grid": false,
+ "title": "date",
+ "labelFlush": true,
+ "labelOverlap": true,
+ "tickCount": {"signal": "ceil(width/40)"},
+ "zindex": 0
+ },
+ {
+ "scale": "y",
+ "orient": "left",
+ "grid": false,
+ "title": "price",
+ "labelOverlap": true,
+ "tickCount": {"signal": "ceil(height/40)"},
+ "zindex": 0
+ }
+ ]
+}
diff --git a/examples/specs/area_overlay_with_y2.vl.json b/examples/specs/area_overlay_with_y2.vl.json
new file mode 100644
index 00000000000..4f4af3426dc
--- /dev/null
+++ b/examples/specs/area_overlay_with_y2.vl.json
@@ -0,0 +1,12 @@
+{
+ "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
+ "description": "Google's stock price over time.",
+ "data": {"url": "data/stocks.csv"},
+ "transform": [{"filter": "datum.symbol==='GOOG'"}],
+ "mark": {"type": "area", "line": true, "point": true},
+ "encoding": {
+ "x": {"field": "date", "type": "temporal"},
+ "y": {"field": "price", "type": "quantitative"},
+ "y2": {"datum": 0, "type": "quantitative"}
+ }
+}
diff --git a/examples/specs/normalized/area_overlay_with_y2_normalized.vl.json b/examples/specs/normalized/area_overlay_with_y2_normalized.vl.json
new file mode 100644
index 00000000000..9052e00bd04
--- /dev/null
+++ b/examples/specs/normalized/area_overlay_with_y2_normalized.vl.json
@@ -0,0 +1,30 @@
+{
+ "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
+ "description": "Google's stock price over time.",
+ "data": {"url": "data/stocks.csv"},
+ "transform": [{"filter": "datum.symbol==='GOOG'"}],
+ "layer": [
+ {
+ "mark": {"opacity": 0.7, "type": "area"},
+ "encoding": {
+ "x": {"field": "date", "type": "temporal"},
+ "y": {"field": "price", "type": "quantitative"},
+ "y2": {"datum": 0, "type": "quantitative"}
+ }
+ },
+ {
+ "mark": {"type": "line"},
+ "encoding": {
+ "x": {"field": "date", "type": "temporal"},
+ "y": {"field": "price", "type": "quantitative"}
+ }
+ },
+ {
+ "mark": {"type": "point", "opacity": 1, "filled": true},
+ "encoding": {
+ "x": {"field": "date", "type": "temporal"},
+ "y": {"field": "price", "type": "quantitative"}
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/normalize/pathoverlay.ts b/src/normalize/pathoverlay.ts
index 333cd2b84cd..33e988f7a0f 100644
--- a/src/normalize/pathoverlay.ts
+++ b/src/normalize/pathoverlay.ts
@@ -143,6 +143,11 @@ export class PathOverlayNormalizer implements NonFacetUnitNormalizer {
});
});
+ it('correctly normalizes area using y2 with overlay line.', () => {
+ const spec: TopLevelSpec = {
+ data: {url: 'data/stocks.csv'},
+ mark: 'area',
+ encoding: {
+ x: {field: 'date', type: 'temporal'},
+ y: {field: 'price', type: 'quantitative'},
+ y2: {value: 0, type: 'quantitative'}
+ },
+ config: {area: {line: {}, point: {}}}
+ };
+ const normalizedSpec = normalize(spec);
+ expect(normalizedSpec).toEqual({
+ data: {url: 'data/stocks.csv'},
+ layer: [
+ {
+ mark: {type: 'area', opacity: 0.7},
+ encoding: {
+ x: {field: 'date', type: 'temporal'},
+ y: {field: 'price', type: 'quantitative'},
+ y2: {value: 0, type: 'quantitative'}
+ }
+ },
+ {
+ mark: {type: 'line'},
+ encoding: {
+ x: {field: 'date', type: 'temporal'},
+ y: {field: 'price', type: 'quantitative', stack: 'zero'}
+ }
+ },
+ {
+ mark: {type: 'point', opacity: 1, filled: true},
+ encoding: {
+ x: {field: 'date', type: 'temporal'},
+ y: {field: 'price', type: 'quantitative', stack: 'zero'}
+ }
+ }
+ ],
+ config: {area: {line: {}, point: {}}}
+ });
+ });
+
it('correctly normalizes interpolated area with overlay line', () => {
const spec: TopLevelSpec = {
data: {url: 'data/stocks.csv'},