{"spec_id":"heatmap-correlation","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nheatmap-correlation: Correlation Matrix Heatmap\nLibrary: letsplot 4.11.0 | Python 3.13.15\nQuality: 88/100 | Updated: 2026-08-18\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\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    ggsave,\n    ggsize,\n    labs,\n    scale_color_identity,\n    scale_fill_gradient2,\n    theme,\n)\n\n\nLetsPlot.setup_html()\n\n# Theme tokens (see prompts/default-style-guide.md \"Theme-adaptive Chrome\")\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\"\nMIDPOINT = PAGE_BG  # imprint_div midpoint is theme-adaptive\n\n# Data - realistic dataset with meaningful correlations\nnp.random.seed(42)\nn = 200\n\nrevenue = np.random.normal(100, 20, n)\nmarketing_spend = 0.3 * revenue + np.random.normal(10, 5, n)\nemployees = 0.5 * revenue + np.random.normal(20, 10, n)\ncustomer_satisfaction = 0.4 * employees - 0.1 * marketing_spend + np.random.normal(50, 15, n)\nprofit = 0.7 * revenue - 0.5 * marketing_spend + np.random.normal(20, 10, n)\nmarket_share = 0.3 * revenue + 0.2 * customer_satisfaction + np.random.normal(15, 5, n)\ninnovation_index = np.random.normal(60, 20, n)  # Independent variable\ndebt_ratio = -0.4 * profit + np.random.normal(30, 10, n)\n\ndf = pd.DataFrame(\n    {\n        \"Revenue\": revenue,\n        \"Marketing\": marketing_spend,\n        \"Employees\": employees,\n        \"Satisfaction\": customer_satisfaction,\n        \"Profit\": profit,\n        \"Market Share\": market_share,\n        \"Innovation\": innovation_index,\n        \"Debt Ratio\": debt_ratio,\n    }\n)\n\ncorr_matrix = df.corr()\nvariables = corr_matrix.columns.tolist()\nvar_pos = {v: i for i, v in enumerate(variables)}\n\n# Long format for geom_tile; annotation color adapts to per-cell contrast\n# (near-zero cells sit on the theme-adaptive midpoint, extremes on saturated\n# red/blue) rather than a single hardcoded color. Upper triangle is masked\n# (spec: \"Consider masking upper or lower triangle to reduce redundancy\") —\n# every pair is symmetric, so only the lower triangle + diagonal is kept.\ncorr_data = []\nfor var_y in variables:\n    for var_x in variables:\n        if var_pos[var_x] > var_pos[var_y]:\n            continue\n        corr_val = corr_matrix.loc[var_y, var_x]\n        corr_data.append(\n            {\n                \"x\": var_x,\n                \"y\": var_y,\n                \"correlation\": corr_val,\n                \"label\": f\"{corr_val:.2f}\",\n                \"text_color\": \"#FFFFFF\" if abs(corr_val) > 0.5 else INK,\n            }\n        )\n\ncorr_df = pd.DataFrame(corr_data)\ncorr_df[\"x\"] = pd.Categorical(corr_df[\"x\"], categories=variables, ordered=True)\ncorr_df[\"y\"] = pd.Categorical(corr_df[\"y\"], categories=variables[::-1], ordered=True)\n\n# Storytelling focal point: outline the strongest off-diagonal correlation\n# so the reader's eye lands on the standout relationship, not just a flat grid.\noff_diagonal = corr_df[corr_df[\"x\"].astype(str) != corr_df[\"y\"].astype(str)]\nstrongest = off_diagonal.loc[off_diagonal[\"correlation\"].abs().idxmax()]\nhighlight_df = pd.DataFrame([strongest])\n\n# Title — mandated format, scaled per prompts/plot-generator.md\ntitle = \"heatmap-correlation · python · letsplot · anyplot.ai\"\ntitle_fontsize = round(16 * min(1.0, 67 / len(title)))\n\n# Plot — square canvas for a symmetric matrix (600x600 @ scale=4 -> 2400x2400)\nplot = (\n    ggplot(corr_df, aes(x=\"x\", y=\"y\", fill=\"correlation\"))\n    + geom_tile(color=PAGE_BG, size=1.5)\n    + geom_tile(data=highlight_df, fill=PAGE_BG, alpha=0, color=INK, size=3, tooltips=\"none\")\n    + geom_text(aes(label=\"label\", color=\"text_color\"), size=4.5, fontface=\"bold\", tooltips=\"none\")\n    + scale_color_identity()\n    + scale_fill_gradient2(\n        low=\"#AE3030\",  # Imprint diverging — negative correlation\n        mid=MIDPOINT,  # theme-adaptive midpoint\n        high=\"#4467A3\",  # Imprint diverging — positive correlation\n        midpoint=0,\n        limits=[-1, 1],\n        name=\"Correlation\",\n    )\n    + labs(x=\"Financial Metric\", y=\"Financial Metric\", title=title)\n    + theme(\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_grid=element_blank(),\n        axis_ticks=element_blank(),\n        axis_line=element_blank(),\n        plot_title=element_text(size=title_fontsize, face=\"bold\", color=INK),\n        axis_title=element_text(size=12, color=INK),\n        axis_text_x=element_text(size=10, color=INK_SOFT, angle=45, hjust=1),\n        axis_text_y=element_text(size=10, color=INK_SOFT),\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n        legend_title=element_text(size=11, color=INK),\n        legend_text=element_text(size=10, color=INK_SOFT),\n    )\n    + ggsize(600, 600)\n)\n\n# Save (PNG + interactive HTML)\nggsave(plot, f\"plot-{THEME}.png\", path=\".\", scale=4)\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}