{"spec_id":"icicle-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nicicle-basic: Basic Icicle Chart\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 84/100 | Updated: 2026-05-13\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport pandas as pd\nfrom matplotlib.patches import Rectangle\n\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\n\n# Hierarchical data: File system structure\nhierarchy_data = [\n    (\"Root\", None, 1000),\n    (\"Documents\", \"Root\", 350),\n    (\"Media\", \"Root\", 450),\n    (\"Projects\", \"Root\", 200),\n    (\"Reports\", \"Documents\", 150),\n    (\"Presentations\", \"Documents\", 120),\n    (\"Templates\", \"Documents\", 80),\n    (\"Images\", \"Media\", 200),\n    (\"Videos\", \"Media\", 180),\n    (\"Audio\", \"Media\", 70),\n    (\"Q1_Report.pdf\", \"Reports\", 50),\n    (\"Q2_Report.pdf\", \"Reports\", 60),\n    (\"Annual.pdf\", \"Reports\", 40),\n    (\"Sales.pptx\", \"Presentations\", 70),\n    (\"Training.pptx\", \"Presentations\", 50),\n    (\"Photos\", \"Images\", 120),\n    (\"Screenshots\", \"Images\", 80),\n    (\"Tutorials\", \"Videos\", 100),\n    (\"Recordings\", \"Videos\", 80),\n    (\"Code\", \"Projects\", 120),\n    (\"Designs\", \"Projects\", 80),\n]\n\n# Build node dictionary\nnodes = {}\nfor name, parent, value in hierarchy_data:\n    nodes[name] = {\"name\": name, \"parent\": parent, \"value\": value, \"children\": []}\n\nfor name, parent, _value in hierarchy_data:\n    if parent and parent in nodes:\n        nodes[parent][\"children\"].append(name)\n\n# Calculate levels\nlevels = {}\nfor name in nodes:\n    level = 0\n    current = name\n    while nodes[current][\"parent\"] is not None:\n        level += 1\n        current = nodes[current][\"parent\"]\n    levels[name] = level\n\nmax_level = max(levels.values())\n\n# Calculate totals (sum of children or own value if leaf)\ntotals = {}\nsorted_nodes = sorted(nodes.keys(), key=lambda x: levels[x], reverse=True)\nfor name in sorted_nodes:\n    children = nodes[name][\"children\"]\n    if not children:\n        totals[name] = nodes[name][\"value\"]\n    else:\n        totals[name] = sum(totals[child] for child in children)\n\n# Calculate icicle chart positions\nrectangles = []\nstack = [(\"Root\", 0.0, 1.0, 0)]\n\nwhile stack:\n    name, x_start, x_end, level = stack.pop()\n    width = x_end - x_start\n    height = 1.0 / (max_level + 1)\n    y = 1.0 - (level + 1) * height\n\n    rectangles.append(\n        {\"name\": name, \"x\": x_start, \"y\": y, \"width\": width, \"height\": height, \"level\": level, \"value\": totals[name]}\n    )\n\n    children = nodes[name][\"children\"]\n    if children:\n        total_child_value = sum(totals[c] for c in children)\n        current_x = x_start\n        for child in reversed(children):\n            child_fraction = totals[child] / total_child_value\n            child_width = width * child_fraction\n            stack.append((child, current_x, current_x + child_width, level + 1))\n            current_x += child_width\n\nrect_df = pd.DataFrame(rectangles)\nn_levels = max_level + 1\n\n# Use viridis colormap for hierarchy levels (theme-independent, works on both light and dark)\ncmap = plt.colormaps[\"viridis\"]\nlevel_colors = {i: cmap(i / (n_levels - 1)) for i in range(n_levels)}\n\n# Create figure and axes\nfig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Draw rectangles\ngap = 0.005\nfor _, rect in rect_df.iterrows():\n    x = rect[\"x\"] + gap\n    y = rect[\"y\"] + gap\n    w = max(rect[\"width\"] - 2 * gap, 0.001)\n    h = max(rect[\"height\"] - 2 * gap, 0.001)\n    level = int(rect[\"level\"])\n    color = level_colors[level]\n\n    patch = Rectangle((x, y), w, h, facecolor=color, edgecolor=INK_SOFT, linewidth=1.5)\n    ax.add_patch(patch)\n\n    # Add text labels with names and values\n    if rect[\"width\"] < 0.02:\n        continue\n\n    cx = rect[\"x\"] + rect[\"width\"] / 2\n    cy = rect[\"y\"] + rect[\"height\"] / 2\n\n    # Determine text color for contrast\n    rgb = color[:3]\n    luminance = 0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]\n    text_color = INK_SOFT if luminance > 0.5 else \"#F5F5F5\"\n\n    fontsize = 16 if level == 0 else (14 if level == 1 else (12 if level == 2 else 10))\n\n    # Format value\n    value = int(rect[\"value\"])\n    if value >= 1000:\n        value_str = f\"{value / 1000:.1f}GB\"\n    else:\n        value_str = f\"{value}MB\"\n\n    # Smart label truncation\n    name = rect[\"name\"]\n    available_width = rect[\"width\"]\n    available_chars = max(5, int(available_width * 100))\n\n    if len(name) <= available_chars:\n        display_text = f\"{name}\\n{value_str}\"\n    else:\n        if \".\" in name:\n            parts = name.rsplit(\".\", 1)\n            ext = \".\" + parts[1]\n            base_chars = available_chars - len(ext) - 1\n            if base_chars > 0:\n                display_text = f\"{parts[0][:base_chars]}…\\n{value_str}\"\n            else:\n                display_text = value_str\n        else:\n            display_text = f\"{name[: available_chars - 1]}…\\n{value_str}\"\n\n    ax.text(\n        cx,\n        cy,\n        display_text,\n        ha=\"center\",\n        va=\"center\",\n        fontsize=fontsize,\n        fontweight=\"bold\",\n        color=text_color,\n        linespacing=1.2,\n    )\n\n# Configure axes\nax.set_xlim(0, 1)\nax.set_ylim(0, 1)\nax.set_aspect(\"auto\")\nax.axis(\"off\")\n\n# Title\nax.text(\n    0.5,\n    0.98,\n    \"icicle-basic · seaborn · anyplot.ai\",\n    ha=\"center\",\n    va=\"top\",\n    fontsize=24,\n    fontweight=\"medium\",\n    color=INK,\n    transform=ax.transAxes,\n)\n\n# Legend for hierarchy levels\nlegend_labels = [\"Level 0\", \"Level 1\", \"Level 2\", \"Level 3\"][:n_levels]\nlegend_patches = [\n    plt.Line2D([0], [0], marker=\"s\", color=\"w\", markerfacecolor=level_colors[i], markersize=12, label=legend_labels[i])\n    for i in range(n_levels)\n]\nax.legend(\n    handles=legend_patches,\n    loc=\"lower right\",\n    fontsize=14,\n    framealpha=0.95,\n    facecolor=ELEVATED_BG,\n    edgecolor=INK_SOFT,\n    title=\"Hierarchy Level\",\n    title_fontsize=16,\n)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}