codexnewton-root-iteration.py
newton-root-iteration.py
"""Draw Newton tangent geometry; save newton-root-iteration.png in cwd.
Tested with Python 3.14.4, NumPy 2.3.5, Matplotlib 3.10.7.
"""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
def main():
plt.rcParams.update({"font.size": 11, "axes.titlesize": 13})
fig, axes = plt.subplots(1, 2, figsize=(10.8, 4.8), layout="constrained")
fig.patch.set_facecolor("white")
blue, orange, green = "#2166ac", "#d46514", "#25834a"
ax = axes[0]
t = np.linspace(0.85, 1.85, 400)
ax.plot(t, t * t - 2, color=blue, lw=2.5, label=r"$F(t)=t^2-2$")
x0, x1, x2 = 1.0, 1.5, 17 / 12
assert np.isclose(x1 - (x1 * x1 - 2) / (2 * x1), x2)
ax.plot([0.94, 1.7], [2 * 0.94 - 3, 2 * 1.7 - 3],
color=orange, lw=1.8, label=r"Tangent at $t_0=1$")
ax.plot([1.28, 1.74], [3 * 1.28 - 4.25, 3 * 1.74 - 4.25],
color=green, lw=1.8, label=r"Tangent at $t_1=1.5$")
for start, end, color in [((x0, -1), (x1, 0), orange),
((x1, 0.25), (x2, 0), green)]:
ax.annotate("", xy=end, xytext=start,
arrowprops={"arrowstyle": "->", "color": color, "lw": 2.2})
ax.plot([x0, x0], [0, -1], ":", color="0.5")
ax.plot([x1, x1], [0, 0.25], ":", color="0.5")
ax.scatter([x0, x1], [-1, 0.25], c=[orange, green], zorder=5)
ax.scatter([x1, x2], [0, 0], c=[orange, green], zorder=5)
ax.scatter([np.sqrt(2)], [0], color="black", marker="*", s=80, zorder=6)
ax.annotate(r"$t_0=1$", (x0, 0), xytext=(0.90, 0.24),
arrowprops={"arrowstyle": "-", "color": "0.4"})
ax.annotate(r"$t_1=1.5$", (x1, 0), xytext=(1.60, -0.50),
arrowprops={"arrowstyle": "-", "color": orange}, color=orange)
ax.annotate(r"$t_2=17/12$", (x2, 0), xytext=(1.02, 0.65),
arrowprops={"arrowstyle": "-", "color": green}, color=green)
ax.annotate(r"Root: $\sqrt{2}\approx1.41421$", (np.sqrt(2), 0),
xytext=(1.09, -0.85),
arrowprops={"arrowstyle": "-", "color": "0.3"})
ax.set(xlim=(0.85, 1.85), ylim=(-1.25, 1.65), xlabel=r"$t$", ylabel=r"$F(t)$",
title="Two tangent steps toward a square root")
ax.legend(loc="upper left", fontsize=9, framealpha=1)
ax = axes[1]
x = np.linspace(-2.05, 1.4, 600)
f = lambda value: value**3 - 2 * value + 2
df = lambda value: 3 * value**2 - 2
assert 0 - f(0) / df(0) == 1
assert 1 - f(1) / df(1) == 0
ax.plot(x, f(x), color=blue, lw=2.5, label=r"$F(x)=x^3-2x+2$")
ax.plot([-0.2, 1.35], [2.4, -0.7], color=orange, lw=1.8,
label=r"Tangent at $x_0=0$")
ax.plot([-0.2, 1.35], [-0.2, 1.35], color=green, lw=1.8,
label=r"Tangent at $x_1=1$")
for start, end, color in [((0, 2), (1, 0), orange),
((1, 1), (0, 0), green)]:
ax.annotate("", xy=end, xytext=start,
arrowprops={"arrowstyle": "->", "color": color, "lw": 2.2})
for xx, yy in [(0, 2), (1, 1)]:
ax.annotate("", xy=(xx, yy), xytext=(xx, 0),
arrowprops={"arrowstyle": "->", "linestyle": ":", "color": "0.4"})
ax.scatter([0, 1], [2, 1], c=[orange, green], zorder=5)
ax.scatter([0, 1], [0, 0], c=[green, orange], zorder=5)
ax.text(0, -0.5, r"$0$", ha="center")
ax.text(1, -0.5, r"$1$", ha="center")
root = -1.8
for _ in range(6):
root -= f(root) / df(root)
ax.scatter([root], [0], color="black", marker="*", s=80, zorder=6)
ax.annotate(r"Root $\approx-1.76929$", (root, 0), xytext=(-1.94, 0.75),
fontsize=10, arrowprops={"arrowstyle": "-", "color": "0.3"})
ax.text(-1.75, -1.2, r"Iteration: $0\to1\to0\to1\to\cdots$", fontsize=11)
ax.set(xlim=(-2.05, 1.4), ylim=(-2.65, 4.45), xlabel=r"$x$", ylabel=r"$F(x)$",
title="A defined iteration can cycle forever")
ax.legend(loc="upper left", fontsize=9, framealpha=1)
for ax in axes:
ax.set_facecolor("white")
ax.axhline(0, color="0.25", lw=0.8, zorder=0)
ax.grid(alpha=0.16)
ax.spines[["top", "right"]].set_visible(False)
fig.savefig(Path.cwd() / "newton-root-iteration.png", dpi=110,
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()