{"spec_id":"histogram-2d","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nhistogram-2d: 2D Histogram Heatmap\nLibrary: letsplot 4.9.0 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-08\n\"\"\"\n\nimport os\nimport shutil\n\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import *\nfrom lets_plot import ggsave\n\nLetsPlot.setup_html()\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\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\nRULE = \"rgba(26,26,23,0.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\n\n# Data - Bivariate normal distribution with correlation (2000 points)\nnp.random.seed(42)\nn_points = 2000\n\n# Simulating: Customer Age vs Annual Spending ($k)\nmean = [42, 55]  # Average age 42, average spending $55k\ncov = [[120, 60], [60, 200]]  # Positive correlation between age and spending\n\ndata = np.random.multivariate_normal(mean, cov, n_points)\nage = np.clip(data[:, 0], 18, 75)  # Realistic age range\nspending = np.clip(data[:, 1], 5, 120)  # Realistic spending range\n\ndf = pd.DataFrame({\"age\": age, \"spending\": spending})\n\n# Plot - 2D histogram heatmap using geom_bin2d\nplot = (\n    ggplot(df, aes(x=\"age\", y=\"spending\"))\n    + geom_bin2d(bins=[25, 25], alpha=0.95)\n    + scale_fill_viridis(name=\"Count\", option=\"viridis\")\n    + labs(x=\"Customer Age (years)\", y=\"Annual Spending ($k)\", title=\"histogram-2d · letsplot · anyplot.ai\")\n    + theme_minimal()\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_major=element_line(color=RULE, size=0.3),\n        panel_grid_minor=element_blank(),\n        plot_title=element_text(size=24, color=INK, face=\"bold\"),\n        axis_title=element_text(size=20, color=INK),\n        axis_text=element_text(size=16, color=INK_SOFT),\n        axis_line=element_line(color=INK_SOFT, size=0.5),\n        legend_title=element_text(size=18, color=INK),\n        legend_text=element_text(size=16, color=INK_SOFT),\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n    )\n    + ggsize(1600, 900)\n)\n\n# Save\nggsave(plot, f\"plot-{THEME}.png\", scale=3)\nggsave(plot, f\"plot-{THEME}.html\")\n\n# Move files from lets-plot-images to current directory\nif os.path.exists(f\"lets-plot-images/plot-{THEME}.png\"):\n    shutil.move(f\"lets-plot-images/plot-{THEME}.png\", f\"plot-{THEME}.png\")\nif os.path.exists(f\"lets-plot-images/plot-{THEME}.html\"):\n    shutil.move(f\"lets-plot-images/plot-{THEME}.html\", f\"plot-{THEME}.html\")\n# Clean up empty directory\nif os.path.exists(\"lets-plot-images\") and not os.listdir(\"lets-plot-images\"):\n    shutil.rmtree(\"lets-plot-images\")\n"}