codex/css-mixed-font-line-box.py

css-mixed-font-line-box.py
"""Draw baseline-aligned CSS metric boxes; save a PNG in the working directory."""
from pathlib import Path

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle


def measure(ax, x, bottom, top, label, color):
    ax.annotate("", xy=(x, bottom), xytext=(x, top),
                arrowprops={"arrowstyle": "<->", "linewidth": 1.5,
                            "color": color})
    ax.text(x + 0.15, (bottom + top) / 2, label, va="center",
            color=color, fontsize=10)


def main():
    fig, ax = plt.subplots(figsize=(8.5, 5.4), dpi=100, facecolor="white")
    fig.subplots_adjust(left=0.05, right=0.98, bottom=0.19, top=0.82)
    fig.suptitle("Two line heights, a taller line box", y=0.97,
                 fontsize=16, weight="bold", color="#172330")
    fig.text(0.5, 0.9, "Hypothetical font metrics; one common baseline",
             ha="center", fontsize=11, color="#45535d")
    ax.add_patch(Rectangle((0.8, -8), 8.5, 21, facecolor="#f1f3f5",
                           edgecolor="#7a8895", linewidth=1.2,
                           linestyle="--"))
    for x, a, d, height, color, name in [
        (1.25, 11, 3, 18, "#226a9a", "Run A"),
        (5.4, 8, 4, 20, "#26734d", "Run B"),
    ]:
        leading = height - a - d
        above, below = a + leading / 2, d + leading / 2
        ax.add_patch(Rectangle((x, -below), 2.5, height,
                               facecolor=color, alpha=0.12, edgecolor="none"))
        ax.add_patch(Rectangle((x, -d), 2.5, a + d,
                               facecolor="white", edgecolor=color,
                               linewidth=1.2, linestyle=":"))
        ax.add_patch(Rectangle((x, -below), 2.5, height,
                               facecolor="none", edgecolor=color,
                               linewidth=2))
        ax.text(x + 1.25, a / 2, name, ha="center", va="center",
                color=color, fontsize=12, weight="bold")
        ax.text(x + 1.25, 14.2, f"A = {a}, D = {d}, H = {height}",
                ha="center", color=color, fontsize=10)
        ax.text(x + 1.25, -10.1,
                f"Above baseline: {above:g}; below: {below:g}",
                ha="center", va="center", color=color, fontsize=9)
        measure(ax, x + 2.75, -below, above, f"{height}", color)
    ax.axhline(0, xmin=0.03, xmax=0.8, color="#34495e", linewidth=1.2)
    ax.text(0.3, 0.6, "baseline", fontsize=9, color="#34495e")
    measure(ax, 10.0, -8, 13, "21", "#9b4928")
    ax.text(10.0, 14.2, "Line box", ha="center", fontsize=10,
            color="#9b4928")
    ax.set_xlim(0, 11.7)
    ax.set_ylim(-11.7, 16)
    ax.axis("off")
    fig.text(0.5, 0.115, "Top comes from A; bottom comes from B: 13 + 8 = 21 CSS pixels.",
             ha="center", fontsize=11, color="#172330")
    fig.text(0.5, 0.055, "Dotted inner boxes: font metrics. Pale bands: half-leading.",
             ha="center", fontsize=10, color="#45535d")
    fig.text(0.5, 0.018, "The block's strut is assumed to add no greater extent.",
             ha="center", fontsize=9, color="#45535d")
    fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), dpi=100,
                facecolor="white", transparent=False)
    plt.close(fig)


if __name__ == "__main__":
    main()