codexorientation-selectivity-signed-bars.py
orientation-selectivity-signed-bars.py
"""Original signed-filter schematic; all numbers are toy assumptions, not data.
Run from _media with MPLCONFIGDIR=/tmp/codex-wiki-matplotlib.
Tested with Python 3.14.4, matplotlib 3.10.7 and numpy 2.3.5.
Writes only orientation-selectivity-signed-bars.png to CWD.
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import ListedColormap
OUTPUT = Path("orientation-selectivity-signed-bars.png")
def main():
plt.rcParams.update({"font.family": "DejaVu Sans", "font.size": 11})
weights = np.tile(np.array([-.5, -.5, 2., -.5, -.5]) / 10, (5, 1))
central = np.zeros((5, 5)); central[:, 2] = 1
horizontal = np.zeros((5, 5)); horizontal[2, :] = 1
shifted = np.zeros((5, 5)); shifted[:, 3] = 1
stimuli = [central, horizontal, np.ones((5, 5)), shifted, -shifted]
titles = ["Centered bright bar", "Rotated bright bar", "Uniform bright patch",
"Shifted bright bar", "Shifted dark bar"]
drives = [round(float(np.sum(weights * stimulus)), 12) for stimulus in stimuli]
assert np.allclose(drives, [1, 0, 0, -.25, .25], atol=1e-14)
fig = plt.figure(figsize=(9, 6.3), dpi=120, facecolor="white")
grid = fig.add_gridspec(2, 5, left=.045, right=.97, bottom=.14, top=.84,
hspace=.63, wspace=.35)
fig.suptitle("Orientation, position and polarity: a signed-filter toy", fontsize=16,
weight="bold", y=.97)
fig.text(.5, .91, "Original schematic • chosen weights • not measured receptive fields or spikes",
ha="center", fontsize=10.5)
ax = fig.add_subplot(grid[0, :2])
ax.imshow(weights, cmap=ListedColormap(["#cee4f3", "#f6c8a2"]),
vmin=-.05, vmax=.2, origin="lower")
for y in range(5):
for x in range(5):
ax.text(x, y, "+" if x == 2 else "−", ha="center", va="center",
fontsize=16, color="#24364a")
ax.set_title("A. Weight map K (5 × 5)", fontsize=11, weight="bold", pad=10)
ax.set_xticks([]); ax.set_yticks([])
ax.set_xlabel("OFF-like flanks | ON-like center", fontsize=10, labelpad=8)
ax = fig.add_subplot(grid[0, 2:])
ax.axis("off")
ax.text(.02, .94, "B. Multiply each contrast by its weight; add", weight="bold", va="top")
ax.text(.02, .77, r"$D=\sum K_{ij}C_{ij}$ $R=\max(0,D)$", fontsize=15, va="top")
ax.text(.02, .55, "Each + site: K = +0.20; each − site: K = −0.05\nC = +1: bright; C = 0: background; C = −1: dark",
fontsize=10, linespacing=1.8, va="top")
ax.text(.02, .20, "D is signed drive; R is rectified toy output.\nNeither is a measured firing rate.",
fontsize=10, color="#42566b", va="top")
for index, (stimulus, title, drive) in enumerate(zip(stimuli, titles, drives)):
ax = fig.add_subplot(grid[1, index])
ax.imshow(stimulus, cmap="gray", vmin=-1, vmax=1, origin="lower")
ax.set_xticks([]); ax.set_yticks([])
ax.set_title(title.replace(" ", "\n", 1), fontsize=10, pad=10)
ax.set_xlabel(f"D = {drive:g}\nR = {max(0, drive):g}", fontsize=11, labelpad=9)
fig.text(.5, .035, "Each image uses the same background. Rotation preserves bar area; shifting preserves bar angle.",
ha="center", fontsize=9.5)
fig.savefig(OUTPUT, facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()