{"spec_id":"pictogram-basic","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\npictogram-basic: Pictogram Chart (Isotype Visualization)\nLibrary: plotnine 0.15.5 | Python 3.13.13\nQuality: 85/100 | Updated: 2026-06-03\n\"\"\"\n\nimport os\n\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    element_blank,\n    element_rect,\n    element_text,\n    geom_text,\n    geom_tile,\n    ggplot,\n    guide_legend,\n    labs,\n    scale_color_identity,\n    scale_fill_manual,\n    scale_x_continuous,\n    scale_y_discrete,\n    theme,\n    theme_void,\n)\n\n\n# Theme tokens — Imprint palette, theme-adaptive chrome\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\n# Imprint categorical palette (hybrid-v3) — first series always #009E73\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\"]\n\n# Data: Fruit production (thousands of tonnes), sorted by value for visual hierarchy\ncategories = [\"Apples\", \"Grapes\", \"Oranges\", \"Bananas\", \"Strawberries\"]\nvalues = [35, 28, 22, 18, 12]\nunit_value = 5  # Each icon = 5 thousand tonnes\n\n# Imprint palette by category (ordinal; Grapes=purple and Strawberries=red are semantic matches)\nfruit_colors = dict(zip(categories, IMPRINT, strict=True))\n\n# Tile dimensions\ntile_w, tile_h = 0.82, 0.70\n\n# Build icon tiles: full icons + partial icons (left-aligned fraction)\ncat_order = categories[::-1]  # highest value at top\n\ntile_rows = []\nfor cat, val in zip(categories, values, strict=True):\n    full_icons = val // unit_value\n    remainder = val % unit_value\n    color = fruit_colors[cat]\n\n    for i in range(full_icons):\n        tile_rows.append({\"category\": cat, \"col\": i + 1, \"border\": \"none\", \"width\": tile_w, \"layer\": \"full\"})\n\n    if remainder > 0:\n        px = full_icons + 1\n        frac = remainder / unit_value\n        tile_rows.append({\"category\": cat, \"col\": px, \"border\": color, \"width\": tile_w, \"layer\": \"outline\"})\n        filled_w = tile_w * frac\n        offset = (tile_w - filled_w) / 2\n        tile_rows.append(\n            {\"category\": cat, \"col\": px - offset, \"border\": \"none\", \"width\": filled_w, \"layer\": \"partial_fill\"}\n        )\n\ndf = pd.DataFrame(tile_rows)\ndf[\"category\"] = pd.Categorical(df[\"category\"], categories=cat_order, ordered=True)\n\ndf_full = df[df[\"layer\"] == \"full\"].copy()\ndf_outline = df[df[\"layer\"] == \"outline\"].copy()\ndf_partial = df[df[\"layer\"] == \"partial_fill\"].copy()\n\n# Value labels at end of each row\nmax_cols = {\n    cat: (val // unit_value) + (1 if val % unit_value > 0 else 0) for cat, val in zip(categories, values, strict=True)\n}\nlabel_df = pd.DataFrame(\n    {\n        \"category\": pd.Categorical(categories, categories=cat_order, ordered=True),\n        \"col\": [max_cols[c] + 0.7 for c in categories],\n        \"label\": [f\"{v}k\" for v in values],\n    }\n)\n\nx_max = max(max_cols.values()) + 2.0\n\nTITLE = \"pictogram-basic · python · plotnine · anyplot.ai\"\n\nplot = (\n    ggplot(df_full, aes(x=\"col\", y=\"category\"))\n    # Layer 1: Full icon tiles — fill mapped to category via Imprint palette\n    + geom_tile(aes(fill=\"category\"), width=tile_w, height=tile_h)\n    # Layer 2: Partial icon outline (dashed border, faint fill so unfilled region is visible)\n    + geom_tile(\n        aes(fill=\"category\", color=\"border\"),\n        data=df_outline,\n        height=tile_h,\n        width=tile_w,\n        alpha=0.3,\n        linetype=\"dashed\",\n        size=0.6,\n        show_legend=False,\n    )\n    # Layer 3: Partial icon fill (left-aligned proportion)\n    + geom_tile(aes(fill=\"category\", width=\"width\"), data=df_partial, height=tile_h, show_legend=False)\n    # Layer 4: Value labels\n    + geom_text(\n        aes(x=\"col\", y=\"category\", label=\"label\"), data=label_df, size=4.0, color=INK, ha=\"left\", fontweight=\"bold\"\n    )\n    + scale_fill_manual(\n        name=\"Each square = 5k tonnes\", values=fruit_colors, breaks=[\"Apples\"], labels=[\"\"], guide=guide_legend(nrow=1)\n    )\n    + scale_color_identity()\n    + scale_x_continuous(limits=(0.3, x_max), expand=(0, 0))\n    + scale_y_discrete(expand=(0.2, 0.15))\n    + labs(x=\"\", y=\"\", title=TITLE, caption=\"Partial squares show fractional units  ·  Source: FAO estimates\")\n    + theme_void()\n    + theme(\n        figure_size=(8, 4.5),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG),\n        plot_title=element_text(size=12, weight=\"bold\", color=INK, margin={\"b\": 15}),\n        plot_caption=element_text(size=7, color=INK_MUTED, ha=\"left\", margin={\"t\": 12}),\n        axis_text_y=element_text(size=8, color=INK_SOFT, ha=\"right\", margin={\"r\": 10}),\n        axis_text_x=element_blank(),\n        legend_position=\"bottom\",\n        legend_background=element_rect(fill=ELEVATED_BG),\n        legend_title=element_text(size=8, weight=\"bold\", color=INK_SOFT),\n        legend_text=element_text(size=8, color=INK_SOFT),\n        plot_margin=0.06,\n    )\n)\n\nplot.save(f\"plot-{THEME}.png\", dpi=400, width=8, height=4.5, units=\"in\", verbose=False)\n"}