From 4fdbb5953618d783dd010c1a49829d2cfd19f03a Mon Sep 17 00:00:00 2001 From: Kanit Wongsuphasawat Date: Mon, 23 Mar 2020 22:55:24 -0700 Subject: [PATCH 1/9] feat: support datum in encoding --- src/channeldef.ts | 238 +++++++++++++++----- src/compile/axis/encode.ts | 13 +- src/compile/axis/parse.ts | 55 +++-- src/compile/axis/properties.ts | 51 +++-- src/compile/data/formatparse.ts | 10 +- src/compile/data/geojson.ts | 19 +- src/compile/data/geopoint.ts | 19 +- src/compile/format.ts | 52 +++-- src/compile/header/assemble.ts | 3 +- src/compile/layoutsize/init.ts | 11 +- src/compile/legend/encode.ts | 18 +- src/compile/legend/parse.ts | 48 ++-- src/compile/legend/properties.ts | 6 +- src/compile/mark/encode/position-point.ts | 10 +- src/compile/mark/encode/position-range.ts | 6 +- src/compile/mark/encode/position-rect.ts | 39 +++- src/compile/mark/encode/text.ts | 2 +- src/compile/mark/encode/tooltip.ts | 3 +- src/compile/mark/encode/valueref.ts | 120 ++++++---- src/compile/mark/init.ts | 18 +- src/compile/projection/parse.ts | 5 +- src/compile/scale/domain.ts | 46 ++-- src/compile/scale/parse.ts | 24 +- src/compile/scale/properties.ts | 57 +++-- src/compile/scale/range.ts | 5 +- src/compile/scale/type.ts | 14 +- src/compile/selection/transforms/legends.ts | 16 +- src/compile/unit.ts | 59 ++--- src/compositemark/common.ts | 20 +- src/compositemark/errorbar.ts | 68 +++--- src/encoding.ts | 71 ++++-- src/normalize/core.ts | 9 +- src/normalize/pathoverlay.ts | 3 +- src/normalize/rangestep.ts | 6 +- src/normalize/repeater.ts | 56 +++-- src/normalize/ruleforrangedline.ts | 8 +- src/stack.ts | 38 ++-- test-runtime/util.ts | 8 +- test/compile/axis/properties.test.ts | 37 ++- test/compile/format.test.ts | 18 +- test/compile/mark/encoding/valueref.test.ts | 15 ++ test/compile/scale/properties.test.ts | 2 +- test/compile/scale/type.test.ts | 67 +++--- test/encoding.test.ts | 4 +- test/normalize/repeat.test.ts | 15 ++ 45 files changed, 887 insertions(+), 525 deletions(-) diff --git a/src/channeldef.ts b/src/channeldef.ts index 0a79c9d753..cf73e165f2 100644 --- a/src/channeldef.ts +++ b/src/channeldef.ts @@ -56,8 +56,8 @@ export interface ValueDef { * F defines the underlying FieldDef type. */ -export type ChannelDefWithCondition, V extends ValueOrGradientOrText = Value> = - | FieldDefWithCondition +export type ChannelDefWithCondition | DatumDef, V extends ValueOrGradientOrText = Value> = + | FieldOrDatumDefWithCondition | ValueDefWithCondition | SignalRefWithCondition; @@ -72,9 +72,10 @@ export type ChannelDefWithCondition, V extends ValueOrGr /** * @minProperties 1 */ -export type ValueDefWithCondition, V extends ValueOrGradientOrText = Value> = Partial< - ValueDef -> & { +export type ValueDefWithCondition< + F extends FieldDef | DatumDef, + V extends ValueOrGradientOrText = Value +> = Partial> & { /** * A field definition or one or more value definition(s) with a selection predicate. */ @@ -84,33 +85,37 @@ export type ValueDefWithCondition, V extends ValueOrGrad /** * @hidden */ -export type SignalRefWithCondition, V extends ValueOrGradientOrText = Value> = SignalRef & { +export type SignalRefWithCondition< + F extends FieldDef | DatumDef, + V extends ValueOrGradientOrText = Value +> = SignalRef & { /** * A field definition or one or more value definition(s) with a selection predicate. */ condition?: Conditional | ValueOrSignalCondition; }; -export type ValueOrSignalWithCondition, V extends ValueOrGradientOrText = Value> = - | ValueDefWithCondition - | SignalRefWithCondition; +export type ValueOrSignalWithCondition< + F extends FieldDef | DatumDef, + V extends ValueOrGradientOrText = Value +> = ValueDefWithCondition | SignalRefWithCondition; export type StringValueOrSignalWithCondition< F extends Field, T extends Type = StandardType -> = ValueOrSignalWithCondition, string | null>; +> = ValueOrSignalWithCondition, string | null>; export type ColorGradientValueOrSignalWithCondition< F extends Field, T extends Type = StandardType -> = ValueOrSignalWithCondition, Gradient | string | null>; +> = ValueOrSignalWithCondition, Gradient | string | null>; export type NumericValueOrSignalWithCondition = ValueOrSignalWithCondition< - MarkPropFieldDef, + MarkPropFieldOrDatumDef, number >; export type NumericArrayValueDefWithCondition = ValueDefWithCondition< - MarkPropFieldDef, + MarkPropFieldOrDatumDef, number[] >; @@ -120,18 +125,18 @@ export type ShapeValueOrSignalWithCondition = StringValueOrSign export type TextValueOrSignalWithCondition = ValueOrSignalWithCondition, Text>; -export type Conditional | ValueDef | SignalRef> = +export type Conditional | DatumDef | ValueDef | SignalRef> = | ConditionalPredicate | ConditionalSelection; -export type ConditionalPredicate | ValueDef | SignalRef> = { +export type ConditionalPredicate | DatumDef | ValueDef | SignalRef> = { /** * Predicate for triggering the condition */ test: LogicalComposition; } & CD; -export type ConditionalSelection | ValueDef | SignalRef> = { +export type ConditionalSelection | DatumDef | ValueDef | SignalRef> = { /** * A [selection name](https://vega.github.io/vega-lite/docs/selection.html), or a series of [composed selections](https://vega.github.io/vega-lite/docs/selection.html#compose). */ @@ -167,31 +172,45 @@ export interface ConditionValueDefMixins, V extends ValueOrGradientOrText = Value> = F & - ConditionValueDefMixins; +export type FieldOrDatumDefWithCondition< + F extends FieldDef | DatumDef, + V extends ValueOrGradientOrText = Value +> = F & ConditionValueDefMixins; + +export type ColorGradientFieldDefWithCondition = FieldOrDatumDefWithCondition< + MarkPropFieldDef, + Gradient | string | null +>; -export type ColorGradientFieldDefWithCondition = FieldDefWithCondition< - MarkPropFieldDef, +export type ColorGradientDatumDefWithCondition = FieldOrDatumDefWithCondition< + DatumDef, Gradient | string | null >; -export type NumericFieldDefWithCondition = FieldDefWithCondition< +export type NumericFieldDefWithCondition = FieldOrDatumDefWithCondition< MarkPropFieldDef, number >; -export type NumericArrayFieldDefWithCondition = FieldDefWithCondition< + +export type NumericDatumDefWithCondition = FieldOrDatumDefWithCondition, number>; + +export type NumericArrayFieldDefWithCondition = FieldOrDatumDefWithCondition< MarkPropFieldDef, number[] >; -export type ShapeFieldDefWithCondition = FieldDefWithCondition< +export type NumericArrayDatumDefWithCondition = FieldOrDatumDefWithCondition, number[]>; + +export type ShapeFieldDefWithCondition = FieldOrDatumDefWithCondition< MarkPropFieldDef, string | null >; -export type TextFieldDefWithCondition = FieldDefWithCondition, Text>; +export type TextFieldDefWithCondition = FieldOrDatumDefWithCondition, Text>; + +export type StringFieldDefWithCondition = FieldOrDatumDefWithCondition, string>; -export type StringFieldDefWithCondition = FieldDefWithCondition, string>; +export type StringDatumDefWithCondition = FieldOrDatumDefWithCondition, string>; /** * A ValueDef with optional Condition @@ -211,7 +230,7 @@ export interface RepeatRef { export type FieldName = string; export type Field = FieldName | RepeatRef; -export function isRepeatRef(field: Field): field is RepeatRef { +export function isRepeatRef(field: Field | any): field is RepeatRef { return field && !isString(field) && 'repeat' in field; } @@ -357,6 +376,18 @@ export interface ScaleMixins { scale?: Scale | null; } +export interface DatumDef extends Partial> { + /** + * A constant value in data domain. + */ + datum?: F extends RepeatRef ? V | RepeatRef : V; + // only apply Repeatref is field (F) can be RepeatRef + // FIXME(https://github.com/microsoft/TypeScript/issues/37586): + // `F extends RepeatRef` probably should be `RepeatRef extends F` but there is likely a bug in TS. +} + +export type ScaleDatumDef = ScaleMixins & DatumDef; + /** * A field definition of a secondary channel that shares a scale with another primary channel. For example, `x2`, `xError` and `xError2` share the same scale with `x`. */ @@ -380,6 +411,8 @@ export type PositionFieldDef = ScaleFieldDef< > & PositionMixins; +export type PositionDatumDef = PositionMixins & ScaleDatumDef; + export interface PositionMixins { /** * An object defining properties of axis's gridlines, ticks and labels. @@ -441,7 +474,7 @@ export function getBand( ) { const {timeUnit, bin} = fieldDef; if (contains(['x', 'y'], channel)) { - if (isPositionFieldDef(fieldDef) && fieldDef.band !== undefined) { + if (isPositionFieldOrDatumDef(fieldDef) && fieldDef.band !== undefined) { return fieldDef.band; } else if (timeUnit && !fieldDef2) { if (isMidPoint) { @@ -475,6 +508,12 @@ export function hasBand( export type MarkPropFieldDef = ScaleFieldDef & LegendMixins; +export type MarkPropDatumDef = LegendMixins & ScaleDatumDef; + +export type MarkPropFieldOrDatumDef = + | MarkPropFieldDef + | MarkPropDatumDef; + export interface LegendMixins { /** * An object defining properties of the legend. @@ -519,6 +558,13 @@ export function hasConditionalFieldDef( return !!condition && !isArray(condition) && isFieldDef(condition); } +export function hasConditionalFieldOrDatumDef( + channelDef: ChannelDef +): channelDef is {condition: Conditional>} { + const condition = channelDef && channelDef['condition']; + return !!condition && !isArray(condition) && isFieldOrDatumDef(condition); +} + export function hasConditionalValueDef( channelDef: ChannelDef ): channelDef is ValueDef & {condition: Conditional> | Conditional>[]} { @@ -527,11 +573,41 @@ export function hasConditionalValueDef( } export function isFieldDef( - channelDef: ChannelDef -): channelDef is TypedFieldDef | SecondaryFieldDef { + channelDef: ChannelDef | FieldDefBase | DatumDef +): channelDef is FieldDefBase | TypedFieldDef | SecondaryFieldDef { return !!channelDef && (!!channelDef['field'] || channelDef['aggregate'] === 'count'); } +export function channelDefType(channelDef: ChannelDef): Type | undefined { + return channelDef && channelDef['type']; +} + +export function isDatumDef( + channelDef: ChannelDef | FieldDefBase | DatumDef +): channelDef is DatumDef { + return !!channelDef && !!channelDef['datum']; +} + +export function isContinuousFieldOrDatumDef(cd: ChannelDef) { + // TODO: make datum support DateTime object + return (isTypedFieldDef(cd) && isContinuous(cd)) || isNumericDataDef(cd); +} + +export function isQuantitativeFieldOrDatumDef(cd: ChannelDef) { + // TODO: make datum support DateTime object + return channelDefType(cd) === 'quantitative' || isNumericDataDef(cd); +} + +export function isNumericDataDef(cd: ChannelDef): cd is DatumDef { + return isDatumDef(cd) && isNumber(cd.datum); +} + +export function isFieldOrDatumDef( + channelDef: ChannelDef +): channelDef is FieldDef | DatumDef { + return isFieldDef(channelDef) || isDatumDef(channelDef); +} + export function isTypedFieldDef(channelDef: ChannelDef): channelDef is TypedFieldDef { return !!channelDef && ((!!channelDef['field'] && !!channelDef['type']) || channelDef['aggregate'] === 'count'); } @@ -544,14 +620,18 @@ export function isScaleFieldDef(channelDef: ChannelDef): cha return !!channelDef && (!!channelDef['scale'] || !!channelDef['sort']); } -export function isPositionFieldDef(channelDef: ChannelDef): channelDef is PositionFieldDef { +export function isPositionFieldOrDatumDef( + channelDef: ChannelDef +): channelDef is PositionFieldDef | PositionDatumDef { return ( !!channelDef && (!!channelDef['axis'] || !!channelDef['stack'] || !!channelDef['impute'] || channelDef['band'] !== undefined) ); } -export function isMarkPropFieldDef(channelDef: ChannelDef): channelDef is MarkPropFieldDef { +export function isMarkPropFieldOrDatumDef( + channelDef: ChannelDef +): channelDef is MarkPropFieldDef | MarkPropDatumDef { return !!channelDef && !!channelDef['legend']; } @@ -650,18 +730,18 @@ export function vgField( } } -export function isDiscrete(fieldDef: TypedFieldDef) { - switch (fieldDef.type) { +export function isDiscrete(def: TypedFieldDef | DatumDef) { + switch (def.type) { case 'nominal': case 'ordinal': case 'geojson': return true; case 'quantitative': - return !!fieldDef.bin; + return isFieldDef(def) && !!def.bin; case 'temporal': return false; } - throw new Error(log.message.invalidFieldType(fieldDef.type)); + throw new Error(log.message.invalidFieldType(def.type)); } export function isContinuous(fieldDef: TypedFieldDef) { @@ -737,12 +817,18 @@ export function resetTitleFormatter() { } export function title( - fieldDef: TypedFieldDef | SecondaryFieldDef, + fieldOrDatumDef: TypedFieldDef | SecondaryFieldDef | DatumDef, config: Config, {allowDisabling, includeDefault = true}: {allowDisabling: boolean; includeDefault?: boolean} ) { - const guide = getGuide(fieldDef) ?? {}; + const guide = getGuide(fieldOrDatumDef) ?? {}; const guideTitle = guide.title; + + if (!isFieldDef(fieldOrDatumDef)) { + return guideTitle; + } + const fieldDef = fieldOrDatumDef; + const def = includeDefault ? defaultTitle(fieldDef, config) : undefined; if (allowDisabling) { @@ -752,10 +838,10 @@ export function title( } } -export function getGuide(fieldDef: TypedFieldDef | SecondaryFieldDef): Guide { - if (isPositionFieldDef(fieldDef) && fieldDef.axis) { +export function getGuide(fieldDef: TypedFieldDef | SecondaryFieldDef | DatumDef): Guide { + if (isPositionFieldOrDatumDef(fieldDef) && fieldDef.axis) { return fieldDef.axis; - } else if (isMarkPropFieldDef(fieldDef) && fieldDef.legend) { + } else if (isMarkPropFieldOrDatumDef(fieldDef) && fieldDef.legend) { return fieldDef.legend; } else if (isFacetFieldDef(fieldDef) && fieldDef.header) { return fieldDef.header; @@ -811,6 +897,17 @@ export function getFieldDef(channelDef: ChannelDef): FieldDe return undefined; } +export function getFieldOrDatumDef = ChannelDef>( + channelDef: CD +): FieldDef | DatumDef { + if (isFieldOrDatumDef(channelDef)) { + return channelDef; + } else if (hasConditionalFieldOrDatumDef(channelDef)) { + return channelDef.condition; + } + return undefined; +} + /** * Convert type to full, lowercase type, or augment the fieldDef with a default type if missing. */ @@ -822,17 +919,36 @@ export function initChannelDef(channelDef: ChannelDef, channel: Channel) } // If a fieldDef contains a field, we need type. - if (isFieldDef(channelDef)) { - return initFieldDef(channelDef, channel); - } else if (hasConditionalFieldDef(channelDef)) { + if (isFieldOrDatumDef(channelDef)) { + return initFieldOrDatumDef(channelDef, channel); + } else if (hasConditionalFieldOrDatumDef(channelDef)) { return { ...channelDef, // Need to cast as normalizeFieldDef normally return FieldDef, but here we know that it is definitely Condition - condition: initFieldDef(channelDef.condition, channel) as Conditional> + condition: initFieldOrDatumDef(channelDef.condition, channel) as Conditional> }; } return channelDef; } + +export function initFieldOrDatumDef(fd: FieldDef | DatumDef, channel: Channel) { + if (isFieldDef(fd)) { + return initFieldDef(fd, channel); + } + return initDatumDef(fd); +} + +function initDatumDef(datumDef: DatumDef) { + let type = datumDef['type']; + if (type) { + return datumDef; + } + const {datum} = datumDef; + type = isNumber(datum) ? 'quantitative' : isString(datum) ? 'nominal' : isDateTime(datum) ? 'temporal' : undefined; + + return {...datumDef, type}; +} + export function initFieldDef(fd: FieldDef, channel: Channel) { const {aggregate, timeUnit, bin, field} = fd; const fieldDef = {...fd}; @@ -1038,23 +1154,23 @@ export function channelCompatibility( * Check if the field def uses a time format or does not use any format but is temporal * (this does not cover field defs that are temporal but use a number format). */ -export function isFieldDefForTimeFormat(fieldDef: FieldDef): boolean { - const guide = getGuide(fieldDef); - const formatType = (guide && guide.formatType) || (isTextFieldDef(fieldDef) && fieldDef.formatType); - return formatType === 'time' || (!formatType && isTimeFieldDef(fieldDef)); +export function isFieldOrDatumDefForTimeFormat(fieldOrDatumDef: FieldDef | DatumDef): boolean { + const guide = getGuide(fieldOrDatumDef); + const formatType = (guide && guide.formatType) || (isTextFieldDef(fieldOrDatumDef) && fieldOrDatumDef.formatType); + return formatType === 'time' || (!formatType && isTimeFieldDef(fieldOrDatumDef)); } -export function isFieldDefWithCustomTimeFormat(fieldDef: TypedFieldDef): boolean { - const guide = getGuide(fieldDef); - const formatType = (guide && guide.formatType) || (isTextFieldDef(fieldDef) && fieldDef.formatType); +export function isFieldDefWithCustomTimeFormat(fieldOrDatumDef: TypedFieldDef | DatumDef): boolean { + const guide = getGuide(fieldOrDatumDef); + const formatType = (guide && guide.formatType) || (isTextFieldDef(fieldOrDatumDef) && fieldOrDatumDef.formatType); return formatType && isCustomFormatType(formatType); } /** * Check if field def has type `temporal`. If you want to also cover field defs that use a time format, use `isTimeFormatFieldDef`. */ -export function isTimeFieldDef(fieldDef: FieldDef) { - return fieldDef['type'] === 'temporal' || !!fieldDef.timeUnit; +export function isTimeFieldDef(def: FieldDef | DatumDef): boolean { + return def && (def['type'] === 'temporal' || (isFieldDef(def) && !!def.timeUnit)); } /** @@ -1075,7 +1191,7 @@ export function valueExpr( undefinedIfExprNotRequired?: boolean; } ): string { - const unit = normalizeTimeUnit(timeUnit)?.unit; + const unit = timeUnit && normalizeTimeUnit(timeUnit)?.unit; let expr; if (isSignalRef(v)) { @@ -1109,11 +1225,17 @@ export function valueExpr( /** * Standardize value array -- convert each value to Vega expression if applicable */ -export function valueArray(fieldDef: TypedFieldDef, values: (number | string | boolean | DateTime)[]) { - const {type} = fieldDef; - const timeUnit = normalizeTimeUnit(fieldDef.timeUnit)?.unit; +export function valueArray( + fieldOrDatumDef: TypedFieldDef | DatumDef, + values: (number | string | boolean | DateTime)[] +) { + const {type} = fieldOrDatumDef; return values.map(v => { - const expr = valueExpr(v, {timeUnit, type, undefinedIfExprNotRequired: true}); + const expr = valueExpr(v, { + timeUnit: isFieldDef(fieldOrDatumDef) ? fieldOrDatumDef.timeUnit : undefined, + type, + undefinedIfExprNotRequired: true + }); // return signal for the expression if we need an expression if (expr !== undefined) { return {signal: expr}; diff --git a/src/compile/axis/encode.ts b/src/compile/axis/encode.ts index e61201dd4d..68fb010efd 100644 --- a/src/compile/axis/encode.ts +++ b/src/compile/axis/encode.ts @@ -1,19 +1,20 @@ -import {PositionScaleChannel} from '../../channel'; +import {getSecondaryRangeChannel, PositionScaleChannel} from '../../channel'; +import {getFieldOrDatumDef} from '../../channeldef'; import {ScaleType} from '../../scale'; import {keys} from '../../util'; import {formatSignalRef} from '../format'; import {UnitModel} from '../unit'; export function labels(model: UnitModel, channel: PositionScaleChannel, specifiedLabelsSpec: any) { - const fieldDef = - model.typedFieldDef(channel) ?? - (channel === 'x' ? model.fieldDef('x2') : channel === 'y' ? model.fieldDef('y2') : undefined); + const {encoding, config} = model; + + const fieldOrDatumDef = + getFieldOrDatumDef(encoding[channel]) ?? getFieldOrDatumDef(encoding[getSecondaryRangeChannel(channel)]); const axis = model.axis(channel) || {}; const {format, formatType} = axis; - const {config} = model; const text = formatSignalRef({ - fieldDef, + fieldOrDatumDef, field: 'datum.value', format, formatType, diff --git a/src/compile/axis/parse.ts b/src/compile/axis/parse.ts index ed35b833c7..2b1cc18d7b 100644 --- a/src/compile/axis/parse.ts +++ b/src/compile/axis/parse.ts @@ -2,7 +2,16 @@ import {AxisEncode as VgAxisEncode, AxisOrient, SignalRef, Text} from 'vega'; import {Axis, AXIS_PARTS, isAxisProperty, isConditionalAxisValue} from '../../axis'; import {isBinned} from '../../bin'; import {PositionScaleChannel, POSITION_SCALE_CHANNELS, X, Y} from '../../channel'; -import {FieldDefBase, isFieldDefForTimeFormat, isFieldDefWithCustomTimeFormat, toFieldDefBase} from '../../channeldef'; +import { + FieldDefBase, + getFieldOrDatumDef, + isFieldDef, + isFieldDefWithCustomTimeFormat as isFieldOrDatumDefWithCustomTimeFormat, + isFieldOrDatumDefForTimeFormat, + PositionDatumDef, + PositionFieldDef, + toFieldDefBase +} from '../../channeldef'; import {contains, getFirstDefined, keys, normalizeAngle} from '../../util'; import {isSignalRef} from '../../vega.schema'; import {mergeTitle, mergeTitleComponent, mergeTitleFieldDefs} from '../common'; @@ -312,53 +321,54 @@ function getProperty( specifiedAxis = specifiedAxis || {}; // assign object so the rest doesn't have to check if legend exists - const fieldDef = model.typedFieldDef(channel); - - const {mark, config} = model; + const {mark, encoding, config} = model; + const fieldOrDatumDef = getFieldOrDatumDef(encoding[channel]) as PositionFieldDef | PositionDatumDef; switch (property) { case 'scale': return model.scaleName(channel) as AxisComponentProps[K]; case 'gridScale': return properties.gridScale(model, channel) as AxisComponentProps[K]; - case 'format': + case 'format': { // We don't include temporal field and custom format as we apply format in encode block - if (isFieldDefForTimeFormat(fieldDef) || isFieldDefWithCustomTimeFormat(fieldDef)) { + if (isFieldOrDatumDefForTimeFormat(fieldOrDatumDef) || isFieldOrDatumDefWithCustomTimeFormat(fieldOrDatumDef)) { return undefined; } - return numberFormat(fieldDef, specifiedAxis.format, config) as AxisComponentProps[K]; + return numberFormat(fieldOrDatumDef.type, specifiedAxis.format, config) as AxisComponentProps[K]; + } case 'formatType': // As with format, we don't include temporal field and custom format here as we apply format in encode block - if (isFieldDefForTimeFormat(fieldDef) || isFieldDefWithCustomTimeFormat(fieldDef)) { + if (isFieldOrDatumDefForTimeFormat(fieldOrDatumDef) || isFieldOrDatumDefWithCustomTimeFormat(fieldOrDatumDef)) { return undefined; } return specifiedAxis.formatType as AxisComponentProps[K]; + case 'grid': { - if (isBinned(model.fieldDef(channel).bin)) { + if (isBinned(model.fieldDef(channel)?.bin)) { return false as AxisComponentProps[K]; } else { const scaleType = model.getScaleComponent(channel).get('type'); return getFirstDefined( specifiedAxis.grid, - properties.defaultGrid(scaleType, fieldDef) + properties.defaultGrid(scaleType, model.typedFieldDef(channel)) ) as AxisComponentProps[K]; } } case 'labelAlign': { const orient = getFirstDefined(specifiedAxis.orient, properties.orient(channel)); - const labelAngle = properties.labelAngle(model, specifiedAxis, channel, fieldDef); + const labelAngle = properties.labelAngle(model, specifiedAxis, channel, fieldOrDatumDef); return getFirstDefined( specifiedAxis.labelAlign, properties.defaultLabelAlign(labelAngle, orient) ) as AxisComponentProps[K]; } case 'labelAngle': { - const labelAngle = properties.labelAngle(model, specifiedAxis, channel, fieldDef); + const labelAngle = properties.labelAngle(model, specifiedAxis, channel, fieldOrDatumDef); return labelAngle as AxisComponentProps[K]; } case 'labelBaseline': { const orient = getFirstDefined(specifiedAxis.orient, properties.orient(channel)); - const labelAngle = properties.labelAngle(model, specifiedAxis, channel, fieldDef); + const labelAngle = properties.labelAngle(model, specifiedAxis, channel, fieldOrDatumDef); return getFirstDefined( specifiedAxis.labelBaseline, properties.defaultLabelBaseline(labelAngle, orient) @@ -367,13 +377,13 @@ function getProperty( case 'labelFlush': return getFirstDefined( specifiedAxis.labelFlush, - properties.defaultLabelFlush(fieldDef, channel) + properties.defaultLabelFlush(fieldOrDatumDef.type, channel) ) as AxisComponentProps[K]; case 'labelOverlap': { const scaleType = model.getScaleComponent(channel).get('type'); return getFirstDefined( specifiedAxis.labelOverlap, - properties.defaultLabelOverlap(fieldDef, scaleType) + properties.defaultLabelOverlap(fieldOrDatumDef.type, scaleType) ) as AxisComponentProps[K]; } case 'orient': { @@ -386,10 +396,11 @@ function getProperty( const size = sizeType ? model.getSizeSignalRef(sizeType) : undefined; return getFirstDefined( specifiedAxis.tickCount, - properties.defaultTickCount({fieldDef, scaleType, size}) + properties.defaultTickCount({fieldOrDatumDef, scaleType, size}) ) as AxisComponentProps[K]; } case 'title': { + const fieldDef = model.typedFieldDef(channel); const channel2 = channel === 'x' ? 'x2' : 'y2'; const fieldDef2 = model.fieldDef(channel2); // Keep undefined so we use default if title is unspecified. @@ -397,13 +408,19 @@ function getProperty( return getFirstDefined[]>( specifiedAxis.title, getFieldDefTitle(model, channel), // If title not specified, store base parts of fieldDef (and fieldDef2 if exists) - mergeTitleFieldDefs([toFieldDefBase(fieldDef)], fieldDef2 ? [toFieldDefBase(fieldDef2)] : []) + mergeTitleFieldDefs( + fieldDef ? [toFieldDefBase(fieldDef)] : [], + isFieldDef(fieldDef2) ? [toFieldDefBase(fieldDef2)] : [] + ) ) as AxisComponentProps[K]; } case 'values': - return properties.values(specifiedAxis, model, fieldDef) as AxisComponentProps[K]; + return properties.values(specifiedAxis, fieldOrDatumDef) as AxisComponentProps[K]; case 'zindex': - return getFirstDefined(specifiedAxis.zindex, properties.defaultZindex(mark, fieldDef)) as AxisComponentProps[K]; + return getFirstDefined( + specifiedAxis.zindex, + properties.defaultZindex(mark, fieldOrDatumDef) + ) as AxisComponentProps[K]; } // Otherwise, return specified property. return isAxisProperty(property) ? (specifiedAxis[property] as AxisComponentProps[K]) : undefined; diff --git a/src/compile/axis/properties.ts b/src/compile/axis/properties.ts index 9ea83cfed3..fa042d684f 100644 --- a/src/compile/axis/properties.ts +++ b/src/compile/axis/properties.ts @@ -3,12 +3,12 @@ import {isArray} from 'vega-util'; import {Axis} from '../../axis'; import {isBinning} from '../../bin'; import {PositionScaleChannel, X, Y} from '../../channel'; -import {isDiscrete, TypedFieldDef, valueArray} from '../../channeldef'; +import {DatumDef, isDiscrete, isFieldDef, TypedFieldDef, valueArray} from '../../channeldef'; import * as log from '../../log'; import {Mark} from '../../mark'; import {hasDiscreteDomain, ScaleType} from '../../scale'; import {normalizeTimeUnit} from '../../timeunit'; -import {NOMINAL, ORDINAL} from '../../type'; +import {NOMINAL, ORDINAL, Type} from '../../type'; import {contains, normalizeAngle} from '../../util'; import {isSignalRef} from '../../vega.schema'; import {UnitModel} from '../unit'; @@ -19,8 +19,9 @@ import {getAxisConfig} from './config'; * Default rules for whether to show a grid should be shown for a channel. * If `grid` is unspecified, the default value is `true` for ordinal scales that are not binned */ + export function defaultGrid(scaleType: ScaleType, fieldDef: TypedFieldDef) { - return !hasDiscreteDomain(scaleType) && !isBinning(fieldDef.bin); + return !hasDiscreteDomain(scaleType) && !isBinning(fieldDef?.bin); } export function gridScale(model: UnitModel, channel: PositionScaleChannel) { @@ -35,7 +36,7 @@ export function labelAngle( model: UnitModel, specifiedAxis: Axis, channel: PositionScaleChannel, - fieldDef: TypedFieldDef + fieldOrDatumDef: TypedFieldDef | DatumDef ) { // try axis value if (specifiedAxis?.labelAngle !== undefined) { @@ -54,7 +55,7 @@ export function labelAngle( return normalizeAngle(angle); } else { // get default value - if (channel === X && contains([NOMINAL, ORDINAL], fieldDef.type)) { + if (channel === X && contains([NOMINAL, ORDINAL], fieldOrDatumDef.type)) { return 270; } // no default @@ -111,16 +112,16 @@ export function defaultLabelAlign(angle: number, axisOrient: AxisOrient): Align return undefined; } -export function defaultLabelFlush(fieldDef: TypedFieldDef, channel: PositionScaleChannel) { - if (channel === 'x' && contains(['quantitative', 'temporal'], fieldDef.type)) { +export function defaultLabelFlush(type: Type, channel: PositionScaleChannel) { + if (channel === 'x' && contains(['quantitative', 'temporal'], type)) { return true; } return undefined; } -export function defaultLabelOverlap(fieldDef: TypedFieldDef, scaleType: ScaleType) { +export function defaultLabelOverlap(type: Type, scaleType: ScaleType) { // do not prevent overlap for nominal data because there is no way to infer what the missing labels are - if (fieldDef.type !== 'nominal') { + if (type !== 'nominal') { if (scaleType === 'log') { return 'greedy'; } @@ -141,34 +142,40 @@ export function orient(channel: PositionScaleChannel) { } export function defaultTickCount({ - fieldDef, + fieldOrDatumDef, scaleType, size }: { - fieldDef: TypedFieldDef; + fieldOrDatumDef: TypedFieldDef | DatumDef; scaleType: ScaleType; size?: SignalRef; }) { - if ( - !hasDiscreteDomain(scaleType) && - scaleType !== 'log' && - !contains(['month', 'hours', 'day', 'quarter'], normalizeTimeUnit(fieldDef.timeUnit)?.unit) - ) { - if (isBinning(fieldDef.bin)) { - // for binned data, we don't want more ticks than maxbins - return {signal: `ceil(${size.signal}/10)`}; + if (!hasDiscreteDomain(scaleType) && scaleType !== 'log') { + if (isFieldDef(fieldOrDatumDef)) { + if (isBinning(fieldOrDatumDef.bin)) { + // for binned data, we don't want more ticks than maxbins + return {signal: `ceil(${size.signal}/10)`}; + } + + if ( + fieldOrDatumDef.timeUnit && + contains(['month', 'hours', 'day', 'quarter'], normalizeTimeUnit(fieldOrDatumDef.timeUnit)?.unit) + ) { + return undefined; + } } + return {signal: `ceil(${size.signal}/40)`}; } return undefined; } -export function values(specifiedAxis: Axis, model: UnitModel, fieldDef: TypedFieldDef) { +export function values(specifiedAxis: Axis, fieldOrDatumDef: TypedFieldDef | DatumDef) { const vals = specifiedAxis.values; if (isArray(vals)) { - return valueArray(fieldDef, vals); + return valueArray(fieldOrDatumDef, vals); } else if (isSignalRef(vals)) { return vals; } @@ -176,7 +183,7 @@ export function values(specifiedAxis: Axis, model: UnitModel, fieldDef: TypedFie return undefined; } -export function defaultZindex(mark: Mark, fieldDef: TypedFieldDef) { +export function defaultZindex(mark: Mark, fieldDef: TypedFieldDef | DatumDef) { if (mark === 'rect' && isDiscrete(fieldDef)) { return 1; } diff --git a/src/compile/data/formatparse.ts b/src/compile/data/formatparse.ts index 7235192ed2..02a126bd9f 100644 --- a/src/compile/data/formatparse.ts +++ b/src/compile/data/formatparse.ts @@ -3,7 +3,13 @@ import {isNumber, isString} from 'vega-util'; import {AncestorParse} from '.'; import {isMinMaxOp} from '../../aggregate'; import {getMainRangeChannel, SingleDefChannel} from '../../channel'; -import {isFieldDef, isFieldDefForTimeFormat, isScaleFieldDef, isTypedFieldDef, TypedFieldDef} from '../../channeldef'; +import { + isFieldDef, + isFieldOrDatumDefForTimeFormat, + isScaleFieldDef, + isTypedFieldDef, + TypedFieldDef +} from '../../channeldef'; import {isGenerator, Parse} from '../../data'; import {DateTime, isDateTime} from '../../datetime'; import * as log from '../../log'; @@ -101,7 +107,7 @@ export function getImplicitFromEncoding(model: Model) { const implicit: Dict = {}; function add(fieldDef: TypedFieldDef) { - if (isFieldDefForTimeFormat(fieldDef)) { + if (isFieldOrDatumDefForTimeFormat(fieldDef)) { implicit[fieldDef.field] = 'date'; } else if ( fieldDef.type === 'quantitative' && diff --git a/src/compile/data/geojson.ts b/src/compile/data/geojson.ts index eaea8a1698..654c0a9e00 100644 --- a/src/compile/data/geojson.ts +++ b/src/compile/data/geojson.ts @@ -1,7 +1,7 @@ import {GeoJSONTransform as VgGeoJSONTransform, Vector2} from 'vega'; import {isString} from 'vega-util'; import {GeoPositionChannel, LATITUDE, LATITUDE2, LONGITUDE, LONGITUDE2, SHAPE} from '../../channel'; -import {isValueDef, ValueDef} from '../../channeldef'; +import {getFieldOrDatumDef, isDatumDef, isFieldDef, isValueDef} from '../../channeldef'; import {GEOJSON} from '../../type'; import {duplicate, hash} from '../../util'; import {VgExprRef} from '../../vega.schema'; @@ -24,13 +24,16 @@ export class GeoJSONNode extends DataFlowNode { [LONGITUDE, LATITUDE], [LONGITUDE2, LATITUDE2] ] as Vector2[]) { - const pair = coordinates.map(channel => - model.channelHasField(channel) - ? model.fieldDef(channel).field - : isValueDef(model.encoding[channel]) - ? {expr: (model.encoding[channel] as ValueDef).value + ''} - : undefined - ) as [GeoPositionChannel, GeoPositionChannel]; + const pair = coordinates.map(channel => { + const def = getFieldOrDatumDef(model.encoding[channel]); + return isFieldDef(def) + ? def.field + : isDatumDef(def) + ? {expr: `${def.datum}`} + : isValueDef(def) + ? {expr: `${def['value']}`} + : undefined; + }) as [GeoPositionChannel, GeoPositionChannel]; if (pair[0] || pair[1]) { parent = new GeoJSONNode(parent, pair, null, model.getName(`geojson_${geoJsonCounter++}`)); diff --git a/src/compile/data/geopoint.ts b/src/compile/data/geopoint.ts index 49dd5209dc..88130156a8 100644 --- a/src/compile/data/geopoint.ts +++ b/src/compile/data/geopoint.ts @@ -1,7 +1,7 @@ import {GeoPointTransform as VgGeoPointTransform, Vector2} from 'vega'; import {isString} from 'vega-util'; import {GeoPositionChannel, LATITUDE, LATITUDE2, LONGITUDE, LONGITUDE2} from '../../channel'; -import {isValueDef, ValueDef} from '../../channeldef'; +import {getFieldOrDatumDef, isDatumDef, isFieldDef, isValueDef} from '../../channeldef'; import {duplicate, hash} from '../../util'; import {VgExprRef} from '../../vega.schema'; import {UnitModel} from '../unit'; @@ -30,13 +30,16 @@ export class GeoPointNode extends DataFlowNode { [LONGITUDE, LATITUDE], [LONGITUDE2, LATITUDE2] ] as Vector2[]) { - const pair = coordinates.map(channel => - model.channelHasField(channel) - ? model.fieldDef(channel).field - : isValueDef(model.encoding[channel]) - ? {expr: (model.encoding[channel] as ValueDef).value + ''} - : undefined - ) as [GeoPositionChannel, GeoPositionChannel]; + const pair = coordinates.map(channel => { + const def = getFieldOrDatumDef(model.encoding[channel]); + return isFieldDef(def) + ? def.field + : isDatumDef(def) + ? {expr: `${def.datum}`} + : isValueDef(def) + ? {expr: `${def['value']}`} + : undefined; + }) as [GeoPositionChannel, GeoPositionChannel]; const suffix = coordinates[0] === LONGITUDE2 ? '2' : ''; diff --git a/src/compile/format.ts b/src/compile/format.ts index da1aebf75b..b7b000269a 100644 --- a/src/compile/format.ts +++ b/src/compile/format.ts @@ -1,11 +1,19 @@ import {isString} from 'vega-util'; import {isBinning} from '../bin'; -import {FieldDef, isFieldDefForTimeFormat, isScaleFieldDef, isTypedFieldDef, vgField} from '../channeldef'; +import { + channelDefType, + DatumDef, + FieldDef, + isFieldDef, + isFieldOrDatumDefForTimeFormat, + isScaleFieldDef, + vgField +} from '../channeldef'; import {Config} from '../config'; import {fieldValidPredicate} from '../predicate'; import {ScaleType} from '../scale'; import {formatExpression, normalizeTimeUnit, TimeUnit} from '../timeunit'; -import {QUANTITATIVE} from '../type'; +import {QUANTITATIVE, Type} from '../type'; export const BIN_RANGE_DELIMITER = ' \u2013 '; @@ -24,7 +32,7 @@ function customFormatExpr({formatType, field, format}: {formatType: string; fiel } export function formatSignalRef({ - fieldDef, + fieldOrDatumDef, format, formatType, expr, @@ -35,7 +43,7 @@ export function formatSignalRef({ omitTimeFormatConfig, isUTCScale }: { - fieldDef: FieldDef; + fieldOrDatumDef: FieldDef | DatumDef; format: string | object; formatType: string; expr?: 'datum' | 'parent' | 'datum.datum'; @@ -47,20 +55,26 @@ export function formatSignalRef({ isUTCScale?: boolean; }) { if (!field) { - if (normalizeStack) { - field = `${vgField(fieldDef, {expr, suffix: 'end'})}-${vgField(fieldDef, {expr, suffix: 'start'})}`; + if (isFieldDef(fieldOrDatumDef)) { + if (normalizeStack) { + field = `${vgField(fieldOrDatumDef, {expr, suffix: 'end'})}-${vgField(fieldOrDatumDef, { + expr, + suffix: 'start' + })}`; + } else { + field = vgField(fieldOrDatumDef, {expr}); + } } else { - field = vgField(fieldDef, {expr}); + field = `${fieldOrDatumDef.datum}`; } } - isUTCScale = - isUTCScale ?? (isScaleFieldDef(fieldDef) && fieldDef['scale'] && fieldDef['scale'].type === ScaleType.UTC); + isUTCScale = isUTCScale ?? (isScaleFieldDef(fieldOrDatumDef) && fieldOrDatumDef.scale?.type === ScaleType.UTC); const defaultTimeFormat = omitTimeFormatConfig ? null : config.timeFormat; if (isCustomFormatType(formatType)) { - if (isBinning(fieldDef.bin)) { - const endField = vgField(fieldDef, {expr, binSuffix: 'end'}); + if (isFieldDef(fieldOrDatumDef) && isBinning(fieldOrDatumDef.bin)) { + const endField = vgField(fieldOrDatumDef, {expr, binSuffix: 'end'}); return { signal: binFormatExpression(field, endField, format, formatType, config) }; @@ -70,10 +84,10 @@ export function formatSignalRef({ formatType = undefined; // drop unregistered custom formatType } - if (isFieldDefForTimeFormat(fieldDef)) { + if (isFieldOrDatumDefForTimeFormat(fieldOrDatumDef)) { const signal = timeFormatExpression( field, - normalizeTimeUnit(fieldDef.timeUnit)?.unit, + isFieldDef(fieldOrDatumDef) ? normalizeTimeUnit(fieldOrDatumDef.timeUnit)?.unit : undefined, format, defaultTimeFormat, isUTCScale, @@ -81,13 +95,13 @@ export function formatSignalRef({ ); return signal ? {signal} : undefined; } else if (!omitNumberFormatAndEmptyTimeFormat) { - format = numberFormat(fieldDef, format, config); - if (isBinning(fieldDef.bin)) { - const endField = vgField(fieldDef, {expr, binSuffix: 'end'}); + format = numberFormat(channelDefType(fieldOrDatumDef), format, config); + if (isFieldDef(fieldOrDatumDef) && isBinning(fieldOrDatumDef.bin)) { + const endField = vgField(fieldOrDatumDef, {expr, binSuffix: 'end'}); return { signal: binFormatExpression(field, endField, format, formatType, config) }; - } else if (format || (isTypedFieldDef(fieldDef) && fieldDef.type === 'quantitative')) { + } else if (format || channelDefType(fieldOrDatumDef) === 'quantitative') { return { signal: `${formatExpr(field, format)}` }; @@ -101,13 +115,13 @@ export function formatSignalRef({ /** * Returns number format for a fieldDef */ -export function numberFormat(fieldDef: FieldDef, specifiedFormat: string | object, config: Config) { +export function numberFormat(type: Type, specifiedFormat: string | object, config: Config) { // Specified format in axis/legend has higher precedence than fieldDef.format if (isString(specifiedFormat)) { return specifiedFormat; } - if (isTypedFieldDef(fieldDef) && fieldDef.type === QUANTITATIVE) { + if (type === QUANTITATIVE) { // we only apply the default if the field is quantitative return config.numberFormat; } diff --git a/src/compile/header/assemble.ts b/src/compile/header/assemble.ts index 13eccdf4d9..15ca0f7302 100644 --- a/src/compile/header/assemble.ts +++ b/src/compile/header/assemble.ts @@ -124,7 +124,8 @@ export function assembleLabelTitle(facetFieldDef: FacetFieldDef, channel channel ); - const titleTextExpr = formatSignalRef({fieldDef: facetFieldDef, format, formatType, expr: 'parent', config}).signal; + const titleTextExpr = formatSignalRef({fieldOrDatumDef: facetFieldDef, format, formatType, expr: 'parent', config}) + .signal; const headerChannel = getHeaderChannel(channel, labelOrient); return { diff --git a/src/compile/layoutsize/init.ts b/src/compile/layoutsize/init.ts index 4e2d94e3df..8bb81dca7d 100644 --- a/src/compile/layoutsize/init.ts +++ b/src/compile/layoutsize/init.ts @@ -1,5 +1,5 @@ import {getSizeType, POSITION_SCALE_CHANNELS} from '../../channel'; -import {getFieldDef, isContinuous, PositionFieldDef} from '../../channeldef'; +import {isContinuousFieldOrDatumDef} from '../../channeldef'; import {Encoding} from '../../encoding'; import * as log from '../../log'; import {isStep, LayoutSizeMixins} from '../../spec/base'; @@ -7,13 +7,10 @@ import {isStep, LayoutSizeMixins} from '../../spec/base'; export function initLayoutSize({encoding, size}: {encoding: Encoding; size: LayoutSizeMixins}) { for (const channel of POSITION_SCALE_CHANNELS) { const sizeType = getSizeType(channel); - const fieldDef = getFieldDef(encoding[channel]) as PositionFieldDef; if (isStep(size[sizeType])) { - if (fieldDef) { - if (isContinuous(fieldDef)) { - delete size[sizeType]; - log.warn(log.message.stepDropped(sizeType)); - } + if (isContinuousFieldOrDatumDef(encoding[channel])) { + delete size[sizeType]; + log.warn(log.message.stepDropped(sizeType)); } } } diff --git a/src/compile/legend/encode.ts b/src/compile/legend/encode.ts index b69c8b3cca..3b179c12f9 100644 --- a/src/compile/legend/encode.ts +++ b/src/compile/legend/encode.ts @@ -3,8 +3,10 @@ import {array, isArray, stringValue} from 'vega-util'; import {COLOR, NonPositionScaleChannel, OPACITY, ScaleChannel} from '../../channel'; import { Conditional, + DatumDef, Gradient, hasConditionalValueDef, + isFieldDef, isValueDef, TypedFieldDef, Value, @@ -28,7 +30,7 @@ function type(legendCmp: LegendComponent, model: UnitModel, channel: ScaleChanne } export function symbols( - fieldDef: TypedFieldDef, + fieldOrDatumDef: TypedFieldDef | DatumDef, symbolsSpec: any, model: UnitModel, channel: ScaleChannel, @@ -47,7 +49,6 @@ export function symbols( } as SymbolEncodeEntry; // FIXME: remove this when VgEncodeEntry is compatible with SymbolEncodeEntry const opacity = getMaxValue(encoding.opacity) ?? markDef.opacity; - const condition = selectedCondition(model, legendCmp, fieldDef); if (out.fill) { // for fill legend, we don't want any fill in symbol @@ -93,6 +94,8 @@ export function symbols( } if (channel !== OPACITY) { + const condition = isFieldDef(fieldOrDatumDef) && selectedCondition(model, legendCmp, fieldOrDatumDef); + if (condition) { out.opacity = [ {test: condition, ...signalOrValueRef(opacity ?? 1)}, @@ -109,7 +112,7 @@ export function symbols( } export function gradient( - fieldDef: TypedFieldDef, + fieldOrDatumDef: TypedFieldDef | DatumDef, gradientSpec: any, model: UnitModel, channel: ScaleChannel, @@ -132,7 +135,7 @@ export function gradient( } export function labels( - fieldDef: TypedFieldDef, + fieldOrDatumDef: TypedFieldDef | DatumDef, specifiedlabelsSpec: any, model: UnitModel, channel: NonPositionScaleChannel, @@ -140,13 +143,14 @@ export function labels( ) { const legend = model.legend(channel) || {}; const config = model.config; - const condition = selectedCondition(model, legendCmp, fieldDef); + + const condition = isFieldDef(fieldOrDatumDef) ? selectedCondition(model, legendCmp, fieldOrDatumDef) : undefined; const opacity = condition ? [{test: condition, value: 1}, {value: config.legend.unselectedOpacity}] : undefined; const {format, formatType} = legend; const text = formatSignalRef({ - fieldDef, + fieldOrDatumDef, format, formatType, field: 'datum.value', @@ -165,7 +169,7 @@ export function labels( } export function entries( - fieldDef: TypedFieldDef, + fieldOrDatumDef: TypedFieldDef | DatumDef, entriesSpec: any, model: UnitModel, channel: NonPositionScaleChannel, diff --git a/src/compile/legend/parse.ts b/src/compile/legend/parse.ts index 15e17014fa..4024b96f23 100644 --- a/src/compile/legend/parse.ts +++ b/src/compile/legend/parse.ts @@ -12,7 +12,16 @@ import { STROKEOPACITY, STROKEWIDTH } from '../../channel'; -import {FieldDef, isFieldDef, isFieldDefForTimeFormat, title as fieldDefTitle} from '../../channeldef'; +import { + DatumDef, + FieldDef, + getFieldOrDatumDef, + isFieldDef, + isFieldOrDatumDefForTimeFormat, + MarkPropDatumDef, + MarkPropFieldDef, + title as fieldDefTitle +} from '../../channeldef'; import {Legend} from '../../legend'; import {normalizeTimeUnit} from '../../timeunit'; import {GEOJSON} from '../../type'; @@ -42,12 +51,8 @@ function parseUnitLegend(model: UnitModel): LegendComponentIndex { const {encoding} = model; return [COLOR, FILL, STROKE, STROKEWIDTH, STROKEDASH, SIZE, SHAPE, OPACITY, FILLOPACITY, STROKEOPACITY].reduce( (legendComponent, channel) => { - const def = encoding[channel]; - if ( - model.channelHasField(channel) && - model.getScaleComponent(channel) && - !(isFieldDef(def) && channel === SHAPE && def.type === GEOJSON) - ) { + const def = getFieldOrDatumDef(encoding[channel]) as MarkPropFieldDef | MarkPropDatumDef; + if (def && model.getScaleComponent(channel) && !(isFieldDef(def) && channel === SHAPE && def.type === GEOJSON)) { legendComponent[channel] = parseLegendForChannel(model, channel); } return legendComponent; @@ -88,7 +93,7 @@ function isExplicit( return !!legend?.values; case 'title': // title can be explicit if fieldDef.title is set - if (property === 'title' && value === fieldDef.title) { + if (property === 'title' && value === fieldDef?.title) { return true; } } @@ -97,7 +102,6 @@ function isExplicit( } export function parseLegendForChannel(model: UnitModel, channel: NonPositionScaleChannel): LegendComponent { - const fieldDef = model.fieldDef(channel); const legend = model.legend(channel); const legendCmpt = new LegendComponent({}, getLegendDefWithScale(model, channel)); @@ -106,7 +110,7 @@ export function parseLegendForChannel(model: UnitModel, channel: NonPositionScal for (const property of LEGEND_COMPONENT_PROPERTIES) { const value = getProperty(property, legend, channel, model); if (value !== undefined) { - const explicit = isExplicit(value, property, legend, fieldDef); + const explicit = isExplicit(value, property, legend, model.fieldDef(channel)); if (explicit || model.config.legend[property] === undefined) { legendCmpt.set(property, value, explicit); } @@ -118,12 +122,18 @@ export function parseLegendForChannel(model: UnitModel, channel: NonPositionScal const legendEncode = (['labels', 'legend', 'title', 'symbols', 'gradient', 'entries'] as const).reduce( (e: LegendEncode, part) => { const legendEncodingPart = guideEncodeEntry(legendEncoding[part] ?? {}, model); + + const fieldOrDatumDef = getFieldOrDatumDef(model.encoding[channel]); + const value = encode[part] - ? encode[part](fieldDef, legendEncodingPart, model, channel, legendCmpt) // apply rule + ? encode[part](fieldOrDatumDef, legendEncodingPart, model, channel, legendCmpt) // apply rule : legendEncodingPart; // no rule -- just default values + if (value !== undefined && keys(value).length > 0) { e[part] = { - ...(selections?.length ? {name: `${varName(fieldDef.field)}_legend_${part}`} : {}), + ...(selections?.length && isFieldDef(fieldOrDatumDef) + ? {name: `${varName(fieldOrDatumDef.field)}_legend_${part}`} + : {}), ...(selections?.length ? {interactive: !!selections} : {}), update: value }; @@ -152,9 +162,9 @@ function getProperty( legend = legend || {}; // assign object so the rest doesn't have to check if legend exists const {encoding, mark} = model; - const fieldDef = model.typedFieldDef(channel); + const fieldOrDatumDef = getFieldOrDatumDef(encoding[channel]) as MarkPropFieldDef | DatumDef; const legendConfig = model.config.legend; - const timeUnit = normalizeTimeUnit(fieldDef.timeUnit)?.unit; + const timeUnit = isFieldDef(fieldOrDatumDef) ? normalizeTimeUnit(fieldOrDatumDef.timeUnit)?.unit : undefined; const scaleType = model.getScaleComponent(channel).get('type'); @@ -174,14 +184,14 @@ function getProperty( case 'format': // We don't include temporal field here as we apply format in encode block - if (isFieldDefForTimeFormat(fieldDef)) { + if (isFieldOrDatumDefForTimeFormat(fieldOrDatumDef)) { return undefined; } - return numberFormat(fieldDef, legend.format, model.config) as LegendComponentProps[K]; + return numberFormat(fieldOrDatumDef.type, legend.format, model.config) as LegendComponentProps[K]; case 'formatType': // As with format, we don't include temporal field here as we apply format in encode block - if (isFieldDefForTimeFormat(fieldDef)) { + if (isFieldOrDatumDefForTimeFormat(fieldOrDatumDef)) { return undefined; } return legend.formatType as LegendComponentProps[K]; @@ -211,13 +221,13 @@ function getProperty( ) as LegendComponentProps[K]; case 'title': - return fieldDefTitle(fieldDef, model.config, {allowDisabling: true}) as LegendComponentProps[K]; + return fieldDefTitle(fieldOrDatumDef, model.config, {allowDisabling: true}) as LegendComponentProps[K]; case 'type': return type({legend, channel, timeUnit, scaleType, alwaysReturn: false}) as LegendComponentProps[K]; case 'values': - return properties.values(legend, fieldDef) as LegendComponentProps[K]; + return properties.values(legend, fieldOrDatumDef) as LegendComponentProps[K]; } // Otherwise, return specified property. diff --git a/src/compile/legend/properties.ts b/src/compile/legend/properties.ts index 3c5122e45a..be908edf5d 100644 --- a/src/compile/legend/properties.ts +++ b/src/compile/legend/properties.ts @@ -1,7 +1,7 @@ import {LabelOverlap, LegendOrient, LegendType, SignalRef, SymbolShape} from 'vega'; import {isArray} from 'vega-util'; import {Channel, isColorChannel} from '../../channel'; -import {TypedFieldDef, valueArray} from '../../channeldef'; +import {DatumDef, TypedFieldDef, valueArray} from '../../channeldef'; import {Encoding} from '../../encoding'; import {Legend, LegendConfig} from '../../legend'; import {Mark} from '../../mark'; @@ -12,11 +12,11 @@ import {isSignalRef} from '../../vega.schema'; import {Model} from '../model'; import {getFirstConditionValue} from './encode'; -export function values(legend: Legend, fieldDef: TypedFieldDef) { +export function values(legend: Legend, fieldOrDatumDef: TypedFieldDef | DatumDef) { const vals = legend.values; if (isArray(vals)) { - return valueArray(fieldDef, vals); + return valueArray(fieldOrDatumDef, vals); } else if (isSignalRef(vals)) { return vals; } diff --git a/src/compile/mark/encode/position-point.ts b/src/compile/mark/encode/position-point.ts index 0526841ca4..610fb5536a 100644 --- a/src/compile/mark/encode/position-point.ts +++ b/src/compile/mark/encode/position-point.ts @@ -1,5 +1,5 @@ import {getMainRangeChannel, PositionChannel, X, X2, Y2} from '../../../channel'; -import {isFieldDef, isPositionFieldDef} from '../../../channeldef'; +import {isFieldOrDatumDef, isPositionFieldOrDatumDef} from '../../../channeldef'; import {ScaleType} from '../../../scale'; import {contains, getFirstDefined} from '../../../util'; import {VgValueRef} from '../../../vega.schema'; @@ -71,18 +71,18 @@ function positionRef( const {channel, channelDef, scaleName, stack, offset} = params; // This isn't a part of midPoint because we use midPoint for non-position too - if (isFieldDef(channelDef) && stack && channel === stack.fieldChannel) { - if (isPositionFieldDef(channelDef) && channelDef.band !== undefined) { + if (isFieldOrDatumDef(channelDef) && stack && channel === stack.fieldChannel) { + if (isPositionFieldOrDatumDef(channelDef) && channelDef.band !== undefined) { return ref.interpolatedSignalRef({ scaleName, - fieldDef: channelDef, + fieldOrDatumDef: channelDef, startSuffix: 'start', band: channelDef.band, offset: 0 }); } // x or y use stack_end so that stacked line's point mark use stack_end too. - return ref.fieldRef(channelDef, scaleName, {suffix: 'end'}, {offset}); + return ref.valueRefForFieldOrDatumDef(channelDef, scaleName, {suffix: 'end'}, {offset}); } return ref.midPointRefWithPositionInvalidTest(params); diff --git a/src/compile/mark/encode/position-range.ts b/src/compile/mark/encode/position-range.ts index d94403e266..f418d4d035 100644 --- a/src/compile/mark/encode/position-range.ts +++ b/src/compile/mark/encode/position-range.ts @@ -1,4 +1,4 @@ -import {isFieldDef} from '../../../channeldef'; +import {isFieldOrDatumDef} from '../../../channeldef'; import {MarkConfig} from '../../../mark'; import {getFirstDefined} from '../../../util'; import {VgEncodeEntry, VgValueRef} from '../../../vega.schema'; @@ -136,12 +136,12 @@ function position2Ref({ channel: 'x2' | 'y2'; }): VgValueRef | VgValueRef[] { if ( - isFieldDef(channelDef) && + isFieldOrDatumDef(channelDef) && stack && // If fieldChannel is X and channel is X2 (or Y and Y2) channel.charAt(0) === stack.fieldChannel.charAt(0) ) { - return ref.fieldRef(channelDef, scaleName, {suffix: 'start'}, {offset}); + return ref.valueRefForFieldOrDatumDef(channelDef, scaleName, {suffix: 'start'}, {offset}); } return ref.midPointRefWithPositionInvalidTest({ channel, diff --git a/src/compile/mark/encode/position-rect.ts b/src/compile/mark/encode/position-rect.ts index de429428a7..48b00f2367 100644 --- a/src/compile/mark/encode/position-rect.ts +++ b/src/compile/mark/encode/position-rect.ts @@ -5,8 +5,10 @@ import {PositionChannel, X, X2, Y2} from '../../../channel'; import { getBand, isFieldDef, - isPositionFieldDef, + isFieldOrDatumDef, + isPositionFieldOrDatumDef, isValueDef, + PositionDatumDef, PositionFieldDef, TypedFieldDef } from '../../../channeldef'; @@ -69,10 +71,10 @@ export function rectPosition(model: UnitModel, channel: 'x' | 'y', mark: 'bar' | reverse: scale.get('reverse'), config }); - } else if (((isFieldDef(fieldDef) && hasDiscreteDomain(scaleType)) || isBarBand) && !fieldDef2) { + } else if (((isFieldOrDatumDef(fieldDef) && hasDiscreteDomain(scaleType)) || isBarBand) && !fieldDef2) { // vertical - if (isFieldDef(fieldDef) && scaleType === ScaleType.BAND) { - const band = isPositionFieldDef(fieldDef) ? fieldDef.band : undefined; + if (isFieldOrDatumDef(fieldDef) && scaleType === ScaleType.BAND) { + const band = isPositionFieldOrDatumDef(fieldDef) ? fieldDef.band : undefined; return rectBandPosition( fieldDef, channel, @@ -162,7 +164,7 @@ function bandRef(scaleName: string, band: number | boolean = true): VgValueRef { } function rectBandPosition( - fieldDef: PositionFieldDef, + fieldDef: PositionFieldDef | PositionDatumDef, channel: 'x' | 'y', model: UnitModel, sizeRef?: VgValueRef @@ -175,13 +177,13 @@ function rectBandPosition( const offset = getOffset(channel, markDef); const centeredBandPositionMixins = { - [vgChannel]: ref.fieldRef(fieldDef, scaleName, {}, {band: 0.5, offset}) + [vgChannel]: ref.valueRefForFieldOrDatumDef(fieldDef, scaleName, {}, {band: 0.5, offset}) }; if (encoding.size || (markDef.size !== null && markDef.size !== undefined)) { const orient = markDef.orient; if (orient) { - if (isFieldDef(encoding.size) || isValueDef(encoding.size)) { + if (isFieldOrDatumDef(encoding.size) || isValueDef(encoding.size)) { return { ...centeredBandPositionMixins, ...nonPosition('size', model, {vgChannel: sizeChannel}) @@ -206,7 +208,12 @@ function rectBandPosition( const {band = 1} = fieldDef; return { - [channel]: ref.fieldRef(fieldDef, scaleName, {binSuffix: 'range'}, {band: (1 - band) / 2, offset}), + [channel]: ref.valueRefForFieldOrDatumDef( + fieldDef, + scaleName, + {binSuffix: 'range'}, + {band: (1 - band) / 2, offset} + ), [sizeChannel]: sizeRef ?? bandRef(scaleName, band) }; } @@ -274,8 +281,18 @@ export function rectBinPosition({ }; } else if (isBinned(fieldDef.bin) && isFieldDef(fieldDef2)) { return { - [channel2]: ref.fieldRef(fieldDef, scaleName, {}, {offset: getBinSpacing(channel2, spacing, reverse)}), - [channel]: ref.fieldRef(fieldDef2, scaleName, {}, {offset: getBinSpacing(channel, spacing, reverse)}) + [channel2]: ref.valueRefForFieldOrDatumDef( + fieldDef, + scaleName, + {}, + {offset: getBinSpacing(channel2, spacing, reverse)} + ), + [channel]: ref.valueRefForFieldOrDatumDef( + fieldDef2, + scaleName, + {}, + {offset: getBinSpacing(channel, spacing, reverse)} + ) }; } else { log.warn(log.message.channelRequiredForBinned(channel2)); @@ -305,7 +322,7 @@ export function rectBinRef({ }) { const r = ref.interpolatedSignalRef({ scaleName, - fieldDef, + fieldOrDatumDef: fieldDef, band, offset }); diff --git a/src/compile/mark/encode/text.ts b/src/compile/mark/encode/text.ts index 18aa5347f8..c6161c09b1 100644 --- a/src/compile/mark/encode/text.ts +++ b/src/compile/mark/encode/text.ts @@ -23,7 +23,7 @@ export function textRef( } if (isTypedFieldDef(channelDef)) { const {format, formatType} = getFormatMixins(channelDef); - return formatSignalRef({fieldDef: channelDef, format, formatType, expr, config}); + return formatSignalRef({fieldOrDatumDef: channelDef, format, formatType, expr, config}); } } return undefined; diff --git a/src/compile/mark/encode/tooltip.ts b/src/compile/mark/encode/tooltip.ts index 6b66cd1a5a..78f74fcb43 100644 --- a/src/compile/mark/encode/tooltip.ts +++ b/src/compile/mark/encode/tooltip.ts @@ -101,7 +101,8 @@ export function tooltipRefForEncoding( toSkip[channel2] = true; } else if (stack && stack.fieldChannel === channel && stack.offset === 'normalize') { const {format, formatType} = getFormatMixins(fieldDef); - value = formatSignalRef({fieldDef, format, formatType, expr, config, normalizeStack: true}).signal; + value = formatSignalRef({fieldOrDatumDef: fieldDef, format, formatType, expr, config, normalizeStack: true}) + .signal; } } diff --git a/src/compile/mark/encode/valueref.ts b/src/compile/mark/encode/valueref.ts index 7bc3b56eb7..b1074bae27 100644 --- a/src/compile/mark/encode/valueref.ts +++ b/src/compile/mark/encode/valueref.ts @@ -9,13 +9,16 @@ import {Channel, getMainRangeChannel, PositionChannel, X, X2, Y, Y2} from '../.. import { binRequiresRange, ChannelDef, + DatumDef, FieldDef, FieldDefBase, FieldName, FieldRefOption, getBand, + isDatumDef, isFieldDef, - isPositionFieldDef, + isFieldOrDatumDef, + isPositionFieldOrDatumDef, isTypedFieldDef, isValueDef, SecondaryChannelDef, @@ -104,24 +107,32 @@ export function fieldInvalidPredicate(field: FieldName | FieldDef, inval return fieldValidPredicate(isString(field) ? field : vgField(field, {expr: 'datum'}), !invalid); } -export function fieldRef( - fieldDef: FieldDefBase, +export function valueRefForFieldOrDatumDef( + fieldDef: FieldDefBase | DatumDef, scaleName: string, opt: FieldRefOption, encode: {offset?: number | VgValueRef; band?: number | boolean} ): VgValueRef { - const ref: VgValueRef = { - ...(scaleName ? {scale: scaleName} : {}), - field: vgField(fieldDef, opt) - }; + const ref: VgValueRef = {}; + + if (scaleName) { + ref.scale = scaleName; + } + + if (isDatumDef(fieldDef)) { + ref.value = fieldDef.datum; + } else { + ref.field = vgField(fieldDef, opt); + } if (encode) { const {offset, band} = encode; - return { - ...ref, - ...(offset ? {offset} : {}), - ...(band ? {band} : {}) - }; + if (offset) { + ref.offset = offset; + } + if (band) { + ref.band = band; + } } return ref; } @@ -131,43 +142,49 @@ export function fieldRef( */ export function interpolatedSignalRef({ scaleName, - fieldDef, - fieldDef2, + fieldOrDatumDef, + fieldOrDatumDef2, offset, startSuffix, band = 0.5 }: { scaleName: string; - fieldDef: TypedFieldDef; - fieldDef2?: SecondaryFieldDef; + fieldOrDatumDef: TypedFieldDef | DatumDef; + fieldOrDatumDef2?: SecondaryFieldDef | DatumDef; startSuffix?: string; offset: number | SignalRef; band: number; -}) { +}): VgValueRef { const expr = 0 < band && band < 1 ? 'datum' : undefined; - const start = vgField(fieldDef, {expr, suffix: startSuffix}); - const end = fieldDef2 !== undefined ? vgField(fieldDef2, {expr}) : vgField(fieldDef, {suffix: 'end', expr}); + const start = isFieldDef(fieldOrDatumDef) ? vgField(fieldOrDatumDef, {expr, suffix: startSuffix}) : fieldOrDatumDef; + const end = + fieldOrDatumDef2 !== undefined + ? isFieldDef(fieldOrDatumDef2) + ? vgField(fieldOrDatumDef2, {expr}) + : fieldOrDatumDef2 + : isFieldDef(fieldOrDatumDef) + ? vgField(fieldOrDatumDef, {suffix: 'end', expr}) + : fieldOrDatumDef; - if (band === 0) { - return { - scale: scaleName, - field: start, - ...(offset ? {offset} : {}) - }; - } else if (band === 1) { - return { - scale: scaleName, - field: end, - ...(offset ? {offset} : {}) - }; + const ref: VgValueRef = {}; + + if (band === 0 || band === 1) { + ref.scale = scaleName; + const val = band === 0 ? start : end; + if (isString(val)) { + ref.field = val; + } else { + ref.value = val.datum; + } } else { const datum = `${band} * ${start} + ${1 - band} * ${end}`; + ref.signal = `scale("${scaleName}", ${datum})`; + } - return { - signal: `scale("${scaleName}", ${datum})`, - ...(offset ? {offset} : {}) - }; + if (offset) { + ref.offset = offset; } + return ref; } export interface MidPointParams { @@ -204,7 +221,7 @@ export function midPoint({ if (channelDef) { /* istanbul ignore else */ - if (isFieldDef(channelDef)) { + if (isFieldOrDatumDef(channelDef)) { if (isTypedFieldDef(channelDef)) { const band = getBand(channel, channelDef, channel2Def, markDef, config, {isMidPoint: true}); @@ -214,17 +231,28 @@ export function midPoint({ if (contains([X, Y], channel) && contains([QUANTITATIVE, TEMPORAL], channelDef.type)) { if (stack && stack.impute) { // For stack, we computed bin_mid so we can impute. - return fieldRef(channelDef, scaleName, {binSuffix: 'mid'}, {offset}); + return valueRefForFieldOrDatumDef(channelDef, scaleName, {binSuffix: 'mid'}, {offset}); } // For non-stack, we can just calculate bin mid on the fly using signal. - return interpolatedSignalRef({scaleName, fieldDef: channelDef, band, offset}); + return interpolatedSignalRef({scaleName, fieldOrDatumDef: channelDef, band, offset}); } - return fieldRef(channelDef, scaleName, binRequiresRange(channelDef, channel) ? {binSuffix: 'range'} : {}, { - offset - }); + return valueRefForFieldOrDatumDef( + channelDef, + scaleName, + binRequiresRange(channelDef, channel) ? {binSuffix: 'range'} : {}, + { + offset + } + ); } else if (isBinned(channelDef.bin)) { if (isFieldDef(channel2Def)) { - return interpolatedSignalRef({scaleName, fieldDef: channelDef, fieldDef2: channel2Def, band, offset}); + return interpolatedSignalRef({ + scaleName, + fieldOrDatumDef: channelDef, + fieldOrDatumDef2: channel2Def, + band, + offset + }); } else { const channel2 = channel === X ? X2 : Y2; log.warn(log.message.channelRequiredForBinned(channel2)); @@ -237,13 +265,13 @@ export function midPoint({ if (hasDiscreteDomain(scaleType)) { if (scaleType === 'band') { // For band, to get mid point, need to offset by half of the band - const band = getFirstDefined(isPositionFieldDef(channelDef) ? channelDef.band : undefined, 0.5); - return fieldRef(channelDef, scaleName, {binSuffix: 'range'}, {band, offset}); + const band = getFirstDefined(isPositionFieldOrDatumDef(channelDef) ? channelDef.band : undefined, 0.5); + return valueRefForFieldOrDatumDef(channelDef, scaleName, {binSuffix: 'range'}, {band, offset}); } - return fieldRef(channelDef, scaleName, {binSuffix: 'range'}, {offset}); + return valueRefForFieldOrDatumDef(channelDef, scaleName, {binSuffix: 'range'}, {offset}); } } - return fieldRef(channelDef, scaleName, {}, {offset}); // no need for bin suffix + return valueRefForFieldOrDatumDef(channelDef, scaleName, {}, {offset}); // no need for bin suffix } else if (isValueDef(channelDef)) { const value = channelDef.value; const offsetMixins = offset ? {offset} : {}; diff --git a/src/compile/mark/init.ts b/src/compile/mark/init.ts index 567c98394e..c7774ed6a7 100644 --- a/src/compile/mark/init.ts +++ b/src/compile/mark/init.ts @@ -1,6 +1,6 @@ import {Orientation} from 'vega'; import {isBinned, isBinning} from '../../bin'; -import {isContinuous, isFieldDef, TypedFieldDef} from '../../channeldef'; +import {isContinuousFieldOrDatumDef, isFieldDef, isNumericDataDef, TypedFieldDef} from '../../channeldef'; import {Config} from '../../config'; import {Encoding, isAggregate} from '../../encoding'; import * as log from '../../log'; @@ -136,13 +136,17 @@ function orient(mark: Mark, encoding: Encoding, specifiedOrient: Orienta } // If y is range and x is non-range, non-bin Q, y is likely a prebinned field - if (!x2 && isFieldDef(x) && x.type === QUANTITATIVE && !isBinning(x.bin)) { - return 'horizontal'; + if (!x2) { + if ((isFieldDef(x) && x.type === QUANTITATIVE && !isBinning(x.bin)) || isNumericDataDef(x)) { + return 'horizontal'; + } } // If x is range and y is non-range, non-bin Q, x is likely a prebinned field - if (!y2 && isFieldDef(y) && y.type === QUANTITATIVE && !isBinning(y.bin)) { - return 'vertical'; + if (!y2) { + if ((isFieldDef(y) && y.type === QUANTITATIVE && !isBinning(y.bin)) || isNumericDataDef(y)) { + return 'vertical'; + } } } @@ -181,8 +185,8 @@ function orient(mark: Mark, encoding: Encoding, specifiedOrient: Orienta case LINE: case TICK: { // Tick is opposite to bar, line, area and never have ranged mark. - const xIsContinuous = isFieldDef(x) && isContinuous(x); - const yIsContinuous = isFieldDef(y) && isContinuous(y); + const xIsContinuous = isContinuousFieldOrDatumDef(x); + const yIsContinuous = isContinuousFieldOrDatumDef(y); if (xIsContinuous && !yIsContinuous) { return mark !== 'tick' ? 'horizontal' : 'vertical'; } else if (!xIsContinuous && yIsContinuous) { diff --git a/src/compile/projection/parse.ts b/src/compile/projection/parse.ts index 8c8d4f2ab6..6a7248c18e 100644 --- a/src/compile/projection/parse.ts +++ b/src/compile/projection/parse.ts @@ -1,6 +1,7 @@ import {SignalRef} from 'vega'; import {hasOwnProperty} from 'vega-util'; import {LATITUDE, LATITUDE2, LONGITUDE, LONGITUDE2, SHAPE} from '../../channel'; +import {getFieldOrDatumDef} from '../../channeldef'; import {MAIN} from '../../data'; import {PROJECTION_PROPERTIES} from '../../projection'; import {GEOJSON} from '../../type'; @@ -37,11 +38,13 @@ function parseUnitProjection(model: UnitModel): ProjectionComponent { function gatherFitData(model: UnitModel) { const data: (SignalRef | string)[] = []; + const {encoding} = model; + for (const posssiblePair of [ [LONGITUDE, LATITUDE], [LONGITUDE2, LATITUDE2] ]) { - if (model.channelHasField(posssiblePair[0]) || model.channelHasField(posssiblePair[1])) { + if (getFieldOrDatumDef(encoding[posssiblePair[0]]) || getFieldOrDatumDef(encoding[posssiblePair[1]])) { data.push({ signal: model.getName(`geojson_${data.length}`) }); diff --git a/src/compile/scale/domain.ts b/src/compile/scale/domain.ts index 6ffe4ea591..cf87cdb15d 100644 --- a/src/compile/scale/domain.ts +++ b/src/compile/scale/domain.ts @@ -10,7 +10,17 @@ import { } from '../../aggregate'; import {isBinning, isBinParams, isSelectionExtent} from '../../bin'; import {getMainRangeChannel, getSecondaryRangeChannel, isScaleChannel, ScaleChannel} from '../../channel'; -import {binRequiresRange, hasBand, ScaleFieldDef, TypedFieldDef, valueExpr, vgField} from '../../channeldef'; +import { + binRequiresRange, + getFieldOrDatumDef, + hasBand, + isDatumDef, + isFieldDef, + ScaleFieldDef, + TypedFieldDef, + valueExpr, + vgField +} from '../../channeldef'; import {MAIN, RAW} from '../../data'; import {DateTime} from '../../datetime'; import * as log from '../../log'; @@ -152,6 +162,7 @@ function normalizeUnaggregatedDomain( export function parseDomainForChannel(model: UnitModel, channel: ScaleChannel): Explicit { const scaleType = model.getScaleComponent(channel).get('type'); + const {encoding} = model; const domain = normalizeUnaggregatedDomain( model.scaleDomain(channel), @@ -167,8 +178,8 @@ export function parseDomainForChannel(model: UnitModel, channel: ScaleChannel): } // If channel is either X or Y then union them with X2 & Y2 if they exist - if (channel === 'x' && model.channelHasField('x2')) { - if (model.channelHasField('x')) { + if (channel === 'x' && getFieldOrDatumDef(encoding.x2)) { + if (getFieldOrDatumDef(encoding.x)) { return mergeValuesWithExplicit( parseSingleChannelDomain(scaleType, domain, model, 'x'), parseSingleChannelDomain(scaleType, domain, model, 'x2'), @@ -179,8 +190,8 @@ export function parseDomainForChannel(model: UnitModel, channel: ScaleChannel): } else { return parseSingleChannelDomain(scaleType, domain, model, 'x2'); } - } else if (channel === 'y' && model.channelHasField('y2')) { - if (model.channelHasField('y')) { + } else if (channel === 'y' && getFieldOrDatumDef(encoding.y2)) { + if (getFieldOrDatumDef(encoding.y)) { return mergeValuesWithExplicit( parseSingleChannelDomain(scaleType, domain, model, 'y'), parseSingleChannelDomain(scaleType, domain, model, 'y2'), @@ -226,19 +237,22 @@ function parseSingleChannelDomain( model: UnitModel, channel: ScaleChannel | 'x2' | 'y2' ): Explicit { - const fieldDef = model.fieldDef(channel); - const mainFieldDef = model.typedFieldDef(getMainRangeChannel(channel)); + const {encoding} = model; + const fieldOrDatumDef = getFieldOrDatumDef(encoding[channel]); if (isDomainUnionWith(domain)) { const defaultDomain = parseSingleChannelDomain(scaleType, undefined, model, channel); - const unionWith = convertDomainIfItIsDateTime(domain.unionWith, mainFieldDef.type, fieldDef.timeUnit); + const {type, timeUnit} = model.typedFieldDef(getMainRangeChannel(channel)) || {}; + + const unionWith = convertDomainIfItIsDateTime(domain.unionWith, type, timeUnit); return makeExplicit([...defaultDomain.value, ...unionWith]); } else if (isSignalRef(domain)) { return makeExplicit([domain]); } else if (domain && domain !== 'unaggregated' && !isSelectionDomain(domain)) { - return makeExplicit(convertDomainIfItIsDateTime(domain, mainFieldDef.type, fieldDef.timeUnit)); + const {type, timeUnit} = model.typedFieldDef(getMainRangeChannel(channel)) || {}; + return makeExplicit(convertDomainIfItIsDateTime(domain, type, timeUnit)); } const stack = model.stack; @@ -260,13 +274,17 @@ function parseSingleChannelDomain( ]); } - const sort: undefined | true | VgSortField = isScaleChannel(channel) - ? domainSort(model, channel, scaleType) - : undefined; + const sort: undefined | true | VgSortField = + isScaleChannel(channel) && isFieldDef(fieldOrDatumDef) ? domainSort(model, channel, scaleType) : undefined; + + if (isDatumDef(fieldOrDatumDef)) { + return makeImplicit([[fieldOrDatumDef.datum] as VgNonUnionDomain]); + } + const fieldDef = fieldOrDatumDef; // now we can be sure it's a fieldDef if (domain === 'unaggregated') { const data = model.requestDataName(MAIN); - const {field} = fieldDef; + const {field} = fieldOrDatumDef; return makeImplicit([ { data, @@ -380,7 +398,7 @@ function normalizeSortField(sort: EncodingSortField, isStackedMeasure: b function parseSelectionDomain(model: UnitModel, channel: ScaleChannel) { const scale = model.component.scales[channel]; const spec = model.specifiedScales[channel].domain; - const bin = model.fieldDef(channel).bin; + const bin = model.fieldDef(channel)?.bin; const domain = isSelectionDomain(spec) && spec; const extent = isBinParams(bin) && isSelectionExtent(bin.extent) && bin.extent; diff --git a/src/compile/scale/parse.ts b/src/compile/scale/parse.ts index 0a23f390ae..21603d121f 100644 --- a/src/compile/scale/parse.ts +++ b/src/compile/scale/parse.ts @@ -1,9 +1,8 @@ import {ScaleChannel, SCALE_CHANNELS, SHAPE} from '../../channel'; -import {hasConditionalFieldDef, isFieldDef, TypedFieldDef} from '../../channeldef'; +import {getFieldOrDatumDef, ScaleDatumDef, TypedFieldDef} from '../../channeldef'; import {GEOSHAPE} from '../../mark'; import { NON_TYPE_DOMAIN_RANGE_VEGA_SCALE_PROPERTIES, - Scale, scaleCompatible, ScaleType, scaleTypePrecedence @@ -47,29 +46,18 @@ function parseUnitScaleCore(model: UnitModel): ScaleComponentIndex { const {encoding, mark} = model; return SCALE_CHANNELS.reduce((scaleComponents: ScaleComponentIndex, channel: ScaleChannel) => { - let fieldDef: TypedFieldDef; - let specifiedScale: Scale | null; - - const channelDef = encoding[channel]; + const fieldOrDatumDef = getFieldOrDatumDef(encoding[channel]) as TypedFieldDef | ScaleDatumDef; // must be typed def to have scale // Don't generate scale for shape of geoshape - if (isFieldDef(channelDef) && mark === GEOSHAPE && channel === SHAPE && channelDef.type === GEOJSON) { + if (fieldOrDatumDef && mark === GEOSHAPE && channel === SHAPE && fieldOrDatumDef.type === GEOJSON) { return scaleComponents; } + let specifiedScale = fieldOrDatumDef && fieldOrDatumDef['scale']; - if (isFieldDef(channelDef)) { - fieldDef = channelDef; - specifiedScale = channelDef.scale; - } else if (hasConditionalFieldDef(channelDef)) { - // Need to specify generic for hasConditionalFieldDef as the value type can vary across channels - fieldDef = channelDef.condition; - specifiedScale = channelDef.condition['scale']; // We use ['scale'] since we know that channel here has scale for sure - } - - if (fieldDef && specifiedScale !== null && specifiedScale !== false) { + if (fieldOrDatumDef && specifiedScale !== null && specifiedScale !== false) { specifiedScale = specifiedScale ?? {}; - const sType = scaleType(specifiedScale, channel, fieldDef, mark); + const sType = scaleType(specifiedScale, channel, fieldOrDatumDef, mark); scaleComponents[channel] = new ScaleComponent(model.scaleName(channel + '', true), { value: sType, explicit: specifiedScale.type === sType diff --git a/src/compile/scale/properties.ts b/src/compile/scale/properties.ts index cb25abbc25..13489eee2b 100644 --- a/src/compile/scale/properties.ts +++ b/src/compile/scale/properties.ts @@ -2,7 +2,14 @@ import {SignalRef, TimeInterval} from 'vega'; import {isArray} from 'vega-util'; import {isBinned, isBinning, isBinParams} from '../../bin'; import {Channel, COLOR, FILL, ScaleChannel, STROKE, X, Y} from '../../channel'; -import {ScaleFieldDef, TypedFieldDef} from '../../channeldef'; +import { + getFieldDef, + getFieldOrDatumDef, + isFieldDef, + ScaleDatumDef, + ScaleFieldDef, + TypedFieldDef +} from '../../channeldef'; import {Config} from '../../config'; import * as log from '../../log'; import {Mark, MarkDef, RectConfig} from '../../mark'; @@ -40,13 +47,13 @@ export function parseScaleProperty(model: Model, property: keyof (Scale | ScaleC function parseUnitScaleProperty(model: UnitModel, property: keyof (Scale | ScaleComponentProps)) { const localScaleComponents: ScaleComponentIndex = model.component.scales; + const {config, encoding, markDef, specifiedScales} = model; keys(localScaleComponents).forEach((channel: ScaleChannel) => { - const specifiedScale = model.specifiedScales[channel]; + const specifiedScale = specifiedScales[channel]; const localScaleCmpt = localScaleComponents[channel]; const mergedScaleCmpt = model.getScaleComponent(channel); - const fieldDef = model.fieldDef(channel) as ScaleFieldDef; - const config = model.config; + const fieldOrDatumDef = getFieldOrDatumDef(encoding[channel]) as ScaleFieldDef | ScaleDatumDef; const specifiedValue = specifiedScale[property]; const sType = mergedScaleCmpt.get('type'); @@ -72,12 +79,12 @@ function parseUnitScaleProperty(model: UnitModel, property: keyof (Scale | Scale property, model, channel, - fieldDef, + fieldOrDatumDef, mergedScaleCmpt.get('type'), mergedScaleCmpt.get('padding'), mergedScaleCmpt.get('paddingInner'), specifiedScale.domain, - model.markDef, + markDef, config ); if (value !== undefined) { @@ -93,7 +100,7 @@ export function getDefaultValue( property: keyof Scale, model: Model, channel: Channel, - fieldDef: ScaleFieldDef, + fieldOrDatumDef: ScaleFieldDef | ScaleDatumDef, scaleType: ScaleType, scalePadding: number | SignalRef, scalePaddingInner: number | SignalRef, @@ -102,26 +109,28 @@ export function getDefaultValue( config: Config ) { const scaleConfig = config.scale; - const {type, sort} = fieldDef; + const {type} = fieldOrDatumDef; // If we have default rule-base, determine default value first switch (property) { case 'bins': - return bins(model, fieldDef); + return isFieldDef(fieldOrDatumDef) ? bins(model, fieldOrDatumDef) : undefined; case 'interpolate': return interpolate(channel, type); case 'nice': - return nice(scaleType, channel, fieldDef); + return nice(scaleType, channel, fieldOrDatumDef); case 'padding': - return padding(channel, scaleType, scaleConfig, fieldDef, markDef, config.bar); + return padding(channel, scaleType, scaleConfig, fieldOrDatumDef, markDef, config.bar); case 'paddingInner': return paddingInner(scalePadding, channel, markDef.type, scaleConfig); case 'paddingOuter': return paddingOuter(scalePadding, channel, scaleType, markDef.type, scalePaddingInner, scaleConfig); - case 'reverse': + case 'reverse': { + const sort = isFieldDef(fieldOrDatumDef) ? fieldOrDatumDef.sort : undefined; return reverse(scaleType, sort, channel, scaleConfig); + } case 'zero': - return zero(channel, fieldDef, specifiedDomain, markDef, scaleType); + return zero(channel, fieldOrDatumDef, specifiedDomain, markDef, scaleType); } // Otherwise, use scale config return scaleConfig[property]; @@ -201,8 +210,12 @@ export function interpolate(channel: Channel, type: Type) { return undefined; } -export function nice(scaleType: ScaleType, channel: Channel, fieldDef: TypedFieldDef): boolean | TimeInterval { - if (fieldDef.bin || util.contains([ScaleType.TIME, ScaleType.UTC], scaleType)) { +export function nice( + scaleType: ScaleType, + channel: Channel, + fieldOrDatumDef: TypedFieldDef | ScaleDatumDef +): boolean | TimeInterval { + if (getFieldDef(fieldOrDatumDef)?.bin || util.contains([ScaleType.TIME, ScaleType.UTC], scaleType)) { return undefined; } return util.contains([X, Y], channel) ? true : undefined; @@ -212,7 +225,7 @@ export function padding( channel: Channel, scaleType: ScaleType, scaleConfig: ScaleConfig, - fieldDef: TypedFieldDef, + fieldOrDatumDef: TypedFieldDef | ScaleDatumDef, markDef: MarkDef, barConfig: RectConfig ) { @@ -223,7 +236,7 @@ export function padding( } const {type, orient} = markDef; - if (type === 'bar' && !fieldDef.bin && !fieldDef.timeUnit) { + if (type === 'bar' && !(isFieldDef(fieldOrDatumDef) && (fieldOrDatumDef.bin || fieldOrDatumDef.timeUnit))) { if ((orient === 'vertical' && channel === 'x') || (orient === 'horizontal' && channel === 'y')) { return barConfig.continuousBandSize; } @@ -289,10 +302,8 @@ export function paddingOuter( } export function reverse(scaleType: ScaleType, sort: Sort, channel: Channel, scaleConfig: ScaleConfig) { - const isDescendingSort = hasContinuousDomain(scaleType) && sort === 'descending'; - if (channel === 'x' && scaleConfig.xReverse !== undefined) { - if (isDescendingSort) { + if (hasContinuousDomain(scaleType) && sort === 'descending') { if (isSignalRef(scaleConfig.xReverse)) { return {signal: `!${scaleConfig.xReverse.signal}`}; } else { @@ -302,7 +313,7 @@ export function reverse(scaleType: ScaleType, sort: Sort, channel: Chann return scaleConfig.xReverse; } - if (isDescendingSort) { + if (hasContinuousDomain(scaleType) && sort === 'descending') { // For continuous domain scales, Vega does not support domain sort. // Thus, we reverse range instead if sort is descending return true; @@ -312,7 +323,7 @@ export function reverse(scaleType: ScaleType, sort: Sort, channel: Chann export function zero( channel: Channel, - fieldDef: TypedFieldDef, + fieldDef: TypedFieldDef | ScaleDatumDef, specifiedDomain: Domain, markDef: MarkDef, scaleType: ScaleType @@ -346,7 +357,7 @@ export function zero( // 2) non-binned, quantitative x-scale or y-scale // (For binning, we should not include zero by default because binning are calculated without zero.) - if (!fieldDef.bin && util.contains([X, Y], channel)) { + if (!(isFieldDef(fieldDef) && fieldDef.bin) && util.contains([X, Y], channel)) { const {orient, type} = markDef; if (contains(['bar', 'area', 'line', 'trail'], type)) { if ((orient === 'horizontal' && channel === 'y') || (orient === 'vertical' && channel === 'x')) { diff --git a/src/compile/scale/range.ts b/src/compile/scale/range.ts index 5d13a04847..3d03c27b03 100644 --- a/src/compile/scale/range.ts +++ b/src/compile/scale/range.ts @@ -18,6 +18,7 @@ import { X, Y } from '../../channel'; +import {getFieldOrDatumDef, ScaleDatumDef, ScaleFieldDef} from '../../channeldef'; import {Config, getViewConfigDiscreteSize, getViewConfigDiscreteStep, ViewConfig} from '../../config'; import * as log from '../../log'; import {Mark} from '../../mark'; @@ -155,11 +156,11 @@ function parseScheme(scheme: Scheme | SignalRef): RangeScheme { } function defaultRange(channel: ScaleChannel, model: UnitModel): VgRange { - const {size, config, mark} = model; + const {size, config, mark, encoding} = model; const getSignalName = model.getSignalName.bind(model); - const {type} = model.typedFieldDef(channel); + const {type} = getFieldOrDatumDef(encoding[channel]) as ScaleFieldDef | ScaleDatumDef; const mergedScaleCmpt = model.getScaleComponent(channel); const scaleType = mergedScaleCmpt.get('type'); diff --git a/src/compile/scale/type.ts b/src/compile/scale/type.ts index b7f5f45ac4..8c22b53bab 100644 --- a/src/compile/scale/type.ts +++ b/src/compile/scale/type.ts @@ -1,11 +1,11 @@ import {isBinning} from '../../bin'; import {Channel, isColorChannel, isScaleChannel, rangeType} from '../../channel'; -import {TypedFieldDef} from '../../channeldef'; +import {DatumDef, isFieldDef, ScaleDatumDef, TypedFieldDef} from '../../channeldef'; import * as log from '../../log'; import {Mark} from '../../mark'; import {channelSupportScaleType, Scale, ScaleType, scaleTypeSupportDataType} from '../../scale'; -import * as util from '../../util'; import {normalizeTimeUnit} from '../../timeunit'; +import * as util from '../../util'; export type RangeType = 'continuous' | 'discrete' | 'flexible' | undefined; @@ -17,7 +17,7 @@ export type RangeType = 'continuous' | 'discrete' | 'flexible' | undefined; export function scaleType( specifiedScale: Scale, channel: Channel, - fieldDef: TypedFieldDef, + fieldDef: TypedFieldDef | DatumDef, mark: Mark ): ScaleType { const defaultScaleType = defaultType(channel, fieldDef, mark); @@ -35,7 +35,7 @@ export function scaleType( } // Check if explicitly specified scale type is supported by the data type - if (!scaleTypeSupportDataType(type, fieldDef.type)) { + if (isFieldDef(fieldDef) && !scaleTypeSupportDataType(type, fieldDef.type)) { log.warn(log.message.scaleTypeNotWorkWithFieldDef(type, defaultScaleType)); return defaultScaleType; } @@ -50,7 +50,7 @@ export function scaleType( * Determine appropriate default scale type. */ // NOTE: Voyager uses this method. -function defaultType(channel: Channel, fieldDef: TypedFieldDef, mark: Mark): ScaleType { +function defaultType(channel: Channel, fieldDef: TypedFieldDef | ScaleDatumDef, mark: Mark): ScaleType { switch (fieldDef.type) { case 'nominal': case 'ordinal': @@ -78,14 +78,14 @@ function defaultType(channel: Channel, fieldDef: TypedFieldDef, mark: Ma log.warn(log.message.discreteChannelCannotEncode(channel, 'temporal')); // TODO: consider using quantize (equivalent to binning) once we have it return 'ordinal'; - } else if (fieldDef.timeUnit && normalizeTimeUnit(fieldDef.timeUnit).utc) { + } else if (isFieldDef(fieldDef) && fieldDef.timeUnit && normalizeTimeUnit(fieldDef.timeUnit).utc) { return 'utc'; } return 'time'; case 'quantitative': if (isColorChannel(channel)) { - if (isBinning(fieldDef.bin)) { + if (isFieldDef(fieldDef) && isBinning(fieldDef.bin)) { return 'bin-ordinal'; } diff --git a/src/compile/selection/transforms/legends.ts b/src/compile/selection/transforms/legends.ts index dccf126039..290da54d8f 100644 --- a/src/compile/selection/transforms/legends.ts +++ b/src/compile/selection/transforms/legends.ts @@ -1,16 +1,16 @@ +import {MergedStream, Stream} from 'vega'; import {selector as parseSelector} from 'vega-event-selector'; -import {TransformCompiler} from './transforms'; -import {UnitModel} from '../../unit'; -import {NonPositionScaleChannel} from '../../../channel'; -import {LegendComponent} from '../../legend/component'; -import {forEachSelection, SelectionComponent, TUPLE} from '..'; import {array, isString} from 'vega-util'; -import {Stream, MergedStream} from 'vega'; -import {SELECTION_ID, isLegendBinding, isLegendStreamBinding} from '../../../selection'; +import {forEachSelection, SelectionComponent, TUPLE} from '..'; +import {NonPositionScaleChannel} from '../../../channel'; import * as log from '../../../log'; +import {isLegendBinding, isLegendStreamBinding, SELECTION_ID} from '../../../selection'; import {duplicate, varName} from '../../../util'; +import {LegendComponent} from '../../legend/component'; +import {UnitModel} from '../../unit'; import {TUPLE_FIELDS} from './project'; import {TOGGLE} from './toggle'; +import {TransformCompiler} from './transforms'; const legendBindings: TransformCompiler = { has: (selCmpt: SelectionComponent<'single' | 'multi'>) => { @@ -118,7 +118,7 @@ export function parseInteractiveLegend( channel: NonPositionScaleChannel, legendCmpt: LegendComponent ) { - const field = model.fieldDef(channel).field; + const field = model.fieldDef(channel)?.field; forEachSelection(model, selCmpt => { const proj = selCmpt.project.hasField[field] ?? selCmpt.project.hasChannel[channel]; if (proj && legendBindings.has(selCmpt)) { diff --git a/src/compile/unit.ts b/src/compile/unit.ts index ed40ac6624..8702c25dd3 100644 --- a/src/compile/unit.ts +++ b/src/compile/unit.ts @@ -11,7 +11,14 @@ import { X, Y } from '../channel'; -import {getFieldDef, hasConditionalFieldDef, isFieldDef, isTypedFieldDef, TypedFieldDef} from '../channeldef'; +import { + getFieldDef, + getFieldOrDatumDef, + isFieldOrDatumDef, + isTypedFieldDef, + MarkPropFieldOrDatumDef, + PositionFieldDef +} from '../channeldef'; import {Config} from '../config'; import {isGraticuleGenerator} from '../data'; import * as vlEncoding from '../encoding'; @@ -19,7 +26,7 @@ import {Encoding, initEncoding} from '../encoding'; import {Legend} from '../legend'; import {GEOSHAPE, isMarkDef, Mark, MarkDef} from '../mark'; import {Projection} from '../projection'; -import {Domain, Scale} from '../scale'; +import {Domain} from '../scale'; import {SelectionDef} from '../selection'; import {LayoutSizeMixins, NormalizedUnitSpec} from '../spec'; import {isFrameMixins} from '../spec/base'; @@ -108,7 +115,7 @@ export class UnitModel extends ModelWithField { public get hasProjection(): boolean { const {encoding} = this; const isGeoShapeMark = this.mark === GEOSHAPE; - const hasGeoPosition = encoding && GEOPOSITION_CHANNELS.some(channel => isFieldDef(encoding[channel])); + const hasGeoPosition = encoding && GEOPOSITION_CHANNELS.some(channel => isFieldOrDatumDef(encoding[channel])); return isGeoShapeMark || hasGeoPosition; } @@ -131,22 +138,11 @@ export class UnitModel extends ModelWithField { private initScales(mark: Mark, encoding: Encoding): ScaleIndex { return SCALE_CHANNELS.reduce((scales, channel) => { - let fieldDef: TypedFieldDef; - let specifiedScale: Scale; - - const channelDef = encoding[channel]; - - if (isFieldDef(channelDef)) { - fieldDef = channelDef; - specifiedScale = channelDef.scale; - } else if (hasConditionalFieldDef(channelDef)) { - // Need to specify generic for hasConditionalFieldDef as the value type can vary across channels - fieldDef = channelDef.condition; - specifiedScale = channelDef.condition['scale']; - } - - if (fieldDef) { - scales[channel] = specifiedScale ?? {}; + const fieldOrDatumDef = getFieldOrDatumDef(encoding[channel]) as + | PositionFieldDef + | MarkPropFieldOrDatumDef; + if (fieldOrDatumDef) { + scales[channel] = fieldOrDatumDef.scale ?? {}; } return scales; }, {} as ScaleIndex); @@ -159,11 +155,11 @@ export class UnitModel extends ModelWithField { // TODO: handle ConditionFieldDef const channelDef = encoding[channel]; if ( - isFieldDef(channelDef) || - (channel === X && isFieldDef(encoding.x2)) || - (channel === Y && isFieldDef(encoding.y2)) + isFieldOrDatumDef(channelDef) || + (channel === X && isFieldOrDatumDef(encoding.x2)) || + (channel === Y && isFieldOrDatumDef(encoding.y2)) ) { - const axisSpec = isFieldDef(channelDef) ? channelDef.axis : undefined; + const axisSpec = isFieldOrDatumDef(channelDef) ? channelDef.axis : undefined; _axis[channel] = axisSpec ? {...axisSpec} : axisSpec; // convert truthy value to object } @@ -173,17 +169,11 @@ export class UnitModel extends ModelWithField { private initLegend(encoding: Encoding): LegendIndex { return NONPOSITION_SCALE_CHANNELS.reduce((_legend, channel) => { - const channelDef = encoding[channel]; - if (channelDef) { - const legend = isFieldDef(channelDef) - ? channelDef.legend - : hasConditionalFieldDef(channelDef) // Need to specify generic for hasConditionalFieldDef as the value type can vary across channels - ? channelDef.condition['legend'] - : undefined; - - if (supportLegend(channel)) { - _legend[channel] = legend ? {...legend} : legend; // convert truthy value to object - } + const fieldOrDatumDef = getFieldOrDatumDef(encoding[channel]) as MarkPropFieldOrDatumDef; + + if (fieldOrDatumDef && supportLegend(channel)) { + const legend = fieldOrDatumDef.legend; + _legend[channel] = legend ? {...legend} : legend; // convert truthy value to object } return _legend; @@ -259,6 +249,7 @@ export class UnitModel extends ModelWithField { const channelDef = this.encoding[channel]; return getFieldDef(channelDef); } + public typedFieldDef(channel: SingleDefChannel) { const fieldDef = this.fieldDef(channel); if (isTypedFieldDef(fieldDef)) { diff --git a/src/compositemark/common.ts b/src/compositemark/common.ts index 62463999e8..1e39a13e09 100644 --- a/src/compositemark/common.ts +++ b/src/compositemark/common.ts @@ -4,7 +4,7 @@ import {CompositeMark, CompositeMarkDef} from '.'; import { Field, FieldDefBase, - isContinuous, + isContinuousFieldOrDatumDef, isFieldDef, PositionFieldDef, SecondaryFieldDef, @@ -257,20 +257,24 @@ function filterAggregateFromChannelDef( - spec: GenericUnitSpec, CompositeMark | CompositeMarkDef>, + spec: GenericUnitSpec, CompositeMark | CompositeMarkDef>, compositeMark: M ): Orientation { const {mark, encoding} = spec; + const {x, y} = encoding; - if (isFieldDef(encoding.x) && isContinuous(encoding.x)) { + if (isContinuousFieldOrDatumDef(x)) { // x is continuous - if (isFieldDef(encoding.y) && isContinuous(encoding.y)) { + if (isContinuousFieldOrDatumDef(y)) { // both x and y are continuous - if (encoding.x.aggregate === undefined && encoding.y.aggregate === compositeMark) { + const xAggregate = isFieldDef(x) && x.aggregate; + const yAggregate = isFieldDef(y) && y.aggregate; + + if (!xAggregate && yAggregate === compositeMark) { return 'vertical'; - } else if (encoding.y.aggregate === undefined && encoding.x.aggregate === compositeMark) { + } else if (!yAggregate && xAggregate === compositeMark) { return 'horizontal'; - } else if (encoding.x.aggregate === compositeMark && encoding.y.aggregate === compositeMark) { + } else if (xAggregate === compositeMark && yAggregate === compositeMark) { throw new Error('Both x and y cannot have aggregate'); } else { if (isMarkDef(mark) && mark.orient) { @@ -284,7 +288,7 @@ export function compositeMarkOrient( // x is continuous but y is not return 'horizontal'; - } else if (isFieldDef(encoding.y) && isContinuous(encoding.y)) { + } else if (isContinuousFieldOrDatumDef(y)) { // y is continuous but x is not return 'vertical'; } else { diff --git a/src/compositemark/errorbar.ts b/src/compositemark/errorbar.ts index 30c65227da..52ab785796 100644 --- a/src/compositemark/errorbar.ts +++ b/src/compositemark/errorbar.ts @@ -1,6 +1,14 @@ import {AggregateOp, Orientation, Text} from 'vega'; import {PositionChannel} from '../channel'; -import {Field, isContinuous, isFieldDef, PositionFieldDef, SecondaryFieldDef, title, ValueDef} from '../channeldef'; +import { + Field, + isContinuousFieldOrDatumDef, + isFieldOrDatumDef, + PositionFieldDef, + SecondaryFieldDef, + title, + ValueDef +} from '../channeldef'; import {Config} from '../config'; import {Data} from '../data'; import {Encoding, extractTransformsFromEncoding} from '../encoding'; @@ -9,10 +17,10 @@ import {isMarkDef, MarkDef} from '../mark'; import {NormalizerParams} from '../normalize'; import {GenericUnitSpec, NormalizedLayerSpec} from '../spec'; import {Step} from '../spec/base'; +import {NormalizedUnitSpec} from '../spec/unit'; import {TitleParams} from '../title'; import {AggregatedFieldDef, CalculateTransform, Transform} from '../transform'; import {Flag, keys, replaceAll, titlecase} from '../util'; -import {NormalizedUnitSpec} from '../spec/unit'; import {CompositeMarkNormalizer} from './base'; import { compositeMarkContinuousAxis, @@ -168,7 +176,7 @@ export function normalizeErrorBar( } function errorBarOrientAndInputType( - spec: GenericUnitSpec, ErrorBar | ErrorBand | ErrorBarDef | ErrorBandDef>, + spec: GenericUnitSpec, ErrorBar | ErrorBand | ErrorBarDef | ErrorBandDef>, compositeMark: ErrorBar | ErrorBand ): { orient: Orientation; @@ -198,20 +206,20 @@ function errorBarOrientAndInputType( const x2 = encoding.x2; const y2 = encoding.y2; - if (isFieldDef(x2) && isFieldDef(y2)) { + if (isFieldOrDatumDef(x2) && isFieldOrDatumDef(y2)) { // having both x, x2 and y, y2 throw new Error(`${compositeMark} cannot have both x2 and y2`); - } else if (isFieldDef(x2)) { - if (isFieldDef(x) && isContinuous(x)) { + } else if (isFieldOrDatumDef(x2)) { + if (isContinuousFieldOrDatumDef(x)) { // having x, x2 quantitative and field y, y2 are not specified return {orient: 'horizontal', inputType: 'aggregated-upper-lower'}; } else { // having x, x2 that are not both quantitative throw new Error(`Both x and x2 have to be quantitative in ${compositeMark}`); } - } else if (isFieldDef(y2)) { + } else if (isFieldOrDatumDef(y2)) { // y2 is a FieldDef - if (isFieldDef(y) && isContinuous(y)) { + if (isContinuousFieldOrDatumDef(y)) { // having y, y2 quantitative and field x, x2 are not specified return {orient: 'vertical', inputType: 'aggregated-upper-lower'}; } else { @@ -228,29 +236,29 @@ function errorBarOrientAndInputType( const yError = encoding.yError; const yError2 = encoding.yError2; - if (isFieldDef(xError2) && !isFieldDef(xError)) { + if (isFieldOrDatumDef(xError2) && !isFieldOrDatumDef(xError)) { // having xError2 without xError throw new Error(`${compositeMark} cannot have xError2 without xError`); } - if (isFieldDef(yError2) && !isFieldDef(yError)) { + if (isFieldOrDatumDef(yError2) && !isFieldOrDatumDef(yError)) { // having yError2 without yError throw new Error(`${compositeMark} cannot have yError2 without yError`); } - if (isFieldDef(xError) && isFieldDef(yError)) { + if (isFieldOrDatumDef(xError) && isFieldOrDatumDef(yError)) { // having both xError and yError throw new Error(`${compositeMark} cannot have both xError and yError with both are quantiative`); - } else if (isFieldDef(xError)) { - if (isFieldDef(x) && isContinuous(x)) { + } else if (isFieldOrDatumDef(xError)) { + if (isContinuousFieldOrDatumDef(x)) { // having x and xError that are all quantitative return {orient: 'horizontal', inputType: 'aggregated-error'}; } else { // having x, xError, and xError2 that are not all quantitative throw new Error('All x, xError, and xError2 (if exist) have to be quantitative'); } - } else if (isFieldDef(yError)) { - if (isFieldDef(y) && isContinuous(y)) { + } else if (isFieldOrDatumDef(yError)) { + if (isContinuousFieldOrDatumDef(y)) { // having y and yError that are all quantitative return {orient: 'vertical', inputType: 'aggregated-error'}; } else { @@ -262,28 +270,28 @@ function errorBarOrientAndInputType( } } -function errorBarIsInputTypeRaw(encoding: ErrorEncoding): boolean { +function errorBarIsInputTypeRaw(encoding: ErrorEncoding): boolean { return ( - (isFieldDef(encoding.x) || isFieldDef(encoding.y)) && - !isFieldDef(encoding.x2) && - !isFieldDef(encoding.y2) && - !isFieldDef(encoding.xError) && - !isFieldDef(encoding.xError2) && - !isFieldDef(encoding.yError) && - !isFieldDef(encoding.yError2) + (isFieldOrDatumDef(encoding.x) || isFieldOrDatumDef(encoding.y)) && + !isFieldOrDatumDef(encoding.x2) && + !isFieldOrDatumDef(encoding.y2) && + !isFieldOrDatumDef(encoding.xError) && + !isFieldOrDatumDef(encoding.xError2) && + !isFieldOrDatumDef(encoding.yError) && + !isFieldOrDatumDef(encoding.yError2) ); } -function errorBarIsInputTypeAggregatedUpperLower(encoding: ErrorEncoding): boolean { - return isFieldDef(encoding.x2) || isFieldDef(encoding.y2); +function errorBarIsInputTypeAggregatedUpperLower(encoding: ErrorEncoding): boolean { + return isFieldOrDatumDef(encoding.x2) || isFieldOrDatumDef(encoding.y2); } -function errorBarIsInputTypeAggregatedError(encoding: ErrorEncoding): boolean { +function errorBarIsInputTypeAggregatedError(encoding: ErrorEncoding): boolean { return ( - isFieldDef(encoding.xError) || - isFieldDef(encoding.xError2) || - isFieldDef(encoding.yError) || - isFieldDef(encoding.yError2) + isFieldOrDatumDef(encoding.xError) || + isFieldOrDatumDef(encoding.xError2) || + isFieldOrDatumDef(encoding.yError) || + isFieldOrDatumDef(encoding.yError2) ); } diff --git a/src/encoding.ts b/src/encoding.ts index efe0b85d49..78b2ff3606 100644 --- a/src/encoding.ts +++ b/src/encoding.ts @@ -6,8 +6,10 @@ import {Channel, CHANNELS, isChannel, isNonPositionScaleChannel, isSecondaryRang import { binRequiresRange, ChannelDef, + ColorGradientDatumDefWithCondition, ColorGradientFieldDefWithCondition, ColorGradientValueOrSignalWithCondition, + DatumDef, Field, FieldDef, FieldDefWithoutScale, @@ -17,19 +19,24 @@ import { initChannelDef, initFieldDef, isConditionalDef, + isDatumDef, isFieldDef, isTypedFieldDef, isValueDef, LatLongFieldDef, + NumericArrayDatumDefWithCondition, NumericArrayFieldDefWithCondition, NumericArrayValueDefWithCondition, + NumericDatumDefWithCondition, NumericFieldDefWithCondition, NumericValueOrSignalWithCondition, OrderFieldDef, + PositionDatumDef, PositionFieldDef, SecondaryFieldDef, ShapeFieldDefWithCondition, ShapeValueOrSignalWithCondition, + StringDatumDefWithCondition, StringFieldDef, StringFieldDefWithCondition, StringValueOrSignalWithCondition, @@ -55,14 +62,14 @@ export interface Encoding { * * The `value` of this channel can be a number or a string `"width"` for the width of the plot. */ - x?: PositionFieldDef | ValueDef | SignalRef; + x?: PositionFieldDef | PositionDatumDef | ValueDef | SignalRef; /** * Y coordinates of the marks, or height of vertical `"bar"` and `"area"` without specified `y2` or `height`. * * The `value` of this channel can be a number or a string `"height"` for the height of the plot. */ - y?: PositionFieldDef | ValueDef | SignalRef; + y?: PositionFieldDef | PositionDatumDef | ValueDef | SignalRef; /** * X2 coordinates for ranged `"area"`, `"bar"`, `"rect"`, and `"rule"`. @@ -71,7 +78,7 @@ export interface Encoding { */ // TODO: Ham need to add default behavior // `x2` cannot have type as it should have the same type as `x` - x2?: SecondaryFieldDef | ValueDef | SignalRef; + x2?: SecondaryFieldDef | DatumDef | ValueDef | SignalRef; /** * Y2 coordinates for ranged `"area"`, `"bar"`, `"rect"`, and `"rule"`. @@ -80,29 +87,29 @@ export interface Encoding { */ // TODO: Ham need to add default behavior // `y2` cannot have type as it should have the same type as `y` - y2?: SecondaryFieldDef | ValueDef | SignalRef; + y2?: SecondaryFieldDef | DatumDef | ValueDef | SignalRef; /** * Longitude position of geographically projected marks. */ - longitude?: LatLongFieldDef | ValueDef; + longitude?: LatLongFieldDef | DatumDef | ValueDef; /** * Latitude position of geographically projected marks. */ - latitude?: LatLongFieldDef | ValueDef; + latitude?: LatLongFieldDef | DatumDef | ValueDef; /** * Longitude-2 position for geographically projected ranged `"area"`, `"bar"`, `"rect"`, and `"rule"`. */ // `longitude2` cannot have type as it should have the same type as `longitude` - longitude2?: SecondaryFieldDef | ValueDef; + longitude2?: SecondaryFieldDef | DatumDef | ValueDef; /** * Latitude-2 position for geographically projected ranged `"area"`, `"bar"`, `"rect"`, and `"rule"`. */ // `latitude2` cannot have type as it should have the same type as `latitude` - latitude2?: SecondaryFieldDef | ValueDef; + latitude2?: SecondaryFieldDef | DatumDef | ValueDef; /** * Color of the marks – either fill or stroke color based on the `filled` property of mark definition. @@ -115,7 +122,10 @@ export interface Encoding { * 1) For fine-grained control over both fill and stroke colors of the marks, please use the `fill` and `stroke` channels. The `fill` or `stroke` encodings have higher precedence than `color`, thus may override the `color` encoding if conflicting encodings are specified. * 2) See the scale documentation for more information about customizing [color scheme](https://vega.github.io/vega-lite/docs/scale.html#scheme). */ - color?: ColorGradientFieldDefWithCondition | ColorGradientValueOrSignalWithCondition; + color?: + | ColorGradientFieldDefWithCondition + | ColorGradientDatumDefWithCondition + | ColorGradientValueOrSignalWithCondition; /** * Fill color of the marks. @@ -123,7 +133,10 @@ export interface Encoding { * * _Note:_ The `fill` encoding has higher precedence than `color`, thus may override the `color` encoding if conflicting encodings are specified. */ - fill?: ColorGradientFieldDefWithCondition | ColorGradientValueOrSignalWithCondition; + fill?: + | ColorGradientFieldDefWithCondition + | ColorGradientDatumDefWithCondition + | ColorGradientValueOrSignalWithCondition; /** * Stroke color of the marks. @@ -132,42 +145,57 @@ export interface Encoding { * _Note:_ The `stroke` encoding has higher precedence than `color`, thus may override the `color` encoding if conflicting encodings are specified. */ - stroke?: ColorGradientFieldDefWithCondition | ColorGradientValueOrSignalWithCondition; + stroke?: + | ColorGradientFieldDefWithCondition + | ColorGradientDatumDefWithCondition + | ColorGradientValueOrSignalWithCondition; /** * Opacity of the marks. * * __Default value:__ If undefined, the default opacity depends on [mark config](https://vega.github.io/vega-lite/docs/config.html#mark)'s `opacity` property. */ - opacity?: NumericFieldDefWithCondition | NumericValueOrSignalWithCondition; + opacity?: NumericFieldDefWithCondition | NumericDatumDefWithCondition | NumericValueOrSignalWithCondition; /** * Fill opacity of the marks. * * __Default value:__ If undefined, the default opacity depends on [mark config](https://vega.github.io/vega-lite/docs/config.html#mark)'s `fillOpacity` property. */ - fillOpacity?: NumericFieldDefWithCondition | NumericValueOrSignalWithCondition; + fillOpacity?: + | NumericFieldDefWithCondition + | NumericDatumDefWithCondition + | NumericValueOrSignalWithCondition; /** * Stroke opacity of the marks. * * __Default value:__ If undefined, the default opacity depends on [mark config](https://vega.github.io/vega-lite/docs/config.html#mark)'s `strokeOpacity` property. */ - strokeOpacity?: NumericFieldDefWithCondition | NumericValueOrSignalWithCondition; + strokeOpacity?: + | NumericFieldDefWithCondition + | NumericDatumDefWithCondition + | NumericValueOrSignalWithCondition; /** * Stroke width of the marks. * * __Default value:__ If undefined, the default stroke width depends on [mark config](https://vega.github.io/vega-lite/docs/config.html#mark)'s `strokeWidth` property. */ - strokeWidth?: NumericFieldDefWithCondition | NumericValueOrSignalWithCondition; + strokeWidth?: + | NumericFieldDefWithCondition + | NumericDatumDefWithCondition + | NumericValueOrSignalWithCondition; /** * Stroke dash of the marks. * * __Default value:__ `[1,0]` (No dash). */ - strokeDash?: NumericArrayFieldDefWithCondition | NumericArrayValueDefWithCondition; + strokeDash?: + | NumericArrayFieldDefWithCondition + | NumericArrayDatumDefWithCondition + | NumericArrayValueDefWithCondition; /** * Size of the mark. @@ -176,7 +204,7 @@ export interface Encoding { * - For `"text"` – the text's font size. * - Size is unsupported for `"line"`, `"area"`, and `"rect"`. (Use `"trail"` instead of line with varying size) */ - size?: NumericFieldDefWithCondition | NumericValueOrSignalWithCondition; + size?: NumericFieldDefWithCondition | NumericDatumDefWithCondition | NumericValueOrSignalWithCondition; /** * Shape of the mark. @@ -191,7 +219,7 @@ export interface Encoding { * * __Default value:__ If undefined, the default shape depends on [mark config](https://vega.github.io/vega-lite/docs/config.html#point-config)'s `shape` property. (`"circle"` if unset.) */ - shape?: ShapeFieldDefWithCondition | ShapeValueOrSignalWithCondition; + shape?: ShapeFieldDefWithCondition | StringDatumDefWithCondition | ShapeValueOrSignalWithCondition; /** * Additional levels of detail for grouping data in aggregate views and * in line, trail, and area marks without mapping data to a specific visual channel. @@ -250,7 +278,7 @@ export function channelHasField(encoding: EncodingWithFacet, return false; } -export function isAggregate(encoding: EncodingWithFacet) { +export function isAggregate(encoding: EncodingWithFacet) { return some(CHANNELS, channel => { if (channelHasField(encoding, channel)) { const channelDef = encoding[channel]; @@ -265,7 +293,7 @@ export function isAggregate(encoding: EncodingWithFacet) { }); } -export function extractTransformsFromEncoding(oldEncoding: Encoding, config: Config) { +export function extractTransformsFromEncoding(oldEncoding: Encoding, config: Config) { const groupby: string[] = []; const bins: BinTransform[] = []; const timeUnits: TimeUnitTransform[] = []; @@ -367,7 +395,7 @@ export function extractTransformsFromEncoding(oldEncoding: Encoding, conf encoding[channel] = oldEncoding[channel]; } } else { - // For value def, just copy + // For value def / signal ref / datum def, just copy encoding[channel] = oldEncoding[channel]; } }); @@ -457,6 +485,7 @@ export function initEncoding(encoding: Encoding, markDef: MarkDef): Enco normalizedEncoding[channel] = null; } else if ( !isFieldDef(channelDef) && + !isDatumDef(channelDef) && !isValueDef(channelDef) && !isConditionalDef(channelDef) && !isSignalRef(channelDef) diff --git a/src/normalize/core.ts b/src/normalize/core.ts index 195d3697ea..a07e157d4f 100644 --- a/src/normalize/core.ts +++ b/src/normalize/core.ts @@ -59,7 +59,10 @@ export class CoreNormalizer extends SpecMapper): MarkConfig { +function getPointOverlay(markDef: MarkDef, markConfig: LineConfig = {}, encoding: Encoding): MarkConfig { if (markDef.point === 'transparent') { return {opacity: 0}; } else if (markDef.point) { diff --git a/src/normalize/rangestep.ts b/src/normalize/rangestep.ts index 3e4159dd42..d9fc79fc75 100644 --- a/src/normalize/rangestep.ts +++ b/src/normalize/rangestep.ts @@ -1,5 +1,5 @@ import {getSizeType, POSITION_SCALE_CHANNELS} from '../channel'; -import {isFieldDef} from '../channeldef'; +import {isFieldOrDatumDef} from '../channeldef'; import {Encoding} from '../encoding'; import * as log from '../log'; import {Scale} from '../scale'; @@ -17,7 +17,7 @@ export class RangeStepNormalizer implements NonFacetUnitNormalizer; + return replaceRepeaterInMapping(facet, repeater) as FacetMapping; } return replaceRepeaterInFieldDef(facet, repeater) as FacetFieldDef; } -export function replaceRepeaterInEncoding(encoding: Encoding, repeater: RepeaterValue): Encoding { +export function replaceRepeaterInEncoding>( + encoding: E, + repeater: RepeaterValue +): Encoding { if (!repeater) { return encoding as Encoding; } - return replaceRepeater(encoding, repeater) as Encoding; + return replaceRepeaterInMapping(encoding, repeater) as Encoding; } /** * Replaces repeated value and returns if the repeated value is valid. */ -function replaceRepeat(o: T, repeater: RepeaterValue): T { - if (isRepeatRef(o.field)) { - if (o.field.repeat in repeater) { - return {...o, field: repeater[o.field.repeat]}; +function replaceRepeatInProp(prop: keyof T, o: T, repeater: RepeaterValue): T { + const val = o[prop]; + if (isRepeatRef(val)) { + if (val.repeat in repeater) { + return {...o, [prop]: repeater[val.repeat]}; } else { - log.warn(log.message.noSuchRepeatedValue(o.field.repeat)); + log.warn(log.message.noSuchRepeatedValue(val.repeat)); return undefined; } } @@ -66,8 +72,9 @@ function replaceRepeat(o: T, repeater: RepeaterValue) /** * Replace repeater values in a field def with the concrete field name. */ -function replaceRepeaterInFieldDef(fieldDef: FieldDef, repeater: RepeaterValue): FieldDef { - fieldDef = replaceRepeat(fieldDef, repeater); + +function replaceRepeaterInFieldDef(fieldDef: FieldDef, repeater: RepeaterValue) { + fieldDef = replaceRepeatInProp('field', fieldDef, repeater); if (fieldDef === undefined) { // the field def should be ignored @@ -77,7 +84,7 @@ function replaceRepeaterInFieldDef(fieldDef: FieldDef, repeater: Repeater } if (isSortableFieldDef(fieldDef) && isSortField(fieldDef.sort)) { - const sort = replaceRepeat(fieldDef.sort, repeater); + const sort = replaceRepeatInProp('field', fieldDef.sort, repeater); fieldDef = { ...fieldDef, ...(sort ? {sort} : {}) @@ -87,17 +94,29 @@ function replaceRepeaterInFieldDef(fieldDef: FieldDef, repeater: Repeater return fieldDef as ScaleFieldDef; } +function replaceRepeaterInFieldOrDatumDef(def: FieldDef | DatumDef, repeater: RepeaterValue) { + if (isFieldDef(def)) { + return replaceRepeaterInFieldDef(def, repeater); + } else { + const datumDef = replaceRepeatInProp('datum', def, repeater); + if (datumDef !== def && !datumDef.type) { + datumDef.type = 'nominal'; + } + return datumDef; + } +} + function replaceRepeaterInChannelDef(channelDef: ChannelDef, repeater: RepeaterValue) { - if (isFieldDef(channelDef)) { - const fd = replaceRepeaterInFieldDef(channelDef, repeater); + if (isFieldOrDatumDef(channelDef)) { + const fd = replaceRepeaterInFieldOrDatumDef(channelDef, repeater); if (fd) { return fd; } else if (isConditionalDef>(channelDef)) { return {condition: channelDef.condition}; } } else { - if (hasConditionalFieldDef(channelDef)) { - const fd = replaceRepeaterInFieldDef(channelDef.condition, repeater); + if (hasConditionalFieldOrDatumDef(channelDef)) { + const fd = replaceRepeaterInFieldOrDatumDef(channelDef.condition, repeater); if (fd) { return { ...channelDef, @@ -115,7 +134,10 @@ function replaceRepeaterInChannelDef(channelDef: ChannelDef, repeater: Re type EncodingOrFacet = Encoding | FacetMapping; -function replaceRepeater(mapping: EncodingOrFacet, repeater: RepeaterValue): EncodingOrFacet { +function replaceRepeaterInMapping( + mapping: EncodingOrFacet, + repeater: RepeaterValue +): EncodingOrFacet { const out: EncodingOrFacet = {}; for (const channel in mapping) { if (hasOwnProperty(mapping, channel)) { diff --git a/src/normalize/ruleforrangedline.ts b/src/normalize/ruleforrangedline.ts index add85cf40d..b28ffa6c09 100644 --- a/src/normalize/ruleforrangedline.ts +++ b/src/normalize/ruleforrangedline.ts @@ -1,6 +1,6 @@ import {isBinned} from '../bin'; import {getMainRangeChannel, SECONDARY_RANGE_CHANNEL} from '../channel'; -import {Field, isFieldDef} from '../channeldef'; +import {Field, isDatumDef, isFieldDef} from '../channeldef'; import {Encoding} from '../encoding'; import * as log from '../log'; import {GenericSpec} from '../spec'; @@ -28,8 +28,10 @@ export class RuleForRangedLineNormalizer implements NonFacetUnitNormalizer): 'x' | 'y' | undefined { +function potentialStackedChannel(encoding: Encoding): 'x' | 'y' | undefined { const xDef = encoding.x; const yDef = encoding.y; if (isFieldDef(xDef) && isFieldDef(yDef)) { - if (xDef.type === 'quantitative' && yDef.type === 'quantitative') { + if (channelDefType(xDef) === 'quantitative' && channelDefType(yDef) === 'quantitative') { if (xDef.stack) { return 'x'; } else if (yDef.stack) { return 'y'; } + const xAggregate = isFieldDef(xDef) && !!xDef.aggregate; + const yAggregate = isFieldDef(yDef) && !!yDef.aggregate; // if there is no explicit stacking, only apply stack if there is only one aggregate for x or y - if (!!xDef.aggregate !== !!yDef.aggregate) { - return xDef.aggregate ? 'x' : 'y'; + if (xAggregate !== yAggregate) { + return xAggregate ? 'x' : 'y'; } - } else if (xDef.type === 'quantitative') { + } else if (channelDefType(xDef) === 'quantitative') { return 'x'; - } else if (yDef.type === 'quantitative') { + } else if (channelDefType(yDef) === 'quantitative') { return 'y'; } - } else if (isFieldDef(xDef) && xDef.type === 'quantitative') { + } else if (channelDefType(xDef) === 'quantitative') { return 'x'; - } else if (isFieldDef(yDef) && yDef.type === 'quantitative') { + } else if (channelDefType(yDef) === 'quantitative') { return 'y'; } return undefined; @@ -98,8 +110,8 @@ export function stack( return null; } - const stackedFieldDef = encoding[fieldChannel] as PositionFieldDef; - const stackedField = vgField(stackedFieldDef, {}); + const stackedFieldDef = encoding[fieldChannel] as PositionFieldDef | PositionDatumDef; + const stackedField = isFieldDef(stackedFieldDef) ? vgField(stackedFieldDef, {}) : undefined; const dimensionChannel = fieldChannel === 'x' ? 'y' : 'x'; const dimensionDef = encoding[dimensionChannel]; @@ -162,7 +174,7 @@ export function stack( } // Check if it is a ranged mark - if (channelHasField(encoding, fieldChannel === X ? X2 : Y2)) { + if (isFieldOrDatumDef(encoding[fieldChannel === X ? X2 : Y2])) { if (stackedFieldDef.stack !== undefined) { log.warn(log.message.cannotStackRangedMark(fieldChannel)); } @@ -170,7 +182,7 @@ export function stack( } // Warn if stacking non-summative aggregate - if (stackedFieldDef.aggregate && !contains(SUM_OPS, stackedFieldDef.aggregate)) { + if (isFieldDef(stackedFieldDef) && stackedFieldDef.aggregate && !contains(SUM_OPS, stackedFieldDef.aggregate)) { log.warn(log.message.stackNonSummativeAggregate(stackedFieldDef.aggregate)); } diff --git a/test-runtime/util.ts b/test-runtime/util.ts index dd73fc32ad..f5cb8024f0 100644 --- a/test-runtime/util.ts +++ b/test-runtime/util.ts @@ -1,10 +1,10 @@ import * as fs from 'fs'; import {sync as mkdirp} from 'mkdirp'; import {Page} from 'puppeteer'; +import {promisify} from 'util'; import {stringValue} from 'vega-util'; import {SelectionResolution, SelectionType} from '../src/selection'; import {NormalizedLayerSpec, NormalizedUnitSpec, TopLevelSpec} from '../src/spec'; -import {promisify} from 'util'; const generate = process.env.VL_GENERATE_TESTS; const output = 'test-runtime/resources'; @@ -164,7 +164,7 @@ export function spec(compose: ComposeType, iter: number, sel: any, opts: any = { const config = {view: {discreteWidth: {step: 21}, discreteHeight: {step: 21}}}; // A lot of magic numbers in this file use the old step = 21 switch (compose) { case 'unit': - return {data, ...specification, config}; + return {data, ...specification, config} as TopLevelSpec; case 'facet': return { data, @@ -172,7 +172,7 @@ export function spec(compose: ComposeType, iter: number, sel: any, opts: any = { spec: specification, resolve, config - }; + } as TopLevelSpec; case 'repeat': return { data, @@ -180,7 +180,7 @@ export function spec(compose: ComposeType, iter: number, sel: any, opts: any = { spec: specification, resolve, config - }; + } as TopLevelSpec; } } diff --git a/test/compile/axis/properties.test.ts b/test/compile/axis/properties.test.ts index 1d13a15148..cf22ab2b45 100644 --- a/test/compile/axis/properties.test.ts +++ b/test/compile/axis/properties.test.ts @@ -36,7 +36,7 @@ describe('compile/axis', () => { describe('defaultTickCount()', () => { it('should return undefined by default for a binned field', () => { const tickCount = properties.defaultTickCount({ - fieldDef: {bin: {maxbins: 10}, field: 'a', type: 'quantitative'}, + fieldOrDatumDef: {bin: {maxbins: 10}, field: 'a', type: 'quantitative'}, scaleType: 'linear', size: {signal: 'a'} }); @@ -46,7 +46,7 @@ describe('compile/axis', () => { for (const timeUnit of ['month', 'hours', 'day', 'quarter'] as TimeUnit[]) { it(`should return undefined by default for a temporal field with timeUnit=${timeUnit}`, () => { const tickCount = properties.defaultTickCount({ - fieldDef: {timeUnit, field: 'a', type: 'temporal'}, + fieldOrDatumDef: {timeUnit, field: 'a', type: 'temporal'}, scaleType: 'linear', size: {signal: 'a'} }); @@ -56,7 +56,7 @@ describe('compile/axis', () => { it('should return size/40 by default for linear scale', () => { const tickCount = properties.defaultTickCount({ - fieldDef: {field: 'a', type: 'quantitative'}, + fieldOrDatumDef: {field: 'a', type: 'quantitative'}, scaleType: 'linear', size: {signal: 'a'} }); @@ -65,7 +65,7 @@ describe('compile/axis', () => { it('should return undefined by default for log scale', () => { const tickCount = properties.defaultTickCount({ - fieldDef: {field: 'a', type: 'quantitative'}, + fieldOrDatumDef: {field: 'a', type: 'quantitative'}, scaleType: 'log' }); expect(tickCount).toBeUndefined(); @@ -73,7 +73,7 @@ describe('compile/axis', () => { it('should return undefined by default for point scale', () => { const tickCount = properties.defaultTickCount({ - fieldDef: {field: 'a', type: 'quantitative'}, + fieldOrDatumDef: {field: 'a', type: 'quantitative'}, scaleType: 'point' }); expect(tickCount).toBeUndefined(); @@ -82,7 +82,7 @@ describe('compile/axis', () => { describe('values', () => { it('should return correct timestamp values for DateTimes', () => { - const values = properties.values({values: [{year: 1970}, {year: 1980}]}, null, {field: 'a', type: 'temporal'}); + const values = properties.values({values: [{year: 1970}, {year: 1980}]}, {field: 'a', type: 'temporal'}); expect(values).toEqual([ {signal: 'datetime(1970, 0, 1, 0, 0, 0, 0)'}, @@ -91,29 +91,24 @@ describe('compile/axis', () => { }); it('should simply return values for non-DateTime', () => { - const values = properties.values({values: [1, 2, 3, 4]}, null, {field: 'a', type: 'quantitative'}); + const values = properties.values({values: [1, 2, 3, 4]}, {field: 'a', type: 'quantitative'}); expect(values).toEqual([1, 2, 3, 4]); }); it('returns signal correctly for non-DateTime', () => { - const values = properties.values({values: {signal: 'a'}}, null, {field: 'a', type: 'quantitative'}); + const values = properties.values({values: {signal: 'a'}}, {field: 'a', type: 'quantitative'}); expect(values).toEqual({signal: 'a'}); }); it('should simply drop values when domain is specified', () => { - const model1 = parseUnitModelWithScale({ - mark: 'bar', - encoding: { - y: { - type: 'quantitative', - field: 'US_Gross', - scale: {domain: [-1, 2]}, - bin: {extent: [0, 1]} - } - }, - data: {url: 'data/movies.json'} - }); - const values = properties.values({}, model1, model1.typedFieldDef('y')); + const values = properties.values( + {}, + { + type: 'quantitative', + field: 'US_Gross', + bin: {extent: [0, 1]} + } + ); expect(values).toBeUndefined(); }); diff --git a/test/compile/format.test.ts b/test/compile/format.test.ts index d93a161a7c..9e3e1b30c3 100644 --- a/test/compile/format.test.ts +++ b/test/compile/format.test.ts @@ -74,31 +74,31 @@ describe('Format', () => { describe('numberFormat()', () => { it('should use number format for quantitative scale', () => { - expect(numberFormat({field: 'a', type: QUANTITATIVE}, undefined, {numberFormat: 'd'})).toBe('d'); + expect(numberFormat(QUANTITATIVE, undefined, {numberFormat: 'd'})).toBe('d'); }); it('should use number format for ordinal and nominal data but don not use config', () => { for (const type of [ORDINAL, NOMINAL]) { - expect(numberFormat({field: 'a', type: type}, undefined, {numberFormat: 'd'})).toBeUndefined(); - expect(numberFormat({field: 'a', type: type}, 'd', {numberFormat: 'd'})).toBe('d'); + expect(numberFormat(type, undefined, {numberFormat: 'd'})).toBeUndefined(); + expect(numberFormat(type, 'd', {numberFormat: 'd'})).toBe('d'); } }); it('should support empty number format', () => { - expect(numberFormat({field: 'a', type: QUANTITATIVE}, undefined, {numberFormat: ''})).toBe(''); + expect(numberFormat(QUANTITATIVE, undefined, {numberFormat: ''})).toBe(''); }); it('should use format if provided', () => { - expect(numberFormat({field: 'a', type: QUANTITATIVE}, 'a', {})).toBe('a'); + expect(numberFormat(QUANTITATIVE, 'a', {})).toBe('a'); }); it('should not use number format for binned quantitative scale', () => { - expect(numberFormat({bin: true, field: 'a', type: QUANTITATIVE}, undefined, {})).toBeUndefined(); + expect(numberFormat(QUANTITATIVE, undefined, {})).toBeUndefined(); }); it('should not use number format for temporal scale', () => { - expect(numberFormat({bin: true, field: 'a', type: TEMPORAL}, undefined, {})).toBeUndefined(); - expect(numberFormat({bin: true, field: 'a', type: ORDINAL, timeUnit: 'month'}, undefined, {})).toBeUndefined(); + expect(numberFormat(TEMPORAL, undefined, {})).toBeUndefined(); + expect(numberFormat(ORDINAL, undefined, {})).toBeUndefined(); }); }); @@ -106,7 +106,7 @@ describe('Format', () => { it('should format ordinal field defs if format is present', () => { expect( formatSignalRef({ - fieldDef: {field: 'foo', type: 'ordinal'}, + fieldOrDatumDef: {field: 'foo', type: 'ordinal'}, format: '.2f', formatType: undefined, expr: 'parent', diff --git a/test/compile/mark/encoding/valueref.test.ts b/test/compile/mark/encoding/valueref.test.ts index c79272a928..42a9e23a1b 100644 --- a/test/compile/mark/encoding/valueref.test.ts +++ b/test/compile/mark/encoding/valueref.test.ts @@ -17,6 +17,7 @@ describe('compile/mark/valueref', () => { }); expect(ref).toEqual({field: {group: 'width'}}); }); + it('should return correct value for height', () => { const ref = midPoint({ channel: 'y', @@ -29,6 +30,20 @@ describe('compile/mark/valueref', () => { }); expect(ref).toEqual({field: {group: 'height'}}); }); + + it('returns correct value for datum', () => { + const ref = midPoint({ + channel: 'y', + channelDef: {datum: 5}, + markDef: {type: 'point'}, + config: defaultConfig, + scaleName: 'x', + scale: undefined, + defaultRef + }); + expect(ref).toEqual({scale: 'x', value: 5}); + }); + it('should return correct value for binned data', () => { const fieldDef: TypedFieldDef = {field: 'bin_start', bin: 'binned', type: 'quantitative'}; const fieldDef2: SecondaryFieldDef = {field: 'bin_end'}; diff --git a/test/compile/scale/properties.test.ts b/test/compile/scale/properties.test.ts index 1d0e66ca1a..d13f34651f 100644 --- a/test/compile/scale/properties.test.ts +++ b/test/compile/scale/properties.test.ts @@ -13,7 +13,7 @@ describe('compile/scale', () => { it('should not return nice for binned x and y.', () => { for (const c of ['x', 'y'] as Channel[]) { - expect(rules.nice('linear', c, {type: 'quantitative', bin: true})).toEqual(undefined); + expect(rules.nice('linear', c, {type: 'quantitative', field: 'a', bin: true})).toEqual(undefined); } }); diff --git a/test/compile/scale/type.test.ts b/test/compile/scale/type.test.ts index 67f01252b4..100086e1f1 100644 --- a/test/compile/scale/type.test.ts +++ b/test/compile/scale/type.test.ts @@ -1,12 +1,11 @@ import {rangeType, SCALE_CHANNELS, X, Y} from '../../../src/channel'; import {scaleType} from '../../../src/compile/scale/type'; import * as log from '../../../src/log'; -import {BAR, PRIMITIVE_MARKS, RULE} from '../../../src/mark'; +import {BAR, PRIMITIVE_MARKS, RECT, RULE} from '../../../src/mark'; import {ScaleType} from '../../../src/scale'; -import {TIMEUNITS, isUTCTimeUnit} from '../../../src/timeunit'; +import {isUTCTimeUnit, TIMEUNITS} from '../../../src/timeunit'; import {NOMINAL, ORDINAL} from '../../../src/type'; import * as util from '../../../src/util'; -import {RECT} from '../../../src/mark'; describe('compile/scale', () => { describe('type()', () => { @@ -17,7 +16,7 @@ describe('compile/scale', () => { it( 'should show warning if users try to override the scale and use bin', log.wrap(localLogger => { - expect(scaleType({type: 'point'}, 'color', {type: 'quantitative', bin: true}, 'point')).toEqual( + expect(scaleType({type: 'point'}, 'color', {type: 'quantitative', field: 'x', bin: true}, 'point')).toEqual( ScaleType.BIN_ORDINAL ); expect(localLogger.warns[0]).toEqual( @@ -46,7 +45,9 @@ describe('compile/scale', () => { 'should return ordinal even if other type is specified', log.wrap(localLogger => { [ScaleType.LINEAR, ScaleType.BAND, ScaleType.POINT].forEach(badScaleType => { - expect(scaleType({type: badScaleType}, 'shape', {type: 'nominal'}, 'point')).toEqual(ScaleType.ORDINAL); + expect(scaleType({type: badScaleType}, 'shape', {field: 'x', type: 'nominal'}, 'point')).toEqual( + ScaleType.ORDINAL + ); const warns = localLogger.warns; expect(warns[warns.length - 1]).toEqual( log.message.scaleTypeNotWorkWithChannel('shape', badScaleType, 'ordinal') @@ -142,13 +143,13 @@ describe('compile/scale', () => { it('should return time for all non-utc time units.', () => { for (const timeUnit of TIMEUNITS.filter(t => !isUTCTimeUnit(t))) { - expect(scaleType({}, Y, {type: 'temporal', timeUnit: timeUnit}, 'point')).toEqual(ScaleType.TIME); + expect(scaleType({}, Y, {type: 'temporal', field: 'x', timeUnit: timeUnit}, 'point')).toEqual(ScaleType.TIME); } }); it('should return utc for all utc time units.', () => { for (const timeUnit of TIMEUNITS.filter(t => isUTCTimeUnit(t))) { - expect(scaleType({}, Y, {type: 'temporal', timeUnit: timeUnit}, 'point')).toEqual(ScaleType.UTC); + expect(scaleType({}, Y, {type: 'temporal', field: 'x', timeUnit: timeUnit}, 'point')).toEqual(ScaleType.UTC); } }); }); @@ -164,7 +165,9 @@ describe('compile/scale', () => { }); it('should return ordinal bin scale for quantitative color field with binning.', () => { - expect(scaleType({}, 'color', {type: 'quantitative', bin: true}, 'point')).toEqual(ScaleType.BIN_ORDINAL); + expect(scaleType({}, 'color', {type: 'quantitative', field: 'x', bin: true}, 'point')).toEqual( + ScaleType.BIN_ORDINAL + ); }); it( @@ -176,15 +179,17 @@ describe('compile/scale', () => { ); it('should return linear scale for quantitative by default.', () => { - expect(scaleType({}, 'x', {type: 'quantitative'}, 'point')).toEqual(ScaleType.LINEAR); + expect(scaleType({}, 'x', {type: 'quantitative', field: 'x'}, 'point')).toEqual(ScaleType.LINEAR); }); it('should return linear scale for quantitative even if binned.', () => { - expect(scaleType({}, 'opacity', {type: 'quantitative', bin: true}, 'point')).toEqual(ScaleType.LINEAR); + expect(scaleType({}, 'opacity', {type: 'quantitative', field: 'x', bin: true}, 'point')).toEqual( + ScaleType.LINEAR + ); }); it('should return linear scale for quantitative x and y.', () => { - expect(scaleType({}, 'x', {type: 'quantitative', bin: true}, 'point')).toEqual(ScaleType.LINEAR); + expect(scaleType({}, 'x', {type: 'quantitative', field: 'x', bin: true}, 'point')).toEqual(ScaleType.LINEAR); }); }); @@ -194,43 +199,47 @@ describe('compile/scale', () => { }); it('should return default scale type if data type is temporal but specified scale type is not time or utc', () => { - expect(scaleType({type: ScaleType.LINEAR}, 'x', {type: 'temporal', timeUnit: 'year'}, 'point')).toEqual( - ScaleType.TIME - ); + expect( + scaleType({type: ScaleType.LINEAR}, 'x', {type: 'temporal', field: 'x', timeUnit: 'year'}, 'point') + ).toEqual(ScaleType.TIME); - expect(scaleType({type: ScaleType.LINEAR}, 'color', {type: 'temporal', timeUnit: 'year'}, 'point')).toBe( - 'time' - ); + expect( + scaleType({type: ScaleType.LINEAR}, 'color', {type: 'temporal', field: 'x', timeUnit: 'year'}, 'point') + ).toBe('time'); }); it('should return time if data type is temporal but specified scale type is discrete', () => { - expect(scaleType({type: ScaleType.POINT}, 'x', {type: 'temporal', timeUnit: 'year'}, 'point')).toEqual( - ScaleType.TIME - ); + expect( + scaleType({type: ScaleType.POINT}, 'x', {type: 'temporal', field: 'x', timeUnit: 'year'}, 'point') + ).toEqual(ScaleType.TIME); }); it('should return default scale type if data type is temporal but specified scale type is time or utc or any discrete type', () => { - expect(scaleType({type: ScaleType.LINEAR}, 'x', {type: 'temporal', timeUnit: 'year'}, 'point')).toEqual( - ScaleType.TIME - ); + expect( + scaleType({type: ScaleType.LINEAR}, 'x', {type: 'temporal', field: 'x', timeUnit: 'year'}, 'point') + ).toEqual(ScaleType.TIME); }); it('should return utc scale type if data type is temporal and specified scale type is utc', () => { - expect(scaleType({type: ScaleType.UTC}, 'x', {type: 'temporal', timeUnit: 'year'}, 'point')).toEqual( - ScaleType.UTC - ); + expect( + scaleType({type: ScaleType.UTC}, 'x', {type: 'temporal', field: 'x', timeUnit: 'year'}, 'point') + ).toEqual(ScaleType.UTC); }); it('should return default scale type if data type is quantative but scale type do not support quantative', () => { - expect(scaleType({type: ScaleType.TIME}, 'color', {type: 'quantitative'}, 'point')).toEqual(ScaleType.LINEAR); + expect(scaleType({type: ScaleType.TIME}, 'color', {field: 'x', type: 'quantitative'}, 'point')).toEqual( + ScaleType.LINEAR + ); }); it('should return default scale type if data type is quantative and scale type supports quantative', () => { - expect(scaleType({type: ScaleType.TIME}, 'x', {type: 'quantitative'}, 'point')).toEqual(ScaleType.LINEAR); + expect(scaleType({type: ScaleType.TIME}, 'x', {field: 'x', type: 'quantitative'}, 'point')).toEqual( + ScaleType.LINEAR + ); }); it('should return default scale type if data type is quantative and scale type supports quantative', () => { - expect(scaleType({type: ScaleType.TIME}, 'x', {type: 'temporal'}, 'point')).toEqual(ScaleType.TIME); + expect(scaleType({type: ScaleType.TIME}, 'x', {field: 'x', type: 'temporal'}, 'point')).toEqual(ScaleType.TIME); }); }); }); diff --git a/test/encoding.test.ts b/test/encoding.test.ts index 69075f5232..74e9ecc606 100644 --- a/test/encoding.test.ts +++ b/test/encoding.test.ts @@ -10,7 +10,7 @@ import { X2, Y2 } from '../src/channel'; -import {isPositionFieldDef} from '../src/channeldef'; +import {isPositionFieldOrDatumDef} from '../src/channeldef'; import {defaultConfig} from '../src/config'; import { Encoding, @@ -79,7 +79,7 @@ describe('encoding', () => { const x = encoding.x; expect(x).toBeDefined(); - if (isPositionFieldDef(x)) { + if (isPositionFieldOrDatumDef(x)) { expect(x.axis).toBeDefined(); expect(x.axis.labelAngle).toBe(15); } else { diff --git a/test/normalize/repeat.test.ts b/test/normalize/repeat.test.ts index 997bd4ffb5..f0fbb372cb 100644 --- a/test/normalize/repeat.test.ts +++ b/test/normalize/repeat.test.ts @@ -18,6 +18,21 @@ describe('Repeat', () => { }); }); + it('should resolve repeated datums', () => { + const resolved = replaceRepeaterInEncoding( + { + x: {datum: {repeat: 'row'}, type: 'quantitative'}, + y: {field: 'bar', type: 'quantitative'} + }, + {row: 'foo'} + ); + + expect(resolved).toEqual({ + x: {datum: 'foo', type: 'quantitative'}, + y: {field: 'bar', type: 'quantitative'} + }); + }); + it( 'should show warning if repeat in field def cannot be resolved', log.wrap(localLogger => { From abc15f9ab2f2fde5e74646dc0d1c4c33e22e2076 Mon Sep 17 00:00:00 2001 From: Kanit Wongsuphasawat Date: Tue, 24 Mar 2020 23:39:27 -0700 Subject: [PATCH 2/9] docs: update examples --- examples/specs/geo_constant_value.vl.json | 4 +-- examples/specs/layer_bar_annotations.vl.json | 29 ++++++-------------- examples/specs/layer_line_datum_rule.vl.json | 21 ++++++++++++++ examples/specs/repeat_layer.vl.json | 7 ++++- 4 files changed, 38 insertions(+), 23 deletions(-) create mode 100644 examples/specs/layer_line_datum_rule.vl.json diff --git a/examples/specs/geo_constant_value.vl.json b/examples/specs/geo_constant_value.vl.json index 23cadfd9bb..ef73e26cae 100644 --- a/examples/specs/geo_constant_value.vl.json +++ b/examples/specs/geo_constant_value.vl.json @@ -32,7 +32,7 @@ "mark": "square", "encoding": { "longitude": { - "value": -122.335167 + "datum": -122.335167 }, "latitude": { "field": "latitude", @@ -54,7 +54,7 @@ "type": "quantitative" }, "latitude": { - "value": 47.608013 + "datum": 47.608013 }, "size": { "value": 1 diff --git a/examples/specs/layer_bar_annotations.vl.json b/examples/specs/layer_bar_annotations.vl.json index b03bf1ac60..45da4d66df 100644 --- a/examples/specs/layer_bar_annotations.vl.json +++ b/examples/specs/layer_bar_annotations.vl.json @@ -35,40 +35,29 @@ ], "encoding": { "x": {"field": "Day", "type": "ordinal"}, - "y": {"field": "baseline", "type": "quantitative"}, + "y": {"field": "baseline", "type": "quantitative", "title": "PM2.5 Value"}, "y2": {"field": "Value"}, "color": {"value": "#e45755"} } } ]}, { "data": { - "values": [ - {"ThresholdValue": 300, "Threshold": "hazardous"} - ] + "values": [{}] + }, + "encoding": { + "y": {"datum": 300} }, "layer": [{ - "mark": "rule", - "encoding": { - "y": {"field": "ThresholdValue", "type": "quantitative"} - } + "mark": "rule" }, { "mark": { "type": "text", "align": "right", "baseline": "bottom", "dx": -2, - "dy": -2 - }, - "encoding": { - "x": { - "value": "width" - }, - "y": { - "field": "ThresholdValue", - "type": "quantitative", - "axis": {"title": "PM2.5 Value"} - }, - "text": {"field": "Threshold", "type": "ordinal"} + "dy": -2, + "x": "width", + "text": "hazardous" } }] } diff --git a/examples/specs/layer_line_datum_rule.vl.json b/examples/specs/layer_line_datum_rule.vl.json new file mode 100644 index 0000000000..8741692af0 --- /dev/null +++ b/examples/specs/layer_line_datum_rule.vl.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://vega.github.io/schema/vega-lite/v4.json", + "layer": [ + { + "data": {"url": "data/stocks.csv"}, + "mark": "line", + "encoding": { + "x": {"field": "date", "type": "temporal"}, + "y": {"field": "price", "type": "quantitative"}, + "color": {"field": "symbol", "type": "nominal"} + } + }, + { + "data": {"values": [{}]}, + "mark": {"type": "rule", "strokeDash": [2, 2], "size": 2}, + "encoding": { + "y": {"datum": 300} + } + } + ] +} diff --git a/examples/specs/repeat_layer.vl.json b/examples/specs/repeat_layer.vl.json index cb7fe49dd0..0dc198ff02 100644 --- a/examples/specs/repeat_layer.vl.json +++ b/examples/specs/repeat_layer.vl.json @@ -17,7 +17,12 @@ "y": { "aggregate": "mean", "field": {"repeat": "layer"}, - "type": "quantitative" + "type": "quantitative", + "title": "Mean of US and Worldwide Gross" + }, + "color": { + "datum": {"repeat": "layer"}, + "type": "nominal" } } } From d5c2696062825bed577bf6016f62ecd20788b0af Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot Date: Wed, 25 Mar 2020 06:52:04 +0000 Subject: [PATCH 3/9] chore: update schema [CI] --- build/vega-lite-schema.json | 1968 ++++++++++++++++++++++------------- 1 file changed, 1258 insertions(+), 710 deletions(-) diff --git a/build/vega-lite-schema.json b/build/vega-lite-schema.json index 66ad76e83d..db7a9cf5d3 100644 --- a/build/vega-lite-schema.json +++ b/build/vega-lite-schema.json @@ -2696,11 +2696,14 @@ } ] }, + "ColorGradientDatumDefWithCondition": { + "$ref": "#/definitions/FieldOrDatumDefWithCondition" + }, "ColorGradientFieldDefWithCondition": { - "$ref": "#/definitions/FieldDefWithCondition" + "$ref": "#/definitions/FieldOrDatumDefWithCondition" }, "ColorGradientValueWithCondition": { - "$ref": "#/definitions/ValueWithCondition" + "$ref": "#/definitions/ValueWithCondition" }, "ColorName": { "enum": [ @@ -2882,6 +2885,9 @@ { "$ref": "#/definitions/ColorGradientFieldDefWithCondition" }, + { + "$ref": "#/definitions/ColorGradientDatumDefWithCondition" + }, { "$ref": "#/definitions/ColorGradientValueWithCondition" } @@ -2907,6 +2913,9 @@ { "$ref": "#/definitions/ColorGradientFieldDefWithCondition" }, + { + "$ref": "#/definitions/ColorGradientDatumDefWithCondition" + }, { "$ref": "#/definitions/ColorGradientValueWithCondition" } @@ -2918,6 +2927,9 @@ { "$ref": "#/definitions/NumericFieldDefWithCondition" }, + { + "$ref": "#/definitions/NumericDatumDefWithCondition" + }, { "$ref": "#/definitions/NumericValueWithCondition" } @@ -2944,6 +2956,9 @@ { "$ref": "#/definitions/LatLongFieldDef" }, + { + "$ref": "#/definitions/DatumDef" + }, { "$ref": "#/definitions/NumberValueDef" } @@ -2955,6 +2970,9 @@ { "$ref": "#/definitions/SecondaryFieldDef" }, + { + "$ref": "#/definitions/DatumDef" + }, { "$ref": "#/definitions/NumberValueDef" } @@ -2966,6 +2984,9 @@ { "$ref": "#/definitions/LatLongFieldDef" }, + { + "$ref": "#/definitions/DatumDef" + }, { "$ref": "#/definitions/NumberValueDef" } @@ -2977,6 +2998,9 @@ { "$ref": "#/definitions/SecondaryFieldDef" }, + { + "$ref": "#/definitions/DatumDef" + }, { "$ref": "#/definitions/NumberValueDef" } @@ -2988,6 +3012,9 @@ { "$ref": "#/definitions/NumericFieldDefWithCondition" }, + { + "$ref": "#/definitions/NumericDatumDefWithCondition" + }, { "$ref": "#/definitions/NumericValueWithCondition" } @@ -3016,6 +3043,9 @@ { "$ref": "#/definitions/ShapeFieldDefWithCondition" }, + { + "$ref": "#/definitions/StringDatumDefWithCondition" + }, { "$ref": "#/definitions/ShapeValueWithCondition" } @@ -3027,6 +3057,9 @@ { "$ref": "#/definitions/NumericFieldDefWithCondition" }, + { + "$ref": "#/definitions/NumericDatumDefWithCondition" + }, { "$ref": "#/definitions/NumericValueWithCondition" } @@ -3038,6 +3071,9 @@ { "$ref": "#/definitions/ColorGradientFieldDefWithCondition" }, + { + "$ref": "#/definitions/ColorGradientDatumDefWithCondition" + }, { "$ref": "#/definitions/ColorGradientValueWithCondition" } @@ -3049,6 +3085,9 @@ { "$ref": "#/definitions/NumericArrayFieldDefWithCondition" }, + { + "$ref": "#/definitions/NumericArrayDatumDefWithCondition" + }, { "$ref": "#/definitions/NumericArrayValueDefWithCondition" } @@ -3060,6 +3099,9 @@ { "$ref": "#/definitions/NumericFieldDefWithCondition" }, + { + "$ref": "#/definitions/NumericDatumDefWithCondition" + }, { "$ref": "#/definitions/NumericValueWithCondition" } @@ -3071,6 +3113,9 @@ { "$ref": "#/definitions/NumericFieldDefWithCondition" }, + { + "$ref": "#/definitions/NumericDatumDefWithCondition" + }, { "$ref": "#/definitions/NumericValueWithCondition" } @@ -3124,6 +3169,9 @@ { "$ref": "#/definitions/PositionFieldDef" }, + { + "$ref": "#/definitions/PositionDatumDef" + }, { "$ref": "#/definitions/XValueDef" } @@ -3135,6 +3183,9 @@ { "$ref": "#/definitions/SecondaryFieldDef" }, + { + "$ref": "#/definitions/DatumDef" + }, { "$ref": "#/definitions/XValueDef" } @@ -3168,6 +3219,9 @@ { "$ref": "#/definitions/PositionFieldDef" }, + { + "$ref": "#/definitions/PositionDatumDef" + }, { "$ref": "#/definitions/YValueDef" } @@ -3179,6 +3233,9 @@ { "$ref": "#/definitions/SecondaryFieldDef" }, + { + "$ref": "#/definitions/DatumDef" + }, { "$ref": "#/definitions/YValueDef" } @@ -3250,23 +3307,23 @@ }, "type": "object" }, - "ConditionalMarkPropFieldDef": { + "ConditionalMarkPropFieldOrDatumDef": { "anyOf": [ { - "$ref": "#/definitions/ConditionalPredicate" + "$ref": "#/definitions/ConditionalPredicate" }, { - "$ref": "#/definitions/ConditionalSelection" + "$ref": "#/definitions/ConditionalSelection" } ] }, - "ConditionalMarkPropFieldDef": { + "ConditionalMarkPropFieldOrDatumDef": { "anyOf": [ { - "$ref": "#/definitions/ConditionalPredicate>" + "$ref": "#/definitions/ConditionalPredicate>" }, { - "$ref": "#/definitions/ConditionalSelection>" + "$ref": "#/definitions/ConditionalSelection>" } ] }, @@ -3631,7 +3688,291 @@ "ConditionalAxisString": { "$ref": "#/definitions/ConditionalAxisProperty<(string|null)>" }, - "ConditionalPredicate": { + "ConditionalPredicate": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "aggregate": { + "$ref": "#/definitions/Aggregate", + "description": "Aggregation function for the field\n(e.g., `\"mean\"`, `\"sum\"`, `\"median\"`, `\"min\"`, `\"max\"`, `\"count\"`).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html) documentation." + }, + "bin": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/definitions/BinParams" + }, + { + "type": "null" + } + ], + "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." + }, + "field": { + "$ref": "#/definitions/Field", + "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." + }, + "legend": { + "anyOf": [ + { + "$ref": "#/definitions/Legend" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." + }, + "scale": { + "anyOf": [ + { + "$ref": "#/definitions/Scale" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." + }, + "sort": { + "$ref": "#/definitions/Sort", + "description": "Sort order for the encoded field.\n\nFor continuous fields (quantitative or temporal), `sort` can be either `\"ascending\"` or `\"descending\"`.\n\nFor discrete fields, `sort` can be one of the following:\n- `\"ascending\"` or `\"descending\"` -- for sorting by the values' natural order in JavaScript.\n- [A string indicating an encoding channel name to sort by](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding) (e.g., `\"x\"` or `\"y\"`) with an optional minus prefix for descending sort (e.g., `\"-x\"` to sort by x-field, descending). This channel string is short-form of [a sort-by-encoding definition](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding). For example, `\"sort\": \"-x\"` is equivalent to `\"sort\": {\"encoding\": \"x\", \"order\": \"descending\"}`.\n- [A sort field definition](https://vega.github.io/vega-lite/docs/sort.html#sort-field) for sorting by another field.\n- [An array specifying the field values in preferred order](https://vega.github.io/vega-lite/docs/sort.html#sort-array). In this case, the sort order will obey the values in the array, followed by any unspecified values in their original order. For discrete time field, values in the sort array can be [date-time definition objects](types#datetime). In addition, for time units `\"month\"` and `\"day\"`, the values can be the month or day names (case insensitive) or their 3-letter initials (e.g., `\"Mon\"`, `\"Tue\"`).\n- `null` indicating no sort.\n\n__Default value:__ `\"ascending\"`\n\n__Note:__ `null` and sorting by another channel is not supported for `row` and `column`.\n\n__See also:__ [`sort`](https://vega.github.io/vega-lite/docs/sort.html) documentation." + }, + "test": { + "$ref": "#/definitions/PredicateComposition", + "description": "Predicate for triggering the condition" + }, + "timeUnit": { + "anyOf": [ + { + "$ref": "#/definitions/TimeUnit" + }, + { + "$ref": "#/definitions/TimeUnitParams" + } + ], + "description": "Time unit (e.g., `year`, `yearmonth`, `month`, `hours`) for a temporal field.\nor [a temporal field that gets casted as ordinal](https://vega.github.io/vega-lite/docs/type.html#cast).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html) documentation." + }, + "title": { + "anyOf": [ + { + "$ref": "#/definitions/Text" + }, + { + "type": "null" + } + ], + "description": "A title for the field. If `null`, the title will be removed.\n\n__Default value:__ derived from the field's name and transformation function (`aggregate`, `bin` and `timeUnit`). If the field has an aggregate function, the function is displayed as part of the title (e.g., `\"Sum of Profit\"`). If the field is binned or has a time unit applied, the applied function is shown in parentheses (e.g., `\"Profit (binned)\"`, `\"Transaction Date (year-month)\"`). Otherwise, the title is simply the field name.\n\n__Notes__:\n\n1) You can customize the default field title format by providing the [`fieldTitle`](https://vega.github.io/vega-lite/docs/config.html#top-level-config) property in the [config](https://vega.github.io/vega-lite/docs/config.html) or [`fieldTitle` function via the `compile` function's options](https://vega.github.io/vega-lite/docs/compile.html#field-title).\n\n2) If both field definition's `title` and axis, header, or legend `title` are defined, axis/header/legend title will be used." + }, + "type": { + "$ref": "#/definitions/StandardType", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." + } + }, + "required": [ + "test", + "type" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "datum": { + "anyOf": [ + { + "$ref": "#/definitions/Value" + }, + { + "$ref": "#/definitions/RepeatRef" + } + ], + "description": "A constant value in data domain." + }, + "legend": { + "anyOf": [ + { + "$ref": "#/definitions/Legend" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." + }, + "scale": { + "anyOf": [ + { + "$ref": "#/definitions/Scale" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." + }, + "test": { + "$ref": "#/definitions/PredicateComposition", + "description": "Predicate for triggering the condition" + }, + "type": { + "$ref": "#/definitions/Type", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." + } + }, + "required": [ + "test" + ], + "type": "object" + } + ] + }, + "ConditionalPredicate>": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "aggregate": { + "$ref": "#/definitions/Aggregate", + "description": "Aggregation function for the field\n(e.g., `\"mean\"`, `\"sum\"`, `\"median\"`, `\"min\"`, `\"max\"`, `\"count\"`).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html) documentation." + }, + "bin": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/definitions/BinParams" + }, + { + "type": "null" + } + ], + "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." + }, + "field": { + "$ref": "#/definitions/Field", + "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." + }, + "legend": { + "anyOf": [ + { + "$ref": "#/definitions/Legend" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." + }, + "scale": { + "anyOf": [ + { + "$ref": "#/definitions/Scale" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." + }, + "sort": { + "$ref": "#/definitions/Sort", + "description": "Sort order for the encoded field.\n\nFor continuous fields (quantitative or temporal), `sort` can be either `\"ascending\"` or `\"descending\"`.\n\nFor discrete fields, `sort` can be one of the following:\n- `\"ascending\"` or `\"descending\"` -- for sorting by the values' natural order in JavaScript.\n- [A string indicating an encoding channel name to sort by](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding) (e.g., `\"x\"` or `\"y\"`) with an optional minus prefix for descending sort (e.g., `\"-x\"` to sort by x-field, descending). This channel string is short-form of [a sort-by-encoding definition](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding). For example, `\"sort\": \"-x\"` is equivalent to `\"sort\": {\"encoding\": \"x\", \"order\": \"descending\"}`.\n- [A sort field definition](https://vega.github.io/vega-lite/docs/sort.html#sort-field) for sorting by another field.\n- [An array specifying the field values in preferred order](https://vega.github.io/vega-lite/docs/sort.html#sort-array). In this case, the sort order will obey the values in the array, followed by any unspecified values in their original order. For discrete time field, values in the sort array can be [date-time definition objects](types#datetime). In addition, for time units `\"month\"` and `\"day\"`, the values can be the month or day names (case insensitive) or their 3-letter initials (e.g., `\"Mon\"`, `\"Tue\"`).\n- `null` indicating no sort.\n\n__Default value:__ `\"ascending\"`\n\n__Note:__ `null` and sorting by another channel is not supported for `row` and `column`.\n\n__See also:__ [`sort`](https://vega.github.io/vega-lite/docs/sort.html) documentation." + }, + "test": { + "$ref": "#/definitions/PredicateComposition", + "description": "Predicate for triggering the condition" + }, + "timeUnit": { + "anyOf": [ + { + "$ref": "#/definitions/TimeUnit" + }, + { + "$ref": "#/definitions/TimeUnitParams" + } + ], + "description": "Time unit (e.g., `year`, `yearmonth`, `month`, `hours`) for a temporal field.\nor [a temporal field that gets casted as ordinal](https://vega.github.io/vega-lite/docs/type.html#cast).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html) documentation." + }, + "title": { + "anyOf": [ + { + "$ref": "#/definitions/Text" + }, + { + "type": "null" + } + ], + "description": "A title for the field. If `null`, the title will be removed.\n\n__Default value:__ derived from the field's name and transformation function (`aggregate`, `bin` and `timeUnit`). If the field has an aggregate function, the function is displayed as part of the title (e.g., `\"Sum of Profit\"`). If the field is binned or has a time unit applied, the applied function is shown in parentheses (e.g., `\"Profit (binned)\"`, `\"Transaction Date (year-month)\"`). Otherwise, the title is simply the field name.\n\n__Notes__:\n\n1) You can customize the default field title format by providing the [`fieldTitle`](https://vega.github.io/vega-lite/docs/config.html#top-level-config) property in the [config](https://vega.github.io/vega-lite/docs/config.html) or [`fieldTitle` function via the `compile` function's options](https://vega.github.io/vega-lite/docs/compile.html#field-title).\n\n2) If both field definition's `title` and axis, header, or legend `title` are defined, axis/header/legend title will be used." + }, + "type": { + "$ref": "#/definitions/TypeForShape", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." + } + }, + "required": [ + "test", + "type" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "datum": { + "anyOf": [ + { + "$ref": "#/definitions/Value" + }, + { + "$ref": "#/definitions/RepeatRef" + } + ], + "description": "A constant value in data domain." + }, + "legend": { + "anyOf": [ + { + "$ref": "#/definitions/Legend" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." + }, + "scale": { + "anyOf": [ + { + "$ref": "#/definitions/Scale" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." + }, + "test": { + "$ref": "#/definitions/PredicateComposition", + "description": "Predicate for triggering the condition" + }, + "type": { + "$ref": "#/definitions/Type", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." + } + }, + "required": [ + "test" + ], + "type": "object" + } + ] + }, + "ConditionalPredicate": { "additionalProperties": false, "properties": { "aggregate": { @@ -3646,6 +3987,12 @@ { "$ref": "#/definitions/BinParams" }, + { + "enum": [ + "binned" + ], + "type": "string" + }, { "type": "null" } @@ -3656,198 +4003,16 @@ "$ref": "#/definitions/Field", "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." }, - "legend": { + "format": { "anyOf": [ { - "$ref": "#/definitions/Legend" + "type": "string" }, { - "type": "null" + "type": "object" } ], - "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." - }, - "scale": { - "anyOf": [ - { - "$ref": "#/definitions/Scale" - }, - { - "type": "null" - } - ], - "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." - }, - "sort": { - "$ref": "#/definitions/Sort", - "description": "Sort order for the encoded field.\n\nFor continuous fields (quantitative or temporal), `sort` can be either `\"ascending\"` or `\"descending\"`.\n\nFor discrete fields, `sort` can be one of the following:\n- `\"ascending\"` or `\"descending\"` -- for sorting by the values' natural order in JavaScript.\n- [A string indicating an encoding channel name to sort by](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding) (e.g., `\"x\"` or `\"y\"`) with an optional minus prefix for descending sort (e.g., `\"-x\"` to sort by x-field, descending). This channel string is short-form of [a sort-by-encoding definition](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding). For example, `\"sort\": \"-x\"` is equivalent to `\"sort\": {\"encoding\": \"x\", \"order\": \"descending\"}`.\n- [A sort field definition](https://vega.github.io/vega-lite/docs/sort.html#sort-field) for sorting by another field.\n- [An array specifying the field values in preferred order](https://vega.github.io/vega-lite/docs/sort.html#sort-array). In this case, the sort order will obey the values in the array, followed by any unspecified values in their original order. For discrete time field, values in the sort array can be [date-time definition objects](types#datetime). In addition, for time units `\"month\"` and `\"day\"`, the values can be the month or day names (case insensitive) or their 3-letter initials (e.g., `\"Mon\"`, `\"Tue\"`).\n- `null` indicating no sort.\n\n__Default value:__ `\"ascending\"`\n\n__Note:__ `null` and sorting by another channel is not supported for `row` and `column`.\n\n__See also:__ [`sort`](https://vega.github.io/vega-lite/docs/sort.html) documentation." - }, - "test": { - "$ref": "#/definitions/PredicateComposition", - "description": "Predicate for triggering the condition" - }, - "timeUnit": { - "anyOf": [ - { - "$ref": "#/definitions/TimeUnit" - }, - { - "$ref": "#/definitions/TimeUnitParams" - } - ], - "description": "Time unit (e.g., `year`, `yearmonth`, `month`, `hours`) for a temporal field.\nor [a temporal field that gets casted as ordinal](https://vega.github.io/vega-lite/docs/type.html#cast).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html) documentation." - }, - "title": { - "anyOf": [ - { - "$ref": "#/definitions/Text" - }, - { - "type": "null" - } - ], - "description": "A title for the field. If `null`, the title will be removed.\n\n__Default value:__ derived from the field's name and transformation function (`aggregate`, `bin` and `timeUnit`). If the field has an aggregate function, the function is displayed as part of the title (e.g., `\"Sum of Profit\"`). If the field is binned or has a time unit applied, the applied function is shown in parentheses (e.g., `\"Profit (binned)\"`, `\"Transaction Date (year-month)\"`). Otherwise, the title is simply the field name.\n\n__Notes__:\n\n1) You can customize the default field title format by providing the [`fieldTitle`](https://vega.github.io/vega-lite/docs/config.html#top-level-config) property in the [config](https://vega.github.io/vega-lite/docs/config.html) or [`fieldTitle` function via the `compile` function's options](https://vega.github.io/vega-lite/docs/compile.html#field-title).\n\n2) If both field definition's `title` and axis, header, or legend `title` are defined, axis/header/legend title will be used." - }, - "type": { - "$ref": "#/definitions/StandardType", - "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." - } - }, - "required": [ - "test", - "type" - ], - "type": "object" - }, - "ConditionalPredicate>": { - "additionalProperties": false, - "properties": { - "aggregate": { - "$ref": "#/definitions/Aggregate", - "description": "Aggregation function for the field\n(e.g., `\"mean\"`, `\"sum\"`, `\"median\"`, `\"min\"`, `\"max\"`, `\"count\"`).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html) documentation." - }, - "bin": { - "anyOf": [ - { - "type": "boolean" - }, - { - "$ref": "#/definitions/BinParams" - }, - { - "type": "null" - } - ], - "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." - }, - "field": { - "$ref": "#/definitions/Field", - "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." - }, - "legend": { - "anyOf": [ - { - "$ref": "#/definitions/Legend" - }, - { - "type": "null" - } - ], - "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." - }, - "scale": { - "anyOf": [ - { - "$ref": "#/definitions/Scale" - }, - { - "type": "null" - } - ], - "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." - }, - "sort": { - "$ref": "#/definitions/Sort", - "description": "Sort order for the encoded field.\n\nFor continuous fields (quantitative or temporal), `sort` can be either `\"ascending\"` or `\"descending\"`.\n\nFor discrete fields, `sort` can be one of the following:\n- `\"ascending\"` or `\"descending\"` -- for sorting by the values' natural order in JavaScript.\n- [A string indicating an encoding channel name to sort by](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding) (e.g., `\"x\"` or `\"y\"`) with an optional minus prefix for descending sort (e.g., `\"-x\"` to sort by x-field, descending). This channel string is short-form of [a sort-by-encoding definition](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding). For example, `\"sort\": \"-x\"` is equivalent to `\"sort\": {\"encoding\": \"x\", \"order\": \"descending\"}`.\n- [A sort field definition](https://vega.github.io/vega-lite/docs/sort.html#sort-field) for sorting by another field.\n- [An array specifying the field values in preferred order](https://vega.github.io/vega-lite/docs/sort.html#sort-array). In this case, the sort order will obey the values in the array, followed by any unspecified values in their original order. For discrete time field, values in the sort array can be [date-time definition objects](types#datetime). In addition, for time units `\"month\"` and `\"day\"`, the values can be the month or day names (case insensitive) or their 3-letter initials (e.g., `\"Mon\"`, `\"Tue\"`).\n- `null` indicating no sort.\n\n__Default value:__ `\"ascending\"`\n\n__Note:__ `null` and sorting by another channel is not supported for `row` and `column`.\n\n__See also:__ [`sort`](https://vega.github.io/vega-lite/docs/sort.html) documentation." - }, - "test": { - "$ref": "#/definitions/PredicateComposition", - "description": "Predicate for triggering the condition" - }, - "timeUnit": { - "anyOf": [ - { - "$ref": "#/definitions/TimeUnit" - }, - { - "$ref": "#/definitions/TimeUnitParams" - } - ], - "description": "Time unit (e.g., `year`, `yearmonth`, `month`, `hours`) for a temporal field.\nor [a temporal field that gets casted as ordinal](https://vega.github.io/vega-lite/docs/type.html#cast).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html) documentation." - }, - "title": { - "anyOf": [ - { - "$ref": "#/definitions/Text" - }, - { - "type": "null" - } - ], - "description": "A title for the field. If `null`, the title will be removed.\n\n__Default value:__ derived from the field's name and transformation function (`aggregate`, `bin` and `timeUnit`). If the field has an aggregate function, the function is displayed as part of the title (e.g., `\"Sum of Profit\"`). If the field is binned or has a time unit applied, the applied function is shown in parentheses (e.g., `\"Profit (binned)\"`, `\"Transaction Date (year-month)\"`). Otherwise, the title is simply the field name.\n\n__Notes__:\n\n1) You can customize the default field title format by providing the [`fieldTitle`](https://vega.github.io/vega-lite/docs/config.html#top-level-config) property in the [config](https://vega.github.io/vega-lite/docs/config.html) or [`fieldTitle` function via the `compile` function's options](https://vega.github.io/vega-lite/docs/compile.html#field-title).\n\n2) If both field definition's `title` and axis, header, or legend `title` are defined, axis/header/legend title will be used." - }, - "type": { - "$ref": "#/definitions/TypeForShape", - "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." - } - }, - "required": [ - "test", - "type" - ], - "type": "object" - }, - "ConditionalPredicate": { - "additionalProperties": false, - "properties": { - "aggregate": { - "$ref": "#/definitions/Aggregate", - "description": "Aggregation function for the field\n(e.g., `\"mean\"`, `\"sum\"`, `\"median\"`, `\"min\"`, `\"max\"`, `\"count\"`).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html) documentation." - }, - "bin": { - "anyOf": [ - { - "type": "boolean" - }, - { - "$ref": "#/definitions/BinParams" - }, - { - "enum": [ - "binned" - ], - "type": "string" - }, - { - "type": "null" - } - ], - "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." - }, - "field": { - "$ref": "#/definitions/Field", - "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." - }, - "format": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "object" - } - ], - "description": "When used with the default `\"number\"` and `\"time\"` format type, the text formatting pattern for labels of guides (axes, legends, headers) and text marks.\n\n- If the format type is `\"number\"` (e.g., for quantitative fields), this is D3's [number format pattern](https://github.com/d3/d3-format#locale_format).\n- If the format type is `\"time\"` (e.g., for temporal fields), this is D3's [time format pattern](https://github.com/d3/d3-time-format#locale_format).\n\nSee the [format documentation](https://vega.github.io/vega-lite/docs/format.html) for more examples.\n\nWhen used with a [custom `\"formatType\"`](https://vega.github.io/vega-lite/usage/compile.html#format-type) that takes `datum.value` and format parameter as input), this property represents the format parameter.\n\n__Default value:__ Derived from [numberFormat](https://vega.github.io/vega-lite/docs/config.html#format) config for number format and from [timeFormat](https://vega.github.io/vega-lite/docs/config.html#format) config for time format." + "description": "When used with the default `\"number\"` and `\"time\"` format type, the text formatting pattern for labels of guides (axes, legends, headers) and text marks.\n\n- If the format type is `\"number\"` (e.g., for quantitative fields), this is D3's [number format pattern](https://github.com/d3/d3-format#locale_format).\n- If the format type is `\"time\"` (e.g., for temporal fields), this is D3's [time format pattern](https://github.com/d3/d3-time-format#locale_format).\n\nSee the [format documentation](https://vega.github.io/vega-lite/docs/format.html) for more examples.\n\nWhen used with a [custom `\"formatType\"`](https://vega.github.io/vega-lite/usage/compile.html#format-type) that takes `datum.value` and format parameter as input), this property represents the format parameter.\n\n__Default value:__ Derived from [numberFormat](https://vega.github.io/vega-lite/docs/config.html#format) config for number format and from [timeFormat](https://vega.github.io/vega-lite/docs/config.html#format) config for time format." }, "formatType": { "description": "The format type for labels (`\"number\"` or `\"time\"` or a [registered custom format type](https://vega.github.io/vega-lite/usage/compile.html#format-type)).\n\n\n__Default value:__\n- `\"time\"` for temporal fields and ordinal and nomimal fields with `timeUnit`.\n- `\"number\"` for quantitative fields as well as ordinal and nomimal fields without `timeUnit`.", @@ -4192,181 +4357,289 @@ ], "type": "object" }, - "ConditionalSelection": { - "additionalProperties": false, - "properties": { - "aggregate": { - "$ref": "#/definitions/Aggregate", - "description": "Aggregation function for the field\n(e.g., `\"mean\"`, `\"sum\"`, `\"median\"`, `\"min\"`, `\"max\"`, `\"count\"`).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html) documentation." - }, - "bin": { - "anyOf": [ - { - "type": "boolean" + "ConditionalSelection": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "aggregate": { + "$ref": "#/definitions/Aggregate", + "description": "Aggregation function for the field\n(e.g., `\"mean\"`, `\"sum\"`, `\"median\"`, `\"min\"`, `\"max\"`, `\"count\"`).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html) documentation." }, - { - "$ref": "#/definitions/BinParams" + "bin": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/definitions/BinParams" + }, + { + "type": "null" + } + ], + "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." }, - { - "type": "null" - } - ], - "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." - }, - "field": { - "$ref": "#/definitions/Field", - "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." - }, - "legend": { - "anyOf": [ - { - "$ref": "#/definitions/Legend" + "field": { + "$ref": "#/definitions/Field", + "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." }, - { - "type": "null" + "legend": { + "anyOf": [ + { + "$ref": "#/definitions/Legend" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." + }, + "scale": { + "anyOf": [ + { + "$ref": "#/definitions/Scale" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." + }, + "selection": { + "$ref": "#/definitions/SelectionComposition", + "description": "A [selection name](https://vega.github.io/vega-lite/docs/selection.html), or a series of [composed selections](https://vega.github.io/vega-lite/docs/selection.html#compose)." + }, + "sort": { + "$ref": "#/definitions/Sort", + "description": "Sort order for the encoded field.\n\nFor continuous fields (quantitative or temporal), `sort` can be either `\"ascending\"` or `\"descending\"`.\n\nFor discrete fields, `sort` can be one of the following:\n- `\"ascending\"` or `\"descending\"` -- for sorting by the values' natural order in JavaScript.\n- [A string indicating an encoding channel name to sort by](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding) (e.g., `\"x\"` or `\"y\"`) with an optional minus prefix for descending sort (e.g., `\"-x\"` to sort by x-field, descending). This channel string is short-form of [a sort-by-encoding definition](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding). For example, `\"sort\": \"-x\"` is equivalent to `\"sort\": {\"encoding\": \"x\", \"order\": \"descending\"}`.\n- [A sort field definition](https://vega.github.io/vega-lite/docs/sort.html#sort-field) for sorting by another field.\n- [An array specifying the field values in preferred order](https://vega.github.io/vega-lite/docs/sort.html#sort-array). In this case, the sort order will obey the values in the array, followed by any unspecified values in their original order. For discrete time field, values in the sort array can be [date-time definition objects](types#datetime). In addition, for time units `\"month\"` and `\"day\"`, the values can be the month or day names (case insensitive) or their 3-letter initials (e.g., `\"Mon\"`, `\"Tue\"`).\n- `null` indicating no sort.\n\n__Default value:__ `\"ascending\"`\n\n__Note:__ `null` and sorting by another channel is not supported for `row` and `column`.\n\n__See also:__ [`sort`](https://vega.github.io/vega-lite/docs/sort.html) documentation." + }, + "timeUnit": { + "anyOf": [ + { + "$ref": "#/definitions/TimeUnit" + }, + { + "$ref": "#/definitions/TimeUnitParams" + } + ], + "description": "Time unit (e.g., `year`, `yearmonth`, `month`, `hours`) for a temporal field.\nor [a temporal field that gets casted as ordinal](https://vega.github.io/vega-lite/docs/type.html#cast).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html) documentation." + }, + "title": { + "anyOf": [ + { + "$ref": "#/definitions/Text" + }, + { + "type": "null" + } + ], + "description": "A title for the field. If `null`, the title will be removed.\n\n__Default value:__ derived from the field's name and transformation function (`aggregate`, `bin` and `timeUnit`). If the field has an aggregate function, the function is displayed as part of the title (e.g., `\"Sum of Profit\"`). If the field is binned or has a time unit applied, the applied function is shown in parentheses (e.g., `\"Profit (binned)\"`, `\"Transaction Date (year-month)\"`). Otherwise, the title is simply the field name.\n\n__Notes__:\n\n1) You can customize the default field title format by providing the [`fieldTitle`](https://vega.github.io/vega-lite/docs/config.html#top-level-config) property in the [config](https://vega.github.io/vega-lite/docs/config.html) or [`fieldTitle` function via the `compile` function's options](https://vega.github.io/vega-lite/docs/compile.html#field-title).\n\n2) If both field definition's `title` and axis, header, or legend `title` are defined, axis/header/legend title will be used." + }, + "type": { + "$ref": "#/definitions/StandardType", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." } + }, + "required": [ + "selection", + "type" ], - "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." + "type": "object" }, - "scale": { - "anyOf": [ - { - "$ref": "#/definitions/Scale" + { + "additionalProperties": false, + "properties": { + "datum": { + "anyOf": [ + { + "$ref": "#/definitions/Value" + }, + { + "$ref": "#/definitions/RepeatRef" + } + ], + "description": "A constant value in data domain." }, - { - "type": "null" - } - ], - "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." - }, - "selection": { - "$ref": "#/definitions/SelectionComposition", - "description": "A [selection name](https://vega.github.io/vega-lite/docs/selection.html), or a series of [composed selections](https://vega.github.io/vega-lite/docs/selection.html#compose)." - }, - "sort": { - "$ref": "#/definitions/Sort", - "description": "Sort order for the encoded field.\n\nFor continuous fields (quantitative or temporal), `sort` can be either `\"ascending\"` or `\"descending\"`.\n\nFor discrete fields, `sort` can be one of the following:\n- `\"ascending\"` or `\"descending\"` -- for sorting by the values' natural order in JavaScript.\n- [A string indicating an encoding channel name to sort by](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding) (e.g., `\"x\"` or `\"y\"`) with an optional minus prefix for descending sort (e.g., `\"-x\"` to sort by x-field, descending). This channel string is short-form of [a sort-by-encoding definition](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding). For example, `\"sort\": \"-x\"` is equivalent to `\"sort\": {\"encoding\": \"x\", \"order\": \"descending\"}`.\n- [A sort field definition](https://vega.github.io/vega-lite/docs/sort.html#sort-field) for sorting by another field.\n- [An array specifying the field values in preferred order](https://vega.github.io/vega-lite/docs/sort.html#sort-array). In this case, the sort order will obey the values in the array, followed by any unspecified values in their original order. For discrete time field, values in the sort array can be [date-time definition objects](types#datetime). In addition, for time units `\"month\"` and `\"day\"`, the values can be the month or day names (case insensitive) or their 3-letter initials (e.g., `\"Mon\"`, `\"Tue\"`).\n- `null` indicating no sort.\n\n__Default value:__ `\"ascending\"`\n\n__Note:__ `null` and sorting by another channel is not supported for `row` and `column`.\n\n__See also:__ [`sort`](https://vega.github.io/vega-lite/docs/sort.html) documentation." - }, - "timeUnit": { - "anyOf": [ - { - "$ref": "#/definitions/TimeUnit" + "legend": { + "anyOf": [ + { + "$ref": "#/definitions/Legend" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." }, - { - "$ref": "#/definitions/TimeUnitParams" - } - ], - "description": "Time unit (e.g., `year`, `yearmonth`, `month`, `hours`) for a temporal field.\nor [a temporal field that gets casted as ordinal](https://vega.github.io/vega-lite/docs/type.html#cast).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html) documentation." - }, - "title": { - "anyOf": [ - { - "$ref": "#/definitions/Text" + "scale": { + "anyOf": [ + { + "$ref": "#/definitions/Scale" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." }, - { - "type": "null" + "selection": { + "$ref": "#/definitions/SelectionComposition", + "description": "A [selection name](https://vega.github.io/vega-lite/docs/selection.html), or a series of [composed selections](https://vega.github.io/vega-lite/docs/selection.html#compose)." + }, + "type": { + "$ref": "#/definitions/Type", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." } + }, + "required": [ + "selection" ], - "description": "A title for the field. If `null`, the title will be removed.\n\n__Default value:__ derived from the field's name and transformation function (`aggregate`, `bin` and `timeUnit`). If the field has an aggregate function, the function is displayed as part of the title (e.g., `\"Sum of Profit\"`). If the field is binned or has a time unit applied, the applied function is shown in parentheses (e.g., `\"Profit (binned)\"`, `\"Transaction Date (year-month)\"`). Otherwise, the title is simply the field name.\n\n__Notes__:\n\n1) You can customize the default field title format by providing the [`fieldTitle`](https://vega.github.io/vega-lite/docs/config.html#top-level-config) property in the [config](https://vega.github.io/vega-lite/docs/config.html) or [`fieldTitle` function via the `compile` function's options](https://vega.github.io/vega-lite/docs/compile.html#field-title).\n\n2) If both field definition's `title` and axis, header, or legend `title` are defined, axis/header/legend title will be used." - }, - "type": { - "$ref": "#/definitions/StandardType", - "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." + "type": "object" } - }, - "required": [ - "selection", - "type" - ], - "type": "object" + ] }, - "ConditionalSelection>": { - "additionalProperties": false, - "properties": { - "aggregate": { - "$ref": "#/definitions/Aggregate", - "description": "Aggregation function for the field\n(e.g., `\"mean\"`, `\"sum\"`, `\"median\"`, `\"min\"`, `\"max\"`, `\"count\"`).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html) documentation." - }, - "bin": { - "anyOf": [ - { - "type": "boolean" + "ConditionalSelection>": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "aggregate": { + "$ref": "#/definitions/Aggregate", + "description": "Aggregation function for the field\n(e.g., `\"mean\"`, `\"sum\"`, `\"median\"`, `\"min\"`, `\"max\"`, `\"count\"`).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html) documentation." }, - { - "$ref": "#/definitions/BinParams" + "bin": { + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/definitions/BinParams" + }, + { + "type": "null" + } + ], + "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." }, - { - "type": "null" - } - ], - "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." - }, - "field": { - "$ref": "#/definitions/Field", - "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." - }, - "legend": { - "anyOf": [ - { - "$ref": "#/definitions/Legend" + "field": { + "$ref": "#/definitions/Field", + "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." }, - { - "type": "null" - } - ], - "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." - }, - "scale": { - "anyOf": [ - { - "$ref": "#/definitions/Scale" + "legend": { + "anyOf": [ + { + "$ref": "#/definitions/Legend" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." }, - { - "type": "null" - } - ], - "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." - }, - "selection": { - "$ref": "#/definitions/SelectionComposition", - "description": "A [selection name](https://vega.github.io/vega-lite/docs/selection.html), or a series of [composed selections](https://vega.github.io/vega-lite/docs/selection.html#compose)." - }, - "sort": { - "$ref": "#/definitions/Sort", - "description": "Sort order for the encoded field.\n\nFor continuous fields (quantitative or temporal), `sort` can be either `\"ascending\"` or `\"descending\"`.\n\nFor discrete fields, `sort` can be one of the following:\n- `\"ascending\"` or `\"descending\"` -- for sorting by the values' natural order in JavaScript.\n- [A string indicating an encoding channel name to sort by](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding) (e.g., `\"x\"` or `\"y\"`) with an optional minus prefix for descending sort (e.g., `\"-x\"` to sort by x-field, descending). This channel string is short-form of [a sort-by-encoding definition](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding). For example, `\"sort\": \"-x\"` is equivalent to `\"sort\": {\"encoding\": \"x\", \"order\": \"descending\"}`.\n- [A sort field definition](https://vega.github.io/vega-lite/docs/sort.html#sort-field) for sorting by another field.\n- [An array specifying the field values in preferred order](https://vega.github.io/vega-lite/docs/sort.html#sort-array). In this case, the sort order will obey the values in the array, followed by any unspecified values in their original order. For discrete time field, values in the sort array can be [date-time definition objects](types#datetime). In addition, for time units `\"month\"` and `\"day\"`, the values can be the month or day names (case insensitive) or their 3-letter initials (e.g., `\"Mon\"`, `\"Tue\"`).\n- `null` indicating no sort.\n\n__Default value:__ `\"ascending\"`\n\n__Note:__ `null` and sorting by another channel is not supported for `row` and `column`.\n\n__See also:__ [`sort`](https://vega.github.io/vega-lite/docs/sort.html) documentation." - }, - "timeUnit": { - "anyOf": [ - { - "$ref": "#/definitions/TimeUnit" + "scale": { + "anyOf": [ + { + "$ref": "#/definitions/Scale" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." }, - { - "$ref": "#/definitions/TimeUnitParams" + "selection": { + "$ref": "#/definitions/SelectionComposition", + "description": "A [selection name](https://vega.github.io/vega-lite/docs/selection.html), or a series of [composed selections](https://vega.github.io/vega-lite/docs/selection.html#compose)." + }, + "sort": { + "$ref": "#/definitions/Sort", + "description": "Sort order for the encoded field.\n\nFor continuous fields (quantitative or temporal), `sort` can be either `\"ascending\"` or `\"descending\"`.\n\nFor discrete fields, `sort` can be one of the following:\n- `\"ascending\"` or `\"descending\"` -- for sorting by the values' natural order in JavaScript.\n- [A string indicating an encoding channel name to sort by](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding) (e.g., `\"x\"` or `\"y\"`) with an optional minus prefix for descending sort (e.g., `\"-x\"` to sort by x-field, descending). This channel string is short-form of [a sort-by-encoding definition](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding). For example, `\"sort\": \"-x\"` is equivalent to `\"sort\": {\"encoding\": \"x\", \"order\": \"descending\"}`.\n- [A sort field definition](https://vega.github.io/vega-lite/docs/sort.html#sort-field) for sorting by another field.\n- [An array specifying the field values in preferred order](https://vega.github.io/vega-lite/docs/sort.html#sort-array). In this case, the sort order will obey the values in the array, followed by any unspecified values in their original order. For discrete time field, values in the sort array can be [date-time definition objects](types#datetime). In addition, for time units `\"month\"` and `\"day\"`, the values can be the month or day names (case insensitive) or their 3-letter initials (e.g., `\"Mon\"`, `\"Tue\"`).\n- `null` indicating no sort.\n\n__Default value:__ `\"ascending\"`\n\n__Note:__ `null` and sorting by another channel is not supported for `row` and `column`.\n\n__See also:__ [`sort`](https://vega.github.io/vega-lite/docs/sort.html) documentation." + }, + "timeUnit": { + "anyOf": [ + { + "$ref": "#/definitions/TimeUnit" + }, + { + "$ref": "#/definitions/TimeUnitParams" + } + ], + "description": "Time unit (e.g., `year`, `yearmonth`, `month`, `hours`) for a temporal field.\nor [a temporal field that gets casted as ordinal](https://vega.github.io/vega-lite/docs/type.html#cast).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html) documentation." + }, + "title": { + "anyOf": [ + { + "$ref": "#/definitions/Text" + }, + { + "type": "null" + } + ], + "description": "A title for the field. If `null`, the title will be removed.\n\n__Default value:__ derived from the field's name and transformation function (`aggregate`, `bin` and `timeUnit`). If the field has an aggregate function, the function is displayed as part of the title (e.g., `\"Sum of Profit\"`). If the field is binned or has a time unit applied, the applied function is shown in parentheses (e.g., `\"Profit (binned)\"`, `\"Transaction Date (year-month)\"`). Otherwise, the title is simply the field name.\n\n__Notes__:\n\n1) You can customize the default field title format by providing the [`fieldTitle`](https://vega.github.io/vega-lite/docs/config.html#top-level-config) property in the [config](https://vega.github.io/vega-lite/docs/config.html) or [`fieldTitle` function via the `compile` function's options](https://vega.github.io/vega-lite/docs/compile.html#field-title).\n\n2) If both field definition's `title` and axis, header, or legend `title` are defined, axis/header/legend title will be used." + }, + "type": { + "$ref": "#/definitions/TypeForShape", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." } + }, + "required": [ + "selection", + "type" ], - "description": "Time unit (e.g., `year`, `yearmonth`, `month`, `hours`) for a temporal field.\nor [a temporal field that gets casted as ordinal](https://vega.github.io/vega-lite/docs/type.html#cast).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html) documentation." + "type": "object" }, - "title": { - "anyOf": [ - { - "$ref": "#/definitions/Text" + { + "additionalProperties": false, + "properties": { + "datum": { + "anyOf": [ + { + "$ref": "#/definitions/Value" + }, + { + "$ref": "#/definitions/RepeatRef" + } + ], + "description": "A constant value in data domain." }, - { - "type": "null" + "legend": { + "anyOf": [ + { + "$ref": "#/definitions/Legend" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." + }, + "scale": { + "anyOf": [ + { + "$ref": "#/definitions/Scale" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." + }, + "selection": { + "$ref": "#/definitions/SelectionComposition", + "description": "A [selection name](https://vega.github.io/vega-lite/docs/selection.html), or a series of [composed selections](https://vega.github.io/vega-lite/docs/selection.html#compose)." + }, + "type": { + "$ref": "#/definitions/Type", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." } + }, + "required": [ + "selection" ], - "description": "A title for the field. If `null`, the title will be removed.\n\n__Default value:__ derived from the field's name and transformation function (`aggregate`, `bin` and `timeUnit`). If the field has an aggregate function, the function is displayed as part of the title (e.g., `\"Sum of Profit\"`). If the field is binned or has a time unit applied, the applied function is shown in parentheses (e.g., `\"Profit (binned)\"`, `\"Transaction Date (year-month)\"`). Otherwise, the title is simply the field name.\n\n__Notes__:\n\n1) You can customize the default field title format by providing the [`fieldTitle`](https://vega.github.io/vega-lite/docs/config.html#top-level-config) property in the [config](https://vega.github.io/vega-lite/docs/config.html) or [`fieldTitle` function via the `compile` function's options](https://vega.github.io/vega-lite/docs/compile.html#field-title).\n\n2) If both field definition's `title` and axis, header, or legend `title` are defined, axis/header/legend title will be used." - }, - "type": { - "$ref": "#/definitions/TypeForShape", - "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." + "type": "object" } - }, - "required": [ - "selection", - "type" - ], - "type": "object" + ] }, "ConditionalSelection": { "additionalProperties": false, @@ -5033,6 +5306,27 @@ }, "type": "object" }, + "DatumDef": { + "additionalProperties": false, + "properties": { + "datum": { + "anyOf": [ + { + "$ref": "#/definitions/Value" + }, + { + "$ref": "#/definitions/RepeatRef" + } + ], + "description": "A constant value in data domain." + }, + "type": { + "$ref": "#/definitions/Type", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." + } + }, + "type": "object" + }, "Day": { "maximum": 7, "minimum": 1, @@ -6078,6 +6372,9 @@ { "$ref": "#/definitions/ColorGradientFieldDefWithCondition" }, + { + "$ref": "#/definitions/ColorGradientDatumDefWithCondition" + }, { "$ref": "#/definitions/ColorGradientValueWithCondition" } @@ -6111,6 +6408,9 @@ { "$ref": "#/definitions/ColorGradientFieldDefWithCondition" }, + { + "$ref": "#/definitions/ColorGradientDatumDefWithCondition" + }, { "$ref": "#/definitions/ColorGradientValueWithCondition" } @@ -6122,6 +6422,9 @@ { "$ref": "#/definitions/NumericFieldDefWithCondition" }, + { + "$ref": "#/definitions/NumericDatumDefWithCondition" + }, { "$ref": "#/definitions/NumericValueWithCondition" } @@ -6148,6 +6451,9 @@ { "$ref": "#/definitions/LatLongFieldDef" }, + { + "$ref": "#/definitions/DatumDef" + }, { "$ref": "#/definitions/NumberValueDef" } @@ -6159,6 +6465,9 @@ { "$ref": "#/definitions/SecondaryFieldDef" }, + { + "$ref": "#/definitions/DatumDef" + }, { "$ref": "#/definitions/NumberValueDef" } @@ -6170,6 +6479,9 @@ { "$ref": "#/definitions/LatLongFieldDef" }, + { + "$ref": "#/definitions/DatumDef" + }, { "$ref": "#/definitions/NumberValueDef" } @@ -6181,6 +6493,9 @@ { "$ref": "#/definitions/SecondaryFieldDef" }, + { + "$ref": "#/definitions/DatumDef" + }, { "$ref": "#/definitions/NumberValueDef" } @@ -6192,6 +6507,9 @@ { "$ref": "#/definitions/NumericFieldDefWithCondition" }, + { + "$ref": "#/definitions/NumericDatumDefWithCondition" + }, { "$ref": "#/definitions/NumericValueWithCondition" } @@ -6224,6 +6542,9 @@ { "$ref": "#/definitions/ShapeFieldDefWithCondition" }, + { + "$ref": "#/definitions/StringDatumDefWithCondition" + }, { "$ref": "#/definitions/ShapeValueWithCondition" } @@ -6235,6 +6556,9 @@ { "$ref": "#/definitions/NumericFieldDefWithCondition" }, + { + "$ref": "#/definitions/NumericDatumDefWithCondition" + }, { "$ref": "#/definitions/NumericValueWithCondition" } @@ -6246,6 +6570,9 @@ { "$ref": "#/definitions/ColorGradientFieldDefWithCondition" }, + { + "$ref": "#/definitions/ColorGradientDatumDefWithCondition" + }, { "$ref": "#/definitions/ColorGradientValueWithCondition" } @@ -6257,6 +6584,9 @@ { "$ref": "#/definitions/NumericArrayFieldDefWithCondition" }, + { + "$ref": "#/definitions/NumericArrayDatumDefWithCondition" + }, { "$ref": "#/definitions/NumericArrayValueDefWithCondition" } @@ -6268,6 +6598,9 @@ { "$ref": "#/definitions/NumericFieldDefWithCondition" }, + { + "$ref": "#/definitions/NumericDatumDefWithCondition" + }, { "$ref": "#/definitions/NumericValueWithCondition" } @@ -6279,6 +6612,9 @@ { "$ref": "#/definitions/NumericFieldDefWithCondition" }, + { + "$ref": "#/definitions/NumericDatumDefWithCondition" + }, { "$ref": "#/definitions/NumericValueWithCondition" } @@ -6332,6 +6668,9 @@ { "$ref": "#/definitions/PositionFieldDef" }, + { + "$ref": "#/definitions/PositionDatumDef" + }, { "$ref": "#/definitions/XValueDef" } @@ -6343,6 +6682,9 @@ { "$ref": "#/definitions/SecondaryFieldDef" }, + { + "$ref": "#/definitions/DatumDef" + }, { "$ref": "#/definitions/XValueDef" } @@ -6376,6 +6718,9 @@ { "$ref": "#/definitions/PositionFieldDef" }, + { + "$ref": "#/definitions/PositionDatumDef" + }, { "$ref": "#/definitions/YValueDef" } @@ -6387,6 +6732,9 @@ { "$ref": "#/definitions/SecondaryFieldDef" }, + { + "$ref": "#/definitions/DatumDef" + }, { "$ref": "#/definitions/YValueDef" } @@ -6544,61 +6892,33 @@ } ] }, - "FieldDefWithCondition": { + "FieldDefWithoutScale": { + "$ref": "#/definitions/TypedFieldDef", + "description": "Field Def without scale (and without bin: \"binned\" support)." + }, + "FieldEqualPredicate": { "additionalProperties": false, - "description": "A FieldDef with Condition\n{\n condition: {value: ...},\n field: ...,\n ...\n}", "properties": { - "aggregate": { - "$ref": "#/definitions/Aggregate", - "description": "Aggregation function for the field\n(e.g., `\"mean\"`, `\"sum\"`, `\"median\"`, `\"min\"`, `\"max\"`, `\"count\"`).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html) documentation." - }, - "bin": { + "equal": { "anyOf": [ { - "type": "boolean" - }, - { - "$ref": "#/definitions/BinParams" + "type": "string" }, { - "type": "null" - } - ], - "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." - }, - "condition": { - "$ref": "#/definitions/ValueCondition<(Gradient|string|null)>", - "description": "One or more value definition(s) with [a selection or a test predicate](https://vega.github.io/vega-lite/docs/condition.html).\n\n__Note:__ A field definition's `condition` property can only contain [conditional value definitions](https://vega.github.io/vega-lite/docs/condition.html#value)\nsince Vega-Lite only allows at most one encoded field per encoding channel." - }, - "field": { - "$ref": "#/definitions/Field", - "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." - }, - "legend": { - "anyOf": [ - { - "$ref": "#/definitions/Legend" + "type": "number" }, { - "type": "null" - } - ], - "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." - }, - "scale": { - "anyOf": [ - { - "$ref": "#/definitions/Scale" + "type": "boolean" }, { - "type": "null" + "$ref": "#/definitions/DateTime" } ], - "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." + "description": "The value that the field should be equal to." }, - "sort": { - "$ref": "#/definitions/Sort", - "description": "Sort order for the encoded field.\n\nFor continuous fields (quantitative or temporal), `sort` can be either `\"ascending\"` or `\"descending\"`.\n\nFor discrete fields, `sort` can be one of the following:\n- `\"ascending\"` or `\"descending\"` -- for sorting by the values' natural order in JavaScript.\n- [A string indicating an encoding channel name to sort by](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding) (e.g., `\"x\"` or `\"y\"`) with an optional minus prefix for descending sort (e.g., `\"-x\"` to sort by x-field, descending). This channel string is short-form of [a sort-by-encoding definition](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding). For example, `\"sort\": \"-x\"` is equivalent to `\"sort\": {\"encoding\": \"x\", \"order\": \"descending\"}`.\n- [A sort field definition](https://vega.github.io/vega-lite/docs/sort.html#sort-field) for sorting by another field.\n- [An array specifying the field values in preferred order](https://vega.github.io/vega-lite/docs/sort.html#sort-array). In this case, the sort order will obey the values in the array, followed by any unspecified values in their original order. For discrete time field, values in the sort array can be [date-time definition objects](types#datetime). In addition, for time units `\"month\"` and `\"day\"`, the values can be the month or day names (case insensitive) or their 3-letter initials (e.g., `\"Mon\"`, `\"Tue\"`).\n- `null` indicating no sort.\n\n__Default value:__ `\"ascending\"`\n\n__Note:__ `null` and sorting by another channel is not supported for `row` and `column`.\n\n__See also:__ [`sort`](https://vega.github.io/vega-lite/docs/sort.html) documentation." + "field": { + "$ref": "#/definitions/FieldName", + "description": "Field to be tested." }, "timeUnit": { "anyOf": [ @@ -6609,84 +6929,74 @@ "$ref": "#/definitions/TimeUnitParams" } ], - "description": "Time unit (e.g., `year`, `yearmonth`, `month`, `hours`) for a temporal field.\nor [a temporal field that gets casted as ordinal](https://vega.github.io/vega-lite/docs/type.html#cast).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html) documentation." - }, - "title": { - "anyOf": [ - { - "$ref": "#/definitions/Text" - }, - { - "type": "null" - } - ], - "description": "A title for the field. If `null`, the title will be removed.\n\n__Default value:__ derived from the field's name and transformation function (`aggregate`, `bin` and `timeUnit`). If the field has an aggregate function, the function is displayed as part of the title (e.g., `\"Sum of Profit\"`). If the field is binned or has a time unit applied, the applied function is shown in parentheses (e.g., `\"Profit (binned)\"`, `\"Transaction Date (year-month)\"`). Otherwise, the title is simply the field name.\n\n__Notes__:\n\n1) You can customize the default field title format by providing the [`fieldTitle`](https://vega.github.io/vega-lite/docs/config.html#top-level-config) property in the [config](https://vega.github.io/vega-lite/docs/config.html) or [`fieldTitle` function via the `compile` function's options](https://vega.github.io/vega-lite/docs/compile.html#field-title).\n\n2) If both field definition's `title` and axis, header, or legend `title` are defined, axis/header/legend title will be used." - }, - "type": { - "$ref": "#/definitions/StandardType", - "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." + "description": "Time unit for the field to be tested." } }, "required": [ - "type" + "equal", + "field" ], "type": "object" }, - "FieldDefWithCondition": { + "FieldGTEPredicate": { "additionalProperties": false, - "description": "A FieldDef with Condition\n{\n condition: {value: ...},\n field: ...,\n ...\n}", "properties": { - "aggregate": { - "$ref": "#/definitions/Aggregate", - "description": "Aggregation function for the field\n(e.g., `\"mean\"`, `\"sum\"`, `\"median\"`, `\"min\"`, `\"max\"`, `\"count\"`).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html) documentation." + "field": { + "$ref": "#/definitions/FieldName", + "description": "Field to be tested." }, - "bin": { + "gte": { "anyOf": [ { - "type": "boolean" + "type": "string" }, { - "$ref": "#/definitions/BinParams" + "type": "number" }, { - "type": "null" + "$ref": "#/definitions/DateTime" } ], - "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." - }, - "condition": { - "$ref": "#/definitions/ValueCondition", - "description": "One or more value definition(s) with [a selection or a test predicate](https://vega.github.io/vega-lite/docs/condition.html).\n\n__Note:__ A field definition's `condition` property can only contain [conditional value definitions](https://vega.github.io/vega-lite/docs/condition.html#value)\nsince Vega-Lite only allows at most one encoded field per encoding channel." - }, - "field": { - "$ref": "#/definitions/Field", - "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." + "description": "The value that the field should be greater than or equals to." }, - "legend": { + "timeUnit": { "anyOf": [ { - "$ref": "#/definitions/Legend" + "$ref": "#/definitions/TimeUnit" }, { - "type": "null" + "$ref": "#/definitions/TimeUnitParams" } ], - "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." + "description": "Time unit for the field to be tested." + } + }, + "required": [ + "field", + "gte" + ], + "type": "object" + }, + "FieldGTPredicate": { + "additionalProperties": false, + "properties": { + "field": { + "$ref": "#/definitions/FieldName", + "description": "Field to be tested." }, - "scale": { + "gt": { "anyOf": [ { - "$ref": "#/definitions/Scale" + "type": "string" }, { - "type": "null" + "type": "number" + }, + { + "$ref": "#/definitions/DateTime" } ], - "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." - }, - "sort": { - "$ref": "#/definitions/Sort", - "description": "Sort order for the encoded field.\n\nFor continuous fields (quantitative or temporal), `sort` can be either `\"ascending\"` or `\"descending\"`.\n\nFor discrete fields, `sort` can be one of the following:\n- `\"ascending\"` or `\"descending\"` -- for sorting by the values' natural order in JavaScript.\n- [A string indicating an encoding channel name to sort by](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding) (e.g., `\"x\"` or `\"y\"`) with an optional minus prefix for descending sort (e.g., `\"-x\"` to sort by x-field, descending). This channel string is short-form of [a sort-by-encoding definition](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding). For example, `\"sort\": \"-x\"` is equivalent to `\"sort\": {\"encoding\": \"x\", \"order\": \"descending\"}`.\n- [A sort field definition](https://vega.github.io/vega-lite/docs/sort.html#sort-field) for sorting by another field.\n- [An array specifying the field values in preferred order](https://vega.github.io/vega-lite/docs/sort.html#sort-array). In this case, the sort order will obey the values in the array, followed by any unspecified values in their original order. For discrete time field, values in the sort array can be [date-time definition objects](types#datetime). In addition, for time units `\"month\"` and `\"day\"`, the values can be the month or day names (case insensitive) or their 3-letter initials (e.g., `\"Mon\"`, `\"Tue\"`).\n- `null` indicating no sort.\n\n__Default value:__ `\"ascending\"`\n\n__Note:__ `null` and sorting by another channel is not supported for `row` and `column`.\n\n__See also:__ [`sort`](https://vega.github.io/vega-lite/docs/sort.html) documentation." + "description": "The value that the field should be greater than." }, "timeUnit": { "anyOf": [ @@ -6697,84 +7007,74 @@ "$ref": "#/definitions/TimeUnitParams" } ], - "description": "Time unit (e.g., `year`, `yearmonth`, `month`, `hours`) for a temporal field.\nor [a temporal field that gets casted as ordinal](https://vega.github.io/vega-lite/docs/type.html#cast).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html) documentation." - }, - "title": { - "anyOf": [ - { - "$ref": "#/definitions/Text" - }, - { - "type": "null" - } - ], - "description": "A title for the field. If `null`, the title will be removed.\n\n__Default value:__ derived from the field's name and transformation function (`aggregate`, `bin` and `timeUnit`). If the field has an aggregate function, the function is displayed as part of the title (e.g., `\"Sum of Profit\"`). If the field is binned or has a time unit applied, the applied function is shown in parentheses (e.g., `\"Profit (binned)\"`, `\"Transaction Date (year-month)\"`). Otherwise, the title is simply the field name.\n\n__Notes__:\n\n1) You can customize the default field title format by providing the [`fieldTitle`](https://vega.github.io/vega-lite/docs/config.html#top-level-config) property in the [config](https://vega.github.io/vega-lite/docs/config.html) or [`fieldTitle` function via the `compile` function's options](https://vega.github.io/vega-lite/docs/compile.html#field-title).\n\n2) If both field definition's `title` and axis, header, or legend `title` are defined, axis/header/legend title will be used." - }, - "type": { - "$ref": "#/definitions/StandardType", - "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." + "description": "Time unit for the field to be tested." } }, "required": [ - "type" + "field", + "gt" ], "type": "object" }, - "FieldDefWithCondition": { + "FieldLTEPredicate": { "additionalProperties": false, - "description": "A FieldDef with Condition\n{\n condition: {value: ...},\n field: ...,\n ...\n}", "properties": { - "aggregate": { - "$ref": "#/definitions/Aggregate", - "description": "Aggregation function for the field\n(e.g., `\"mean\"`, `\"sum\"`, `\"median\"`, `\"min\"`, `\"max\"`, `\"count\"`).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html) documentation." + "field": { + "$ref": "#/definitions/FieldName", + "description": "Field to be tested." }, - "bin": { + "lte": { "anyOf": [ { - "type": "boolean" + "type": "string" }, { - "$ref": "#/definitions/BinParams" + "type": "number" }, { - "type": "null" + "$ref": "#/definitions/DateTime" } ], - "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." - }, - "condition": { - "$ref": "#/definitions/ValueCondition", - "description": "One or more value definition(s) with [a selection or a test predicate](https://vega.github.io/vega-lite/docs/condition.html).\n\n__Note:__ A field definition's `condition` property can only contain [conditional value definitions](https://vega.github.io/vega-lite/docs/condition.html#value)\nsince Vega-Lite only allows at most one encoded field per encoding channel." - }, - "field": { - "$ref": "#/definitions/Field", - "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." + "description": "The value that the field should be less than or equals to." }, - "legend": { + "timeUnit": { "anyOf": [ { - "$ref": "#/definitions/Legend" + "$ref": "#/definitions/TimeUnit" }, { - "type": "null" + "$ref": "#/definitions/TimeUnitParams" } ], - "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." + "description": "Time unit for the field to be tested." + } + }, + "required": [ + "field", + "lte" + ], + "type": "object" + }, + "FieldLTPredicate": { + "additionalProperties": false, + "properties": { + "field": { + "$ref": "#/definitions/FieldName", + "description": "Field to be tested." }, - "scale": { + "lt": { "anyOf": [ { - "$ref": "#/definitions/Scale" + "type": "string" }, { - "type": "null" + "type": "number" + }, + { + "$ref": "#/definitions/DateTime" } ], - "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." - }, - "sort": { - "$ref": "#/definitions/Sort", - "description": "Sort order for the encoded field.\n\nFor continuous fields (quantitative or temporal), `sort` can be either `\"ascending\"` or `\"descending\"`.\n\nFor discrete fields, `sort` can be one of the following:\n- `\"ascending\"` or `\"descending\"` -- for sorting by the values' natural order in JavaScript.\n- [A string indicating an encoding channel name to sort by](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding) (e.g., `\"x\"` or `\"y\"`) with an optional minus prefix for descending sort (e.g., `\"-x\"` to sort by x-field, descending). This channel string is short-form of [a sort-by-encoding definition](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding). For example, `\"sort\": \"-x\"` is equivalent to `\"sort\": {\"encoding\": \"x\", \"order\": \"descending\"}`.\n- [A sort field definition](https://vega.github.io/vega-lite/docs/sort.html#sort-field) for sorting by another field.\n- [An array specifying the field values in preferred order](https://vega.github.io/vega-lite/docs/sort.html#sort-array). In this case, the sort order will obey the values in the array, followed by any unspecified values in their original order. For discrete time field, values in the sort array can be [date-time definition objects](types#datetime). In addition, for time units `\"month\"` and `\"day\"`, the values can be the month or day names (case insensitive) or their 3-letter initials (e.g., `\"Mon\"`, `\"Tue\"`).\n- `null` indicating no sort.\n\n__Default value:__ `\"ascending\"`\n\n__Note:__ `null` and sorting by another channel is not supported for `row` and `column`.\n\n__See also:__ [`sort`](https://vega.github.io/vega-lite/docs/sort.html) documentation." + "description": "The value that the field should be less than." }, "timeUnit": { "anyOf": [ @@ -6785,30 +7085,177 @@ "$ref": "#/definitions/TimeUnitParams" } ], - "description": "Time unit (e.g., `year`, `yearmonth`, `month`, `hours`) for a temporal field.\nor [a temporal field that gets casted as ordinal](https://vega.github.io/vega-lite/docs/type.html#cast).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html) documentation." - }, - "title": { + "description": "Time unit for the field to be tested." + } + }, + "required": [ + "field", + "lt" + ], + "type": "object" + }, + "FieldName": { + "type": "string" + }, + "FieldOneOfPredicate": { + "additionalProperties": false, + "properties": { + "field": { + "$ref": "#/definitions/FieldName", + "description": "Field to be tested." + }, + "oneOf": { "anyOf": [ { - "$ref": "#/definitions/Text" + "items": { + "type": "string" + }, + "type": "array" }, { - "type": "null" + "items": { + "type": "number" + }, + "type": "array" + }, + { + "items": { + "type": "boolean" + }, + "type": "array" + }, + { + "items": { + "$ref": "#/definitions/DateTime" + }, + "type": "array" } ], - "description": "A title for the field. If `null`, the title will be removed.\n\n__Default value:__ derived from the field's name and transformation function (`aggregate`, `bin` and `timeUnit`). If the field has an aggregate function, the function is displayed as part of the title (e.g., `\"Sum of Profit\"`). If the field is binned or has a time unit applied, the applied function is shown in parentheses (e.g., `\"Profit (binned)\"`, `\"Transaction Date (year-month)\"`). Otherwise, the title is simply the field name.\n\n__Notes__:\n\n1) You can customize the default field title format by providing the [`fieldTitle`](https://vega.github.io/vega-lite/docs/config.html#top-level-config) property in the [config](https://vega.github.io/vega-lite/docs/config.html) or [`fieldTitle` function via the `compile` function's options](https://vega.github.io/vega-lite/docs/compile.html#field-title).\n\n2) If both field definition's `title` and axis, header, or legend `title` are defined, axis/header/legend title will be used." + "description": "A set of values that the `field`'s value should be a member of,\nfor a data item included in the filtered data." }, - "type": { - "$ref": "#/definitions/StandardType", - "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." + "timeUnit": { + "anyOf": [ + { + "$ref": "#/definitions/TimeUnit" + }, + { + "$ref": "#/definitions/TimeUnitParams" + } + ], + "description": "Time unit for the field to be tested." } }, "required": [ - "type" + "field", + "oneOf" ], "type": "object" }, - "FieldDefWithCondition,(string|null)>": { + "FieldOrDatumDefWithCondition": { + "additionalProperties": false, + "description": "A FieldDef with Condition\n{\n condition: {value: ...},\n field: ...,\n ...\n}", + "properties": { + "condition": { + "$ref": "#/definitions/ValueCondition<(Gradient|string|null)>", + "description": "One or more value definition(s) with [a selection or a test predicate](https://vega.github.io/vega-lite/docs/condition.html).\n\n__Note:__ A field definition's `condition` property can only contain [conditional value definitions](https://vega.github.io/vega-lite/docs/condition.html#value)\nsince Vega-Lite only allows at most one encoded field per encoding channel." + }, + "datum": { + "anyOf": [ + { + "$ref": "#/definitions/Value" + }, + { + "$ref": "#/definitions/RepeatRef" + } + ], + "description": "A constant value in data domain." + }, + "type": { + "$ref": "#/definitions/Type", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." + } + }, + "type": "object" + }, + "FieldOrDatumDefWithCondition": { + "additionalProperties": false, + "description": "A FieldDef with Condition\n{\n condition: {value: ...},\n field: ...,\n ...\n}", + "properties": { + "condition": { + "$ref": "#/definitions/ValueCondition", + "description": "One or more value definition(s) with [a selection or a test predicate](https://vega.github.io/vega-lite/docs/condition.html).\n\n__Note:__ A field definition's `condition` property can only contain [conditional value definitions](https://vega.github.io/vega-lite/docs/condition.html#value)\nsince Vega-Lite only allows at most one encoded field per encoding channel." + }, + "datum": { + "anyOf": [ + { + "$ref": "#/definitions/Value" + }, + { + "$ref": "#/definitions/RepeatRef" + } + ], + "description": "A constant value in data domain." + }, + "type": { + "$ref": "#/definitions/Type", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." + } + }, + "type": "object" + }, + "FieldOrDatumDefWithCondition": { + "additionalProperties": false, + "description": "A FieldDef with Condition\n{\n condition: {value: ...},\n field: ...,\n ...\n}", + "properties": { + "condition": { + "$ref": "#/definitions/ValueCondition", + "description": "One or more value definition(s) with [a selection or a test predicate](https://vega.github.io/vega-lite/docs/condition.html).\n\n__Note:__ A field definition's `condition` property can only contain [conditional value definitions](https://vega.github.io/vega-lite/docs/condition.html#value)\nsince Vega-Lite only allows at most one encoded field per encoding channel." + }, + "datum": { + "anyOf": [ + { + "$ref": "#/definitions/Value" + }, + { + "$ref": "#/definitions/RepeatRef" + } + ], + "description": "A constant value in data domain." + }, + "type": { + "$ref": "#/definitions/Type", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." + } + }, + "type": "object" + }, + "FieldOrDatumDefWithCondition": { + "additionalProperties": false, + "description": "A FieldDef with Condition\n{\n condition: {value: ...},\n field: ...,\n ...\n}", + "properties": { + "condition": { + "$ref": "#/definitions/ValueCondition", + "description": "One or more value definition(s) with [a selection or a test predicate](https://vega.github.io/vega-lite/docs/condition.html).\n\n__Note:__ A field definition's `condition` property can only contain [conditional value definitions](https://vega.github.io/vega-lite/docs/condition.html#value)\nsince Vega-Lite only allows at most one encoded field per encoding channel." + }, + "datum": { + "anyOf": [ + { + "$ref": "#/definitions/Value" + }, + { + "$ref": "#/definitions/RepeatRef" + } + ], + "description": "A constant value in data domain." + }, + "type": { + "$ref": "#/definitions/Type", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." + } + }, + "type": "object" + }, + "FieldOrDatumDefWithCondition": { "additionalProperties": false, "description": "A FieldDef with Condition\n{\n condition: {value: ...},\n field: ...,\n ...\n}", "properties": { @@ -6831,7 +7278,7 @@ "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." }, "condition": { - "$ref": "#/definitions/ValueCondition<(string|null)>", + "$ref": "#/definitions/ValueCondition<(Gradient|string|null)>", "description": "One or more value definition(s) with [a selection or a test predicate](https://vega.github.io/vega-lite/docs/condition.html).\n\n__Note:__ A field definition's `condition` property can only contain [conditional value definitions](https://vega.github.io/vega-lite/docs/condition.html#value)\nsince Vega-Lite only allows at most one encoded field per encoding channel." }, "field": { @@ -6887,7 +7334,7 @@ "description": "A title for the field. If `null`, the title will be removed.\n\n__Default value:__ derived from the field's name and transformation function (`aggregate`, `bin` and `timeUnit`). If the field has an aggregate function, the function is displayed as part of the title (e.g., `\"Sum of Profit\"`). If the field is binned or has a time unit applied, the applied function is shown in parentheses (e.g., `\"Profit (binned)\"`, `\"Transaction Date (year-month)\"`). Otherwise, the title is simply the field name.\n\n__Notes__:\n\n1) You can customize the default field title format by providing the [`fieldTitle`](https://vega.github.io/vega-lite/docs/config.html#top-level-config) property in the [config](https://vega.github.io/vega-lite/docs/config.html) or [`fieldTitle` function via the `compile` function's options](https://vega.github.io/vega-lite/docs/compile.html#field-title).\n\n2) If both field definition's `title` and axis, header, or legend `title` are defined, axis/header/legend title will be used." }, "type": { - "$ref": "#/definitions/TypeForShape", + "$ref": "#/definitions/StandardType", "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." } }, @@ -6896,7 +7343,7 @@ ], "type": "object" }, - "FieldDefWithCondition": { + "FieldOrDatumDefWithCondition": { "additionalProperties": false, "description": "A FieldDef with Condition\n{\n condition: {value: ...},\n field: ...,\n ...\n}", "properties": { @@ -6912,12 +7359,6 @@ { "$ref": "#/definitions/BinParams" }, - { - "enum": [ - "binned" - ], - "type": "string" - }, { "type": "null" } @@ -6925,31 +7366,38 @@ "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." }, "condition": { - "$ref": "#/definitions/ValueCondition", + "$ref": "#/definitions/ValueCondition", "description": "One or more value definition(s) with [a selection or a test predicate](https://vega.github.io/vega-lite/docs/condition.html).\n\n__Note:__ A field definition's `condition` property can only contain [conditional value definitions](https://vega.github.io/vega-lite/docs/condition.html#value)\nsince Vega-Lite only allows at most one encoded field per encoding channel." }, "field": { "$ref": "#/definitions/Field", "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." }, - "format": { + "legend": { "anyOf": [ { - "type": "string" + "$ref": "#/definitions/Legend" }, { - "type": "object" + "type": "null" } ], - "description": "When used with the default `\"number\"` and `\"time\"` format type, the text formatting pattern for labels of guides (axes, legends, headers) and text marks.\n\n- If the format type is `\"number\"` (e.g., for quantitative fields), this is D3's [number format pattern](https://github.com/d3/d3-format#locale_format).\n- If the format type is `\"time\"` (e.g., for temporal fields), this is D3's [time format pattern](https://github.com/d3/d3-time-format#locale_format).\n\nSee the [format documentation](https://vega.github.io/vega-lite/docs/format.html) for more examples.\n\nWhen used with a [custom `\"formatType\"`](https://vega.github.io/vega-lite/usage/compile.html#format-type) that takes `datum.value` and format parameter as input), this property represents the format parameter.\n\n__Default value:__ Derived from [numberFormat](https://vega.github.io/vega-lite/docs/config.html#format) config for number format and from [timeFormat](https://vega.github.io/vega-lite/docs/config.html#format) config for time format." + "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." }, - "formatType": { - "description": "The format type for labels (`\"number\"` or `\"time\"` or a [registered custom format type](https://vega.github.io/vega-lite/usage/compile.html#format-type)).\n\n\n__Default value:__\n- `\"time\"` for temporal fields and ordinal and nomimal fields with `timeUnit`.\n- `\"number\"` for quantitative fields as well as ordinal and nomimal fields without `timeUnit`.", - "type": "string" + "scale": { + "anyOf": [ + { + "$ref": "#/definitions/Scale" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." }, - "labelExpr": { - "description": "[Vega expression](https://vega.github.io/vega/docs/expressions/) for customizing labels text.\n\n__Note:__ The label text and value can be assessed via the `label` and `value` properties of the axis's backing `datum` object.", - "type": "string" + "sort": { + "$ref": "#/definitions/Sort", + "description": "Sort order for the encoded field.\n\nFor continuous fields (quantitative or temporal), `sort` can be either `\"ascending\"` or `\"descending\"`.\n\nFor discrete fields, `sort` can be one of the following:\n- `\"ascending\"` or `\"descending\"` -- for sorting by the values' natural order in JavaScript.\n- [A string indicating an encoding channel name to sort by](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding) (e.g., `\"x\"` or `\"y\"`) with an optional minus prefix for descending sort (e.g., `\"-x\"` to sort by x-field, descending). This channel string is short-form of [a sort-by-encoding definition](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding). For example, `\"sort\": \"-x\"` is equivalent to `\"sort\": {\"encoding\": \"x\", \"order\": \"descending\"}`.\n- [A sort field definition](https://vega.github.io/vega-lite/docs/sort.html#sort-field) for sorting by another field.\n- [An array specifying the field values in preferred order](https://vega.github.io/vega-lite/docs/sort.html#sort-array). In this case, the sort order will obey the values in the array, followed by any unspecified values in their original order. For discrete time field, values in the sort array can be [date-time definition objects](types#datetime). In addition, for time units `\"month\"` and `\"day\"`, the values can be the month or day names (case insensitive) or their 3-letter initials (e.g., `\"Mon\"`, `\"Tue\"`).\n- `null` indicating no sort.\n\n__Default value:__ `\"ascending\"`\n\n__Note:__ `null` and sorting by another channel is not supported for `row` and `column`.\n\n__See also:__ [`sort`](https://vega.github.io/vega-lite/docs/sort.html) documentation." }, "timeUnit": { "anyOf": [ @@ -6983,7 +7431,7 @@ ], "type": "object" }, - "FieldDefWithCondition": { + "FieldOrDatumDefWithCondition": { "additionalProperties": false, "description": "A FieldDef with Condition\n{\n condition: {value: ...},\n field: ...,\n ...\n}", "properties": { @@ -6999,12 +7447,6 @@ { "$ref": "#/definitions/BinParams" }, - { - "enum": [ - "binned" - ], - "type": "string" - }, { "type": "null" } @@ -7012,31 +7454,38 @@ "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." }, "condition": { - "$ref": "#/definitions/ValueCondition", + "$ref": "#/definitions/ValueCondition", "description": "One or more value definition(s) with [a selection or a test predicate](https://vega.github.io/vega-lite/docs/condition.html).\n\n__Note:__ A field definition's `condition` property can only contain [conditional value definitions](https://vega.github.io/vega-lite/docs/condition.html#value)\nsince Vega-Lite only allows at most one encoded field per encoding channel." }, "field": { "$ref": "#/definitions/Field", "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." }, - "format": { + "legend": { "anyOf": [ { - "type": "string" + "$ref": "#/definitions/Legend" }, { - "type": "object" + "type": "null" } ], - "description": "When used with the default `\"number\"` and `\"time\"` format type, the text formatting pattern for labels of guides (axes, legends, headers) and text marks.\n\n- If the format type is `\"number\"` (e.g., for quantitative fields), this is D3's [number format pattern](https://github.com/d3/d3-format#locale_format).\n- If the format type is `\"time\"` (e.g., for temporal fields), this is D3's [time format pattern](https://github.com/d3/d3-time-format#locale_format).\n\nSee the [format documentation](https://vega.github.io/vega-lite/docs/format.html) for more examples.\n\nWhen used with a [custom `\"formatType\"`](https://vega.github.io/vega-lite/usage/compile.html#format-type) that takes `datum.value` and format parameter as input), this property represents the format parameter.\n\n__Default value:__ Derived from [numberFormat](https://vega.github.io/vega-lite/docs/config.html#format) config for number format and from [timeFormat](https://vega.github.io/vega-lite/docs/config.html#format) config for time format." + "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." }, - "formatType": { - "description": "The format type for labels (`\"number\"` or `\"time\"` or a [registered custom format type](https://vega.github.io/vega-lite/usage/compile.html#format-type)).\n\n\n__Default value:__\n- `\"time\"` for temporal fields and ordinal and nomimal fields with `timeUnit`.\n- `\"number\"` for quantitative fields as well as ordinal and nomimal fields without `timeUnit`.", - "type": "string" + "scale": { + "anyOf": [ + { + "$ref": "#/definitions/Scale" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." }, - "labelExpr": { - "description": "[Vega expression](https://vega.github.io/vega/docs/expressions/) for customizing labels text.\n\n__Note:__ The label text and value can be assessed via the `label` and `value` properties of the axis's backing `datum` object.", - "type": "string" + "sort": { + "$ref": "#/definitions/Sort", + "description": "Sort order for the encoded field.\n\nFor continuous fields (quantitative or temporal), `sort` can be either `\"ascending\"` or `\"descending\"`.\n\nFor discrete fields, `sort` can be one of the following:\n- `\"ascending\"` or `\"descending\"` -- for sorting by the values' natural order in JavaScript.\n- [A string indicating an encoding channel name to sort by](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding) (e.g., `\"x\"` or `\"y\"`) with an optional minus prefix for descending sort (e.g., `\"-x\"` to sort by x-field, descending). This channel string is short-form of [a sort-by-encoding definition](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding). For example, `\"sort\": \"-x\"` is equivalent to `\"sort\": {\"encoding\": \"x\", \"order\": \"descending\"}`.\n- [A sort field definition](https://vega.github.io/vega-lite/docs/sort.html#sort-field) for sorting by another field.\n- [An array specifying the field values in preferred order](https://vega.github.io/vega-lite/docs/sort.html#sort-array). In this case, the sort order will obey the values in the array, followed by any unspecified values in their original order. For discrete time field, values in the sort array can be [date-time definition objects](types#datetime). In addition, for time units `\"month\"` and `\"day\"`, the values can be the month or day names (case insensitive) or their 3-letter initials (e.g., `\"Mon\"`, `\"Tue\"`).\n- `null` indicating no sort.\n\n__Default value:__ `\"ascending\"`\n\n__Note:__ `null` and sorting by another channel is not supported for `row` and `column`.\n\n__See also:__ [`sort`](https://vega.github.io/vega-lite/docs/sort.html) documentation." }, "timeUnit": { "anyOf": [ @@ -7070,189 +7519,148 @@ ], "type": "object" }, - "FieldDefWithoutScale": { - "$ref": "#/definitions/TypedFieldDef", - "description": "Field Def without scale (and without bin: \"binned\" support)." - }, - "FieldEqualPredicate": { + "FieldOrDatumDefWithCondition,(string|null)>": { "additionalProperties": false, + "description": "A FieldDef with Condition\n{\n condition: {value: ...},\n field: ...,\n ...\n}", "properties": { - "equal": { + "aggregate": { + "$ref": "#/definitions/Aggregate", + "description": "Aggregation function for the field\n(e.g., `\"mean\"`, `\"sum\"`, `\"median\"`, `\"min\"`, `\"max\"`, `\"count\"`).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html) documentation." + }, + "bin": { "anyOf": [ { - "type": "string" - }, - { - "type": "number" + "type": "boolean" }, { - "type": "boolean" + "$ref": "#/definitions/BinParams" }, { - "$ref": "#/definitions/DateTime" + "type": "null" } ], - "description": "The value that the field should be equal to." + "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." }, - "field": { - "$ref": "#/definitions/FieldName", - "description": "Field to be tested." + "condition": { + "$ref": "#/definitions/ValueCondition<(string|null)>", + "description": "One or more value definition(s) with [a selection or a test predicate](https://vega.github.io/vega-lite/docs/condition.html).\n\n__Note:__ A field definition's `condition` property can only contain [conditional value definitions](https://vega.github.io/vega-lite/docs/condition.html#value)\nsince Vega-Lite only allows at most one encoded field per encoding channel." }, - "timeUnit": { - "anyOf": [ - { - "$ref": "#/definitions/TimeUnit" - }, - { - "$ref": "#/definitions/TimeUnitParams" - } - ], - "description": "Time unit for the field to be tested." - } - }, - "required": [ - "equal", - "field" - ], - "type": "object" - }, - "FieldGTEPredicate": { - "additionalProperties": false, - "properties": { "field": { - "$ref": "#/definitions/FieldName", - "description": "Field to be tested." + "$ref": "#/definitions/Field", + "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." }, - "gte": { + "legend": { "anyOf": [ { - "type": "string" - }, - { - "type": "number" + "$ref": "#/definitions/Legend" }, { - "$ref": "#/definitions/DateTime" + "type": "null" } ], - "description": "The value that the field should be greater than or equals to." + "description": "An object defining properties of the legend.\nIf `null`, the legend for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [legend properties](https://vega.github.io/vega-lite/docs/legend.html) are applied.\n\n__See also:__ [`legend`](https://vega.github.io/vega-lite/docs/legend.html) documentation." }, - "timeUnit": { + "scale": { "anyOf": [ { - "$ref": "#/definitions/TimeUnit" + "$ref": "#/definitions/Scale" }, { - "$ref": "#/definitions/TimeUnitParams" + "type": "null" } ], - "description": "Time unit for the field to be tested." - } - }, - "required": [ - "field", - "gte" - ], - "type": "object" - }, - "FieldGTPredicate": { - "additionalProperties": false, - "properties": { - "field": { - "$ref": "#/definitions/FieldName", - "description": "Field to be tested." + "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." }, - "gt": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "$ref": "#/definitions/DateTime" - } - ], - "description": "The value that the field should be greater than." + "sort": { + "$ref": "#/definitions/Sort", + "description": "Sort order for the encoded field.\n\nFor continuous fields (quantitative or temporal), `sort` can be either `\"ascending\"` or `\"descending\"`.\n\nFor discrete fields, `sort` can be one of the following:\n- `\"ascending\"` or `\"descending\"` -- for sorting by the values' natural order in JavaScript.\n- [A string indicating an encoding channel name to sort by](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding) (e.g., `\"x\"` or `\"y\"`) with an optional minus prefix for descending sort (e.g., `\"-x\"` to sort by x-field, descending). This channel string is short-form of [a sort-by-encoding definition](https://vega.github.io/vega-lite/docs/sort.html#sort-by-encoding). For example, `\"sort\": \"-x\"` is equivalent to `\"sort\": {\"encoding\": \"x\", \"order\": \"descending\"}`.\n- [A sort field definition](https://vega.github.io/vega-lite/docs/sort.html#sort-field) for sorting by another field.\n- [An array specifying the field values in preferred order](https://vega.github.io/vega-lite/docs/sort.html#sort-array). In this case, the sort order will obey the values in the array, followed by any unspecified values in their original order. For discrete time field, values in the sort array can be [date-time definition objects](types#datetime). In addition, for time units `\"month\"` and `\"day\"`, the values can be the month or day names (case insensitive) or their 3-letter initials (e.g., `\"Mon\"`, `\"Tue\"`).\n- `null` indicating no sort.\n\n__Default value:__ `\"ascending\"`\n\n__Note:__ `null` and sorting by another channel is not supported for `row` and `column`.\n\n__See also:__ [`sort`](https://vega.github.io/vega-lite/docs/sort.html) documentation." }, "timeUnit": { "anyOf": [ { - "$ref": "#/definitions/TimeUnit" - }, - { - "$ref": "#/definitions/TimeUnitParams" - } - ], - "description": "Time unit for the field to be tested." - } - }, - "required": [ - "field", - "gt" - ], - "type": "object" - }, - "FieldLTEPredicate": { - "additionalProperties": false, - "properties": { - "field": { - "$ref": "#/definitions/FieldName", - "description": "Field to be tested." - }, - "lte": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" + "$ref": "#/definitions/TimeUnit" }, { - "$ref": "#/definitions/DateTime" + "$ref": "#/definitions/TimeUnitParams" } ], - "description": "The value that the field should be less than or equals to." + "description": "Time unit (e.g., `year`, `yearmonth`, `month`, `hours`) for a temporal field.\nor [a temporal field that gets casted as ordinal](https://vega.github.io/vega-lite/docs/type.html#cast).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html) documentation." }, - "timeUnit": { + "title": { "anyOf": [ { - "$ref": "#/definitions/TimeUnit" + "$ref": "#/definitions/Text" }, { - "$ref": "#/definitions/TimeUnitParams" + "type": "null" } ], - "description": "Time unit for the field to be tested." + "description": "A title for the field. If `null`, the title will be removed.\n\n__Default value:__ derived from the field's name and transformation function (`aggregate`, `bin` and `timeUnit`). If the field has an aggregate function, the function is displayed as part of the title (e.g., `\"Sum of Profit\"`). If the field is binned or has a time unit applied, the applied function is shown in parentheses (e.g., `\"Profit (binned)\"`, `\"Transaction Date (year-month)\"`). Otherwise, the title is simply the field name.\n\n__Notes__:\n\n1) You can customize the default field title format by providing the [`fieldTitle`](https://vega.github.io/vega-lite/docs/config.html#top-level-config) property in the [config](https://vega.github.io/vega-lite/docs/config.html) or [`fieldTitle` function via the `compile` function's options](https://vega.github.io/vega-lite/docs/compile.html#field-title).\n\n2) If both field definition's `title` and axis, header, or legend `title` are defined, axis/header/legend title will be used." + }, + "type": { + "$ref": "#/definitions/TypeForShape", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." } }, "required": [ - "field", - "lte" + "type" ], "type": "object" }, - "FieldLTPredicate": { + "FieldOrDatumDefWithCondition": { "additionalProperties": false, + "description": "A FieldDef with Condition\n{\n condition: {value: ...},\n field: ...,\n ...\n}", "properties": { - "field": { - "$ref": "#/definitions/FieldName", - "description": "Field to be tested." + "aggregate": { + "$ref": "#/definitions/Aggregate", + "description": "Aggregation function for the field\n(e.g., `\"mean\"`, `\"sum\"`, `\"median\"`, `\"min\"`, `\"max\"`, `\"count\"`).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html) documentation." }, - "lt": { + "bin": { "anyOf": [ { + "type": "boolean" + }, + { + "$ref": "#/definitions/BinParams" + }, + { + "enum": [ + "binned" + ], "type": "string" }, { - "type": "number" + "type": "null" + } + ], + "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." + }, + "condition": { + "$ref": "#/definitions/ValueCondition", + "description": "One or more value definition(s) with [a selection or a test predicate](https://vega.github.io/vega-lite/docs/condition.html).\n\n__Note:__ A field definition's `condition` property can only contain [conditional value definitions](https://vega.github.io/vega-lite/docs/condition.html#value)\nsince Vega-Lite only allows at most one encoded field per encoding channel." + }, + "field": { + "$ref": "#/definitions/Field", + "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." + }, + "format": { + "anyOf": [ + { + "type": "string" }, { - "$ref": "#/definitions/DateTime" + "type": "object" } ], - "description": "The value that the field should be less than." + "description": "When used with the default `\"number\"` and `\"time\"` format type, the text formatting pattern for labels of guides (axes, legends, headers) and text marks.\n\n- If the format type is `\"number\"` (e.g., for quantitative fields), this is D3's [number format pattern](https://github.com/d3/d3-format#locale_format).\n- If the format type is `\"time\"` (e.g., for temporal fields), this is D3's [time format pattern](https://github.com/d3/d3-time-format#locale_format).\n\nSee the [format documentation](https://vega.github.io/vega-lite/docs/format.html) for more examples.\n\nWhen used with a [custom `\"formatType\"`](https://vega.github.io/vega-lite/usage/compile.html#format-type) that takes `datum.value` and format parameter as input), this property represents the format parameter.\n\n__Default value:__ Derived from [numberFormat](https://vega.github.io/vega-lite/docs/config.html#format) config for number format and from [timeFormat](https://vega.github.io/vega-lite/docs/config.html#format) config for time format." + }, + "formatType": { + "description": "The format type for labels (`\"number\"` or `\"time\"` or a [registered custom format type](https://vega.github.io/vega-lite/usage/compile.html#format-type)).\n\n\n__Default value:__\n- `\"time\"` for temporal fields and ordinal and nomimal fields with `timeUnit`.\n- `\"number\"` for quantitative fields as well as ordinal and nomimal fields without `timeUnit`.", + "type": "string" + }, + "labelExpr": { + "description": "[Vega expression](https://vega.github.io/vega/docs/expressions/) for customizing labels text.\n\n__Note:__ The label text and value can be assessed via the `label` and `value` properties of the axis's backing `datum` object.", + "type": "string" }, "timeUnit": { "anyOf": [ @@ -7263,53 +7671,83 @@ "$ref": "#/definitions/TimeUnitParams" } ], - "description": "Time unit for the field to be tested." + "description": "Time unit (e.g., `year`, `yearmonth`, `month`, `hours`) for a temporal field.\nor [a temporal field that gets casted as ordinal](https://vega.github.io/vega-lite/docs/type.html#cast).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html) documentation." + }, + "title": { + "anyOf": [ + { + "$ref": "#/definitions/Text" + }, + { + "type": "null" + } + ], + "description": "A title for the field. If `null`, the title will be removed.\n\n__Default value:__ derived from the field's name and transformation function (`aggregate`, `bin` and `timeUnit`). If the field has an aggregate function, the function is displayed as part of the title (e.g., `\"Sum of Profit\"`). If the field is binned or has a time unit applied, the applied function is shown in parentheses (e.g., `\"Profit (binned)\"`, `\"Transaction Date (year-month)\"`). Otherwise, the title is simply the field name.\n\n__Notes__:\n\n1) You can customize the default field title format by providing the [`fieldTitle`](https://vega.github.io/vega-lite/docs/config.html#top-level-config) property in the [config](https://vega.github.io/vega-lite/docs/config.html) or [`fieldTitle` function via the `compile` function's options](https://vega.github.io/vega-lite/docs/compile.html#field-title).\n\n2) If both field definition's `title` and axis, header, or legend `title` are defined, axis/header/legend title will be used." + }, + "type": { + "$ref": "#/definitions/StandardType", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." } }, "required": [ - "field", - "lt" + "type" ], "type": "object" }, - "FieldName": { - "type": "string" - }, - "FieldOneOfPredicate": { + "FieldOrDatumDefWithCondition": { "additionalProperties": false, + "description": "A FieldDef with Condition\n{\n condition: {value: ...},\n field: ...,\n ...\n}", "properties": { - "field": { - "$ref": "#/definitions/FieldName", - "description": "Field to be tested." + "aggregate": { + "$ref": "#/definitions/Aggregate", + "description": "Aggregation function for the field\n(e.g., `\"mean\"`, `\"sum\"`, `\"median\"`, `\"min\"`, `\"max\"`, `\"count\"`).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html) documentation." }, - "oneOf": { + "bin": { "anyOf": [ { - "items": { - "type": "string" - }, - "type": "array" + "type": "boolean" }, { - "items": { - "type": "number" - }, - "type": "array" + "$ref": "#/definitions/BinParams" }, { - "items": { - "type": "boolean" - }, - "type": "array" + "enum": [ + "binned" + ], + "type": "string" }, { - "items": { - "$ref": "#/definitions/DateTime" - }, - "type": "array" + "type": "null" } ], - "description": "A set of values that the `field`'s value should be a member of,\nfor a data item included in the filtered data." + "description": "A flag for binning a `quantitative` field, [an object defining binning parameters](https://vega.github.io/vega-lite/docs/bin.html#params), or indicating that the data for `x` or `y` channel are binned before they are imported into Vega-Lite (`\"binned\"`).\n\n- If `true`, default [binning parameters](https://vega.github.io/vega-lite/docs/bin.html) will be applied.\n\n- If `\"binned\"`, this indicates that the data for the `x` (or `y`) channel are already binned. You can map the bin-start field to `x` (or `y`) and the bin-end field to `x2` (or `y2`). The scale and axis will be formatted similar to binning in Vega-Lite. To adjust the axis ticks based on the bin step, you can also set the axis's [`tickMinStep`](https://vega.github.io/vega-lite/docs/axis.html#ticks) property.\n\n__Default value:__ `false`\n\n__See also:__ [`bin`](https://vega.github.io/vega-lite/docs/bin.html) documentation." + }, + "condition": { + "$ref": "#/definitions/ValueCondition", + "description": "One or more value definition(s) with [a selection or a test predicate](https://vega.github.io/vega-lite/docs/condition.html).\n\n__Note:__ A field definition's `condition` property can only contain [conditional value definitions](https://vega.github.io/vega-lite/docs/condition.html#value)\nsince Vega-Lite only allows at most one encoded field per encoding channel." + }, + "field": { + "$ref": "#/definitions/Field", + "description": "__Required.__ A string defining the name of the field from which to pull a data value\nor an object defining iterated values from the [`repeat`](https://vega.github.io/vega-lite/docs/repeat.html) operator.\n\n__See also:__ [`field`](https://vega.github.io/vega-lite/docs/field.html) documentation.\n\n__Notes:__\n1) Dots (`.`) and brackets (`[` and `]`) can be used to access nested objects (e.g., `\"field\": \"foo.bar\"` and `\"field\": \"foo['bar']\"`).\nIf field names contain dots or brackets but are not nested, you can use `\\\\` to escape dots and brackets (e.g., `\"a\\\\.b\"` and `\"a\\\\[0\\\\]\"`).\nSee more details about escaping in the [field documentation](https://vega.github.io/vega-lite/docs/field.html).\n2) `field` is not required if `aggregate` is `count`." + }, + "format": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object" + } + ], + "description": "When used with the default `\"number\"` and `\"time\"` format type, the text formatting pattern for labels of guides (axes, legends, headers) and text marks.\n\n- If the format type is `\"number\"` (e.g., for quantitative fields), this is D3's [number format pattern](https://github.com/d3/d3-format#locale_format).\n- If the format type is `\"time\"` (e.g., for temporal fields), this is D3's [time format pattern](https://github.com/d3/d3-time-format#locale_format).\n\nSee the [format documentation](https://vega.github.io/vega-lite/docs/format.html) for more examples.\n\nWhen used with a [custom `\"formatType\"`](https://vega.github.io/vega-lite/usage/compile.html#format-type) that takes `datum.value` and format parameter as input), this property represents the format parameter.\n\n__Default value:__ Derived from [numberFormat](https://vega.github.io/vega-lite/docs/config.html#format) config for number format and from [timeFormat](https://vega.github.io/vega-lite/docs/config.html#format) config for time format." + }, + "formatType": { + "description": "The format type for labels (`\"number\"` or `\"time\"` or a [registered custom format type](https://vega.github.io/vega-lite/usage/compile.html#format-type)).\n\n\n__Default value:__\n- `\"time\"` for temporal fields and ordinal and nomimal fields with `timeUnit`.\n- `\"number\"` for quantitative fields as well as ordinal and nomimal fields without `timeUnit`.", + "type": "string" + }, + "labelExpr": { + "description": "[Vega expression](https://vega.github.io/vega/docs/expressions/) for customizing labels text.\n\n__Note:__ The label text and value can be assessed via the `label` and `value` properties of the axis's backing `datum` object.", + "type": "string" }, "timeUnit": { "anyOf": [ @@ -7320,12 +7758,26 @@ "$ref": "#/definitions/TimeUnitParams" } ], - "description": "Time unit for the field to be tested." + "description": "Time unit (e.g., `year`, `yearmonth`, `month`, `hours`) for a temporal field.\nor [a temporal field that gets casted as ordinal](https://vega.github.io/vega-lite/docs/type.html#cast).\n\n__Default value:__ `undefined` (None)\n\n__See also:__ [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html) documentation." + }, + "title": { + "anyOf": [ + { + "$ref": "#/definitions/Text" + }, + { + "type": "null" + } + ], + "description": "A title for the field. If `null`, the title will be removed.\n\n__Default value:__ derived from the field's name and transformation function (`aggregate`, `bin` and `timeUnit`). If the field has an aggregate function, the function is displayed as part of the title (e.g., `\"Sum of Profit\"`). If the field is binned or has a time unit applied, the applied function is shown in parentheses (e.g., `\"Profit (binned)\"`, `\"Transaction Date (year-month)\"`). Otherwise, the title is simply the field name.\n\n__Notes__:\n\n1) You can customize the default field title format by providing the [`fieldTitle`](https://vega.github.io/vega-lite/docs/config.html#top-level-config) property in the [config](https://vega.github.io/vega-lite/docs/config.html) or [`fieldTitle` function via the `compile` function's options](https://vega.github.io/vega-lite/docs/compile.html#field-title).\n\n2) If both field definition's `title` and axis, header, or legend `title` are defined, axis/header/legend title will be used." + }, + "type": { + "$ref": "#/definitions/StandardType", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." } }, "required": [ - "field", - "oneOf" + "type" ], "type": "object" }, @@ -12250,17 +12702,23 @@ ], "type": "object" }, + "NumericArrayDatumDefWithCondition": { + "$ref": "#/definitions/FieldOrDatumDefWithCondition" + }, "NumericArrayFieldDefWithCondition": { - "$ref": "#/definitions/FieldDefWithCondition" + "$ref": "#/definitions/FieldOrDatumDefWithCondition" }, "NumericArrayValueDefWithCondition": { - "$ref": "#/definitions/ValueDefWithCondition" + "$ref": "#/definitions/ValueDefWithCondition" + }, + "NumericDatumDefWithCondition": { + "$ref": "#/definitions/FieldOrDatumDefWithCondition" }, "NumericFieldDefWithCondition": { - "$ref": "#/definitions/FieldDefWithCondition" + "$ref": "#/definitions/FieldOrDatumDefWithCondition" }, "NumericValueWithCondition": { - "$ref": "#/definitions/ValueWithCondition" + "$ref": "#/definitions/ValueWithCondition" }, "OrderFieldDef": { "additionalProperties": false, @@ -12824,6 +13282,80 @@ ], "type": "object" }, + "PositionDatumDef": { + "additionalProperties": false, + "properties": { + "axis": { + "anyOf": [ + { + "$ref": "#/definitions/Axis" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of axis's gridlines, ticks and labels.\nIf `null`, the axis for the encoding channel will be removed.\n\n__Default value:__ If undefined, default [axis properties](https://vega.github.io/vega-lite/docs/axis.html) are applied.\n\n__See also:__ [`axis`](https://vega.github.io/vega-lite/docs/axis.html) documentation." + }, + "band": { + "description": "For rect-based marks (`rect`, `bar`, and `image`), mark size relative to bandwidth of [band scales](https://vega.github.io/vega-lite/docs/scale.html#band) or time units. If set to `1`, the mark size is set to the bandwidth or the time unit interval. If set to `0.5`, the mark size is half of the bandwidth or the time unit interval.\n\nFor other marks, relative position on a band of a stacked, binned, time unit or band scale. If set to `0`, the marks will be positioned at the beginning of the band. If set to `0.5`, the marks will be positioned in the middle of the band.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "datum": { + "anyOf": [ + { + "$ref": "#/definitions/Value" + }, + { + "$ref": "#/definitions/RepeatRef" + } + ], + "description": "A constant value in data domain." + }, + "impute": { + "anyOf": [ + { + "$ref": "#/definitions/ImputeParams" + }, + { + "type": "null" + } + ], + "description": "An object defining the properties of the Impute Operation to be applied.\nThe field value of the other positional channel is taken as `key` of the `Impute` Operation.\nThe field of the `color` channel if specified is used as `groupby` of the `Impute` Operation.\n\n__See also:__ [`impute`](https://vega.github.io/vega-lite/docs/impute.html) documentation." + }, + "scale": { + "anyOf": [ + { + "$ref": "#/definitions/Scale" + }, + { + "type": "null" + } + ], + "description": "An object defining properties of the channel's scale, which is the function that transforms values in the data domain (numbers, dates, strings, etc) to visual values (pixels, colors, sizes) of the encoding channels.\n\nIf `null`, the scale will be [disabled and the data value will be directly encoded](https://vega.github.io/vega-lite/docs/scale.html#disable).\n\n__Default value:__ If undefined, default [scale properties](https://vega.github.io/vega-lite/docs/scale.html) are applied.\n\n__See also:__ [`scale`](https://vega.github.io/vega-lite/docs/scale.html) documentation." + }, + "stack": { + "anyOf": [ + { + "$ref": "#/definitions/StackOffset" + }, + { + "type": "null" + }, + { + "type": "boolean" + } + ], + "description": "Type of stacking offset if the field should be stacked.\n`stack` is only applicable for `x` and `y` channels with continuous domains.\nFor example, `stack` of `y` can be used to customize stacking for a vertical bar chart.\n\n`stack` can be one of the following values:\n- `\"zero\"` or `true`: stacking with baseline offset at zero value of the scale (for creating typical stacked [bar](https://vega.github.io/vega-lite/docs/stack.html#bar) and [area](https://vega.github.io/vega-lite/docs/stack.html#area) chart).\n- `\"normalize\"` - stacking with normalized domain (for creating [normalized stacked bar and area charts](https://vega.github.io/vega-lite/docs/stack.html#normalized).
\n-`\"center\"` - stacking with center baseline (for [streamgraph](https://vega.github.io/vega-lite/docs/stack.html#streamgraph)).\n- `null` or `false` - No-stacking. This will produce layered [bar](https://vega.github.io/vega-lite/docs/stack.html#layered-bar-chart) and area chart.\n\n__Default value:__ `zero` for plots with all of the following conditions are true:\n(1) the mark is `bar` or `area`;\n(2) the stacked measure channel (x or y) has a linear scale;\n(3) At least one of non-position channels mapped to an unaggregated field that is different from x and y. Otherwise, `null` by default.\n\n__See also:__ [`stack`](https://vega.github.io/vega-lite/docs/stack.html) documentation." + }, + "type": { + "$ref": "#/definitions/Type", + "description": "The encoded field's type of measurement (`\"quantitative\"`, `\"temporal\"`, `\"ordinal\"`, or `\"nominal\"`).\nIt can also be a `\"geojson\"` type for encoding ['geoshape'](https://vega.github.io/vega-lite/docs/geoshape.html).\n\n\n__Note:__\n\n- Data values for a temporal field can be either a date-time string (e.g., `\"2015-03-07 12:32:17\"`, `\"17:01\"`, `\"2015-03-16\"`. `\"2015\"`) or a timestamp number (e.g., `1552199579097`).\n- Data `type` describes the semantics of the data rather than the primitive data types (number, string, etc.). The same primitive data type can have different types of measurement. For example, numeric data can represent quantitative, ordinal, or nominal data.\n- When using with [`bin`](https://vega.github.io/vega-lite/docs/bin.html), the `type` property can be either `\"quantitative\"` (for using a linear bin scale) or [`\"ordinal\"` (for using an ordinal bin scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`timeUnit`](https://vega.github.io/vega-lite/docs/timeunit.html), the `type` property can be either `\"temporal\"` (for using a temporal scale) or [`\"ordinal\"` (for using an ordinal scale)](https://vega.github.io/vega-lite/docs/type.html#cast-bin).\n- When using with [`aggregate`](https://vega.github.io/vega-lite/docs/aggregate.html), the `type` property refers to the post-aggregation data type. For example, we can calculate count `distinct` of a categorical field `\"cat\"` using `{\"aggregate\": \"distinct\", \"field\": \"cat\", \"type\": \"quantitative\"}`. The `\"type\"` of the aggregate output is `\"quantitative\"`.\n- Secondary channels (e.g., `x2`, `y2`, `xError`, `yError`) do not have `type` as they have exactly the same type as their primary channels (e.g., `x`, `y`).\n\n__See also:__ [`type`](https://vega.github.io/vega-lite/docs/type.html) documentation." + } + }, + "type": "object" + }, "PositionFieldDef": { "additionalProperties": false, "properties": { @@ -14797,7 +15329,7 @@ "type": "string" }, "ShapeFieldDefWithCondition": { - "$ref": "#/definitions/FieldDefWithCondition,(string|null)>" + "$ref": "#/definitions/FieldOrDatumDefWithCondition,(string|null)>" }, "ShapeValueWithCondition": { "$ref": "#/definitions/StringValueWithCondition" @@ -15280,6 +15812,9 @@ } ] }, + "StringDatumDefWithCondition": { + "$ref": "#/definitions/FieldOrDatumDefWithCondition" + }, "StringFieldDef": { "additionalProperties": false, "properties": { @@ -15363,13 +15898,13 @@ "type": "object" }, "StringFieldDefWithCondition": { - "$ref": "#/definitions/FieldDefWithCondition" + "$ref": "#/definitions/FieldOrDatumDefWithCondition" }, "StringValueWithCondition": { - "$ref": "#/definitions/ValueWithCondition,(string|null)>" + "$ref": "#/definitions/ValueWithCondition,(string|null)>" }, "StringValueWithCondition": { - "$ref": "#/definitions/ValueWithCondition" + "$ref": "#/definitions/ValueWithCondition" }, "StyleConfigIndex": { "additionalProperties": { @@ -15507,7 +16042,7 @@ "type": "string" }, "TextFieldDefWithCondition": { - "$ref": "#/definitions/FieldDefWithCondition" + "$ref": "#/definitions/FieldOrDatumDefWithCondition" }, "TextValueWithCondition": { "$ref": "#/definitions/ValueWithCondition" @@ -17395,6 +17930,19 @@ } ] }, + "Type": { + "anyOf": [ + { + "$ref": "#/definitions/StandardType" + }, + { + "enum": [ + "geojson" + ], + "type": "string" + } + ] + }, "TypeForShape": { "enum": [ "nominal", @@ -17812,14 +18360,14 @@ ], "type": "object" }, - "ValueDefWithCondition": { + "ValueDefWithCondition": { "additionalProperties": false, "minProperties": 1, "properties": { "condition": { "anyOf": [ { - "$ref": "#/definitions/ConditionalMarkPropFieldDef" + "$ref": "#/definitions/ConditionalMarkPropFieldOrDatumDef" }, { "$ref": "#/definitions/ValueCondition<(Gradient|string|null)>" @@ -17844,14 +18392,14 @@ }, "type": "object" }, - "ValueDefWithCondition": { + "ValueDefWithCondition": { "additionalProperties": false, "minProperties": 1, "properties": { "condition": { "anyOf": [ { - "$ref": "#/definitions/ConditionalMarkPropFieldDef" + "$ref": "#/definitions/ConditionalMarkPropFieldOrDatumDef" }, { "$ref": "#/definitions/ValueCondition<(string|null)>" @@ -17869,14 +18417,14 @@ }, "type": "object" }, - "ValueDefWithCondition": { + "ValueDefWithCondition": { "additionalProperties": false, "minProperties": 1, "properties": { "condition": { "anyOf": [ { - "$ref": "#/definitions/ConditionalMarkPropFieldDef" + "$ref": "#/definitions/ConditionalMarkPropFieldOrDatumDef" }, { "$ref": "#/definitions/ValueCondition" @@ -17891,14 +18439,14 @@ }, "type": "object" }, - "ValueDefWithCondition": { + "ValueDefWithCondition": { "additionalProperties": false, "minProperties": 1, "properties": { "condition": { "anyOf": [ { - "$ref": "#/definitions/ConditionalMarkPropFieldDef" + "$ref": "#/definitions/ConditionalMarkPropFieldOrDatumDef" }, { "$ref": "#/definitions/ValueCondition" @@ -17916,14 +18464,14 @@ }, "type": "object" }, - "ValueDefWithCondition,(string|null)>": { + "ValueDefWithCondition,(string|null)>": { "additionalProperties": false, "minProperties": 1, "properties": { "condition": { "anyOf": [ { - "$ref": "#/definitions/ConditionalMarkPropFieldDef" + "$ref": "#/definitions/ConditionalMarkPropFieldOrDatumDef" }, { "$ref": "#/definitions/ValueCondition<(string|null)>" @@ -18041,17 +18589,17 @@ } ] }, - "ValueWithCondition": { - "$ref": "#/definitions/ValueDefWithCondition" + "ValueWithCondition": { + "$ref": "#/definitions/ValueDefWithCondition" }, - "ValueWithCondition": { - "$ref": "#/definitions/ValueDefWithCondition" + "ValueWithCondition": { + "$ref": "#/definitions/ValueDefWithCondition" }, - "ValueWithCondition": { - "$ref": "#/definitions/ValueDefWithCondition" + "ValueWithCondition": { + "$ref": "#/definitions/ValueDefWithCondition" }, - "ValueWithCondition,(string|null)>": { - "$ref": "#/definitions/ValueDefWithCondition,(string|null)>" + "ValueWithCondition,(string|null)>": { + "$ref": "#/definitions/ValueDefWithCondition,(string|null)>" }, "ValueWithCondition": { "$ref": "#/definitions/ValueDefWithCondition" From ff6a9f938640d8d2d5827bd3b209f6dacf555f01 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot Date: Wed, 25 Mar 2020 15:36:49 +0000 Subject: [PATCH 4/9] chore: update examples [CI] --- .../compiled/layer_bar_annotations.vg.json | 38 +---- examples/compiled/layer_line_datum_rule.svg | 1 + .../compiled/layer_line_datum_rule.vg.json | 140 ++++++++++++++++++ examples/compiled/repeat_layer.svg | 2 +- examples/compiled/repeat_layer.vg.json | 15 +- .../geo_constant_value_normalized.vl.json | 4 +- .../layer_bar_annotations_normalized.vl.json | 71 +++++++++ .../repeat_layer_normalized.vl.json | 14 +- 8 files changed, 244 insertions(+), 41 deletions(-) create mode 100644 examples/compiled/layer_line_datum_rule.svg create mode 100644 examples/compiled/layer_line_datum_rule.vg.json create mode 100644 examples/specs/normalized/layer_bar_annotations_normalized.vl.json diff --git a/examples/compiled/layer_bar_annotations.vg.json b/examples/compiled/layer_bar_annotations.vg.json index 6da023e690..62f1b24d4c 100644 --- a/examples/compiled/layer_bar_annotations.vg.json +++ b/examples/compiled/layer_bar_annotations.vg.json @@ -26,10 +26,7 @@ {"Day": 15, "Value": 130.5} ] }, - { - "name": "source_1", - "values": [{"ThresholdValue": 300, "Threshold": "hazardous"}] - }, + {"name": "source_1", "values": [{}]}, { "name": "data_1", "source": "source_0", @@ -51,26 +48,6 @@ "expr": "isValid(datum[\"baseline\"]) && isFinite(+datum[\"baseline\"])" } ] - }, - { - "name": "data_4", - "source": "source_1", - "transform": [ - { - "type": "filter", - "expr": "isValid(datum[\"ThresholdValue\"]) && isFinite(+datum[\"ThresholdValue\"])" - } - ] - }, - { - "name": "data_5", - "source": "source_1", - "transform": [ - { - "type": "filter", - "expr": "isValid(datum[\"ThresholdValue\"]) && isFinite(+datum[\"ThresholdValue\"])" - } - ] } ], "signals": [ @@ -115,13 +92,13 @@ "name": "layer_1_layer_0_marks", "type": "rule", "style": ["rule"], - "from": {"data": "data_4"}, + "from": {"data": "source_1"}, "encode": { "update": { "stroke": {"value": "black"}, "x": {"field": {"group": "width"}}, "x2": {"value": 0}, - "y": {"scale": "y", "field": "ThresholdValue"} + "y": {"scale": "y", "value": 300} } } }, @@ -129,17 +106,17 @@ "name": "layer_1_layer_1_marks", "type": "text", "style": ["text"], - "from": {"data": "data_5"}, + "from": {"data": "source_1"}, "encode": { "update": { "align": {"value": "right"}, "baseline": {"value": "bottom"}, + "text": {"value": "hazardous"}, "dx": {"value": -2}, "dy": {"value": -2}, "fill": {"value": "black"}, "x": {"field": {"group": "width"}}, - "y": {"scale": "y", "field": "ThresholdValue"}, - "text": {"signal": "''+datum[\"Threshold\"]"} + "y": {"scale": "y", "value": 300} } } } @@ -167,8 +144,7 @@ {"data": "data_1", "field": "Value"}, {"data": "data_2", "field": "baseline"}, {"data": "data_2", "field": "Value"}, - {"data": "data_4", "field": "ThresholdValue"}, - {"data": "data_5", "field": "ThresholdValue"} + [300] ] }, "range": [{"signal": "height"}, 0], diff --git a/examples/compiled/layer_line_datum_rule.svg b/examples/compiled/layer_line_datum_rule.svg new file mode 100644 index 0000000000..6ec6ebd6ca --- /dev/null +++ b/examples/compiled/layer_line_datum_rule.svg @@ -0,0 +1 @@ +200020022004200620082010date0200400600800priceAAPLAMZNGOOGIBMMSFTsymbol \ No newline at end of file diff --git a/examples/compiled/layer_line_datum_rule.vg.json b/examples/compiled/layer_line_datum_rule.vg.json new file mode 100644 index 0000000000..dec1fa7158 --- /dev/null +++ b/examples/compiled/layer_line_datum_rule.vg.json @@ -0,0 +1,140 @@ +{ + "$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/stocks.csv", + "format": {"type": "csv", "parse": {"date": "date"}} + }, + {"name": "source_1", "values": [{}]} + ], + "marks": [ + { + "name": "layer_0_pathgroup", + "type": "group", + "from": { + "facet": { + "name": "faceted_path_layer_0_main", + "data": "source_0", + "groupby": ["symbol"] + } + }, + "encode": { + "update": { + "width": {"field": {"group": "width"}}, + "height": {"field": {"group": "height"}} + } + }, + "marks": [ + { + "name": "layer_0_marks", + "type": "line", + "style": ["line"], + "sort": {"field": "datum[\"date\"]"}, + "from": {"data": "faceted_path_layer_0_main"}, + "encode": { + "update": { + "stroke": {"scale": "color", "field": "symbol"}, + "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_1_marks", + "type": "rule", + "style": ["rule"], + "from": {"data": "source_1"}, + "encode": { + "update": { + "strokeDash": {"value": [2, 2]}, + "stroke": {"value": "black"}, + "x": {"field": {"group": "width"}}, + "x2": {"value": 0}, + "y": {"scale": "y", "value": 300}, + "strokeWidth": {"value": 2} + } + } + } + ], + "scales": [ + { + "name": "x", + "type": "time", + "domain": {"data": "source_0", "field": "date"}, + "range": [0, {"signal": "width"}] + }, + { + "name": "y", + "type": "linear", + "domain": {"fields": [{"data": "source_0", "field": "price"}, [300]]}, + "range": [{"signal": "height"}, 0], + "nice": true, + "zero": true + }, + { + "name": "color", + "type": "ordinal", + "domain": {"data": "source_0", "field": "symbol", "sort": true}, + "range": "category" + } + ], + "axes": [ + { + "scale": "x", + "orient": "bottom", + "gridScale": "y", + "grid": true, + "tickCount": {"signal": "ceil(width/40)"}, + "domain": false, + "labels": 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, + "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 + } + ], + "legends": [{"stroke": "color", "symbolType": "stroke", "title": "symbol"}] +} diff --git a/examples/compiled/repeat_layer.svg b/examples/compiled/repeat_layer.svg index 469fb6697f..60bf5269a5 100644 --- a/examples/compiled/repeat_layer.svg +++ b/examples/compiled/repeat_layer.svg @@ -1 +1 @@ -1.02.03.04.05.06.07.08.09.010.0IMDB_Rating (binned)050,000,000100,000,000150,000,000200,000,000250,000,000Mean of US_Gross, Mean of Worldwide_Gross \ No newline at end of file +1.02.03.04.05.06.07.08.09.010.0IMDB_Rating (binned)050,000,000100,000,000150,000,000200,000,000250,000,000Mean of US and Worldwide GrossUS_GrossWorldwide_Gross \ No newline at end of file diff --git a/examples/compiled/repeat_layer.vg.json b/examples/compiled/repeat_layer.vg.json index 07e1294ab4..7e47cce562 100644 --- a/examples/compiled/repeat_layer.vg.json +++ b/examples/compiled/repeat_layer.vg.json @@ -51,7 +51,7 @@ "from": {"data": "source_0"}, "encode": { "update": { - "stroke": {"value": "#4c78a8"}, + "stroke": {"scale": "color", "value": "US_Gross"}, "x": { "signal": "scale(\"x\", 0.5 * datum[\"bin_maxbins_10_IMDB_Rating\"] + 0.5 * datum[\"bin_maxbins_10_IMDB_Rating_end\"])" }, @@ -70,7 +70,7 @@ "from": {"data": "source_0"}, "encode": { "update": { - "stroke": {"value": "#4c78a8"}, + "stroke": {"scale": "color", "value": "Worldwide_Gross"}, "x": { "signal": "scale(\"x\", 0.5 * datum[\"bin_maxbins_10_IMDB_Rating\"] + 0.5 * datum[\"bin_maxbins_10_IMDB_Rating_end\"])" }, @@ -105,6 +105,12 @@ "range": [{"signal": "height"}, 0], "nice": true, "zero": true + }, + { + "name": "color", + "type": "ordinal", + "domain": {"fields": [["US_Gross"], ["Worldwide_Gross"]]}, + "range": "category" } ], "axes": [ @@ -135,10 +141,11 @@ "scale": "y", "orient": "left", "grid": false, - "title": "Mean of US_Gross, Mean of Worldwide_Gross", + "title": "Mean of US and Worldwide Gross", "labelOverlap": true, "tickCount": {"signal": "ceil(height/40)"}, "zindex": 0 } - ] + ], + "legends": [{"stroke": "color", "symbolType": "stroke"}] } diff --git a/examples/specs/normalized/geo_constant_value_normalized.vl.json b/examples/specs/normalized/geo_constant_value_normalized.vl.json index 6526b415f4..a5db30b03c 100644 --- a/examples/specs/normalized/geo_constant_value_normalized.vl.json +++ b/examples/specs/normalized/geo_constant_value_normalized.vl.json @@ -17,7 +17,7 @@ { "mark": "square", "encoding": { - "longitude": {"value": -122.335167}, + "longitude": {"datum": -122.335167}, "latitude": {"field": "latitude", "type": "quantitative"}, "size": {"value": 1}, "color": {"value": "steelblue"} @@ -28,7 +28,7 @@ "mark": "square", "encoding": { "longitude": {"field": "longitude", "type": "quantitative"}, - "latitude": {"value": 47.608013}, + "latitude": {"datum": 47.608013}, "size": {"value": 1}, "color": {"value": "firebrick"} }, diff --git a/examples/specs/normalized/layer_bar_annotations_normalized.vl.json b/examples/specs/normalized/layer_bar_annotations_normalized.vl.json new file mode 100644 index 0000000000..6d4f260f49 --- /dev/null +++ b/examples/specs/normalized/layer_bar_annotations_normalized.vl.json @@ -0,0 +1,71 @@ +{ + "$schema": "https://vega.github.io/schema/vega-lite/v4.json", + "description": "The PM2.5 value of Beijing observed 15 days, highlighting the days when PM2.5 level is hazardous to human health. Data source https://chartaccent.github.io/chartaccent.html", + "layer": [ + { + "data": { + "values": [ + {"Day": 1, "Value": 54.8}, + {"Day": 2, "Value": 112.1}, + {"Day": 3, "Value": 63.6}, + {"Day": 4, "Value": 37.6}, + {"Day": 5, "Value": 79.7}, + {"Day": 6, "Value": 137.9}, + {"Day": 7, "Value": 120.1}, + {"Day": 8, "Value": 103.3}, + {"Day": 9, "Value": 394.8}, + {"Day": 10, "Value": 199.5}, + {"Day": 11, "Value": 72.3}, + {"Day": 12, "Value": 51.1}, + {"Day": 13, "Value": 112}, + {"Day": 14, "Value": 174.5}, + {"Day": 15, "Value": 130.5} + ] + }, + "layer": [ + { + "mark": "bar", + "encoding": { + "x": {"field": "Day", "type": "ordinal", "axis": {"labelAngle": 0}}, + "y": {"field": "Value", "type": "quantitative"} + } + }, + { + "mark": "bar", + "transform": [ + {"filter": "datum.Value >= 300"}, + {"calculate": "300", "as": "baseline"} + ], + "encoding": { + "x": {"field": "Day", "type": "ordinal"}, + "y": { + "field": "baseline", + "type": "quantitative", + "title": "PM2.5 Value" + }, + "y2": {"field": "Value"}, + "color": {"value": "#e45755"} + } + } + ] + }, + { + "data": {"values": [{}]}, + "layer": [ + {"mark": "rule", "encoding": {"y": {"datum": 300}}}, + { + "mark": { + "type": "text", + "align": "right", + "baseline": "bottom", + "dx": -2, + "dy": -2, + "x": "width", + "text": "hazardous" + }, + "encoding": {"y": {"datum": 300}} + } + ] + } + ] +} \ No newline at end of file diff --git a/examples/specs/normalized/repeat_layer_normalized.vl.json b/examples/specs/normalized/repeat_layer_normalized.vl.json index b468b5912a..892c48a16d 100644 --- a/examples/specs/normalized/repeat_layer_normalized.vl.json +++ b/examples/specs/normalized/repeat_layer_normalized.vl.json @@ -6,7 +6,13 @@ "mark": "line", "encoding": { "x": {"bin": true, "field": "IMDB_Rating", "type": "quantitative"}, - "y": {"aggregate": "mean", "field": "US_Gross", "type": "quantitative"} + "y": { + "aggregate": "mean", + "field": "US_Gross", + "type": "quantitative", + "title": "Mean of US and Worldwide Gross" + }, + "color": {"datum": "US_Gross", "type": "nominal"} }, "name": "child__layer_US_Gross" }, @@ -17,8 +23,10 @@ "y": { "aggregate": "mean", "field": "Worldwide_Gross", - "type": "quantitative" - } + "type": "quantitative", + "title": "Mean of US and Worldwide Gross" + }, + "color": {"datum": "Worldwide_Gross", "type": "nominal"} }, "name": "child__layer_Worldwide_Gross" } From 7727d4a59f95fe51c6540b5f76e5104d8efae765 Mon Sep 17 00:00:00 2001 From: Kanit Wongsuphasawat Date: Wed, 25 Mar 2020 10:01:07 -0700 Subject: [PATCH 5/9] refactor: get fieldOrDatumDef only once in axis parse --- src/compile/axis/parse.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/compile/axis/parse.ts b/src/compile/axis/parse.ts index 2b1cc18d7b..8642f607f8 100644 --- a/src/compile/axis/parse.ts +++ b/src/compile/axis/parse.ts @@ -248,9 +248,13 @@ function parseAxis(channel: PositionScaleChannel, model: UnitModel): AxisCompone const axisComponent = new AxisComponent(); + const fieldOrDatumDef = getFieldOrDatumDef(model.encoding[channel]) as + | PositionFieldDef + | PositionDatumDef; + // 1.2. Add properties for (const property of AXIS_COMPONENT_PROPERTIES) { - const value = getProperty(property, axis, channel, model); + const value = getProperty(fieldOrDatumDef, property, axis, channel, model); const {configValue = undefined, configFrom = undefined} = isAxisProperty(property) ? getAxisConfig( property, @@ -310,6 +314,7 @@ function parseAxis(channel: PositionScaleChannel, model: UnitModel): AxisCompone } function getProperty( + fieldOrDatumDef: PositionFieldDef | PositionDatumDef, property: K, specifiedAxis: Axis, channel: PositionScaleChannel, @@ -321,8 +326,7 @@ function getProperty( specifiedAxis = specifiedAxis || {}; // assign object so the rest doesn't have to check if legend exists - const {mark, encoding, config} = model; - const fieldOrDatumDef = getFieldOrDatumDef(encoding[channel]) as PositionFieldDef | PositionDatumDef; + const {mark, config} = model; switch (property) { case 'scale': From 03110b32ae7d7446e5363da2c75c3139d56afb13 Mon Sep 17 00:00:00 2001 From: Kanit Wongsuphasawat Date: Wed, 25 Mar 2020 12:43:06 -0700 Subject: [PATCH 6/9] refactor: remove unnecessary any --- src/channeldef.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/channeldef.ts b/src/channeldef.ts index cf73e165f2..a1950ff8b0 100644 --- a/src/channeldef.ts +++ b/src/channeldef.ts @@ -574,7 +574,7 @@ export function hasConditionalValueDef( export function isFieldDef( channelDef: ChannelDef | FieldDefBase | DatumDef -): channelDef is FieldDefBase | TypedFieldDef | SecondaryFieldDef { +): channelDef is FieldDefBase | TypedFieldDef | SecondaryFieldDef { return !!channelDef && (!!channelDef['field'] || channelDef['aggregate'] === 'count'); } @@ -838,7 +838,7 @@ export function title( } } -export function getGuide(fieldDef: TypedFieldDef | SecondaryFieldDef | DatumDef): Guide { +export function getGuide(fieldDef: TypedFieldDef | SecondaryFieldDef | DatumDef): Guide { if (isPositionFieldOrDatumDef(fieldDef) && fieldDef.axis) { return fieldDef.axis; } else if (isMarkPropFieldOrDatumDef(fieldDef) && fieldDef.legend) { From cdc04cb0feb36a92edcc3bbaab5d1e166cc6241d Mon Sep 17 00:00:00 2001 From: Kanit Wongsuphasawat Date: Wed, 25 Mar 2020 13:53:19 -0700 Subject: [PATCH 7/9] fix: allow datum to be 0 / falsy value --- src/channeldef.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/channeldef.ts b/src/channeldef.ts index a1950ff8b0..fb3e59f9b3 100644 --- a/src/channeldef.ts +++ b/src/channeldef.ts @@ -585,7 +585,7 @@ export function channelDefType(channelDef: ChannelDef): Type export function isDatumDef( channelDef: ChannelDef | FieldDefBase | DatumDef ): channelDef is DatumDef { - return !!channelDef && !!channelDef['datum']; + return !!channelDef && 'datum' in channelDef; } export function isContinuousFieldOrDatumDef(cd: ChannelDef) { From b5166f6839425d75d1571cbc6fffb8f842827499 Mon Sep 17 00:00:00 2001 From: Kanit Wongsuphasawat Date: Wed, 25 Mar 2020 14:01:06 -0700 Subject: [PATCH 8/9] fix: adjust message to include datum --- src/log/message.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/log/message.ts b/src/log/message.ts index eec2877d57..9320d6afd2 100644 --- a/src/log/message.ts +++ b/src/log/message.ts @@ -151,7 +151,7 @@ export function droppingColor(type: 'encoding' | 'property', opt: {fill?: boolea export function emptyFieldDef(fieldDef: TypedFieldDef, channel: Channel) { return `Dropping ${stringify( fieldDef - )} from channel "${channel}" since it does not contain any data field, value, or signal.`; + )} from channel "${channel}" since it does not contain any data field, datum, value, or signal.`; } export function latLongDeprecated(channel: Channel, type: Type, newChannel: GeoPositionChannel) { return `${channel}-encoding with type ${type} is deprecated. Replacing with ${newChannel}-encoding.`; From 9d861d409664984433074612d6c076982db10aa8 Mon Sep 17 00:00:00 2001 From: Dominik Moritz Date: Wed, 25 Mar 2020 14:18:14 -0700 Subject: [PATCH 9/9] Update src/channeldef.ts --- src/channeldef.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/channeldef.ts b/src/channeldef.ts index fb3e59f9b3..c2856dd2ea 100644 --- a/src/channeldef.ts +++ b/src/channeldef.ts @@ -381,7 +381,7 @@ export interface DatumDef ext * A constant value in data domain. */ datum?: F extends RepeatRef ? V | RepeatRef : V; - // only apply Repeatref is field (F) can be RepeatRef + // only apply Repeatref if field (F) can be RepeatRef // FIXME(https://github.com/microsoft/TypeScript/issues/37586): // `F extends RepeatRef` probably should be `RepeatRef extends F` but there is likely a bug in TS. }