or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

aggregation-systems.mdcontour-layer.mdgrid-layer.mdheatmap-layer.mdhexagon-layer.mdindex.mdscreen-grid-layer.md
tile.json

aggregation-systems.mddocs/

Aggregation Systems

The aggregation systems provide high-performance data processing capabilities for all aggregation layers. The package includes both GPU-accelerated (WebGLAggregator) and CPU-based (CPUAggregator) implementations, enabling optimal performance across different data sizes and hardware capabilities.

Capabilities

WebGLAggregator Class

GPU-based aggregation implementation using WebGL compute shaders for high-performance processing of large datasets.

/**
 * GPU-based aggregation implementation using WebGL compute shaders
 * @param props - Configuration properties for WebGL aggregation
 */
class WebGLAggregator implements Aggregator {
  constructor(props: WebGLAggregatorProps);
  
  /** Check if WebGL aggregation is supported on the current device */
  static isSupported(device: Device): boolean;
  
  /** Update aggregator properties */
  setProps(props: Partial<AggregationProps>): void;
  
  /** Mark aggregator as needing update for specific channel */
  setNeedsUpdate(channel?: number): void;
  
  /** Execute the aggregation computation */
  update(): void;
  
  /** Prepare for rendering (called before draw) */
  preDraw(): void;
  
  /** Clean up resources */
  destroy(): void;
  
  /** Get aggregated bin data as binary attribute */
  getBins(): BinaryAttribute | null;
  
  /** Get aggregation result for specific channel */
  getResult(channel: number): BinaryAttribute | null;
  
  /** Get the value domain [min, max] for specific channel */
  getResultDomain(channel: number): [min: number, max: number];
  
  /** Get individual bin data by index */
  getBin(index: number): AggregatedBin | null;
}

interface WebGLAggregatorProps extends AggregationProps {
  /** Number of dimensions (1 for screen-grid, 2 for hexagon/grid) */
  dimensions: 1 | 2;
  
  /** Number of output channels (1-3) */
  channelCount: 1 | 2 | 3;
  
  /** Buffer layout for input data */
  bufferLayout?: BufferLayout[];
  
  /** Vertex shader source code */
  vs: string;
  
  /** Additional shader modules to include */
  modules?: ShaderModule[];
  
  /** Transform feedback varyings */
  varyings?: string[];
  
  /** Custom uniforms for the shader */
  uniforms?: Record<string, any>;
  
  /** Number of bins in each dimension */
  binIdxToOrd?: number[];
  
  /** Bin sorting configuration */
  binSort?: boolean;
}

CPUAggregator Class

CPU-based aggregation implementation providing full control and debugging capabilities.

/**
 * CPU-based aggregation implementation
 * @param props - Configuration properties for CPU aggregation
 */
class CPUAggregator implements Aggregator {
  constructor(props: CPUAggregatorProps);
  
  /** Update aggregator properties */
  setProps(props: Partial<AggregationProps>): void;
  
  /** Mark aggregator as needing update for specific channel */
  setNeedsUpdate(channel?: number): void;
  
  /** Execute the aggregation computation */
  update(): void;
  
  /** Prepare for rendering (called before draw) */
  preDraw(): void;
  
  /** Clean up resources */
  destroy(): void;
  
  /** Get aggregated bin data as binary attribute */
  getBins(): BinaryAttribute | null;
  
  /** Get aggregation result for specific channel */
  getResult(channel: number): BinaryAttribute | null;
  
  /** Get the value domain [min, max] for specific channel */
  getResultDomain(channel: number): [min: number, max: number];
  
  /** Get individual bin data by index */
  getBin(index: number): AggregatedBin | null;
}

interface CPUAggregatorProps extends AggregationProps {
  /** Number of dimensions for binning */
  dimensions: number;
  
  /** Function to extract bin coordinates from data */
  getBin: VertexAccessor<number[] | null, any>;
  
  /** Array of functions to extract values for each channel */
  getValue: VertexAccessor<number>[];
  
  /** Aggregation operations for each channel */
  operations?: AggregationOperation[];
  
  /** Whether to track point indices in bins (for picking) */
  pointIndices?: boolean;
}

Core Aggregator Interface

