Skip to main content

Volumetric Density-Equalizing Reference Map — 3D shape deformation and 2D cartogram generation

Project description

diffusion-cartogram

PyPI version GitHub release Python 3.8+ License: MIT

Density-Equalizing Reference Map — a Python implementation of the VDERM algorithm for 3D shape deformation and (new in v2.0) 2D cartogram generation from GeoJSON / Shapefile inputs.

Overview

diffusion-cartogram implements the Volumetric Density-Equalizing Reference Map (VDERM) method by Choi & Rycroft (2020). VDERM is a 3D generalization of the diffusion-based cartogram method, enabling volume-preserving deformations of 3D objects based on prescribed density distributions.

v2.0 extends this to 2D using the same diffusion-advection process — no FFTs, just the VDERM physics with one spatial dimension removed — making 2D cartograms straightforward to produce from standard geographic files.

Applications

  • 3D data visualization and cartograms
  • 2D geographic cartograms from GeoJSON / Shapefiles
  • Adaptive mesh refinement
  • Shape modeling and morphing

Key Features

  • 3D: Fast regular grid interpolation, STL / VTK / XYZ export, optional PyMeshLab mesh support
  • 2D (new): GeoJSON and Shapefile input, GeoTIFF built-in densities, 2D scatter / heatmap visualization
  • Comprehensive matplotlib animations for both 2D and 3D pipelines
  • Progress tracking with intermediate state exports
  • Automatic grid sizing with customizable padding

Installation

Base / lite (no optional dependencies)

pip install diffusion-cartogram

With 2-D geographic I/O (GeoJSON, Shapefile, GeoTIFF)

pip install diffusion-cartogram[2D]

With 3-D mesh support (STL, OBJ, Poisson reconstruction)

pip install diffusion-cartogram[3D]

Full installation

pip install diffusion-cartogram[all]

Development

git clone https://github.com/jspector792/diffusion-cartogram.git
cd diffusion-cartogram
pip install -e .[all]

Quick Start — 3D

import diffusion_cartogram as vd
import numpy as np

# 1. Load a mesh and sample a surface point cloud
surface_points, normals = vd.create_pcd('mesh.stl', n_pts=25000)

# 2. Create computational grid (automatically sized)
params = vd.make_initial_grid(surface_points, max_points=32768)

# 3. Initialize VDERM grid and set density
grid = vd.VDERMGrid(params['shape'], params['h'], params['min_bounds'])

def my_density(x, y, z):
    r = np.sqrt((x - 1.5)**2 + (y - 1.5)**2 + (z - 1.5)**2)
    return 1.0 + 3.0 * np.exp(-5 * r**2)

grid.set_density(my_density)

# 4. Run deformation
result = vd.run_VDERM(grid, n_max=100, max_eps=0.02)

# 5. Apply deformation to surface and export
final_surface = vd.interpolate_to_surface(
    surface_points, params, result.get_displacement_field()
)
vd.export_mesh_file('deformed_mesh.stl', final_surface)

Quick Start — 2D Cartogram

import diffusion_cartogram as vd

# 1. Load geographic boundary (GeoJSON or Shapefile)
pts, crs = vd.read_geojson('countries.geojson')   # or read_shapefile()

# 2. Create 2D grid sized to the data
params = vd.make_initial_grid_2d(pts, max_points=16384)
grid = vd.VDERMGrid2D(params['shape'], params['h'], params['min_bounds'])

# 3. Set density from a GeoTIFF (e.g. population raster)
vd.density_from_geotiff(grid, 'population.tif')
# or define analytically:  grid.set_density(lambda x, y: ...)

# 4. Run deformation — run_VDERM works for both 2D and 3D grids
result = vd.run_VDERM(grid, n_max=200, max_eps=0.02)

# 5. Apply deformation to map points
deformed = vd.interpolate_to_map_2d(
    pts, params, result.get_displacement_field()
)

# 6. Visualize
dens = vd.interpolate_densities_2d(pts, result)
vd.plot_map_before_after(pts, deformed, densities=dens,
                         title='Population Cartogram')

Examples

Detailed Jupyter notebook examples are in the examples/ directory:

  • 01_quickStart.ipynb: Basic 3-D workflow and concepts
  • 02_boundaryConditions.ipynb: Boundary condition effects
  • 03_densityFields.ipynb: Different density functions
  • 04_tracking.ipynb: Animations and intermediate exports
  • 05_diffusion-cartogram_lite.ipynb: 3-D point-cloud workflow without mesh dependencies
  • 06_2D_quickStart.ipynb: 2-D quick start — 2×2 grid from scratch (base install)
  • 07_worldCartogram.ipynb: World population cartogram from GeoJSON / Shapefile / GeoTIFF (pip install diffusion-cartogram[2D])
  • 08_2D_lite.ipynb: 2-D lite mode — XY CSV files only (base install)

