{"spec_id":"marimekko-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nmarimekko-basic: Basic Marimekko Chart\nLibrary: seaborn 0.13.2 | Python 3.13.14\nQuality: 90/100 | Updated: 2026-07-24\n\"\"\"\n\nimport os\n\nimport matplotlib.patches as mpatches\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\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\nsns.set_theme(\n    style=\"ticks\",\n    rc={\n        \"figure.facecolor\": PAGE_BG,\n        \"axes.facecolor\": PAGE_BG,\n        \"axes.edgecolor\": INK_SOFT,\n        \"axes.labelcolor\": INK,\n        \"text.color\": INK,\n        \"xtick.color\": INK_SOFT,\n        \"ytick.color\": INK_SOFT,\n        \"grid.color\": INK,\n        \"grid.alpha\": 0.10,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\n# Imprint palette — canonical order, first series always #009E73\nIMPRINT_PALETTE = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\"]\nsns.set_palette(IMPRINT_PALETTE)\n\nnp.random.seed(42)\n\nregions = [\"North America\", \"Europe\", \"Asia Pacific\", \"Latin America\", \"Middle East\"]\nproducts = [\"Electronics\", \"Apparel\", \"Food & Beverage\", \"Home Goods\"]\n\ndata = {\n    \"North America\": [45, 32, 28, 25],\n    \"Europe\": [38, 42, 35, 22],\n    \"Asia Pacific\": [65, 48, 52, 38],\n    \"Latin America\": [18, 15, 22, 12],\n    \"Middle East\": [12, 8, 15, 10],\n}\n\ndf_data = []\nfor region in regions:\n    for i, product in enumerate(products):\n        df_data.append({\"Region\": region, \"Product\": product, \"Revenue\": data[region][i]})\ndf = pd.DataFrame(df_data)\n\n# Reindex to `regions` order (groupby sorts alphabetically by default) so widths\n# and x_positions stay aligned below.\nregion_totals = df.groupby(\"Region\")[\"Revenue\"].sum().reindex(regions)\ntotal_revenue = region_totals.sum()\nwidths = region_totals / total_revenue\ntop_region = region_totals.idxmax()\n\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400)\nfig.subplots_adjust(left=0.09, right=0.78, top=0.86, bottom=0.28)\n\nx_positions = np.zeros(len(regions))\ncumsum = 0\nfor i, region in enumerate(regions):\n    x_positions[i] = cumsum\n    cumsum += widths[region]\n\n# Derive segment colors from the seaborn-registered Imprint palette\npatch_colors = sns.color_palette(n_colors=len(products))\n\nfor region_idx, region in enumerate(regions):\n    region_data = df[df[\"Region\"] == region]\n    region_total = region_totals[region]\n    bar_width = widths[region]\n    x_start = x_positions[region_idx]\n\n    y_bottom = 0\n    for prod_idx, product in enumerate(products):\n        value = region_data[region_data[\"Product\"] == product][\"Revenue\"].values[0]\n        height = value / region_total  # Normalized to proportion\n\n        # Draw rectangle (seaborn has no native Marimekko; matplotlib patches required)\n        rect = mpatches.Rectangle(\n            (x_start, y_bottom), bar_width, height, facecolor=patch_colors[prod_idx], edgecolor=\"white\", linewidth=1\n        )\n        ax.add_patch(rect)\n\n        if height > 0.12:\n            ax.text(\n                x_start + bar_width / 2,\n                y_bottom + height / 2,\n                f\"${value}B\",\n                ha=\"center\",\n                va=\"center\",\n                fontsize=8,\n                fontweight=\"bold\",\n                color=\"white\",\n            )\n\n        y_bottom += height\n\n# Emphasize the widest column — the story's focal point — with a bold outline\ntop_idx = regions.index(top_region)\nax.add_patch(\n    mpatches.Rectangle(\n        (x_positions[top_idx], 0), widths[top_region], 1, facecolor=\"none\", edgecolor=INK, linewidth=1.2, zorder=5\n    )\n)\n\nax.set_xlim(0, 1)\nax.set_ylim(0, 1)\n\nx_centers = x_positions + widths.values / 2\nax.set_xticks(x_centers)\nax.set_xticklabels([])\nax.tick_params(axis=\"x\", length=0)\n\n# Custom labels staggered on two vertical tiers (odd/even) so the narrow Latin\n# America / Middle East columns don't collide with their neighbor's label.\nstagger_y = [-0.06, -0.15]\nfor i, region in enumerate(regions):\n    is_top = region == top_region\n    ax.text(\n        x_centers[i],\n        stagger_y[i % 2],\n        f\"{region}\\n${region_totals[region]}B\",\n        transform=ax.get_xaxis_transform(),\n        ha=\"center\",\n        va=\"top\",\n        fontsize=8,\n        fontweight=\"bold\" if is_top else \"normal\",\n        color=INK if is_top else INK_SOFT,\n    )\n\nax.set_yticks([0, 0.25, 0.5, 0.75, 1.0])\nax.set_yticklabels([\"0%\", \"25%\", \"50%\", \"75%\", \"100%\"], fontsize=8)\n\nax.set_xlabel(\"Region (width ∝ total revenue)\", fontsize=10, labelpad=62)\nax.set_ylabel(\"Product Mix (%)\", fontsize=10)\n\n# Title with storytelling subtitle\nfig.text(\n    0.5,\n    0.96,\n    \"marimekko-basic · python · seaborn · anyplot.ai\",\n    ha=\"center\",\n    va=\"top\",\n    fontsize=12,\n    fontweight=\"bold\",\n    color=INK,\n)\nfig.text(\n    0.5,\n    0.90,\n    f\"{top_region} leads with ${region_totals[top_region]}B total revenue — Electronics is the top product line globally\",\n    ha=\"center\",\n    va=\"top\",\n    fontsize=8,\n    color=INK_SOFT,\n    style=\"italic\",\n)\n\nlegend_handles = [\n    mpatches.Patch(facecolor=patch_colors[i], edgecolor=\"white\", label=products[i]) for i in range(len(products))\n]\nax.legend(\n    handles=legend_handles,\n    loc=\"upper left\",\n    bbox_to_anchor=(1.02, 1),\n    fontsize=8,\n    title=\"Product Line\",\n    title_fontsize=8,\n)\n\n# Solid thin grid lines (not dashed)\nax.yaxis.grid(True, alpha=0.10, linewidth=0.4, linestyle=\"-\")\nax.set_axisbelow(True)\n\nsns.despine(ax=ax, top=True, right=True)\n\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}