Circle Packing
Chart overview
Circle packing is a hierarchical visualization where data is represented as circles containing other circles.
Key points
- The area of each circle is proportional to the value it represents, making it effective for showing part-to-whole relationships in nested data.
- Unlike treemaps which use rectangles, circle packing can sometimes waste space but creates a more organic, visually appealing representation.
- It's particularly effective for organizational charts, file systems, and budget allocations.
Example Visualization
.png&w=1920&q=75)
Create This Chart Now
Generate publication-ready circle packings with AI in seconds. No coding required – just describe your data and let AI do the work.
View example prompt
"Create a circle packing diagram showing 'Corporate Budget Allocation' for a $200M annual budget across 5 departments. Generate hierarchical data: Marketing ($45M: Advertising $25M, Digital $15M, Events $5M), Engineering ($65M: Development $40M, QA $15M, DevOps $10M), Sales ($50M: Enterprise $30M, SMB $15M, Support $5M), HR ($25M: Recruiting $15M, Training $10M), Finance ($15M: Accounting $10M, Compliance $5M). Use distinct colors for each department. Label outer circles with department names and totals, inner circles with subcategory names. Add a legend mapping colors to departments. Include tooltips showing percentage of total budget."
How to create this chart in 30 seconds
Upload Data
Drag & drop your Excel or CSV file. Plotivy securely processes it in your browser.
AI Generation
Our AI analyzes your data and generates the Circle Packing code automatically.
Customize & Export
Tweak the design with natural language, then export as high-res PNG, SVG or PDF.
Python Code Example
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.colors as mcolors
import matplotlib.cm as cm
import circlify
# === 1. DATA ===
df = pd.DataFrame({
'Department': ['Marketing', 'Marketing', 'Engineering', 'Engineering', 'Sales', 'Sales', 'HR', 'HR'],
'Subcategory': ['Advertising', 'Social Media', 'Development', 'Testing', 'Direct Sales', 'Online Sales', 'Recruitment', 'Training'],
'Budget': [30000000, 20000000, 50000000, 15000000, 25000000, 18000000, 12000000, 8000000]
})
# === 2. HIERARCHY BUILDING ===
data = []
for dept, group in df.groupby('Department'):
sub_children = []
for _, row in group.iterrows():
sub_children.append({'id': row['Subcategory'], 'datum': row['Budget']})
data.append({'id': dept, 'datum': group['Budget'].sum(), 'children': sub_children})
# Compute circle positions (always normalized to radius 1.0)
circles = circlify.circlify(
data,
show_enclosure=False,
target_enclosure=circlify.Circle(x=0, y=0, r=1)
)
# === 3. SETUP PLOT (THE FIX) ===
fig, ax = plt.subplots(figsize=(14, 14), facecolor='white')
# !!! CRITICAL FIX: Lock the view to see the whole unit circle !!!
ax.set_xlim(-1.2, 1.2)
ax.set_ylim(-1.2, 1.2)
ax.axis('off')
ax.set_aspect('equal') # Prevents distortion
# Colormap setup
budgets = df['Budget'].values
norm = mcolors.LogNorm(vmin=min(budgets), vmax=max(budgets))
cmap = cm.get_cmap('magma_r')
# === 4. DRAWING LOOP ===
for circle in circles:
x, y, r = circle.x, circle.y, circle.r
level = circle.level
if level == 1:
# --- PARENT (Department) ---
# Draw a light container circle
ax.add_patch(patches.Circle(
(x, y), r,
facecolor='#f0f0f0',
edgecolor='#999999',
linewidth=2,
zorder=0 # BACKGROUND LAYER
))
# Label: Place at the top edge of the circle
label_y = y + r
ax.text(
x, label_y,
circle.ex['id'].upper(),
ha='center', va='bottom',
fontsize=16, fontweight='bold', color='#333333',
zorder=2
)
elif level == 2:
# --- CHILD (Subcategory) ---
budget = circle.ex['datum']
label = circle.ex['id']
# Color based on budget
color = cmap(norm(budget))
# Draw the bubble
ax.add_patch(patches.Circle(
(x, y), r * 0.95, # Slight gap
facecolor=color,
edgecolor='white',
linewidth=1,
zorder=1 # FOREGROUND LAYER
))
# Smart Labeling (Hide if too small)
if r > 0.05:
# Contrast check
lum = 0.2126*color[0] + 0.7152*color[1] + 0.0722*color[2]
text_col = 'black' if lum > 0.6 else 'white'
# Label
ax.text(x, y + r*0.15, label, ha='center', va='center',
fontsize=11, fontweight='bold', color=text_col, zorder=3)
# Value
val_str = f"${budget/1000000:.1f}M"
ax.text(x, y - r*0.15, val_str, ha='center', va='center',
fontsize=9, color=text_col, zorder=3)
# === 5. TITLE & LEGEND ===
total_budget = df['Budget'].sum()
plt.title(f"Budget Allocation (Total: ${total_budget/1000000:.1f}M)",
fontsize=24, fontweight='bold', y=0.95)
# Add Colorbar
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
sm.set_array([])
cbar = plt.colorbar(sm, ax=ax, shrink=0.5, pad=0.02)
cbar.set_label('Budget Scale (Log)', fontsize=12)
plt.tight_layout()
plt.savefig('fixed_budget_plot.png', dpi=300)
plt.show()Opens the Analyze page with this code pre-loaded and ready to execute
Common Use Cases
- 1Corporate budget allocation visualization
- 2File system size analysis
- 3Organizational structure display
- 4Market segmentation by size
Pro Tips
Use contrasting colors for different hierarchy levels
Add labels only for circles large enough to display them
Consider treemaps for more space-efficient layouts
Scientific Chart Selection Cheat Sheet
Not sure whether to use a Violin Plot, Box Plot, or Ridge Plot? Download our single-page reference mapping the most-used scientific chart types, exactly when to use them, and the core Matplotlib/Seaborn functions.