{"spec_id":"waffle-basic","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nwaffle-basic: Basic Waffle Chart\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-05\n\"\"\"\n\nimport os\nimport sys\n\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\nIMPRINT = (\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\")\n\n_cwd = sys.path[0] if sys.path[0] else \".\"\nif _cwd in sys.path:\n    sys.path.remove(_cwd)\n\nfrom pygal.graph.graph import Graph\nfrom pygal.style import Style\n\n\nsys.path.insert(0, _cwd)\n\n\nclass Waffle(Graph):\n    _serie_margin = 0\n\n    def __init__(self, *args, **kwargs):\n        self.rows = kwargs.pop(\"rows\", 10)\n        self.cols = kwargs.pop(\"cols\", 10)\n        super().__init__(*args, **kwargs)\n\n    def _plot(self):\n        total = sum(sum(v for v in serie.values if v is not None) for serie in self.series)\n        if total == 0:\n            return\n\n        total_squares = self.rows * self.cols\n\n        plot_width = self.view.width\n        plot_height = self.view.height\n\n        square_size = min(plot_width / self.cols, plot_height / self.rows) * 0.85\n        gap = square_size * 0.12\n\n        grid_width = self.cols * (square_size + gap) - gap\n        grid_height = self.rows * (square_size + gap) - gap\n\n        x_start = self.view.x(0)\n        y_start = self.view.y(self.rows)\n\n        x_offset = x_start + (plot_width - grid_width) / 2\n        y_offset = y_start + (plot_height - grid_height) / 2\n\n        plot_node = self.nodes[\"plot\"]\n        waffle_group = self.svg.node(plot_node, class_=\"waffle-chart\")\n\n        square_index = 0\n        for serie_index, serie in enumerate(self.series):\n            serie_value = sum(v for v in serie.values if v is not None)\n            num_squares = round(serie_value / total * total_squares)\n\n            color = self.style.colors[serie_index % len(self.style.colors)]\n\n            serie_group = self.svg.node(waffle_group, class_=\"series serie-%d color-%d\" % (serie_index, serie_index))\n\n            for _ in range(num_squares):\n                if square_index >= total_squares:\n                    break\n\n                row = square_index // self.cols\n                col = square_index % self.cols\n\n                x = x_offset + col * (square_size + gap)\n                y = y_offset + row * (square_size + gap)\n\n                self.svg.node(\n                    serie_group,\n                    \"rect\",\n                    x=x,\n                    y=y,\n                    width=square_size,\n                    height=square_size,\n                    fill=color,\n                    rx=square_size * 0.1,\n                    ry=square_size * 0.1,\n                    class_=\"waffle-square reactive\",\n                )\n\n                square_index += 1\n\n    def _compute(self):\n        self._box.xmin = 0\n        self._box.xmax = self.cols\n        self._box.ymin = 0\n        self._box.ymax = self.rows\n\n\ncustom_style = Style(\n    background=PAGE_BG,\n    plot_background=PAGE_BG,\n    foreground=INK,\n    foreground_strong=INK,\n    foreground_subtle=INK_MUTED,\n    colors=IMPRINT,\n    title_font_size=28,\n    label_font_size=22,\n    major_label_font_size=18,\n    legend_font_size=16,\n    value_font_size=14,\n    stroke_width=3,\n)\n\ncategories = {\"Operations\": 42, \"Marketing\": 28, \"R&D\": 18, \"Admin\": 12}\n\nchart = Waffle(\n    width=4800,\n    height=2700,\n    rows=10,\n    cols=10,\n    style=custom_style,\n    title=\"Budget Allocation · waffle-basic · pygal · anyplot.ai\",\n    show_legend=True,\n    legend_at_bottom=True,\n    legend_at_bottom_columns=4,\n    margin=80,\n    margin_bottom=250,\n    show_x_labels=False,\n    show_y_labels=False,\n)\n\nfor category, value in categories.items():\n    chart.add(f\"{category} ({value}%)\", [value])\n\nchart.render_to_png(f\"plot-{THEME}.png\")\n\nwith open(f\"plot-{THEME}.html\", \"wb\") as f:\n    f.write(chart.render())\n"}