Base interface implemented by both WebGL and CPU aggregators.

/**
 * Core aggregator interface for data processing
 */
interface Aggregator {
  /** Update aggregator properties */
  setProps(props: Partial<AggregationProps>): void;
  
  /** Mark aggregator as needing update for specific channel */
  setNeedsUpdate(channel?: number): void;
  
  /** Execute the aggregation computation */
  update(): void;
  
  /** Prepare for rendering (called before draw) */
  preDraw(): void;
  
  /** Clean up resources */
  destroy(): void;
  
  /** Get aggregated bin data as binary attribute */
  getBins(): BinaryAttribute | null;
  
  /** Get aggregation result for specific channel */
  getResult(channel: number): BinaryAttribute | null;
  
  /** Get the value domain [min, max] for specific channel */
  getResultDomain(channel: number): [min: number, max: number];
  
  /** Get individual bin data by index */
  getBin(index: number): AggregatedBin | null;
}

interface AggregationProps {
  /** Input data array */
  data: any[];
  
  /** Accessor function to get position from data */
  getPosition: VertexAccessor<number[]>;
  
  /** Array of accessor functions for value extraction */
  getWeight?: VertexAccessor<number>[];
  
  /** Aggregation operations to apply */
  operations?: AggregationOperation[];
  
  /** Bin configuration parameters */
  binOptions?: BinOptions;
  
  /** Whether aggregation needs update */
  needsUpdate?: boolean;
  
  /** Data change triggers */
  dataChanged?: boolean;
  
  /** Transform change triggers */
  changeFlags?: number;
}

interface AggregatedBin {
  /** Unique bin identifier coordinates */
  id: number[];
  
  /** Aggregated values for each channel */
  value: number[];
  
  /** Number of data points in this bin */
  count: number;
  
  /** Indices of data points in this bin (CPU aggregation only) */
  pointIndices?: number[];
}

Aggregation Operations

Built-in aggregation operations supported by both aggregators.

/** Available aggregation operations */
type AggregationOperation = 'SUM' | 'MEAN' | 'MIN' | 'MAX' | 'COUNT';

/** Aggregation function signature */
type AggregationFunc = (values: number[]) => number;

/** Built-in aggregation operation implementations */
const BUILT_IN_OPERATIONS: Record<AggregationOperation, AggregationFunc>;

// Operation implementations
const SUM: AggregationFunc = (values) => values.reduce((a, b) => a + b, 0);
const MEAN: AggregationFunc = (values) => values.length ? SUM(values) / values.length : 0;
const MIN: AggregationFunc = (values) => Math.min(...values);
const MAX: AggregationFunc = (values) => Math.max(...values);
const COUNT: AggregationFunc = (values) => values.length;

Performance Characteristics

GPU Aggregation (WebGLAggregator):

  • Optimal for datasets > 100,000 points
  • Parallel processing on GPU
  • Limited debugging capabilities
  • Hardware dependent (requires WebGL 2.0)
  • Memory efficient for large datasets

CPU Aggregation (CPUAggregator):

  • Better for smaller datasets (< 100,000 points)
  • Full debugging and inspection capabilities
  • Point indices tracking for advanced picking
  • Platform independent
  • More memory usage for large datasets
// Performance comparison example
const useGPU = data.length > 100000 && WebGLAggregator.isSupported(device);
const aggregator = useGPU 
  ? new WebGLAggregator(gpuProps)
  : new CPUAggregator(cpuProps);

Usage Examples

import { WebGLAggregator, CPUAggregator } from "@deck.gl/aggregation-layers";

// GPU aggregation for large dataset
const gpuAggregator = new WebGLAggregator({
  dimensions: 2, // 2D hexagon binning
  channelCount: 2, // Color and elevation channels
  vs: hexagonVertexShader,
  modules: [aggregationModule],
  bufferLayout: [
    { name: 'positions', format: 'float32x2' },
    { name: 'weights', format: 'float32x2' }
  ]
});

