{"spec_id":"treemap-basic","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\ntreemap-basic: Basic Treemap\nLibrary: plotnine 0.15.4 | Python 3.13.13\nQuality: 80/100 | Updated: 2026-05-05\n\"\"\"\n\nimport pandas as pd\nfrom plotnine import aes, element_text, geom_rect, geom_text, ggplot, labs, scale_fill_manual, theme, theme_void\n\n\n# Data - Budget allocation by department\ndata = {\n    \"category\": [\n        \"Engineering\",\n        \"Engineering\",\n        \"Engineering\",\n        \"Marketing\",\n        \"Marketing\",\n        \"Sales\",\n        \"Sales\",\n        \"Sales\",\n        \"Operations\",\n        \"Operations\",\n        \"HR\",\n        \"Finance\",\n    ],\n    \"subcategory\": [\n        \"R&D\",\n        \"Infrastructure\",\n        \"QA\",\n        \"Digital\",\n        \"Events\",\n        \"Direct\",\n        \"Channel\",\n        \"Support\",\n        \"Logistics\",\n        \"Facilities\",\n        \"Recruiting\",\n        \"Accounting\",\n    ],\n    \"value\": [450, 280, 120, 200, 80, 350, 180, 90, 150, 100, 130, 170],\n}\ndf = pd.DataFrame(data)\n\n# Sort by value descending for better treemap layout\ndf = df.sort_values(\"value\", ascending=False).reset_index(drop=True)\n\n# Squarified treemap layout algorithm (inline)\nvalues = df[\"value\"].tolist()\nx, y, width, height = 0, 0, 100, 56.25  # 16:9 aspect ratio\ntotal = sum(values)\nrects = []\nremaining = list(enumerate(values))\ncurr_x, curr_y = x, y\ncurr_w, curr_h = width, height\n\nwhile remaining:\n    # Decide layout direction (horizontal or vertical)\n    horizontal = curr_w >= curr_h\n    remaining_total = sum(v for _, v in remaining)\n    area_scale = (curr_w * curr_h) / remaining_total if remaining_total > 0 else 0\n\n    best_row = []\n    best_ratio = float(\"inf\")\n\n    for i in range(1, len(remaining) + 1):\n        row = remaining[:i]\n        row_sum = sum(v for _, v in row)\n        row_area = row_sum * area_scale\n\n        if horizontal:\n            row_width = row_area / curr_h if curr_h > 0 else 0\n            ratios = []\n            for _, v in row:\n                rect_h = (v * area_scale / row_width) if row_width > 0 else 0\n                if rect_h > 0 and row_width > 0:\n                    ratio = max(row_width / rect_h, rect_h / row_width)\n                    ratios.append(ratio)\n        else:\n            row_height = row_area / curr_w if curr_w > 0 else 0\n            ratios = []\n            for _, v in row:\n                rect_w = (v * area_scale / row_height) if row_height > 0 else 0\n                if rect_w > 0 and row_height > 0:\n                    ratio = max(rect_w / row_height, row_height / rect_w)\n                    ratios.append(ratio)\n\n        if ratios:\n            max_ratio = max(ratios)\n            if max_ratio <= best_ratio:\n                best_ratio = max_ratio\n                best_row = row\n            else:\n                break\n\n    if not best_row:\n        best_row = remaining[:1]\n\n    # Place the best row\n    row_sum = sum(v for _, v in best_row)\n    row_area = row_sum * area_scale\n\n    if horizontal:\n        row_width = row_area / curr_h if curr_h > 0 else 0\n        rect_y = curr_y\n        for idx, v in best_row:\n            rect_h = (v * area_scale / row_width) if row_width > 0 else 0\n            rects.append({\"idx\": idx, \"x\": curr_x, \"y\": rect_y, \"dx\": row_width, \"dy\": rect_h})\n            rect_y += rect_h\n        curr_x += row_width\n        curr_w -= row_width\n    else:\n        row_height = row_area / curr_w if curr_w > 0 else 0\n        rect_x = curr_x\n        for idx, v in best_row:\n            rect_w = (v * area_scale / row_height) if row_height > 0 else 0\n            rects.append({\"idx\": idx, \"x\": rect_x, \"y\": curr_y, \"dx\": rect_w, \"dy\": row_height})\n            rect_x += rect_w\n        curr_y += row_height\n        curr_h -= row_height\n\n    remaining = remaining[len(best_row) :]\n\n# Sort by original index\nrects.sort(key=lambda r: r[\"idx\"])\nrects = [{\"x\": r[\"x\"], \"y\": r[\"y\"], \"dx\": r[\"dx\"], \"dy\": r[\"dy\"]} for r in rects]\n\n# Add rectangle coordinates to dataframe\ndf[\"x\"] = [r[\"x\"] for r in rects]\ndf[\"y\"] = [r[\"y\"] for r in rects]\ndf[\"dx\"] = [r[\"dx\"] for r in rects]\ndf[\"dy\"] = [r[\"dy\"] for r in rects]\n\n# Calculate rectangle bounds for geom_rect\ndf[\"xmin\"] = df[\"x\"]\ndf[\"xmax\"] = df[\"x\"] + df[\"dx\"]\ndf[\"ymin\"] = df[\"y\"]\ndf[\"ymax\"] = df[\"y\"] + df[\"dy\"]\n\n# Calculate center for labels\ndf[\"xcenter\"] = df[\"x\"] + df[\"dx\"] / 2\ndf[\"ycenter\"] = df[\"y\"] + df[\"dy\"] / 2\n\n# Create combined label with value\ndf[\"label\"] = df[\"subcategory\"] + \"\\n$\" + df[\"value\"].astype(str) + \"K\"\n\n# Color palette for categories (Python Blue and Yellow first, then colorblind-safe)\ncategory_colors = {\n    \"Engineering\": \"#306998\",  # Python Blue\n    \"Marketing\": \"#FFD43B\",  # Python Yellow\n    \"Sales\": \"#4ECDC4\",  # Teal\n    \"Operations\": \"#FF6B6B\",  # Coral\n    \"HR\": \"#95E1A3\",  # Light green\n    \"Finance\": \"#DDA0DD\",  # Plum\n}\n\n# Create plot\nplot = (\n    ggplot(df)\n    + geom_rect(aes(xmin=\"xmin\", xmax=\"xmax\", ymin=\"ymin\", ymax=\"ymax\", fill=\"category\"), color=\"white\", size=2)\n    + geom_text(aes(x=\"xcenter\", y=\"ycenter\", label=\"label\"), size=12, color=\"black\", fontweight=\"bold\")\n    + scale_fill_manual(values=category_colors)\n    + labs(title=\"Budget Allocation by Department · treemap-basic · plotnine · pyplots.ai\", fill=\"Department\")\n    + theme_void()\n    + theme(\n        figure_size=(16, 9),\n        plot_title=element_text(size=24, ha=\"center\", weight=\"bold\", margin={\"b\": 20}),\n        legend_title=element_text(size=18),\n        legend_text=element_text(size=16),\n        legend_position=\"right\",\n    )\n)\n\n# Save\nplot.save(\"plot.png\", dpi=300, verbose=False)\n"}