{"spec_id":"bar-basic","library":"altair","language":"python","code":"\"\"\" anyplot.ai\nbar-basic: Basic Bar Chart\nLibrary: altair 6.1.0 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-28\n\"\"\"\n\nimport os\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\"\n\nIMPRINT_PALETTE = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\"]\nBRAND = IMPRINT_PALETTE[0]  # brand green — regular bars\nHIGHLIGHT = IMPRINT_PALETTE[3]  # ochre — warm top-performer accent\n\n# Data — product sales by category, deterministic retail scenario\ndata = pd.DataFrame(\n    {\n        \"category\": [\"Electronics\", \"Clothing\", \"Home & Garden\", \"Sports\", \"Books\", \"Toys\", \"Food\"],\n        \"value\": [45200, 31500, 29800, 21800, 18500, 14200, 13100],\n    }\n)\ndata[\"is_top\"] = data[\"value\"] == data[\"value\"].max()\nsort_order = data.sort_values(\"value\", ascending=False)[\"category\"].tolist()\n\n# Title (40 chars < 67 baseline — no size reduction needed)\ntitle = \"bar-basic · python · altair · anyplot.ai\"\ntitle_fontsize = 16\n\n# Bars with conditional color for top performer\nbars = (\n    alt.Chart(data)\n    .mark_bar(cornerRadiusTopLeft=4, cornerRadiusTopRight=4)\n    .encode(\n        x=alt.X(\"category:N\", title=\"Product Category\", sort=sort_order, axis=alt.Axis(labelAngle=-45)),\n        y=alt.Y(\n            \"value:Q\",\n            title=\"Sales ($)\",\n            scale=alt.Scale(domain=[0, 55000]),\n            axis=alt.Axis(format=\"$,.0f\", values=[0, 10000, 20000, 30000, 40000, 50000]),\n        ),\n        color=alt.condition(alt.datum.is_top, alt.value(HIGHLIGHT), alt.value(BRAND)),\n        tooltip=[alt.Tooltip(\"category:N\", title=\"Category\"), alt.Tooltip(\"value:Q\", title=\"Sales\", format=\"$,.0f\")],\n    )\n)\n\n# Value labels above each bar — same size as tick labels for visual consistency\nlabels = bars.mark_text(align=\"center\", baseline=\"bottom\", dy=-6, fontSize=10).encode(\n    text=alt.Text(\"value:Q\", format=\"$,.0f\"), color=alt.value(INK_SOFT)\n)\n\n# Top-performer callout annotation\nannotation = (\n    alt.Chart(pd.DataFrame({\"category\": [\"Electronics\"], \"value\": [45200], \"label\": [\"Top seller — $45.2k\"]}))\n    .mark_text(align=\"center\", baseline=\"bottom\", dy=-22, fontSize=10, fontWeight=\"bold\")\n    .encode(\n        x=alt.X(\"category:N\", sort=sort_order), y=alt.Y(\"value:Q\"), text=alt.Text(\"label:N\"), color=alt.value(HIGHLIGHT)\n    )\n)\n\nchart = (\n    (bars + labels + annotation)\n    .properties(width=620, height=320, background=PAGE_BG, title=alt.Title(title, fontSize=title_fontsize, color=INK))\n    .configure_view(fill=PAGE_BG, strokeWidth=0)\n    .configure_axis(\n        labelFontSize=10,\n        titleFontSize=12,\n        labelColor=INK_SOFT,\n        titleColor=INK,\n        domainColor=INK_SOFT,\n        tickColor=INK_SOFT,\n        grid=False,\n    )\n    .configure_axisY(grid=True, gridOpacity=0.15, gridDash=[4, 4], gridColor=INK_SOFT)\n)\n\n# Save PNG then pad to exact 3200×1800 target\nchart.save(f\"plot-{THEME}.png\", scale_factor=4.0)\n\nTW, TH = 3200, 1800\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)\n    _canvas.paste(_img, ((TW - _w) // 2, (TH - _h) // 2))\n    _canvas.save(f\"plot-{THEME}.png\")\n\n# Save interactive HTML\nchart.save(f\"plot-{THEME}.html\")\n"}