// CPU aggregation with point tracking
const cpuAggregator = new CPUAggregator({
  dimensions: 2,
  getBin: (point) => [
    Math.floor(point[0] / cellSize),
    Math.floor(point[1] / cellSize)
  ],
  getValue: [
    (point) => point.colorWeight,
    (point) => point.elevationWeight
  ],
  operations: ['SUM', 'MEAN'],
  pointIndices: true // Enable for picking support
});

// Configuration and execution
aggregator.setProps({
  data: myData,
  getPosition: (d) => [d.lng, d.lat],
  getWeight: [(d) => d.value1, (d) => d.value2],
  operations: ['SUM', 'SUM']
});

aggregator.update();
const results = aggregator.getResult(0); // Get first channel results
const domain = aggregator.getResultDomain(0); // Get value range

Bin Management

Both aggregators provide bin-level access for detailed analysis and picking.

/** Get individual bin information */
interface BinAccessor {
  /** Get bin by index */
  getBin(index: number): AggregatedBin | null;
  
  /** Get all bins as binary attribute */
  getBins(): BinaryAttribute | null;
  
  /** Get sorted bin indices */
  getBinIds(): number[] | null;
}

// Usage example
const bin = aggregator.getBin(selectedIndex);
if (bin) {
  console.log(`Bin [${bin.id.join(',')}]: ${bin.count} points, values: [${bin.value.join(',')}]`);
  
  // CPU aggregator provides point indices
  if (bin.pointIndices) {
    const originalPoints = bin.pointIndices.map(i => data[i]);
    console.log('Original data points:', originalPoints);
  }
}

Custom Aggregation Operations

Both aggregators support custom aggregation functions:

// Custom aggregation operation
const customOperation: AggregationFunc = (values: number[]) => {
  // Custom logic, e.g., geometric mean
  const product = values.reduce((a, b) => a * b, 1);
  return Math.pow(product, 1 / values.length);
};

// Register custom operation
const customAggregator = new CPUAggregator({
  dimensions: 2,
  getBin: binFunction,
  getValue: [weightFunction],
  operations: [customOperation] // Use custom function
});

Memory Management

Proper resource management is crucial for aggregators:

// Lifecycle management
class AggregationLayerManager {
  private aggregator: Aggregator;
  
  constructor(useGPU: boolean) {
    this.aggregator = useGPU 
      ? new WebGLAggregator(gpuConfig)
      : new CPUAggregator(cpuConfig);
  }
  
  updateData(newData: any[]) {
    this.aggregator.setProps({ data: newData });
    this.aggregator.setNeedsUpdate(); // Mark for update
  }
  
  render() {
    this.aggregator.update(); // Process data
    this.aggregator.preDraw(); // Prepare for rendering
    // ... render layer geometry
  }
  
  cleanup() {
    this.aggregator.destroy(); // Clean up GPU resources
  }
}

Error Handling

Aggregators provide error handling and fallback mechanisms:

// Robust aggregator selection
function createAggregator(data: any[], device: Device): Aggregator {
  // Try GPU first for large datasets
  if (data.length > 50000 && WebGLAggregator.isSupported(device)) {
    try {
      return new WebGLAggregator(gpuConfig);
    } catch (error) {
      console.warn('GPU aggregation failed, falling back to CPU:', error);
    }
  }
  
  // Fallback to CPU aggregation
  return new CPUAggregator(cpuConfig);
}

// Handle aggregation errors
try {
  aggregator.update();
} catch (error) {
  console.error('Aggregation failed:', error);
  // Handle gracefully, possibly with reduced data or different settings
}

Integration with Layers

Aggregators are typically used internally by layer implementations:

// Example layer integration
class CustomAggregationLayer extends AggregationLayer {
  getAggregatorType(): string {
    return this.props.gpuAggregation && this.context.device.features.has('webgl2')
      ? 'webgl' : 'cpu';
  }
  
  createAggregator(type: string): Aggregator {
    const commonProps = {
      data: this.props.data,
      getPosition: this.props.getPosition,
      getWeight: this.props.getWeight ? [this.props.getWeight] : [],
      operations: [this.props.aggregation || 'SUM']
    };
    
    return type === 'webgl'
      ? new WebGLAggregator({ ...commonProps, ...this.getWebGLProps() })
      : new CPUAggregator({ ...commonProps, ...this.getCPUProps() });
  }
}