or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

chart-registry.mdcoordinate-grid-charts.mdcore-utilities.mddata-display-widgets.mdfilters.mdindex.mdlegends.mdmixins.mdordinal-specialized-charts.md
tile.json

filters.mddocs/

Filters and Data Manipulation

Filter constructors and data manipulation tools for crossfilter integration and chart interactions. Filters define which records are selected and how charts respond to user interactions like brushing and clicking.

Capabilities

Filter System Overview

DC.js filters are objects that determine which data records are included when crossfilter applies filtering. Each filter has an isFiltered method and a filterType identifier. When applied to dimensions, they work with crossfilter to update all charts in the same group.

/**
 * Filters namespace containing filter constructors
 */
const filters: FiltersNamespace;

interface FilterObject {
  /** Function to test if value passes filter */
  isFiltered: (value: any) => boolean;
  
  /** String identifying the filter type */
  filterType: string;
}

RangedFilter

Filter for selecting values within a numeric range, commonly used for brushing on coordinate grid charts.

/**
 * Create a ranged filter for numeric ranges
 * @param {Number} low - Lower bound (inclusive)
 * @param {Number} high - Upper bound (exclusive)  
 * @returns {RangedFilterObject} Filter object with range checking
 */
function RangedFilter(low: number, high: number): RangedFilterObject;

interface RangedFilterObject extends Array<number> {
  /** Test if value is within range [low, high) */
  isFiltered: (value: number) => boolean;
  
  /** Filter type identifier */
  filterType: 'RangedFilter';
  
  /** Lower bound (inclusive) */
  0: number;
  
  /** Upper bound (exclusive) */
  1: number;
}

Usage Example:

import { filters } from 'dc';

// Create filter for values between 10 and 50
const rangeFilter = filters.RangedFilter(10, 50);

console.log(rangeFilter.isFiltered(25)); // true (25 >= 10 && 25 < 50)
console.log(rangeFilter.isFiltered(50)); // false (50 is not < 50)
console.log(rangeFilter.isFiltered(5));  // false (5 is not >= 10)

// Used automatically by coordinate grid charts for brushing
barChart.on('filtered', function(chart) {
  const filters = chart.filters();
  filters.forEach(filter => {
    if (filter.filterType === 'RangedFilter') {
      console.log(`Range: ${filter[0]} to ${filter[1]}`);
    }
  });
});

TwoDimensionalFilter

Filter for selecting single points in two-dimensional space, used by heat maps for cell selection.

/**
 * Create a two-dimensional point filter
 * @param {Array} key - Two-element array [x, y] representing the point
 * @returns {TwoDimensionalFilterObject} Filter object for 2D point matching
 */
function TwoDimensionalFilter(key: [any, any]): TwoDimensionalFilterObject;

interface TwoDimensionalFilterObject extends Array<any> {
  /** Test if value matches the exact 2D point */
  isFiltered: (value: [any, any]) => boolean;
  
  /** Filter type identifier */
  filterType: 'TwoDimensionalFilter';
  
  /** X coordinate */
  0: any;
  
  /** Y coordinate */  
  1: any;
}

Usage Example:

import { filters } from 'dc';

// Create filter for specific cell in heatmap
const cellFilter = filters.TwoDimensionalFilter(['Category A', 'Q1']);

console.log(cellFilter.isFiltered(['Category A', 'Q1'])); // true
console.log(cellFilter.isFiltered(['Category B', 'Q1'])); // false
console.log(cellFilter.isFiltered(['Category A', 'Q2'])); // false

// Used automatically by heatmap charts
heatMap.on('filtered', function(chart) {
  const filters = chart.filters();
  filters.forEach(filter => {
    if (filter.filterType === 'TwoDimensionalFilter') {
      console.log(`Cell: ${filter[0]}, ${filter[1]}`);
    }
  });
});

RangedTwoDimensionalFilter

Filter for selecting rectangular regions in two-dimensional space, used for area selection in heatmaps and scatter plots.

