Skip to content

Commit edfd3ae

Browse files
feat(matplotlib): implement scatter-matrix (#2248)
## Implementation: `scatter-matrix` - matplotlib Implements the **matplotlib** version of `scatter-matrix`. **File:** `plots/scatter-matrix/implementations/matplotlib.py` --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20525444128)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent ae63566 commit edfd3ae

2 files changed

Lines changed: 117 additions & 0 deletions

File tree

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
""" pyplots.ai
2+
scatter-matrix: Scatter Plot Matrix
3+
Library: matplotlib 3.10.8 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-26
5+
"""
6+
7+
import matplotlib.pyplot as plt
8+
import numpy as np
9+
from matplotlib.gridspec import GridSpec
10+
11+
12+
# Data: Iris-like flower measurements (4 variables, 3 species)
13+
np.random.seed(42)
14+
15+
# Species parameters (mean, std for each measurement)
16+
species_params = {
17+
"Setosa": {"sl": (5.0, 0.35), "sw": (3.4, 0.38), "pl": (1.5, 0.17), "pw": (0.2, 0.1)},
18+
"Versicolor": {"sl": (5.9, 0.52), "sw": (2.8, 0.31), "pl": (4.3, 0.47), "pw": (1.3, 0.2)},
19+
"Virginica": {"sl": (6.6, 0.64), "sw": (3.0, 0.32), "pl": (5.5, 0.55), "pw": (2.0, 0.27)},
20+
}
21+
22+
n_per_species = 50
23+
data = {var: [] for var in ["Sepal Length (cm)", "Sepal Width (cm)", "Petal Length (cm)", "Petal Width (cm)"]}
24+
species_labels = []
25+
var_keys = ["sl", "sw", "pl", "pw"]
26+
var_names = ["Sepal Length (cm)", "Sepal Width (cm)", "Petal Length (cm)", "Petal Width (cm)"]
27+
28+
for species, params in species_params.items():
29+
for key, name in zip(var_keys, var_names, strict=True):
30+
mean, std = params[key]
31+
data[name].extend(np.random.normal(mean, std, n_per_species))
32+
species_labels.extend([species] * n_per_species)
33+
34+
# Convert to arrays
35+
data_arrays = [np.array(data[name]) for name in var_names]
36+
n_vars = len(var_names)
37+
38+
# Colors for species
39+
colors_map = {"Setosa": "#306998", "Versicolor": "#FFD43B", "Virginica": "#4CAF50"}
40+
colors = [colors_map[s] for s in species_labels]
41+
42+
# Create scatter plot matrix using GridSpec for tighter control (square format)
43+
fig = plt.figure(figsize=(12, 12))
44+
gs = GridSpec(n_vars, n_vars, figure=fig, wspace=0.08, hspace=0.08)
45+
axes = [[fig.add_subplot(gs[i, j]) for j in range(n_vars)] for i in range(n_vars)]
46+
47+
# Plot each cell
48+
for i in range(n_vars):
49+
for j in range(n_vars):
50+
ax = axes[i][j]
51+
52+
if i == j:
53+
# Diagonal: histograms for each species
54+
for species, color in colors_map.items():
55+
mask = [s == species for s in species_labels]
56+
species_data = data_arrays[i][mask]
57+
ax.hist(species_data, bins=12, alpha=0.7, color=color, edgecolor="white", linewidth=0.5)
58+
else:
59+
# Off-diagonal: scatter plots with increased marker size
60+
ax.scatter(data_arrays[j], data_arrays[i], c=colors, s=70, alpha=0.6, edgecolors="white", linewidth=0.5)
61+
62+
# Grid styling
63+
ax.grid(True, alpha=0.3, linestyle="--")
64+
ax.tick_params(axis="both", labelsize=16)
65+
66+
# Axis labels only on edges with proper font sizes
67+
if i == n_vars - 1:
68+
ax.set_xlabel(var_names[j], fontsize=20)
69+
else:
70+
ax.set_xticklabels([])
71+
72+
if j == 0:
73+
ax.set_ylabel(var_names[i], fontsize=20)
74+
else:
75+
ax.set_yticklabels([])
76+
77+
# Legend (add to top-right subplot with larger marker size)
78+
legend_elements = [
79+
plt.Line2D([0], [0], marker="o", color="w", markerfacecolor=color, markersize=14, label=species)
80+
for species, color in colors_map.items()
81+
]
82+
axes[0][n_vars - 1].legend(handles=legend_elements, loc="upper right", fontsize=16, framealpha=0.9)
83+
84+
# Title with proper font size
85+
fig.suptitle("scatter-matrix · matplotlib · pyplots.ai", fontsize=24, y=0.995)
86+
87+
plt.savefig("plot.png", dpi=300, bbox_inches="tight")
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
library: matplotlib
2+
specification_id: scatter-matrix
3+
created: '2025-12-26T16:13:20Z'
4+
updated: '2025-12-26T16:23:50Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20525444128
7+
issue: 0
8+
python_version: 3.13.11
9+
library_version: 3.10.8
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/scatter-matrix/matplotlib/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/scatter-matrix/matplotlib/plot_thumb.png
12+
preview_html: null
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent implementation of the scatter plot matrix with clear visual separation
17+
of species clusters
18+
- Proper use of GridSpec for tight subplot spacing creating a cohesive matrix appearance
19+
- Appropriate use of transparency (alpha=0.6 for scatter, 0.7 for histograms) to
20+
handle overlapping points
21+
- Clean axis label placement with labels only on edges (left and bottom)
22+
- Well-chosen colorblind-safe palette with good contrast
23+
- Realistic Iris-like data with biologically plausible parameters
24+
weaknesses:
25+
- Legend placement in top-right subplot overlaps with scatter data in that cell;
26+
consider placing legend outside the matrix or in a dedicated area
27+
- Scatter marker size (s=70) is adequate but could be slightly larger for better
28+
visibility given the data density
29+
- Could leverage more distinctive matplotlib features like shared axes linking or
30+
colorbar for additional encoding

0 commit comments

Comments
 (0)