Skip to main content

weighted-voronoi

Voronoi treemaps from a spreadsheet, in Python and nothing else.

A treemap that tiles a square with cells whose areas are proportional to your weights, nested down a hierarchy — and where the cells are polygons rather than rectangles. Pure Python on top of numpy, scipy, pandas and matplotlib: no external tools to install, nothing to configure.

pip install weighted-voronoi

Excel input needs one extra (quote it — zsh treats the brackets as a glob):

pip install 'weighted-voronoi[excel]'

Quick start

from weighted_voronoi import treemap

fig = treemap("examples/ecoli_proteome_test.csv", label_level="Level2")
fig.savefig("treemap.png", dpi=200)

treemap() takes a path (CSV, TSV or Excel), a file object, CSV/TSV text, or a DataFrame, and returns a matplotlib Figure — so it saves to PNG/SVG/PDF, composes into a larger figure, and displays on its own in a notebook.

A worked example lives in examples/quickstart.ipynb, executed so its figures render without running anything. It covers label levels, styling, DataFrame input, reading the layout back as data, seeds and progress reporting.

Input format

One row per leaf, with the hierarchy spelled out in columns:

Column Meaning
Level1..LevelN the groups the leaf belongs to, outermost first (up to 10 levels)
Name the leaf's own name
Weight a positive number; cell areas follow it
Color optional — #1f77b4, rgb()/rgba(), hsl()/hsla(), or a CSS color name

Rows sharing a level path are grouped, and a group's weight is the sum of its children. Rows with a non-positive weight are dropped, and a blank level cell becomes a group named (none).

Colors are per row. Rows that leave the column blank get one derived from their position in the hierarchy — distinct hues per Level1 group, varied within it — and a group's own swatch is the weight-averaged color of the tiles beneath it.

Command line

weighted-voronoi examples/ecoli_proteome_test.csv -o map.png --level Level2 --label-color contrast
weighted-voronoi examples/microbe_test.xlsx       -o map.svg --borders none --font "Liberation Serif"
weighted-voronoi workbook.xlsx --sheet costs -o map.pdf --random-seed

weighted_voronoi and python -m weighted_voronoi do the same thing. Under uv, without installing anything:

uvx --from weighted-voronoi weighted-voronoi data.csv -o map.png

Output format follows the -o extension: .png, .svg, .pdf or .eps.

Flag Meaning
--level Level2 / --level Name / --level 2 which depth to label
--label-color white|black|contrast contrast picks per label, from the tile's luminance
--borders white|black|none none lets tiles touch
--font "DejaVu Serif" three sans and three serif families, all freely licensed
--seed N, --random-seed reshuffle the layout
--no-legend, --no-frame drop the legend column, drop the frame
--sheet which sheet of an Excel workbook
--size-inches, --dpi output size
--iterations, --convergence trade layout quality against time

--help lists them all.

A large file takes a few seconds to lay out, so there is a progress bar with an estimate of the time left. It appears only when stderr is a terminal, and --no-progress suppresses it. If a map is wanted sooner than exact, --iterations 20 (from the default 50) roughly halves the time, at the price of the worst-fitted tiles drifting from 0.05% to 0.3% of the map.

Rendering options

render(), and the corresponding treemap() keywords:

