{"spec_id":"heatmap-basic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nheatmap-basic: Basic Heatmap\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-28\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport plotly.graph_objects as go\n\n\n# Theme-adaptive chrome\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\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\nGRID = \"rgba(26,26,23,0.15)\" if THEME == \"light\" else \"rgba(240,239,232,0.15)\"\n\n# Imprint diverging colorscale — matte-red ↔ [theme-adaptive midpoint] ↔ blue\n_mid = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nimprint_div = [[0.0, \"#AE3030\"], [0.5, _mid], [1.0, \"#4467A3\"]]\n\n# Data\nnp.random.seed(42)\n\nmonths = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]\ncategories = [\"Electronics\", \"Clothing\", \"Food & Beverage\", \"Books\", \"Sports\", \"Home & Garden\", \"Beauty\", \"Toys\"]\n\n# Monthly sales growth (%) relative to annual average — realistic seasonal patterns\nbase = np.random.randn(len(categories), len(months)) * 8\nfor i, cat in enumerate(categories):\n    if cat in (\"Sports\", \"Toys\", \"Home & Garden\"):\n        base[i, 5:8] += 12  # Summer peak\n    if cat in (\"Electronics\", \"Toys\", \"Books\", \"Beauty\"):\n        base[i, 10:12] += 18  # Holiday season lift\n    if cat == \"Food & Beverage\":\n        base[i, 10:12] += 8  # Modest holiday lift\n    if cat == \"Clothing\":\n        base[i, 3:5] += 10  # Spring fashion\n        base[i, 8:10] += 10  # Back-to-school\nvalues = np.round(base, 1)\n\n# Symmetric color range so zero is exactly the midpoint of the diverging scale\nabs_max = float(np.abs(values).max())\n\nfont_family = \"Palatino, Georgia, serif\"\n\n# Plot\nfig = go.Figure(\n    data=go.Heatmap(\n        z=values,\n        x=months,\n        y=categories,\n        colorscale=imprint_div,\n        zmid=0,\n        zmin=-abs_max,\n        zmax=abs_max,\n        colorbar={\n            \"title\": {\"text\": \"Sales Growth (%)\", \"font\": {\"size\": 12, \"family\": font_family, \"color\": INK}},\n            \"tickfont\": {\"size\": 10, \"family\": font_family, \"color\": INK_SOFT},\n            \"ticksuffix\": \"%\",\n            \"thickness\": 15,\n            \"len\": 0.80,\n            \"x\": 1.01,\n            \"xpad\": 6,\n            \"outlinewidth\": 0,\n            \"bgcolor\": PAGE_BG,\n        },\n        text=values,\n        texttemplate=\"%{text:+.1f}\",\n        textfont={\"size\": 11, \"family\": font_family, \"color\": INK_SOFT},\n        hovertemplate=\"<b>%{y}</b> · %{x}<br>Growth: %{z:+.1f}%<extra></extra>\",\n        xgap=2,\n        ygap=2,\n    )\n)\n\ntitle_str = (\n    \"Monthly Sales Growth · heatmap-basic · plotly · anyplot.ai\"\n    f\"<br><sup style='color:{INK_MUTED}; font-size:10px;'>\"\n    \"Retail categories show clear seasonal surges — \"\n    \"summer outdoor/leisure peaks and Q4 holiday gift spikes\"\n    \"</sup>\"\n)\n\nfig.update_layout(\n    autosize=False,\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font={\"color\": INK, \"family\": font_family},\n    title={\n        \"text\": title_str,\n        \"font\": {\"size\": 16, \"family\": font_family, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n        \"y\": 0.98,\n        \"yanchor\": \"top\",\n    },\n    xaxis={\n        \"title\": {\"text\": \"Month\", \"font\": {\"size\": 12, \"family\": font_family, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"family\": font_family, \"color\": INK_SOFT},\n        \"side\": \"bottom\",\n        \"showgrid\": False,\n        \"linecolor\": INK_SOFT,\n    },\n    yaxis={\n        \"title\": {\"text\": \"Product Category\", \"font\": {\"size\": 12, \"family\": font_family, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"family\": font_family, \"color\": INK_SOFT},\n        \"autorange\": \"reversed\",\n        \"showgrid\": False,\n        \"linecolor\": INK_SOFT,\n    },\n    template=\"plotly_white\",\n    # Square canvas: 600×600 at scale=4 → 2400×2400 px (heatmap = symmetric content)\n    margin={\"l\": 130, \"r\": 80, \"t\": 100, \"b\": 60},\n    width=600,\n    height=600,\n)\n\n# Save — square 2400×2400 canvas\nfig.write_image(f\"plot-{THEME}.png\", width=600, height=600, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}