codexcytokinesis-ring-and-cell-plate.py
cytokinesis-ring-and-cell-plate.py
"""Original sectional cartoons of cytokinesis. Python 3.14; matplotlib 3.10.7, numpy 2.3.5."""
from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, Ellipse, Polygon, Rectangle
import numpy as np
BOUNDARY = "#265b79"
CYTOPLASM = "#eef6fa"
NUCLEUS = "#7154a5"
RING = "#c65b13"
PLATE = "#287b43"
def nucleus(ax, x, y=0):
ax.add_patch(Circle((x, y), 0.24, facecolor="#e8ddf6", edgecolor=NUCLEUS, lw=1.7))
ax.text(x, y, r"$2n$" + "\n" + r"$2C$", ha="center", va="center", fontsize=11, color=NUCLEUS)
def frame(ax):
ax.set(xlim=(-1.8, 1.8), ylim=(-1.05, 1.22), aspect="equal")
ax.axis("off")
def animal(ax, stage):
if stage == 0:
ax.add_patch(Ellipse((0, 0), 2.65, 1.5, fc=CYTOPLASM, ec=BOUNDARY, lw=2))
waist = 0.70
elif stage == 1:
angle = np.linspace(0, 2 * np.pi, 301)
x = 1.35 * np.cos(angle)
y = 0.75 * np.sin(angle) * (1 - 0.76 * np.exp(-(x / 0.48) ** 2))
ax.add_patch(Polygon(np.column_stack((x, y)), closed=True, fc=CYTOPLASM, ec=BOUNDARY, lw=2))
waist = 0.18
else:
for x in (-0.78, 0.78):
ax.add_patch(Ellipse((x, 0), 1.22, 1.35, fc=CYTOPLASM, ec=BOUNDARY, lw=2))
waist = None
for x in (-0.78, 0.78):
nucleus(ax, x)
if waist is not None:
for y in (-waist, waist):
ax.plot((-0.13, 0.13), (y, y), color=RING, lw=6, solid_capstyle="round")
if stage == 1:
ax.annotate("Furrow", (0.03, waist), (0.48, 0.92), fontsize=11, color=RING,
arrowprops={"arrowstyle": "->", "color": RING}, ha="center")
def plant(ax, stage):
ax.add_patch(Rectangle((-1.35, -0.75), 2.7, 1.5, fc=CYTOPLASM, ec=PLATE, lw=5))
ax.add_patch(Rectangle((-1.29, -0.69), 2.58, 1.38, fill=False, ec=BOUNDARY, lw=1.3))
for x in (-0.78, 0.78):
nucleus(ax, x)
if stage == 0:
for y in (-0.22, 0, 0.22):
ax.add_patch(Circle((0, y), 0.065, fc="#b3dabc", ec=PLATE, lw=1))
else:
length = 0.39 if stage == 1 else 0.73
ax.plot((0, 0), (-length, length), color=PLATE, lw=5)
if stage == 1:
for sign in (-1, 1):
ax.annotate("", (0, sign * 0.65), (0, sign * 0.44),
arrowprops={"arrowstyle": "->", "color": PLATE, "lw": 1.8})
else:
for x in (-0.045, 0.045):
ax.plot((x, x), (-0.69, 0.69), color=BOUNDARY, lw=1)
def main():
fig, axes = plt.subplots(2, 3, figsize=(10.8, 6.5), dpi=100, facecolor="white")
fig.subplots_adjust(left=0.055, right=0.97, top=0.81, bottom=0.15, hspace=0.50, wspace=0.22)
fig.suptitle("Cytokinesis changes the boundary around two existing nuclei", y=0.97, fontsize=17)
fig.text(0.5, 0.895, "Animal: inward furrow • Plant: outward cell plate", ha="center", fontsize=13)
for stage in range(3):
for row in range(2):
frame(axes[row, stage])
animal(axes[0, stage], stage)
plant(axes[1, stage], stage)
axes[0, stage].set_title(["Ring at the surface", "Furrow deepens", "Separate daughters"][stage], fontsize=12, pad=0)
axes[1, stage].set_title(["Vesicles at the center", "Plate grows outward", "New wall and boundaries"][stage], fontsize=12, pad=0)
fig.text([0.184, 0.511, 0.837][stage], 0.105,
["1 cell, 2 nuclei", "1 cell, partition forming", "2 cells, 1 nucleus each"][stage],
ha="center", fontsize=12)
fig.text(0.5, 0.035, "Nuclear DNA total: 4C throughout. Orange: ring intersections. Green: plant partition.\nSectional cartoons; sizes and stage spacing are illustrative.", ha="center", fontsize=11)
fig.savefig(Path(__file__).stem + ".png", facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()