{"spec_id":"chessboard-pieces","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nchessboard-pieces: Chess Board with Pieces for Position Diagrams\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 80/100 | Created: 2026-05-17\n\"\"\"\n\nimport importlib\nimport os\nimport sys\nimport xml.etree.ElementTree as ET\n\n\n# This file is named pygal.py; strip its directory from sys.path so that\n# importlib resolves to the installed package, not this script itself.\n_self_dir = os.path.dirname(os.path.abspath(__file__))\nsys.path = [p for p in sys.path if os.path.realpath(p or \".\") != _self_dir]\n\npygal = importlib.import_module(\"pygal\")\nStyle = importlib.import_module(\"pygal.style\").Style\n\nET.register_namespace(\"\", \"http://www.w3.org/2000/svg\")\nET.register_namespace(\"xlink\", \"http://www.w3.org/1999/xlink\")\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\"\nLIGHT_SQUARE = \"#E8D5C4\" if THEME == \"light\" else \"#4A4136\"\nDARK_SQUARE = \"#B5956F\" if THEME == \"light\" else \"#2D2622\"\nWHITE_PIECE_COLOR = \"#F5E6D0\"\nBLACK_PIECE_COLOR = \"#1A1A17\"\n\nIMPRINT = (\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\")\n\nPIECE_UNICODE = {\n    \"K\": \"♔\",\n    \"Q\": \"♕\",\n    \"R\": \"♖\",\n    \"B\": \"♗\",\n    \"N\": \"♘\",\n    \"P\": \"♙\",\n    \"k\": \"♚\",\n    \"q\": \"♛\",\n    \"r\": \"♜\",\n    \"b\": \"♝\",\n    \"n\": \"♞\",\n    \"p\": \"♟\",\n}\n\npieces = {\n    \"a1\": \"R\",\n    \"b1\": \"N\",\n    \"c1\": \"B\",\n    \"d1\": \"Q\",\n    \"e1\": \"K\",\n    \"f1\": \"B\",\n    \"g1\": \"N\",\n    \"h1\": \"R\",\n    \"a2\": \"P\",\n    \"b2\": \"P\",\n    \"c2\": \"P\",\n    \"d2\": \"P\",\n    \"e2\": \"P\",\n    \"f2\": \"P\",\n    \"g2\": \"P\",\n    \"h2\": \"P\",\n    \"a7\": \"p\",\n    \"b7\": \"p\",\n    \"c7\": \"p\",\n    \"d7\": \"p\",\n    \"e7\": \"p\",\n    \"f7\": \"p\",\n    \"g7\": \"p\",\n    \"h7\": \"p\",\n    \"a8\": \"r\",\n    \"b8\": \"n\",\n    \"c8\": \"b\",\n    \"d8\": \"q\",\n    \"e8\": \"k\",\n    \"f8\": \"b\",\n    \"g8\": \"n\",\n    \"h8\": \"r\",\n}\n\n# Pygal Style — maps ANYPLOT_THEME tokens to pygal's 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=72,\n    label_font_size=40,\n    major_label_font_size=40,\n    legend_font_size=36,\n)\n\n# pygal.XY renders the SVG skeleton: title, background, and theme chrome\nchart = pygal.XY(\n    width=3600,\n    height=3600,\n    title=\"chessboard-pieces · pygal · anyplot.ai\",\n    style=custom_style,\n    show_legend=False,\n    show_x_guides=False,\n    show_y_guides=False,\n    show_dots=False,\n    show_x_labels=False,\n    show_y_labels=False,\n    margin=80,\n)\nchart.add(\"\", [(0, 0)])  # single invisible seed point — show_dots=False hides it\n\n# Render via pygal to get the themed SVG base\nsvg_bytes = chart.render()\n\n# Inject chess board elements into pygal's SVG tree\nroot = ET.fromstring(svg_bytes)\nNS = \"http://www.w3.org/2000/svg\"\n\nBOARD_SIZE = 2800\nMARGIN_X = (3600 - BOARD_SIZE) // 2  # 400 px side margins\nMARGIN_Y = 210  # clears title + top margin\nSQ = BOARD_SIZE // 8  # 350 px per square\n\nboard_g = ET.SubElement(root, f\"{{{NS}}}g\", attrib={\"id\": \"chess-board\"})\n\n# 64 alternating squares — h1 (file=7, rank=0): (7+0)%2==1 → light ✓\nfor rank in range(8):\n    for file in range(8):\n        x = MARGIN_X + file * SQ\n        y = MARGIN_Y + (7 - rank) * SQ\n        fill = LIGHT_SQUARE if (file + rank) % 2 == 1 else DARK_SQUARE\n        ET.SubElement(\n            board_g,\n            f\"{{{NS}}}rect\",\n            attrib={\"x\": str(x), \"y\": str(y), \"width\": str(SQ), \"height\": str(SQ), \"fill\": fill},\n        )\n\n# Pieces — white pieces cream, black pieces near-black for visual distinction\nfor sq_name, piece in pieces.items():\n    file = ord(sq_name[0]) - ord(\"a\")\n    rank = int(sq_name[1]) - 1\n    cx = MARGIN_X + file * SQ + SQ // 2\n    cy = MARGIN_Y + (7 - rank) * SQ + SQ // 2\n    t = ET.SubElement(\n        board_g,\n        f\"{{{NS}}}text\",\n        attrib={\n            \"x\": str(cx),\n            \"y\": str(cy),\n            \"font-size\": str(int(SQ * 0.7)),\n            \"text-anchor\": \"middle\",\n            \"dominant-baseline\": \"central\",\n            \"fill\": WHITE_PIECE_COLOR if piece.isupper() else BLACK_PIECE_COLOR,\n        },\n    )\n    t.text = PIECE_UNICODE[piece]\n\n# File labels (a–h)\nfor file in range(8):\n    t = ET.SubElement(\n        board_g,\n        f\"{{{NS}}}text\",\n        attrib={\n            \"x\": str(MARGIN_X + file * SQ + SQ // 2),\n            \"y\": str(MARGIN_Y + BOARD_SIZE + 55),\n            \"font-size\": \"44\",\n            \"text-anchor\": \"middle\",\n            \"fill\": INK_MUTED,\n        },\n    )\n    t.text = chr(ord(\"a\") + file)\n\n# Rank labels (1–8)\nfor rank in range(8):\n    t = ET.SubElement(\n        board_g,\n        f\"{{{NS}}}text\",\n        attrib={\n            \"x\": str(MARGIN_X - 30),\n            \"y\": str(MARGIN_Y + (7 - rank) * SQ + SQ // 2),\n            \"font-size\": \"44\",\n            \"text-anchor\": \"end\",\n            \"dominant-baseline\": \"central\",\n            \"fill\": INK_MUTED,\n        },\n    )\n    t.text = str(rank + 1)\n\n# Serialize — register_namespace calls above keep default SVG namespace prefix clean\nsvg_content = ET.tostring(root, encoding=\"unicode\")\n\nwith open(f\"plot-{THEME}.svg\", \"w\", encoding=\"utf-8\") as f:\n    f.write(svg_content)\n\ntry:\n    import cairosvg\n\n    cairosvg.svg2png(bytestring=svg_content.encode(), write_to=f\"plot-{THEME}.png\")\nexcept ImportError:\n    pass\n\nwith open(f\"plot-{THEME}.html\", \"w\", encoding=\"utf-8\") as f:\n    f.write(\n        f'<!DOCTYPE html><html><head><meta charset=\"utf-8\">'\n        f\"<style>body{{margin:0;background:{PAGE_BG}}}</style></head>\"\n        f\"<body>{svg_content}</body></html>\"\n    )\n"}