An icicle chart displaying hierarchical data as adjacent rectangles in a layered structure, where each rectangle's size represents its value in the hierarchy. Unlike treemaps that nest rectangles, icicle charts stack them in rows (horizontal) or columns (vertical), making parent-child relationships explicitly visible through spatial adjacency. This layout excels at showing both the hierarchy levels and the proportional values simultaneously.

""" anyplot.ai
icicle-basic: Basic Icicle Chart
Library: matplotlib 3.10.9 | Python 3.13.13
Quality: 80/100 | Updated: 2026-05-13
"""
import matplotlib.patches as patches
import matplotlib.pyplot as plt
# Data: File system structure with folders and files
# Format: (name, parent, value) - leaf nodes have values, internal nodes will be computed
hierarchy_data = [
("Root", None, 0),
("Documents", "Root", 0),
("Pictures", "Root", 0),
("Music", "Root", 0),
("Reports", "Documents", 0),
("Letters", "Documents", 0),
("Spreadsheets", "Documents", 0),
("Photos", "Pictures", 0),
("Screenshots", "Pictures", 0),
("Icons", "Pictures", 0),
("Albums", "Music", 0),
("Playlists", "Music", 0),
("Podcasts", "Music", 0),
("Q1_Report", "Reports", 45),
("Q2_Report", "Reports", 55),
("Q3_Report", "Reports", 50),
("Cover_Letter", "Letters", 25),
("Resume", "Letters", 35),
("Thank_You", "Letters", 20),
("Budget", "Spreadsheets", 60),
("Forecast", "Spreadsheets", 40),
("Analysis", "Spreadsheets", 20),
("Photo_1", "Photos", 65),
("Photo_2", "Photos", 75),
("Photo_3", "Photos", 60),
("Screen_1", "Screenshots", 25),
("Screen_2", "Screenshots", 25),
("Icon_1", "Icons", 15),
("Icon_2", "Icons", 15),
("Rock", "Albums", 60),
("Jazz", "Albums", 55),
("Pop", "Albums", 65),
("Favorites", "Playlists", 40),
("Podcast_1", "Podcasts", 45),
("Podcast_2", "Podcasts", 45),
]
# Build tree structure inline (no functions per KISS principle)
nodes = {}
children = {}
for name, parent, value in hierarchy_data:
nodes[name] = {"name": name, "parent": parent, "value": value}
if parent is not None:
if parent not in children:
children[parent] = []
children[parent].append(name)
# Calculate total values for all nodes (bottom-up traversal)
# First, get nodes in reverse depth order using BFS
node_depths = {"Root": 0}
queue = ["Root"]
depth_order = []
while queue:
current = queue.pop(0)
depth_order.append(current)
if current in children:
for child in children[current]:
node_depths[child] = node_depths[current] + 1
queue.append(child)
# Calculate values bottom-up
node_values = {}
for node_name in reversed(depth_order):
if node_name not in children:
node_values[node_name] = nodes[node_name]["value"]
else:
node_values[node_name] = sum(node_values[child] for child in children[node_name])
# Calculate positions for icicle chart (top-to-bottom layout)
positions = {}
positions["Root"] = {"x_start": 0, "x_end": 1, "depth": 0, "value": node_values["Root"]}
# Process nodes level by level
for node_name in depth_order:
if node_name in children:
pos = positions[node_name]
current_x = pos["x_start"]
total_value = node_values[node_name]
for child in children[node_name]:
child_value = node_values[child]
child_width = (child_value / total_value) * (pos["x_end"] - pos["x_start"])
positions[child] = {
"x_start": current_x,
"x_end": current_x + child_width,
"depth": pos["depth"] + 1,
"value": child_value,
}
current_x += child_width
# Find max depth
max_depth = max(pos["depth"] for pos in positions.values())
# Color palette by depth level (colorblind-safe)
depth_colors = [
"#306998", # Python Blue - Level 0
"#FFD43B", # Python Yellow - Level 1
"#4ECDC4", # Teal - Level 2
"#FF6B6B", # Coral - Level 3
"#95E1D3", # Light teal - Level 4
]
# Create plot
fig, ax = plt.subplots(figsize=(16, 9))
# Draw rectangles
row_height = 1.0 / (max_depth + 1)
for node_name, pos in positions.items():
depth = pos["depth"]
x_start = pos["x_start"]
x_end = pos["x_end"]
width = x_end - x_start
# Y position (top-to-bottom: depth 0 at top)
y_start = 1.0 - (depth + 1) * row_height
# Get color based on depth
color = depth_colors[depth % len(depth_colors)]
# Draw rectangle
rect = patches.Rectangle(
(x_start, y_start),
width,
row_height * 0.95, # Small gap between rows
linewidth=2,
edgecolor="white",
facecolor=color,
alpha=0.85,
)
ax.add_patch(rect)
# Add label if rectangle is wide enough
if width > 0.03:
label = node_name.replace("_", " ")
max_chars = max(3, int(width * 80))
if len(label) > max_chars:
label = label[: max_chars - 2] + ".."
# Calculate font size based on width
fontsize = min(16, max(9, int(width * 120)))
ax.text(
x_start + width / 2,
y_start + row_height * 0.95 / 2,
label,
ha="center",
va="center",
fontsize=fontsize,
fontweight="bold",
color="white" if depth != 1 else "black",
)
# Configure axes
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.set_aspect("auto")
# Add depth level labels on the right
level_labels = ["Root", "Category", "Subcategory", "Item", "Detail"]
for depth in range(max_depth + 1):
y_pos = 1.0 - (depth + 0.5) * row_height
level_label = level_labels[depth] if depth < len(level_labels) else ""
ax.text(1.02, y_pos, level_label, fontsize=14, va="center", color="#333333")
# Remove axes for cleaner look
ax.axis("off")
# Add title in correct format per spec
ax.set_title("icicle-basic · matplotlib · pyplots.ai", fontsize=24, fontweight="bold", pad=20)
plt.tight_layout()
plt.savefig("plot.png", dpi=300, bbox_inches="tight", facecolor="white")
Part of Basic Icicle Chart on anyplot.ai.