{"spec_id":"heatmap-basic","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nheatmap-basic: Basic Heatmap\nLibrary: plotnine 0.15.4 | Python 3.13.13\nQuality: 85/100 | Updated: 2026-05-28\n\"\"\"\n\nimport os\n\nimport numpy as np\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    labs,\n    scale_color_identity,\n    scale_fill_gradient2,\n    scale_x_discrete,\n    scale_y_discrete,\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\"\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# Imprint diverging colormap: matte-red → theme-adaptive midpoint → blue\nCMAP_MID = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\n\n# Data — quarterly growth rates (%) across 8 departments over 8 quarters\nnp.random.seed(42)\ndepartments = [\"Engineering\", \"Marketing\", \"Sales\", \"Finance\", \"Operations\", \"HR\", \"Research\", \"Support\"]\nquarters = [\"Q1 '23\", \"Q2 '23\", \"Q3 '23\", \"Q4 '23\", \"Q1 '24\", \"Q2 '24\", \"Q3 '24\", \"Q4 '24\"]\n\nbase_trend = np.linspace(-18, 22, 8)\ndept_offsets = np.array([-6, 10, 14, -3, 4, -10, 8, -5])\nvalues = np.round(base_trend[np.newaxis, :] + dept_offsets[:, np.newaxis] + np.random.normal(0, 4, (8, 8)), 1)\n\nvalues[5, 0] = -32.5  # HR deep crisis Q1 '23\nvalues[2, 7] = 38.2  # Sales strong recovery Q4 '24\nvalues[6, 6] = 33.7  # Research surge Q3 '24\n\ndept_idx, qtr_idx = np.meshgrid(np.arange(8), np.arange(8), indexing=\"ij\")\ndf = pd.DataFrame(\n    {\n        \"Department\": pd.Categorical(\n            [departments[i] for i in dept_idx.ravel()], categories=departments[::-1], ordered=True\n        ),\n        \"Quarter\": pd.Categorical([quarters[j] for j in qtr_idx.ravel()], categories=quarters, ordered=True),\n        \"Growth (%)\": values.ravel(),\n    }\n)\n\n# Theme-adaptive text color: white on dark extremes, INK on mid-range\nif THEME == \"light\":\n    df[\"text_color\"] = np.where(df[\"Growth (%)\"] < -20, \"white\", np.where(df[\"Growth (%)\"] > 28, \"white\", INK))\nelse:\n    df[\"text_color\"] = INK  # light cream on all dark cells in dark theme\n\ndf[\"label\"] = [f\"{v:+.1f}\" for v in df[\"Growth (%)\"]]\n\n# Standard title format — no descriptive prefix needed on square canvas (2400px wide)\ntitle = \"heatmap-basic · python · plotnine · anyplot.ai\"\nn = len(title)\ntitle_fs = max(8, round(12 * 67 / n)) if n > 67 else 12\n\n# Plot\nplot = (\n    ggplot(df, aes(x=\"Quarter\", y=\"Department\"))\n    + geom_tile(aes(fill=\"Growth (%)\"), color=INK_SOFT, size=0.5)\n    + geom_text(aes(label=\"label\", color=\"text_color\"), size=3, fontweight=\"bold\", show_legend=False)\n    + scale_fill_gradient2(\n        low=\"#AE3030\",\n        mid=CMAP_MID,\n        high=\"#4467A3\",\n        midpoint=0,\n        name=\"Growth (%)\",\n        limits=(-35, 40),\n        breaks=[-30, -15, 0, 15, 30],\n    )\n    + scale_color_identity()\n    + scale_x_discrete(expand=(0, 0.5))\n    + scale_y_discrete(expand=(0, 0.5))\n    + labs(x=\"Quarter\", y=\"Department\", title=title, subtitle=\"Year-over-year growth rate (%) · Q1 2023 – Q4 2024\")\n    + theme_minimal()\n    + theme(\n        figure_size=(6, 6),\n        text=element_text(family=\"sans-serif\", color=INK),\n        plot_title=element_text(size=title_fs, ha=\"center\", weight=\"bold\", color=INK),\n        plot_subtitle=element_text(size=8, ha=\"center\", color=INK_SOFT),\n        axis_title_x=element_text(size=10, color=INK, margin={\"t\": 6}),\n        axis_title_y=element_text(size=10, color=INK, margin={\"r\": 6}),\n        axis_text_x=element_text(size=8, color=INK_SOFT, rotation=45, ha=\"right\"),\n        axis_text_y=element_text(size=8, color=INK_SOFT, ha=\"right\"),\n        legend_title=element_text(size=8, weight=\"bold\", color=INK),\n        legend_text=element_text(size=7, color=INK_SOFT),\n        legend_position=\"right\",\n        legend_key_height=12,\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n        panel_grid_major=element_blank(),\n        panel_grid_minor=element_blank(),\n        panel_background=element_rect(fill=PAGE_BG),\n        panel_border=element_rect(color=INK_SOFT, fill=None),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        plot_margin=0.02,\n    )\n)\n\nplot.save(f\"plot-{THEME}.png\", dpi=400, width=6, height=6, units=\"in\", verbose=False)\n"}