Define erythropoiesis in very detailed and simple understandable way with vibrant colours and images
erythropoiesis stages diagram red blood cell development

HSC β CMP (Common Myeloid Progenitor)
β MEP (Megakaryocyte/Erythrocyte Progenitor)
β ErP (Erythrocyte-committed Progenitor)
β Proerythroblast β (first cell you can see under a microscope!)

| Feature | Detail |
|---|---|
| Size | Large: 12-20 Β΅m |
| Nucleus | Big, round, 1-2 visible nucleoli |
| Cytoplasm | Mildly blue (basophilic) - loaded with ribosomes ready to make hemoglobin |
| Can divide? | β Yes |
| Duration | ~24 hours |
| Feature | Detail |
|---|---|
| Size | Smaller: 10-16 Β΅m (shrank after dividing) |
| Nucleus | Smaller, chromatin becoming coarser |
| Cytoplasm | Intensely blue - packed with polyribosomes actively synthesizing hemoglobin |
| Can divide? | β Yes |
| Duration | ~24 hours |
| Feature | Detail |
|---|---|
| Size | Smaller still |
| Nucleus | Coarse checkerboard chromatin pattern - very distinctive! |
| Cytoplasm | Gray or lilac - a mix of blue (ribosomes) and pink (hemoglobin) - hence "polychromatic" = many colors |
| Can divide? | β Yes - this is the last stage capable of mitosis |
| Duration | ~30 hours |
| Feature | Detail |
|---|---|
| Size | Just slightly bigger than a mature red cell |
| Nucleus | Small, dense, coal-black - no visible pattern |
| Cytoplasm | Pink/eosinophilic - full of hemoglobin now |
| Can divide? | β No - mitosis is over |
| Duration | ~48 hours |
| Feature | Detail |
|---|---|
| Size | Near-final size |
| Nucleus | Gone! β |
| Cytoplasm | Slightly bluish-red (still has some ribosomes and mRNA) |
| Special feature | Still synthesizes hemoglobin! |
| Duration | ~24 hrs in marrow + ~24 hrs in blood β then spleen |
| Normal count | 1-2% of circulating red cells |
π©Ί Clinical note: A high reticulocyte count = the bone marrow is working overtime (e.g., after blood loss or in hemolytic anemia). A low count = bone marrow failure.
| Feature | Detail |
|---|---|
| Size | 7.8 Β΅m biconcave disc |
| Nucleus | None |
| Cytoplasm | Pure bright red - packed with hemoglobin |
| Life span | ~120 days |
| Function | Carries oxygen via hemoglobin |


