Skip to content

Commit

Permalink
feat: support domainRaw so one may bind domainRaw to a parameter to b…
Browse files Browse the repository at this point in the history
…uild custom interaction (vega#8989)

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 946000e commit b451632
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 2 deletions.
4 changes: 4 additions & 0 deletions build/vega-lite-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -21763,6 +21763,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.
1 change: 1 addition & 0 deletions examples/compiled/interactive_point_domainRaw_binding.svg
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

0 comments on commit b451632

Please sign in to comment.