codexproper-divisor-sum-classification.py
proper-divisor-sum-classification.py
"""Classify n=1,...,30 by proper-divisor sums; write basename PNG to cwd.
Tested with Python 3.14.4, NumPy 2.3.5, and Matplotlib 3.10.7.
Reproduce: make _media/proper-divisor-sum-classification.png
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
def main():
ns = np.arange(1, 31)
sums = np.array([sum(d for d in range(1, n) if n % d == 0) for n in ns])
fig, ax = plt.subplots(figsize=(8.2, 5.3), dpi=120, facecolor="white")
ax.set_facecolor("white")
ax.plot([0, 31], [0, 31], color="#555555", linestyle="--",
linewidth=1.5, label=r"Perfect line: $s(n)=n$", zorder=2)
for mask, color, marker, label in [
(sums < ns, "#245a81", "o", r"Deficient: $s(n)<n$"),
(sums == ns, "#287344", "D", r"Perfect: $s(n)=n$"),
(sums > ns, "#b3541c", "^", r"Abundant: $s(n)>n$"),
]:
ax.scatter(ns[mask], sums[mask], color=color, marker=marker,
s=64, edgecolors="white", linewidths=0.7,
label=label, zorder=3)
for n, label, offset in [
(1, "1: empty sum = 0", (14, 13)),
(6, "6: s = 6", (-31, 33)),
(8, "8: s = 7", (20, -23)),
(12, "12: s = 16", (-24, 30)),
(28, "28: s = 28", (-91, 12)),
]:
ax.annotate(label, (n, sums[n - 1]), xytext=offset,
textcoords="offset points", fontsize=11,
bbox={"boxstyle": "round,pad=0.25", "fc": "white", "ec": "none"},
arrowprops={"arrowstyle": "-", "color": "#666666"}, zorder=4)
ax.set(xlim=(0, 31), ylim=(-2, 45), xlabel=r"Positive integer $n$",
ylabel=r"Sum of positive proper divisors $s(n)=\sigma(n)-n$")
ax.set_xticks([1, 5, 10, 15, 20, 25, 30])
ax.set_yticks(np.arange(0, 41, 10))
ax.grid(alpha=0.16, zorder=0)
ax.spines[["top", "right"]].set_visible(False)
ax.tick_params(labelsize=11)
ax.xaxis.label.set_size(13)
ax.yaxis.label.set_size(13)
ax.set_title("Proper-divisor sums: compare each total with its number",
fontsize=15, pad=14)
ax.legend(loc="upper left", fontsize=10, frameon=True, facecolor="white",
framealpha=1, edgecolor="#dddddd")
fig.subplots_adjust(left=0.12, right=0.97, bottom=0.14, top=0.88)
fig.savefig(Path.cwd() / Path(__file__).with_suffix(".png").name,
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()