codex/past-exam-of-the-physics-b-course-of-the-university-of-cambridge/2018/paper-1-a1-crossed-charge-sheets.py

past-exam-of-the-physics-b-course-of-the-university-of-cambridge/2018/paper-1-a1-crossed-charge-sheets.py
#!/usr/bin/env python3
"""Plot the calculated crossed-sheet field; write the PNG basename to cwd.

Tested with Python 3.14.4, numpy 2.3.5 and matplotlib 3.10.7 (+dfsg1).
Dependencies are already listed in the repository pyproject.toml.
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np


def main():
    axis = np.linspace(-2.65, 2.65, 17)
    x, y = np.meshgrid(axis, axis)
    keep = (abs(y) > .13) & (abs(y-x) > .15)
    u = np.sign(y-x)/np.sqrt(2)
    v = np.sign(y)-np.sign(y-x)/np.sqrt(2)
    fig, ax = plt.subplots(figsize=(5.8, 5.5), dpi=120, facecolor="white")
    ax.set_facecolor("white")
    ax.quiver(x[keep], y[keep], u[keep], v[keep], color="#333333",
              angles="xy", scale_units="xy", scale=5.7, width=.004)
    ax.plot([-3, 3], [0, 0], color="#c84444", lw=2)
    ax.plot([-3, 3], [-3, 3], color="#0072b2", lw=2)
    ax.text(-2.85, .12, r"$+\sigma$ on $y=0$", color="#aa3030", fontsize=11)
    ax.text(1.22, 1.82, r"$-\sigma$ on $y=x$", color="#0072b2", fontsize=11, rotation=45)
    ax.set(xlim=(-3, 3), ylim=(-3, 3), aspect="equal", xlabel=r"$x$", ylabel=r"$y$",
           title="Superposed fields of two oppositely charged sheets")
    ax.spines[["top", "right"]].set_visible(False)
    ax.text(0, -3.75, r"Arrow lengths are proportional to $|\mathbf{E}|$; sheet fields use $E_s=\sigma/(2\varepsilon_0)$.",
            ha="center", fontsize=9)
    fig.tight_layout()
    fig.savefig(Path(__file__).stem+".png", facecolor="white")
    plt.close(fig)


if __name__ == "__main__":
    main()