Write a 30 marks answer for Postgraduate Anaesthesia exam on the topic of coagulation cascade and thromboelastography
thromboelastography coagulation monitoring anaesthesia
PMID: 42145275

| Inhibitor | Mechanism |
|---|---|
| Antithrombin III (ATIII) | Serine protease inhibitor inactivating thrombin, FXa, FIXa, FXIa, FXIIa. Heparin binds ATIII, inducing a conformational change that accelerates its activity ~1000-fold. Physiologically potentiated by heparan sulphate on endothelial surfaces |
| Tissue Factor Pathway Inhibitor (TFPI) | Directly inhibits the TF:FVIIa:FXa complex, limiting initiation phase. Produced by endothelium |
| Protein C / Protein S system | Thrombin bound to thrombomodulin (expressed on intact endothelium) activates Protein C. Activated Protein C (APC) + Protein S (cofactor) inactivate FVa and FVIIIa, shutting down the propagation phase |
| Prostacyclin (PGI2) and Nitric Oxide | Released by intact endothelium; inhibit platelet aggregation and cause vasodilatation |

| Parameter | Definition | Normal Range | Clinical Significance |
|---|---|---|---|
| R time (Reaction time) | Time from sample placement to first clot detection (2mm amplitude) | 5-10 min | Prolonged: coagulation factor deficiency, anticoagulants (heparin, warfarin, DOACs). Shortened: hypercoagulable state |
| K time (Kinetics) | Time from R-time to 20mm amplitude; clot formation rate | 1-3 min | Prolonged: fibrinogen deficiency, thrombocytopaenia. Reflects fibrinogen and early platelet activity |
| Alpha angle (α) | Angle of tangent to the curve at 2mm; rate of fibrin accumulation | 53-72° | Reduced: fibrinogen deficiency, hypofibrinogenaemia. Increased: hypercoagulability. Guides cryoprecipitate use |
| Maximum Amplitude (MA) | Greatest vertical width; reflects clot strength | 50-70 mm | Reduced: platelet dysfunction or thrombocytopaenia (platelets contribute ~80% of clot strength, fibrinogen ~20%). Guides platelet transfusion |
| LY30 (Lysis at 30 min) | % reduction in amplitude 30 minutes after MA | <7.5% | Elevated (>7.5-8%): hyperfibrinolysis. Guides tranexamic acid / aminocaproic acid use |
| EPL (Estimated Percent Lysis) | Predicted lysis before 30 min | <15% | Similar clinical use to LY30 |
| CI (Coagulation Index) | Composite algorithmic score | -3 to +3 | <-3: hypocoagulable; >+3: hypercoagulable |
| ROTEM Parameter | TEG Equivalent |
|---|---|
| CT (Clotting Time) | R time |
| CFT (Clot Formation Time) | K time |
| Alpha angle (α) | Alpha angle |
| MCF (Maximum Clot Firmness) | MA |
| LI30 / ML | LY30 |
| Feature | PT / aPTT / CBC | TEG / ROTEM |
|---|---|---|
| Sample | Plasma only | Whole blood (includes platelets and RBCs) |
| Condition | Static | Dynamic |
| Time | 45-90 min | 20-30 min (functional result) |
| Fibrinolysis detected | No (directly) | Yes |
| Platelet function | No | Yes (via MA / MCF) |
| Hypercoagulability | No | Yes |
| POC availability | Limited | Yes |
| Aspect | Key Points |
|---|---|
| Classical cascade | Extrinsic (TF-FVII) + Intrinsic (contact, FXII) → common pathway (FXa, prothrombin → thrombin → fibrin) |
| Cell-based model | Initiation (TF cells) → Amplification (platelets) → Propagation (platelet surface) |
| Thrombin | Central mediator: fibrinogen cleavage, FXIII activation, platelet activation (PAR-1), feedback activation of FV/FVIII/FXI |
| Anticoagulants | ATIII, TFPI, Protein C/S, PGI2/NO |
| Fibrinolysis | t-PA → plasmin → fibrin degradation; D-dimers as markers |
| TEG/ROTEM | Global viscoelastic assay: R/CT (factors) → K/CFT + alpha (fibrinogen) → MA/MCF (platelets) → LY30/LI30 (fibrinolysis) |
| Clinical use | Goal-directed transfusion in cardiac surgery, trauma, liver Tx, obstetrics |
| Evidence | Cochrane 2026 (35 RCTs): possible mortality reduction, reduced blood product use; very low certainty evidence |
Convert the above answer in a pdf
ls /home/daytona/workspace/ 2>/dev/null || mkdir -p /home/daytona/workspace
mkdir -p /home/daytona/workspace/coagulation-teg && python3 -c "from reportlab.lib.pagesizes import A4; print('reportlab ok')" && python3 -c "import requests; print('requests ok')"
~/coagulation-teg/build_pdf.py
#!/usr/bin/env python3
"""
Build a well-formatted PDF of the Coagulation Cascade & TEG exam answer.
Uses ReportLab Platypus for rich layout.
"""
import io
import os
import requests
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, Image, KeepTogether, PageBreak
)
from reportlab.platypus.tableofcontents import TableOfContents
from reportlab.lib.colors import HexColor
# ── Output path ────────────────────────────────────────────────────────────────
OUTPUT = "/home/daytona/workspace/coagulation-teg/Coagulation_Cascade_and_TEG_Exam_Answer.pdf"
# ── Colour palette ─────────────────────────────────────────────────────────────
NAVY = HexColor("#1a2e4a")
TEAL = HexColor("#0d6e7e")
LIGHT_BG = HexColor("#f0f6f8")
RULE_COL = HexColor("#0d6e7e")
TABLE_HDR = HexColor("#1a2e4a")
TABLE_ALT = HexColor("#e8f4f6")
WHITE = colors.white
BLACK = colors.black
GREY = HexColor("#555555")
ORANGE = HexColor("#c0392b")
# ── Page geometry ──────────────────────────────────────────────────────────────
PAGE_W, PAGE_H = A4
LEFT_M = RIGHT_M = 2.0 * cm
TOP_M = 2.2 * cm
BOT_M = 2.2 * cm
# ── Styles ─────────────────────────────────────────────────────────────────────
base = getSampleStyleSheet()
def make_style(name, parent="Normal", **kw):
return ParagraphStyle(name, parent=base[parent], **kw)
TITLE_STYLE = make_style("MainTitle",
fontSize=22, textColor=NAVY, spaceAfter=4,
alignment=TA_CENTER, fontName="Helvetica-Bold", leading=28)
SUBTITLE_STYLE = make_style("SubTitle",
fontSize=13, textColor=TEAL, spaceAfter=2,
alignment=TA_CENTER, fontName="Helvetica", leading=18)
META_STYLE = make_style("Meta",
fontSize=9, textColor=GREY, spaceAfter=14,
alignment=TA_CENTER, fontName="Helvetica-Oblique")
H1_STYLE = make_style("H1",
fontSize=14, textColor=WHITE, spaceAfter=6, spaceBefore=14,
fontName="Helvetica-Bold", leading=20)
H2_STYLE = make_style("H2",
fontSize=12, textColor=NAVY, spaceAfter=4, spaceBefore=10,
fontName="Helvetica-Bold", leading=16)
H3_STYLE = make_style("H3",
fontSize=10.5, textColor=TEAL, spaceAfter=3, spaceBefore=7,
fontName="Helvetica-Bold", leading=14, leftIndent=0)
BODY_STYLE = make_style("Body",
fontSize=10, textColor=BLACK, spaceAfter=5, spaceBefore=2,
fontName="Helvetica", leading=15, alignment=TA_JUSTIFY)
BULLET_STYLE = make_style("Bullet",
fontSize=10, textColor=BLACK, spaceAfter=3,
fontName="Helvetica", leading=14, leftIndent=14, bulletIndent=4)
CAPTION_STYLE = make_style("Caption",
fontSize=8.5, textColor=GREY, spaceAfter=8,
fontName="Helvetica-Oblique", leading=11, alignment=TA_CENTER)
REF_STYLE = make_style("Ref",
fontSize=8.5, textColor=GREY, spaceAfter=3,
fontName="Helvetica-Oblique", leading=12)
TABLE_HDR_STYLE = make_style("TblHdr",
fontSize=9, textColor=WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)
TABLE_CELL_STYLE = make_style("TblCell",
fontSize=9, textColor=BLACK, fontName="Helvetica", leading=12, alignment=TA_LEFT)
# ── Helper to download image ───────────────────────────────────────────────────
def fetch_img(url, width_cm=14):
try:
r = requests.get(url, timeout=15)
r.raise_for_status()
buf = io.BytesIO(r.content)
img = Image(buf)
aspect = img.imageHeight / float(img.imageWidth)
w = width_cm * cm
img.drawWidth = w
img.drawHeight = w * aspect
return img
except Exception as e:
print(f" [warn] Could not fetch image: {url} — {e}")
return None
# ── Section header with coloured band ─────────────────────────────────────────
def section_header(story, number, title):
tbl = Table([[Paragraph(f"{number}. {title}", H1_STYLE)]],
colWidths=[PAGE_W - LEFT_M - RIGHT_M])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), NAVY),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("ROUNDEDCORNERS", [4]),
]))
story.append(Spacer(1, 8))
story.append(tbl)
story.append(Spacer(1, 6))
# ── Styled table builder ───────────────────────────────────────────────────────
def build_table(headers, rows, col_widths=None):
avail = PAGE_W - LEFT_M - RIGHT_M
if col_widths is None:
n = len(headers)
col_widths = [avail / n] * n
def cell(txt, is_hdr=False):
s = TABLE_HDR_STYLE if is_hdr else TABLE_CELL_STYLE
return Paragraph(str(txt), s)
data = [[cell(h, True) for h in headers]]
for i, row in enumerate(rows):
data.append([cell(c) for c in row])
ts = TableStyle([
("BACKGROUND", (0,0), (-1,0), TABLE_HDR),
("TEXTCOLOR", (0,0), (-1,0), WHITE),
("ROWBACKGROUNDS",(0,1), (-1,-1), [WHITE, TABLE_ALT]),
("GRID", (0,0), (-1,-1), 0.5, HexColor("#cccccc")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 7),
("RIGHTPADDING", (0,0), (-1,-1), 7),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
])
t = Table(data, colWidths=col_widths, repeatRows=1)
t.setStyle(ts)
return t
# ── Page callbacks ─────────────────────────────────────────────────────────────
def header_footer(canvas, doc):
canvas.saveState()
w, h = A4
# Header bar
canvas.setFillColor(NAVY)
canvas.rect(LEFT_M, h - TOP_M + 0.3*cm, w - LEFT_M - RIGHT_M, 0.35*cm, fill=1, stroke=0)
canvas.setFont("Helvetica-Bold", 8)
canvas.setFillColor(WHITE)
canvas.drawString(LEFT_M + 4, h - TOP_M + 0.42*cm,
"Postgraduate Anaesthesia Examination")
canvas.setFont("Helvetica", 8)
canvas.drawRightString(w - RIGHT_M - 4, h - TOP_M + 0.42*cm,
"Coagulation Cascade & Thromboelastography")
# Footer
canvas.setFillColor(GREY)
canvas.setFont("Helvetica", 8)
canvas.drawString(LEFT_M, BOT_M - 0.5*cm, "Orris Medical AI | July 2026")
canvas.drawRightString(w - RIGHT_M, BOT_M - 0.5*cm, f"Page {doc.page}")
canvas.setStrokeColor(RULE_COL)
canvas.setLineWidth(0.5)
canvas.line(LEFT_M, BOT_M - 0.3*cm, w - RIGHT_M, BOT_M - 0.3*cm)
canvas.restoreState()
# ══════════════════════════════════════════════════════════════════════════════
# BUILD DOCUMENT
# ══════════════════════════════════════════════════════════════════════════════
def build():
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
leftMargin=LEFT_M, rightMargin=RIGHT_M,
topMargin=TOP_M, bottomMargin=BOT_M,
title="Coagulation Cascade and Thromboelastography",
author="Orris Medical AI",
subject="Postgraduate Anaesthesia Examination Answer"
)
story = []
# ── Cover block ────────────────────────────────────────────────────────────
story.append(Spacer(1, 1.2*cm))
story.append(Paragraph("Coagulation Cascade and", TITLE_STYLE))
story.append(Paragraph("Thromboelastography", TITLE_STYLE))
story.append(Spacer(1, 0.3*cm))
story.append(HRFlowable(width="100%", thickness=2, color=TEAL, spaceAfter=8))
story.append(Paragraph("Postgraduate Anaesthesia Examination | 30 Marks", SUBTITLE_STYLE))
story.append(Spacer(1, 0.2*cm))
story.append(Paragraph(
"Sources: Robbins Pathologic Basis of Disease · Harrison's Principles of Internal Medicine 22E · "
"Sabiston Textbook of Surgery · Morgan & Mikhail's Clinical Anesthesiology 7e · "
"Schwartz's Principles of Surgery 11e · Rockwood & Green's Fractures 10e · "
"Goldman-Cecil Medicine · Cochrane Database Syst Rev 2026 [PMID: 42145275]",
META_STYLE))
story.append(HRFlowable(width="100%", thickness=1, color=TEAL, spaceAfter=12))
# ══ SECTION 1 ══════════════════════════════════════════════════════════════
section_header(story, 1, "Introduction (2 marks)")
story.append(Paragraph(
"Haemostasis is a tightly regulated physiological process that arrests bleeding while maintaining "
"vascular patency. It integrates three overlapping phases: <b>primary haemostasis</b> (platelet plug "
"formation), <b>secondary haemostasis</b> (the coagulation cascade generating fibrin), and "
"<b>fibrinolysis</b> (clot dissolution). Understanding the cascade and its point-of-care assessment "
"with thromboelastography (TEG) and rotational thromboelastometry (ROTEM) is fundamental to "
"perioperative and critical care anaesthetic practice.", BODY_STYLE))
# ══ SECTION 2 ══════════════════════════════════════════════════════════════
section_header(story, 2, "The Coagulation Cascade (12 marks)")
# 2.1
story.append(Paragraph("2.1 Classical (Waterfall) Model", H2_STYLE))
story.append(Paragraph(
"The classical model, developed in the 1960s, divides coagulation into the <b>extrinsic pathway</b>, "
"the <b>intrinsic pathway</b>, and a <b>common pathway</b>. The cascade is a series of amplifying "
"enzymatic reactions leading to deposition of an insoluble fibrin clot. Each step involves an "
"<b>enzyme</b> (activated coagulation factor), a <b>substrate</b> (inactive proenzyme), and a "
"<b>cofactor</b> (reaction accelerator), assembled on negatively charged phospholipid surfaces "
"provided by activated platelets. Calcium is required, binding to gamma-carboxylated glutamic acid "
"residues on factors II, VII, IX, and X — synthesised using <b>Vitamin K as cofactor</b> and "
"antagonised by coumarin anticoagulants.", BODY_STYLE))
# Insert cascade diagram
img1 = fetch_img(
"https://cdn.orris.care/cdss_images/39a84f124f8f24fe1ca25f86d1b73b95cac5832ac3fcbb3ef69e33afc7bb51d0.png",
width_cm=15)
if img1:
story.append(Spacer(1, 4))
story.append(img1)
story.append(Paragraph(
"Fig. 1 — Coagulation cascade: laboratory (intrinsic/extrinsic pathways) vs. in vivo "
"(tissue factor-driven). Red = inactive factors, Blue = active factors, Green = cofactors. "
"(Robbins Pathologic Basis of Disease)", CAPTION_STYLE))
story.append(Paragraph("Extrinsic pathway (assessed by PT/INR):", H3_STYLE))
for b in [
"Tissue factor (TF), a subendothelial transmembrane glycoprotein constitutively expressed on fibroblasts and vascular smooth muscle cells, is exposed by vascular injury.",
"TF binds plasma FVII, activating it to FVIIa — the <b>TF:FVIIa extrinsic tenase complex</b>.",
"TF:FVIIa activates FX → FXa and FIX → FIXa.",
"The PT assay assesses factors VII, X, V, II (prothrombin), and fibrinogen."
]:
story.append(Paragraph(f"• {b}", BULLET_STYLE))
story.append(Paragraph("Intrinsic pathway (assessed by aPTT):", H3_STYLE))
for b in [
"Initiated in vitro by negatively charged surfaces activating FXII → FXIIa (Hageman factor).",
"FXIIa activates FXI → FXIa → FIX → FIXa.",
"FIXa + FVIIIa (intrinsic tenase complex on platelet surface) activates FX.",
"The aPTT assesses factors XII, XI, IX, VIII, X, V, II, and fibrinogen."
]:
story.append(Paragraph(f"• {b}", BULLET_STYLE))
story.append(Paragraph("Common pathway:", H3_STYLE))
for b in [
"FXa + FVa (prothrombinase complex, on platelet membrane + Ca²⁺) converts prothrombin (FII) → thrombin (FIIa).",
"Thrombin cleaves fibrinogen → fibrin monomers → polymerised insoluble fibrin.",
"Thrombin activates FXIII → FXIIIa, a transglutaminase that covalently cross-links fibrin (clot stabilisation).",
"Thrombin activates FV, FVIII, FXI (positive feedback amplification loops) and platelets via PAR-1.",
]:
story.append(Paragraph(f"• {b}", BULLET_STYLE))
story.append(Paragraph(
"<b>Limitation of the classical model:</b> FXII deficiency prolongs aPTT but does not cause bleeding; "
"FVIII/FIX (haemophilias A/B) deficiencies cause severe bleeding despite each affecting only one pathway. "
"This paradox is resolved by the cell-based model. <i>(Sabiston Textbook of Surgery; Harrison's 22E)</i>",
BODY_STYLE))
# 2.2
story.append(Paragraph("2.2 Cell-Based Model of Coagulation (Current Paradigm)", H2_STYLE))
story.append(Paragraph(
"The cell-based model, now the accepted physiological framework, emphasises overlapping interactions "
"between coagulation proteins and specific cell membranes. It proceeds in three phases:",
BODY_STYLE))
phases = [
("Phase 1 — Initiation\n(TF-bearing cells)",
"Vascular injury exposes subendothelial TF to plasma FVII, creating TF:FVIIa. This activates small amounts "
"of FX→FXa and FIX→FIXa. FXa + FVa (prothrombinase complex) generates trace thrombin — the trigger for "
"amplification. TFPI rapidly inhibits TF:FVIIa:FXa, limiting this phase."),
("Phase 2 — Amplification\n(Platelet surface)",
"Trace thrombin activates platelets (PAR-1/PAR-4), FV→FVa, FVIII→FVIIIa, and releases vWF. Platelets "
"adhere via GPIb to vWF and via GPIa/IIa or GPVI to collagen. Platelet outer membrane becomes net "
"negatively charged — the assembly platform for coagulation."),
("Phase 3 — Propagation\n(Activated platelet surface)",
"Intrinsic tenase (FIXa + FVIIIa) and prothrombinase (FXa + FVa) on platelets generate the thrombin burst "
"→ cleave fibrinogen → fibrin; activate FXIII → cross-linked fibrin; activate TAFI (thrombin activatable "
"fibrinolysis inhibitor); sustain platelet and factor activation."),
]
tbl_data = [[
Paragraph(p[0].replace("\n","<br/>"), ParagraphStyle("ph_h", fontName="Helvetica-Bold",
fontSize=9, textColor=WHITE, leading=12)),
Paragraph(p[1], TABLE_CELL_STYLE)
] for p in phases]
phase_table = Table(tbl_data, colWidths=[4.2*cm, 12.8*cm])
phase_table.setStyle(TableStyle([
("BACKGROUND", (0,0), (0,-1), TEAL),
("BACKGROUND", (1,0), (1,-1), WHITE),
("ROWBACKGROUNDS",(1,0),(1,-1),[WHITE, TABLE_ALT, WHITE]),
("GRID", (0,0), (-1,-1), 0.5, HexColor("#cccccc")),
("VALIGN", (0,0), (-1,-1), "TOP"),
("TOPPADDING", (0,0), (-1,-1), 7),
("BOTTOMPADDING",(0,0), (-1,-1), 7),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING", (0,0), (-1,-1), 8),
]))
story.append(phase_table)
story.append(Spacer(1, 6))
story.append(Paragraph(
"<i>(Schwartz's Principles of Surgery 11e; Rockwood & Green's Fractures in Adults 10e; "
"Sabiston Textbook of Surgery)</i>", REF_STYLE))
# 2.3 Anticoagulant mechanisms
story.append(Paragraph("2.3 Endogenous Anticoagulant Mechanisms", H2_STYLE))
story.append(Paragraph(
"Four major endogenous anticoagulant systems prevent unbounded clot propagation:", BODY_STYLE))
ac_headers = ["Inhibitor", "Mechanism"]
ac_rows = [
["Antithrombin III (ATIII)",
"Serine protease inhibitor inactivating thrombin, FXa, FIXa, FXIa, FXIIa. Heparin binds ATIII, "
"inducing a conformational change that accelerates activity ~1000-fold. Physiologically potentiated "
"by heparan sulphate on endothelial surfaces."],
["Tissue Factor Pathway\nInhibitor (TFPI)",
"Directly inhibits the TF:FVIIa:FXa complex, limiting the initiation phase. Produced by endothelium."],
["Protein C / Protein S",
"Thrombin bound to thrombomodulin (on intact endothelium) activates Protein C. Activated Protein C "
"(APC) + Protein S (cofactor) inactivate FVa and FVIIIa, shutting down propagation."],
["Prostacyclin (PGI₂)\n& Nitric Oxide (NO)",
"Released by intact endothelium; inhibit platelet aggregation and cause vasodilatation."],
]
story.append(build_table(ac_headers, ac_rows, col_widths=[5*cm, 12*cm]))
story.append(Spacer(1, 4))
story.append(Paragraph(
"<i>(Harrison's Principles of Internal Medicine 22E; Goldman-Cecil Medicine)</i>", REF_STYLE))
# 2.4 Fibrinolysis
story.append(Paragraph("2.4 Fibrinolysis", H2_STYLE))
for b in [
"t-PA (tissue plasminogen activator), synthesised by endothelium and most active when bound to fibrin, converts plasminogen → <b>plasmin</b>.",
"Plasmin degrades fibrin into fibrin degradation products (FDPs), notably <b>D-dimers</b> — a clinically useful marker of thrombus formation and lysis (DVT/PE screening, DIC diagnosis).",
"<b>Alpha-2-antiplasmin</b> rapidly inactivates free circulating plasmin.",
"<b>PAI-1</b> (plasminogen activator inhibitor-1) inhibits t-PA and uPA. In DIC, elevated PAI-1 suppresses normal fibrinolysis, worsening microvascular thrombosis.",
"FXII-dependent pathway also activates plasminogen (possibly explaining the paradox of FXII deficiency and thrombosis).",
]:
story.append(Paragraph(f"• {b}", BULLET_STYLE))
story.append(Paragraph(
"<i>(Robbins Pathologic Basis of Disease; Sabiston Textbook of Surgery)</i>", REF_STYLE))
# ══ SECTION 3 ══════════════════════════════════════════════════════════════
section_header(story, 3, "Thromboelastography (TEG) and ROTEM (12 marks)")
# 3.1 Principle
story.append(Paragraph("3.1 Principle and Technology", H2_STYLE))
story.append(Paragraph(
"TEG (Haemonetics) and ROTEM (Werfen) are <b>point-of-care viscoelastic haemostatic assays (VHAs)</b> "
"that measure the mechanical properties of whole blood as it clots. Unlike standard laboratory tests "
"(PT, aPTT, platelet count), which assess individual components in plasma under static conditions, "
"VHAs assess the <b>entire haemostatic process</b> — coagulation factor activity, platelet function, "
"fibrinogen contribution, clot strength, and fibrinolysis — simultaneously and in real time.",
BODY_STYLE))
story.append(Paragraph(
"In TEG, whole blood is placed in a heated cuvette (37 °C). A pin is suspended in the blood on a "
"torsion wire; the cuvette oscillates. As a clot forms and strengthens, increasing mechanical "
"resistance is transmitted to the pin and plotted as the characteristic thromboelastogram. In ROTEM, "
"the cuvette is stationary and the pin rotates — functionally equivalent but numerically distinct "
"and <b>not interchangeable</b>.",
BODY_STYLE))
story.append(Paragraph(
"<i>(Morgan & Mikhail's Clinical Anesthesiology 7e; Scott-Brown's Otorhinolaryngology Vol.1)</i>",
REF_STYLE))
# 3.2 Parameters
story.append(Paragraph("3.2 TEG Trace Parameters and Clinical Interpretation", H2_STYLE))
# Insert TEG diagram
img2 = fetch_img(
"https://cdn.orris.care/cdss_images/0b1425cf1a93207225bb92d1d44f5ea59473ea214e1210004b631d11c938aa87.png",
width_cm=13)
if img2:
story.append(img2)
story.append(Paragraph(
"Fig. 2 — Standard TEG trace. Enzymatic phase (R time) → fibrinogen-mediated clot formation "
"(K time, alpha angle) → platelet-dependent clot strength (MA) → fibrinolysis (LY30, EPL). "
"(Morgan & Mikhail's Clinical Anesthesiology 7e)", CAPTION_STYLE))
teg_headers = ["Parameter", "Definition", "Normal Range", "Clinical Significance"]
teg_rows = [
["R time\n(Reaction time)",
"Time from sample placement to first clot detection (2 mm amplitude)",
"5–10 min",
"Prolonged: factor deficiency, anticoagulants (heparin, warfarin, DOACs). Shortened: hypercoagulable state."],
["K time\n(Kinetics)",
"Time from R-time to 20 mm amplitude; rate of clot formation",
"1–3 min",
"Prolonged: fibrinogen deficiency, thrombocytopaenia. Guides FFP/cryoprecipitate."],
["Alpha angle (α)",
"Angle of tangent to the curve at 2 mm amplitude; rate of fibrin accumulation",
"53–72°",
"Reduced: fibrinogen deficiency. Increased: hypercoagulability. Guides cryoprecipitate/fibrinogen concentrate."],
["Maximum\nAmplitude (MA)",
"Greatest vertical width of trace; reflects clot strength",
"50–70 mm",
"Platelets contribute ~80%, fibrinogen ~20% of clot strength. Reduced: platelet dysfunction/thrombocytopaenia → platelet transfusion."],
["LY30\n(Lysis at 30 min)",
"% reduction in amplitude 30 min after MA",
"<7.5%",
"Elevated (>7.5–8%): hyperfibrinolysis → tranexamic acid or aminocaproic acid."],
["EPL\n(Estimated %\nLysis)",
"Predicted lysis before 30 min",
"<15%",
"Similar clinical significance to LY30; earlier signal."],
["CI\n(Coagulation\nIndex)",
"Composite algorithmic score",
"−3 to +3",
"<−3: hypocoagulable; >+3: hypercoagulable."],
]
avail = PAGE_W - LEFT_M - RIGHT_M
story.append(build_table(teg_headers, teg_rows,
col_widths=[2.8*cm, 4.2*cm, 2.4*cm, avail - 2.8*cm - 4.2*cm - 2.4*cm]))
story.append(Spacer(1, 4))
# ROTEM equivalents
story.append(Paragraph("ROTEM Equivalent Parameters:", H3_STYLE))
rotem_headers = ["TEG Parameter", "ROTEM Equivalent", "ROTEM Activator Used"]
rotem_rows = [
["R time", "CT (Clotting Time)", "EXTEM / INTEM"],
["K time", "CFT (Clot Formation Time)", "EXTEM / INTEM"],
["Alpha angle", "Alpha angle (α)", "EXTEM / FIBTEM"],
["MA", "MCF (Maximum Clot Firmness)", "EXTEM / INTEM / FIBTEM"],
["LY30", "LI30 / ML (Maximum Lysis)", "EXTEM"],
]
story.append(build_table(rotem_headers, rotem_rows))
story.append(Spacer(1, 4))
story.append(Paragraph(
"ROTEM uses specific reagents: <b>EXTEM</b> (tissue factor — extrinsic pathway), "
"<b>INTEM</b> (ellagic acid — intrinsic pathway), <b>FIBTEM</b> (extrinsic + cytochalasin D platelet "
"inhibitor — isolates fibrinogen contribution), <b>APTEM</b> (extrinsic + aprotinin — detects "
"fibrinolysis by comparison).", BODY_STYLE))
# 3.3 Clinical Use
story.append(Paragraph("3.3 TEG/ROTEM-Guided Transfusion Algorithms", H2_STYLE))
story.append(Paragraph(
"The greatest clinical utility of VHAs is in <b>goal-directed transfusion therapy</b>. "
"VHAs free the anaesthetist from reliance solely on the empiric 1:1:1 "
"(FFP:platelets:pRBC) massive transfusion protocol, enabling targeted product use. "
"Key clinical contexts include:", BODY_STYLE))
for b in [
"<b>Major trauma and haemorrhage</b> — identifying trauma-induced coagulopathy (TIC), characterised by early hyperfibrinolysis, dilution, hypothermia, and acidosis (the 'lethal triad').",
"<b>Cardiac surgery</b> — distinguishing surgical bleeding from coagulopathic bleeding; strongest evidence base.",
"<b>Liver transplantation</b> — monitoring complex coagulopathy including hyperfibrinolysis.",
"<b>Obstetric haemorrhage</b> — real-time guidance for clotting factor replacement.",
"<b>Neurosurgery</b> — detecting hypercoagulability and guiding anticoagulation.",
]:
story.append(Paragraph(f"• {b}", BULLET_STYLE))
story.append(Paragraph("<b>Algorithm summary:</b>", H3_STYLE))
algo_headers = ["VHA Finding", "Likely Defect", "Recommended Intervention"]
algo_rows = [
["Prolonged R time / CT", "Coagulation factor deficiency", "FFP or factor concentrates"],
["Prolonged K time / CFT", "Fibrinogen deficiency", "Cryoprecipitate or fibrinogen concentrate"],
["Reduced alpha angle", "Fibrinogen deficiency", "Cryoprecipitate or fibrinogen concentrate"],
["Reduced MA / MCF", "Platelet dysfunction / thrombocytopaenia", "Platelet transfusion"],
["Elevated LY30 / LI30", "Hyperfibrinolysis", "Tranexamic acid or aminocaproic acid"],
["Elevated CI (>+3)", "Hypercoagulable state", "Anticoagulation (clinical context dependent)"],
]
avail = PAGE_W - LEFT_M - RIGHT_M
story.append(build_table(algo_headers, algo_rows,
col_widths=[4.5*cm, 5.5*cm, avail - 4.5*cm - 5.5*cm]))
# 3.4 Advantages
story.append(Paragraph("3.4 Advantages over Standard Coagulation Tests", H2_STYLE))
adv_headers = ["Feature", "PT / aPTT / CBC", "TEG / ROTEM"]
adv_rows = [
["Sample", "Plasma only", "Whole blood (includes platelets and RBCs)"],
["Condition", "Static", "Dynamic"],
["Turnaround time", "45–90 min", "20–30 min (functional result)"],
["Fibrinolysis", "Not detected", "Yes (LY30 / LI30)"],
["Platelet function", "No", "Yes (via MA / MCF)"],
["Hypercoagulability", "No", "Yes (CI, shortened R time)"],
["Point-of-care use", "Limited", "Yes"],
]
story.append(build_table(adv_headers, adv_rows,
col_widths=[4.5*cm, 4.5*cm, PAGE_W - LEFT_M - RIGHT_M - 9*cm]))
# 3.5 Limitations
story.append(Paragraph("3.5 Limitations of TEG/ROTEM", H2_STYLE))
for b in [
"Temperature sensitivity: samples must be maintained at 37 °C; hypothermia artefacts affect results.",
"Inter-operator variability; time-sensitive sample processing required.",
"Do not assess <b>endothelial function</b> or the vascular component of haemostasis.",
"Weak sensitivity for antiplatelet drugs (aspirin, P2Y12 inhibitors) — specific platelet mapping reagents required.",
"ROTEM and TEG values are <b>not interchangeable</b> and use different reference ranges.",
"Evidence base predominantly from cardiac surgery; emerging but variable certainty in trauma and obstetrics.",
"Cost and availability in lower-resource settings.",
]:
story.append(Paragraph(f"• {b}", BULLET_STYLE))
# ══ SECTION 4 ══════════════════════════════════════════════════════════════
section_header(story, 4, "Current Evidence (4 marks)")
story.append(Paragraph(
"A <b>2026 Cochrane systematic review</b> (Kvisselgaard et al., 35 RCTs, n=3,096, predominantly "
"cardiac surgery patients) found TEG/ROTEM-guided transfusion compared with standard care:",
BODY_STYLE))
for b in [
"<b>May reduce all-cause mortality</b> (RR 0.76, 95% CI 0.63–0.92; 19 trials, 1865 participants; I²=0%; very low certainty evidence).",
"<b>May reduce bleeding volume</b> (SMD −0.31, 95% CI −0.51 to −0.11; 19 trials; I²=72%; very low certainty evidence).",
"<b>May reduce FFP and platelet transfusion use</b> and surgical re-exploration.",
"<b>No significant reduction in packed red blood cell use</b> (RR 0.94, 95% CI 0.87–1.01; I²=91%).",
"Overall: <b>very low certainty evidence</b> across all outcomes due to heterogeneity, risk of bias, and indirectness.",
]:
story.append(Paragraph(f"• {b}", BULLET_STYLE))
story.append(Paragraph(
"This is consistent with earlier systematic reviews published in Anaesthesia (2017;72:519–531), "
"cited in Morgan & Mikhail and Goldman-Cecil Medicine. Evidence is <b>strongest for elective "
"cardiac surgery</b>; emerging data exist for trauma, liver transplantation, and obstetrics.",
BODY_STYLE))
story.append(Paragraph(
"<i>Kvisselgaard AD et al. Cochrane Database Syst Rev. 2026 May 18. doi:10.1002/14651858.CD007871.pub4 "
"[PMID: 42145275]</i>", REF_STYLE))
# ══ SECTION 5 ══════════════════════════════════════════════════════════════
section_header(story, 5, "Anaesthetic Relevance — Practical Summary")
story.append(Paragraph("The anaesthetist must:", BODY_STYLE))
for b in [
"Understand the <b>cell-based model</b> rather than the classical cascade alone, to correctly interpret clinical factor deficiencies and guide targeted replacement.",
"Recognise the <b>limitations of PT/aPTT</b>: normal values do not exclude coagulopathy, and they do not detect fibrinolysis or platelet dysfunction.",
"Use TEG/ROTEM as <b>decision support tools within a goal-directed algorithm</b>, not as isolated tests.",
"Apply <b>tranexamic acid early</b> in high-risk haemorrhage (CRASH-2/WOMAN trial evidence), with VHA-confirmed hyperfibrinolysis (LY30 >7.5%) as additional guidance.",
"Account for the <b>lethal triad</b> (hypothermia, acidosis, coagulopathy) in major haemorrhage: hypothermia impairs enzymatic reactions and platelet function; acidosis disrupts the coagulation factor environment; haemodilution reduces factor and platelet concentrations.",
]:
story.append(Paragraph(f"• {b}", BULLET_STYLE))
# ══ SUMMARY TABLE ══════════════════════════════════════════════════════════
story.append(Spacer(1, 10))
story.append(HRFlowable(width="100%", thickness=1.5, color=TEAL))
story.append(Spacer(1, 6))
story.append(Paragraph("Summary Table", H2_STYLE))
sum_headers = ["Aspect", "Key Points"]
sum_rows = [
["Classical cascade",
"Extrinsic (TF-FVII) + Intrinsic (contact, FXII) → common pathway (FXa, prothrombin → thrombin → fibrin)"],
["Cell-based model",
"Initiation (TF cells) → Amplification (platelets) → Propagation (platelet surface)"],
["Thrombin",
"Central mediator: fibrinogen cleavage, FXIII activation, platelet activation (PAR-1), feedback activation of FV/FVIII/FXI"],
["Endogenous anticoagulants",
"ATIII (+ heparin), TFPI (inhibits TF:FVIIa:FXa), Protein C/S (inhibits FVa/FVIIIa), PGI₂/NO"],
["Fibrinolysis",
"t-PA → plasmin → fibrin degradation; D-dimers as markers; controlled by alpha-2-antiplasmin and PAI-1"],
["TEG/ROTEM principle",
"Global viscoelastic assay of whole blood: R/CT (factors) → K/CFT + alpha angle (fibrinogen) → MA/MCF (platelets) → LY30/LI30 (fibrinolysis)"],
["Clinical use",
"Goal-directed transfusion in cardiac surgery, trauma, liver Tx, obstetrics; algorithm-guided product choice"],
["Current evidence",
"Cochrane 2026 (35 RCTs): possible mortality reduction RR 0.76, reduced FFP/platelet use; very low certainty evidence overall"],
]
story.append(build_table(sum_headers, sum_rows, col_widths=[4.5*cm, PAGE_W - LEFT_M - RIGHT_M - 4.5*cm]))
# ══ REFERENCES ══════════════════════════════════════════════════════════════
story.append(Spacer(1, 12))
story.append(HRFlowable(width="100%", thickness=1, color=GREY))
story.append(Spacer(1, 6))
story.append(Paragraph("Key References", H2_STYLE))
refs = [
"Kumar V, Abbas AK, Aster JC. <i>Robbins and Cotran Pathologic Basis of Disease</i>, 10th ed. Elsevier, 2020.",
"Fauci AS et al. <i>Harrison's Principles of Internal Medicine</i>, 22nd ed. McGraw-Hill, 2025.",
"Townsend CM et al. <i>Sabiston Textbook of Surgery</i>, 21st ed. Elsevier, 2022.",
"Morgan GE, Mikhail MS. <i>Clinical Anesthesiology</i>, 7th ed. McGraw-Hill, 2022.",
"Brunicardi FC et al. <i>Schwartz's Principles of Surgery</i>, 11th ed. McGraw-Hill, 2019.",
"Bucholz RW et al. <i>Rockwood and Green's Fractures in Adults</i>, 10th ed. Wolters Kluwer, 2025.",
"Goldman L, Cooney KA. <i>Goldman-Cecil Medicine</i>, 27th ed. Elsevier, 2024.",
"Kvisselgaard AD, Wolthers SA, Wikkelso AJ, et al. Thromboelastography (TEG) or thromboelastometry (ROTEM) to monitor haemostatic treatment versus usual care in adults or children with bleeding. <i>Cochrane Database Syst Rev.</i> 2026 May 18. doi:10.1002/14651858.CD007871.pub4. PMID: 42145275.",
]
for i, r in enumerate(refs, 1):
story.append(Paragraph(f"{i}. {r}", REF_STYLE))
# ── Build PDF ──────────────────────────────────────────────────────────────
doc.build(story, onFirstPage=header_footer, onLaterPages=header_footer)
print(f"PDF saved to: {OUTPUT}")
if __name__ == "__main__":
build()
cd /home/daytona/workspace/coagulation-teg && python3 build_pdf.py 2>&1
ls -lh /home/daytona/workspace/coagulation-teg/Coagulation_Cascade_and_TEG_Exam_Answer.pdf
Coagulation Cascade and TEG Exam Answer
PDF Document · PDF
Create a quick reference laminated TEG/ROTEM interpretation card for theatre use
ls /home/daytona/workspace/coagulation-teg/
~/coagulation-teg/build_card.py
#!/usr/bin/env python3
"""
TEG / ROTEM Quick-Reference Laminated Card for Theatre
Two-sided A5 card (landscape) — both sides on one A4 sheet (print, fold, laminate)
Side A: TEG parameters + ROTEM equivalents + trace diagram
Side B: Goal-directed algorithm + lethal triad + drug effects
"""
import io, requests
from reportlab.lib.pagesizes import A4, landscape
from reportlab.lib.units import cm, mm
from reportlab.lib.colors import HexColor, white, black
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.platypus import (
SimpleDocTemplate, Table, TableStyle, Paragraph,
Spacer, HRFlowable, Image, KeepTogether
)
OUTPUT = "/home/daytona/workspace/coagulation-teg/TEG_ROTEM_Theatre_Card.pdf"
# ── Palette ────────────────────────────────────────────────────────────────────
NAVY = HexColor("#1a2e4a")
TEAL = HexColor("#0d6e7e")
TEAL_LT = HexColor("#e0f2f5")
GREEN = HexColor("#1a6b3c")
GREEN_LT= HexColor("#d4edda")
RED = HexColor("#8b1a1a")
RED_LT = HexColor("#fde8e8")
AMBER = HexColor("#7a4f00")
AMBER_LT= HexColor("#fff3cd")
PURPLE = HexColor("#4a1a6b")
PURPLE_LT=HexColor("#ede0f7")
GREY = HexColor("#444444")
LGREY = HexColor("#f5f5f5")
WHITE = white
MID = HexColor("#cccccc")
# ── Card geometry (A4 landscape = two A5 landscape panels) ─────────────────────
PAGE_W, PAGE_H = landscape(A4) # 841 x 595 pt
CARD_W = PAGE_W / 2 - 10 # each panel
MARGIN = 0.4 * cm
# ── Styles ─────────────────────────────────────────────────────────────────────
def S(name, **kw):
return ParagraphStyle(name, **kw)
CARD_TITLE = S("CT", fontName="Helvetica-Bold", fontSize=11,
textColor=WHITE, alignment=TA_CENTER, leading=14)
SECTION = S("SC", fontName="Helvetica-Bold", fontSize=8.5,
textColor=WHITE, alignment=TA_CENTER, leading=11)
HDR = S("HD", fontName="Helvetica-Bold", fontSize=7.5,
textColor=WHITE, alignment=TA_CENTER, leading=10)
CELL = S("CL", fontName="Helvetica", fontSize=7.5,
textColor=black, alignment=TA_LEFT, leading=10)
CELL_C = S("CC", fontName="Helvetica", fontSize=7.5,
textColor=black, alignment=TA_CENTER, leading=10)
CELL_B = S("CB", fontName="Helvetica-Bold", fontSize=7.5,
textColor=black, alignment=TA_LEFT, leading=10)
CELL_BC = S("CBC", fontName="Helvetica-Bold", fontSize=7.5,
textColor=black, alignment=TA_CENTER, leading=10)
SMALL = S("SM", fontName="Helvetica", fontSize=6.5,
textColor=GREY, alignment=TA_CENTER, leading=8)
SMALL_B = S("SMB", fontName="Helvetica-Bold", fontSize=6.5,
textColor=GREY, alignment=TA_LEFT, leading=8)
FOOT = S("FT", fontName="Helvetica-Oblique", fontSize=6,
textColor=GREY, alignment=TA_CENTER, leading=8)
def p(txt, style): return Paragraph(txt, style)
def sp(h=2): return Spacer(1, h)
def fetch_img(url, w_cm, max_h_cm=None):
try:
r = requests.get(url, timeout=12)
r.raise_for_status()
buf = io.BytesIO(r.content)
img = Image(buf)
aspect = img.imageHeight / float(img.imageWidth)
w = w_cm * cm
h = w * aspect
if max_h_cm and h > max_h_cm * cm:
h = max_h_cm * cm
w = h / aspect
img.drawWidth = w
img.drawHeight = h
return img
except Exception as e:
print(f" [warn] img fetch failed: {e}")
return None
# ── Generic section banner ──────────────────────────────────────────────────────
def banner(txt, color=NAVY, w=None):
cw = w or CARD_W
t = Table([[p(txt, SECTION)]], colWidths=[cw])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), color),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING",(0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 4),
("RIGHTPADDING", (0,0),(-1,-1), 4),
]))
return t
# ══════════════════════════════════════════════════════════════════════════════
# SIDE A — Parameters + Trace + ROTEM equivalents
# ══════════════════════════════════════════════════════════════════════════════
def build_side_a():
elems = []
CW = CARD_W
# ── Title bar ──────────────────────────────────────────────────────────────
title_tbl = Table([[p("TEG / ROTEM QUICK REFERENCE", CARD_TITLE)]], colWidths=[CW])
title_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), NAVY),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 6),
("RIGHTPADDING", (0,0),(-1,-1), 6),
]))
elems.append(title_tbl)
elems.append(sp(2))
# ── TEG trace image ────────────────────────────────────────────────────────
img = fetch_img(
"https://cdn.orris.care/cdss_images/0b1425cf1a93207225bb92d1d44f5ea59473ea214e1210004b631d11c938aa87.png",
w_cm=9.5, max_h_cm=3.8)
if img:
img_tbl = Table([[img]], colWidths=[CW])
img_tbl.setStyle(TableStyle([("ALIGN",(0,0),(-1,-1),"CENTER"),
("VALIGN",(0,0),(-1,-1),"MIDDLE")]))
elems.append(img_tbl)
elems.append(p("TEG trace — R time · K time · α angle · MA · LY30", SMALL))
elems.append(sp(3))
# ── TEG Parameters table ───────────────────────────────────────────────────
elems.append(banner("TEG PARAMETERS", TEAL))
elems.append(sp(1))
hdr = [p("Parameter", HDR), p("Definition", HDR),
p("Normal", HDR), p("↑ / ↓ Meaning", HDR)]
rows = [hdr,
[p("R time", CELL_B), p("Time to first clot (2 mm amplitude)", CELL),
p("5–10 min", CELL_C), p("↑ Factor deficiency / anticoagulants\n↓ Hypercoagulable", CELL)],
[p("K time", CELL_B), p("Time to 20 mm amplitude", CELL),
p("1–3 min", CELL_C), p("↑ Low fibrinogen / platelets", CELL)],
[p("α angle", CELL_B), p("Rate of fibrin accumulation", CELL),
p("53–72°", CELL_C), p("↓ Fibrinogen deficiency\n↑ Hypercoagulable", CELL)],
[p("MA", CELL_B), p("Max clot strength\n(~80% platelets, ~20% fibrinogen)", CELL),
p("50–70 mm", CELL_C), p("↓ Platelet dysfunction / low count", CELL)],
[p("LY30", CELL_B), p("% amplitude loss at 30 min", CELL),
p("<7.5%", CELL_C), p("↑ >7.5%: Hyperfibrinolysis", CELL)],
[p("EPL", CELL_B), p("Estimated % lysis (earlier signal)", CELL),
p("<15%", CELL_C), p("↑ Fibrinolysis (acts before LY30)", CELL)],
[p("CI", CELL_B), p("Composite coagulation index", CELL),
p("−3 to +3", CELL_C), p("<−3 hypocoag · >+3 hypercoag", CELL)],
]
c1,c2,c3,c4 = 1.5*cm, 4.0*cm, 1.6*cm, CW-1.5*cm-4.0*cm-1.6*cm
teg_t = Table(rows, colWidths=[c1, c2, c3, c4], repeatRows=1)
teg_t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), TEAL),
("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, TEAL_LT]),
("GRID", (0,0),(-1,-1), 0.4, MID),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 4),
("RIGHTPADDING", (0,0),(-1,-1), 4),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
elems.append(teg_t)
elems.append(sp(3))
# ── ROTEM equivalents ──────────────────────────────────────────────────────
elems.append(banner("ROTEM EQUIVALENTS & REAGENTS", NAVY))
elems.append(sp(1))
r_hdr = [p("TEG", HDR), p("ROTEM", HDR), p("Reagent", HDR), p("Pathway Tested", HDR)]
r_rows = [r_hdr,
[p("R time", CELL_B), p("CT", CELL_BC), p("EXTEM / INTEM", CELL), p("Extrinsic / Intrinsic factors", CELL)],
[p("K time", CELL_B), p("CFT", CELL_BC), p("EXTEM / INTEM", CELL), p("Fibrinogen + platelets (kinetics)", CELL)],
[p("α angle", CELL_B), p("α angle", CELL_BC), p("EXTEM / FIBTEM", CELL), p("Fibrinogen contribution", CELL)],
[p("MA", CELL_B), p("MCF", CELL_BC), p("EXTEM / INTEM / FIBTEM", CELL), p("Clot strength (plts + fibrinogen)", CELL)],
[p("LY30", CELL_B), p("LI30 / ML", CELL_BC), p("EXTEM ± APTEM", CELL), p("Fibrinolysis (APTEM confirms)", CELL)],
]
ca, cb, cc, cd = 1.5*cm, 1.5*cm, 3.2*cm, CW - 1.5*cm - 1.5*cm - 3.2*cm
rotem_t = Table(r_rows, colWidths=[ca, cb, cc, cd], repeatRows=1)
rotem_t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), NAVY),
("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, LGREY]),
("GRID", (0,0),(-1,-1), 0.4, MID),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 4),
("RIGHTPADDING", (0,0),(-1,-1), 4),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
elems.append(rotem_t)
elems.append(sp(3))
# ── ROTEM reagent key ──────────────────────────────────────────────────────
reagent_data = [
[p("EXTEM", S("x", fontName="Helvetica-Bold", fontSize=7, textColor=RED, alignment=TA_CENTER)),
p("Tissue factor → extrinsic pathway", SMALL),
p("INTEM", S("x", fontName="Helvetica-Bold", fontSize=7, textColor=TEAL, alignment=TA_CENTER)),
p("Ellagic acid → intrinsic pathway", SMALL)],
[p("FIBTEM", S("x", fontName="Helvetica-Bold", fontSize=7, textColor=GREEN, alignment=TA_CENTER)),
p("EXTEM + cytochalasin D (platelet inhibitor) → fibrinogen only", SMALL),
p("APTEM", S("x", fontName="Helvetica-Bold", fontSize=7, textColor=AMBER, alignment=TA_CENTER)),
p("EXTEM + aprotinin → confirm fibrinolysis", SMALL)],
]
rkey = Table(reagent_data, colWidths=[1.3*cm, (CW/2-1.3*cm), 1.3*cm, (CW/2-1.3*cm)])
rkey.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), LGREY),
("GRID", (0,0),(-1,-1), 0.3, MID),
("TOPPADDING", (0,0),(-1,-1), 2),
("BOTTOMPADDING",(0,0),(-1,-1), 2),
("LEFTPADDING",(0,0),(-1,-1), 4),
("RIGHTPADDING",(0,0),(-1,-1), 4),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
elems.append(rkey)
elems.append(sp(4))
elems.append(p("Orris Medical AI | July 2026 | Side A — Parameters", FOOT))
return elems
# ══════════════════════════════════════════════════════════════════════════════
# SIDE B — Algorithm + Lethal Triad + Drug Effects + Causes
# ══════════════════════════════════════════════════════════════════════════════
def build_side_b():
elems = []
CW = CARD_W
# Title bar
title_tbl = Table([[p("TEG / ROTEM GOAL-DIRECTED ALGORITHM", CARD_TITLE)]], colWidths=[CW])
title_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), NAVY),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
]))
elems.append(title_tbl)
elems.append(sp(2))
# ── Algorithm table ────────────────────────────────────────────────────────
elems.append(banner("INTERPRETATION → INTERVENTION", TEAL))
elems.append(sp(1))
algo_hdr = [p("VHA Finding", HDR), p("Likely Defect", HDR),
p("TEG\nParameter", HDR), p("ROTEM\nParameter", HDR), p("Give →", HDR)]
def row_col(bg):
return bg
algo_rows = [algo_hdr,
[p("Prolonged R time / CT", CELL_B),
p("Coagulation factor\ndeficiency / anticoagulant", CELL),
p("R time ↑", CELL_BC), p("CT ↑", CELL_BC),
p("FFP or Factor\nConcentrates\n(PCC / FibC)", CELL_B)],
[p("Prolonged K time / CFT\n+ Reduced α angle", CELL_B),
p("Fibrinogen deficiency", CELL),
p("K time ↑\nα angle ↓", CELL_BC), p("CFT ↑\nα ↓ or\nFIBTEM MCF ↓", CELL_BC),
p("Cryoprecipitate\nor Fibrinogen\nConcentrate", CELL_B)],
[p("Reduced MA / MCF\n(normal α angle)", CELL_B),
p("Platelet dysfunction\nor thrombocytopaenia", CELL),
p("MA ↓", CELL_BC), p("EXTEM MCF ↓\nFIBTEM MCF normal", CELL_BC),
p("Platelet\nTransfusion", CELL_B)],
[p("Elevated LY30 / LI30\nor ML", CELL_B),
p("Hyperfibrinolysis", CELL),
p("LY30 >7.5%\nEPL >15%", CELL_BC), p("LI30 <85%\nML >15%\nAPTEM MCF ↑", CELL_BC),
p("Tranexamic Acid\nor EACA\n(if no CI)", CELL_B)],
[p("MA / MCF ↓\n+ α angle ↓\n+ K time ↑", CELL_B),
p("Combined fibrinogen\n+ platelet deficit\n(e.g. massive haemorrhage)", CELL),
p("Multiple\nabnormal", CELL_BC), p("EXTEM + FIBTEM\nboth low", CELL_BC),
p("Cryoprecipitate\nTHEN Platelets\n(fibrinogen first)", CELL_B)],
[p("Short R time\nElevated CI (>+3)", CELL_B),
p("Hypercoagulable\nstate", CELL),
p("R time ↓\nCI >+3", CELL_BC), p("CT ↓", CELL_BC),
p("Anticoagulation\n(clinical context\ndependent)", CELL_B)],
]
# Column widths
ca1 = 3.2*cm; ca2 = 3.0*cm; ca3 = 1.6*cm; ca4 = 2.5*cm
ca5 = CW - ca1 - ca2 - ca3 - ca4
algo_bg = [WHITE, GREEN_LT, AMBER_LT, RED_LT, PURPLE_LT, LGREY]
algo_t = Table(algo_rows, colWidths=[ca1, ca2, ca3, ca4, ca5], repeatRows=1)
algo_t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), TEAL),
("BACKGROUND", (0,1),(-1,1), GREEN_LT),
("BACKGROUND", (0,2),(-1,2), AMBER_LT),
("BACKGROUND", (0,3),(-1,3), RED_LT),
("BACKGROUND", (0,4),(-1,4), PURPLE_LT),
("BACKGROUND", (0,5),(-1,5), TEAL_LT),
("BACKGROUND", (0,6),(-1,6), LGREY),
("GRID", (0,0),(-1,-1), 0.4, MID),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 4),
("RIGHTPADDING", (0,0),(-1,-1), 4),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("LINEBELOW", (0,0),(-1,0), 1.0, TEAL),
]))
elems.append(algo_t)
elems.append(sp(3))
# ── Drug effects row ───────────────────────────────────────────────────────
elems.append(banner("DRUG EFFECTS ON TEG/ROTEM", NAVY))
elems.append(sp(1))
drug_hdr = [p("Drug / Condition", HDR), p("Effect on Trace", HDR), p("Affected Parameter", HDR)]
drug_rows = [drug_hdr,
[p("Heparin (UFH)", CELL_B), p("Prolongs enzymatic phase", CELL), p("↑ R time / CT (INTEM sensitive)", CELL)],
[p("Warfarin / VKA", CELL_B), p("Prolonged initiation", CELL), p("↑ R time / CT (EXTEM sensitive)", CELL)],
[p("DOACs (direct Xa/IIa)", CELL_B), p("Prolongs R time variably", CELL), p("↑ R time / CT (drug-specific assays needed)", CELL)],
[p("Aspirin / NSAIDs", CELL_B), p("Reduced platelet contribution", CELL), p("↓ MA / MCF (use platelet mapping)", CELL)],
[p("P2Y12 inhibitors", CELL_B), p("Reduced platelet aggregation", CELL), p("↓ MA / MCF (ADP-specific mapping)", CELL)],
[p("Tranexamic acid", CELL_B), p("Inhibits fibrinolysis", CELL), p("↓ LY30 / LI30 (normalises if elevated)", CELL)],
[p("Hypothermia", CELL_B), p("Slows all enzymatic reactions", CELL), p("↑ R, K times · ↓ MA (Note: TEG runs at 37°C — underestimates!)", CELL)],
[p("DIC (acute)", CELL_B), p("Consumption coagulopathy + fibrinolysis", CELL), p("↑ R + K · ↓ α, MA + ↑↑ LY30", CELL)],
]
da1 = 2.8*cm; da2 = 3.2*cm; da3 = CW - da1 - da2
drug_t = Table(drug_rows, colWidths=[da1, da2, da3], repeatRows=1)
drug_t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), NAVY),
("ROWBACKGROUNDS",(0,1),(-1,-1), [WHITE, LGREY]),
("GRID", (0,0),(-1,-1), 0.4, MID),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 4),
("RIGHTPADDING", (0,0),(-1,-1), 4),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
elems.append(drug_t)
elems.append(sp(3))
# ── Lethal triad + periop contexts ────────────────────────────────────────
triad_data = [
[p("THE LETHAL TRIAD", S("LT", fontName="Helvetica-Bold", fontSize=7.5,
textColor=WHITE, alignment=TA_CENTER)),
p("PERIOP HIGH-RISK CONTEXTS", S("LT2", fontName="Helvetica-Bold", fontSize=7.5,
textColor=WHITE, alignment=TA_CENTER))],
[p("🌡 Hypothermia <35°C\n→ Impairs enzymatic clotting + platelet fx\n\n"
"⚗ Acidosis pH <7.2\n→ Disrupts factor + platelet environment\n\n"
"🩸 Haemodilution\n→ Dilutes factors + platelets\n\n"
"All three are synergistic → TEG/ROTEM-guided\ncorrection superior to empiric 1:1:1",
S("tri", fontName="Helvetica", fontSize=7.5, textColor=black, leading=11, alignment=TA_LEFT)),
p("• <b>Cardiac surgery</b> (strongest evidence)\n"
"• Major trauma / haemorrhage\n"
"• Liver transplantation (hyperfibrinolysis)\n"
"• Obstetric major haemorrhage (PPH)\n"
"• Neurosurgery (detect hypercoag)\n"
"• Massive transfusion protocol guidance\n\n"
"<i>NOTE: TEG ≠ ROTEM — not interchangeable.\nValues differ; use institution-specific ranges.</i>",
S("ctx", fontName="Helvetica", fontSize=7.5, textColor=black, leading=11, alignment=TA_LEFT))],
]
triad_t = Table(triad_data, colWidths=[CW/2, CW/2])
triad_t.setStyle(TableStyle([
("BACKGROUND", (0,0),(0,0), RED),
("BACKGROUND", (1,0),(1,0), GREEN),
("BACKGROUND", (0,1),(0,1), RED_LT),
("BACKGROUND", (1,1),(1,1), GREEN_LT),
("GRID", (0,0),(-1,-1), 0.4, MID),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING",(0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 5),
("RIGHTPADDING", (0,0),(-1,-1), 5),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
elems.append(triad_t)
elems.append(sp(4))
elems.append(p(
"Cochrane 2026 (35 RCTs, n=3096): TEG/ROTEM may ↓ mortality (RR 0.76) and ↓ FFP/platelet use — very low certainty evidence | "
"Morgan & Mikhail Clin Anaesthesiology 7e | Orris Medical AI | July 2026 | Side B — Algorithm",
FOOT))
return elems
# ══════════════════════════════════════════════════════════════════════════════
# ASSEMBLE: two panels side by side on one A4 landscape sheet
# ══════════════════════════════════════════════════════════════════════════════
def build():
doc = SimpleDocTemplate(
OUTPUT,
pagesize=landscape(A4),
leftMargin=MARGIN, rightMargin=MARGIN,
topMargin=MARGIN, bottomMargin=MARGIN,
title="TEG/ROTEM Quick Reference Theatre Card",
author="Orris Medical AI"
)
side_a = build_side_a()
side_b = build_side_b()
# Wrap each side into a single-cell table column, then place both side by side
def side_table(elems, width):
rows = [[e] for e in elems]
t = Table(rows, colWidths=[width])
t.setStyle(TableStyle([
("TOPPADDING", (0,0),(-1,-1), 0),
("BOTTOMPADDING", (0,0),(-1,-1), 0),
("LEFTPADDING", (0,0),(-1,-1), 0),
("RIGHTPADDING", (0,0),(-1,-1), 0),
("VALIGN", (0,0),(-1,-1), "TOP"),
]))
return t
CW = CARD_W
DIVIDER = 8 # points of gutter between the two panels
outer = Table(
[[side_table(side_a, CW), Spacer(DIVIDER, 1), side_table(side_b, CW)]],
colWidths=[CW, DIVIDER, CW]
)
outer.setStyle(TableStyle([
("VALIGN", (0,0),(-1,-1), "TOP"),
("TOPPADDING", (0,0),(-1,-1), 0),
("BOTTOMPADDING", (0,0),(-1,-1), 0),
("LEFTPADDING", (0,0),(-1,-1), 0),
("RIGHTPADDING", (0,0),(-1,-1), 0),
# Dashed centre cut line
("LINEAFTER", (0,0),(0,-1), 0.5, HexColor("#aaaaaa"), None, None, None, (3,3)),
]))
doc.build([outer])
print(f"Card saved: {OUTPUT}")
if __name__ == "__main__":
build()
cd /home/daytona/workspace/coagulation-teg && python3 build_card.py 2>&1
~/coagulation-teg/build_card.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/coagulation-teg/build_card.py'
cd /home/daytona/workspace/coagulation-teg && python3 build_card.py 2>&1
~/coagulation-teg/build_card.py
#!/usr/bin/env python3
"""
TEG / ROTEM Quick-Reference Laminated Card — Theatre Use
Two A5-landscape panels printed on one A4-landscape page.
Built with ReportLab canvas + Platypus Frame for precise layout.
"""
import io, requests
from reportlab.lib.pagesizes import A4, landscape
from reportlab.lib.units import cm, mm
from reportlab.lib.colors import HexColor, white, black
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.platypus import (
Table, TableStyle, Paragraph, Spacer, HRFlowable, Image, Frame
)
from reportlab.pdfgen import canvas as pdfcanvas
OUTPUT = "/home/daytona/workspace/coagulation-teg/TEG_ROTEM_Theatre_Card.pdf"
# ── Page ──────────────────────────────────────────────────────────────────────
PW, PH = landscape(A4) # 841.89 x 595.28 pt
GUTTER = 6 # pt between panels
PAD = 6 # pt inner padding
PANEL_W = (PW - GUTTER) / 2
PANEL_H = PH
# ── Palette ───────────────────────────────────────────────────────────────────
NAVY = HexColor("#1a2e4a")
TEAL = HexColor("#0d6e7e")
TEAL_LT = HexColor("#dff0f3")
GREEN = HexColor("#1a6b3c")
GREEN_LT = HexColor("#d4edda")
RED = HexColor("#8b1a1a")
RED_LT = HexColor("#fde8e8")
AMBER = HexColor("#7a4f00")
AMBER_LT = HexColor("#fff3cd")
PURPLE = HexColor("#4a1a6b")
PURPLE_LT = HexColor("#ede0f7")
GREY = HexColor("#555555")
LGREY = HexColor("#f5f5f5")
MID = HexColor("#cccccc")
WHITE = white
# ── Styles ────────────────────────────────────────────────────────────────────
def S(name, **kw):
return ParagraphStyle(name, **kw)
TITLE = S("TI", fontName="Helvetica-Bold", fontSize=10, textColor=WHITE, alignment=TA_CENTER, leading=13)
SECT = S("SE", fontName="Helvetica-Bold", fontSize=8, textColor=WHITE, alignment=TA_CENTER, leading=11)
HDR = S("HD", fontName="Helvetica-Bold", fontSize=7, textColor=WHITE, alignment=TA_CENTER, leading=9)
CELL = S("CL", fontName="Helvetica", fontSize=7, textColor=black, alignment=TA_LEFT, leading=9)
CELLC = S("CC", fontName="Helvetica", fontSize=7, textColor=black, alignment=TA_CENTER, leading=9)
CELLB = S("CB", fontName="Helvetica-Bold", fontSize=7, textColor=black, alignment=TA_LEFT, leading=9)
CELLBC= S("CBC",fontName="Helvetica-Bold", fontSize=7, textColor=black, alignment=TA_CENTER, leading=9)
SMALL = S("SM", fontName="Helvetica", fontSize=6, textColor=GREY, alignment=TA_CENTER, leading=8)
SMALLB= S("SB", fontName="Helvetica-Bold", fontSize=6, textColor=GREY, alignment=TA_LEFT, leading=8)
FOOT = S("FT", fontName="Helvetica-Oblique", fontSize=5.5, textColor=GREY, alignment=TA_CENTER, leading=7)
p = lambda txt, sty: Paragraph(txt, sty)
sp = lambda h=2: Spacer(1, h)
# ── Image fetch ───────────────────────────────────────────────────────────────
def fetch_img(url, w_pt, max_h_pt=None):
try:
r = requests.get(url, timeout=12)
r.raise_for_status()
buf = io.BytesIO(r.content)
img = Image(buf)
aspect = img.imageHeight / float(img.imageWidth)
h = w_pt * aspect
if max_h_pt and h > max_h_pt:
h = max_h_pt
w_pt = h / aspect
img.drawWidth = w_pt
img.drawHeight = h
return img
except Exception as e:
print(f" [warn] {e}")
return None
# ── Table helpers ─────────────────────────────────────────────────────────────
def banner_row(txt, color, width):
t = Table([[p(txt, SECT)]], colWidths=[width])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), color),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 4),
("RIGHTPADDING", (0,0),(-1,-1), 4),
]))
return t
def mk_table(rows, cw, row_bgs=None, hdr_color=NAVY):
t = Table(rows, colWidths=cw, repeatRows=1)
style = [
("BACKGROUND", (0,0),(-1,0), hdr_color),
("GRID", (0,0),(-1,-1), 0.4, MID),
("TOPPADDING", (0,0),(-1,-1), 2),
("BOTTOMPADDING", (0,0),(-1,-1), 2),
("LEFTPADDING", (0,0),(-1,-1), 3),
("RIGHTPADDING", (0,0),(-1,-1), 3),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]
if row_bgs:
for i, bg in enumerate(row_bgs, start=1):
if bg:
style.append(("BACKGROUND", (0,i),(-1,i), bg))
else:
style.append(("ROWBACKGROUNDS", (0,1),(-1,-1), [WHITE, LGREY]))
t.setStyle(TableStyle(style))
return t
# ══════════════════════════════════════════════════════════════════════════════
# SIDE A flowables
# ══════════════════════════════════════════════════════════════════════════════
def side_a_flowables(W):
elems = []
IW = W - 2*PAD # inner width
# Title
title = Table([[p("TEG / ROTEM QUICK REFERENCE — THEATRE CARD", TITLE)]], colWidths=[W])
title.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), NAVY),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
]))
elems.append(title); elems.append(sp(3))
# TEG trace image
img = fetch_img(
"https://cdn.orris.care/cdss_images/0b1425cf1a93207225bb92d1d44f5ea59473ea214e1210004b631d11c938aa87.png",
w_pt=IW * 0.78, max_h_pt=80)
if img:
img_wrap = Table([[img]], colWidths=[IW])
img_wrap.setStyle(TableStyle([
("ALIGN",(0,0),(-1,-1),"CENTER"), ("VALIGN",(0,0),(-1,-1),"MIDDLE"),
("TOPPADDING",(0,0),(-1,-1),0), ("BOTTOMPADDING",(0,0),(-1,-1),0),
]))
elems.append(img_wrap)
elems.append(p("R time · K time · α angle · MA · LY30 · EPL", SMALL))
elems.append(sp(3))
# TEG Parameters
elems.append(banner_row("TEG PARAMETERS", TEAL, IW)); elems.append(sp(1))
c1,c2,c3,c4 = 1.4*cm, 3.8*cm, 1.4*cm, IW - 1.4*cm - 3.8*cm - 1.4*cm
teg_hdr = [p("Param",HDR), p("Definition",HDR), p("Normal",HDR), p("↑/↓ Meaning & Action",HDR)]
teg_rows = [teg_hdr,
[p("R time",CELLB), p("First clot formation (2 mm)",CELL), p("5–10 min",CELLC),
p("↑ Factor deficiency / anticoag → FFP/PCC\n↓ Hypercoagulable",CELL)],
[p("K time",CELLB), p("Clot kinetics to 20 mm",CELL), p("1–3 min",CELLC),
p("↑ Low fibrinogen / platelets → Cryo",CELL)],
[p("α angle",CELLB), p("Rate of fibrin crosslinking",CELL), p("53–72°",CELLC),
p("↓ Fibrinogen deficiency → Cryo/FibC\n↑ Hypercoagulable",CELL)],
[p("MA",CELLB), p("Max clot strength\n(~80% plt, ~20% fibrinogen)",CELL), p("50–70 mm",CELLC),
p("↓ Plt dysfunction / low count → Platelets",CELL)],
[p("LY30",CELLB), p("% amplitude loss at 30 min",CELL), p("<7.5%",CELLC),
p("↑>7.5%: Hyperfibrinolysis → TXA / EACA",CELL)],
[p("EPL",CELLB), p("Estimated % lysis (earlier)",CELL), p("<15%",CELLC),
p("↑ Earlier fibrinolysis signal",CELL)],
[p("CI",CELLB), p("Composite index",CELL), p("−3 to+3",CELLC),
p("<−3 hypocoag | >+3 hypercoag",CELL)],
]
elems.append(mk_table(teg_rows, [c1,c2,c3,c4], hdr_color=TEAL)); elems.append(sp(4))
# ROTEM equivalents
elems.append(banner_row("ROTEM EQUIVALENTS & REAGENTS", NAVY, IW)); elems.append(sp(1))
ra,rb,rc,rd = 1.2*cm, 1.2*cm, 3.0*cm, IW - 1.2*cm - 1.2*cm - 3.0*cm
rotem_hdr = [p("TEG",HDR), p("ROTEM",HDR), p("Reagent(s)",HDR), p("Tests",HDR)]
rotem_rows = [rotem_hdr,
[p("R time",CELLB), p("CT",CELLBC), p("EXTEM / INTEM",CELL), p("Extrinsic / Intrinsic factors",CELL)],
[p("K time",CELLB), p("CFT",CELLBC), p("EXTEM / INTEM",CELL), p("Fibrinogen + platelet kinetics",CELL)],
[p("α",CELLB), p("α angle",CELLBC),p("EXTEM / FIBTEM",CELL), p("Fibrinogen contribution",CELL)],
[p("MA",CELLB), p("MCF",CELLBC), p("EXTEM/INTEM/FIBTEM",CELL), p("Clot strength (plt + fibrinogen)",CELL)],
[p("LY30",CELLB), p("LI30/ML",CELLBC),p("EXTEM ± APTEM",CELL), p("Fibrinolysis (APTEM confirms)",CELL)],
]
elems.append(mk_table(rotem_rows, [ra,rb,rc,rd])); elems.append(sp(2))
# Reagent key
rkw = IW/4
rk = Table([
[p("EXTEM",S("e",fontName="Helvetica-Bold",fontSize=7,textColor=RED,alignment=TA_CENTER)),
p("Tissue factor → extrinsic",SMALL),
p("INTEM",S("i",fontName="Helvetica-Bold",fontSize=7,textColor=TEAL,alignment=TA_CENTER)),
p("Ellagic acid → intrinsic",SMALL)],
[p("FIBTEM",S("f",fontName="Helvetica-Bold",fontSize=7,textColor=GREEN,alignment=TA_CENTER)),
p("EXTEM + cytoD → fibrinogen only",SMALL),
p("APTEM",S("a",fontName="Helvetica-Bold",fontSize=7,textColor=AMBER,alignment=TA_CENTER)),
p("EXTEM + aprotinin → confirms lysis",SMALL)],
], colWidths=[rkw*0.55, rkw*1.45, rkw*0.55, rkw*1.45])
rk.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1),LGREY),("GRID",(0,0),(-1,-1),0.3,MID),
("TOPPADDING",(0,0),(-1,-1),2),("BOTTOMPADDING",(0,0),(-1,-1),2),
("LEFTPADDING",(0,0),(-1,-1),3),("RIGHTPADDING",(0,0),(-1,-1),3),
("VALIGN",(0,0),(-1,-1),"MIDDLE"),
]))
elems.append(rk); elems.append(sp(4))
elems.append(p("Orris Medical AI | July 2026 | Side A — Parameters | Print on A4 landscape · cut · laminate", FOOT))
return elems
# ══════════════════════════════════════════════════════════════════════════════
# SIDE B flowables
# ══════════════════════════════════════════════════════════════════════════════
def side_b_flowables(W):
elems = []
IW = W - 2*PAD
title = Table([[p("TEG / ROTEM GOAL-DIRECTED ALGORITHM — THEATRE CARD", TITLE)]], colWidths=[W])
title.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), NAVY),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING",(0,0),(-1,-1), 5),
]))
elems.append(title); elems.append(sp(3))
# Algorithm
elems.append(banner_row("INTERPRETATION → INTERVENTION", TEAL, IW)); elems.append(sp(1))
aa,ab,ac,ad,ae = 3.0*cm, 2.8*cm, 1.5*cm, 2.4*cm, IW - 3.0*cm - 2.8*cm - 1.5*cm - 2.4*cm
alg_hdr = [p("VHA Finding",HDR), p("Likely Defect",HDR), p("TEG",HDR), p("ROTEM",HDR), p("Give →",HDR)]
alg_rows = [alg_hdr,
[p("Prolonged R time/CT",CELLB), p("Factor deficiency\nor anticoagulant",CELL),
p("R ↑",CELLBC), p("CT ↑",CELLBC), p("FFP or\nPCC/FibC",CELLB)],
[p("Prolonged K/CFT\n+ Reduced α",CELLB), p("Fibrinogen\ndeficiency",CELL),
p("K ↑\nα ↓",CELLBC), p("CFT ↑\nFIBTEM MCF ↓",CELLBC), p("Cryo or\nFibrinogen Conc.",CELLB)],
[p("Reduced MA/MCF\n(normal α)",CELLB), p("Platelet dysfunction\nor ↓ count",CELL),
p("MA ↓",CELLBC), p("EXTEM MCF ↓\nFIBTEM normal",CELLBC), p("Platelet\nTransfusion",CELLB)],
[p("↑ LY30 / LI30\nor ML",CELLB), p("Hyperfibrinolysis",CELL),
p("LY30\n>7.5%",CELLBC), p("LI30 <85%\nAPTEM MCF ↑",CELLBC), p("TXA 1g IV\nor EACA",CELLB)],
[p("MA ↓ + α ↓\n+ K ↑ (combined)",CELLB), p("Mixed fibrinogen\n+ platelet deficit",CELL),
p("Multiple\nabnormal",CELLBC), p("EXTEM+FIBTEM\nboth low",CELLBC), p("Cryo FIRST\nthen Platelets",CELLB)],
[p("Short R / CI >+3",CELLB), p("Hypercoagulable",CELL),
p("R ↓\nCI >+3",CELLBC), p("CT ↓",CELLBC), p("Anticoag\n(context-dep.)",CELLB)],
]
row_bgs = [None, GREEN_LT, AMBER_LT, RED_LT, PURPLE_LT, HexColor("#e8f0fe"), LGREY]
elems.append(mk_table(alg_rows, [aa,ab,ac,ad,ae], row_bgs=row_bgs, hdr_color=TEAL))
elems.append(sp(4))
# Drug effects
elems.append(banner_row("DRUG & CONDITION EFFECTS ON VHA", NAVY, IW)); elems.append(sp(1))
da,db,dc = 2.5*cm, 3.0*cm, IW - 2.5*cm - 3.0*cm
drug_hdr = [p("Drug / Condition",HDR), p("Effect",HDR), p("Key Parameter(s) Affected",HDR)]
drug_rows = [drug_hdr,
[p("Heparin (UFH)",CELLB), p("Prolongs enzymatic phase",CELL), p("↑ R time/CT — INTEM most sensitive",CELL)],
[p("Warfarin/VKA",CELLB), p("Impairs initiation",CELL), p("↑ R time/CT — EXTEM sensitive",CELL)],
[p("DOACs",CELLB), p("Variable R time prolongation",CELL), p("Drug-specific assays often needed",CELL)],
[p("Aspirin/NSAIDs",CELLB), p("Platelet dysfunction",CELL), p("↓ MA/MCF — use platelet mapping",CELL)],
[p("P2Y12 inhibitors",CELLB), p("↓ platelet aggregation",CELL), p("↓ MA/MCF — ADP mapping assay",CELL)],
[p("TXA / EACA",CELLB), p("Anti-fibrinolytic",CELL), p("↓ LY30/LI30 — normalises if elevated",CELL)],
[p("Hypothermia <35°C",CELLB), p("Slows all enzymatic steps",CELL),p("↑ R, K · ↓ MA ⚠ TEG runs at 37°C — underestimates effect!",CELL)],
[p("Acute DIC",CELLB), p("Consumption + fibrinolysis",CELL),p("↑↑ R + K · ↓↓ α, MA · ↑↑ LY30",CELL)],
]
elems.append(mk_table(drug_rows, [da,db,dc])); elems.append(sp(3))
# Lethal triad + contexts
half = IW / 2
triad_data = [
[p("LETHAL TRIAD IN HAEMORRHAGE",
S("lt",fontName="Helvetica-Bold",fontSize=7,textColor=WHITE,alignment=TA_CENTER)),
p("CLINICAL CONTEXTS (strongest → emerging)",
S("lc",fontName="Helvetica-Bold",fontSize=7,textColor=WHITE,alignment=TA_CENTER))],
[p("🌡 <b>Hypothermia</b> <35°C\n— impairs enzymatic clotting & platelet function\n\n"
"⚗ <b>Acidosis</b> pH <7.2\n— disrupts factor and platelet environment\n\n"
"🩸 <b>Haemodilution</b>\n— dilutes factors and platelets\n\n"
"<i>Synergistic — TEG/ROTEM-guided correction superior\nto empiric 1:1:1 FFP:Plt:pRBC</i>",
S("tri",fontName="Helvetica",fontSize=7,textColor=black,leading=10,alignment=TA_LEFT)),
p("<b>1.</b> Cardiac surgery (strongest RCT evidence)\n"
"<b>2.</b> Major trauma / TIC\n"
"<b>3.</b> Liver transplantation (hyperfibrinolysis)\n"
"<b>4.</b> Obstetric PPH\n"
"<b>5.</b> Neurosurgery (hypercoag detection)\n"
"<b>6.</b> Massive transfusion protocol guidance\n\n"
"<i>⚠ TEG ≠ ROTEM — not interchangeable.\nUse institution-specific reference ranges.</i>",
S("ctx",fontName="Helvetica",fontSize=7,textColor=black,leading=10,alignment=TA_LEFT))],
]
triad_t = Table(triad_data, colWidths=[half, half])
triad_t.setStyle(TableStyle([
("BACKGROUND",(0,0),(0,0), RED), ("BACKGROUND",(1,0),(1,0), GREEN),
("BACKGROUND",(0,1),(0,1), RED_LT),("BACKGROUND",(1,1),(1,1), GREEN_LT),
("GRID",(0,0),(-1,-1),0.4,MID),
("TOPPADDING",(0,0),(-1,-1),3),("BOTTOMPADDING",(0,0),(-1,-1),3),
("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5),
("VALIGN",(0,0),(-1,-1),"TOP"),
]))
elems.append(triad_t); elems.append(sp(3))
elems.append(p(
"Evidence: Cochrane 2026 (35 RCTs, n=3096): TEG/ROTEM may ↓ mortality RR 0.76 (95%CI 0.63–0.92) and ↓ FFP/plt use — very low certainty | "
"Orris Medical AI | July 2026 | Side B — Algorithm | PMID 42145275",
FOOT))
return elems
# ══════════════════════════════════════════════════════════════════════════════
# RENDER using Frames placed on canvas
# ══════════════════════════════════════════════════════════════════════════════
def build():
c = pdfcanvas.Canvas(OUTPUT, pagesize=landscape(A4))
c.setTitle("TEG/ROTEM Quick Reference Theatre Card")
c.setAuthor("Orris Medical AI")
# Thin separator line
c.setStrokeColor(MID)
c.setLineWidth(0.5)
c.line(PW/2, 4, PW/2, PH - 4)
# Frame A — left panel
fA = Frame(0, 0, PANEL_W, PANEL_H,
leftPadding=PAD, rightPadding=PAD,
topPadding=PAD, bottomPadding=PAD,
showBoundary=0)
fA.addFromList(side_a_flowables(PANEL_W), c)
# Frame B — right panel
fB = Frame(PANEL_W + GUTTER, 0, PANEL_W, PANEL_H,
leftPadding=PAD, rightPadding=PAD,
topPadding=PAD, bottomPadding=PAD,
showBoundary=0)
fB.addFromList(side_b_flowables(PANEL_W), c)
c.save()
print(f"Card saved: {OUTPUT}")
if __name__ == "__main__":
build()
cat > /home/daytona/workspace/coagulation-teg/build_card.py << 'PYEOF' #!/usr/bin/env python3 """ TEG / ROTEM Quick-Reference Laminated Card — Theatre Use Two A5-landscape panels on one A4-landscape page via canvas Frames. """ import io, requests from reportlab.lib.pagesizes import A4, landscape from reportlab.lib.units import cm from reportlab.lib.colors import HexColor, white, black from reportlab.lib.styles import ParagraphStyle from reportlab.lib.enums import TA_CENTER, TA_LEFT from reportlab.platypus import Table, TableStyle, Paragraph, Spacer, Image, Frame from reportlab.pdfgen import canvas as pdfcanvas OUTPUT = "/home/daytona/workspace/coagulation-teg/TEG_ROTEM_Theatre_Card.pdf" PW, PH = landscape(A4) GUTTER = 6 PAD = 5 PANEL_W = (PW - GUTTER) / 2 PANEL_H = PH NAVY=HexColor("#1a2e4a"); TEAL=HexColor("#0d6e7e"); TEAL_LT=HexColor("#dff0f3") GREEN=HexColor("#1a6b3c"); GREEN_LT=HexColor("#d4edda") RED=HexColor("#8b1a1a"); RED_LT=HexColor("#fde8e8") AMBER=HexColor("#7a4f00"); AMBER_LT=HexColor("#fff3cd") PURPLE_LT=HexColor("#ede0f7"); GREY=HexColor("#555555") LGREY=HexColor("#f5f5f5"); MID=HexColor("#cccccc"); WHITE=white def S(name,**kw): return ParagraphStyle(name,**kw) TITLE=S("TI",fontName="Helvetica-Bold",fontSize=10,textColor=WHITE,alignment=TA_CENTER,leading=13) SECT =S("SE",fontName="Helvetica-Bold",fontSize=8, textColor=WHITE,alignment=TA_CENTER,leading=11) HDR =S("HD",fontName="Helvetica-Bold",fontSize=7, textColor=WHITE,alignment=TA_CENTER,leading=9) CELL =S("CL",fontName="Helvetica", fontSize=7, textColor=black,alignment=TA_LEFT, leading=9) CELLC=S("CC",fontName="Helvetica", fontSize=7, textColor=black,alignment=TA_CENTER,leading=9) CELLB=S("CB",fontName="Helvetica-Bold",fontSize=7, textColor=black,alignment=TA_LEFT, leading=9) CELLBC=S("CBC",fontName="Helvetica-Bold",fontSize=7,textColor=black,alignment=TA_CENTER,leading=9) SMALL=S("SM",fontName="Helvetica", fontSize=6, textColor=GREY, alignment=TA_CENTER,leading=8) FOOT =S("FT",fontName="Helvetica-Oblique",fontSize=5.5,textColor=GREY,alignment=TA_CENTER,leading=7) p = lambda t,s: Paragraph(t,s) sp = lambda h=2: Spacer(1,h) def fetch_img(url, w_pt, max_h_pt=None): try: r=requests.get(url,timeout=12); r.raise_for_status() buf=io.BytesIO(r.content); img=Image(buf) aspect=img.imageHeight/float(img.imageWidth) h=w_pt*aspect if max_h_pt and h>max_h_pt: h=max_h_pt; w_pt=h/aspect img.drawWidth=w_pt; img.drawHeight=h; return img except Exception as e: print(f" [warn] {e}"); return None def banner(txt, color, W): t=Table([[p(txt,SECT)]],colWidths=[W]) t.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),color), ("TOPPADDING",(0,0),(-1,-1),3),("BOTTOMPADDING",(0,0),(-1,-1),3), ("LEFTPADDING",(0,0),(-1,-1),4),("RIGHTPADDING",(0,0),(-1,-1),4)])) return t def mktbl(rows,cw,row_bgs=None,hc=NAVY): t=Table(rows,colWidths=cw,repeatRows=1) sty=[("BACKGROUND",(0,0),(-1,0),hc),("GRID",(0,0),(-1,-1),0.4,MID), ("TOPPADDING",(0,0),(-1,-1),2),("BOTTOMPADDING",(0,0),(-1,-1),2), ("LEFTPADDING",(0,0),(-1,-1),3),("RIGHTPADDING",(0,0),(-1,-1),3), ("VALIGN",(0,0),(-1,-1),"MIDDLE")] if row_bgs: for i,bg in enumerate(row_bgs,1): if bg: sty.append(("BACKGROUND",(0,i),(-1,i),bg)) else: sty.append(("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE,LGREY])) t.setStyle(TableStyle(sty)); return t def side_a(W): E=[]; IW=W-2*PAD ttl=Table([[p("TEG / ROTEM QUICK REFERENCE — THEATRE CARD",TITLE)]],colWidths=[W]) ttl.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),NAVY), ("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5)])) E.append(ttl); E.append(sp(3)) img=fetch_img("https://cdn.orris.care/cdss_images/0b1425cf1a93207225bb92d1d44f5ea59473ea214e1210004b631d11c938aa87.png", w_pt=IW*0.76,max_h_pt=78) if img: iw=Table([[img]],colWidths=[IW]) iw.setStyle(TableStyle([("ALIGN",(0,0),(-1,-1),"CENTER"),("VALIGN",(0,0),(-1,-1),"MIDDLE"), ("TOPPADDING",(0,0),(-1,-1),0),("BOTTOMPADDING",(0,0),(-1,-1),0)])) E.append(iw); E.append(p("R time · K time · α angle · MA · LY30 · EPL",SMALL)); E.append(sp(3)) E.append(banner("TEG PARAMETERS",TEAL,IW)); E.append(sp(1)) c1,c2,c3,c4=1.4*cm,3.8*cm,1.4*cm,IW-1.4*cm-3.8*cm-1.4*cm rows=[ [p("Param",HDR),p("Definition",HDR),p("Normal",HDR),p("↑/↓ Meaning & Action",HDR)], [p("R time",CELLB),p("First clot (2 mm amplitude)",CELL),p("5–10 min",CELLC),p("↑ Factor deficiency/anticoag → FFP/PCC\n↓ Hypercoagulable",CELL)], [p("K time",CELLB),p("Time to 20 mm amplitude",CELL),p("1–3 min",CELLC),p("↑ Low fibrinogen/platelets → Cryo",CELL)], [p("α angle",CELLB),p("Rate of fibrin crosslinking",CELL),p("53–72°",CELLC),p("↓ Fibrinogen deficiency → Cryo/FibC\n↑ Hypercoagulable",CELL)], [p("MA",CELLB),p("Max clot strength\n(~80% plt, ~20% fibrinogen)",CELL),p("50–70 mm",CELLC),p("↓ Platelet dysfunction/low count → Platelets",CELL)], [p("LY30",CELLB),p("% amplitude loss at 30 min",CELL),p("<7.5%",CELLC),p("↑>7.5%: Hyperfibrinolysis → TXA/EACA",CELL)], [p("EPL",CELLB),p("Estimated % lysis (earlier signal)",CELL),p("<15%",CELLC),p("↑ Earlier fibrinolysis detection",CELL)], [p("CI",CELLB),p("Composite index",CELL),p("−3 to+3",CELLC),p("<−3 hypocoag | >+3 hypercoag",CELL)], ] E.append(mktbl(rows,[c1,c2,c3,c4],hc=TEAL)); E.append(sp(4)) E.append(banner("ROTEM EQUIVALENTS & REAGENTS",NAVY,IW)); E.append(sp(1)) ra,rb,rc,rd=1.2*cm,1.2*cm,3.0*cm,IW-1.2*cm-1.2*cm-3.0*cm r2=[ [p("TEG",HDR),p("ROTEM",HDR),p("Reagent(s)",HDR),p("Tests",HDR)], [p("R time",CELLB),p("CT",CELLBC),p("EXTEM / INTEM",CELL),p("Extrinsic / Intrinsic factors",CELL)], [p("K time",CELLB),p("CFT",CELLBC),p("EXTEM / INTEM",CELL),p("Fibrinogen + platelet kinetics",CELL)], [p("α",CELLB),p("α angle",CELLBC),p("EXTEM / FIBTEM",CELL),p("Fibrinogen contribution",CELL)], [p("MA",CELLB),p("MCF",CELLBC),p("EXTEM/INTEM/FIBTEM",CELL),p("Clot strength (plt + fibrinogen)",CELL)], [p("LY30",CELLB),p("LI30/ML",CELLBC),p("EXTEM ± APTEM",CELL),p("Fibrinolysis (APTEM confirms)",CELL)], ] E.append(mktbl(r2,[ra,rb,rc,rd])); E.append(sp(2)) qw=IW/4 rk=Table([ [p("EXTEM",S("ex",fontName="Helvetica-Bold",fontSize=7,textColor=RED,alignment=TA_CENTER)), p("Tissue factor → extrinsic",SMALL), p("INTEM",S("in",fontName="Helvetica-Bold",fontSize=7,textColor=TEAL,alignment=TA_CENTER)), p("Ellagic acid → intrinsic",SMALL)], [p("FIBTEM",S("fi",fontName="Helvetica-Bold",fontSize=7,textColor=GREEN,alignment=TA_CENTER)), p("EXTEM + cytoD → fibrinogen only",SMALL), p("APTEM",S("ap",fontName="Helvetica-Bold",fontSize=7,textColor=AMBER,alignment=TA_CENTER)), p("EXTEM + aprotinin → confirm lysis",SMALL)], ],colWidths=[qw*0.55,qw*1.45,qw*0.55,qw*1.45]) rk.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),LGREY),("GRID",(0,0),(-1,-1),0.3,MID), ("TOPPADDING",(0,0),(-1,-1),2),("BOTTOMPADDING",(0,0),(-1,-1),2), ("LEFTPADDING",(0,0),(-1,-1),3),("RIGHTPADDING",(0,0),(-1,-1),3), ("VALIGN",(0,0),(-1,-1),"MIDDLE")])) E.append(rk); E.append(sp(4)) E.append(p("Orris Medical AI | July 2026 | Side A — Parameters | Print A4 landscape · cut · laminate",FOOT)) return E def side_b(W): E=[]; IW=W-2*PAD ttl=Table([[p("TEG / ROTEM GOAL-DIRECTED ALGORITHM — THEATRE CARD",TITLE)]],colWidths=[W]) ttl.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),NAVY), ("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5)])) E.append(ttl); E.append(sp(3)) E.append(banner("INTERPRETATION → INTERVENTION",TEAL,IW)); E.append(sp(1)) aa,ab,ac,ad,ae=3.0*cm,2.8*cm,1.4*cm,2.4*cm,IW-3.0*cm-2.8*cm-1.4*cm-2.4*cm alg=[ [p("VHA Finding",HDR),p("Likely Defect",HDR),p("TEG",HDR),p("ROTEM",HDR),p("Give →",HDR)], [p("Prolonged R time/CT",CELLB),p("Factor deficiency\nor anticoagulant",CELL),p("R ↑",CELLBC),p("CT ↑",CELLBC),p("FFP or\nPCC/FibC",CELLB)], [p("Prolonged K/CFT\n+ Reduced α",CELLB),p("Fibrinogen\ndeficiency",CELL),p("K ↑\nα ↓",CELLBC),p("CFT ↑\nFIBTEM MCF ↓",CELLBC),p("Cryo or\nFibrinogen Conc.",CELLB)], [p("Reduced MA/MCF\n(normal α)",CELLB),p("Platelet dysfunction\nor ↓ count",CELL),p("MA ↓",CELLBC),p("EXTEM MCF ↓\nFIBTEM normal",CELLBC),p("Platelet\nTransfusion",CELLB)], [p("↑ LY30/LI30 or ML",CELLB),p("Hyperfibrinolysis",CELL),p("LY30\n>7.5%",CELLBC),p("LI30 <85%\nAPTEM MCF ↑",CELLBC),p("TXA 1g IV\nor EACA",CELLB)], [p("MA ↓ + α ↓ + K ↑",CELLB),p("Mixed fibrinogen\n+ platelet deficit",CELL),p("Multiple\nabnormal",CELLBC),p("EXTEM+FIBTEM\nboth low",CELLBC),p("Cryo FIRST\nthen Platelets",CELLB)], [p("Short R / CI >+3",CELLB),p("Hypercoagulable",CELL),p("R ↓\nCI >+3",CELLBC),p("CT ↓",CELLBC),p("Anticoag\n(context-dep.)",CELLB)], ] bgs=[None,GREEN_LT,AMBER_LT,RED_LT,PURPLE_LT,HexColor("#e8f0fe"),LGREY] E.append(mktbl(alg,[aa,ab,ac,ad,ae],row_bgs=bgs,hc=TEAL)); E.append(sp(4)) E.append(banner("DRUG & CONDITION EFFECTS ON VHA",NAVY,IW)); E.append(sp(1)) da,db,dc=2.5*cm,3.0*cm,IW-2.5*cm-3.0*cm drugs=[ [p("Drug / Condition",HDR),p("Effect",HDR),p("Key Parameter(s) Affected",HDR)], [p("Heparin (UFH)",CELLB),p("Prolongs enzymatic phase",CELL),p("↑ R time/CT — INTEM most sensitive",CELL)], [p("Warfarin/VKA",CELLB),p("Impairs initiation",CELL),p("↑ R time/CT — EXTEM sensitive",CELL)], [p("DOACs",CELLB),p("Variable R time prolongation",CELL),p("Drug-specific assays often needed",CELL)], [p("Aspirin/NSAIDs",CELLB),p("Platelet dysfunction",CELL),p("↓ MA/MCF — use platelet mapping",CELL)], [p("P2Y12 inhibitors",CELLB),p("↓ platelet aggregation",CELL),p("↓ MA/MCF — ADP mapping assay",CELL)], [p("TXA / EACA",CELLB),p("Anti-fibrinolytic",CELL),p("↓ LY30/LI30 — normalises if elevated",CELL)], [p("Hypothermia <35°C",CELLB),p("Slows enzymatic reactions",CELL),p("↑ R, K · ↓ MA ⚠ TEG at 37°C underestimates!",CELL)], [p("Acute DIC",CELLB),p("Consumption + fibrinolysis",CELL),p("↑↑ R+K · ↓↓ α, MA · ↑↑ LY30",CELL)], ] E.append(mktbl(drugs,[da,db,dc])); E.append(sp(3)) half=IW/2 triad=Table([ [p("LETHAL TRIAD IN HAEMORRHAGE",S("lt",fontName="Helvetica-Bold",fontSize=7,textColor=WHITE,alignment=TA_CENTER)), p("CLINICAL CONTEXTS (strongest→emerging)",S("lc",fontName="Helvetica-Bold",fontSize=7,textColor=WHITE,alignment=TA_CENTER))], [p("<b>Hypothermia</b> <35°C — impairs enzymatic clotting + platelet fx\n\n" "<b>Acidosis</b> pH <7.2 — disrupts factor + platelet environment\n\n" "<b>Haemodilution</b> — dilutes factors and platelets\n\n" "<i>All three synergistic. VHA-guided correction\nsuperior to empiric 1:1:1 FFP:Plt:pRBC.</i>", S("tri",fontName="Helvetica",fontSize=7,textColor=black,leading=10,alignment=TA_LEFT)), p("<b>1.</b> Cardiac surgery (strongest RCT evidence)\n" "<b>2.</b> Major trauma / TIC\n" "<b>3.</b> Liver transplantation (hyperfibrinolysis)\n" "<b>4.</b> Obstetric PPH\n" "<b>5.</b> Neurosurgery (hypercoag detection)\n" "<b>6.</b> Massive transfusion protocol guidance\n\n" "<i>⚠ TEG ≠ ROTEM — not interchangeable.\nUse institution-specific reference ranges.</i>", S("ctx",fontName="Helvetica",fontSize=7,textColor=black,leading=10,alignment=TA_LEFT))], ],colWidths=[half,half]) triad.setStyle(TableStyle([ ("BACKGROUND",(0,0),(0,0),RED),("BACKGROUND",(1,0),(1,0),GREEN), ("BACKGROUND",(0,1),(0,1),RED_LT),("BACKGROUND",(1,1),(1,1),GREEN_LT), ("GRID",(0,0),(-1,-1),0.4,MID), ("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4), ("LEFTPADDING",(0,0),(-1,-1),5),("RIGHTPADDING",(0,0),(-1,-1),5), ("VALIGN",(0,0),(-1,-1),"TOP")])) E.append(triad); E.append(sp(3)) E.append(p("Evidence: Cochrane 2026 (35 RCTs, n=3096): TEG/ROTEM may ↓ mortality RR 0.76 (95%CI 0.63–0.92) & ↓ FFP/plt use — very low certainty | Orris Medical AI | July 2026 | Side B — Algorithm | PMID 42145275",FOOT)) return E def build(): c=pdfcanvas.Canvas(OUTPUT,pagesize=landscape(A4)) c.setTitle("TEG/ROTEM Quick Reference Theatre Card") c.setAuthor("Orris Medical AI") c.setStrokeColor(MID); c.setLineWidth(0.5) c.line(PW/2,4,PW/2,PH-4) fA=Frame(0,0,PANEL_W,PANEL_H,leftPadding=PAD,rightPadding=PAD,topPadding=PAD,bottomPadding=PAD,showBoundary=0) fA.addFromList(side_a(PANEL_W),c) fB=Frame(PANEL_W+GUTTER,0,PANEL_W,PANEL_H,leftPadding=PAD,rightPadding=PAD,topPadding=PAD,bottomPadding=PAD,showBoundary=0) fB.addFromList(side_b(PANEL_W),c) c.save() print(f"Card saved: {OUTPUT}") if __name__=="__main__": build() PYEOF echo "written"
cd /home/daytona/workspace/coagulation-teg && python3 build_card.py 2>&1
ls -lh /home/daytona/workspace/coagulation-teg/TEG_ROTEM_Theatre_Card.pdf
TEG ROTEM Theatre Card
PDF Document · PDF
Generate a 30 marks answer for Postgraduate Anaesthesia exam on the topic of Ultrasound in Anaesthesia with diagrams
ultrasound guided regional anesthesia outcomes
Wave speed (c) = Frequency (f) × Wavelength (λ)
| Term | Appearance | Example |
|---|---|---|
| Hyperechoic | Bright white | Bone cortex, needle, fascia |
| Hypoechoic | Dark grey | Muscle, nerve, solid organ |
| Anechoic | Black | Fluid (blood, urine, effusion) |
| Isoechoic | Same as surrounding tissue | Thrombus (fresh) |
| Mode | Description | Clinical Use in Anaesthesia |
|---|---|---|
| B-mode (2D) | Brightness-based greyscale cross-section | Standard imaging for all procedures |
| M-mode | Single-line motion over time | Lung sliding ("seashore sign"), IVC diameter |
| Colour Doppler | Direction and velocity of flow (colour-coded) | Distinguish vein from artery |
| Pulsed wave Doppler | Flow velocity at a specific depth | Cardiac output, stenosis grading |
| Power Doppler | Sensitive low-flow detection | Confirm vessel patency |
| Artefact | Cause | Significance |
|---|---|---|
| Acoustic shadowing | Bone/air blocks beam | Confirms calcification or gas |
| Posterior acoustic enhancement | Fluid transmits beam | Confirms fluid-filled structure |
| Reverberation / A-lines | Repeated reflections between two surfaces | Normal lung; horizontal bright parallel lines |
| B-lines (comet tail) | Fluid in interlobular septa | Pulmonary oedema, ARDS |
| Mirror artefact | Strong reflector duplicates image | Diaphragm-liver interface |
| Anisotropy | Angle-dependent reflectance of tendons/nerves | Nerve appears less echogenic off-axis |
| Feature | Nerve Stimulator | Ultrasound Guided |
|---|---|---|
| Real-time visualisation | No | Yes |
| Needle-nerve relationship | Indirect (electrical) | Direct visual |
| Local anaesthetic spread | Not seen | Visualised in real time |
| Intravascular injection detection | No | Yes (Doppler) |
| Intraneural injection warning | No | Yes (nerve swelling) |
| Deep block accuracy | Variable | Improved |
| Effectiveness in patients with neuropathy | Reduced | Maintained |
| View | Probe Position | Structures Assessed |
|---|---|---|
| Parasternal long axis (PLAX) | Left parasternal, 3rd/4th ICS | LV size, wall motion, MV, AV, pericardial effusion |
| Parasternal short axis (PSAX) | Left parasternal, rotated 90° | LV end-diastolic area, RV:LV ratio, wall motion |
| Apical 4-chamber | Cardiac apex | Biventricular size and function, valves, effusion |
| Subcostal 4-chamber | Subxiphoid | RV/LV, pericardial effusion (tamponade), IVC |
| IVC long axis | Subcostal | Volume status: IVC collapsibility >50% = hypovolaemia |


| Finding | Appearance | Significance |
|---|---|---|
| A-lines | Horizontal regularly spaced bright lines | Normal lung - aeration present |
| Lung sliding | Shimmering motion at pleural line | Pleural surfaces in apposition (normal) |
| B-lines ("rockets") | Vertical comet-tail artefacts reaching screen edge | Interstitial fluid: pulmonary oedema, ARDS |
| Lung point | Transition between sliding and non-sliding | Highly specific for pneumothorax |
| Absent lung sliding | No pleural movement | Pneumothorax, apnoea, mainstem intubation |
| "Seashore sign" (M-mode) | Granular pattern below pleural line | Normal lung sliding present |
| "Barcode sign" (M-mode) | Parallel lines throughout | Pneumothorax (absent lung sliding) |


Gastric volume (mL) = 27.0 + 14.6 × right-lateral CSA − 1.28 × age
| Application | Probe | Frequency | Key Benefit |
|---|---|---|---|
| Central venous access (IJV) | Linear | 10-15 MHz | ↓ arterial puncture, ↓ pneumothorax |
| Arterial cannulation | Linear | 10-15 MHz | ↑ first-attempt success |
| Nerve blocks (superficial) | Linear | 10-15 MHz | Direct visualisation, ↓ LAST |
| Nerve blocks (deep - e.g., femoral) | Curved/Linear | 5-10 MHz | Depth penetration |
| Cardiac (FoCUS/TOE) | Phased array | 2-5 MHz | Haemodynamic assessment |
| Lung | Curved/Linear | 2-10 MHz | Pneumothorax, effusion, oedema |
| Gastric assessment | Curved | 2-5 MHz | Aspiration risk |
| Airway/CTM | Linear | 10-15 MHz | FONA planning |
Write a 30 marks answer for Postgraduate Anaesthesia exam on the topic of Capnography and Capnometry