from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, Rectangle, FancyBboxPatch
import numpy as np
Path("figures").mkdir(exist_ok=True)
def export_figure(fig, name):
fig.savefig(f"figures/{name}.svg", bbox_inches="tight")
fig.savefig(f"figures/{name}.png", dpi=180, bbox_inches="tight")
plt.show()
# Fixed four-person examples; checked against the constructors below.
dyad_examples = [
("Eldest first · recipient resets", True,
[(4, 3), (4, 2), (4, 1), (3, 2), (3, 1), (2, 1)]),
("Optimal recipient batching", False,
[(4, 3), (4, 2), (3, 2), (3, 1), (4, 1), (2, 1)]),
("Optimal two-seat giver blocks", False,
[(4, 3), (4, 1), (4, 2), (3, 2), (3, 1), (2, 1)]),
]
fig, axes = plt.subplots(3, 1, figsize=(7.7, 7.1), constrained_layout=True)
for ax, (title, reset, order) in zip(axes, dyad_examples):
counts = []
for role, y, label, edge, fill in [
(0, 1, "Giver", "#8e4b16", "#fff0df"),
(1, 0, "Recipient", "#17627a", "#dceff5"),
]:
bands = []
for t, pair in enumerate(order):
if t == 0 or pair[role] != order[t - 1][role] or (reset and role == 1):
bands.append([t, t, pair[role]])
else:
bands[-1][1] = t
counts.append(len(bands))
for start, end, person in bands:
ax.add_patch(FancyBboxPatch(
(start - .34, y - .25), end - start + .68, .5,
boxstyle="round,pad=0.015,rounding_size=0.12",
facecolor=fill, edgecolor=edge, linewidth=1.4))
for t, pair in enumerate(order):
ax.text(t, y, str(pair[role]), ha="center", va="center",
fontsize=16, weight="bold", color=edge)
ax.text(-.63, y, label, ha="right", va="center", fontsize=11, color=edge)
for t in range(6):
ax.text(t, 1.52, f"{t + 1}", ha="center", va="center", fontsize=10, color="#64748b")
ax.annotate("", xy=(t, .29), xytext=(t, .71),
arrowprops={"arrowstyle": "->", "color": "#475569", "lw": 1.4})
g, r = counts
ax.text(-.63, 1.52, "Step", ha="right", va="center", fontsize=10, color="#64748b")
ax.text(-1.5, -.71, f"Recipient only: {r}e", fontsize=12, weight="bold", color="#17627a")
ax.text(1.35, -.71, f"Two seats: {g}e + {r}e = {g + r}e", fontsize=12, weight="bold")
ax.set_title(title, loc="left", fontsize=13, weight="bold", pad=8)
ax.set(xlim=(-1.55, 5.55), ylim=(-.86, 1.75))
ax.axis("off")
export_figure(fig, "dyad-comparison")