{"spec_id":"scatter-matrix","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nscatter-matrix: Scatter Plot Matrix\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 94/100 | Updated: 2026-05-09\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.gridspec import GridSpec\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\"\n\n# Okabe-Ito palette (3 colors for 3 species)\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\"]\n\n# Data: Iris-like flower measurements (4 variables, 3 species)\nnp.random.seed(42)\n\nspecies_params = {\n    \"Setosa\": {\"sl\": (5.0, 0.35), \"sw\": (3.4, 0.38), \"pl\": (1.5, 0.17), \"pw\": (0.2, 0.1)},\n    \"Versicolor\": {\"sl\": (5.9, 0.52), \"sw\": (2.8, 0.31), \"pl\": (4.3, 0.47), \"pw\": (1.3, 0.2)},\n    \"Virginica\": {\"sl\": (6.6, 0.64), \"sw\": (3.0, 0.32), \"pl\": (5.5, 0.55), \"pw\": (2.0, 0.27)},\n}\n\nn_per_species = 50\ndata = {var: [] for var in [\"Sepal Length (cm)\", \"Sepal Width (cm)\", \"Petal Length (cm)\", \"Petal Width (cm)\"]}\nspecies_labels = []\nvar_keys = [\"sl\", \"sw\", \"pl\", \"pw\"]\nvar_names = [\"Sepal Length (cm)\", \"Sepal Width (cm)\", \"Petal Length (cm)\", \"Petal Width (cm)\"]\n\nfor idx, (_species, params) in enumerate(species_params.items()):\n    for key, name in zip(var_keys, var_names, strict=True):\n        mean, std = params[key]\n        data[name].extend(np.random.normal(mean, std, n_per_species))\n    species_labels.extend([idx] * n_per_species)\n\n# Convert to arrays\ndata_arrays = [np.array(data[name]) for name in var_names]\nspecies_names = list(species_params.keys())\nspecies_indices = np.array(species_labels)\nn_vars = len(var_names)\n\n# Create figure with extra space for legend\nfig = plt.figure(figsize=(16, 9), facecolor=PAGE_BG)\ngs = GridSpec(n_vars, n_vars, figure=fig, left=0.08, right=0.88, wspace=0.15, hspace=0.15)\naxes = [[fig.add_subplot(gs[i, j]) for j in range(n_vars)] for i in range(n_vars)]\n\n# Plot each cell\nfor i in range(n_vars):\n    for j in range(n_vars):\n        ax = axes[i][j]\n        ax.set_facecolor(PAGE_BG)\n\n        if i == j:\n            # Diagonal: histograms with enhanced visual hierarchy\n            for species_idx, (_species, color) in enumerate(zip(species_names, IMPRINT, strict=True)):\n                mask = species_indices == species_idx\n                species_data = data_arrays[i][mask]\n                ax.hist(species_data, bins=12, alpha=0.85, color=color, edgecolor=INK_SOFT, linewidth=1.0)\n        else:\n            # Off-diagonal: scatter plots with enhanced marker definition\n            for species_idx, (_species, color) in enumerate(zip(species_names, IMPRINT, strict=True)):\n                mask = species_indices == species_idx\n                ax.scatter(\n                    data_arrays[j][mask],\n                    data_arrays[i][mask],\n                    c=color,\n                    s=140,\n                    alpha=0.8,\n                    edgecolors=INK_SOFT,\n                    linewidth=0.8,\n                )\n\n        # Grid styling\n        ax.grid(True, alpha=0.12, linestyle=\"-\", color=INK_SOFT, linewidth=0.6)\n        ax.tick_params(axis=\"both\", labelsize=14, colors=INK_SOFT)\n\n        # Remove top and right spines for refined look\n        ax.spines[\"top\"].set_visible(False)\n        ax.spines[\"right\"].set_visible(False)\n        ax.spines[\"left\"].set_color(INK_SOFT)\n        ax.spines[\"left\"].set_linewidth(0.8)\n        ax.spines[\"bottom\"].set_color(INK_SOFT)\n        ax.spines[\"bottom\"].set_linewidth(0.8)\n\n        # Visual distinction: subtle background for diagonal (histogram) cells\n        if i == j:\n            ax.set_facecolor(ELEVATED_BG)\n        else:\n            ax.set_facecolor(PAGE_BG)\n\n        # Axis labels only on edges\n        if i == n_vars - 1:\n            ax.set_xlabel(var_names[j], fontsize=18, color=INK)\n        else:\n            ax.set_xticklabels([])\n\n        if j == 0:\n            ax.set_ylabel(var_names[i], fontsize=18, color=INK)\n        else:\n            ax.set_yticklabels([])\n\n# Legend outside matrix (right side)\nlegend_elements = [\n    plt.Line2D(\n        [0],\n        [0],\n        marker=\"o\",\n        color=\"w\",\n        markerfacecolor=color,\n        markersize=12,\n        label=species,\n        markeredgecolor=PAGE_BG,\n        markeredgewidth=0.5,\n    )\n    for species, color in zip(species_names, IMPRINT, strict=True)\n]\nleg = fig.legend(\n    handles=legend_elements, loc=\"center right\", fontsize=16, frameon=True, fancybox=False, edgecolor=INK_SOFT\n)\nleg.get_frame().set_facecolor(ELEVATED_BG)\nleg.get_frame().set_edgecolor(INK_SOFT)\nfor text in leg.get_texts():\n    text.set_color(INK)\n\n# Title\nfig.suptitle(\"scatter-matrix · matplotlib · anyplot.ai\", fontsize=24, fontweight=\"medium\", color=INK, y=0.98)\n\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}