{"spec_id":"scatter-matrix","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nscatter-matrix: Scatter Plot Matrix\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 89/100 | Updated: 2026-05-09\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\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# Okabe-Ito palette\nIMPRINT = [\n    \"#009E73\",  # bluish green (brand, first series)\n    \"#C475FD\",  # vermillion\n    \"#4467A3\",  # blue\n]\n\n# Data - Weather station measurements across 4 variables\nnp.random.seed(42)\nn = 200\n\n# Weather data: daily measurements from 3 different geographic regions\nregion = np.repeat([\"Coastal\", \"Mountain\", \"Desert\"], n // 3)\n\n# Temperature (°C) - region-specific distributions\ntemperature = np.concatenate(\n    [\n        np.random.normal(18, 2.5, n // 3),  # Coastal - moderate\n        np.random.normal(12, 3.0, n // 3),  # Mountain - cooler\n        np.random.normal(28, 4.0, n // 3),  # Desert - hot\n    ]\n)\n\n# Humidity (%) - inverse to temperature\nhumidity = np.concatenate(\n    [\n        np.random.normal(72, 8, n // 3),  # Coastal - high\n        np.random.normal(65, 10, n // 3),  # Mountain - moderate\n        np.random.normal(35, 12, n // 3),  # Desert - low\n    ]\n)\n\n# Pressure (hPa) - region-specific\npressure = np.concatenate(\n    [\n        np.random.normal(1013, 2, n // 3),  # Coastal - sea level\n        np.random.normal(950, 3, n // 3),  # Mountain - high altitude\n        np.random.normal(1010, 2, n // 3),  # Desert - high\n    ]\n)\n\n# Wind speed (m/s) - variable by region\nwind_speed = np.concatenate(\n    [\n        np.random.normal(4.5, 1.5, n // 3),  # Coastal - breezy\n        np.random.normal(6.0, 2.0, n // 3),  # Mountain - stronger winds\n        np.random.normal(3.5, 1.2, n // 3),  # Desert - lighter winds\n    ]\n)\n\ndf = pd.DataFrame(\n    {\n        \"Temperature (°C)\": temperature,\n        \"Humidity (%)\": humidity,\n        \"Pressure (hPa)\": pressure,\n        \"Wind Speed (m/s)\": wind_speed,\n        \"Region\": region,\n    }\n)\n\n# Variables for matrix\ndimensions = [\"Temperature (°C)\", \"Humidity (%)\", \"Pressure (hPa)\", \"Wind Speed (m/s)\"]\nregion_list = [\"Coastal\", \"Mountain\", \"Desert\"]\nregion_colors = {\"Coastal\": IMPRINT[0], \"Mountain\": IMPRINT[1], \"Desert\": IMPRINT[2]}\nn_dims = len(dimensions)\n\n# Create subplots grid\nfig = make_subplots(rows=n_dims, cols=n_dims, horizontal_spacing=0.04, vertical_spacing=0.04)\n\n# Track legend status\nlegend_added = dict.fromkeys(region_list, False)\n\n# Build scatter matrix with histograms on diagonal\nfor i, dim_y in enumerate(dimensions):\n    for j, dim_x in enumerate(dimensions):\n        row, col = i + 1, j + 1\n\n        if i == j:\n            # Diagonal: histograms\n            for region in region_list:\n                mask = df[\"Region\"] == region\n                fig.add_trace(\n                    go.Histogram(\n                        x=df.loc[mask, dim_x],\n                        name=region,\n                        marker=dict(color=region_colors[region]),\n                        opacity=0.75,\n                        showlegend=not legend_added[region],\n                        legendgroup=region,\n                        nbinsx=15,\n                    ),\n                    row=row,\n                    col=col,\n                )\n                legend_added[region] = True\n            fig.update_xaxes(showticklabels=True, row=row, col=col)\n            fig.update_yaxes(showticklabels=False, row=row, col=col)\n        else:\n            # Off-diagonal: scatter plots\n            for region in region_list:\n                mask = df[\"Region\"] == region\n                fig.add_trace(\n                    go.Scatter(\n                        x=df.loc[mask, dim_x],\n                        y=df.loc[mask, dim_y],\n                        mode=\"markers\",\n                        name=region,\n                        marker=dict(\n                            color=region_colors[region], size=8, opacity=0.7, line=dict(width=0.5, color=PAGE_BG)\n                        ),\n                        showlegend=False,\n                        legendgroup=region,\n                    ),\n                    row=row,\n                    col=col,\n                )\n\n        # Add axis labels on edges only\n        if i == n_dims - 1:\n            fig.update_xaxes(title_text=dim_x, row=row, col=col, title_font=dict(size=20, color=INK))\n        if j == 0:\n            fig.update_yaxes(title_text=dim_y, row=row, col=col, title_font=dict(size=20, color=INK))\n\n# Update overall layout\nfig.update_layout(\n    title=dict(text=\"scatter-matrix · plotly · anyplot.ai\", font=dict(size=28, color=INK), x=0.5, xanchor=\"center\"),\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font=dict(size=16, color=INK),\n    legend=dict(\n        bgcolor=ELEVATED_BG,\n        bordercolor=INK_SOFT,\n        borderwidth=1,\n        font=dict(size=18, color=INK_SOFT),\n        title=dict(text=\"Region\", font=dict(size=20, color=INK)),\n        yanchor=\"top\",\n        y=0.98,\n        xanchor=\"right\",\n        x=0.98,\n    ),\n    showlegend=True,\n    barmode=\"overlay\",\n    margin=dict(l=100, r=100, t=120, b=100),\n)\n\n# Update all axes with theme-adaptive colors\nfig.update_xaxes(tickfont=dict(size=16, color=INK_SOFT), showgrid=True, gridwidth=1, gridcolor=GRID, linecolor=INK_SOFT)\nfig.update_yaxes(tickfont=dict(size=16, color=INK_SOFT), showgrid=True, gridwidth=1, gridcolor=GRID, linecolor=INK_SOFT)\n\n# Save as PNG (square format for matrix)\nfig.write_image(f\"plot-{THEME}.png\", width=1600, height=1600, scale=3)\n\n# Save interactive HTML\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}