/**
 * Create a two-dimensional range filter for rectangular regions
 * @param {Array} filter - [[x1, y1], [x2, y2]] defining rectangle bounds
 * @returns {RangedTwoDimensionalFilterObject} Filter object for 2D range matching
 */
function RangedTwoDimensionalFilter(filter: [[any, any], [any, any]]): RangedTwoDimensionalFilterObject;

interface RangedTwoDimensionalFilterObject extends Array<[any, any]> {
  /** Test if 2D point falls within rectangle */
  isFiltered: (value: [any, any]) => boolean;
  
  /** Filter type identifier */
  filterType: 'RangedTwoDimensionalFilter';
  
  /** Bottom-left corner [x1, y1] */
  0: [any, any];
  
  /** Top-right corner [x2, y2] */
  1: [any, any];
}

Usage Example:

import { filters } from 'dc';

// Create rectangular filter from (10,20) to (50,80)
const rectFilter = filters.RangedTwoDimensionalFilter([[10, 20], [50, 80]]);

console.log(rectFilter.isFiltered([25, 40])); // true (within rectangle)
console.log(rectFilter.isFiltered([5, 30]));  // false (x < 10)
console.log(rectFilter.isFiltered([30, 90])); // false (y > 80)

// Used for area brushing in scatter plots
scatterPlot.on('filtered', function(chart) {
  const filters = chart.filters();
  filters.forEach(filter => {
    if (filter.filterType === 'RangedTwoDimensionalFilter') {
      const [[x1, y1], [x2, y2]] = filter;
      console.log(`Rectangle: (${x1},${y1}) to (${x2},${y2})`);
    }
  });
});

HierarchyFilter

Filter for selecting paths in hierarchical data structures, used by sunburst and tree charts.

/**
 * Create a hierarchical path filter
 * @param {Array} path - Array representing path from root to target node
 * @returns {HierarchyFilterObject} Filter object for hierarchy path matching
 */
function HierarchyFilter(path: any[]): HierarchyFilterObject;

interface HierarchyFilterObject extends Array<any> {
  /** Test if value represents a path under this filter's path */
  isFiltered: (value: any[]) => boolean;
  
  /** Filter type identifier */
  filterType: 'HierarchyFilter';
}

Usage Example:

import { filters } from 'dc';

// Create filter for hierarchical path: Root > Technology > Software
const pathFilter = filters.HierarchyFilter(['Root', 'Technology', 'Software']);

// Tests if paths are under the filtered path
console.log(pathFilter.isFiltered(['Root', 'Technology', 'Software'])); // true (exact match)
console.log(pathFilter.isFiltered(['Root', 'Technology', 'Software', 'Web'])); // true (child)
console.log(pathFilter.isFiltered(['Root', 'Technology', 'Hardware'])); // false (different branch)
console.log(pathFilter.isFiltered(['Root', 'Technology'])); // false (parent)

// Used by sunburst charts for segment selection
sunburstChart.on('filtered', function(chart) {
  const filters = chart.filters();
  filters.forEach(filter => {
    if (filter.filterType === 'HierarchyFilter') {
      console.log(`Path: ${filter.join(' > ')}`);
    }
  });
});

Filter Integration Patterns

Chart Filter Events

All charts emit filter events when their selection changes:

import { BarChart } from 'dc';

const chart = new BarChart('#chart');

chart.on('filtered', function(chart, filter) {
  console.log('Filter applied:', filter);
  
  // Get all current filters
  const allFilters = chart.filters();
  console.log('All filters:', allFilters);
  
  // Check filter types
  allFilters.forEach(f => {
    switch(f.filterType) {
      case 'RangedFilter':
        console.log(`Range: ${f[0]} to ${f[1]}`);
        break;
      case 'TwoDimensionalFilter':
        console.log(`Point: (${f[0]}, ${f[1]})`);
        break;
      // Handle other filter types...
    }
  });
});

Custom Filter Handlers

Charts provide methods to customize how filters are applied and managed:

import { BarChart } from 'dc';

