codexwater-hydrogen-bond-roles.py
water-hydrogen-bond-roles.py
"""Schematic donor/acceptor roles for two water molecules.
Output matching PNG to CWD. Not a measured water-dimer structure.
Tested with Python 3.14, NumPy 2.3.5 and Matplotlib 3.10.7.
"""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Circle
def atom(ax, point, label):
oxygen = label == "O"
ax.add_patch(Circle(point, 0.17 if oxygen else 0.13,
facecolor="#bf4244" if oxygen else "#f3f5f7",
edgecolor="#9a3235" if oxygen else "#8b98a3",
linewidth=1.2, zorder=4))
ax.text(*point, label, ha="center", va="center", weight="bold",
color="white" if oxygen else "#334451", zorder=5, fontsize=12)
def main():
plt.rcParams.update({"font.size": 12})
fig, ax = plt.subplots(figsize=(11.4, 5.1), dpi=100, facecolor="white")
fig.subplots_adjust(left=0.045, right=0.965, bottom=0.18, top=0.83)
donor = np.array([0.0, 0.0])
acceptor = np.array([2.3, 0.0])
angle = np.deg2rad(104.5)
donor_h = [np.array([0.9, 0]), 0.9*np.array([np.cos(angle), np.sin(angle)])]
acceptor_h = [
acceptor+0.9*np.array([np.cos(angle/2), np.sin(angle/2)]),
acceptor+0.9*np.array([np.cos(angle/2), -np.sin(angle/2)]),
]
for oxygen, hydrogens in [(donor, donor_h), (acceptor, acceptor_h)]:
for hydrogen in hydrogens:
ax.plot([oxygen[0], hydrogen[0]], [oxygen[1], hydrogen[1]],
color="#526472", linewidth=3, zorder=1)
atom(ax, oxygen, "O")
for hydrogen in hydrogens:
atom(ax, hydrogen, "H")
ax.plot([donor_h[0][0], acceptor[0]], [0, 0], color="#b77b2b",
linestyle=(0, (2, 3)), linewidth=2.7, zorder=1)
for oxygen, offsets in [
(donor, [(-0.28, -0.23), (0.15, -0.32)]),
(acceptor, [(-0.32, 0.28), (-0.32, -0.28)]),
]:
for dx, dy in offsets:
ax.scatter([oxygen[0]+dx-0.025, oxygen[0]+dx+0.025],
[oxygen[1]+dy, oxygen[1]+dy], s=15,
c="#536b96", zorder=6)
ax.text(0.0, 1.32, "Donor molecule\nO–H supplies the hydrogen",
ha="center", fontsize=12, linespacing=1.5, color="#334d70")
ax.text(2.3, 1.32, "Acceptor molecule\nO supplies the accepting site",
ha="center", fontsize=12, linespacing=1.5, color="#334d70")
ax.annotate("Covalent O–H bond", xy=(0.43, 0), xytext=(0.08, -0.65),
ha="center", color="#526472",
arrowprops={"arrowstyle": "->", "color": "#526472"})
ax.annotate("Hydrogen bond H···O", xy=(1.58, 0), xytext=(1.62, -0.65),
ha="center", color="#966521",
arrowprops={"arrowstyle": "->", "color": "#966521"})
ax.set(xlim=(-0.75, 3.35), ylim=(-0.95, 1.7), aspect="equal")
ax.axis("off")
fig.suptitle("One association, two roles: hydrogen-bond donor and acceptor",
fontsize=16, y=0.96)
fig.text(0.5, 0.065,
"Schematic single pair, not a measured dimer geometry. Both molecules keep their covalent O–H bonds.\n"
"Blue dot pairs are Lewis bookkeeping; they do not specify fixed electron positions.",
ha="center", fontsize=11, linespacing=1.5, color="#444")
fig.savefig(Path.cwd() / "water-hydrogen-bond-roles.png",
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()