Volumetric Density-Equalizing Reference Map — 3D shape deformation and 2D cartogram generation
Project description
diffusion-cartogram
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c06497f0bc9902b29496697c54fbd273b74710d7ff563fbad631ac7757f21ac
|
|
| MD5 |
a1e357b5b0d9ee4e2b104a3ff1ece021
|
|
| BLAKE2b-256 |
97dad33e361c5e3e69f7807539478022762ba60f80258a95f997a6b9da1a8db3
|
File details
Details for the file diffusion_cartogram-0.2.0-py3-none-any.whl.
File metadata
- Download URL: diffusion_cartogram-0.2.0-py3-none-any.whl
- Upload date:
- Size: 42.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9be63bd846ec963c225b21337cd4db25fc7e5b309ea7b5c111a80322f214645b
|
|
| MD5 |
dcfb260ff0b5ec8b9cbf5f86f1baa467
|
|
| BLAKE2b-256 |
50966eb26ef71c1b908a3dea2f8079eb2845539a344caef0ba0f45edda27afdd
|