codex/lp-unit-balls-triangle-geometry.py

lp-unit-balls-triangle-geometry.py
"""Draw closed planar Lp unit balls; run from _media with Python 3.14.

Uses matplotlib 3.10.7 and numpy 2.3.5. Writes its basename to the CWD.
"""

from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np


def main():
    plt.rcParams.update({"font.size": 11, "axes.titlesize": 14})
    fig, axes = plt.subplots(1, 3, figsize=(10.5, 4.1), layout="constrained")
    fig.patch.set_facecolor("white")
    theta = np.linspace(0, 2 * np.pi, 1001)
    direction = np.column_stack((np.cos(theta), np.sin(theta)))
    specifications = [
        (1, r"$p=1$: diamond", r"$|x|+|y|\leq 1$", "#007f8b"),
        (2, r"$p=2$: disk", r"$x^2+y^2\leq 1$", "#3758a8"),
        (np.inf, r"$p=\infty$: square", r"$\max(|x|,|y|)\leq 1$", "#a26121"),
    ]
    for ax, (p, title, formula, color) in zip(axes, specifications):
        radius = (
            np.max(np.abs(direction), axis=1)
            if np.isinf(p)
            else np.sum(np.abs(direction) ** p, axis=1) ** (1 / p)
        )
        boundary = direction / radius[:, None]
        ax.set_facecolor("white")
        ax.fill(*boundary.T, color=color, alpha=0.12)
        ax.plot(*boundary.T, color=color, linewidth=2)
        points = np.array([[1.0, 0.0], [0.0, 1.0]])
        if np.isinf(p):
            points = np.array([[1.0, -0.7], [1.0, 0.7]])
        midpoint = points.mean(axis=0)
        ax.plot(*points.T, "o--", color="#3f3f3f", linewidth=1.3, markersize=5)
        ax.plot(*midpoint, "o", color="#c13248", markersize=7)
        label = "midpoint inside" if p == 2 else "midpoint on boundary"
        ax.text(0, -1.48, label, ha="center", color="#a42035", fontsize=11)
        ax.axhline(0, color="#777777", linewidth=0.7)
        ax.axvline(0, color="#777777", linewidth=0.7)
        ax.set(xlim=(-1.3, 1.3), ylim=(-1.6, 1.25), aspect="equal")
        ax.set_xticks([-1, 0, 1])
        ax.set_yticks([-1, 0, 1])
        ax.set_xlabel("x")
        ax.set_ylabel("y", labelpad=0)
        ax.set_title(title + "\n" + formula)
        ax.spines[["top", "right"]].set_visible(False)
    fig.suptitle("Convex unit balls; flat edges allow distinct unit vectors to share a midpoint", fontsize=13)
    fig.savefig(Path(Path(__file__).stem + ".png"), dpi=110, facecolor="white", transparent=False)
    plt.close(fig)


if __name__ == "__main__":
    main()