import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt

# Hypothetical amounts: 100 mol total, no experimental observations.
# Chemical purity here counts BOTH enantiomers as target.
def measures(label, L, R, I):
    total = L + R + I
    target = L + R
    return dict(mixture=label, L_mol=L, R_mol=R, impurity_mol=I,
                total_mol=total, chemical_purity_pct=100*target/total,
                L_within_target_pct=100*L/target,
                R_within_target_pct=100*R/target,
                ee_pct=100*abs(L-R)/target,
                signed_ee_L_pct=100*(L-R)/target,
                majority="L" if L>R else ("R" if R>L else "neither"),
                L_in_total_pct=100*L/total)

examples = pd.DataFrame([
    measures("A",49.5,49.5,1),
    measures("B",74.25,24.75,1),
    measures("C",89.1,9.9,1),
    measures("D",9.9,89.1,1),
    measures("E",99,0,1),
    measures("F",72,8,20),
    measures("G: 99% L within target",98.01,0.99,1),
    measures("H: 99% ee favoring L",98.505,0.495,1),
])
# 0.1 percentage-point grid includes 99% L and 99.5% L.
f = np.arange(1001)/1000
sweep = pd.DataFrame({
    "L_within_target_pct":100*f,
    "R_within_target_pct":100*(1-f),
    "L_mol":99*f, "R_mol":99*(1-f), "impurity_mol":np.ones_like(f),
    "chemical_purity_pct":np.full_like(f,99),
    "ee_pct":100*np.abs(2*f-1),
    "signed_ee_L_pct":100*(2*f-1),
    "L_in_total_pct":99*f,
})
assert np.allclose(examples.total_mol,100)
assert np.allclose(sweep.L_mol+sweep.R_mol+sweep.impurity_mol,100)
assert np.allclose(sweep.ee_pct,
                   100*abs(sweep.L_mol-sweep.R_mol)/(sweep.L_mol+sweep.R_mol))
assert np.allclose(examples.loc[6:7,"ee_pct"],[98,99])
assert np.allclose(examples.loc[6:7,"L_within_target_pct"],[99,99.5])
examples.to_csv("hypothetical_mixtures.csv",index=False,float_format="%.6f")
sweep.to_csv("purity_99_sweep.csv",index=False,float_format="%.6f")

# Standalone export: standard Matplotlib defaults replace the notebook style helper.
plt.style.use('default')
mpl.rcParams.update({"font.size":11,"axes.titlesize":11,"axes.labelsize":11,
                     "xtick.labelsize":9,"ytick.labelsize":9,"legend.fontsize":10})
fig, ax = plt.subplots(figsize=(8,5.5),dpi=180)
fig.subplots_adjust(left=0.12,right=0.96,bottom=0.28,top=0.88)
x=sweep.L_within_target_pct
ax.plot(x,sweep.chemical_purity_pct,color="#555555",ls="--",lw=2,
        label="Chemical purity (L + R)")
ax.plot(x,sweep.ee_pct,color="#0072B2",lw=2.5,label="Enantiomeric excess (magnitude)")
ax.plot(x,sweep.L_in_total_pct,color="#E69F00",ls="-.",lw=2,
        label="L as % of total mixture")
ax.set(xlim=(-2,102),ylim=(-3,104),
       xlabel="L as % of target molecules (L + R)",ylabel="Percent")
ax.set_xticks([0,25,50,75,100])
ax.set_yticks([0,25,50,75,100])
ax.set_title("Chemical purity stays fixed while enantiomeric balance changes",loc="left",pad=16)
ax.grid(axis="y",alpha=0.15)
ax.legend(loc="upper center",bbox_to_anchor=(0.5,-0.24),ncol=1,frameon=False)
fig.canvas.draw()
renderer=fig.canvas.get_renderer()
texts=[(t,t.get_window_extent(renderer)) for t in fig.findobj(mpl.text.Text)
       if t.get_visible() and t.get_text().strip()]
overlaps=[(a.get_text(),b.get_text()) for j,(a,ba) in enumerate(texts)
          for b,bb in texts[j+1:] if ba.overlaps(bb)]
outside=[t.get_text() for t,b in texts
         if b.x0<fig.bbox.x0 or b.y0<fig.bbox.y0 or
            b.x1>fig.bbox.x1 or b.y1>fig.bbox.y1]
assert not overlaps, overlaps
assert not outside, outside
fig.savefig("purity_and_enantiomers.png",dpi=180)
print(examples.round(3).to_string(index=False))
print("Checks passed: mass balance, ee formula, special cases, text layout.")
print("Sweep: 1001 points; L fraction 0–100%; chemical purity fixed at 99%.")
plt.show()
