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

hexagon-layer.mddocs/

Hexagon Layer

HexagonLayer aggregates data into a hexagonal grid-based heatmap. It bins data points into hexagonal cells and can visualize both color and elevation based on aggregated values, making it ideal for geographic data visualization with natural spatial distribution.

Capabilities

HexagonLayer Class

Creates a layer that aggregates data points into hexagonal bins with configurable radius and optional 3D extrusion.

/**
 * Aggregate data into a hexagonal grid-based heatmap
 * @param props - Configuration properties for the hexagon layer
 */
class HexagonLayer<DataT = any> extends AggregationLayer<DataT, HexagonLayerProps<DataT>> {
  constructor(props: HexagonLayerProps<DataT>);
}

interface HexagonLayerProps<DataT> extends LayerProps {
  /** Array of data objects to aggregate */
  data: DataT[];
  /** Function to extract position from data object (default: d => d.position) */
  getPosition?: Accessor<DataT, Position>;
  /** Function to extract weight value for color aggregation (default: 1) */
  getColorWeight?: Accessor<DataT, number>;
  /** Function to extract weight value for elevation aggregation (default: 1) */
  getElevationWeight?: Accessor<DataT, number>;
  /** After data objects are aggregated into cells, this accessor is called on each cell to get the value that its color is based on. Not supported by GPU aggregation. */
  getColorValue?: AggregateAccessor<DataT> | null;
  /** After data objects are aggregated into cells, this accessor is called on each cell to get the value that its elevation is based on. Not supported by GPU aggregation. */
  getElevationValue?: AggregateAccessor<DataT> | null;
  /** Radius of hexagons in meters (default: 1000) */
  radius?: number;
  /** Cell size multiplier (0-1) (default: 1) */
  coverage?: number;
  /** Whether to extrude hexagons in 3D (default: false) */
  extruded?: boolean;
  /** Cell elevation multiplier (default: 1) */
  elevationScale?: number;
  /** Aggregation operation for color values (default: 'SUM') */
  colorAggregation?: AggregationOperation;
  /** Aggregation operation for elevation values (default: 'SUM') */
  elevationAggregation?: AggregationOperation;
  /** Array of colors for the color scale (default: 6-class YlOrRd) */
  colorRange?: Color[];
  /** Color scale domain, default is set to the extent of aggregated weights in each cell */
  colorDomain?: [number, number] | null;
  /** Scaling function used to determine the color of the grid cell (default: 'quantize') */
  colorScaleType?: 'quantize' | 'linear' | 'quantile' | 'ordinal';
  /** Elevation scale output range (default: [0, 1000]) */
  elevationRange?: [number, number];
  /** Elevation scale input domain, default is set to between 0 and the max of aggregated weights in each cell */
  elevationDomain?: [number, number] | null;
  /** Scaling function used to determine the elevation of the grid cell (default: 'linear') */
  elevationScaleType?: 'linear';
  /** Whether to use GPU aggregation (default: true) */
  gpuAggregation?: boolean;
  /** Filter cells and re-calculate color by lowerPercentile (0-100) (default: 0) */
  lowerPercentile?: number;
  /** Filter cells and re-calculate color by upperPercentile (0-100) (default: 100) */
  upperPercentile?: number;
  /** Filter cells and re-calculate elevation by elevationLowerPercentile (0-100) (default: 0) */
  elevationLowerPercentile?: number;
  /** Filter cells and re-calculate elevation by elevationUpperPercentile (0-100) (default: 100) */
  elevationUpperPercentile?: number;
  /** Custom accessor to retrieve a hexagonal bin index from each data object. Not supported by GPU aggregation. */
  hexagonAggregator?: ((position: number[], radius: number) => [number, number]) | null;
  /** Material settings for lighting effect. Applies if extruded: true */
  material?: Material;
  /** This callback will be called when bin color domain has been calculated */
  onSetColorDomain?: (minMax: [number, number]) => void;
  /** This callback will be called when bin elevation domain has been calculated */
  onSetElevationDomain?: (minMax: [number, number]) => void;
}

interface HexagonLayerPickingInfo<DataT = any> extends PickingInfo<DataT> {
  /** The aggregated bin data */
  object: AggregatedBin | null;
  /** Hexagon coordinates [i, j] */
  index: [number, number];
  /** Total count of points in the bin */
  count: number;
  /** Aggregated color value for the bin */
  colorValue?: number;
  /** Aggregated elevation value for the bin */
  elevationValue?: number;
  /** Array indices of points in this bin (CPU aggregation only) */
  pointIndices?: number[];
}

Usage Examples:

import { HexagonLayer } from "@deck.gl/aggregation-layers";

// Basic hexagon layer for population density
const populationLayer = new HexagonLayer({
  id: "population-hexagons",
  data: censusData,
  getPosition: (d) => [d.longitude, d.latitude],
  getColorWeight: (d) => d.population,
  getElevationWeight: (d) => d.population, 
  radius: 5000, // 5km radius
  extruded: true,
  elevationScale: 4,
  colorRange: [
    [255, 255, 204],
    [199, 233, 180],
    [127, 205, 187],
    [65, 182, 196],
    [29, 145, 192],
    [34, 94, 168],
    [12, 44, 132]
  ],
  pickable: true
});