Argument Values
label_level None/"Name" for the leaves, a level column name, or a 1-based depth
label_color "white", "black", "contrast" (per label, from the tile's luminance)
borders "white", "black", None (tiles touch)
font a key of FONT_STACKS — three sans, three serif, all freely licensed
legend, map_inches, legend_inches, dpi, margin, frame figure geometry

Labels are sized to the room their own cell actually has at the anchor, and dropped when they would come out unreadably small. The default font is DejaVu Sans because matplotlib ships it: the figure looks the same on a machine with no fonts installed at all.

There is no interactivity — no hover tooltips, no rebuild button. Pass a different seed to reshuffle, and re-render to change options. Tile shares are available programmatically: every record from compute_layout() carries value and its path.

Using the layout on its own

weighted_voronoi.layout is useful without any of the spreadsheet machinery above. It needs only numpy and scipy — matplotlib is imported lazily, when something asks to draw.

import numpy as np
from weighted_voronoi.layout import power_diagram, voronoi_map, voronoi_treemap

square = [[0, 0], [0, 900], [900, 900], [900, 0]]

# A power (Laguerre) diagram: one cell per site, heavier sites take more room
# from their neighbours.
cells = power_diagram(np.array([[300., 450.], [600., 450.]]),
                      np.array([5000., 1000.]), square)

# Cells whose *areas* follow the weights, found by relaxation.
result = voronoi_map([1.0, 2.0, 4.0, 8.0], square, seed=0)
result["cells"], result["converged"], result["area_error_ratio"]

# The same, recursively, down a hierarchy of dicts.
records = voronoi_treemap({"name": "root", "children": [...]}, square, seed=0)

# Anything slow enough to be worth watching takes a progress callback.
records = voronoi_treemap(tree, square, seed=0,
                          progress=lambda done, total: print(done, "of", total))

Nothing in there knows about spreadsheets, colors or pandas. Cell areas land within 0.2% of the weights they were asked for, and every loop is bounded — no input hangs the layout, and no seed needs retrying.

Speed is set by the number of nodes: 14 nodes lay out in 0.07 s, 1080 in about 5 s.

In the browser

milo-lab-public.gitlab.io/weighted-voronoi is this package running under Pyodide: pick a spreadsheet and the layout is computed by weighted_voronoi.layout in WebAssembly. The file never leaves your machine — it is read in the browser. Exports are SVG, PNG and PDF.

It is a demonstration, not a replacement: the page downloads ~86 MB of wheels, and WebAssembly runs the layout about 2.6× slower again — a 1000-leaf file takes roughly 12 s. Small maps are comfortable.

The page is index.html, which Pages publishes from the default branch. It is generated from the package, not written by hand:

python tools/build_web.py

The markup lives beside the builder in tools/template.html. The builder pastes the package's own modules in verbatim, and tests/test_web_page.py regenerates and compares, so the committed page cannot fall behind the source.

Tests

pip install 'weighted-voronoi[test]'
python -m pytest tests -q

Without that extra the suite still passes; only the Excel tests skip.

tests/golden/reference.json holds expected layout outputs, captured once and checked in; test_reference_parity.py checks against them. tests/golden/regenerate.py says what regenerating it takes, and refuses to run rather than guessing. Never edit it by hand.

Releasing

Tagging is the whole procedure. CI runs the suite on every push, and on a v* tag it builds a wheel and an sdist, checks them, and uploads to PyPI via Trusted Publishing — no token stored here.

# bump `version` in pyproject.toml first -- CI refuses a tag that disagrees
git tag v0.1.1 && git push origin v0.1.1

Licensing

This package's own code is MIT, in LICENSE. layout/ is a derived work: power.py and clip.py port d3-weighted-voronoi, relax.py ports d3-voronoi-map, treemap.py ports d3-voronoi-treemap — all BSD 3-Clause, Copyright (c) 2018, LEBEAU Franck — and clip.py is additionally derived from D3 (BSD 3-Clause, Copyright 2010-2017 Mike Bostock).

No JavaScript is redistributed here, but a port is a derived work, so the notices travel with it: see weighted_voronoi/THIRD-PARTY-LICENSES.md, which ships inside the installed package and in the wheel.

parsing.py and drawing.py are copies of files in the origin project's python/proteomap/. Nothing enforces that they stay copies — if you change the parsing rules in one place, change them in all three.

Download files

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

Source Distribution

weighted_voronoi-0.1.0.tar.gz (65.0 kB view details)

Uploaded Source

Built Distribution

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

weighted_voronoi-0.1.0-py3-none-any.whl (49.7 kB view details)

Uploaded Python 3

File details

Details for the file weighted_voronoi-0.1.0.tar.gz.

File metadata

  • Download URL: weighted_voronoi-0.1.0.tar.gz
  • Upload date:
  • Size: 65.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for weighted_voronoi-0.1.0.tar.gz
Algorithm Hash digest
SHA256 db64dbb0eb3048153ac417d91dc5ae7ee9328bc2e1463d58865f634befa3ceea
MD5 aa2bd644b3fac4d0e11fe63d9fbc6328
BLAKE2b-256 c0b458bc3e42f73f66dbcfebc6b257a7c807a420bd2c5ced40dd8cca435ff4ab

See more details on using hashes here.

File details

Details for the file weighted_voronoi-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: weighted_voronoi-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 49.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for weighted_voronoi-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a2189321fadaad2d16cd03cefb5406561cddad2b2a017e2150e9d2f331000f19
MD5 c9811b91fbbdd4ba82a874ab595c27be
BLAKE2b-256 f24a54bd519f805d60129c80d98dff21f9e79c8dfdc42534927946110c4cd3fb

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 Sentry Error logging StatusPage Status page