π©Ί Clinical note: When too many red cells are destroyed (hemolysis), bilirubin builds up β jaundice (yellow skin/eyes). Sickle cell disease patients often develop pigmented gallstones from excess bilirubin.
| Feature | Early (Proerythroblast) | Late (Normoblast) |
|---|---|---|
| Cell size | Large (12-20 Β΅m) | Small (~8 Β΅m) |
| Nucleus | Large, multiple nucleoli | Small, dense, then ejected |
| N:C ratio | 1:8 (nucleus huge) | 1:2 (cytoplasm dominant) |
| Cytoplasm color | Deep blue | Bright pink/red |
| RNA | High | Low β absent |
| Hemoglobin | Low | High |
| Mitosis | Active | Stops at normoblast |
| Condition | What's Disrupted |
|---|---|
| Anemia of chronic kidney disease | Low EPO from damaged kidneys β fewer red cells made |
| Iron deficiency anemia | Not enough iron β hemoglobin cannot be made |
| B12/folate deficiency | DNA synthesis fails β cells can't divide properly (megaloblastic anemia) |
| Polycythemia vera | Uncontrolled overproduction of red cells |
| Aplastic anemia | Stem cells are destroyed β no red cells made at all |
Convert it into hand written format
ls /tmp/workspace/ 2>/dev/null && echo "---" && pip show reportlab pillow 2>/dev/null | grep -E "^(Name|Version)"
pip show reportlab 2>/dev/null | grep Version; python3 -c "from reportlab.pdfbase import pdfmetrics; from reportlab.pdfbase.ttfonts import TTFont; print('ok')"
find /usr/share/fonts /usr/local/share/fonts ~/.fonts 2>/dev/null -name "*.ttf" | grep -i -E "caveat|indie|patrick|kalam|shadows|handlee|dancing|gloria|architects|permanent" | head -20
# Download handwriting-style fonts mkdir -p /tmp/workspace/erythropoiesis-notes/fonts cd /tmp/workspace/erythropoiesis-notes/fonts # Download Caveat (handwriting font) from Google Fonts curl -sL "https://fonts.gstatic.com/s/caveat/v17/WnznHAc5bAfYB2Q7ZjYYiA.ttf" -o Caveat-Regular.ttf curl -sL "https://fonts.gstatic.com/s/caveat/v17/WnznHAc5bAfYB2Q7aDcYiA.ttf" -o Caveat-Bold.ttf ls -lh *.ttf
python3 -c " from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont try: pdfmetrics.registerFont(TTFont('Caveat', '/tmp/workspace/erythropoiesis-notes/fonts/Caveat-Regular.ttf')) print('Regular loaded') pdfmetrics.registerFont(TTFont('Caveat-Bold', '/tmp/workspace/erythropoiesis-notes/fonts/Caveat-Bold.ttf')) print('Bold loaded') except Exception as e: print('Error:', e) "
cd /tmp/workspace/erythropoiesis-notes/fonts # Try direct download from GitHub curl -sL "https://github.com/google/fonts/raw/main/ofl/caveat/Caveat%5Bwght%5D.ttf" -o Caveat-VF.ttf ls -lh *.ttf file Caveat-VF.ttf
python3 -c " from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont try: pdfmetrics.registerFont(TTFont('Caveat', '/tmp/workspace/erythropoiesis-notes/fonts/Caveat-VF.ttf')) print('VF loaded OK') except Exception as e: print('Error:', e) "
~/erythropoiesis-notes/build_notes.py
"""
Erythropoiesis - Handwritten-style colorful student notebook PDF
Uses ReportLab with Caveat variable font (handwriting style)
"""
import math, random
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm, mm
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.colors import HexColor
# ββ Fonts ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
FONT_PATH = "/tmp/workspace/erythropoiesis-notes/fonts/Caveat-VF.ttf"
pdfmetrics.registerFont(TTFont("Caveat", FONT_PATH))
# ββ Colours ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PAGE_BG = HexColor("#FFFDF4") # warm cream notebook paper
LINE_COLOR = HexColor("#C8D8E8") # faint blue ruled lines
MARGIN_LINE = HexColor("#F5B8B8") # pink margin line
TITLE_COLOR = HexColor("#C0392B") # bold red for main title
H1_COLOR = HexColor("#1A5276") # dark navy for section heads
H2_COLOR = HexColor("#1E8449") # forest green sub-heads
BODY_COLOR = HexColor("#2C3E50") # near-black body text
HIGHLIGHT_YEL = HexColor("#FFF176") # yellow highlighter
HIGHLIGHT_GRN = HexColor("#B9F6CA") # green highlighter
HIGHLIGHT_BLU = HexColor("#B3E5FC") # blue highlighter
HIGHLIGHT_PNK = HexColor("#FCE4EC") # pink highlighter
HIGHLIGHT_ORG = HexColor("#FFE0B2") # orange highlighter
BOX_BLUE = HexColor("#D6EAF8")
BOX_GREEN = HexColor("#D5F5E3")
BOX_PINK = HexColor("#FDEDEC")
BOX_YELLOW = HexColor("#FEF9E7")
ARROW_COLOR = HexColor("#E74C3C")
STAR_COLOR = HexColor("#F39C12")
NOTE_COLOR = HexColor("#7D3C98")
# ββ Page setup βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
W, H = A4 # 595 x 842 pt
MARGIN = 2.2 * cm
LINE_H = 0.75 * cm # ruled line spacing
OUT = "/tmp/workspace/erythropoiesis-notes/Erythropoiesis_Handwritten_Notes.pdf"
# ββ Helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def draw_ruled_page(c):
"""Draw cream background + ruled lines + red margin."""
c.setFillColor(PAGE_BG)
c.rect(0, 0, W, H, fill=1, stroke=0)
# horizontal ruled lines
c.setStrokeColor(LINE_COLOR)
c.setLineWidth(0.4)
y = H - 3.2 * cm
while y > 1.5 * cm:
c.line(MARGIN, y, W - MARGIN + 0.5*cm, y)
y -= LINE_H
# red margin line
c.setStrokeColor(MARGIN_LINE)
c.setLineWidth(1.2)
c.line(MARGIN + 0.8*cm, H - 1*cm, MARGIN + 0.8*cm, 1*cm)
def cw(c, text, x, y, font="Caveat", size=14, color=BODY_COLOR):
"""Write coloured text."""
c.setFont(font, size)
c.setFillColor(color)
c.drawString(x, y, text)
def highlight_rect(c, x, y, w, h, col):
"""Draw a highlighter-style filled rectangle (no border)."""
c.setFillColor(col)
c.setStrokeColor(col)
c.roundRect(x, y - h*0.15, w, h*1.1, 3, fill=1, stroke=0)
def box(c, x, y, w, h, fill_col, stroke_col, radius=6, lw=1.5):
c.setFillColor(fill_col)
c.setStrokeColor(stroke_col)
c.setLineWidth(lw)
c.roundRect(x, y, w, h, radius, fill=1, stroke=1)
def arrow(c, x1, y1, x2, y2, col=ARROW_COLOR, lw=1.8):
c.setStrokeColor(col)
c.setLineWidth(lw)
c.line(x1, y1, x2, y2)
# arrowhead
angle = math.atan2(y2-y1, x2-x1)
size = 7
for da in [0.4, -0.4]:
c.line(x2, y2,
x2 - size*math.cos(angle+da),
y2 - size*math.sin(angle+da))
def star(c, x, y, col=STAR_COLOR, sz=10):
c.setFillColor(col)
c.setFont("Caveat", sz*2)
c.drawString(x, y, "β
")
def bullet(c, x, y, col=ARROW_COLOR):
c.setFillColor(col)
c.circle(x+4, y+5, 3.5, fill=1, stroke=0)
def wrapped_text(c, text, x, y, max_width, font="Caveat", size=13,
color=BODY_COLOR, line_spacing=18):
"""Simple word-wrap for handwritten body text."""
c.setFont(font, size)
words = text.split()
line = ""
for word in words:
test = line + (" " if line else "") + word
if c.stringWidth(test, font, size) <= max_width:
line = test
else:
cw(c, line, x, y, font, size, color)
y -= line_spacing
line = word
if line:
cw(c, line, x, y, font, size, color)
y -= line_spacing
return y
def page_number(c, num, total):
c.setFont("Caveat", 11)
c.setFillColor(HexColor("#888888"))
c.drawCentredString(W/2, 0.7*cm, f"β {num} / {total} β")
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# CONTENT PAGES
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
c = canvas.Canvas(OUT, pagesize=A4)
TOTAL_PAGES = 7
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAGE 1 : TITLE PAGE
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
draw_ruled_page(c)
# Decorative top strip
c.setFillColor(HexColor("#E74C3C"))
c.rect(0, H-1.5*cm, W, 1.5*cm, fill=1, stroke=0)
cw(c, "Medical Notes βοΈ", 1.5*cm, H-1.1*cm, size=16, color=colors.white)
# Big title
cw(c, "Erythropoiesis", MARGIN+1*cm, H-3.5*cm, size=52, color=TITLE_COLOR)
# underline scribble
c.setStrokeColor(TITLE_COLOR)
c.setLineWidth(2.5)
c.line(MARGIN+1*cm, H-3.9*cm, MARGIN+11*cm, H-3.9*cm)
cw(c, "How Your Body Makes Red Blood Cells π΄", MARGIN+1*cm, H-4.8*cm, size=20, color=H1_COLOR)
# Definition box
box(c, MARGIN+0.5*cm, H-8.2*cm, W-MARGIN*2-0.8*cm, 2.8*cm, BOX_YELLOW,
HexColor("#F39C12"), radius=8, lw=2)
cw(c, "π Definition", MARGIN+1*cm, H-5.7*cm, size=16, color=HexColor("#B7770D"))
wrapped_text(c, "Erythropoiesis = the step-by-step process of producing mature red blood cells",
MARGIN+1.2*cm, H-6.3*cm, W-MARGIN*2-1.5*cm, size=14)
wrapped_text(c, "(erythrocytes) from hematopoietic stem cells in the red bone marrow.",
MARGIN+1.2*cm, H-6.85*cm, W-MARGIN*2-1.5*cm, size=14)
cw(c, "Greek: erythros (red) + poiesis (making)", MARGIN+1.2*cm, H-7.5*cm, size=13,
color=HexColor("#7D6608"))
# Key facts grid
y0 = H - 9.5*cm
facts = [
("π Site", "Red bone marrow (adults)", BOX_BLUE, HexColor("#1A5276")),
("β±οΈ Time", "~7 days stemβRBC", BOX_GREEN, HexColor("#1E8449")),
("π Trigger","Low Oβ β EPO from kidney", BOX_PINK, HexColor("#C0392B")),
("π’ Output", "2Γ10ΒΉΒΉ RBCs/day", HIGHLIGHT_ORG, HexColor("#784212")),
]
xpos = [MARGIN+0.3*cm, MARGIN+0.3*cm + (W-2*MARGIN)/2 + 0.3*cm]
for i, (label, val, fc, tc) in enumerate(facts):
bx = xpos[i % 2]
by = y0 - (i // 2)*1.8*cm
box(c, bx, by, (W-2*MARGIN)/2 - 0.5*cm, 1.5*cm, fc, tc, radius=6, lw=1.5)
cw(c, label, bx+0.3*cm, by+0.95*cm, size=13, color=tc)
cw(c, val, bx+0.3*cm, by+0.3*cm, size=12, color=BODY_COLOR)
# Decorative doodles - RBC circles
def draw_rbc_doodle(c, cx, cy, r=10):
c.setFillColor(HexColor("#FFCDD2"))
c.setStrokeColor(HexColor("#E57373"))
c.setLineWidth(1)
c.circle(cx, cy, r, fill=1, stroke=1)
c.setFillColor(HexColor("#EF9A9A"))
c.circle(cx, cy, r*0.45, fill=1, stroke=0)
for i in range(6):
draw_rbc_doodle(c, W-2.5*cm + math.sin(i)*1.2*cm,
H-13*cm + i*1.5*cm, r=9+i*1.5)
# Bottom note
cw(c, "β
RBCs have NO nucleus & NO mitochondria in final form!",
MARGIN+1*cm, 2.5*cm, size=14, color=NOTE_COLOR)
cw(c, "β
Life span β 120 days", MARGIN+1*cm, 1.8*cm, size=14, color=NOTE_COLOR)
page_number(c, 1, TOTAL_PAGES)
c.showPage()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAGE 2 : THE TRIGGER β ERYTHROPOIETIN
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
draw_ruled_page(c)
cw(c, "The Trigger: Erythropoietin (EPO) π₯", MARGIN+1*cm, H-2.3*cm, size=24, color=TITLE_COLOR)
c.setStrokeColor(TITLE_COLOR); c.setLineWidth(2)
c.line(MARGIN+1*cm, H-2.6*cm, W-MARGIN-1*cm, H-2.6*cm)
# EPO feedback cycle drawn as boxes + arrows
steps = [
("Low Blood Oβ\n(Hypoxia)", H-4.5*cm, BOX_PINK, HexColor("#C0392B")),
("Kidneys detect\nβ Oβ", H-6.8*cm, BOX_BLUE, HexColor("#1A5276")),
("EPO released\ninto blood", H-9.1*cm, BOX_GREEN, HexColor("#1E8449")),
("Bone marrow\nactivated", H-11.4*cm, BOX_YELLOW, HexColor("#784212")),
("More RBCs\nproduced π΄", H-13.7*cm, HIGHLIGHT_ORG, HexColor("#784212")),
]
bx = W/2 - 4*cm
bw = 8*cm
bh = 1.7*cm
for label, by, fc, tc in steps:
box(c, bx, by, bw, bh, fc, tc, radius=8, lw=2)
lines = label.split("\n")
if len(lines)==2:
cw(c, lines[0], bx+0.5*cm, by+1.1*cm, size=15, color=tc)
cw(c, lines[1], bx+0.5*cm, by+0.3*cm, size=13, color=BODY_COLOR)
else:
cw(c, label, bx+0.5*cm, by+0.9*cm, size=15, color=tc)
for i in range(len(steps)-1):
ay = steps[i][1] # bottom of box above
by2 = steps[i+1][1]+bh
mx = bx + bw/2
arrow(c, mx, ay, mx, by2+2, lw=2.2)
# annotation
cw(c, "β EPO = 34 kDa glycoprotein hormone", W/2+4.5*cm, H-9.4*cm, size=12,
color=HexColor("#7D3C98"))
cw(c, "β Acts on ErP receptors", W/2+4.5*cm, H-11.7*cm, size=12,
color=HexColor("#7D3C98"))
# feedback arrow (curved feel)
c.setStrokeColor(HexColor("#27AE60"))
c.setLineWidth(1.5)
c.line(bx, H-13.7*cm+bh/2, MARGIN+0.3*cm, H-13.7*cm+bh/2)
c.line(MARGIN+0.3*cm, H-13.7*cm+bh/2, MARGIN+0.3*cm, H-4.5*cm+bh/2)
c.line(MARGIN+0.3*cm, H-4.5*cm+bh/2, bx, H-4.5*cm+bh/2)
cw(c, "Negative feedback\n(enough Oβ β stop EPO)", MARGIN+0.35*cm, H-9*cm, size=11,
color=HexColor("#27AE60"))
# Note box
box(c, MARGIN+0.5*cm, 2.5*cm, W-2*MARGIN-0.8*cm, 2.2*cm, BOX_PINK,
HexColor("#C0392B"), radius=6, lw=1.5)
cw(c, "π©Ί Clinical note:", MARGIN+1*cm, 4.3*cm, size=14, color=HexColor("#C0392B"))
cw(c, "Chronic kidney disease β low EPO β anemia of chronic disease",
MARGIN+1*cm, 3.6*cm, size=13, color=BODY_COLOR)
cw(c, "Treatment: synthetic EPO (epoetin alfa, darbepoetin)", MARGIN+1*cm, 3.0*cm,
size=13, color=BODY_COLOR)
page_number(c, 2, TOTAL_PAGES)
c.showPage()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAGE 3 : STAGES 1-3
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
draw_ruled_page(c)
cw(c, "Stages of Erythropoiesis (Part 1)", MARGIN+1*cm, H-2.3*cm, size=24, color=TITLE_COLOR)
c.setStrokeColor(TITLE_COLOR); c.setLineWidth(2)
c.line(MARGIN+1*cm, H-2.6*cm, W-MARGIN-1*cm, H-2.6*cm)
stage_data_1 = [
{
"num": "1",
"name": "Proerythroblast",
"emoji": "π£",
"color_label": "Large, BLUE cell",
"fc": BOX_BLUE,
"tc": HexColor("#1A5276"),
"facts": [
"Size: 12β20 Β΅m (biggest stage)",
"Large round nucleus, 1-2 nucleoli",
"Cytoplasm: mildly BLUE (basophilic)",
"Lots of ribosomes ready to make Hb",
"Duration: ~24 hours",
"Can divide β
",
],
"tip": "Think: 'Pro' = first big blue blob"
},
{
"num": "2",
"name": "Basophilic Erythroblast",
"emoji": "π΅",
"color_label": "Smaller, DEEP BLUE cell",
"fc": HexColor("#D6EAF8"),
"tc": HexColor("#154360"),
"facts": [
"Size: 10β16 Β΅m (shrank after dividing)",
"Nucleus: smaller, heterochromatin",
"Cytoplasm: INTENSELY BLUE",
"Packed polyribosomes making Hb!",
"Duration: ~24 hours",
"Can divide β
",
],
"tip": "Think: 'Basophilic' = loves blue stain"
},
{
"num": "3",
"name": "Polychromatophilic Erythroblast",
"emoji": "π€",
"color_label": "GRAY/LILAC 'tie-dye' cell",
"fc": HexColor("#EDE7F6"),
"tc": HexColor("#4A235A"),
"facts": [
"Nucleus: coarse CHECKERBOARD pattern",
"Cytoplasm: GRAY-LILAC mix of blue+pink",
"Both ribosomes (blue) + Hb (pink)",
"LAST STAGE capable of mitosis!",
"Duration: ~30 hours",
"Can divide β
(last time!)",
],
"tip": "Think: 'Poly' = many colours β tie-dye"
},
]
y_start = H - 3.4*cm
for sd in stage_data_1:
bh_box = 4.6*cm
box(c, MARGIN+0.3*cm, y_start-bh_box, W-2*MARGIN-0.4*cm, bh_box,
sd["fc"], sd["tc"], radius=8, lw=2)
# Stage number circle
c.setFillColor(sd["tc"])
c.circle(MARGIN+1.1*cm, y_start-0.55*cm, 0.55*cm, fill=1, stroke=0)
c.setFont("Caveat", 18); c.setFillColor(colors.white)
c.drawCentredString(MARGIN+1.1*cm, y_start-0.75*cm, sd["num"])
# Name + emoji
cw(c, sd["emoji"]+" "+sd["name"], MARGIN+2*cm, y_start-0.6*cm, size=18, color=sd["tc"])
cw(c, "β "+sd["color_label"], MARGIN+2*cm, y_start-1.15*cm, size=13,
color=HexColor("#7D6608"))
# Facts in two columns
col1 = sd["facts"][:3]; col2 = sd["facts"][3:]
for j, fact in enumerate(col1):
bullet(c, MARGIN+1.2*cm, y_start-1.8*cm-j*0.55*cm, sd["tc"])
cw(c, fact, MARGIN+1.8*cm, y_start-1.75*cm-j*0.55*cm, size=12, color=BODY_COLOR)
for j, fact in enumerate(col2):
bullet(c, W/2+0.3*cm, y_start-1.8*cm-j*0.55*cm, sd["tc"])
cw(c, fact, W/2+0.9*cm, y_start-1.75*cm-j*0.55*cm, size=12, color=BODY_COLOR)
# Tip
cw(c, "π‘ "+sd["tip"], MARGIN+1.2*cm, y_start-bh_box+0.25*cm, size=11,
color=HexColor("#7D3C98"))
y_start -= bh_box + 0.35*cm
page_number(c, 3, TOTAL_PAGES)
c.showPage()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAGE 4 : STAGES 4-6
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
draw_ruled_page(c)
cw(c, "Stages of Erythropoiesis (Part 2)", MARGIN+1*cm, H-2.3*cm, size=24, color=TITLE_COLOR)
c.setStrokeColor(TITLE_COLOR); c.setLineWidth(2)
c.line(MARGIN+1*cm, H-2.6*cm, W-MARGIN-1*cm, H-2.6*cm)
stage_data_2 = [
{
"num": "4",
"name": "Orthochromatophilic Erythroblast",
"alt": "(Normoblast)",
"emoji": "π©·",
"fc": BOX_PINK,
"tc": HexColor("#922B21"),
"facts": [
"Nucleus: small, coal-black, solid",
"Cytoplasm: PINK/eosinophilic = full Hb!",
"Cannot divide anymore β",
"Duration: ~48 hours",
"Nucleus is EJECTED at end of stage!",
"Leftover fragments = Howell-Jolly bodies",
],
"tip": "Nucleus kicked out β cell becomes anuclear"
},
{
"num": "5",
"name": "Reticulocyte",
"alt": "(Polychromatophilic Erythrocyte)",
"emoji": "π΄",
"fc": HexColor("#FDEDEC"),
"tc": HexColor("#7B241C"),
"facts": [
"NO nucleus β (extruded in stage 4)",
"Still has ribosomes & mRNA",
"Can still make Hb!",
"~1-2% of circulating RBCs normally",
"Matures in the SPLEEN (1-2 days)",
"High reticulocyte = marrow working hard",
],
"tip": "Retic count β = good marrow response (after bleed/hemolysis)"
},
{
"num": "6",
"name": "Mature Erythrocyte",
"alt": "(Red Blood Cell)",
"emoji": "β€οΈ",
"fc": HexColor("#FADBD8"),
"tc": HexColor("#641E16"),
"facts": [
"Size: 7.8 Β΅m biconcave disc",
"NO nucleus, NO mitochondria",
"Cytoplasm: pure bright RED (all Hb)",
"Carries Oβ via hemoglobin",
"Life span: ~120 days",
"Destroyed by spleen/liver macrophages",
],
"tip": "Biconcave = max surface area for gas exchange!"
},
]
y_start = H - 3.4*cm
for sd in stage_data_2:
bh_box = 4.6*cm
box(c, MARGIN+0.3*cm, y_start-bh_box, W-2*MARGIN-0.4*cm, bh_box,
sd["fc"], sd["tc"], radius=8, lw=2)
c.setFillColor(sd["tc"])
c.circle(MARGIN+1.1*cm, y_start-0.55*cm, 0.55*cm, fill=1, stroke=0)
c.setFont("Caveat", 18); c.setFillColor(colors.white)
c.drawCentredString(MARGIN+1.1*cm, y_start-0.75*cm, sd["num"])
cw(c, sd["emoji"]+" "+sd["name"], MARGIN+2*cm, y_start-0.6*cm, size=18, color=sd["tc"])
cw(c, sd["alt"], MARGIN+2*cm, y_start-1.15*cm, size=13, color=HexColor("#7D6608"))
col1 = sd["facts"][:3]; col2 = sd["facts"][3:]
for j, fact in enumerate(col1):
bullet(c, MARGIN+1.2*cm, y_start-1.8*cm-j*0.55*cm, sd["tc"])
cw(c, fact, MARGIN+1.8*cm, y_start-1.75*cm-j*0.55*cm, size=12, color=BODY_COLOR)
for j, fact in enumerate(col2):
bullet(c, W/2+0.3*cm, y_start-1.8*cm-j*0.55*cm, sd["tc"])
cw(c, fact, W/2+0.9*cm, y_start-1.75*cm-j*0.55*cm, size=12, color=BODY_COLOR)
cw(c, "π‘ "+sd["tip"], MARGIN+1.2*cm, y_start-bh_box+0.25*cm, size=11,
color=HexColor("#7D3C98"))
y_start -= bh_box + 0.35*cm
page_number(c, 4, TOTAL_PAGES)
c.showPage()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAGE 5 : SUMMARY FLOW DIAGRAM
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
draw_ruled_page(c)
cw(c, "Summary Flow Diagram π", MARGIN+1*cm, H-2.3*cm, size=26, color=TITLE_COLOR)
c.setStrokeColor(TITLE_COLOR); c.setLineWidth(2)
c.line(MARGIN+1*cm, H-2.6*cm, W-MARGIN-1*cm, H-2.6*cm)
flow = [
("Hematopoietic\nStem Cell (HSC)", HexColor("#7F8C8D"), colors.white),
("CMP β MEP β ErP\n(Progenitor cells)", HexColor("#2980B9"), colors.white),
("1. Proerythroblast\n(12-20 Β΅m, blue)", HexColor("#8E44AD"), colors.white),
("2. Basophilic\nErythroblast (deep blue)", HexColor("#1A5276"), colors.white),
("3. Polychromatophilic\nErythroblast (lilac)", HexColor("#6C3483"), colors.white),
("4. Normoblast\n(pink, nucleus ejected β)", HexColor("#CB4335"), colors.white),
("5. Reticulocyte\n(anuclear, blue-red)", HexColor("#922B21"), colors.white),
("6. Mature Erythrocyte\n(7.8 Β΅m, pure red β€οΈ)", HexColor("#641E16"), colors.white),
]
bw2 = 7*cm; bh2 = 1.5*cm
bx2 = W/2 - bw2/2
y2 = H - 3.6*cm
for i, (label, fc, tc) in enumerate(flow):
c.setFillColor(fc)
c.setStrokeColor(HexColor("#FFFFFF"))
c.setLineWidth(1.5)
c.roundRect(bx2, y2-bh2, bw2, bh2, 7, fill=1, stroke=1)
lines = label.split("\n")
if len(lines) == 2:
c.setFont("Caveat", 13); c.setFillColor(tc)
c.drawCentredString(bx2+bw2/2, y2-0.55*cm, lines[0])
c.setFont("Caveat", 11)
c.drawCentredString(bx2+bw2/2, y2-1.05*cm, lines[1])
else:
c.setFont("Caveat", 13); c.setFillColor(tc)
c.drawCentredString(bx2+bw2/2, y2-0.8*cm, label)
# Side annotations
if i == 0:
cw(c, "β Multipotent master cell", bx2+bw2+0.5*cm, y2-0.9*cm, size=11, color=H1_COLOR)
if i == 2:
cw(c, "β 1st recognizable cell", bx2+bw2+0.5*cm, y2-0.9*cm, size=11, color=NOTE_COLOR)
if i == 4:
cw(c, "β Last stage to divide!", bx2+bw2+0.5*cm, y2-0.9*cm, size=11,
color=HexColor("#E74C3C"))
if i == 5:
cw(c, "β Howell-Jolly bodies", bx2+bw2+0.5*cm, y2-0.9*cm, size=11, color=NOTE_COLOR)
if i == 6:
cw(c, "β Matures in spleen", bx2+bw2+0.5*cm, y2-0.9*cm, size=11, color=H2_COLOR)
if i < len(flow)-1:
arrow(c, bx2+bw2/2, y2-bh2, bx2+bw2/2, y2-bh2-0.45*cm, lw=2)
y2 -= bh2 + 0.55*cm
# Duration timeline on left
cw(c, "β± Timeline:", MARGIN+0.2*cm, H-3.8*cm, size=13, color=H1_COLOR)
times = ["", "variable", "~24 h", "~24 h", "~30 h", "~48 h", "~2 days", "~120 days"]
ty = H - 3.6*cm
for t in times:
if t:
cw(c, t, MARGIN+0.2*cm, ty-bh2/2, size=11, color=HexColor("#7D3C98"))
ty -= bh2 + 0.55*cm
page_number(c, 5, TOTAL_PAGES)
c.showPage()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAGE 6 : KEY CHANGES TABLE + RNA vs Hb concept
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
draw_ruled_page(c)
cw(c, "Key Changes During Maturation π", MARGIN+1*cm, H-2.3*cm, size=24, color=TITLE_COLOR)
c.setStrokeColor(TITLE_COLOR); c.setLineWidth(2)
c.line(MARGIN+1*cm, H-2.6*cm, W-MARGIN-1*cm, H-2.6*cm)
# Table
headers = ["Feature", "Early (Proerythroblast)", "Late (Normoblast)"]
rows = [
["Cell size", "Large 12-20 Β΅m", "Small ~8 Β΅m"],
["Nucleus", "Large, 2 nucleoli", "Small β EJECTED"],
["N:C ratio", "1:8 (nucleus huge)", "1:2 (cytoplasm wins)"],
["Cytoplasm colour","DEEP BLUE (basophilic)", "BRIGHT PINK (Hb)"],
["RNA content", "HIGH (ribosomes active)","Low β absent"],
["Haemoglobin", "Low (just starting)", "HIGH (packed)"],
["Mitosis", "Active β
", "Stops at normoblast β"],
]
col_w = [(W-2*MARGIN-0.6*cm)*0.28, (W-2*MARGIN-0.6*cm)*0.36, (W-2*MARGIN-0.6*cm)*0.36]
tx = MARGIN + 0.3*cm
ty = H - 3.4*cm
row_h = 0.75*cm
# Header row
c.setFillColor(HexColor("#1A5276"))
c.rect(tx, ty-row_h, sum(col_w), row_h, fill=1, stroke=0)
cx = tx
for i, h in enumerate(headers):
c.setFont("Caveat", 13); c.setFillColor(colors.white)
c.drawString(cx+0.2*cm, ty-0.55*cm, h)
cx += col_w[i]
ty -= row_h
alt_cols = [HexColor("#EBF5FB"), HexColor("#FDFEFE")]
for ri, row in enumerate(rows):
c.setFillColor(alt_cols[ri % 2])
c.rect(tx, ty-row_h, sum(col_w), row_h, fill=1, stroke=0)
# light grid lines
c.setStrokeColor(HexColor("#AED6F1")); c.setLineWidth(0.5)
c.rect(tx, ty-row_h, sum(col_w), row_h, fill=0, stroke=1)
cx = tx
for ci, cell in enumerate(row):
colour = BODY_COLOR
if ci == 1 and "BLUE" in cell: colour = HexColor("#1A5276")
if ci == 2 and "PINK" in cell: colour = HexColor("#C0392B")
if "β
" in cell: colour = HexColor("#1E8449")
if "β" in cell: colour = HexColor("#C0392B")
c.setFont("Caveat", 12); c.setFillColor(colour)
c.drawString(cx+0.2*cm, ty-0.52*cm, cell)
cx += col_w[ci]
ty -= row_h
# RNA vs Hb bar chart (simplified hand-drawn style)
cw(c, "RNA vs Haemoglobin during maturation:", MARGIN+0.5*cm, ty-0.8*cm, size=15, color=H1_COLOR)
chart_y = ty - 5.5*cm
chart_h = 3.8*cm
chart_x = MARGIN + 1*cm
chart_w = W - 2*MARGIN - 2*cm
stages_short = ["ProE", "BasoE", "PolyE", "OrthoE", "Retic", "RBC"]
rna_vals = [0.7, 1.0, 0.7, 0.3, 0.1, 0.0]
hb_vals = [0.1, 0.2, 0.45, 0.75, 0.9, 1.0]
bar_w = chart_w / (len(stages_short)*2 + 1)
# axes
c.setStrokeColor(BODY_COLOR); c.setLineWidth(1.2)
c.line(chart_x, chart_y, chart_x, chart_y+chart_h)
c.line(chart_x, chart_y, chart_x+chart_w, chart_y)
cw(c, "100%", chart_x-1*cm, chart_y+chart_h-0.1*cm, size=10, color=BODY_COLOR)
cw(c, "0%", chart_x-0.7*cm, chart_y-0.15*cm, size=10, color=BODY_COLOR)
for i, s in enumerate(stages_short):
bx_rna = chart_x + (2*i+0.5) * bar_w
bx_hb = bx_rna + bar_w
# RNA bar (blue)
rh = rna_vals[i]*chart_h
c.setFillColor(HexColor("#5DADE2"))
c.rect(bx_rna, chart_y, bar_w*0.9, rh, fill=1, stroke=0)
# Hb bar (red)
hh = hb_vals[i]*chart_h
c.setFillColor(HexColor("#E74C3C"))
c.rect(bx_hb, chart_y, bar_w*0.9, hh, fill=1, stroke=0)
# label
c.setFont("Caveat", 9); c.setFillColor(BODY_COLOR)
c.drawCentredString(bx_rna+bar_w, chart_y-0.3*cm, s)
# legend
c.setFillColor(HexColor("#5DADE2"))
c.rect(chart_x+chart_w-3.5*cm, chart_y+chart_h-0.9*cm, 0.6*cm, 0.5*cm, fill=1, stroke=0)
cw(c, "RNA", chart_x+chart_w-2.7*cm, chart_y+chart_h-0.75*cm, size=12,
color=HexColor("#1A5276"))
c.setFillColor(HexColor("#E74C3C"))
c.rect(chart_x+chart_w-1.5*cm, chart_y+chart_h-0.9*cm, 0.6*cm, 0.5*cm, fill=1, stroke=0)
cw(c, "Hb", chart_x+chart_w-0.7*cm, chart_y+chart_h-0.75*cm, size=12,
color=HexColor("#C0392B"))
page_number(c, 6, TOTAL_PAGES)
c.showPage()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PAGE 7 : CLINICAL APPLICATIONS + RBC DESTRUCTION
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
draw_ruled_page(c)
cw(c, "Clinical Applications π©Ί", MARGIN+1*cm, H-2.3*cm, size=26, color=TITLE_COLOR)
c.setStrokeColor(TITLE_COLOR); c.setLineWidth(2)
c.line(MARGIN+1*cm, H-2.6*cm, W-MARGIN-1*cm, H-2.6*cm)
clinical = [
("Anemia of CKD", "Low EPO from damaged kidneys β fewer RBCs", "Rx: recombinant EPO (epoetin)", BOX_PINK, HexColor("#C0392B")),
("Iron Deficiency Anemia","Not enough iron β Hb cannot be built", "Rx: iron supplements", HIGHLIGHT_YEL, HexColor("#784212")),
("Megaloblastic Anemia", "B12/Folate deficiency β DNA synthesis fails", "Cells can't divide β giant cells", BOX_BLUE, HexColor("#1A5276")),
("Aplastic Anemia", "Stem cells destroyed β NO RBCs made at all", "Rx: bone marrow transplant", BOX_GREEN, HexColor("#1E8449")),
("Polycythemia Vera", "Uncontrolled overproduction of RBCs", "JAK2 mutation; Rx: phlebotomy", HIGHLIGHT_ORG, HexColor("#784212")),
("High Reticulocyte Count","Marrow working overtime β after bleed/hemolysis", "Good compensation sign", HIGHLIGHT_GRN, HexColor("#1E8449")),
]
y_c = H - 3.4*cm
for cond, mech, rx, fc, tc in clinical:
bh_c = 1.6*cm
box(c, MARGIN+0.3*cm, y_c-bh_c, W-2*MARGIN-0.4*cm, bh_c, fc, tc, radius=6, lw=1.5)
cw(c, "β "+cond, MARGIN+0.8*cm, y_c-0.5*cm, size=14, color=tc)
cw(c, mech, MARGIN+1.2*cm, y_c-1.0*cm, size=12, color=BODY_COLOR)
cw(c, rx, W/2+0.5*cm, y_c-1.0*cm, size=11, color=HexColor("#7D3C98"))
y_c -= bh_c + 0.3*cm
# RBC destruction section
cw(c, "β» RBC Destruction (after 120 days)", MARGIN+0.5*cm, y_c-0.3*cm, size=17, color=H1_COLOR)
y_c -= 1.0*cm
dest_steps = [
("Senescent RBC phagocytosed by macrophages\n(spleen, liver, bone marrow)", BOX_PINK),
("Hb splits β Haem + Globin", BOX_BLUE),
("Globin β amino acids β recycled to protein pool", BOX_GREEN),
("Iron released β stored as ferritin/hemosiderin β reused for new Hb", HIGHLIGHT_YEL),
("Heme ring β bilirubin β albumin β liver\nβ conjugated β bile β excreted", HIGHLIGHT_ORG),
]
for step, fc2 in dest_steps:
lines2 = step.split("\n")
bh3 = 1.0*cm * len(lines2)
box(c, MARGIN+0.3*cm, y_c-bh3, W-2*MARGIN-0.4*cm, bh3, fc2,
HexColor("#7F8C8D"), radius=5, lw=1)
for li, ln in enumerate(lines2):
cw(c, ("β " if li==0 else " ")+ln, MARGIN+0.9*cm,
y_c - 0.5*cm - li*0.55*cm, size=12, color=BODY_COLOR)
if dest_steps.index((step, fc2)) < len(dest_steps)-1:
arrow(c, MARGIN+4*cm, y_c-bh3, MARGIN+4*cm, y_c-bh3-0.18*cm, lw=1.5)
y_c -= bh3 + 0.3*cm
# Clinical note bilirubin
if y_c > 1.8*cm:
box(c, MARGIN+0.3*cm, 1.3*cm, W-2*MARGIN-0.4*cm, y_c-1.8*cm,
HIGHLIGHT_PNK, HexColor("#922B21"), radius=5, lw=1.5)
cw(c, "π©Ί High bilirubin = jaundice (yellow skin/eyes)",
MARGIN+0.8*cm, y_c-0.6*cm, size=13, color=HexColor("#922B21"))
cw(c, " Sickle cell patients β excess bilirubin β pigmented gallstones",
MARGIN+0.8*cm, y_c-1.2*cm, size=12, color=BODY_COLOR)
page_number(c, 7, TOTAL_PAGES)
c.showPage()
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
c.save()
print(f"PDF saved to: {OUT}")
cd /tmp/workspace/erythropoiesis-notes && python3 build_notes.py 2>&1
ls -lh /tmp/workspace/erythropoiesis-notes/Erythropoiesis_Handwritten_Notes.pdf
Erythropoiesis Handwritten Notes
PDF Document Β· PDF
| Page | Content |
|---|---|
| Page 1 | Title page - definition, key facts grid, decorative RBC doodles |
| Page 2 | The EPO trigger - kidney-to-marrow feedback cycle with step-by-step arrow diagram |
| Page 3 | Stages 1-3 (Proerythroblast β Basophilic β Polychromatophilic Erythroblast) with coloured boxes |
| Page 4 | Stages 4-6 (Normoblast β Reticulocyte β Mature RBC) with clinical tips |
| Page 5 | Full summary flow diagram - all 8 stages stacked with side annotations and timeline |
| Page 6 | Key changes table (size, nucleus, colour, RNA, Hb) + bar chart of RNA vs Hb |
| Page 7 | Clinical applications table + RBC destruction/recycling pathway |