File Formats

3D — XYZ (space-delimited text)

# 3 cols: positions only
x y z
# 4 cols: positions + density
x y z rho
# 6 cols: positions + normals / velocities
x y z n_x n_y n_z
# 7 cols: complete
x y z n_x n_y n_z rho

2D — CSV (space-delimited text)

# 2 cols: positions only
x y
# 3 cols: positions + density
x y rho

Geographic inputs: GeoJSON, Shapefile (via geopandas), GeoTIFF density rasters (via rasterio).

Tips

Grid Resolution

  • Quick test / 2D: 4 000–16 000 points (64²–128²)
  • Standard 3D: 30 000–50 000 points (30–35³)
  • High quality 3D: 100 000–250 000 points (45–60³)

Density Field Design

  • Keep densities positive: ρ > 0
  • Avoid sharp discontinuities near object boundaries
  • Embed large gradients in a uniform density sea rather than against a wall

Numerical Stability

If epsilon becomes very large or negative, reduce the timestep:

vd.run_VDERM(grid, dt=0.001)

Known issues

macOS + conda: OpenMP conflict with pymeshlab (3D only)

Users running the 3D reconstruction features (export_mesh_file, export_mesh_vtk) on macOS in a conda environment may encounter a hard crash:

OMP: Error #15: Initializing libomp.dylib, but found libomp.dylib already initialized.

This is caused by a conflict between the OpenMP runtime bundled inside pymeshlab's wheel and the one loaded by conda-forge's numpy/scipy. It is not specific to diffusion-cartogram — it will occur with any package that uses both pymeshlab and conda-forge numpy on macOS.

Fix: Replace pymeshlab's bundled libomp.dylib with a symlink to conda's. Both are LLVM OpenMP with the same ABI, so this is safe. The file to replace is at $CONDA_PREFIX/lib/python*/site-packages/pymeshlab/Frameworks/libomp.dylib. See this discussion for approaches and context. Note that the fix is environment-level and will need to be reapplied if pymeshlab is reinstalled or upgraded.

Dependencies

Dependency Required for
numpy, scipy, matplotlib, tqdm Always required
geopandas, rasterio, shapely 2-D geographic I/O (pip install diffusion-cartogram[2D])
pymeshlab 3-D mesh I/O and reconstruction (pip install diffusion-cartogram[3D])

Citation

If you use this package in academic work, please cite the appropriate original paper(s):

@article{choi2021volumetric,
  title={Volumetric density-equalizing reference map with applications},
  author={Choi, Gary Pui-Tung and Rycroft, Chris H},
  journal={Journal of Scientific Computing},
  volume={86},
  number={3},
  pages={1--26},
  year={2021},
  publisher={Springer}
}

@article{gastner2004,
  title   = {Diffusion-based method for producing density-equalizing maps},
  author  = {Gastner, Michael T. and Newman, M. E. J.},
  journal = {Proceedings of the National Academy of Sciences},
  volume  = {101},
  number  = {20},
  pages   = {7499--7504},
  year    = {2004},
  doi     = {10.1073/pnas.0400280101}
}

And optionally, this implementation:

@software{vderm2026,
  title={diffusion-cartogram: A Python implementation of Volumetric Density-Equalizing Reference Map},
  author={Jonah Spector},
  year={2026},
  url={https://github.com/jspector792/diffusion-cartogram}
}

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

  • Original VDERM algorithm by Gary P.T. Choi and Chris H. Rycroft
  • Based on the diffusion cartogram method by Gastner & Newman (2004)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

diffusion_cartogram-0.2.0.tar.gz (52.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

diffusion_cartogram-0.2.0-py3-none-any.whl (42.2 kB view details)

Uploaded Python 3

File details

Details for the file diffusion_cartogram-0.2.0.tar.gz.

File metadata

  • Download URL: diffusion_cartogram-0.2.0.tar.gz
  • Upload date:
  • Size: 52.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for diffusion_cartogram-0.2.0.tar.gz
Algorithm Hash digest
SHA256 1c06497f0bc9902b29496697c54fbd273b74710d7ff563fbad631ac7757f21ac
MD5 a1e357b5b0d9ee4e2b104a3ff1ece021
BLAKE2b-256 97dad33e361c5e3e69f7807539478022762ba60f80258a95f997a6b9da1a8db3

See more details on using hashes here.

File details

Details for the file diffusion_cartogram-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for diffusion_cartogram-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9be63bd846ec963c225b21337cd4db25fc7e5b309ea7b5c111a80322f214645b
MD5 dcfb260ff0b5ec8b9cbf5f86f1baa467
BLAKE2b-256 50966eb26ef71c1b908a3dea2f8079eb2845539a344caef0ba0f45edda27afdd

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page