{"spec_id":"pie-basic","library":"altair","language":"python","code":"\"\"\" anyplot.ai\npie-basic: Basic Pie Chart\nLibrary: altair 6.1.0 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-28\n\"\"\"\n\nimport os\nimport sys\n\n\n# This file is named altair.py — same as the library. Remove the script\n# directory from sys.path so Python finds the real altair package in the venv.\n_here = os.path.normcase(os.path.abspath(os.path.dirname(__file__)))\nsys.path[:] = [p for p in sys.path if os.path.normcase(os.path.abspath(p if p else os.getcwd())) != _here]\n\nimport altair as alt\nimport pandas as pd\nfrom PIL import Image\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_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\nIMPRINT_PALETTE = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\"]\n\n# Data — cloud infrastructure market share\ndata = pd.DataFrame(\n    {\"category\": [\"AWS\", \"Azure\", \"Google Cloud\", \"Alibaba\", \"Oracle\", \"Others\"], \"value\": [31, 24, 11, 4, 3, 27]}\n)\n\ntotal = data[\"value\"].sum()\ndata[\"percentage\"] = data[\"value\"] / total * 100\ndata[\"label\"] = data[\"percentage\"].apply(lambda x: f\"{x:.0f}%\")\ndata[\"order\"] = range(len(data))\n\ndomain = data[\"category\"].tolist()\ncolor_scale = alt.Scale(domain=domain, range=IMPRINT_PALETTE)\n\ntitle_str = \"pie-basic · python · altair · anyplot.ai\"\n\n# Shared base encodings\nbase = alt.Chart(data).encode(\n    theta=alt.Theta(\"value:Q\", stack=True),\n    order=alt.Order(\"order:O\"),\n    color=alt.Color(\n        \"category:N\",\n        scale=color_scale,\n        legend=alt.Legend(\n            title=\"Provider\",\n            titleFontSize=12,\n            labelFontSize=11,\n            symbolSize=180,\n            orient=\"bottom\",\n            direction=\"horizontal\",\n            columns=6,\n            titleAnchor=\"middle\",\n        ),\n    ),\n)\n\n# Non-AWS pie slices\npie = (\n    base.transform_filter(alt.datum.category != \"AWS\")\n    .mark_arc(outerRadius=185, innerRadius=0, stroke=PAGE_BG, strokeWidth=2, padAngle=0.02, cornerRadius=3)\n    .encode(tooltip=[alt.Tooltip(\"category:N\", title=\"Provider\"), alt.Tooltip(\"value:Q\", title=\"Market Share (%)\")])\n)\n\n# Exploded AWS slice — emphasises the market leader\nexploded_aws = (\n    base.transform_filter(alt.datum.category == \"AWS\")\n    .mark_arc(\n        outerRadius=185, innerRadius=0, radiusOffset=25, stroke=PAGE_BG, strokeWidth=2.5, padAngle=0.04, cornerRadius=3\n    )\n    .encode(tooltip=[alt.Tooltip(\"category:N\", title=\"Provider\"), alt.Tooltip(\"value:Q\", title=\"Market Share (%)\")])\n)\n\n# Percentage labels for slices ≥5% at standard radius\ntext_main = (\n    base.transform_filter((alt.datum.category != \"AWS\") & (alt.datum.percentage >= 5))\n    .mark_text(radius=228, fontSize=16, fontWeight=\"bold\", color=INK)\n    .encode(text=\"label:N\")\n)\n\n# Small slices (<5%) pushed further out to reduce crowding between 3% and 4% labels\ntext_small = (\n    base.transform_filter((alt.datum.category != \"AWS\") & (alt.datum.percentage < 5))\n    .mark_text(radius=250, fontSize=13, fontWeight=\"bold\", color=INK_SOFT)\n    .encode(text=\"label:N\")\n)\n\n# AWS label with matching radiusOffset\ntext_aws = (\n    base.transform_filter(alt.datum.category == \"AWS\")\n    .mark_text(radius=228, radiusOffset=25, fontSize=16, fontWeight=\"bold\", color=INK)\n    .encode(text=\"label:N\")\n)\n\nchart = (\n    alt.layer(pie, exploded_aws, text_main, text_small, text_aws)\n    .properties(\n        width=500,\n        height=460,\n        background=PAGE_BG,\n        title=alt.Title(\n            text=title_str,\n            subtitle=\"Global Cloud Infrastructure Market Share\",\n            fontSize=16,\n            subtitleFontSize=12,\n            subtitleColor=INK_SOFT,\n            anchor=\"middle\",\n            color=INK,\n        ),\n    )\n    .configure_view(fill=PAGE_BG, strokeWidth=0)\n    .configure_legend(\n        fillColor=ELEVATED_BG, strokeColor=INK_SOFT, labelColor=INK_SOFT, titleColor=INK, padding=12, offset=8\n    )\n)\n\n# Save PNG targeting 2400×2400 (square — pie chart)\nchart.save(f\"plot-{THEME}.png\", scale_factor=4.0)\n\n# PAD-only-to-target (2400×2400) — DO NOT crop\nTW, TH = 2400, 2400\nPAGE_BG_RGB = tuple(int(PAGE_BG.lstrip(\"#\")[i : i + 2], 16) for i in (0, 2, 4))\n_img = Image.open(f\"plot-{THEME}.png\").convert(\"RGB\")\n_w, _h = _img.size\nif _w > TW or _h > TH:\n    raise SystemExit(\n        f\"altair vl-convert produced {_w}×{_h}, exceeds target {TW}×{TH}. \"\n        f\"Shrink chart .properties(width=, height=) values and re-render.\"\n    )\nif _w < TW or _h < TH:\n    _canvas = Image.new(\"RGB\", (TW, TH), PAGE_BG_RGB)\n    _canvas.paste(_img, ((TW - _w) // 2, (TH - _h) // 2))\n    _canvas.save(f\"plot-{THEME}.png\")\n\nchart.save(f\"plot-{THEME}.html\")\n"}