{"spec_id":"subplot-mosaic","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nsubplot-mosaic: Mosaic Subplot Layout with Varying Sizes\nLibrary: plotnine 0.15.4 | Python 3.13.13\nQuality: 95/100 | Updated: 2026-05-14\n\"\"\"\n\nimport os\nimport sys\n\n\n# Workaround for module/filename conflict: remove current dir from path persistently\nsys.path = [p for p in sys.path if not p.startswith(os.path.dirname(__file__))]\n\nimport numpy as np\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    element_line,\n    element_rect,\n    element_text,\n    geom_bar,\n    geom_line,\n    geom_point,\n    geom_tile,\n    ggplot,\n    labs,\n    scale_color_manual,\n    scale_fill_cmap,\n    scale_fill_manual,\n    theme,\n    theme_minimal,\n)\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\n\n# Okabe-Ito palette\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\"]\n\n# Data - Product performance dashboard\nnp.random.seed(42)\n\n# Daily metrics for overview chart (large top-left panel)\nn_days = 60\ndays = np.arange(n_days)\nproducts = [\"Alpha\", \"Beta\", \"Gamma\"]\ncolors_panel_a = IMPRINT[:3]\n\ndf_overview = pd.concat(\n    [\n        pd.DataFrame({\"day\": days, \"sales\": 100 + i * 15 + np.cumsum(np.random.randn(n_days) * 3), \"product\": name})\n        for i, name in enumerate(products)\n    ],\n    ignore_index=True,\n)\n\n# Category performance (medium right panel)\ncategories = [\"Q1\", \"Q2\", \"Q3\", \"Q4\"]\ndf_category = pd.DataFrame({\"quarter\": categories, \"revenue\": [48, 35, 42, 55]})\ndf_category[\"quarter\"] = pd.Categorical(df_category[\"quarter\"], categories=categories, ordered=True)\n\n# Distribution data (bottom-left)\ndf_scatter = pd.DataFrame({\"units\": np.random.uniform(50, 400, 80), \"margin\": 15 + np.random.randn(80) * 8})\ndf_scatter[\"margin\"] = df_scatter[\"margin\"] + 0.03 * df_scatter[\"units\"]\n\n# Heatmap data (bottom-middle)\nregions = [\"North\", \"South\", \"East\", \"West\"]\nmetrics_list = [\"Sales\", \"Profit\", \"Growth\"]\nheatmap_vals = np.random.rand(len(metrics_list), len(regions)) * 100\ndf_heat = pd.DataFrame(\n    [\n        {\"region\": regions[j], \"metric\": metrics_list[i], \"value\": heatmap_vals[i, j]}\n        for i in range(len(metrics_list))\n        for j in range(len(regions))\n    ]\n)\ndf_heat[\"region\"] = pd.Categorical(df_heat[\"region\"], categories=regions, ordered=True)\ndf_heat[\"metric\"] = pd.Categorical(df_heat[\"metric\"], categories=metrics_list[::-1], ordered=True)\n\n# Small metric panel (bottom-right)\nmonths = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\"]\ndf_monthly = pd.DataFrame({\"month\": months, \"score\": [82, 78, 91, 88, 95, 92]})\ndf_monthly[\"month\"] = pd.Categorical(df_monthly[\"month\"], categories=months, ordered=True)\n\n# Theme configuration\nanyplot_theme = theme(\n    plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n    panel_background=element_rect(fill=PAGE_BG),\n    panel_grid_major=element_line(color=INK, size=0.3, alpha=0.10),\n    panel_grid_minor=element_line(color=INK, size=0.2, alpha=0.05),\n    axis_title=element_text(size=20, color=INK, face=\"bold\"),\n    axis_text=element_text(size=16, color=INK_SOFT),\n    plot_title=element_text(size=24, color=INK, face=\"bold\"),\n    legend_background=element_rect(fill=PAGE_BG, color=\"none\"),\n    legend_text=element_text(size=16, color=INK_SOFT),\n    legend_title=element_text(size=18, color=INK, face=\"bold\"),\n)\n\n# Panel A: Sales Overview - line plot (large, 2/3 width)\np_overview = (\n    ggplot(df_overview, aes(x=\"day\", y=\"sales\", color=\"product\"))\n    + geom_line(size=1.2)\n    + geom_point(size=2.5, alpha=0.6)\n    + scale_color_manual(values=colors_panel_a)\n    + labs(x=\"Day\", y=\"Sales (Units)\", color=\"Product\", title=\"Sales Trend\")\n    + theme_minimal()\n    + anyplot_theme\n    + theme(figure_size=(10.5, 5.2))\n)\n\n# Panel B: Quarterly Revenue - bar plot (small, 1/3 width)\np_category = (\n    ggplot(df_category, aes(x=\"quarter\", y=\"revenue\", fill=\"quarter\"))\n    + geom_bar(stat=\"identity\", width=0.7, show_legend=False)\n    + scale_fill_manual(values=IMPRINT[:4])\n    + labs(x=\"Quarter\", y=\"Revenue (k$)\", title=\"Q Revenue\")\n    + theme_minimal()\n    + anyplot_theme\n    + theme(figure_size=(3.5, 5.2))\n)\n\n# Panel C: Units vs Margin - scatter (bottom-left)\np_scatter = (\n    ggplot(df_scatter, aes(x=\"units\", y=\"margin\"))\n    + geom_point(size=3, color=IMPRINT[0], alpha=0.7)\n    + labs(x=\"Units Sold\", y=\"Margin (%)\", title=\"Margin Analysis\")\n    + theme_minimal()\n    + anyplot_theme\n    + theme(figure_size=(4, 3.2))\n)\n\n# Panel D: Regional Performance - heatmap (bottom-middle)\np_heatmap = (\n    ggplot(df_heat, aes(x=\"region\", y=\"metric\", fill=\"value\"))\n    + geom_tile(color=INK_SOFT, size=0.5)\n    + scale_fill_cmap(cmap_name=\"viridis\")\n    + labs(x=\"Region\", y=\"\", fill=\"Score\", title=\"Regional Heat\")\n    + theme_minimal()\n    + anyplot_theme\n    + theme(figure_size=(4.5, 3.2), legend_position=\"bottom\", legend_direction=\"horizontal\")\n)\n\n# Panel E: Monthly Score - bar plot (bottom-right)\np_monthly = (\n    ggplot(df_monthly, aes(x=\"month\", y=\"score\"))\n    + geom_bar(stat=\"identity\", fill=IMPRINT[0], width=0.6, show_legend=False)\n    + labs(x=\"Month\", y=\"Score\", title=\"Performance\")\n    + theme_minimal()\n    + anyplot_theme\n    + theme(figure_size=(4, 3.2))\n)\n\n# Create mosaic layout using plotnine composition\n# Top row: A (large) | B (small)\n# Bottom row: C | D | E\ntop_row = p_overview | p_category\nbottom_row = p_scatter | p_heatmap | p_monthly\nlayout = top_row / bottom_row\n\n# Draw and save\nfig = layout.draw()\nfig.suptitle(\"subplot-mosaic · plotnine · anyplot.ai\", fontsize=28, fontweight=\"bold\", y=0.98, color=INK)\nfig.set_facecolor(PAGE_BG)\nfig.subplots_adjust(top=0.92, bottom=0.08, left=0.05, right=0.95, hspace=0.32, wspace=0.22)\n\nfig.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}