codexchroma-sampling-grids.py
chroma-sampling-grids.py
"""Write chroma-sampling-grids.png in cwd; Python 3.14, NumPy 2.3, Matplotlib 3.10."""
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
luma = np.array([(x, y) for y in range(4) for x in range(4)])
grids = [luma, np.array([(x, y) for y in range(4) for x in (.5, 2.5)]), np.array([(x, y) for y in (.5, 2.5) for x in (.5, 2.5)])]
assert [len(x) for x in grids] == [16, 8, 4]
fig, axes = plt.subplots(1, 3, figsize=(7.8, 3.15), dpi=100, facecolor='white')
for ax, grid, title in zip(axes, grids, ['4:4:4 16 Y + 16 Cb + 16 Cr', '4:2:2 16 Y + 8 Cb + 8 Cr', '4:2:0 16 Y + 4 Cb + 4 Cr']):
ax.scatter(luma[:, 0], luma[:, 1], marker='+', s=60, color='#222222', linewidth=1.5, zorder=2)
ax.scatter(grid[:, 0], grid[:, 1], marker='o', s=125, facecolors='none', edgecolors='#126ba3', linewidth=1.7, zorder=3)
ax.set(xlim=(-.4, 3.4), ylim=(3.4, -.4), aspect='equal', xticks=range(4), yticks=range(4), xlabel='horizontal position')
ax.set_title(title, fontsize=10)
ax.tick_params(labelsize=8)
ax.grid(alpha=.18)
axes[0].set_ylabel('vertical position')
fig.text(.5, .07, '+ luma sample blue circle: one Cb and one Cr sample', ha='center', fontsize=10)
fig.text(.5, .015, 'Illustrative progressive grids; centred chroma is a declared choice, not a universal format rule.', ha='center', fontsize=9)
fig.subplots_adjust(left=.07, right=.99, top=.86, bottom=.23, wspace=.24)
fig.savefig('chroma-sampling-grids.png', facecolor='white')
plt.close(fig)