Skip to content

Commit

Permalink
feat: config.rect/bar.minBandSize (#8959)
Browse files Browse the repository at this point in the history
Co-authored-by: GitHub Actions Bot <vega-actions-bot@users.noreply.github.com>
  • Loading branch information
kanitw and GitHub Actions Bot authored Jun 21, 2023
1 parent f54895c commit f541070
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 14 deletions.
33 changes: 33 additions & 0 deletions build/vega-lite-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3424,6 +3424,17 @@
}
]
},
"minBandSize": {
"anyOf": [
{
"type": "number"
},
{
"$ref": "#/definitions/ExprRef"
}
],
"description": "The minimum band size for bar and rectangle marks. __Default value:__ `0.25`"
},
"opacity": {
"anyOf": [
{
Expand Down Expand Up @@ -16963,6 +16974,17 @@
}
]
},
"minBandSize": {
"anyOf": [
{
"type": "number"
},
{
"$ref": "#/definitions/ExprRef"
}
],
"description": "The minimum band size for bar and rectangle marks. __Default value:__ `0.25`"
},
"opacity": {
"anyOf": [
{
Expand Down Expand Up @@ -20757,6 +20779,17 @@
}
]
},
"minBandSize": {
"anyOf": [
{
"type": "number"
},
{
"$ref": "#/definitions/ExprRef"
}
],
"description": "The minimum band size for bar and rectangle marks. __Default value:__ `0.25`"
},
"opacity": {
"anyOf": [
{
Expand Down
2 changes: 1 addition & 1 deletion examples/compiled/arc_ordinal_theta.vg.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"endAngle": {
"scale": "theta",
"field": "dir",
"offset": {"signal": "max(0.25, bandwidth('theta'))"}
"offset": {"signal": "bandwidth('theta')"}
}
}
}
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/bar_grouped_thin_minBandSize.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
120 changes: 120 additions & 0 deletions examples/compiled/bar_grouped_thin_minBandSize.vg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"background": "white",
"padding": 5,
"width": 500,
"height": 200,
"style": "cell",
"data": [
{
"name": "source_0",
"url": "data/movies.json",
"format": {"type": "json"},
"transform": [
{
"type": "aggregate",
"groupby": ["Director", "Title"],
"ops": ["mean"],
"fields": ["Rotten Tomatoes Rating"],
"as": ["mean_Rotten Tomatoes Rating"]
}
]
}
],
"marks": [
{
"name": "marks",
"type": "rect",
"style": ["bar"],
"from": {"data": "source_0"},
"encode": {
"update": {
"fill": [
{
"test": "datum['IMDB Rating'] === null || datum['Rotten Tomatoes Rating'] === null",
"value": "#aaa"
},
{"value": "#4c78a8"}
],
"ariaRoleDescription": {"value": "bar"},
"description": {
"signal": "\"Director: \" + (isValid(datum[\"Director\"]) ? datum[\"Director\"] : \"\"+datum[\"Director\"]) + \"; Mean of Rotten Tomatoes Rating: \" + (format(datum[\"mean_Rotten Tomatoes Rating\"], \"\")) + \"; Title: \" + (isValid(datum[\"Title\"]) ? datum[\"Title\"] : \"\"+datum[\"Title\"])"
},
"x": {
"scale": "x",
"field": "Director",
"offset": {"scale": "xOffset", "field": "Title"}
},
"width": {"signal": "max(4, bandwidth('xOffset'))"},
"y": [
{
"test": "!isValid(datum[\"mean_Rotten Tomatoes Rating\"]) || !isFinite(+datum[\"mean_Rotten Tomatoes Rating\"])",
"field": {"group": "height"}
},
{"scale": "y", "field": "mean_Rotten Tomatoes Rating"}
],
"y2": {"scale": "y", "value": 0}
}
}
}
],
"scales": [
{
"name": "x",
"type": "band",
"domain": {"data": "source_0", "field": "Director", "sort": true},
"range": [0, {"signal": "width"}],
"paddingInner": 0.2,
"paddingOuter": 0.2
},
{
"name": "y",
"type": "linear",
"domain": {"data": "source_0", "field": "mean_Rotten Tomatoes Rating"},
"range": [{"signal": "height"}, 0],
"nice": true,
"zero": true
},
{
"name": "xOffset",
"type": "band",
"domain": {"data": "source_0", "field": "Title", "sort": true},
"range": [0, {"signal": "bandwidth('x')"}]
}
],
"axes": [
{
"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": "Director",
"labelAlign": "right",
"labelAngle": 270,
"labelBaseline": "middle",
"zindex": 0
},
{
"scale": "y",
"orient": "left",
"grid": false,
"title": "Mean of Rotten Tomatoes Rating",
"labelOverlap": true,
"tickCount": {"signal": "ceil(height/40)"},
"zindex": 0
}
]
}
22 changes: 22 additions & 0 deletions examples/specs/bar_grouped_thin_minBandSize.vl.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {"url": "data/movies.json"},
"width": 500,
"mark": "bar",
"encoding": {
"x": {"field": "Director", "type": "nominal"},
"xOffset": {"field": "Title", "type": "nominal"},
"y": {
"aggregate": "mean",
"field": "Rotten Tomatoes Rating",
"type": "quantitative"
},
"color": {
"condition": {
"test": "datum['IMDB Rating'] === null || datum['Rotten Tomatoes Rating'] === null",
"value": "#aaa"
}
}
},
"config": {"mark": {"invalid": null}, "bar": {"minBandSize": 4}}
}
4 changes: 2 additions & 2 deletions site/docs/mark/bar.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,6 @@ Specifying `x2` or `y2` for the quantitative axis of bar marks creates ranged ba

