{"spec_id":"heatmap-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nheatmap-basic: Basic Heatmap\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-28\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport seaborn as sns\nfrom matplotlib.colors import LinearSegmentedColormap\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 — theme-adaptive midpoint (matte-red ↔ neutral ↔ blue)\nmidpoint = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nimprint_div = LinearSegmentedColormap.from_list(\"imprint_div\", [\"#AE3030\", midpoint, \"#4467A3\"])\n\n# Global seaborn style\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    },\n)\n\n# Data — monthly performance metrics across departments\nnp.random.seed(42)\ndepartments = [\"Sales\", \"Marketing\", \"Engineering\", \"Support\", \"Finance\", \"HR\", \"Operations\"]\nmonths = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]\n\ndata = np.random.randn(len(departments), len(months)) * 20 + 50\ndata[0, :6] += 20  # Sales surge first half\ndata[2, 6:] += 25  # Engineering ramp second half\ndata[4, :] = data[4, :] * 0.3 + 70  # Finance steady high\ndata[5, 3:9] -= 15  # HR mid-year dip\ndata[3, 10:] -= 22  # Support year-end slump (sharp outlier)\ndata = np.clip(data, 5, 95)\n\n# Plot\ntitle = \"heatmap-basic · python · seaborn · anyplot.ai\"\nn = len(title)\nratio = 67 / n if n > 67 else 1.0\ntitle_fontsize = max(8, round(12 * ratio))\n\ng = sns.clustermap(\n    data,\n    annot=True,\n    fmt=\".0f\",\n    cmap=imprint_div,\n    center=50,\n    xticklabels=months,\n    yticklabels=departments,\n    linewidths=1.0,\n    linecolor=INK_SOFT,\n    annot_kws={\"fontsize\": 10, \"fontweight\": \"medium\", \"color\": INK},\n    figsize=(6, 6),\n    row_cluster=True,\n    col_cluster=False,\n    dendrogram_ratio=0.08,\n    cbar_pos=(0.05, 0.15, 0.04, 0.6),\n    cbar_kws={\"ticks\": [0, 25, 50, 75, 100]},\n    vmin=0,\n    vmax=100,\n)\ng.figure.set_dpi(400)\n\n# Background\ng.figure.patch.set_facecolor(PAGE_BG)\ng.ax_heatmap.set_facecolor(PAGE_BG)\n\n# Style row dendrogram\ng.ax_row_dendrogram.set_facecolor(PAGE_BG)\nfor spine in g.ax_row_dendrogram.spines.values():\n    spine.set_visible(False)\nfor line in g.ax_row_dendrogram.get_lines():\n    line.set_color(INK_SOFT)\n\n# Style column dendrogram area (empty when col_cluster=False)\nif g.ax_col_dendrogram is not None:\n    g.ax_col_dendrogram.set_facecolor(PAGE_BG)\n    for spine in g.ax_col_dendrogram.spines.values():\n        spine.set_visible(False)\n\n# Colorbar styling — small labelpad keeps label on-canvas given cbar_pos x=0.05\ng.cax.set_ylabel(\"Performance Score\", fontsize=9, labelpad=2, color=INK)\ng.cax.yaxis.set_label_position(\"left\")\ng.cax.tick_params(labelsize=7, colors=INK_SOFT)\nfor spine in g.cax.spines.values():\n    spine.set_color(INK_SOFT)\n\n# Axis labels and ticks\ng.ax_heatmap.set_xlabel(\"Month\", fontsize=10, labelpad=10, color=INK)\ng.ax_heatmap.set_ylabel(\"\", fontsize=10)\ng.ax_heatmap.tick_params(axis=\"x\", labelsize=8, colors=INK_SOFT)\ng.ax_heatmap.tick_params(axis=\"y\", labelsize=8, rotation=0, colors=INK_SOFT)\n\n# Remove heatmap spines\nfor spine in g.ax_heatmap.spines.values():\n    spine.set_visible(False)\n\n# Title\ng.figure.subplots_adjust(top=0.92)\ng.figure.suptitle(title, fontsize=title_fontsize, fontweight=\"medium\", color=INK)\n\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}