diff --git a/build/vega-lite-schema.json b/build/vega-lite-schema.json
index a251280b95..5b773b2649 100644
--- a/build/vega-lite-schema.json
+++ b/build/vega-lite-schema.json
@@ -8145,6 +8145,14 @@
"description": "The minimum number of samples to take along the extent domain for plotting the density.\n\n__Default value:__ `25`",
"type": "number"
},
+ "resolve": {
+ "description": "Indicates how parameters for multiple densities should be resolved. If `\"independent\"`, each density may have its own domain extent and dynamic number of curve sample steps. If `\"shared\"`, the KDE transform will ensure that all densities are defined over a shared domain and curve steps, enabling stacking.\n\n__Default value:__ `\"shared\"`",
+ "enum": [
+ "independent",
+ "shared"
+ ],
+ "type": "string"
+ },
"steps": {
"description": "The exact number of samples to take along the extent domain for plotting the density. If specified, overrides both minsteps and maxsteps to set an exact number of uniform samples. Potentially useful in conjunction with a fixed extent to ensure consistent sample points for stacked densities.",
"type": "number"
diff --git a/examples/compiled/area_density.png b/examples/compiled/area_density.png
index 46d40fa913..767f797ae0 100644
Binary files a/examples/compiled/area_density.png and b/examples/compiled/area_density.png differ
diff --git a/examples/compiled/area_density.svg b/examples/compiled/area_density.svg
index d42b85c260..2f8c497b86 100644
--- a/examples/compiled/area_density.svg
+++ b/examples/compiled/area_density.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/examples/compiled/area_density.vg.json b/examples/compiled/area_density.vg.json
index 8fc8c8ca43..a34a2fc36d 100644
--- a/examples/compiled/area_density.vg.json
+++ b/examples/compiled/area_density.vg.json
@@ -15,7 +15,8 @@
"type": "kde",
"field": "IMDB Rating",
"bandwidth": 0.3,
- "as": ["value", "density"]
+ "as": ["value", "density"],
+ "resolve": "shared"
},
{
"type": "impute",
diff --git a/site/docs/transform/density.md b/site/docs/transform/density.md
index bfe8d224d1..b7399b5663 100644
--- a/site/docs/transform/density.md
+++ b/site/docs/transform/density.md
@@ -21,7 +21,7 @@ The density transform performs one-dimensional [kernel density estimation](https
## Density Transform Definition
-{% include table.html props="density,groupby,cumulative,counts,bandwidth,extent,minsteps,maxsteps,steps,as" source="DensityTransform" %}
+{% include table.html props="density,groupby,cumulative,counts,bandwidth,extent,minsteps,maxsteps,resolve,steps,as" source="DensityTransform" %}
## Usage
diff --git a/src/compile/data/density.ts b/src/compile/data/density.ts
index 6b4317dc50..adbeb22682 100644
--- a/src/compile/data/density.ts
+++ b/src/compile/data/density.ts
@@ -19,6 +19,8 @@ export class DensityTransformNode extends DataFlowNode {
this.transform = duplicate(transform); // duplicate to prevent side effects
const specifiedAs = this.transform.as ?? [undefined, undefined];
this.transform.as = [specifiedAs[0] ?? 'value', specifiedAs[1] ?? 'density'];
+ const resolve = this.transform.resolve ?? 'shared';
+ this.transform.resolve = resolve;
}
public dependentFields() {
@@ -40,9 +42,7 @@ export class DensityTransformNode extends DataFlowNode {
field: density,
...rest
};
- if (this.transform.groupby) {
- result.resolve = 'shared';
- }
+ result.resolve = this.transform.resolve;
return result;
}
}
diff --git a/src/transform.ts b/src/transform.ts
index 33b10bb723..5019088f76 100644
--- a/src/transform.ts
+++ b/src/transform.ts
@@ -496,6 +496,14 @@ export interface DensityTransform {
* __Default value:__ `["value", "density"]`
*/
as?: [FieldName, FieldName];
+ /**
+ * Indicates how parameters for multiple densities should be resolved.
+ * If `"independent"`, each density may have its own domain extent and dynamic number of curve sample steps.
+ * If `"shared"`, the KDE transform will ensure that all densities are defined over a shared domain and curve steps, enabling stacking.
+ *
+ * __Default value:__ `"shared"`
+ */
+ resolve?: 'independent' | 'shared';
}
export function isDensity(t: Transform): t is DensityTransform {
diff --git a/test/compile/data/density.test.ts b/test/compile/data/density.test.ts
index 911510c88f..49e72d6dcc 100644
--- a/test/compile/data/density.test.ts
+++ b/test/compile/data/density.test.ts
@@ -41,6 +41,7 @@ describe('compile/data/fold', () => {
expect(density.assemble()).toEqual({
type: 'kde',
field: 'v',
+ resolve: 'shared',
as: ['value', 'density']
});
});
@@ -54,21 +55,23 @@ describe('compile/data/fold', () => {
expect(density.assemble()).toEqual({
type: 'kde',
field: 'v',
+ resolve: 'shared',
as: ['A', 'density']
});
});
- it('should add resolve shared if we group', () => {
+ it('should add resolve "independent" if we set it explicitly', () => {
const transform: Transform = {
density: 'v',
- groupby: ['a']
+ groupby: ['a'],
+ resolve: 'independent'
};
const density = new DensityTransformNode(null, transform);
expect(density.assemble()).toEqual({
type: 'kde',
groupby: ['a'],
field: 'v',
- resolve: 'shared',
+ resolve: 'independent',
as: ['value', 'density']
});
});
@@ -119,7 +122,7 @@ describe('compile/data/fold', () => {
as: ['A', 'B']
};
const density = new DensityTransformNode(null, transform);
- expect(density.hash()).toBe('DensityTransform {"as":["A","B"],"density":"v"}');
+ expect(density.hash()).toBe('DensityTransform {"as":["A","B"],"density":"v","resolve":"shared"}');
});
});