Treemap & Sunburst (Python)

Authors

[Editor] Shixiang Wang;

[Contributors] ZCode (GLM) โ€” AI-generated, independently AI-reviewed.

Modified

2026-10-31

๐Ÿค– AI Skill โ€” Download the Bizard unified skill for your AI assistant โฌ‡๏ธ Download Skill ZIP
๐Ÿ”Œ MCP Server โ€” Let AI agents (Claude Code, Cursor, โ€ฆ) query Bizard live: claude mcp add bizard -- npx @openbiox/bizard-mcp โ€” or the free hosted instance (no install, faster from mainland China): claude mcp add --transport http bizard http://biotree.top:38123/bizard-mcp/mcp ๐Ÿ“– MCP Docs
๐Ÿ“– Cite Bizard โ€” if Bizard helps your research, please cite: Li, K., Zheng, H., Huang, K., et al. (2026). Bizard: A Community-Driven Platform for Accelerating and Enhancing Biomedical Data Visualization. iMetaMed, e70038. ๐Ÿ”— DOI / BibTeX

The Python counterpart of Treemap and Sunburst: two displays for hierarchical composition. A treemap nests rectangles whose area encodes a value โ€” the best static overview of one or two hierarchy levels; a sunburst nests rings radially and stays interactive โ€” level structure and click-to-zoom. In clinical data they suit cohorts that decompose naturally (cancer type โ†’ response), cost trees, and taxonomic abundance.

This tutorial builds a static treemap with squarify [1] on matplotlib and an interactive sunburst with plotly.graph_objects [2], using the same cohort so the two designs can be compared directly.

This tutorial covers two workflows:

  1. A static treemap of cohort composition (squarify);
  2. An interactive two-level sunburst (plotly).

Example

Setup

  • System Requirements: Cross-platform (Linux/MacOS/Windows)
  • Programming Language: Python
  • Dependencies: matplotlib, pandas, squarify, plotly
import matplotlib.pyplot as plt
import pandas as pd
import squarify
import plotly.graph_objects as go

Data Preparation

A 270-patient oncology cohort of three cancer types (120/90/60) with three response categories each. For branchvalues="total" the parent value must equal the sum of its children โ€” validated programmatically before plotting.

counts = {"Breast": (55, 25, 40),          # (PR, SD, PD)
          "Lung (NSCLC)": (30, 35, 25),
          "Colorectal": (18, 24, 18)}
cnt = pd.DataFrame(
    [{"cancer": c, "response": r, "n": n}
     for c, resp in counts.items() for r, n in zip(["PR", "SD", "PD"], resp)])
cnt["id"] = cnt.cancer + "-" + cnt.response

agg = cnt.groupby("cancer", as_index=False)["n"].sum()

# parent values must equal the sum of their children
parents_ok = all(int(agg.loc[agg.cancer == c, "n"].iloc[0])
                 == int(cnt.loc[cnt.cancer == c, "n"].sum())
                 for c in counts)
assert parents_ok
cnt
cancer response n id
0 Breast PR 55 Breast-PR
1 Breast SD 25 Breast-SD
2 Breast PD 40 Breast-PD
3 Lung (NSCLC) PR 30 Lung (NSCLC)-PR
4 Lung (NSCLC) SD 35 Lung (NSCLC)-SD
5 Lung (NSCLC) PD 25 Lung (NSCLC)-PD
6 Colorectal PR 18 Colorectal-PR
7 Colorectal SD 24 Colorectal-SD
8 Colorectal PD 18 Colorectal-PD

Visualization

1. Static Treemap with squarify

colors = {"Breast": "#4E79A7", "Lung (NSCLC)": "#F28E2B", "Colorectal": "#E15759"}
total = agg.n.sum()

fig, ax = plt.subplots(figsize=(8, 5))
squarify.plot(
    sizes=agg.n,
    label=[f"{r.cancer}\n{r.n} ({r.n / total:.0%})" for r in agg.itertuples()],
    color=[colors[r.cancer] for r in agg.itertuples()],
    ax=ax, alpha=0.85, pad=True)
ax.axis("off")
ax.set_title("Cohort composition treemap (squarify)")
fig.tight_layout()
plt.show()
Figureย 1: squarify treemap of the cohort: rectangle area encodes patient count; labels carry counts and cohort shares. One hierarchy level per call.

squarify lays out one flat list of rectangles; to show two levels, draw the parent rectangles first and then each parentโ€™s children clipped to the parentโ€™s rectangle (or hand the whole hierarchy to plotlyโ€™s treemap trace, which nests automatically).

2. Interactive Sunburst with plotly

roots = agg.cancer.tolist()          # groupby sorts alphabetically: use ITS order
rcolors = {"Breast": "#4E79A7", "Lung (NSCLC)": "#F28E2B", "Colorectal": "#E15759"}
lcolors = {"PR": "#7fa8cc", "SD": "#f5b767", "PD": "#e98a8a"}

fig = go.Figure(go.Sunburst(
    ids=roots + cnt.id.tolist(),
    labels=roots + cnt.response.tolist(),
    parents=[""] * len(roots) + cnt.cancer.tolist(),
    values=agg.n.tolist() + cnt.n.tolist(),
    branchvalues="total",
    marker=dict(colors=[rcolors[c] for c in roots]
                + [lcolors[r] for r in cnt.response]),
    hovertemplate="%{id}<br>n = %{value}<extra></extra>"))
fig.update_layout(width=800, height=800,
                  title="Cohort hierarchy: cancer โ†’ response")
fig
Figureย 2: Two-level sunburst of the same cohort: inner ring = cancer type, outer = response; hover shows counts, click a segment to zoom into its subtree.
TipPractice tips
  • branchvalues="total" requires parent value = sum of children โ€” assert it (as in Data Preparation) or plotly draws overlapping wedges; "remainder" is the alternative where parents hold only their own value.
  • squarify sorts nothing for you: pass sizes in decreasing order for the classic large-to-small layout, and pad=True so adjacent rectangles stay readable.
  • Sunbursts and treemaps both hide small categories: collapse anything below ~2% into โ€œOtherโ€ before plotting.
  • The plotly figure is an HTML widget โ€” the rendered page is interactive; static export for print needs a screenshot (no kaleido in this environment).

Application

Treemaps and sunbursts appear in cohort-reports (registry composition), cost/utilization decomposition, and metagenomics (phylum โ†’ species). The panel below mirrors a typical report layout: (A) the static treemap and (B) the interactive sunburst.

Reference

[1] Lambrechts G. squarify: pure Python implementation of the squarified treemap layout. https://github.com/gregorl/squarify

[2] Sievert C. Interactive Web-Based Data Visualization with R, plotly, and shiny. Chapman and Hall/CRC; 2020. doi:10.1201/9780429447273