codex/x-ray-tube-transmission-detection.py

x-ray-tube-transmission-detection.py
"""Draw an original modern X-ray source and narrow-beam detection schematic.

Tested with Python 3.14, matplotlib 3.10.7; run from _media.
"""

from pathlib import Path

import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch, FancyBboxPatch, Polygon, Rectangle


def main():
    plt.rcParams.update({"font.family": "DejaVu Sans", "font.size": 11})
    fig, ax = plt.subplots(figsize=(11, 5.1), dpi=120, facecolor="white")
    ax.set(xlim=(0, 12), ylim=(0, 5.1))
    ax.axis("off")
    blue, orange, grey = "#1768a2", "#b64a18", "#40464d"

    def arrow(start, end, color, **kwargs):
        ax.add_patch(FancyArrowPatch(start, end, arrowstyle="-|>",
                                    mutation_scale=15, color=color,
                                    linewidth=2, **kwargs))

    ax.text(6, 4.85, "X-ray tube → sample → detector", ha="center",
            fontsize=18, weight="bold")
    ax.text(6, 4.43, "Modern source and ideal narrow-beam measurement • schematic, not to scale",
            ha="center", color=grey, fontsize=10)
    ax.add_patch(FancyBboxPatch((0.35, 1.7), 4.55, 2.1,
                               boxstyle="round,pad=0.04,rounding_size=0.3",
                               facecolor="#f2f7fa", edgecolor=blue, linewidth=1.8))
    ax.text(2.5, 3.95, "evacuated envelope", ha="center", color=blue)
    ax.plot([1.0, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60],
            [2.6, 2.95, 2.6, 2.95, 2.6, 2.95, 2.6], color=orange, lw=2.5)
    ax.text(1.3, 2.25, "heated\ncathode (−)", ha="center", color=orange)
    arrow((1.8, 2.82), (3.6, 2.82), orange)
    ax.text(2.7, 3.04, "electrons", ha="center", color=orange)
    ax.add_patch(Polygon([(3.6, 2.27), (4.2, 3.35), (4.42, 3.35), (4.42, 2.27)],
                         facecolor="#6e7379", edgecolor=grey))
    ax.text(4.03, 2.0, "target anode (+)", ha="center", fontsize=10)
    ax.text(2.55, 1.32, "Accelerating voltage V supplies energy eV per electron",
            ha="center", fontsize=10)
    arrow((3.91, 2.82), (10.95, 2.82), blue)
    ax.text(5.25, 3.06, "X-rays", ha="center", color=blue)
    for x in (5.8, 9.7):
        for y in (2.0, 2.99):
            ax.add_patch(Rectangle((x, y), 0.25, 0.65, facecolor=grey))
    ax.text(6.0, 3.85, "aperture", ha="center", fontsize=10)
    ax.add_patch(Rectangle((7.45, 2.05), 0.55, 1.55,
                           facecolor="#f5dda7", edgecolor="#87642a", linewidth=1.5))
    ax.text(7.72, 3.85, "sample", ha="center")
    ax.annotate("", (7.45, 1.87), (8.0, 1.87),
                arrowprops={"arrowstyle": "<->", "color": grey})
    ax.text(7.72, 1.58, "thickness x", ha="center", fontsize=10)
    arrow((7.78, 2.82), (9.76, 3.43), "#999999", linestyle="--")
    ax.text(9.7, 4.01, "scatter rejected", ha="center", fontsize=10, color=grey)
    ax.add_patch(Rectangle((11.0, 2.2), 0.45, 1.3,
                           facecolor="#c8e7dd", edgecolor="#25795f", linewidth=1.5))
    ax.text(11.2, 3.8, "detector", ha="center")
    ax.text(8.7, 0.83, r"Empty path: $R_0$     Sample: $R$     Background: $b$",
            ha="center", fontsize=11)
    ax.text(8.7, 0.32, r"Transmission: $T=(R-b)/(R_0-b)$", ha="center",
            fontsize=13, color=blue)
    fig.subplots_adjust(left=0.015, right=0.985, bottom=0.035, top=0.985)
    fig.savefig(Path(__file__).stem + ".png", facecolor="white")
    plt.close(fig)


if __name__ == "__main__":
    main()