Make the best way u can include the 1st 2 pages into 1 page including my handwriting jn the corner and every explanation
cd /home/daytona/workspace && python3 -c " import pdfplumber import json pdf_path = '/home/daytona/workspace/attachments/37000a49-f556-4a77-9718-6cccf01534ad/Anemia.pdf' with pdfplumber.open(pdf_path) as pdf: print(f'Total pages: {len(pdf.pages)}') for i, page in enumerate(pdf.pages[:2]): print(f'\n=== PAGE {i+1} ===') print(f'Size: {page.width} x {page.height}') text = page.extract_text(x_tolerance=3, y_tolerance=3) print(text) print(f'\n--- Tables on page {i+1} ---') tables = page.extract_tables() for j, t in enumerate(tables): print(f'Table {j+1}: {t}') "
cd /home/daytona/workspace && python3 -c " from pypdf import PdfReader import json pdf_path = '/home/daytona/workspace/attachments/37000a49-f556-4a77-9718-6cccf01534ad/Anemia.pdf' reader = PdfReader(pdf_path) print(f'Total pages: {len(reader.pages)}') for i, page in enumerate(reader.pages[:2]): print(f'Page {i+1} images: {len(page.images)}') for j, img in enumerate(page.images): print(f' Image {j}: name={img.name}, size={len(img.data)} bytes') "
cd /home/daytona/workspace && mkdir -p anemia-combined/assets && python3 -c " from pypdf import PdfReader pdf_path = '/home/daytona/workspace/attachments/37000a49-f556-4a77-9718-6cccf01534ad/Anemia.pdf' reader = PdfReader(pdf_path) for page_num in range(2): page = reader.pages[page_num] for j, img in enumerate(page.images): ext = img.name.split('.')[-1] out_path = f'/home/daytona/workspace/anemia-combined/assets/page{page_num+1}_img{j}.{ext}' with open(out_path, 'wb') as f: f.write(img.data) print(f'Saved: {out_path} ({len(img.data)} bytes)') "
python3 -c "import fitz; print('pymupdf ok')" 2>/dev/null || echo "no pymupdf" python3 -c "from pdf2image import convert_from_path; print('pdf2image ok')" 2>/dev/null || echo "no pdf2image" which pdftoppm && echo "pdftoppm ok" || echo "no pdftoppm" which convert && echo "imagemagick ok" || echo "no imagemagick"
cd /home/daytona/workspace/anemia-combined && python3 << 'EOF' from pdf2image import convert_from_path from PIL import Image import os pdf_path = '/home/daytona/workspace/attachments/37000a49-f556-4a77-9718-6cccf01534ad/Anemia.pdf' # Convert first 2 pages at high DPI pages = convert_from_path(pdf_path, dpi=200, first_page=1, last_page=2) print(f"Converted {len(pages)} pages") for i, page in enumerate(pages): out = f'/home/daytona/workspace/anemia-combined/assets/page{i+1}_full.png' page.save(out, 'PNG') print(f"Page {i+1}: {page.size} -> saved to {out}") EOF
cd /home/daytona/workspace/anemia-combined && python3 << 'EOF' from PIL import Image # Load both pages p1 = Image.open('assets/page1_full.png') p2 = Image.open('assets/page2_full.png') print(f"Page 1 size: {p1.size}") print(f"Page 2 size: {p2.size}") # Target: A4 landscape at 200 dpi = 2339 x 1654 px (roughly) # Or we can do A3 portrait: 3508 x 4961 at 300dpi # Let's combine side by side on a wide page (landscape A3 at 200dpi = ~3307 x 2339) # Actually let's scale both pages to half width and place side by side TARGET_W = 4400 # combined width TARGET_H = 3200 # height # Scale each page to fit half the width half_w = (TARGET_W - 60) // 2 # 60px gap scale1 = half_w / p1.width new_h1 = int(p1.height * scale1) scale2 = half_w / p2.width new_h2 = int(p2.height * scale2) p1_resized = p1.resize((half_w, new_h1), Image.LANCZOS) p2_resized = p2.resize((half_w, new_h2), Image.LANCZOS) max_h = max(new_h1, new_h2) print(f"Resized page 1: {p1_resized.size}") print(f"Resized page 2: {p2_resized.size}") print(f"Max height: {max_h}") # Create combined white canvas combined = Image.new('RGB', (TARGET_W, max_h + 40), (255, 255, 255)) combined.paste(p1_resized, (10, 20)) combined.paste(p2_resized, (half_w + 50, 20)) combined.save('assets/combined_preview.png', 'PNG') print(f"Combined saved: {combined.size}") EOF
cd /home/daytona/workspace/anemia-combined && python3 << 'EOF' from PIL import Image from reportlab.lib.pagesizes import A3, landscape from reportlab.pdfgen import canvas from reportlab.lib.utils import ImageReader import io # Load both page images p1 = Image.open('assets/page1_full.png') p2 = Image.open('assets/page2_full.png') # A3 landscape: 1190.55 x 841.89 points (approx 420mm x 297mm) page_w, page_h = landscape(A3) print(f"A3 landscape: {page_w:.1f} x {page_h:.1f} pt") # We'll place both pages side by side with a small margin margin = 8 gap = 8 avail_w = page_w - 2*margin - gap avail_h = page_h - 2*margin # Each image gets half the available width half_w = avail_w / 2 # Scale to fit height too scale1 = min(half_w / p1.width, avail_h / p1.height) scale2 = min(half_w / p2.width, avail_h / p2.height) w1 = p1.width * scale1 h1 = p1.height * scale1 w2 = p2.width * scale2 h2 = p2.height * scale2 print(f"Page 1 scaled: {w1:.1f} x {h1:.1f}") print(f"Page 2 scaled: {w2:.1f} x {h2:.1f}") # Create PDF c = canvas.Canvas('Anemia_Combined.pdf', pagesize=landscape(A3)) # Draw page 1 (left side) - centered vertically y1 = margin + (avail_h - h1) / 2 c.drawImage(ImageReader(p1), margin, y1, width=w1, height=h1) # Draw page 2 (right side) x2 = margin + w1 + gap y2 = margin + (avail_h - h2) / 2 c.drawImage(ImageReader(p2), x2, y2, width=w2, height=h2) # Add a subtle divider line c.setStrokeColorRGB(0.7, 0.7, 0.7) c.setLineWidth(0.5) mid_x = margin + w1 + gap/2 c.line(mid_x, margin, mid_x, page_h - margin) c.save() print("PDF saved: Anemia_Combined.pdf") import os size = os.path.getsize('Anemia_Combined.pdf') print(f"File size: {size/1024:.1f} KB") EOF
cd /home/daytona/workspace/anemia-combined && python3 << 'EOF' from PIL import Image, ImageDraw from reportlab.lib.pagesizes import A3, landscape from reportlab.pdfgen import canvas from reportlab.lib.utils import ImageReader import os # Load both page images p1 = Image.open('assets/page1_full.png') p2 = Image.open('assets/page2_full.png') # Add a thin border to each page image to visually separate them def add_border(img, border=6, color=(180,180,180)): draw = ImageDraw.Draw(img) draw.rectangle([0, 0, img.width-1, img.height-1], outline=color, width=border) return img p1 = add_border(p1.copy()) p2 = add_border(p2.copy()) # A3 landscape page_w, page_h = landscape(A3) margin = 10 gap = 10 avail_w = page_w - 2*margin - gap avail_h = page_h - 2*margin half_w = avail_w / 2 scale1 = min(half_w / p1.width, avail_h / p1.height) scale2 = min(half_w / p2.width, avail_h / p2.height) w1 = p1.width * scale1 h1 = p1.height * scale1 w2 = p2.width * scale2 h2 = p2.height * scale2 # Create PDF c = canvas.Canvas('Anemia_Combined_Final.pdf', pagesize=landscape(A3)) c.setTitle("Anemia - Pages 1 & 2 Combined") # Draw page 1 y1 = margin + (avail_h - h1) / 2 c.drawImage(ImageReader(p1), margin, y1, width=w1, height=h1) # Draw page 2 x2 = margin + w1 + gap y2 = margin + (avail_h - h2) / 2 c.drawImage(ImageReader(p2), x2, y2, width=w2, height=h2) c.save() size = os.path.getsize('Anemia_Combined_Final.pdf') print(f"Final PDF saved: Anemia_Combined_Final.pdf ({size/1024:.1f} KB)") EOF
Anemia Combined Final
PDF Document · PDF
Error
ls -la /home/daytona/workspace/anemia-combined/ && ls -la /home/daytona/workspace/anemia-combined/assets/
.json
Can u make a one page good flowchart or anything effiecnt explaining just the first page amd 2nd page ...but every line I have handwritten also in the side
python3 -c " import pdfplumber pdf_path = '/home/daytona/workspace/attachments/37000a49-f556-4a77-9718-6cccf01534ad/Anemia (1).pdf' with pdfplumber.open(pdf_path) as pdf: print(f'Total pages: {len(pdf.pages)}') for i in range(min(2, len(pdf.pages))): page = pdf.pages[i] print(f'\n========= PAGE {i+1} ({page.width:.0f}x{page.height:.0f}) =========') # Extract all words with positions words = page.extract_words(x_tolerance=3, y_tolerance=3, keep_blank_chars=True) print(f'Word count: {len(words)}') # Group by approximate y (lines) lines = {} for w in words: y_key = round(w[\"top\"] / 10) * 10 if y_key not in lines: lines[y_key] = [] lines[y_key].append(w) for y in sorted(lines.keys()): line_words = sorted(lines[y], key=lambda w: w[\"x0\"]) line_text = ' '.join(w[\"text\"] for w in line_words) # Show x position of first word to detect side annotations x0 = line_words[0][\"x0\"] print(f' [y={y:4d}, x0={x0:5.0f}] {line_text}') "
cd /home/daytona/workspace && mkdir -p anemia-v2/assets && python3 << 'EOF' from pypdf import PdfReader from pdf2image import convert_from_path pdf_path = '/home/daytona/workspace/attachments/37000a49-f556-4a77-9718-6cccf01534ad/Anemia (1).pdf' # Save embedded images reader = PdfReader(pdf_path) for page_num in range(2): page = reader.pages[page_num] print(f"Page {page_num+1} has {len(page.images)} embedded images") for j, img in enumerate(page.images): ext = img.name.split('.')[-1] out_path = f'/home/daytona/workspace/anemia-v2/assets/p{page_num+1}_img{j}.{ext}' with open(out_path, 'wb') as f: f.write(img.data) print(f" Saved: {out_path} ({len(img.data)//1024}KB)") # Also render full pages at high res print("\nRendering full pages...") pages = convert_from_path(pdf_path, dpi=250, first_page=1, last_page=2) for i, pg in enumerate(pages): out = f'/home/daytona/workspace/anemia-v2/assets/page{i+1}_full.png' pg.save(out, 'PNG') print(f" Page {i+1}: {pg.size} -> {out}") EOF
python3 << 'EOF' from PIL import Image # Check sizes and crops of the embedded images to find handwriting for fname in [ '/home/daytona/workspace/anemia-v2/assets/p1_img0.png', '/home/daytona/workspace/anemia-v2/assets/p1_img1.png', '/home/daytona/workspace/anemia-v2/assets/p1_img2.png', '/home/daytona/workspace/anemia-v2/assets/p2_img0.png', '/home/daytona/workspace/anemia-v2/assets/p2_img1.png', '/home/daytona/workspace/anemia-v2/assets/p2_img2.jpg', ]: try: img = Image.open(fname) print(f"{fname.split('/')[-1]}: {img.size} mode={img.mode}") except Exception as e: print(f"{fname}: ERROR {e}") EOF
python3 << 'EOF' # Analyze where on the full page the text vs handwriting regions are # The PDF is 1408x1337 units. Rendered at 250dpi = 4888x4643 px # Scale factor: 4888/1408 = 3.472 import pdfplumber pdf_path = '/home/daytona/workspace/attachments/37000a49-f556-4a77-9718-6cccf01534ad/Anemia (1).pdf' with pdfplumber.open(pdf_path) as pdf: for page_num in range(2): page = pdf.pages[page_num] print(f"\n=== PAGE {page_num+1} ===") print(f"Page size: {page.width} x {page.height}") # Find all images on the page with their positions if hasattr(page, 'images'): imgs = page.images print(f"Images on page: {len(imgs)}") for img in imgs: print(f" Image: x0={img['x0']:.0f} y0={img['y0']:.0f} x1={img['x1']:.0f} y1={img['y1']:.0f} w={img['width']:.0f} h={img['height']:.0f} name={img.get('name','?')}") # Find text bounding box words = page.extract_words() if words: xs = [w['x0'] for w in words] + [w['x1'] for w in words] ys = [w['top'] for w in words] + [w['bottom'] for w in words] print(f"Text bbox: x={min(xs):.0f}-{max(xs):.0f}, y={min(ys):.0f}-{max(ys):.0f}") EOF
python3 << 'EOF' from PIL import Image # Scale factor: rendered at 250dpi, PDF units = points at 72dpi # pixels_per_point = 250/72 = 3.472 scale = 250 / 72 def pdf_to_px(x, y_pdf, page_h_pdf, img_h_px): # PDF y is from bottom, PIL y is from top px_x = x * scale # convert PDF y (bottom-origin) to PIL y (top-origin) px_y = img_h_px - (y_pdf * scale) return int(px_x), int(px_y) # Load full page renders p1 = Image.open('/home/daytona/workspace/anemia-v2/assets/page1_full.png') p2 = Image.open('/home/daytona/workspace/anemia-v2/assets/page2_full.png') print(f"Page 1 render: {p1.size}") print(f"Page 2 render: {p2.size}") page_h = 1337.12 # Page 1: FXX1 handwriting at x0=14 y0=242 x1=180 y1=360 (PDF coords) # In PDF, y0 is bottom of box, y1 is top? Let's check: pdfplumber uses top-origin # pdfplumber top means distance from top of page # So: top=242, bottom=360 in pdfplumber -> in image: y_top=242*scale, y_bottom=360*scale x0_p1 = int(14 * scale) y0_p1 = int(242 * scale) # top x1_p1 = int(180 * scale) y1_p1 = int(360 * scale) # bottom print(f"P1 handwriting crop: ({x0_p1},{y0_p1}) to ({x1_p1},{y1_p1})") hw1 = p1.crop((x0_p1-10, y0_p1-10, x1_p1+10, y1_p1+10)) hw1.save('/home/daytona/workspace/anemia-v2/assets/handwriting_p1.png') print(f"Saved handwriting_p1.png: {hw1.size}") # Page 2: FXX1 at x0=135 y0=716 x1=324 y1=841 x0_p2 = int(135 * scale) y0_p2 = int(716 * scale) x1_p2 = int(324 * scale) y1_p2 = int(841 * scale) print(f"P2 handwriting crop: ({x0_p2},{y0_p2}) to ({x1_p2},{y1_p2})") hw2 = p2.crop((x0_p2-10, y0_p2-10, x1_p2+10, y1_p2+10)) hw2.save('/home/daytona/workspace/anemia-v2/assets/handwriting_p2.png') print(f"Saved handwriting_p2.png: {hw2.size}") # Also crop the Im0 images (table/diagram) # Page 1: Im0 at x0=366 y0=733 x1=828 y1=900 im0_p1 = p1.crop((int(366*scale)-5, int(733*scale)-5, int(828*scale)+5, int(900*scale)+5)) im0_p1.save('/home/daytona/workspace/anemia-v2/assets/diagram_p1.png') print(f"Saved diagram_p1.png: {im0_p1.size}") # Page 2: Im0 at x0=643 y0=432 x1=787 y1=541 im0_p2 = p2.crop((int(643*scale)-5, int(432*scale)-5, int(787*scale)+5, int(541*scale)+5)) im0_p2.save('/home/daytona/workspace/anemia-v2/assets/diagram_p2.png') print(f"Saved diagram_p2.png: {im0_p2.size}") EOF
python3 << 'PYEOF' from reportlab.lib.pagesizes import A3, landscape from reportlab.pdfgen import canvas from reportlab.lib.utils import ImageReader from reportlab.lib import colors from reportlab.lib.colors import HexColor from PIL import Image import io # ── Canvas setup (A3 landscape) ────────────────────────────────────────────── W, H = landscape(A3) # 1190.6 x 841.9 pt c = canvas.Canvas('/home/daytona/workspace/anemia-v2/Anemia_Flowchart.pdf', pagesize=(W, H)) c.setTitle("Anemia – Pages 1 & 2 Master Sheet") # ── Color palette ───────────────────────────────────────────────────────────── BG = HexColor('#F5F7FA') TITLE_BG = HexColor('#1A3A5C') TITLE_FG = colors.white BOX_BLUE = HexColor('#D6E4F0') BOX_BLUE2 = HexColor('#AED6F1') BOX_RED = HexColor('#FADBD8') BOX_GREEN = HexColor('#D5F5E3') BOX_ORG = HexColor('#FDEBD0') BOX_PURP = HexColor('#E8DAEF') BOX_TEAL = HexColor('#D1F2EB') HDR_BLUE = HexColor('#2471A3') HDR_RED = HexColor('#C0392B') HDR_GREEN = HexColor('#1E8449') HDR_ORG = HexColor('#D35400') HDR_PURP = HexColor('#6C3483') HDR_TEAL = HexColor('#117A65') BORDER = HexColor('#BDC3C7') TEXT_DARK = HexColor('#17202A') HAND_BG = HexColor('#FFFDE7') # light yellow for handwriting panels # ── Background ──────────────────────────────────────────────────────────────── c.setFillColor(BG) c.rect(0, 0, W, H, fill=1, stroke=0) # ── Helper functions ────────────────────────────────────────────────────────── def box(x, y, w, h, fill=BOX_BLUE, stroke_color=BORDER, radius=4): c.setFillColor(fill) c.setStrokeColor(stroke_color) c.setLineWidth(0.6) c.roundRect(x, y, w, h, radius, fill=1, stroke=1) def header_box(x, y, w, h, text, fill, text_color=colors.white, font='Helvetica-Bold', fsize=8): c.setFillColor(fill) c.setStrokeColor(fill) c.roundRect(x, y, w, h, 3, fill=1, stroke=0) c.setFillColor(text_color) c.setFont(font, fsize) c.drawCentredString(x + w/2, y + h/2 - fsize/3, text) def write(x, y, text, font='Helvetica', size=6.5, color=TEXT_DARK, align='left'): c.setFont(font, size) c.setFillColor(color) if align == 'center': c.drawCentredString(x, y, text) else: c.drawString(x, y, text) def bullet_lines(x, y, lines, size=6, indent=6, line_gap=9, bold_first=False): for i, line in enumerate(lines): font = 'Helvetica-Bold' if (i == 0 and bold_first) else 'Helvetica' write(x, y, line, font=font, size=size) y -= line_gap return y def arrow(x1, y1, x2, y2, color=HexColor('#7F8C8D'), w=0.8): c.setStrokeColor(color) c.setLineWidth(w) c.line(x1, y1, x2, y2) # arrowhead import math angle = math.atan2(y2-y1, x2-x1) al = 6 c.setFillColor(color) path = c.beginPath() path.moveTo(x2, y2) path.lineTo(x2 - al*math.cos(angle-0.4), y2 - al*math.sin(angle-0.4)) path.lineTo(x2 - al*math.cos(angle+0.4), y2 - al*math.sin(angle+0.4)) path.close() c.drawPath(path, fill=1, stroke=0) def embed_image(path, x, y, max_w, max_h): try: img = Image.open(path) iw, ih = img.size scale = min(max_w/iw, max_h/ih) dw, dh = iw*scale, ih*scale c.drawImage(ImageReader(img), x, y, width=dw, height=dh) return dw, dh except Exception as e: print(f"Image error {path}: {e}") return 0, 0 # ═══════════════════════════════════════════════════════════════════════════════ # TITLE BAR # ═══════════════════════════════════════════════════════════════════════════════ c.setFillColor(TITLE_BG) c.rect(0, H-30, W, 30, fill=1, stroke=0) write(W/2, H-21, 'APPROACH TO ANEMIA – Master Review Sheet (Pages 1 & 2)', font='Helvetica-Bold', size=13, color=colors.white, align='center') # ═══════════════════════════════════════════════════════════════════════════════ # LAYOUT: 4 columns # Col A: KEY CONCEPTS + MICROCYTIC (left) # Col B: NORMOCYTIC / MACROCYTIC (centre-left) # Col C: DIFFERENTIAL TABLE (centre-right) # Col D: MANAGEMENT + HANDWRITING (right) # ═══════════════════════════════════════════════════════════════════════════════ TOP = H - 34 BOT = 4 BODY = TOP - BOT # usable height M = 5 # outer margin GAP = 4 # gap between columns COL_WIDTHS = [210, 230, 390, 351] # total = 1181 ~ W - 2*M col_x = [M] for w in COL_WIDTHS[:-1]: col_x.append(col_x[-1] + w + GAP) # ── COLUMN A: KEY CONCEPTS ──────────────────────────────────────────────────── cx = col_x[0]; cw = COL_WIDTHS[0] cy = TOP # --- Handwriting panel (Page 1 corner) --- hw_h = 90 box(cx, cy - hw_h, cw, hw_h, fill=HAND_BG, stroke_color=HexColor('#F39C12')) write(cx+4, cy - 10, '✎ Your Notes (Page 1)', font='Helvetica-BoldOblique', size=7, color=HexColor('#D68910')) try: hw1 = Image.open('/home/daytona/workspace/anemia-v2/assets/handwriting_p1.png') embed_image('/home/daytona/workspace/anemia-v2/assets/handwriting_p1.png', cx+4, cy - hw_h + 3, cw - 8, hw_h - 16) except: pass cy -= hw_h + GAP # --- Definitions box --- box_h = 75 box(cx, cy - box_h, cw, box_h, fill=BOX_BLUE) header_box(cx, cy - 14, cw, 14, 'KEY DEFINITIONS', HDR_BLUE) lines_def = [ '• Anemia = Decreased RBC mass', '• Abs retic count = retic(lab) × Hct/Nl Hct', '• Retic Index (RI) = Abs retic / MF', ' MF: Hct>35%=1 | 25-35%=1.5 | 20-25%=2 | <20%=2.5', '• RI < 2 → Poor BM response', '• RI > 2 → Good BM response (active erythropoiesis)', ] ty = cy - 18 for ln in lines_def: write(cx+4, ty, ln, size=6) ty -= 8.5 cy -= box_h + GAP # --- Microcytic box --- box_h = 100 box(cx, cy - box_h, cw, box_h, fill=BOX_RED) header_box(cx, cy - 14, cw, 14, 'MICROCYTIC ANEMIA (↓ Hgb synthesis)', HDR_RED) lines_mic = [ ' Defect in:', ' GLOBIN → Thalassemia', ' HEME → Sideroblastic anemia', ' Iron Deficiency Anemia (IDA)', ' Anemia of Chronic Disease (AOCD)', '', ' Leukoerythroblastic picture:', ' • Dacrocytes • Nucleated RBCs • Immature WBCs', ' • Hepatosplenomegaly', ' • Hyperseg. Neutrophils (>6 lobes or >5% PMN>5 lobes)', ] ty = cy - 18 for ln in lines_mic: write(cx+4, ty, ln, size=6) ty -= 8.5 cy -= box_h + GAP # --- Drugs causing megaloblastic --- box_h = 76 box(cx, cy - box_h, cw, box_h, fill=BOX_PURP) header_box(cx, cy - 14, cw, 14, 'DRUGS → MEGALOBLASTIC ANEMIA', HDR_PURP) lines_meg = [ '• Anti-cancer drugs • Anti-epileptic drugs', '• Folate antagonists • ART (antiretrovirals)', '• Biguanides (metformin) • Nitrous Oxide', ] ty = cy - 18 for ln in lines_meg: write(cx+4, ty, ln, size=6.5) ty -= 9 cy -= box_h + GAP # ── COLUMN B: NORMOCYTIC / INTRAVASCULAR vs EXTRAVASCULAR ──────────────────── cx = col_x[1]; cw = COL_WIDTHS[1] cy = TOP # --- Normocytic overview --- box_h = 55 box(cx, cy - box_h, cw, box_h, fill=BOX_TEAL) header_box(cx, cy - 14, cw, 14, 'NORMOCYTIC ANEMIA', HDR_TEAL) lines_norm = [ ' Recent Blood Loss → Normal LDH', ' Hemolytic Anemia → Elevated LDH', ] ty = cy - 18 for ln in lines_norm: write(cx+4, ty, ln, size=6.5) ty -= 9 cy -= box_h + GAP # --- Hemolysis comparison --- box_h = 150 box(cx, cy - box_h, cw, box_h, fill=BOX_BLUE) header_box(cx, cy - 14, cw, 14, 'HEMOLYTIC ANEMIA – LOCALIZATION', HDR_BLUE) half = (cw-8) / 2 # Extravascular header c.setFillColor(HexColor('#D6EAF8')) c.setStrokeColor(BORDER) c.roundRect(cx+4, cy - 28, half-2, 12, 2, fill=1, stroke=1) write(cx+4+half/2-2, cy - 25, 'EXTRAVASCULAR', font='Helvetica-Bold', size=6, color=HDR_BLUE, align='center') # Intravascular header c.setFillColor(HexColor('#FADBD8')) c.roundRect(cx+4+half+2, cy - 28, half-2, 12, 2, fill=1, stroke=1) write(cx+4+half+2+half/2-2, cy - 25, 'INTRAVASCULAR', font='Helvetica-Bold', size=6, color=HDR_RED, align='center') ev = ['• Spherocytes more', ' common', '• Splenomegaly', '• Bilirubin elevation', '• Gallstones'] iv = ['• Reduced Haptoglobin', '• Hemosiderinuria', ' (chronic)', '• Increased CoHb', '• Hemoglobinuria'] ty = cy - 32 for e, i in zip(ev, iv): write(cx+6, ty, e, size=6) write(cx+6+half+2, ty, i, size=6, color=HDR_RED) ty -= 9 cy -= box_h + GAP # --- Macrocytic / B12 deficiency diagram --- box_h = 65 box(cx, cy - box_h, cw, box_h, fill=BOX_ORG) header_box(cx, cy - 14, cw, 14, 'MACROCYTIC ANEMIA', HDR_ORG) lines_mac = [ ' B12 / Folate deficiency → Megaloblastic', ' • Hyperseg neutrophils (>5 lobes)', ' • Oval macrocytes • ↑ MMA (B12 def only)', ' Liver disease / Hypothyroid → Non-megaloblastic', ] ty = cy - 18 for ln in lines_mac: write(cx+4, ty, ln, size=6) ty -= 9 cy -= box_h + GAP # --- Thalassemia pathophys --- box_h = 65 box(cx, cy - box_h, cw, box_h, fill=BOX_GREEN) header_box(cx, cy - 14, cw, 14, 'THALASSEMIA – PATHOPHYSIOLOGY', HDR_GREEN) lines_thal = [ ' Chain imbalance (relative excess of normal chains)', ' α-thal: ↓ alpha chains (gene deletion)', ' β-thal: ↓ beta chains (point mutations)', ' Trait (heterozygous) → mild microcytic, ↑ RBC count', ' Major → transfusion-dependent hemolytic anemia', ] ty = cy - 18 for ln in lines_thal: write(cx+4, ty, ln, size=6) ty -= 9 cy -= box_h + GAP # --- Handwriting Page 2 --- hw_h = 100 remaining = cy - BOT hw_h = min(hw_h, remaining - 2) if hw_h > 20: box(cx, cy - hw_h, cw, hw_h, fill=HAND_BG, stroke_color=HexColor('#F39C12')) write(cx+4, cy - 10, '✎ Your Notes (Page 2)', font='Helvetica-BoldOblique', size=7, color=HexColor('#D68910')) try: embed_image('/home/daytona/workspace/anemia-v2/assets/handwriting_p2.png', cx+4, cy - hw_h + 3, cw - 8, hw_h - 16) except: pass # ── COLUMN C: DIFFERENTIAL TABLE ───────────────────────────────────────────── cx = col_x[2]; cw = COL_WIDTHS[2] cy = TOP table_h = BODY - 4 box(cx, cy - table_h, cw, table_h, fill=colors.white) header_box(cx, cy - 16, cw, 16, 'DIFFERENTIAL DIAGNOSIS OF MICROCYTIC ANEMIA', HDR_BLUE, fsize=9) # Table column widths col_labels = ['Characteristic', 'IDA', 'AOCD', 'Thalassemia Trait', 'Sideroblastic (SA)'] col_ws = [92, 68, 78, 92, 98] # sums to 428 but let's scale total_cw = sum(col_ws) col_ws = [w * (cw - 8) / total_cw for w in col_ws] row_data = [ ('Etiology', 'Blood loss\n↓ supply / ↑ demand', 'Autoimmune, infect.\nHIV, malignancy', 'Heterozygous\nthalassemia', 'X-linked (ALAS2)\nIdiopathic, MDS-RARS\n(alcohol, Pb, INH, Cu↓)'), ('RBC/retic', '↓ (MI > 13)', '↓', '↑ (MI < 13)', '↓'), ('RDW', '↑', 'Normal', 'Normal', '↑'), ('Fe indices', '↓Fe ↓Ferritin\n↑sTfR ↑TIBC\nTSAT<18%\nsTfR/logFer>2\n↓Hepcidin', '↓Fe ↑Ferritin\nNl sTfR ↓TIBC\nTSAT>18%\nsTfR/logFer<1\n↑Hepcidin', 'Normal Fe indices', '↑Fe ↑TSAT ↑Ferr\nsTfR & TIBC normal'), ('FEP', '↑', '↑', 'Normal', '↑'), ('BM Fe', '–', '+', '+', '+'), ('Electro-\nphoresis', 'Normal', 'Normal', 'Abnormal\n(↑HbA2/HbF)', 'Normal'), ('Others', '', '↑CRP/ESR', '±Basophilic\nstippling', '±Basophilic\nstippling & RS'), ('Rx', 'Fe replacement\n(oral/IV)', 'Rx underlying\n± IV Fe ± ESA', 'No specific Rx', 'Rx reversible causes\n±Pyridoxine\n±Chelation'), ] row_colors = [BOX_BLUE2, BOX_BLUE, BOX_BLUE, BOX_BLUE2, BOX_BLUE, BOX_BLUE, BOX_BLUE2, BOX_BLUE, BOX_GREEN] ty = cy - 18 hdr_h = 14 # Draw header row hx = cx + 4 for ci, (lbl, cw2) in enumerate(zip(col_labels, col_ws)): hdr_c = HDR_BLUE if ci == 0 else HDR_BLUE box(hx, ty - hdr_h, cw2 - 1, hdr_h, fill=HexColor('#1A5276'), stroke_color=HexColor('#1A5276')) write(hx + cw2/2 - 1, ty - hdr_h + 3, lbl, font='Helvetica-Bold', size=6.5, color=colors.white, align='center') hx += cw2 ty -= hdr_h + 1 for ri, (row, rcol) in enumerate(zip(row_data, row_colors)): # measure row height from content max_lines = max(len(cell.split('\n')) for cell in row) rh = max(12, max_lines * 9 + 4) hx = cx + 4 for ci, (cell, cw2) in enumerate(zip(row, col_ws)): fill_c = HexColor('#EBF5FB') if ci == 0 else rcol box(hx, ty - rh, cw2 - 1, rh, fill=fill_c, stroke_color=BORDER) cell_lines = cell.split('\n') line_y = ty - 5 for cl in cell_lines: fc = HDR_BLUE if ci == 0 else TEXT_DARK fn = 'Helvetica-Bold' if ci == 0 else 'Helvetica' write(hx + 2, line_y, cl, font=fn, size=6, color=fc) line_y -= 8 hx += cw2 ty -= rh + 1 # ── COLUMN D: MANAGEMENT ───────────────────────────────────────────────────── cx = col_x[3]; cw = COL_WIDTHS[3] cy = TOP # IDA management box_h = 148 box(cx, cy - box_h, cw, box_h, fill=BOX_BLUE) header_box(cx, cy - 14, cw, 14, 'IDA MANAGEMENT', HDR_BLUE) lines_mgmt = [ 'ORAL Fe:', ' Duration: ~6 wks to correct Hb; ~6 mo to replete stores', ' Recommended: 200 mg elemental Fe/day', ' • Fe Gluconate – 12% elemental iron', ' • Fe Sulphate – 20% elemental iron', ' • Fe Fumarate – 35% elemental iron ← best content', ' Best absorbed: empty stomach or 2h after meal', '', 'POOR RESPONSE (Hb ↑ <2g/dL in 3 weeks) → consider:', ' Non-compliance | Ongoing bleed | Malabsorption', ' Wrong diagnosis | Mixed deficiency', '', 'ABSORPTION INHIBITORS:', ' Calcium, PPIs/H2RA, phytates, phosphates, tannates', '', 'IV Fe INDICATIONS:', ' Oral intolerance | Malabsorption | Pre-ESA', ' CKD on HD | Cancer | CHF | IRIDA', '', 'RESPONSE MONITORING: Clinical & hematological', ] ty = cy - 18 for ln in lines_mgmt: bold = ln.endswith(':') or ln.startswith('ORAL') or ln.startswith('IV') or ln.startswith('POOR') or ln.startswith('ABS') or ln.startswith('RES') fn = 'Helvetica-Bold' if bold else 'Helvetica' write(cx+4, ty, ln, font=fn, size=6.3) ty -= 8.3 cy -= box_h + GAP # AOCD management box_h = 30 box(cx, cy - box_h, cw, box_h, fill=BOX_ORG) header_box(cx, cy - 14, cw, 14, 'AOCD MANAGEMENT', HDR_ORG) write(cx+4, cy - 22, 'Treat underlying cause ± IV Fe ± ESA (erythropoiesis-stimulating agents)', size=6.3) cy -= box_h + GAP # Oral Fe does NOT give occult blood test positive note box_h = 16 box(cx, cy - box_h, cw, box_h, fill=HexColor('#FDEDEC'), stroke_color=HDR_RED) write(cx+4, cy - 11, '⚠ Oral Fe does NOT give a positive occult blood test', font='Helvetica-Bold', size=6.5, color=HDR_RED) cy -= box_h + GAP # Thalassemia section box_h = 50 box(cx, cy - box_h, cw, box_h, fill=BOX_GREEN) header_box(cx, cy - 14, cw, 14, 'THALASSEMIA INTRO', HDR_GREEN) lines_thal2 = [ ' Pathophys: Chain imbalance (relative excess of normal chains)', ' Trait: Heterozygous – mild microcytosis, ↑ RBC count, ↑ HbA2', ' Abnormal electrophoresis distinguishes from IDA/AOCD', ] ty = cy - 18 for ln in lines_thal2: write(cx+4, ty, ln, size=6.3) ty -= 9 cy -= box_h + GAP # Remaining space: embed the Im0 diagram from page 1 if it fits remaining = cy - BOT if remaining > 40: box(cx, cy - remaining, cw, remaining, fill=HexColor('#F8F9FA'), stroke_color=BORDER) write(cx+4, cy - 11, '✎ Your Notes (Page 2 corner)', font='Helvetica-BoldOblique', size=7, color=HexColor('#D68910')) try: embed_image('/home/daytona/workspace/anemia-v2/assets/handwriting_p2.png', cx+4, BOT + 4, cw - 8, remaining - 18) except: pass # ── Divider lines between columns ───────────────────────────────────────────── for cx_d in col_x[1:]: c.setStrokeColor(HexColor('#BDC3C7')) c.setLineWidth(0.5) c.setDash(3, 3) c.line(cx_d - GAP/2, BOT + 2, cx_d - GAP/2, TOP) c.setDash() # ── Footer ──────────────────────────────────────────────────────────────────── c.setFillColor(HexColor('#BDC3C7')) c.setFont('Helvetica', 5.5) c.drawCentredString(W/2, 2, 'Approach to Anemia – Part 1 & 2 | All content + handwritten notes preserved') c.save() print("Done! Saved: /home/daytona/workspace/anemia-v2/Anemia_Flowchart.pdf") import os sz = os.path.getsize('/home/daytona/workspace/anemia-v2/Anemia_Flowchart.pdf') print(f"File size: {sz/1024:.1f} KB") PYEOF
python3 << 'EOF' # Check if handwriting images are valid from PIL import Image for p in [ '/home/daytona/workspace/anemia-v2/assets/handwriting_p1.png', '/home/daytona/workspace/anemia-v2/assets/handwriting_p2.png', '/home/daytona/workspace/anemia-v2/assets/diagram_p1.png', ]: img = Image.open(p) print(f"{p.split('/')[-1]}: {img.size}, mode={img.mode}") # Save a small preview to check content img.thumbnail((300, 300)) img.save(p.replace('.png','_thumb.png')) print(f" Thumbnail saved") EOF
python3 << 'PYEOF' # The issue: ImageReader from PIL Image object may not work reliably # Fix: pass file path directly, and also ensure images are saved as JPEG for embedding from PIL import Image import os # Convert images to JPEG for reliable embedding for name, src in [ ('hw1', '/home/daytona/workspace/anemia-v2/assets/handwriting_p1.png'), ('hw2', '/home/daytona/workspace/anemia-v2/assets/handwriting_p2.png'), ('diag1', '/home/daytona/workspace/anemia-v2/assets/diagram_p1.png'), ]: img = Image.open(src).convert('RGB') dst = f'/home/daytona/workspace/anemia-v2/assets/{name}.jpg' img.save(dst, 'JPEG', quality=85) print(f"Saved {dst}: {os.path.getsize(dst)//1024}KB, size={img.size}") PYEOF
python3 << 'EOF' from PIL import Image import numpy as np for name, path in [ ('hw1', '/home/daytona/workspace/anemia-v2/assets/hw1.jpg'), ('hw2', '/home/daytona/workspace/anemia-v2/assets/hw2.jpg'), ]: img = Image.open(path).convert('RGB') arr = np.array(img) # Check how many non-white pixels (< 240 in any channel) non_white = np.sum(np.any(arr < 200, axis=2)) total = arr.shape[0] * arr.shape[1] print(f"{name}: {img.size}, non-white pixels: {non_white}/{total} ({100*non_white/total:.1f}%)") print(f" mean RGB: {arr.mean(axis=(0,1))}") print(f" min values: {arr.min(axis=(0,1))}") EOF
python3 << 'EOF' # The FXX1 image is the actual handwriting. Let me check those directly from PIL import Image import numpy as np for name, path in [ ('p1_img0', '/home/daytona/workspace/anemia-v2/assets/p1_img0.png'), ('p1_img1', '/home/daytona/workspace/anemia-v2/assets/p1_img1.png'), ('p1_img2', '/home/daytona/workspace/anemia-v2/assets/p1_img2.png'), ('p2_img0', '/home/daytona/workspace/anemia-v2/assets/p2_img0.png'), ('p2_img1', '/home/daytona/workspace/anemia-v2/assets/p2_img1.png'), ('p2_img2', '/home/daytona/workspace/anemia-v2/assets/p2_img2.jpg'), ]: img = Image.open(path).convert('RGBA') arr = np.array(img) # Non-transparent, non-white pixels non_white = np.sum(np.any(arr[:,:,:3] < 200, axis=2)) total = arr.shape[0] * arr.shape[1] print(f"{name}: {img.size}, non-white/transparent: {non_white}/{total} ({100*non_white/total:.1f}%) mean={arr[:,:,:3].mean(axis=(0,1)).round(1)}") EOF
python3 << 'PYEOF' from PIL import Image import numpy as np, os # p1_img0 is the handwriting (dark background, text/writing on it) img = Image.open('/home/daytona/workspace/anemia-v2/assets/p1_img0.png').convert('RGB') img.save('/home/daytona/workspace/anemia-v2/assets/hw_p1_real.jpg', 'JPEG', quality=88) print(f"hw_p1_real.jpg: {img.size}, {os.path.getsize('/home/daytona/workspace/anemia-v2/assets/hw_p1_real.jpg')//1024}KB") # p1_img2 is the diagram (extravascular/intravascular table) img2 = Image.open('/home/daytona/workspace/anemia-v2/assets/p1_img2.png').convert('RGB') img2.save('/home/daytona/workspace/anemia-v2/assets/diag_p1_real.jpg', 'JPEG', quality=88) print(f"diag_p1_real.jpg: {img2.size}, {os.path.getsize('/home/daytona/workspace/anemia-v2/assets/diag_p1_real.jpg')//1024}KB") # p2_img0 is the diff table area img3 = Image.open('/home/daytona/workspace/anemia-v2/assets/p2_img0.png').convert('RGB') img3.save('/home/daytona/workspace/anemia-v2/assets/hw_p2_real.jpg', 'JPEG', quality=88) print(f"hw_p2_real.jpg: {img3.size}, {os.path.getsize('/home/daytona/workspace/anemia-v2/assets/hw_p2_real.jpg')//1024}KB") # p2_img2 small blue image img4 = Image.open('/home/daytona/workspace/anemia-v2/assets/p2_img2.jpg').convert('RGB') img4.save('/home/daytona/workspace/anemia-v2/assets/stamp_p2.jpg', 'JPEG', quality=88) print(f"stamp_p2.jpg: {img4.size}, {os.path.getsize('/home/daytona/workspace/anemia-v2/assets/stamp_p2.jpg')//1024}KB") PYEOF
python3 << 'PYEOF' from reportlab.lib.pagesizes import A3, landscape from reportlab.pdfgen import canvas from reportlab.lib.utils import ImageReader from reportlab.lib import colors from reportlab.lib.colors import HexColor from PIL import Image import os W, H = landscape(A3) c = canvas.Canvas('/home/daytona/workspace/anemia-v2/Anemia_Flowchart.pdf', pagesize=(W, H)) c.setTitle("Anemia – Pages 1 & 2 Master Sheet") BG = HexColor('#F4F6F9') TITLE_BG = HexColor('#1A3A5C') BOX_BLUE = HexColor('#D6EAF8') BOX_BLUE2 = HexColor('#AED6F1') BOX_RED = HexColor('#FADBD8') BOX_GREEN = HexColor('#D5F5E3') BOX_ORG = HexColor('#FDEBD0') BOX_PURP = HexColor('#E8DAEF') BOX_TEAL = HexColor('#D1F2EB') HDR_BLUE = HexColor('#1A5276') HDR_RED = HexColor('#C0392B') HDR_GREEN = HexColor('#1E8449') HDR_ORG = HexColor('#D35400') HDR_PURP = HexColor('#6C3483') HDR_TEAL = HexColor('#0E6655') BORDER = HexColor('#BDC3C7') TEXT_D = HexColor('#17202A') HAND_BG = HexColor('#FFFDE7') HAND_BDR = HexColor('#F39C12') c.setFillColor(BG) c.rect(0, 0, W, H, fill=1, stroke=0) def box(x, y, w, h, fill=BOX_BLUE, sc=None, r=3): sc = sc or BORDER c.setFillColor(fill); c.setStrokeColor(sc); c.setLineWidth(0.5) c.roundRect(x, y, w, h, r, fill=1, stroke=1) def hdr(x, y, w, h, text, fill, fg=colors.white, fs=8): c.setFillColor(fill); c.setStrokeColor(fill) c.roundRect(x, y, w, h, 2, fill=1, stroke=0) c.setFillColor(fg); c.setFont('Helvetica-Bold', fs) c.drawCentredString(x+w/2, y+h/2-fs/3, text) def txt(x, y, t, font='Helvetica', sz=6.2, col=TEXT_D, align='left'): c.setFont(font, sz); c.setFillColor(col) if align=='center': c.drawCentredString(x, y, t) else: c.drawString(x, y, t) def img_embed(path, x, y, mw, mh): try: im = Image.open(path).convert('RGB') iw, ih = im.size sc = min(mw/iw, mh/ih) dw, dh = iw*sc, ih*sc c.drawImage(ImageReader(im), x+(mw-dw)/2, y+(mh-dh)/2, width=dw, height=dh, preserveAspectRatio=True) return dw, dh except Exception as e: print(f"img_embed error {path}: {e}"); return 0,0 # ── TITLE ───────────────────────────────────────────────────────────────────── c.setFillColor(TITLE_BG) c.rect(0, H-28, W, 28, fill=1, stroke=0) txt(W/2, H-19, 'APPROACH TO ANEMIA | Pages 1 & 2 – Complete Study Sheet', font='Helvetica-Bold', sz=12, col=colors.white, align='center') TOP = H - 31; BOT = 4; M = 5; GAP = 5 # 4-column layout # A=208 | B=230 | C=396 | D=346 total≈1185 ≈ W-2*M=1181 cws = [208, 230, 396, 342] cxs = [M]; [cxs.append(cxs[-1]+cws[i]+GAP) for i in range(3)] # ═══ COLUMN A ════════════════════════════════════════════════════════════════ ax, aw = cxs[0], cws[0]; ay = TOP # Handwriting Panel 1 ────────────────────────────────────────────────────── hw1_h = 100 box(ax, ay-hw1_h, aw, hw1_h, fill=HAND_BG, sc=HAND_BDR) txt(ax+3, ay-10, '✎ Handwritten Notes (Page 1 corner)', font='Helvetica-BoldOblique', sz=7, col=HexColor('#B7770D')) img_embed('/home/daytona/workspace/anemia-v2/assets/hw_p1_real.jpg', ax+3, ay-hw1_h+3, aw-6, hw1_h-16) ay -= hw1_h + GAP # Key Definitions ──────────────────────────────────────────────────────────── dh = 78 box(ax, ay-dh, aw, dh, fill=BOX_BLUE) hdr(ax, ay-13, aw, 13, 'KEY DEFINITIONS', HDR_BLUE) defs = [ '• Anemia = Decreased RBC mass', '• Abs retic = retic(lab) × pt Hct / Nl Hct', '• Reticulocyte Index = Abs retic ÷ MF', ' MF: >35% → 1 | 25-35% → 1.5', ' 20-25% → 2 | <20% → 2.5', '• RI < 2 → Poor BM response', '• RI > 2 → Good BM response', ] ty = ay-17 for d in defs: txt(ax+3, ty, d, sz=6.1); ty -= 8.4 ay -= dh + GAP # Microcytic ───────────────────────────────────────────────────────────────── mh = 105 box(ax, ay-mh, aw, mh, fill=BOX_RED) hdr(ax, ay-13, aw, 13, 'MICROCYTIC ANEMIA', HDR_RED) mics = [ 'Defect → ↓ Hgb synthesis', 'GLOBIN → Thalassemia', 'HEME → Sideroblastic anemia', ' IDA | AOCD', '', 'Leukoerythroblastic picture:', '• Dacrocytes • Nucleated RBCs', '• Immature WBCs • Hepatosplenomeg.', 'Hyperseg. PMN (>6 lobes / >5%→>5 lobes)', ] ty = ay-17 for m in mics: txt(ax+3, ty, m, sz=6.1); ty -= 8.5 ay -= mh + GAP # Drugs → Megaloblastic ────────────────────────────────────────────────────── drug_h = 55 box(ax, ay-drug_h, aw, drug_h, fill=BOX_PURP) hdr(ax, ay-13, aw, 13, 'DRUGS → MEGALOBLASTIC ANEMIA', HDR_PURP) drugs = [ '• Anti-cancer drugs • Anti-epileptics', '• Folate antagonists • ART', '• Biguanides • Nitrous Oxide', ] ty = ay-18 for d in drugs: txt(ax+3, ty, d, sz=6.3); ty -= 9 ay -= drug_h + GAP # ═══ COLUMN B ════════════════════════════════════════════════════════════════ bx, bw = cxs[1], cws[1]; by = TOP # Normocytic ────────────────────────────────────────────────────────────────── nh = 44 box(bx, by-nh, bw, nh, fill=BOX_TEAL) hdr(bx, by-13, bw, 13, 'NORMOCYTIC ANEMIA', HDR_TEAL) for ln in ['Recent Blood Loss → Normal LDH', 'Hemolytic Anemia → Elevated LDH']: txt(bx+3, by-17, ln, sz=6.3); by -= 8 by -= nh - (TOP - by) + GAP + 5 # Reset by properly by = TOP - nh - GAP # Hemolysis EV vs IV ───────────────────────────────────────────────────────── hh2 = 148 box(bx, by-hh2, bw, hh2, fill=BOX_BLUE) hdr(bx, by-13, bw, 13, 'HEMOLYSIS: EV vs IV', HDR_BLUE) hw2 = (bw-8)//2 # EV header c.setFillColor(HexColor('#D6EAF8')); c.setStrokeColor(BORDER); c.setLineWidth(0.4) c.roundRect(bx+3, by-25, hw2-1, 11, 2, fill=1, stroke=1) txt(bx+3+hw2/2, by-22, 'Extravascular', font='Helvetica-Bold', sz=6, col=HDR_BLUE, align='center') # IV header c.setFillColor(HexColor('#FADBD8')); c.roundRect(bx+3+hw2+2, by-25, hw2-1, 11, 2, fill=1, stroke=1) txt(bx+3+hw2+2+hw2/2, by-22, 'Intravascular', font='Helvetica-Bold', sz=6, col=HDR_RED, align='center') ev_list = ['Spherocytes ↑↑', 'Splenomegaly', 'Bilirubin ↑, Gallstones', '(Haptoglobin normal', ' or mildly ↓)'] iv_list = ['Reduced Haptoglobin', 'Hemosiderinuria (chr.)', 'CoHb levels ↑', 'Hemoglobinuria', 'Free Hgb in plasma'] ty = by-29 for e, iv in zip(ev_list, iv_list): txt(bx+4, ty, e, sz=5.9); txt(bx+4+hw2+2, ty, iv, sz=5.9, col=HDR_RED); ty -= 9 # Diagram from page 1 img_embed('/home/daytona/workspace/anemia-v2/assets/diag_p1_real.jpg', bx+3, by-hh2+3, bw-6, 28) by -= hh2 + GAP # Macrocytic ───────────────────────────────────────────────────────────────── mach = 62 box(bx, by-mach, bw, mach, fill=BOX_ORG) hdr(bx, by-13, bw, 13, 'MACROCYTIC ANEMIA', HDR_ORG) macs = ['B12/Folate deficiency → Megaloblastic:',' • Hyperseg. neutrophils • Oval macrocytes', ' • ↑MMA (B12 def only)', 'Liver dis./Hypothyroid → Non-megaloblastic'] ty = by-17 for m in macs: txt(bx+3, ty, m, sz=6.1); ty -= 9 by -= mach + GAP # Thalassemia ──────────────────────────────────────────────────────────────── thalh = 60 box(bx, by-thalh, bw, thalh, fill=BOX_GREEN) hdr(bx, by-13, bw, 13, 'THALASSEMIA', HDR_GREEN) thals = ['Pathophys: Chain imbalance','(↑ relative excess normal chains)', 'α-thal: ↓ alpha (deletion)', 'β-thal: ↓ beta (mutation)', 'Trait: mild microcytosis, ↑ RBC, ↑HbA2'] ty = by-17 for t in thals: txt(bx+3, ty, t, sz=6.1); ty -= 9 by -= thalh + GAP # Handwriting Page 2 ───────────────────────────────────────────────────────── remaining = by - BOT if remaining > 40: box(bx, BOT, bw, remaining, fill=HAND_BG, sc=HAND_BDR) txt(bx+3, by-10, '✎ Handwritten Notes (Page 2)', font='Helvetica-BoldOblique', sz=7, col=HexColor('#B7770D')) img_embed('/home/daytona/workspace/anemia-v2/assets/hw_p2_real.jpg', bx+3, BOT+3, bw-6, remaining-16) # ═══ COLUMN C – DIFFERENTIAL TABLE ══════════════════════════════════════════ cx2, cw2 = cxs[2], cws[2]; cy2 = TOP table_h = TOP - BOT box(cx2, BOT, cw2, table_h, fill=colors.white) hdr(cx2, cy2-15, cw2, 15, 'DIFFERENTIAL DIAGNOSIS – MICROCYTIC ANEMIAS', HDR_BLUE, fs=9) cols = ['', 'IDA', 'AOCD', 'Thalassemia Trait', 'Sideroblastic (SA)'] raw_cw = [88, 66, 76, 90, 96]; total = sum(raw_cw) scaled_cw = [w*(cw2-6)/total for w in raw_cw] rows = [ ('Etiology', 'Blood loss\n↓ supply/↑ demand', 'Autoimmune, infect.\nHIV, malignancy', 'Heterozygous\nthalassemia', 'X-linked (ALAS2)\nIdiopathic, MDS-RARS\nalcohol, Pb, INH, Cu↓'), ('RBC/retic', '↓ (MI > 13)', '↓', '↑ (MI < 13)', '↓'), ('RDW', '↑', 'Normal', 'Normal', '↑'), ('Fe indices', '↓Fe ↓Ferritin\n↑sTfR ↑TIBC\nTSAT <18%\nsTfR/logFer >2\n↓Hepcidin', '↓Fe ↑Ferritin\nNl sTfR ↓TIBC\nTSAT >18%\nsTfR/logFer <1\n↑Hepcidin', 'Normal Fe indices', '↑Fe ↑TSAT ↑Ferritin\nsTfR & TIBC normal'), ('FEP', '↑', '↑', 'Normal', '↑'), ('BM Fe stores', '– (absent)', '+ (present)', '+ (present)', '+ (present)'), ('Electrophoresis', 'Normal', 'Normal', 'Abnormal\n(↑HbA2/HbF)', 'Normal'), ('Others', '', '↑CRP/ESR', '±Basophilic\nstippling', '±Basophilic\nstippling & RS'), ('Rx', 'Fe replacement\n(oral/IV)', 'Rx underlying cause\n± IV Fe ± ESA', 'No specific Rx', 'Rx reversible causes\n±Pyridoxine\n±Chelation'), ] row_fills = [BOX_BLUE2,BOX_BLUE,BOX_BLUE,BOX_BLUE2,BOX_BLUE,BOX_RED,BOX_BLUE2,BOX_BLUE,BOX_GREEN] ty = cy2 - 17 col_hdrs_fill = [HDR_BLUE]*5 # header row hx = cx2+3 for i,(lbl,cw3) in enumerate(zip(cols,scaled_cw)): box(hx, ty-13, cw3-1, 13, fill=HexColor('#1A5276'), sc=HexColor('#1A5276')) txt(hx+cw3/2, ty-10, lbl, font='Helvetica-Bold', sz=6.5, col=colors.white, align='center') hx += cw3 ty -= 14 for row, rfill in zip(rows, row_fills): max_l = max(len(cell.split('\n')) for cell in row) rh = max(13, max_l*8.5 + 4) hx = cx2+3 for i,(cell,cw3) in enumerate(zip(row,scaled_cw)): fc = HexColor('#EBF5FB') if i==0 else rfill box(hx, ty-rh, cw3-1, rh, fill=fc, sc=BORDER) cell_lines = cell.split('\n') line_y = ty-5 for cl in cell_lines: fn = 'Helvetica-Bold' if i==0 else 'Helvetica' cl_col = HDR_BLUE if i==0 else TEXT_D txt(hx+2, line_y, cl, font=fn, sz=5.9, col=cl_col) line_y -= 8 hx += cw3 ty -= rh+1 # ═══ COLUMN D – MANAGEMENT ═══════════════════════════════════════════════════ dx, dw = cxs[3], cws[3]; dy = TOP # IDA management idah = 155 box(dx, dy-idah, dw, idah, fill=BOX_BLUE) hdr(dx, dy-14, dw, 14, 'IDA – MANAGEMENT', HDR_BLUE) mgmt_lines = [ ('ORAL Fe:', True), (' Recommended: 200 mg elemental Fe/day', False), (' Duration: ~6 wks correct Hb; ~6 mo replete stores', False), (' Oral Fe does NOT give occult blood ⊕', False), (' Fe Gluconate – 12% elemental iron', False), (' Fe Sulphate – 20% elemental iron', False), (' Fe Fumarate – 35% elemental iron ← highest', False), (' Best taken: empty stomach or 2h after meal', False), ('POOR RESPONSE (Hb ↑ <2g/dL in 3 wks):', True), (' Non-compliance | Ongoing bleed | Malabsorption', False), (' Wrong diagnosis | Mixed deficiency', False), ('ABSORPTION INHIBITORS:', True), (' Ca, PPIs/H2RA, phytates, phosphates, tannates', False), ('IV Fe INDICATIONS:', True), (' Oral intolerance | Malabsorption | Pre-ESA', False), (' CKD on HD | Cancer | CHF | IRIDA', False), ('RESPONSE: Clinical & hematological', True), ] ty = dy-18 for ln, bold in mgmt_lines: fn = 'Helvetica-Bold' if bold else 'Helvetica' col = HDR_BLUE if bold else TEXT_D txt(dx+3, ty, ln, font=fn, sz=6.2, col=col); ty -= 8.2 dy -= idah + GAP # AOCD aocdh = 26 box(dx, dy-aocdh, dw, aocdh, fill=BOX_ORG) hdr(dx, dy-12, dw, 12, 'AOCD – MANAGEMENT', HDR_ORG) txt(dx+3, dy-22, 'Treat underlying cause ± IV Fe ± ESA', sz=6.3) dy -= aocdh + GAP # Warning box warnh = 15 box(dx, dy-warnh, dw, warnh, fill=HexColor('#FDEDEC'), sc=HDR_RED) txt(dx+3, dy-11, '⚠ Oral Fe does NOT cause occult blood ⊕ (important exam point!)', font='Helvetica-Bold', sz=6.3, col=HDR_RED) dy -= warnh + GAP # Thalassemia intro thalh2 = 52 box(dx, dy-thalh2, dw, thalh2, fill=BOX_GREEN) hdr(dx, dy-12, dw, 12, 'THALASSEMIA – INTRO', HDR_GREEN) thls = [ 'Pathophysiology: Chain imbalance', ' → relative excess of normal chains', ' → ineffective erythropoiesis + hemolysis', 'Abnormal electrophoresis → ↑HbA2 / ↑HbF', ] ty = dy-16 for t in thls: txt(dx+3, ty, t, sz=6.1); ty -= 9 dy -= thalh2 + GAP # Stamp / page 2 image remaining = dy - BOT if remaining > 30: box(dx, BOT, dw, remaining, fill=HAND_BG, sc=HAND_BDR) txt(dx+3, dy-10, '✎ Page 2 Notes', font='Helvetica-BoldOblique', sz=7, col=HexColor('#B7770D')) img_embed('/home/daytona/workspace/anemia-v2/assets/stamp_p2.jpg', dx+3, BOT+3, dw-6, remaining-16) # Dividers for x_d in cxs[1:]: c.setStrokeColor(HexColor('#C8D0D8')); c.setLineWidth(0.5); c.setDash(2,3) c.line(x_d-GAP//2, BOT+2, x_d-GAP//2, TOP) c.setDash() # Footer c.setFillColor(HexColor('#95A5A6')); c.setFont('Helvetica', 5.5) c.drawCentredString(W/2, 1.5, 'Approach to Anemia – Pages 1 & 2 | All text + handwritten notes included') c.save() sz = os.path.getsize('/home/daytona/workspace/anemia-v2/Anemia_Flowchart.pdf') print(f"Saved! {sz/1024:.0f} KB") PYEOF
Anemia Flowchart
PDF Document · PDF
| Column | Content |
|---|---|
| A (Left) | Your handwriting (Page 1 corner) + Key Definitions + Microcytic causes + Drugs → Megaloblastic |
| B | Normocytic overview + Extravascular vs Intravascular hemolysis table + Macrocytic + Thalassemia pathophys + Your handwriting (Page 2) |
| C (Centre) | Full colour-coded differential diagnosis table (IDA vs AOCD vs Thalassemia vs SA) - all rows including Fe indices, FEP, BM stores, electrophoresis, Rx |
| D (Right) | Complete IDA management (oral Fe types, poor response criteria, absorption inhibitors, IV Fe indications) + AOCD + Thalassemia intro + Page 2 image |