UNPKG

compassql

Version:

CompassQL visualization query language

157 lines (138 loc) 5.1 kB
import * as CHANNEL from 'vega-lite/build/src/channel'; import {hasDiscreteDomain} from 'vega-lite/build/src/scale'; import * as TYPE from 'vega-lite/build/src/type'; import {QueryConfig} from './config'; import {SpecQueryModel} from './model'; import {AxisQuery, EncodingQuery, isFieldQuery, ScaleQuery, scaleType} from './query/encoding'; import {ExpandedType} from './query/expandedtype'; import {Schema} from './schema'; import {Dict} from './util'; export function stylize(answerSet: SpecQueryModel[], schema: Schema, opt: QueryConfig): SpecQueryModel[] { let encQIndex: Dict<EncodingQuery> = {}; answerSet = answerSet.map(function(specM) { if (opt.smallRangeStepForHighCardinalityOrFacet) { specM = smallRangeStepForHighCardinalityOrFacet(specM, schema, encQIndex, opt); } if (opt.nominalColorScaleForHighCardinality) { specM = nominalColorScaleForHighCardinality(specM, schema, encQIndex, opt); } if (opt.xAxisOnTopForHighYCardinalityWithoutColumn) { specM = xAxisOnTopForHighYCardinalityWithoutColumn(specM, schema, encQIndex, opt); } return specM; }); return answerSet; } export function smallRangeStepForHighCardinalityOrFacet( specM: SpecQueryModel, schema: Schema, encQIndex: Dict<EncodingQuery>, opt: QueryConfig ): SpecQueryModel { [CHANNEL.ROW, CHANNEL.Y, CHANNEL.COLUMN, CHANNEL.X].forEach(channel => { encQIndex[channel] = specM.getEncodingQueryByChannel(channel); }); const yEncQ = encQIndex[CHANNEL.Y]; if (yEncQ !== undefined && isFieldQuery(yEncQ)) { if ( encQIndex[CHANNEL.ROW] || schema.cardinality(yEncQ) > opt.smallRangeStepForHighCardinalityOrFacet.maxCardinality ) { // We check for undefined rather than // yEncQ.scale = yEncQ.scale || {} to cover the case where // yEncQ.scale has been set to false/null. // This prevents us from incorrectly overriding scale and // assigning a rangeStep when scale is set to false. if (yEncQ.scale === undefined) { yEncQ.scale = {}; } // We do not want to assign a rangeStep if scale is set to false // and we only apply this if the scale is (or can be) an ordinal scale. const yScaleType = scaleType(yEncQ); if (yEncQ.scale && (yScaleType === undefined || hasDiscreteDomain(yScaleType))) { if (!(yEncQ.scale as ScaleQuery).rangeStep) { (yEncQ.scale as ScaleQuery).rangeStep = 12; } } } } const xEncQ = encQIndex[CHANNEL.X]; if (isFieldQuery(xEncQ)) { if ( encQIndex[CHANNEL.COLUMN] || schema.cardinality(xEncQ) > opt.smallRangeStepForHighCardinalityOrFacet.maxCardinality ) { // Just like y, we don't want to do this if scale is null/false if (xEncQ.scale === undefined) { xEncQ.scale = {}; } // We do not want to assign a rangeStep if scale is set to false // and we only apply this if the scale is (or can be) an ordinal scale. const xScaleType = scaleType(xEncQ); if (xEncQ.scale && (xScaleType === undefined || hasDiscreteDomain(xScaleType))) { if (!(xEncQ.scale as ScaleQuery).rangeStep) { (xEncQ.scale as ScaleQuery).rangeStep = 12; } } } } return specM; } export function nominalColorScaleForHighCardinality( specM: SpecQueryModel, schema: Schema, encQIndex: Dict<EncodingQuery>, opt: QueryConfig ): SpecQueryModel { encQIndex[CHANNEL.COLOR] = specM.getEncodingQueryByChannel(CHANNEL.COLOR); const colorEncQ = encQIndex[CHANNEL.COLOR]; if ( isFieldQuery(colorEncQ) && colorEncQ !== undefined && (colorEncQ.type === TYPE.NOMINAL || colorEncQ.type === ExpandedType.KEY) && schema.cardinality(colorEncQ) > opt.nominalColorScaleForHighCardinality.maxCardinality ) { if (colorEncQ.scale === undefined) { colorEncQ.scale = {}; } if (colorEncQ.scale) { if (!(colorEncQ.scale as ScaleQuery).range) { (colorEncQ.scale as ScaleQuery).scheme = opt.nominalColorScaleForHighCardinality.palette; } } } return specM; } export function xAxisOnTopForHighYCardinalityWithoutColumn( specM: SpecQueryModel, schema: Schema, encQIndex: Dict<EncodingQuery>, opt: QueryConfig ): SpecQueryModel { [CHANNEL.COLUMN, CHANNEL.X, CHANNEL.Y].forEach(channel => { encQIndex[channel] = specM.getEncodingQueryByChannel(channel); }); if (encQIndex[CHANNEL.COLUMN] === undefined) { const xEncQ = encQIndex[CHANNEL.X]; const yEncQ = encQIndex[CHANNEL.Y]; if ( isFieldQuery(xEncQ) && isFieldQuery(yEncQ) && yEncQ !== undefined && yEncQ.field && hasDiscreteDomain(scaleType(yEncQ)) ) { if (xEncQ !== undefined) { if (schema.cardinality(yEncQ) > opt.xAxisOnTopForHighYCardinalityWithoutColumn.maxCardinality) { if (xEncQ.axis === undefined) { xEncQ.axis = {}; } if (xEncQ.axis && !(xEncQ.axis as AxisQuery).orient) { (xEncQ.axis as AxisQuery).orient = 'top'; } } } } } return specM; }