// Advanced configuration with dual aggregation
const trafficLayer = new HexagonLayer({
  id: "traffic-analysis",
  data: trafficData,
  getPosition: (d) => d.coords,
  getColorWeight: (d) => d.accidents, // Color by accident count
  getElevationWeight: (d) => d.volume, // Height by traffic volume
  radius: 2000,
  coverage: 0.8,
  extruded: true,
  elevationScale: 10,
  colorAggregation: 'SUM',
  elevationAggregation: 'MEAN',
  colorRange: [
    [0, 255, 0, 128],    // Green for low accidents
    [255, 255, 0, 128],  // Yellow for medium
    [255, 0, 0, 128]     // Red for high accidents
  ],
  elevationRange: [0, 500],
  colorScaleType: 'quantize',
  elevationScaleType: 'linear',
  gpuAggregation: true,
  pickable: true,
  onHover: (info) => {
    if (info.object) {
      console.log(`Accidents: ${info.colorValue}, Volume: ${info.elevationValue}`);
    }
  }
});

Hexagon Configuration

Controls the size and appearance of hexagonal bins.

/** Radius of hexagons in meters (default: 1000) */
radius?: number;

/** Cell size multiplier, 0-1 where 1 = full size (default: 1) */
coverage?: number;

/** Whether to extrude hexagons in 3D (default: false) */
extruded?: boolean;

/** Custom hexagon aggregator function for advanced binning */
hexagonAggregator?: ((position: number[], radius: number) => [number, number]) | null;

Color Configuration

Controls color mapping for hexagonal cells based on aggregated values.

/** Function to extract weight value for color aggregation */
getColorWeight?: Accessor<DataT, number>;

/** Aggregation operation for color values (default: 'SUM') */
colorAggregation?: AggregationOperation;

/** Array of colors for the color scale */
colorRange?: Color[];

/** Domain for color scale [min, max] */
colorDomain?: [number, number] | null;

/** Scaling function used to determine the color of the grid cell (default: 'quantize') */
colorScaleType?: 'quantize' | 'linear' | 'quantile' | 'ordinal';

/** Filter cells and re-calculate color by lowerPercentile (0-100) (default: 0) */
lowerPercentile?: number;

/** Filter cells and re-calculate color by upperPercentile (0-100) (default: 100) */
upperPercentile?: number;

Elevation Configuration

Controls 3D height of hexagons when extruded is true.

/** Function to extract weight value for elevation aggregation */
getElevationWeight?: Accessor<DataT, number>;

/** Aggregation operation for elevation values (default: 'SUM') */
elevationAggregation?: AggregationOperation;

/** Range of elevation values [min, max] (default: [0, 1000]) */
elevationRange?: [number, number];

/** Domain for elevation scale [min, max] */
elevationDomain?: [number, number] | null;

/** Scale factor for elevation values (default: 1) */
elevationScale?: number;

/** Scaling function used to determine the elevation of the grid cell (default: 'linear') */
elevationScaleType?: 'linear';

/** Filter cells and re-calculate elevation by elevationLowerPercentile (0-100) (default: 0) */
elevationLowerPercentile?: number;

/** Filter cells and re-calculate elevation by elevationUpperPercentile (0-100) (default: 100) */
elevationUpperPercentile?: number;

/** Material properties for 3D rendering */
material?: Material;

Hexagonal Binning Algorithm

The layer uses a hexagonal binning algorithm that:

  • Maps geographic coordinates to hexagonal grid coordinates
  • Handles edge cases at hexagon boundaries
  • Supports custom aggregator functions for specialized use cases
  • Optimizes for both CPU and GPU computation
// Built-in hexagon utilities (from hexbin.ts)
const HexbinVertices: number[][];

function pointToHexbin([px, py]: Point, radius: number): HexBin;
function getHexbinCentroid([i, j]: HexBin, radius: number): Point;

// GLSL shader functions for GPU computation
const pointToHexbinGLSL: string;
const getHexbinCentroidGLSL: string;

Performance Considerations

  • Radius Size: Smaller radii create more bins and require more computation
  • GPU vs CPU: GPU aggregation recommended for >100K points
  • Extrusion: 3D rendering has higher GPU memory requirements
  • Coverage: Lower coverage values reduce overlapping geometry

Common Patterns

// Population density with elevation
const densityLayer = new HexagonLayer({
  id: "density",
  data: populationData,
  getPosition: (d) => d.coordinates,
  getColorWeight: (d) => d.population,
  getElevationWeight: (d) => d.population,
  radius: 10000,
  extruded: true,
  elevationScale: 2,
  colorAggregation: 'SUM',
  elevationAggregation: 'SUM'
});

// Temporal analysis with separate metrics
const temporalLayer = new HexagonLayer({
  id: "temporal",
  data: timeSeriesData,
  getPosition: (d) => [d.lng, d.lat],
  getColorWeight: (d) => d.dayCount,    // Daytime activity
  getElevationWeight: (d) => d.nightCount, // Nighttime activity
  radius: 3000,
  extruded: true,
  colorAggregation: 'MEAN',
  elevationAggregation: 'MEAN',
  colorRange: [[255, 255, 0], [255, 0, 0]], // Yellow to red
  elevationScale: 5
});