const chart = new BarChart('#chart')
  .filterHandler(function(dimension, filters) {
    // Custom filter application logic
    if (filters.length === 0) {
      dimension.filter(null); // Clear all filters
    } else {
      // Apply custom filtering logic
      dimension.filterFunction(d => {
        return filters.some(filter => filter.isFiltered(d));
      });
    }
    return filters;
  })
  .hasFilterHandler(function(filters, filter) {
    // Custom logic to check if filter exists
    return filters.some(f => /* custom comparison */);
  })
  .addFilterHandler(function(filters, filter) {
    // Custom logic to add filter
    filters.push(filter);
    return filters;
  })
  .removeFilterHandler(function(filters, filter) {
    // Custom logic to remove filter
    return filters.filter(f => /* custom comparison */);
  });

Multiple Filter Coordination

When multiple filters are active on a chart, they are combined using OR logic:

// If chart has multiple filters
const filters = [
  filters.RangedFilter(10, 20),
  filters.RangedFilter(50, 60)
];

// Records pass if they match ANY filter:
// (value >= 10 && value < 20) OR (value >= 50 && value < 60)

Programmatic Filter Management

Filters can be applied and removed programmatically:

import { BarChart, filters } from 'dc';

const chart = new BarChart('#chart');

// Apply range filter programmatically
chart.filter(filters.RangedFilter(10, 50));

// Add additional filter (accumulates)
chart.filter(filters.RangedFilter(70, 90));

// Remove specific filter
chart.filter(filters.RangedFilter(10, 50));

// Clear all filters
chart.filterAll();

// Replace all filters
chart.replaceFilter(filters.RangedFilter(20, 40));

Performance Considerations

Filter Efficiency

  • RangedFilter: Most efficient for numeric ranges
  • TwoDimensionalFilter: Efficient for exact point matching
  • RangedTwoDimensionalFilter: Good for rectangular selections
  • HierarchyFilter: Performance depends on path depth and data structure

Memory Usage

Filters are lightweight objects, but in high-interaction scenarios consider:

// Avoid creating filters in tight loops
chart.on('brushmove', function(chart) {
  // Bad: Creates new filter object on every mouse move
  const filter = filters.RangedFilter(brush.start, brush.end);
  
  // Better: Reuse filter objects or batch filter updates
});

Types

interface FiltersNamespace {
  RangedFilter: (low: number, high: number) => RangedFilterObject;
  TwoDimensionalFilter: (key: [any, any]) => TwoDimensionalFilterObject;
  RangedTwoDimensionalFilter: (filter: [[any, any], [any, any]]) => RangedTwoDimensionalFilterObject;
  HierarchyFilter: (path: any[]) => HierarchyFilterObject;
}

interface FilterObject {
  isFiltered: (value: any) => boolean;
  filterType: string;
}

interface RangedFilterObject extends Array<number>, FilterObject {
  filterType: 'RangedFilter';
  isFiltered: (value: number) => boolean;
}

interface TwoDimensionalFilterObject extends Array<any>, FilterObject {
  filterType: 'TwoDimensionalFilter';
  isFiltered: (value: [any, any]) => boolean;
}

interface RangedTwoDimensionalFilterObject extends Array<[any, any]>, FilterObject {
  filterType: 'RangedTwoDimensionalFilter';
  isFiltered: (value: [any, any]) => boolean;
}

interface HierarchyFilterObject extends Array<any>, FilterObject {
  filterType: 'HierarchyFilter';
  isFiltered: (value: any[]) => boolean;
}

interface FilterHandlers {
  filterHandler: (handler: (dimension: any, filters: any[]) => any[]) => Chart;
  hasFilterHandler: (handler: (filters: any[], filter: any) => boolean) => Chart;
  addFilterHandler: (handler: (filters: any[], filter: any) => any[]) => Chart;
  removeFilterHandler: (handler: (filters: any[], filter: any) => any[]) => Chart;
  resetFilterHandler: (handler: (filters: any[]) => any[]) => Chart;
}