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