codexelectrolyte-strength-species-inventories.py
electrolyte-strength-species-inventories.py
"""Draw chosen species inventories; run from _media to write the PNG there.
Tested with Python 3.14, matplotlib 3.10.7 and numpy 2.3.5.
Every marker denotes the same chosen amount, rather than a literal molecule.
"""
from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, Rectangle
def main():
plt.rcParams.update({"font.size": 11, "figure.facecolor": "white"})
fig, axes = plt.subplots(1, 3, figsize=(10.8, 5.2), dpi=120)
cases = [
("Strong: small inventory", 2, 2, 0, "2 units dissolved; all converted", "100% converted; 4 ionic units"),
("Weak: larger inventory", 5, 5, 15, "20 units dissolved; 5 converted", "25% converted; 10 ionic units"),
("Nonelectrolyte", 0, 0, 20, "20 units dissolved; none converted", "0% converted; 0 ionic units"),
]
for ax, (title, positive, negative, neutral, inventory, tally) in zip(axes, cases):
ax.set(xlim=(0, 5), ylim=(0, 6.5), aspect="equal")
ax.axis("off")
ax.set_title(title, fontsize=12, fontweight="bold", pad=12)
ax.add_patch(Rectangle((0.1, 0.85), 4.8, 5.0, facecolor="#fbfcfe", edgecolor="#536174", linewidth=1.5))
species = [("+", "#d95e39")] * positive + [("−", "#3278b5")] * negative + [("N", "#647684")] * neutral
# A neutral parent unit yields one positive and one negative ion.
assert neutral + positive == (2 if positive == 2 else 20)
assert positive == negative
for index, (label, color) in enumerate(species):
col, row = index % 5, index // 5
x, y = 0.58 + col * 0.96, 5.30 - row * 0.91
ax.add_patch(Circle((x, y), 0.30, facecolor=color, edgecolor="white", linewidth=0.8))
ax.text(x, y, label, ha="center", va="center", color="white", fontsize=13, fontweight="bold")
ax.text(2.5, 0.45, inventory, ha="center", fontsize=10)
ax.text(2.5, 0.05, tally, ha="center", fontsize=10, fontweight="bold")
fig.suptitle("Converted fraction and ion amount are different", fontsize=16, y=0.97)
fig.text(0.5, 0.115, "Equal solution volumes • one-to-one ion production • solvent omitted", ha="center", fontsize=11)
fig.text(0.5, 0.037, "+ / − = ions; N = neutral unit. Each marker represents the same chosen amount.\nStipulated schematic inventories, not measured material data.", ha="center", fontsize=10, linespacing=1.4)
fig.subplots_adjust(left=0.025, right=0.975, top=0.86, bottom=0.17, wspace=0.14)
fig.savefig(Path(__file__).stem + ".png", facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()