{"spec_id":"heatmap-basic","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nheatmap-basic: Basic Heatmap\nLibrary: letsplot 4.10.1 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-28\n\"\"\"\n\nimport os\n\nimport numpy as np\nfrom lets_plot import (\n    LetsPlot,\n    aes,\n    element_blank,\n    element_rect,\n    element_text,\n    geom_text,\n    geom_tile,\n    ggplot,\n    ggsize,\n    guide_colorbar,\n    labs,\n    layer_tooltips,\n    scale_color_identity,\n    scale_fill_gradient,\n    scale_x_discrete,\n    scale_y_discrete,\n    theme,\n    theme_minimal,\n)\nfrom lets_plot.export import ggsave\n\n\nLetsPlot.setup_html()\n\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# Data - Monthly energy consumption (kWh) by building zone\nnp.random.seed(42)\nmonths = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]\nzones = [\"Lobby\", \"Offices\", \"Lab\", \"Server Room\", \"Cafeteria\", \"Warehouse\"]\n\n# Realistic patterns: seasonal variation + zone-specific baselines\nbaselines = np.array([120, 280, 350, 520, 180, 90])\nseasonal = np.array([1.3, 1.2, 1.0, 0.8, 0.7, 0.75, 0.85, 0.9, 0.8, 0.9, 1.1, 1.25])\n\nvalues = np.outer(seasonal, baselines)\nnoise = np.random.normal(0, 15, (len(months), len(zones)))\nvalues = np.round(values + noise, 0).astype(int)\n\n# Build long-form data using vectorized operations\nn_months, n_zones = len(months), len(zones)\nzone_col = np.tile(zones, n_months).tolist()\nmonth_col = np.repeat(months, n_zones).tolist()\nkwh_col = values.flatten().tolist()\n\n# Adaptive text color: dark on green cells (low kWh), white on blue cells (high kWh)\n# Imprint sequential: low → #009E73 (bright green), high → #4467A3 (dark blue)\nmedian_val = int(np.median(kwh_col))\ntext_color = [\"#FAF8F1\" if v > median_val else \"#1A1A17\" for v in kwh_col]\n\ndata = {\"Zone\": zone_col, \"Month\": month_col, \"kWh\": kwh_col, \"label_color\": text_color}\n\n# Heatmap with Imprint sequential colormap (brand green → blue)\nplot = (\n    ggplot(data, aes(x=\"Zone\", y=\"Month\", fill=\"kWh\"))\n    + geom_tile(\n        width=0.92,\n        height=0.92,\n        tooltips=layer_tooltips()\n        .line(\"@Zone | @Month\")\n        .line(\"Energy: @kWh kWh\")\n        .line(\"Median: \" + str(median_val) + \" kWh\"),\n    )\n    + geom_text(aes(label=\"kWh\", color=\"label_color\"), size=3.5, fontface=\"bold\")\n    + scale_color_identity()\n    + scale_fill_gradient(\n        low=\"#009E73\", high=\"#4467A3\", name=\"Energy (kWh)\", guide=guide_colorbar(barwidth=10, barheight=200, nbin=256)\n    )\n    + scale_x_discrete(limits=zones)\n    + scale_y_discrete(limits=months[::-1])\n    + labs(x=\"Building Zone\", y=\"Month\", title=\"heatmap-basic · python · letsplot · anyplot.ai\")\n    + theme_minimal()\n    + theme(\n        plot_title=element_text(size=16, face=\"bold\", color=INK),\n        axis_title=element_text(size=12, color=INK),\n        axis_text_x=element_text(size=10, face=\"bold\", color=INK_SOFT),\n        axis_text_y=element_text(size=10, color=INK_SOFT),\n        legend_text=element_text(size=10, color=INK_SOFT),\n        legend_title=element_text(size=12, face=\"bold\", color=INK),\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n        panel_grid=element_blank(),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG),\n        plot_margin=[40, 20, 20, 20],\n    )\n    + ggsize(600, 600)\n)\n\n# Square canvas: ggsize(600, 600) × scale=4 → 2400×2400 px\nggsave(plot, f\"plot-{THEME}.png\", path=\".\", scale=4)\n\n# HTML for interactive tooltips\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}