{"spec_id":"dot-matrix-proportional","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\ndot-matrix-proportional: Dot Matrix Chart for Proportional Counts\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 82/100 | Created: 2026-05-08\n\"\"\"\n\nimport os\n\nimport pygal\nfrom pygal.style import Style\n\n\n# Theme tokens\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# Data: employee work-preference survey (100 respondents)\ncategories = [(\"Prefer Remote\", 42), (\"Prefer Office\", 31), (\"Hybrid Model\", 27)]\ntotal = 100\ncols = 10\nrows = total // cols  # 10\n\n# Build grid positions: fill left-to-right, top-to-bottom\nall_positions = []\nfor idx in range(total):\n    col = idx % cols\n    row = idx // cols\n    all_positions.append((float(col), float((rows - 1) - row)))\n\n# Assign positions to each category in order\ncat_series = []\nstart = 0\nfor name, count in categories:\n    cat_series.append((name, count, all_positions[start : start + count]))\n    start += count\n\n# Style\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=18,\n    major_label_font_size=16,\n    legend_font_size=16,\n    value_font_size=14,\n    stroke_width=3,\n)\n\n# Chart — XY scatter with stroke=False gives a pure dot matrix\nchart = pygal.XY(\n    style=custom_style,\n    width=3600,\n    height=3600,\n    title=\"Employee Work Preferences · dot-matrix-proportional · pygal · anyplot.ai\",\n    stroke=False,\n    dots_size=35,\n    show_x_guides=False,\n    show_y_guides=False,\n    show_x_labels=False,\n    show_y_labels=False,\n    legend_at_bottom=True,\n    x_title=\"100 employees surveyed  —  each dot represents 1 person\",\n)\n\nfor name, count, positions in cat_series:\n    chart.add(f\"{name}  ({count})\", positions)\n\n# Save\nchart.render_to_png(f\"plot-{THEME}.png\")\nwith open(f\"plot-{THEME}.html\", \"wb\") as f:\n    f.write(chart.render())\n"}