Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support domainRaw so one may bind domainRaw to a parameter to build custom interaction #8989

Merged
merged 5 commits into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions build/vega-lite-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -21739,6 +21739,10 @@
],
"description": "Sets the minimum value in the scale domain, overriding the domain property. This property is only intended for use with scales having continuous domains."
},
"domainRaw": {
"$ref": "#/definitions/ExprRef",
"description": "An expression for an array of raw values that, if non-null, directly overrides the _domain_ property. This is useful for supporting interactions such as panning or zooming a scale. The scale may be initially determined using a data-driven domain, then modified in response to user input by setting the rawDomain value."
},
"exponent": {
"anyOf": [
{
Expand Down
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.
148 changes: 148 additions & 0 deletions examples/compiled/interactive_point_domainRaw_binding.vg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"background": "white",
"padding": 5,
"width": 200,
"height": 200,
"style": "cell",
"data": [
{
"name": "source_0",
"url": "data/cars.json",
"format": {"type": "json"},
"transform": [
{
"type": "filter",
"expr": "isValid(datum[\"Horsepower\"]) && isFinite(+datum[\"Horsepower\"]) && isValid(datum[\"Miles_per_Gallon\"]) && isFinite(+datum[\"Miles_per_Gallon\"]) && isValid(datum[\"Cylinders\"]) && isFinite(+datum[\"Cylinders\"])"
}
]
}
],
"signals": [
{
"name": "min_x",
"value": 50,
"bind": {"input": "range", "min": 0, "max": 300}
},
{
"name": "max_x",
"value": 250,
"bind": {"input": "range", "min": 0, "max": 300}
},
{"name": "use_custom_x", "value": true, "bind": {"input": "checkbox"}}
],
"marks": [
{
"name": "marks",
"type": "symbol",
"clip": true,
"style": ["circle"],
"from": {"data": "source_0"},
"encode": {
"update": {
"opacity": {"value": 0.7},
"fill": {"value": "#4c78a8"},
"ariaRoleDescription": {"value": "circle"},
"description": {
"signal": "\"Horsepower: \" + (format(datum[\"Horsepower\"], \"\")) + \"; Miles_per_Gallon: \" + (format(datum[\"Miles_per_Gallon\"], \"\")) + \"; Cylinders: \" + (format(datum[\"Cylinders\"], \"\"))"
},
"x": {"scale": "x", "field": "Horsepower"},
"y": {"scale": "y", "field": "Miles_per_Gallon"},
"size": {"scale": "size", "field": "Cylinders"},
"shape": {"value": "circle"}
}
}
}
],
"scales": [
{
"name": "x",
"type": "linear",
"domain": {"data": "source_0", "field": "Horsepower"},
"range": [0, {"signal": "width"}],
"domainRaw": {"signal": "use_custom_x ? [min_x, max_x] : null"},
"nice": true,
"zero": true
},
{
"name": "y",
"type": "linear",
"domain": {"data": "source_0", "field": "Miles_per_Gallon"},
"range": [{"signal": "height"}, 0],
"nice": true,
"zero": true
},
{
"name": "size",
"type": "linear",
"domain": {"data": "source_0", "field": "Cylinders"},
"range": [0, 361],
"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": "Horsepower",
"labelFlush": true,
"labelOverlap": true,
"tickCount": {"signal": "ceil(width/40)"},
"zindex": 0
},
{
"scale": "y",
"orient": "left",
"grid": false,
"title": "Miles_per_Gallon",
"labelOverlap": true,
"tickCount": {"signal": "ceil(height/40)"},
"zindex": 0
}
],
"legends": [
{
"size": "size",
"symbolType": "circle",
"title": "Cylinders",
"encode": {
"symbols": {
"update": {
"fill": {"value": "#4c78a8"},
"opacity": {"value": 0.7},
"stroke": {"value": "transparent"}
}
}
}
}
]
}
40 changes: 40 additions & 0 deletions examples/specs/interactive_point_domainRaw_binding.vl.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {"url": "data/cars.json"},
"params": [{
"name": "min_x",
"value": 50,
"bind": {
"input": "range",
"min": 0,
"max": 300
}
}, {
"name": "max_x",
"value": 250,
"bind": {
"input": "range",
"min": 0,
"max": 300
}
},{
"name": "use_custom_x",
"value": true,
"bind": {
"input": "checkbox"
}
}],
"mark": {"type": "circle", "clip": true},
"encoding": {
"x": {
"field": "Horsepower", "type": "quantitative",
"scale": {
"domainRaw": {"expr": "use_custom_x ? [min_x, max_x] : null"}
}
},
"y": {
"field": "Miles_per_Gallon", "type": "quantitative"
},
"size": {"field": "Cylinders", "type": "quantitative"}
}
}
6 changes: 5 additions & 1 deletion site/docs/encoding/scale.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ bar, image, rect, and rule marks while `"point"` is the default scales for all o

By default, a scale in Vega-Lite draws domain values directly from a channel's encoded field. Users can specify the `domain` property of a scale to customize its domain values. To sort the order of the domain of the encoded, the [`sort`](sort.html) property of a [field definition](encoding.html#field-def) can be specified.

{% include table.html props="domain,domainMax,domainMin,domainMid" source="Scale" %}
{% include table.html props="domain,domainMax,domainMin,domainMid,domainRaw" source="Scale" %}

A common use case for the `domain` property is to limit, for example, the `x` range of values to include in a plot. However, setting the domain property alone is insufficient to achieve the desired effect.

Expand All @@ -101,6 +101,10 @@ There are two approaches to keep the mark from being plotted outside the desired

<div class="vl-example" data-name="line_inside_domain_using_transform"></div>

### Example: Using `domainRaw` to bind domain interactively

<div class="vl-example" data-name="interactive_point_domainRaw_binding"></div>

<!--
#### Example: Custom Domain
TODO: Custom Domain for quantitative / discrete scales
Expand Down
2 changes: 1 addition & 1 deletion src/compile/scale/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {Explicit, Split} from '../split';
* All VgDomain property except domain.
* (We exclude domain as we have a special "domains" array that allow us merge them all at once in assemble.)
*/
export type ScaleComponentProps = Omit<VgScale, 'domain' | 'domainRaw' | 'reverse'> & {
export type ScaleComponentProps = Omit<VgScale, 'domain' | 'reverse'> & {
domains: VgNonUnionDomain[];
selectionExtent?: ParameterExtent;
reverse?: boolean | SignalRef; // Need override since Vega doesn't official support scale reverse yet (though it does in practice)
Expand Down
10 changes: 10 additions & 0 deletions src/scale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,13 @@ export interface Scale<ES extends ExprRef | SignalRef = ExprRef | SignalRef> {
| DomainUnionWith
| ES;

/**
* An expression for an array of raw values that, if non-null, directly overrides the _domain_ property.
* This is useful for supporting interactions such as panning or zooming a scale.
* The scale may be initially determined using a data-driven domain, then modified in response to user input by setting the rawDomain value.
*/
domainRaw?: ES;

/**
* Inserts a single mid-point value into a two-element domain. The mid-point value must lie between the domain minimum and maximum values. This property can be useful for setting a midpoint for [diverging color scales](https://vega.github.io/vega-lite/docs/scale.html#piecewise). The domainMid property is only intended for use with scales supporting continuous, piecewise domains.
*/
Expand Down Expand Up @@ -728,6 +735,7 @@ const SCALE_PROPERTY_INDEX: Flag<keyof Scale<any>> = {
domainMax: 1,
domainMin: 1,
domainMid: 1,
domainRaw: 1,
align: 1,
range: 1,
rangeMax: 1,
Expand Down Expand Up @@ -785,6 +793,7 @@ export function scaleTypeSupportProperty(scaleType: ScaleType, propName: keyof S
case 'domainMax':
case 'domainMid':
case 'domainMin':
case 'domainRaw':
case 'clamp':
return isContinuousToContinuous(scaleType);
case 'nice':
Expand Down Expand Up @@ -830,6 +839,7 @@ export function channelScalePropertyIncompatability(channel: Channel, propName:
case 'domain':
case 'domainMax':
case 'domainMin':
case 'domainRaw':
case 'range':
case 'base':
case 'exponent':
Expand Down