{"spec_id":"venn-basic","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nvenn-basic: Venn Diagram\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 83/100 | Updated: 2026-05-11\n\"\"\"\n\nimport os\n\nimport cairosvg\nimport numpy as np\nimport pygal\nfrom pygal.style import Style\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\")\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    opacity=0.5,\n    title_font_size=28,\n    legend_font_size=16,\n    label_font_size=18,\n    major_label_font_size=16,\n    value_font_size=14,\n    stroke_width=2,\n)\n\nset_labels = [\"Product A\", \"Product B\", \"Product C\"]\nset_sizes = [100, 80, 60]\n\nab_overlap = 30\nac_overlap = 20\nbc_overlap = 25\nabc_overlap = 10\n\nonly_a = set_sizes[0] - ab_overlap - ac_overlap + abc_overlap\nonly_b = set_sizes[1] - ab_overlap - bc_overlap + abc_overlap\nonly_c = set_sizes[2] - ac_overlap - bc_overlap + abc_overlap\nonly_ab = ab_overlap - abc_overlap\nonly_ac = ac_overlap - abc_overlap\nonly_bc = bc_overlap - abc_overlap\n\nchart = pygal.XY(\n    width=3600,\n    height=3600,\n    style=custom_style,\n    fill=True,\n    stroke=True,\n    show_dots=False,\n    show_legend=True,\n    legend_at_bottom=True,\n    legend_box_size=24,\n    title=\"venn-basic · pygal · anyplot.ai\",\n    show_x_guides=False,\n    show_y_guides=False,\n    show_x_labels=False,\n    show_y_labels=False,\n    x_title=None,\n    y_title=None,\n    margin=150,\n    spacing=15,\n    explicit_size=True,\n)\n\nr_a = 0.65\nr_b = 0.60\nr_c = 0.54\n\nn_points = 300\ntheta = np.linspace(0, 2 * np.pi, n_points, endpoint=True)\n\ncx_a, cy_a = -0.4, 0.25\ncx_b, cy_b = 0.4, 0.25\ncx_c, cy_c = 0.0, -0.40\n\ncircle_a = [(cx_a + r_a * np.cos(t), cy_a + r_a * np.sin(t)) for t in theta]\ncircle_b = [(cx_b + r_b * np.cos(t), cy_b + r_b * np.sin(t)) for t in theta]\ncircle_c = [(cx_c + r_c * np.cos(t), cy_c + r_c * np.sin(t)) for t in theta]\n\nchart.add(f\"{set_labels[0]} (n={set_sizes[0]})\", circle_a)\nchart.add(f\"{set_labels[1]} (n={set_sizes[1]})\", circle_b)\nchart.add(f\"{set_labels[2]} (n={set_sizes[2]})\", circle_c)\n\nsvg_content = chart.render().decode(\"utf-8\")\n\nscale = 3600 * 0.35\ncenter_x = 3600 / 2\ncenter_y = 3600 / 2\n\ncount_style = 'font-size=\"48px\" font-weight=\"bold\" fill=\"' + INK + '\" text-anchor=\"middle\" dominant-baseline=\"middle\"'\nname_style = 'font-size=\"36px\" font-weight=\"bold\" fill=\"' + INK + '\" text-anchor=\"middle\" dominant-baseline=\"middle\"'\n\nlabels = [\n    (center_x + (cx_a - 0.35) * scale, center_y - (cy_a + 0.28) * scale, str(only_a), count_style),\n    (center_x + (cx_b + 0.35) * scale, center_y - (cy_b + 0.28) * scale, str(only_b), count_style),\n    (center_x + cx_c * scale, center_y - (cy_c - 0.38) * scale, str(only_c), count_style),\n    (center_x, center_y - (cy_a + 0.32) * scale, str(only_ab), count_style),\n    (\n        center_x + ((cx_a + cx_c) / 2 - 0.2) * scale,\n        center_y - ((cy_a + cy_c) / 2 + 0.05) * scale,\n        str(only_ac),\n        count_style,\n    ),\n    (\n        center_x + ((cx_b + cx_c) / 2 + 0.2) * scale,\n        center_y - ((cy_b + cy_c) / 2 + 0.05) * scale,\n        str(only_bc),\n        count_style,\n    ),\n    (center_x, center_y - ((cy_a + cy_c) / 2 + 0.15) * scale, str(abc_overlap), count_style),\n    (center_x + cx_a * scale, center_y - (cy_a + 0.50) * scale, set_labels[0], name_style),\n    (center_x + cx_b * scale, center_y - (cy_b + 0.50) * scale, set_labels[1], name_style),\n    (center_x + cx_c * scale, center_y - (cy_c - 0.50) * scale, set_labels[2], name_style),\n]\n\ntext_elements = \"\\n\".join(f'<text x=\"{x:.0f}\" y=\"{y:.0f}\" {s}>{v}</text>' for x, y, v, s in labels)\nsvg_content = svg_content.replace(\"</svg>\", f\"{text_elements}\\n</svg>\")\n\nwith open(f\"plot-{THEME}.svg\", \"w\", encoding=\"utf-8\") as f:\n    f.write(svg_content)\n\ncairosvg.svg2png(bytestring=svg_content.encode(\"utf-8\"), write_to=f\"plot-{THEME}.png\")\n\nhtml_content = f\"\"\"<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <title>venn-basic - pygal - anyplot.ai</title>\n    <style>\n        body {{ margin: 0; padding: 20px; background: {PAGE_BG}; display: flex; justify-content: center; }}\n        svg {{ max-width: 100%; height: auto; }}\n    </style>\n</head>\n<body>\n    {svg_content}\n</body>\n</html>\"\"\"\n\nwith open(f\"plot-{THEME}.html\", \"w\", encoding=\"utf-8\") as f:\n    f.write(html_content)\n"}