codexreduction-modulo-one-sawtooth.py
reduction-modulo-one-sawtooth.py
"""Plot fractional-part representatives; write the PNG into the current directory.
Build with ``make _media/reduction-modulo-one-sawtooth.png``.
The curve is an exact mathematical example, not measured data.
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
def main():
lower, upper = -2.4, 2.4
blue, orange = "#176b91", "#a64b16"
fig, ax = plt.subplots(figsize=(7.8, 3.1), layout="constrained")
fig.patch.set_facecolor("white")
ax.set_facecolor("white")
for integer in range(-3, 3):
left, right = max(integer, lower), min(integer + 1, upper)
if left < right:
ax.plot([left, right], [left - integer, right - integer],
color=blue, lw=2)
if lower < integer < upper:
ax.axvline(integer, color="0.85", ls="--", lw=0.8, zorder=0)
ax.plot(integer, 0, "o", color=blue, ms=6, zorder=3)
if lower < integer + 1 < upper:
ax.plot(integer + 1, 1, "o", color=blue, markerfacecolor="white",
markeredgewidth=1.5, ms=6, zorder=3)
ax.scatter([-1.2], [0.8], color=orange, s=42, zorder=4)
ax.annotate(r"$-1.2-(-2)=0.8$", (-1.2, 0.8), (-2.25, 1.08),
color=orange, fontsize=11,
arrowprops={"arrowstyle": "->", "color": orange})
ax.set(xlim=(lower, upper), ylim=(-0.08, 1.22),
xlabel=r"Real input $x$", ylabel=r"$x-\lfloor x\rfloor$",
title="Reduction modulo one: filled points belong; open points do not")
ax.set_xticks(range(-2, 3))
ax.set_yticks([0, 0.5, 1])
ax.tick_params(labelsize=10)
ax.grid(axis="y", alpha=0.2)
fig.savefig(Path(__file__).with_suffix(".png").name, dpi=100,
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()