codex/standardization-endpoint-and-blank-bias.py

standardization-endpoint-and-blank-bias.py
"""Original exact additive-volume bias comparison; no experimental data.

Run from _media using Python 3.14, Matplotlib 3.10.7 and NumPy 2.3.5.
Writes basename.png in the current directory. All parameters are selected.
"""

from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np


def main():
    ink, blue, orange = "#20364b", "#155e9b", "#b75520"
    plt.rcParams.update({"font.family": "DejaVu Sans", "font.size": 10})
    fig = plt.figure(figsize=(10, 5.5), dpi=120, facecolor="white")
    fig.suptitle("Extra titre volume lowers the standardized concentration",
                 y=0.975, fontsize=16, weight="bold", color=ink)
    fig.text(0.5, 0.90, "Original additive-error model • selected inputs • not measured data",
             ha="center", fontsize=10.5, color=ink)

    ax = fig.add_axes([0.075, 0.23, 0.36, 0.56])
    delta = np.linspace(0, 0.2, 401)
    for reference, color in [(24.8, blue), (5.0, orange)]:
        bias = -100 * delta / (reference + delta)
        ax.plot(delta, bias, color=color, lw=2.4,
                label=f"Reference titre {reference:.2f} mL")
        point = -100 * 0.05 / (reference + 0.05)
        ax.plot(0.05, point, "o", color=color)
        ax.annotate(f"{point:.4f}%", xy=(0.05, point),
                    xytext=(0.077, point + (0.28 if reference > 5 else -0.48)),
                    color=color, fontsize=10,
                    arrowprops={"arrowstyle": "-", "color": color})
    ax.axhline(0, color="#8393a2", lw=0.8)
    ax.axvline(0.05, color="#8393a2", ls="--", lw=0.9)
    ax.set(xlim=(0, 0.2), ylim=(-4.1, 0.25),
           xlabel=r"Extra denominator volume $\delta V$ (mL)",
           ylabel="Relative concentration error (%)")
    ax.set_xticks(np.arange(0, 0.201, 0.05))
    ax.grid(alpha=0.2)
    ax.spines[["top", "right"]].set_visible(False)
    ax.legend(loc="lower left", fontsize=9, frameon=False)
    ax.set_title("A small titre magnifies a fixed volume error", fontsize=11, pad=14)

    table_ax = fig.add_axes([0.48, 0.23, 0.50, 0.56])
    table_ax.axis("off")
    table_ax.set_title("Same 0.002500 mol inventory in every row", fontsize=11, pad=14)
    amount_mol, reference_ml = 0.0025, 24.8
    labels = ["Corrected reference", "+0.05 mL overshoot",
              "0.05 mL blank left in", "Both errors"]
    extras = [0.0, 0.05, 0.05, 0.10]
    rows = []
    for label, extra in zip(labels, extras):
        denominator = reference_ml + extra
        concentration = amount_mol / (denominator / 1000)
        error = -100 * extra / denominator
        rows.append([label, f"{denominator:.2f}", f"{concentration:.8f}",
                     "0" if extra == 0 else f"{error:.4f}"])
    table = table_ax.table(cellText=rows,
                          colLabels=["Case", "V (mL)", "c (mol/L)", "Error (%)"],
                          colWidths=[0.40, 0.16, 0.25, 0.19],
                          cellLoc="center", bbox=[0, 0.16, 1, 0.80])
    table.auto_set_font_size(False)
    table.set_fontsize(8.7)
    for (row, col), cell in table.get_celld().items():
        cell.set_edgecolor("#d4dfe8")
        cell.set_linewidth(0.6)
        cell.set_text_props(color=ink)
        if row == 0:
            cell.set_facecolor("#e6f0f7")
            cell.set_text_props(weight="bold")
        elif row in (2, 3):
            cell.set_facecolor("#fff4e9")
        else:
            cell.set_facecolor("white")
    table_ax.text(0.5, 0.02, "Equal extra denominators give equal bias.",
                  ha="center", fontsize=10, color=orange, weight="bold")
    fig.text(0.5, 0.115,
             r"$\widehat{c}=n_s/(V+\delta V)$"
             r"     $\Longrightarrow$     $(\widehat{c}-c)/c=-\delta V/(V+\delta V)$",
             ha="center", fontsize=15, color=blue)
    fig.text(0.5, 0.04,
             "Overshoot and unremoved blank are separate causes; their volume offsets add in this model.",
             ha="center", fontsize=9.5, color=ink)
    fig.savefig(Path(__file__).stem + ".png", facecolor="white", transparent=False)
    plt.close(fig)


if __name__ == "__main__":
    main()