Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

filterWith selections #1267

Merged
merged 3 commits into from
Mar 26, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/compile/data/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {source} from './source';
import {formatParse} from './formatparse';
import {nullFilter} from './nullfilter';
import {filter} from './filter';
import {filterWith} from './filterwith';
import {bin} from './bin';
import {formula} from './formula';
import {nonPositiveFilter} from './nonpositivenullfilter';
Expand Down Expand Up @@ -40,6 +41,9 @@ export interface DataComponent {
/** Filter test expression */
filter: string;

/** Filter test expression against selections */
filterWith: string;

/** Dictionary mapping a bin parameter hash to transforms of the binned field */
bin: Dict<VgTransform[]>;

Expand Down Expand Up @@ -86,6 +90,7 @@ export function parseUnitData(model: UnitModel): DataComponent {
nullFilter: nullFilter.parseUnit(model),
filter: filter.parseUnit(model),
nonPositiveFilter: nonPositiveFilter.parseUnit(model),
filterWith: filterWith.parseUnit(model),

source: source.parseUnit(model),
bin: bin.parseUnit(model),
Expand All @@ -104,6 +109,7 @@ export function parseFacetData(model: FacetModel): DataComponent {
nullFilter: nullFilter.parseFacet(model),
filter: filter.parseFacet(model),
nonPositiveFilter: nonPositiveFilter.parseFacet(model),
filterWith: filterWith.parseFacet(model),

source: source.parseFacet(model),
bin: bin.parseFacet(model),
Expand All @@ -124,6 +130,7 @@ export function parseLayerData(model: LayerModel): DataComponent {
nullFilter: nullFilter.parseLayer(model),
filter: filter.parseLayer(model),
nonPositiveFilter: nonPositiveFilter.parseLayer(model),
filterWith: filterWith.parseLayer(model),

// everything after here does not affect whether we can merge child data into parent or not
source: source.parseLayer(model),
Expand All @@ -143,6 +150,7 @@ export function parseRepeatData(model: RepeatModel): DataComponent {
nullFilter: nullFilter.parseRepeat(model),
filter: filter.parseRepeat(model),
nonPositiveFilter: nonPositiveFilter.parseRepeat(model),
filterWith: filterWith.parseRepeat(model),

source: source.parseRepeat(model),
bin: bin.parseRepeat(model),
Expand Down
60 changes: 60 additions & 0 deletions src/compile/data/filterwith.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import {FacetModel} from '../facet';
import {LayerModel} from '../layer';
import {RepeatModel} from '../repeat';
import {UnitModel} from '../unit';
import {Model} from '../model';
import {unique} from '../../util';
import {compileSelectionPredicate} from '../common';

import {DataComponent} from './data';

export namespace filterWith {
function parse(model: UnitModel): string {
var fw = model.transform().filterWith;
return fw ? compileSelectionPredicate(model, model.transform().filterWith) : null;
}

export const parseUnit = parse;

export function parseFacet(model: FacetModel) {
// todo
return null;
}

export function parseLayer(model: LayerModel) {
// Note that this `filter.parseLayer` method is called before `source.parseLayer`
let filterComponent = '';
model.children().forEach((child) => {
const childDataComponent = child.component.data;
if (model.compatibleSource(child) && childDataComponent.filterWith && childDataComponent.filterWith === filterComponent) {
// same filter in child so we can just delete it
delete childDataComponent.filterWith;
}
});
return filterComponent;
}

export function parseRepeat(model: RepeatModel) {
// Note that this `filter.parseLayer` method is called before `source.parseLayer`

const filters = model.children().map((child) => child.component.data.filterWith);
if (unique(filters).length === 1) {
// all filters are the same
model.children().forEach((child) => {
const childDataComponent = child.component.data;
delete childDataComponent.filterWith;
});
return filters[0];
}

return null;
}

export function assemble(component: DataComponent) {
const filter = component.filterWith;
return filter ? [{
type: 'filter',
test: filter
}] : [];
}
}
8 changes: 5 additions & 3 deletions src/compile/data/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {Model} from '../model';
import {DataComponent} from './data';
import {nullFilter} from './nullfilter';
import {filter} from './filter';
import {filterWith} from './filterwith';
import {bin} from './bin';
import {formula} from './formula';
import {timeUnit} from './timeunit';
Expand Down Expand Up @@ -64,7 +65,7 @@ export namespace source {

if (model.compatibleSource(child)) {
// we cannot merge if the child has filters defined even after we tried to move them up
const canMerge = !childData.filter && !childData.formatParse && !childData.nullFilter;
const canMerge = !childData.filter && !childData.formatParse && !childData.nullFilter && !childData.filterWith;
if (canMerge) {
// rename source because we can just remove it
child.renameData(child.dataName(SOURCE), model.dataName(SOURCE));
Expand Down Expand Up @@ -95,7 +96,7 @@ export namespace source {

// TODO: merge children into different groups that are mergable. (Current we only merge into one.)

const canMerge = !childData.filter && !childData.formatParse && !childData.nullFilter;
const canMerge = !childData.filter && !childData.formatParse && !childData.nullFilter && !childData.filterWith;
if (canMerge) {
// rename source because we can just remove it
child.renameData(child.dataName(SOURCE), model.dataName(SOURCE));
Expand Down Expand Up @@ -128,7 +129,8 @@ export namespace source {
nullFilter.assemble(component),
bin.assemble(component),
filter.assemble(component),
timeUnit.assemble(component)
timeUnit.assemble(component),
filterWith.assemble(component)
);

return sourceData;
Expand Down
4 changes: 4 additions & 0 deletions src/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ export interface Transform {
* Filter null values from the data. If set to true, all rows with null values are filtered. If false, no rows are filtered. Set the property to undefined to filter only quantitative and temporal fields.
*/
filterNull?: boolean;
/**
* Filter with a selection.
*/
filterWith?: string;
/**
* Calculate new field(s) using the provided expresssion(s). Calculation are applied before filter.
*/
Expand Down
10 changes: 10 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"src/compile/data/colorrank.ts",
"src/compile/data/data.ts",
"src/compile/data/filter.ts",
"src/compile/data/filterwith.ts",
"src/compile/data/formatparse.ts",
"src/compile/data/formula.ts",
"src/compile/data/nonpositivenullfilter.ts",
Expand All @@ -67,6 +68,15 @@
"src/compile/model.ts",
"src/compile/repeat.ts",
"src/compile/scale.ts",
"src/compile/selections/index.ts",
"src/compile/selections/interval.ts",
"src/compile/selections/nearest.ts",
"src/compile/selections/project.ts",
"src/compile/selections/scales.ts",
"src/compile/selections/toggle.ts",
"src/compile/selections/transforms.ts",
"src/compile/selections/translate.ts",
"src/compile/selections/zoom.ts",
"src/compile/stack.ts",
"src/compile/time.ts",
"src/compile/unit.ts",
Expand Down