{"spec_id":"waffle-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nwaffle-basic: Basic Waffle Chart\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 85/100 | Updated: 2026-05-05\n\"\"\"\n\nimport os\n\nimport matplotlib.patches as mpatches\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nfrom matplotlib.colors import ListedColormap\n\n\n# Theme tokens\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# Data - Budget allocation example\ncategories = [\"Housing\", \"Food\", \"Transportation\", \"Utilities\", \"Entertainment\"]\nvalues = [35, 25, 20, 12, 8]  # Percentages, sum to 100\n\n# Okabe-Ito palette - first series always #009E73 (brand)\nokabe_ito = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\"]\ncolors = okabe_ito[: len(categories)]\n\n# Grid dimensions (10x10 = 100 squares for percentage representation)\ngrid_size = 10\ntotal_squares = grid_size * grid_size\n\n# Create grid data - filling bottom-to-top (like filling a glass)\ngrid = np.zeros((grid_size, grid_size), dtype=int)\nsquare_idx = 0\n\nfor cat_idx, value in enumerate(values):\n    for _ in range(value):\n        if square_idx < total_squares:\n            # Fill from bottom-left, going right then up\n            row = grid_size - 1 - (square_idx // grid_size)\n            col = square_idx % grid_size\n            grid[row, col] = cat_idx\n            square_idx += 1\n\n# Create DataFrame for seaborn heatmap\nrows, cols = np.meshgrid(range(grid_size), range(grid_size), indexing=\"ij\")\ndf = pd.DataFrame({\"row\": rows.flatten(), \"col\": cols.flatten(), \"category\": grid.flatten()})\n\n# Create plot (square format better for waffle chart)\nfig, ax = plt.subplots(figsize=(16, 16), facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Create a pivot table for the heatmap-style display\npivot_data = df.pivot(index=\"row\", columns=\"col\", values=\"category\")\n\n# Create custom colormap from Okabe-Ito colors\ncmap = ListedColormap(colors)\n\n# Plot using seaborn heatmap\nsns.heatmap(\n    pivot_data,\n    cmap=cmap,\n    vmin=0,\n    vmax=len(categories) - 1,\n    cbar=False,\n    linewidths=2,\n    linecolor=PAGE_BG,\n    square=True,\n    ax=ax,\n)\n\n# Remove axis labels and ticks\nax.set_xlabel(\"\")\nax.set_ylabel(\"\")\nax.set_xticks([])\nax.set_yticks([])\n\n# Style the spines\nfor spine in ax.spines.values():\n    spine.set_visible(True)\n    spine.set_color(INK_SOFT)\n\n# Title\nax.set_title(\"waffle-basic · seaborn · anyplot.ai\", fontsize=24, fontweight=\"medium\", color=INK, pad=30)\n\n# Create legend with category names and percentages\nlegend_handles = [\n    mpatches.Patch(color=colors[i], label=f\"{categories[i]} ({values[i]}%)\") for i in range(len(categories))\n]\nax.legend(\n    handles=legend_handles,\n    loc=\"upper center\",\n    bbox_to_anchor=(0.5, -0.02),\n    ncol=3,\n    fontsize=18,\n    frameon=False,\n    facecolor=ELEVATED_BG,\n    labelcolor=INK,\n)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}