gridmapper

GridMapper

npm version build license stars

A JavaScript library for allocating geographic points to a grid using Mixed Integer Programming (MIP). This library provides an optimized solution for spatial data visualization by mapping geographic coordinates to grid cells while preserving spatial relationships.

see the demo for the interactive demo and usage example.

Inspiration

This library is inspired by and builds upon the work of Jo Wood’s Grid Map Allocation library (@gridmap_allocation). The original implementation demonstrated the concept of using linear programming to allocate geographic points to grid cells. This library extends that work with small additional features and optimisations.

Features

Installation

npm install gridmapper

Quick Start

Simple API (matching original library)

import { GridMapper } from 'gridmapper';
import { GLPKSolver } from 'gridmapper/glpk-solver';
import glpk from 'glpk.js';

const glpkInstance = await glpk();
const mapper = new GridMapper();

const points = [
  [longitude1, latitude1],
  [longitude2, latitude2],
  // ... more points
];

const result = await mapper.allocateSimple(
  points,
  7,   // rows
  12,  // cols
  0.6, // compactness (0-1)
  [],  // spacers
  {
    mip: () => new GLPKSolver(glpkInstance)
  }
);

console.log(result.cells); // [[row, col], ...]

Advanced API

import { GridMapper } from 'gridmapper';
import { GLPKSolver } from 'gridmapper/glpk-solver';
import glpk from 'glpk.js';

const glpkInstance = await glpk();
const mapper = new GridMapper();

const data = [
  { name: 'Location A', lon: -74.0, lat: 40.7 },
  { name: 'Location B', lon: -73.9, lat: 40.8 },
  // ... more locations
];

const result = await mapper.allocate(data, {
  xAccessor: d => d.lon,
  yAccessor: d => d.lat,
  compactness: 0.6,
  rotateByPCA: true,  // Align grid to principal axis
  gridType: 'rect',    // or 'hex'
  mip: () => new GLPKSolver(glpkInstance)
  // rows and cols are auto-calculated if not provided
});

// Result includes gridX and gridY properties added to each data item
result.assignments.forEach(item => {
  console.log(`${item.name}: grid[${item.gridX}, ${item.gridY}]`);
});

API Reference

GridMapper

allocateSimple(points, nRows, nCols, compactness, spacers, options)

Simple allocation API matching the original Jo Wood library.

Parameters:

Returns: Promise<Object> with { nRows, nCols, cells: [[row, col], ...] }

allocate(data, options)

Advanced allocation API with extended features.

Parameters:

Returns: Promise<Object> with { assignments: [...], meta: {...} }

Utility Functions

GeoJSON Export

The library provides utilities to export grid cartograms as GeoJSON for use in mapping libraries or GIS tools:

import { createGridGeoJson, createPointsGeoJson } from 'gridmapper';

// After allocation
const result = await mapper.allocate(data, options);

// Create GeoJSON for grid polygons (supports both 'rect' and 'hex' grid types)
// You can pass gridType directly or pass result.meta for convenience
const gridGeoJson = createGridGeoJson(
  result.assignments,
  result.meta.bounds,
  result.meta  // Automatically uses gridType from meta
);
// Or specify explicitly:
// const gridGeoJson = createGridGeoJson(result.assignments, result.meta.bounds, 'hex');

// Create GeoJSON for input points
const pointsGeoJson = createPointsGeoJson(data);

// Export to file or use with mapping libraries
console.log(JSON.stringify(gridGeoJson, null, 2));

createGridGeoJson(assignments, bounds, gridType)

createPointsGeoJson(data)

Parameter Estimation

The library provides utilities to automatically estimate optimal parameters for grid allocation:

import { estimateParameters, estimateParametersFromData } from 'gridmapper';

// Estimate from GeoJSON data
const geojson = {
  type: 'FeatureCollection',
  features: [
    { type: 'Feature', geometry: { type: 'Point', coordinates: [-74.0, 40.7] } },
    // ... more features
  ]
};

const estimatedParams = estimateParameters(geojson, {
  xAccessor: d => d.lon,
  yAccessor: d => d.lat
});

// Use estimated parameters
const result = await mapper.allocate(data, {
  ...estimatedParams,
  mip: () => new GLPKSolver(glpkInstance)
});

// Or estimate from processed data points
const data = [
  { name: 'Location A', lon: -74.0, lat: 40.7 },
  // ... more locations
];

const params = estimateParametersFromData(data, {
  xAccessor: d => d.lon,
  yAccessor: d => d.lat
});

estimateParameters(geojson, options)

estimateParametersFromData(data, options)

Examples

See the examples/ directory for complete working examples:

Project Structure

The library is organized into clear modules following best practices:

src/
  ├── index.js                    # Main entry point, re-exports
  │
  ├── core/                       # Core allocation logic
  │   ├── grid-mapper.js          # Main GridMapper class (orchestrator)
  │   ├── allocation-engine-simple.js    # Simple MIP allocation
  │   └── allocation-engine-advanced.js  # Advanced MIP allocation
  │
  ├── grid/                       # Grid utilities
  │   └── grid-factory.js         # Grid creation and manipulation
  │
  ├── normalization/              # Point transformation
  │   ├── point-normalizer.js     # Point normalization logic
  │   └── bounds-calculator.js    # Bounds calculation
  │
  ├── features/                   # Advanced features
  │   ├── pca-rotation.js         # PCA rotation utilities
  │   ├── spacer-utils.js         # Spacer computation
  │   └── auto-dimensions.js      # Auto grid dimension calculation
  │
  ├── post-processing/            # Optimization algorithms
  │   └── optimizer.js            # Greedy swaps + simulated annealing
  │
  ├── solvers/                    # MIP solver adapters
  │   └── glpk-solver.js          # GLPK solver adapter
  │
  └── utils/                      # Output utilities
      ├── geojson-utils.js        # GeoJSON output formatting
      └── parameter-estimator.js  # Parameter estimation utilities

Module Organization

This structure provides:

Building

npm install
npm run build

This will create bundled versions in the dist/ directory:

Development

The library uses:

For development with watch mode:

npm run dev

CI Publishing (Draft releases)

Notes:

Automatic changelog & versioning

This project is licensed under the ISC License — see the LICENSE file for details.

Acknowledgments

© 2025 danylaksono