{"spec_id":"scatter-annotated","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nscatter-annotated: Annotated Scatter Plot with Text Labels\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 81/100 | Updated: 2026-05-13\n\"\"\"\n\nimport os\nimport sys\nimport xml.etree.ElementTree as ET\n\nimport cairosvg\n\n\n# Workaround: pygal.py file in cwd conflicts with pygal package.\n# Remove current directory from sys.path before importing.\n_original_path = sys.path[:]\nwhile \"\" in sys.path:\n    sys.path.remove(\"\")\nif sys.path[0].endswith(\"implementations/python\"):\n    sys.path.pop(0)\n\nimport numpy as np\nimport pygal\nfrom pygal.style import Style\n\n\nsys.path = _original_path\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_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Okabe-Ito palette: first series = #009E73 (brand green)\nIMPRINT = (\n    \"#009E73\",  # 1: bluish green (brand)\n    \"#C475FD\",  # 2: vermillion\n    \"#4467A3\",  # 3: blue\n    \"#BD8233\",  # 4: reddish purple\n    \"#AE3030\",  # 5: orange\n    \"#2ABCCD\",  # 6: sky blue\n    \"#954477\",  # 7: yellow\n    \"#009E73\",  # 8: cycle back to brand for 8+ companies\n    \"#C475FD\",\n    \"#4467A3\",\n    \"#BD8233\",\n    \"#AE3030\",\n)\n\n# Data - Tech company market performance\ncompanies = [\n    \"TechFlow\",\n    \"DataPrime\",\n    \"CloudNine\",\n    \"NetWave\",\n    \"CodeSphere\",\n    \"ByteLogic\",\n    \"SoftEdge\",\n    \"DevStack\",\n    \"AppForge\",\n    \"WebCore\",\n    \"CyberLink\",\n    \"DigiTech\",\n]\n\n# Market cap (x) and annual revenue (y) in billions\nmarket_cap = np.array([15, 45, 75, 105, 135, 25, 55, 85, 115, 145, 35, 95])\nrevenue = np.array([8, 22, 35, 28, 48, 12, 18, 42, 32, 55, 15, 38])\n\n# Custom style with theme-adaptive colors and chrome\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=16,\n    stroke_width=3,\n)\n\n# Create scatter chart\nchart = pygal.XY(\n    width=4800,\n    height=2700,\n    style=custom_style,\n    title=\"scatter-annotated · pygal · anyplot.ai\",\n    x_title=\"Market Cap (Billion $)\",\n    y_title=\"Annual Revenue (Billion $)\",\n    show_legend=False,\n    show_x_guides=True,\n    show_y_guides=True,\n    dots_size=16,\n    stroke=False,\n    show_dots=True,\n    range=(0, 65),\n    xrange=(0, 165),\n    print_values=True,\n    print_values_position=\"top\",\n)\n\n# Add each company as individual series with Okabe-Ito color and annotation\nfor i, company in enumerate(companies):\n    chart.add(\n        company,\n        [{\"value\": (market_cap[i], revenue[i]), \"label\": company, \"formatter\": lambda x, c=company: c}],\n        dots_size=18,\n        formatter=lambda x, c=company: c,\n    )\n\n# Render to SVG and fix label colors to match INK theme token\nsvg_bytes = chart.render()\n\n# Parse SVG and fix label text colors\nET.register_namespace(\"\", \"http://www.w3.org/2000/svg\")\nET.register_namespace(\"xlink\", \"http://www.w3.org/1999/xlink\")\nroot = ET.fromstring(svg_bytes)\nns = {\"svg\": \"http://www.w3.org/2000/svg\"}\n\n# Find all text elements and fix those that contain company names\nfor text_elem in root.findall(\".//svg:text\", ns):\n    text_content = \"\".join(text_elem.itertext()).strip()\n    if text_content in companies:\n        # Set fill color to INK using style attribute to ensure it takes precedence\n        current_style = text_elem.get(\"style\", \"\")\n        if current_style:\n            text_elem.set(\"style\", f\"{current_style};fill:{INK}!important\")\n        else:\n            text_elem.set(\"style\", f\"fill:{INK}\")\n\n# Re-serialize SVG and render PNG\nmodified_svg = ET.tostring(root, encoding=\"utf-8\")\nwith open(f\"plot-{THEME}.html\", \"wb\") as f:\n    f.write(modified_svg)\n\n# Convert SVG to PNG using cairosvg\ncairosvg.svg2png(bytestring=modified_svg, write_to=f\"plot-{THEME}.png\")\n"}