{"spec_id":"marimekko-basic","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nmarimekko-basic: Basic Marimekko Chart\nLibrary: plotnine 0.15.7 | Python 3.13.14\nQuality: 89/100 | Updated: 2026-07-24\n\"\"\"\n\nimport os\n\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    geom_label,\n    geom_rect,\n    ggplot,\n    labs,\n    scale_fill_manual,\n    scale_x_continuous,\n    scale_y_continuous,\n    theme,\n    theme_minimal,\n)\n\n\n# Theme-adaptive chrome tokens (Imprint palette)\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\n# Data - Market share by region and product line\ndata = {\n    \"region\": [\n        \"North America\",\n        \"North America\",\n        \"North America\",\n        \"North America\",\n        \"Europe\",\n        \"Europe\",\n        \"Europe\",\n        \"Europe\",\n        \"Asia Pacific\",\n        \"Asia Pacific\",\n        \"Asia Pacific\",\n        \"Asia Pacific\",\n        \"Latin America\",\n        \"Latin America\",\n        \"Latin America\",\n        \"Latin America\",\n    ],\n    \"product\": [\n        \"Electronics\",\n        \"Software\",\n        \"Services\",\n        \"Hardware\",\n        \"Electronics\",\n        \"Software\",\n        \"Services\",\n        \"Hardware\",\n        \"Electronics\",\n        \"Software\",\n        \"Services\",\n        \"Hardware\",\n        \"Electronics\",\n        \"Software\",\n        \"Services\",\n        \"Hardware\",\n    ],\n    \"value\": [\n        180,\n        120,\n        90,\n        60,  # North America: total 450\n        140,\n        80,\n        100,\n        40,  # Europe: total 360\n        200,\n        60,\n        40,\n        80,  # Asia Pacific: total 380\n        50,\n        30,\n        40,\n        30,\n    ],  # Latin America: total 150\n}\ndf = pd.DataFrame(data)\n\n# Calculate totals per region (determines bar width)\nregion_totals = df.groupby(\"region\")[\"value\"].sum().reset_index()\nregion_totals.columns = [\"region\", \"total\"]\ntotal_all = region_totals[\"total\"].sum()\n\n# Calculate cumulative x positions (bar widths)\nregion_totals[\"width_pct\"] = region_totals[\"total\"] / total_all * 100\nregion_totals[\"xmax\"] = region_totals[\"width_pct\"].cumsum()\nregion_totals[\"xmin\"] = region_totals[\"xmax\"] - region_totals[\"width_pct\"]\nregion_totals[\"xcenter\"] = (region_totals[\"xmin\"] + region_totals[\"xmax\"]) / 2\n\n# Merge back to get x positions\ndf = df.merge(region_totals[[\"region\", \"xmin\", \"xmax\", \"total\"]], on=\"region\")\n\n# Calculate y positions within each region (stacked segments)\ndf[\"pct_within\"] = df[\"value\"] / df[\"total\"] * 100\n\n# Sort by product within region for consistent stacking\nproduct_order = [\"Electronics\", \"Software\", \"Services\", \"Hardware\"]\ndf[\"product_order\"] = df[\"product\"].map({p: i for i, p in enumerate(product_order)})\ndf = df.sort_values([\"region\", \"product_order\"]).reset_index(drop=True)\n\n# Calculate cumulative y positions within each region\nrects = []\nfor region in df[\"region\"].unique():\n    region_df = df[df[\"region\"] == region].copy()\n    y_pos = 0\n    for _, row in region_df.iterrows():\n        rect = {\n            \"region\": row[\"region\"],\n            \"product\": row[\"product\"],\n            \"value\": row[\"value\"],\n            \"xmin\": row[\"xmin\"],\n            \"xmax\": row[\"xmax\"],\n            \"ymin\": y_pos,\n            \"ymax\": y_pos + row[\"pct_within\"],\n        }\n        rect[\"ycenter\"] = (rect[\"ymin\"] + rect[\"ymax\"]) / 2\n        rect[\"xcenter\"] = (rect[\"xmin\"] + rect[\"xmax\"]) / 2\n        rects.append(rect)\n        y_pos += row[\"pct_within\"]\n\nplot_df = pd.DataFrame(rects)\n\n# Add labels with value for larger segments\nplot_df[\"label\"] = plot_df.apply(lambda r: f\"${r['value']}M\" if (r[\"ymax\"] - r[\"ymin\"]) > 10 else \"\", axis=1)\nlabel_df = plot_df[plot_df[\"label\"] != \"\"].reset_index(drop=True)\n\n# Flag the segment the subtitle calls out so the visual reinforces the story,\n# not just the caption text\nplot_df[\"highlight\"] = (plot_df[\"region\"] == \"Asia Pacific\") & (plot_df[\"product\"] == \"Electronics\")\ndimmed_df = plot_df[~plot_df[\"highlight\"]].reset_index(drop=True)\nhighlight_df = plot_df[plot_df[\"highlight\"]].reset_index(drop=True)\n\n# Imprint palette — canonical categorical order (abstract product lines, no\n# semantic color cue), brand green always first\nproduct_colors = {\"Electronics\": \"#009E73\", \"Software\": \"#C475FD\", \"Services\": \"#4467A3\", \"Hardware\": \"#BD8233\"}\n\n# Title fontsize scales down from the 12pt default since the descriptive\n# prefix pushes the mandated title past the 67-char baseline\ntitle = \"Market Share by Region · marimekko-basic · python · plotnine · anyplot.ai\"\ntitle_fontsize = round(12 * min(1.0, 67 / len(title)))\n\n# Create plot\nplot = (\n    ggplot(plot_df)\n    + geom_rect(\n        data=dimmed_df,\n        mapping=aes(xmin=\"xmin\", xmax=\"xmax\", ymin=\"ymin\", ymax=\"ymax\", fill=\"product\"),\n        color=PAGE_BG,\n        size=1.0,\n        alpha=0.6,\n    )\n    + geom_rect(\n        data=highlight_df,\n        mapping=aes(xmin=\"xmin\", xmax=\"xmax\", ymin=\"ymin\", ymax=\"ymax\", fill=\"product\"),\n        color=INK,\n        size=1.8,\n        alpha=1.0,\n    )\n    + geom_label(\n        data=label_df,\n        mapping=aes(x=\"xcenter\", y=\"ycenter\", label=\"label\"),\n        size=3.2,\n        color=INK,\n        fill=ELEVATED_BG,\n        label_size=0.15,\n        label_r=0.05,\n        label_padding=0.1,\n        fontweight=\"bold\",\n    )\n    + scale_fill_manual(values=product_colors)\n    + scale_x_continuous(\n        breaks=region_totals[\"xcenter\"].tolist(), labels=region_totals[\"region\"].tolist(), expand=(0.01, 0.01)\n    )\n    + scale_y_continuous(breaks=[0, 25, 50, 75, 100], labels=[\"0%\", \"25%\", \"50%\", \"75%\", \"100%\"], expand=(0.01, 0.01))\n    + labs(\n        x=\"Market Segment (width = total market size)\",\n        y=\"Product Share (%)\",\n        title=title,\n        subtitle=\"Asia Pacific leads in Electronics revenue ($200M — 53% of its regional market)\",\n        fill=\"Product Line\",\n    )\n    + theme_minimal()\n    + theme(\n        figure_size=(8, 4.5),\n        text=element_text(size=7),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG),\n        panel_grid_major_x=element_blank(),\n        panel_grid_minor_x=element_blank(),\n        panel_grid_minor_y=element_blank(),\n        panel_grid_major_y=element_line(color=INK, size=0.3, alpha=0.15),\n        plot_title=element_text(size=title_fontsize, ha=\"center\", weight=\"bold\", color=INK),\n        plot_subtitle=element_text(size=8, ha=\"center\", color=INK_SOFT),\n        axis_title=element_text(size=10, color=INK),\n        axis_text_x=element_text(size=8, color=INK_SOFT),\n        axis_text_y=element_text(size=8, color=INK_SOFT),\n        legend_title=element_text(size=10, color=INK),\n        legend_text=element_text(size=8, color=INK_SOFT),\n        legend_background=element_rect(fill=ELEVATED_BG, color=None),\n        legend_position=\"right\",\n    )\n)\n\n# Save\nplot.save(f\"plot-{THEME}.png\", dpi=400, width=8, height=4.5, units=\"in\", verbose=False)\n"}