Skip to main content

Circular ("fan") dendrograms for Python, in the visual style of R's ape package

Project description

dendrofan

DOI

Circular ("fan") dendrograms for Python, in the visual style of R's ape package (plot.phylo(type = "fan"), Paradis & Schliep, 2019) — computed and rendered entirely with NumPy, SciPy, and Matplotlib. No R dependency, no reimplementation of clustering.

Why this exists

scipy.cluster.hierarchy has no circular/fan layout. The usual workaround is a one-off script: call scipy.cluster.hierarchy.dendrogram(..., no_plot=True), take its rectangular icoord/dcoord output, and manually re-project it into polar coordinates with Matplotlib. That works for one figure, but it tends to:

  • assume a full 360° circle with no gap for labels at the seam,
  • divide by dcoord.max() without checking for a degenerate, all-zero-height tree,
  • hardcode SciPy's 10-units-per-leaf spacing convention,
  • have no story for trees with 1 or 2 leaves,
  • mix clustering, geometry, and plotting into a single script, so none of it is reusable for the next dataset.

dendrofan factors the actually-reusable idea — the rectangular-to-polar coordinate transform — into a small, tested, documented library, and builds a real plotting API on top of it.

Install

pip install -e .          # from a source checkout
pip install -e ".[dev]"   # + pytest, for running the test suite

Quick start

import numpy as np
from dendrofan import circular_dendrogram

rng = np.random.default_rng(0)
data = rng.normal(size=(20, 6))
labels = [f"sample_{i:02d}" for i in range(20)]

result = circular_dendrogram(
    data,
    labels=labels,
    method="ward",       # forwarded to scipy.cluster.hierarchy.linkage
    span=350,             # leave a small angular gap at the seam
    inner_radius=0.15,    # small central gap, ape's fan style
)
result.fig.savefig("tree.png", dpi=200, bbox_inches="tight")

circular_dendrogram accepts the same three kinds of input as SciPy's own dendrogram: raw observations (data=...), a precomputed linkage matrix (Z=...), or a precomputed condensed distance vector (condensed_distances=...).

See examples/quickstart.py and examples/reproduce_station_dendrogram.py (a fully worked, colored-by-group example) for more.

What it handles that the ad hoc version didn't

Case Ad hoc script dendrofan
Angular gap at the seam (for label room) not supported (full circle only) span=350 (or any value <= 360)
All-merge-heights-equal-zero tree ZeroDivisionError / silent NaNs falls back to placing all nodes at the leaf radius
1 or 2 leaves untested, breaks silently validated; raises DegenerateTreeError for < 2, works for 2
Mismatched label count silent misalignment raises LabelMismatchError
Invalid linkage matrix / distance vector undefined behavior raises InvalidLinkageError before plotting
Root at centre vs. rim, radius scale hardcoded linear, root-at-centre inner_radius/outer_radius/invert_radius, plus optional "sqrt" area-preserving radius scale
Per-clade coloring manual, one-off color_threshold/link_color_func forwarded to SciPy, or a label_colors dict/callable
Scale reference / clade highlighting not present dendrofan.annotations.add_scale_ring, highlight_sector
Reuse across datasets copy-paste the script one function call

API overview

  • dendrofan.circular_dendrogram(...) — the main entry point; draws the tree and returns a CircularDendrogramResult (figure, axes, layout, and the PolarTransform used, for further annotation).
  • dendrofan.geometry.PolarTransform — the reusable rectangular-to-polar coordinate map, if you want to bend your own geometry onto the same annulus (e.g. a custom decoration).
  • dendrofan.clustering.build_layout(...) — validated wrapper around scipy.cluster.hierarchy.linkage / dendrogram, decoupled from plotting.
  • dendrofan.styling.resolve_leaf_colors, legend_handles — color and legend helpers.
  • dendrofan.annotations.add_scale_ring, highlight_sector — optional decorations (a distance-reference ring; shaded clade sectors).

Every public function and class has a full docstring; help(...) in a Python session is the fastest way to see the complete parameter reference.

Scope

dendrofan draws circular dendrograms from hierarchical clustering (SciPy linkage matrices) — it does not parse Newick/phylogenetic tree files or handle unequal-tip-depth phylogenies the way ape itself does. If you need that, ape (R) or ete3/Bio.Phylo (Python) are a better fit; dendrofan specifically fills the "I have a SciPy dendrogram and want it circular" gap.

Testing

pytest

The test suite specifically exercises the edge cases listed above (degenerate trees, mismatched labels, invalid linkage matrices, partial spans, single/two-leaf trees).

Citation

If you use dendrofan in a manuscript, please cite the software itself via its Zenodo DOI (see CITATION.cff, or use GitHub's "Cite this repository" button):

Magallanes Quintanar, R. (2026). dendrofan v0.1.0 [Software]. Zenodo. https://doi.org/10.5281/zenodo.21251841

Please also cite the underlying methods it wraps:

  • Virtanen, P. et al. (2020). SciPy 1.0: fundamental algorithms for scientific computing in Python. Nature Methods, 17, 261-272. (hierarchical clustering / linkage, which dendrofan builds on)
  • Paradis, E. & Schliep, K. (2019). ape 5.0: an environment for modern phylogenetics and evolutionary analyses in R. Bioinformatics, 35(3), 526-528. (for the fan-plot visual convention dendrofan follows)

License

MIT — see LICENSE.

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

dendrofan-0.1.1.tar.gz (21.7 kB view details)

Uploaded Source

Built Distribution

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

dendrofan-0.1.1-py3-none-any.whl (20.4 kB view details)

Uploaded Python 3

File details

Details for the file dendrofan-0.1.1.tar.gz.

File metadata

  • Download URL: dendrofan-0.1.1.tar.gz
  • Upload date:
  • Size: 21.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dendrofan-0.1.1.tar.gz
Algorithm Hash digest
SHA256 3fe9c1c6ce30886891d820fa8498d9bb274853676b23f3301dfa0d0ffa657c32
MD5 9324c8d9b5819ad99d88cc4ca530662b
BLAKE2b-256 3d1ba755c4afd456b0c8a00ca73846dc69036ca13829ab929e43ce9c69cf5c67

See more details on using hashes here.

Provenance

The following attestation bundles were made for dendrofan-0.1.1.tar.gz:

Publisher: publish.yml on tiquis/dendrofan

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dendrofan-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: dendrofan-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 20.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dendrofan-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 18eaf1542d36b6468cd371bc7f117154120394e6ccb480ed6b6246ca46196607
MD5 740c44c86aa3640366775aaf8471a1d4
BLAKE2b-256 dbc801b9c205621860425e9e53c204af4e2a46ee14d4fc6283145e36b50cbe54

See more details on using hashes here.

Provenance

The following attestation bundles were made for dendrofan-0.1.1-py3-none-any.whl:

Publisher: publish.yml on tiquis/dendrofan

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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