{"spec_id":"histogram-2d","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nhistogram-2d: 2D Histogram Heatmap\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 94/100 | Updated: 2026-05-08\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport plotly.graph_objects as go\nfrom plotly.subplots import make_subplots\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\"\nGRID = \"rgba(26,26,23,0.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\n\n# Data - customer age vs annual purchase frequency in retail market research\nnp.random.seed(42)\nn_points = 5000\n\n# Create correlated data: older customers tend to have slightly higher purchase frequency\n# with realistic distributions\nmean = [45, 25]  # Mean age and mean purchases per year\ncov = [[150, 35], [35, 120]]  # Positive correlation (0.6)\ndata = np.random.multivariate_normal(mean, cov, n_points)\nage = np.clip(data[:, 0], 18, 85)  # Realistic age range\npurchases = np.clip(data[:, 1], 0, 80)  # Purchases per year\n\n# Create figure with marginal histograms using shared_xaxes/shared_yaxes\nfig = make_subplots(\n    rows=2,\n    cols=2,\n    column_widths=[0.8, 0.2],\n    row_heights=[0.2, 0.8],\n    horizontal_spacing=0.01,\n    vertical_spacing=0.01,\n    shared_xaxes=True,\n    shared_yaxes=True,\n    specs=[[{\"type\": \"histogram\"}, None], [{\"type\": \"histogram2d\"}, {\"type\": \"histogram\"}]],\n)\n\n# Main 2D histogram heatmap\nfig.add_trace(\n    go.Histogram2d(\n        x=age,\n        y=purchases,\n        colorscale=\"Viridis\",\n        nbinsx=40,\n        nbinsy=40,\n        colorbar=dict(\n            title=dict(text=\"Count\", font=dict(size=20)), tickfont=dict(size=16), len=0.65, y=0.35, yanchor=\"middle\"\n        ),\n    ),\n    row=2,\n    col=1,\n)\n\n# Marginal histogram for age (top)\nfig.add_trace(\n    go.Histogram(x=age, nbinsx=40, marker=dict(color=\"#009E73\", line=dict(width=0)), showlegend=False), row=1, col=1\n)\n\n# Marginal histogram for purchases (right)\nfig.add_trace(\n    go.Histogram(y=purchases, nbinsy=40, marker=dict(color=\"#009E73\", line=dict(width=0)), showlegend=False),\n    row=2,\n    col=2,\n)\n\n# Update layout with theme-adaptive styling\nfig.update_layout(\n    title=dict(\n        text=\"histogram-2d · plotly · anyplot.ai\", font=dict(size=28, color=INK), x=0.5, xanchor=\"center\", y=0.98\n    ),\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font=dict(color=INK),\n    bargap=0.02,\n)\n\n# Update axes for main plot with descriptive labels\nfig.update_xaxes(\n    title=dict(text=\"Customer Age (years)\", font=dict(size=22, color=INK)),\n    tickfont=dict(size=18, color=INK_SOFT),\n    gridcolor=GRID,\n    linecolor=INK_SOFT,\n    row=2,\n    col=1,\n)\nfig.update_yaxes(\n    title=dict(text=\"Annual Purchases (count)\", font=dict(size=22, color=INK)),\n    tickfont=dict(size=18, color=INK_SOFT),\n    gridcolor=GRID,\n    linecolor=INK_SOFT,\n    row=2,\n    col=1,\n)\n\n# Configure marginal histogram axes with grid lines\nfig.update_xaxes(showticklabels=False, gridcolor=GRID, linecolor=INK_SOFT, row=1, col=1)\nfig.update_yaxes(showticklabels=False, gridcolor=GRID, linecolor=INK_SOFT, row=1, col=1)\nfig.update_xaxes(showticklabels=False, gridcolor=GRID, linecolor=INK_SOFT, row=2, col=2)\nfig.update_yaxes(showticklabels=False, gridcolor=GRID, linecolor=INK_SOFT, row=2, col=2)\n\n# Save as PNG (4800 x 2700 px)\nfig.write_image(f\"plot-{THEME}.png\", width=1600, height=900, scale=3)\n\n# Save as interactive HTML\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}