The `bar` property of the top-level [`config`](config.html) object sets the default properties for all bar marks. If [mark property encoding channels](encoding.html#mark-prop) are specified for marks, these config values will be overridden.

Besides standard [mark properties](#properties), bar config can contain the following additional properties:
Besides standard [bar mark properties](#properties), bar config can contain the following additional properties:

{% include table.html props="binSpacing,continuousBandSize,discreteBandSize" source="BarConfig" %}
{% include table.html props="continuousBandSize,discreteBandSize,minBandSize" source="BarConfig" %}
6 changes: 4 additions & 2 deletions site/docs/mark/rect.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ The `rect` mark represents an arbitrary rectangle.

A rect mark definition can contain any [standard mark properties](mark.html#mark-def) and the following special properties:

{% include table.html props="width,height,align,baseline,cornerRadius" source="MarkConfig" %}
{% include table.html props="width,height,align,baseline,cornerRadius,binSpacing" source="MarkConfig" %}

## Examples

Expand Down Expand Up @@ -90,4 +90,6 @@ For example, we can use `rect` to create an annotation [`layer`](layer.html) tha

The `rect` property of the top-level [`config`](config.html) object sets the default properties for all rect marks. If [mark property encoding channels](encoding.html#mark-prop) are specified for marks, these config values will be overridden.

The rect config can contain any [rect mark properties](#properties) (except `type`, `style`, and `clip`).
Besides standard [rect mark properties](#properties) (except `type`, `style`, and `clip`), rect config can contain the following additional properties:

{% include table.html props="continuousBandSize,discreteBandSize,minBandSize" source="RectConfig" %}
11 changes: 4 additions & 7 deletions src/compile/mark/encode/position-rect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import * as log from '../../../log';
import {BandSize, isRelativeBandSize} from '../../../mark';
import {hasDiscreteDomain} from '../../../scale';
import {isSignalRef, isVgRangeStep, VgEncodeEntry, VgValueRef} from '../../../vega.schema';
import {getMarkPropOrConfig, signalOrStringValue, signalOrValueRef} from '../../common';
import {getMarkConfig, getMarkPropOrConfig, signalOrStringValue, signalOrValueRef} from '../../common';
import {ScaleComponent} from '../../scale/component';
import {UnitModel} from '../../unit';
import {nonPosition} from './nonposition';
Expand All @@ -30,7 +30,6 @@ import * as ref from './valueref';
import {getOffsetScaleChannel} from '../../../channel';
import {getFirstDefined} from '../../../util';
import {Mark} from '../../../mark';
import {isExprRef} from '../../../expr';

export function rectPosition(model: UnitModel, channel: 'x' | 'y' | 'theta' | 'radius'): VgEncodeEntry {
const {config, encoding, markDef} = model;
Expand Down Expand Up @@ -77,7 +76,7 @@ function defaultSizeRef(
sizeChannel: 'width' | 'height',
scaleName: string,
scale: ScaleComponent,
config: Config,
config: Config<SignalRef>,
bandSize: BandSize,
hasFieldDef: boolean,
mark: Mark
Expand All @@ -90,8 +89,8 @@ function defaultSizeRef(
if (bandSize.band !== 1) {
bandWidth = `${bandSize.band} * ${bandWidth}`;
}
// TODO(#8351): make 0.25 here configurable
return {signal: `max(0.25, ${bandWidth})`};
const minBandSize = getMarkConfig('minBandSize', {type: mark}, config);
return {signal: minBandSize ? `max(${signalOrStringValue(minBandSize)}, ${bandWidth})` : bandWidth};
} else if (bandSize.band !== 1) {
log.warn(log.message.cannotUseRelativeBandSizeWithNonBandScale(scaleType));
bandSize = undefined;
Expand Down Expand Up @@ -122,8 +121,6 @@ function defaultSizeRef(
return {signal: `(1 - (${padding.signal})) * ${sizeChannel}`};
} else if (isNumber(padding)) {
return {signal: `${1 - padding} * ${sizeChannel}`};
} else if (isExprRef(padding)) {
return {signal: `(1 - (${padding.expr})) * ${sizeChannel}`};
}
}
const defaultStep = getViewConfigDiscreteStep(config.view, sizeChannel);
Expand Down
12 changes: 10 additions & 2 deletions src/mark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,8 @@ export const VL_ONLY_MARK_SPECIFIC_CONFIG_PROPERTY_INDEX: {
[k in Mark]?: (keyof Required<MarkConfigMixins<any>>[k])[];
} = {
area: ['line', 'point'],
bar: ['binSpacing', 'continuousBandSize', 'discreteBandSize'],
rect: ['binSpacing', 'continuousBandSize', 'discreteBandSize'],
bar: ['binSpacing', 'continuousBandSize', 'discreteBandSize', 'minBandSize'],
rect: ['binSpacing', 'continuousBandSize', 'discreteBandSize', 'minBandSize'],
line: ['point'],
tick: ['bandSize', 'thickness']
};
Expand Down Expand Up @@ -442,6 +442,12 @@ export interface RectConfig<ES extends ExprRef | SignalRef> extends RectBinSpaci
* @minimum 0
*/
discreteBandSize?: number | RelativeBandSize;

/**
* The minimum band size for bar and rectangle marks.
* __Default value:__ `0.25`
*/
minBandSize?: number | ES;
}

export type BandSize = number | RelativeBandSize | SignalRef;
Expand Down Expand Up @@ -650,12 +656,14 @@ const DEFAULT_RECT_BAND_SIZE = 5;
export const defaultBarConfig: RectConfig<SignalRef> = {
binSpacing: 1,
continuousBandSize: DEFAULT_RECT_BAND_SIZE,
minBandSize: 0.25,
timeUnitBandPosition: 0.5
};

export const defaultRectConfig: RectConfig<SignalRef> = {
binSpacing: 0,
continuousBandSize: DEFAULT_RECT_BAND_SIZE,
minBandSize: 0.25,
timeUnitBandPosition: 0.5
};

Expand Down

0 comments on commit f541070

Please sign in to comment.