Hi

Hi! How can I help you today?

Creatinine based ckd epi formula

Reading File
Searching the Web

CKD-EPI 2021 creatinine formula eGFR equation race-free

CKD-EPI 2021 Creatinine Equation (Race-Free)

The CKD-EPI 2021 is the current standard for estimating GFR from serum creatinine, recommended by both the National Kidney Foundation and American Society of Nephrology. It removed the racial coefficient that was present in the 2009 version.

The Formula

eGFR = 142 × min(Scr/κ, 1)^α × max(Scr/κ, 1)^-1.200 × 0.9938^Age × 1.012 [if female]
Where:
ParameterFemaleMale
κ (kappa)0.70.9
α (alpha)-0.241-0.302
  • Scr = standardized serum creatinine in mg/dL
  • Age = in years (≥18)
  • min(Scr/κ, 1) = the lesser of Scr/κ or 1
  • max(Scr/κ, 1) = the greater of Scr/κ or 1

In SI Units (µmol/L)

For labs reporting creatinine in µmol/L, divide by 88.4 to convert, or use the equivalent κ values:
  • Female: κ = 61.9 µmol/L
  • Male: κ = 79.6 µmol/L
AgeSexScr (µmol/L)Equation
≥18Female≤61.9142 × (Scr/61.88)^-0.241 × 0.9938^Age × 1.012
≥18Female>61.9142 × (Scr/61.88)^-1.200 × 0.9938^Age × 1.012
≥18Male≤79.6142 × (Scr/79.56)^-0.302 × 0.9938^Age
≥18Male>79.6142 × (Scr/79.56)^-1.200 × 0.9938^Age

Key Points

  • Result units: mL/min/1.73 m²
  • Age range: Adults ≥18 years only
  • No race variable - the 2021 revision eliminated the Black race multiplier (1.159) present in CKD-EPI 2009
  • Why 142? This is the scaling factor derived from the refitted dataset
  • 0.9938^Age accounts for the natural decline in GFR with aging
  • The 2021 equation tends to give slightly higher eGFR values than the old non-Black version of CKD-EPI 2009

Comparison with Older Equations

EquationRace factorNotes
MDRD (4-variable)Yes (Black)Underestimates when eGFR >60
CKD-EPI 2009Yes (Black)More accurate than MDRD at higher GFR
CKD-EPI 2021NoCurrent standard; same variables, refitted data
The original 2021 paper by Inker et al. demonstrated that this race-free equation maintains similar overall performance while removing a socially constructed variable from clinical decision-making.

Create a calculator tool or reference card for CKD-EPI 2021

Asking for Preferences
Reading File
Running Command

mkdir -p /tmp/workspace/ckd-epi-card && ls /tmp/workspace/

Writing File

~/ckd-epi-card/create_card.py

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.platypus import (
    SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer,
    HRFlowable, KeepTogether
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
import math

OUTPUT = "/tmp/workspace/ckd-epi-card/CKD-EPI_2021_Reference_Card.pdf"

# ── Colour palette ──────────────────────────────────────────────────────────
NAVY     = colors.HexColor("#1a3560")
TEAL     = colors.HexColor("#0e7490")
LTBLUE   = colors.HexColor("#e0f2fe")
MNTEAL   = colors.HexColor("#ccf5f8")
GOLD     = colors.HexColor("#f59e0b")
LGRAY    = colors.HexColor("#f1f5f9")
MGRAY    = colors.HexColor("#cbd5e1")
DKGRAY   = colors.HexColor("#334155")
WHITE    = colors.white
RED      = colors.HexColor("#dc2626")
AMBER    = colors.HexColor("#d97706")
GREEN    = colors.HexColor("#16a34a")
LGREEN   = colors.HexColor("#dcfce7")
LAMBER   = colors.HexColor("#fef3c7")
LRED     = colors.HexColor("#fee2e2")
LLORANGE = colors.HexColor("#ffedd5")
ORANGE   = colors.HexColor("#ea580c")

doc = SimpleDocTemplate(
    OUTPUT,
    pagesize=A4,
    leftMargin=14*mm, rightMargin=14*mm,
    topMargin=14*mm, bottomMargin=14*mm
)

styles = getSampleStyleSheet()
W = A4[0] - 28*mm   # usable width

def style(name="Normal", **kw):
    s = styles[name].clone(name + str(id(kw)))
    for k, v in kw.items():
        setattr(s, k, v)
    return s

# ── Helper: coloured header block ───────────────────────────────────────────
def section_header(text, bg=NAVY, fg=WHITE, size=11):
    data = [[Paragraph(f"<b>{text}</b>",
                       style(fontSize=size, textColor=fg, alignment=TA_LEFT,
                             leftIndent=4, spaceBefore=0, spaceAfter=0))]]
    t = Table(data, colWidths=[W])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), bg),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 8),
        ("RIGHTPADDING",  (0,0), (-1,-1), 8),
    ]))
    return t

def body(text, size=8.5, color=DKGRAY, indent=0, bold=False):
    tag = f"<b>{text}</b>" if bold else text
    return Paragraph(tag, style(fontSize=size, textColor=color,
                                leftIndent=indent, spaceBefore=1, spaceAfter=1))

# ═══════════════════════════════════════════════════════════════════════════
# BUILD STORY
# ═══════════════════════════════════════════════════════════════════════════
story = []

# ── TITLE BANNER ────────────────────────────────────────────────────────────
title_data = [[
    Paragraph("<b>CKD-EPI 2021</b>",
              style(fontSize=22, textColor=WHITE, alignment=TA_LEFT,
                    spaceBefore=0, spaceAfter=0)),
    Paragraph("eGFR from Serum Creatinine<br/><font size='9'>Race-Free Equation · Adults ≥ 18 years</font>",
              style(fontSize=12, textColor=LTBLUE, alignment=TA_RIGHT,
                    spaceBefore=0, spaceAfter=0)),
]]
title_tbl = Table(title_data, colWidths=[W*0.5, W*0.5])
title_tbl.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,-1), NAVY),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 10),
    ("BOTTOMPADDING", (0,0), (-1,-1), 10),
    ("LEFTPADDING",   (0,0), (-1,-1), 10),
    ("RIGHTPADDING",  (0,0), (-1,-1), 10),
]))
story.append(title_tbl)
story.append(Spacer(1, 5))

# ── FORMULA BOX ─────────────────────────────────────────────────────────────
story.append(section_header("  The Formula", bg=TEAL))
formula_text = (
    "eGFR = 142 × min(Scr / κ, 1)<sup rise='4' size='7'>α</sup> "
    "× max(Scr / κ, 1)<sup rise='4' size='7'>-1.200</sup> "
    "× 0.9938<sup rise='4' size='7'>Age</sup> "
    "× 1.012 <font color='#0e7490'>[if female]</font>"
)
formula_para = Paragraph(formula_text,
    style(fontSize=13, textColor=NAVY, alignment=TA_CENTER,
          spaceBefore=6, spaceAfter=6))
formula_box = Table([[formula_para]], colWidths=[W])
formula_box.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,-1), LTBLUE),
    ("BOX",        (0,0), (-1,-1), 1.2, TEAL),
    ("TOPPADDING",    (0,0), (-1,-1), 10),
    ("BOTTOMPADDING", (0,0), (-1,-1), 10),
]))
story.append(formula_box)
story.append(Spacer(1, 4))

# ── PARAMETERS TABLE ────────────────────────────────────────────────────────
story.append(section_header("  Parameters"))

param_header = [
    Paragraph("<b>Parameter</b>", style(fontSize=8.5, textColor=WHITE, alignment=TA_CENTER)),
    Paragraph("<b>Female</b>",    style(fontSize=8.5, textColor=WHITE, alignment=TA_CENTER)),
    Paragraph("<b>Male</b>",      style(fontSize=8.5, textColor=WHITE, alignment=TA_CENTER)),
    Paragraph("<b>Notes</b>",     style(fontSize=8.5, textColor=WHITE, alignment=TA_CENTER)),
]

def pc(txt, bold=False, align=TA_CENTER, size=8.5, color=DKGRAY):
    t = f"<b>{txt}</b>" if bold else txt
    return Paragraph(t, style(fontSize=size, textColor=color, alignment=align,
                               spaceBefore=2, spaceAfter=2))

param_rows = [
    param_header,
    [pc("κ (kappa)", bold=True), pc("0.7"), pc("0.9"),
     pc("Threshold: Scr below/above κ determines exponent", align=TA_LEFT)],
    [pc("α (alpha)", bold=True), pc("−0.241"), pc("−0.302"),
     pc("Exponent when Scr ≤ κ", align=TA_LEFT)],
    [pc("Scr", bold=True), pc("mg/dL", color=TEAL), pc("mg/dL", color=TEAL),
     pc("Standardized serum creatinine (IDMS-traceable)", align=TA_LEFT)],
    [pc("Age", bold=True), pc("years"), pc("years"),
     pc("Decimal years acceptable; adults ≥18 only", align=TA_LEFT)],
    [pc("Sex multiplier", bold=True), pc("× 1.012"), pc("× 1.000"),
     pc("Female sex assigned at birth adds 1.2% uplift", align=TA_LEFT)],
]

cw = [W*0.15, W*0.12, W*0.12, W*0.61]
param_tbl = Table(param_rows, colWidths=cw, repeatRows=1)
param_tbl.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), NAVY),
    ("BACKGROUND", (0,1), (-1,1), LGRAY),
    ("BACKGROUND", (0,2), (-1,2), WHITE),
    ("BACKGROUND", (0,3), (-1,3), LGRAY),
    ("BACKGROUND", (0,4), (-1,4), WHITE),
    ("BACKGROUND", (0,5), (-1,5), LGRAY),
    ("GRID",       (0,0), (-1,-1), 0.4, MGRAY),
    ("VALIGN",     (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 4),
    ("BOTTOMPADDING", (0,0), (-1,-1), 4),
    ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ("RIGHTPADDING",  (0,0), (-1,-1), 5),
]))
story.append(param_tbl)
story.append(Spacer(1, 4))

# ── SI UNITS SIDEBAR ────────────────────────────────────────────────────────
story.append(section_header("  SI Units (µmol/L) — Expanded Lookup Table"))

si_note = (
    "When creatinine is reported in <b>µmol/L</b>, use κ = <b>61.88</b> (female) or "
    "<b>79.56</b> (male). The table below shows the correct sub-equation for each sex/range combination."
)
story.append(Paragraph(si_note, style(fontSize=8, textColor=DKGRAY,
                                       spaceBefore=2, spaceAfter=4)))

si_header = [
    pc("Sex", bold=True), pc("Scr (µmol/L)", bold=True),
    pc("Exponent used", bold=True), pc("Equation", bold=True, align=TA_LEFT),
]
si_rows = [
    si_header,
    [pc("Female"), pc("≤ 61.9"), pc("α = −0.241"),
     pc("142 × (Scr/61.88)⁻⁰·²⁴¹ × 0.9938ᴬᵍᵉ × 1.012", align=TA_LEFT)],
    [pc("Female"), pc("> 61.9"), pc("−1.200"),
     pc("142 × (Scr/61.88)⁻¹·²⁰⁰ × 0.9938ᴬᵍᵉ × 1.012", align=TA_LEFT)],
    [pc("Male"),   pc("≤ 79.6"), pc("α = −0.302"),
     pc("142 × (Scr/79.56)⁻⁰·³⁰² × 0.9938ᴬᵍᵉ", align=TA_LEFT)],
    [pc("Male"),   pc("> 79.6"), pc("−1.200"),
     pc("142 × (Scr/79.56)⁻¹·²⁰⁰ × 0.9938ᴬᵍᵉ", align=TA_LEFT)],
]
si_cw = [W*0.10, W*0.15, W*0.16, W*0.59]
si_tbl = Table(si_rows, colWidths=si_cw, repeatRows=1)
si_tbl.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), NAVY),
    ("BACKGROUND", (0,1), (-1,1), MNTEAL),
    ("BACKGROUND", (0,2), (-1,2), WHITE),
    ("BACKGROUND", (0,3), (-1,3), MNTEAL),
    ("BACKGROUND", (0,4), (-1,4), WHITE),
    ("GRID",       (0,0), (-1,-1), 0.4, MGRAY),
    ("VALIGN",     (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 4),
    ("BOTTOMPADDING", (0,0), (-1,-1), 4),
    ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ("RIGHTPADDING",  (0,0), (-1,-1), 5),
]))
story.append(si_tbl)
story.append(Spacer(1, 4))

# ── WORKED EXAMPLE ──────────────────────────────────────────────────────────
story.append(section_header("  Worked Example"))

ex_rows = [
    [
        Paragraph("<b>Given</b>", style(fontSize=8.5, textColor=WHITE, alignment=TA_CENTER)),
        Paragraph("<b>Step-by-step calculation</b>", style(fontSize=8.5, textColor=WHITE, alignment=TA_LEFT)),
        Paragraph("<b>Result</b>", style(fontSize=8.5, textColor=WHITE, alignment=TA_CENTER)),
    ],
    [
        Paragraph(
            "Female<br/>Age: 55 yr<br/>Scr: 1.2 mg/dL",
            style(fontSize=8, textColor=DKGRAY, alignment=TA_LEFT)
        ),
        Paragraph(
            "κ = 0.7, α = −0.241 (female)<br/>"
            "Scr/κ = 1.2/0.7 = <b>1.714</b>  → above κ, so min term = 1, max term = 1.714<br/>"
            "min(1.714,1)⁻⁰·²⁴¹ = 1.000<br/>"
            "max(1.714,1)⁻¹·²⁰⁰ = 1.714⁻¹·²⁰⁰ = <b>0.532</b><br/>"
            "0.9938⁵⁵ = <b>0.712</b><br/>"
            "eGFR = 142 × 1.000 × 0.532 × 0.712 × 1.012",
            style(fontSize=8, textColor=DKGRAY, alignment=TA_LEFT)
        ),
        Paragraph(
            "<b>≈ 54.3</b><br/>mL/min<br/>/1.73m²",
            style(fontSize=10, textColor=NAVY, alignment=TA_CENTER, leading=13)
        ),
    ],
    [
        Paragraph(
            "Male<br/>Age: 40 yr<br/>Scr: 0.8 mg/dL",
            style(fontSize=8, textColor=DKGRAY, alignment=TA_LEFT)
        ),
        Paragraph(
            "κ = 0.9, α = −0.302 (male)<br/>"
            "Scr/κ = 0.8/0.9 = <b>0.889</b>  → below κ, so min term = 0.889, max term = 1<br/>"
            "min(0.889,1)⁻⁰·³⁰² = 0.889⁻⁰·³⁰² = <b>1.037</b><br/>"
            "max(0.889,1)⁻¹·²⁰⁰ = 1.000<br/>"
            "0.9938⁴⁰ = <b>0.781</b><br/>"
            "eGFR = 142 × 1.037 × 1.000 × 0.781",
            style(fontSize=8, textColor=DKGRAY, alignment=TA_LEFT)
        ),
        Paragraph(
            "<b>≈ 114.7</b><br/>mL/min<br/>/1.73m²",
            style(fontSize=10, textColor=NAVY, alignment=TA_CENTER, leading=13)
        ),
    ],
]
ex_cw = [W*0.16, W*0.65, W*0.19]
ex_tbl = Table(ex_rows, colWidths=ex_cw, repeatRows=1)
ex_tbl.setStyle(TableStyle([
    ("BACKGROUND", (0,0), (-1,0), NAVY),
    ("BACKGROUND", (0,1), (-1,1), LGRAY),
    ("BACKGROUND", (0,2), (-1,2), WHITE),
    ("GRID",       (0,0), (-1,-1), 0.4, MGRAY),
    ("VALIGN",     (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 5),
    ("BOTTOMPADDING", (0,0), (-1,-1), 5),
    ("LEFTPADDING",   (0,0), (-1,-1), 6),
    ("RIGHTPADDING",  (0,0), (-1,-1), 6),
]))
story.append(ex_tbl)
story.append(Spacer(1, 4))

# ── CKD STAGING TABLE ───────────────────────────────────────────────────────
story.append(section_header("  CKD Staging by eGFR  (KDIGO 2024)"))

stage_data = [
    [pc("Stage", bold=True), pc("eGFR (mL/min/1.73m²)", bold=True),
     pc("Description", bold=True, align=TA_LEFT), pc("Colour code", bold=True)],
    [pc("G1"), pc("≥ 90"),   pc("Normal or high", align=TA_LEFT),           pc("▮ Green")],
    [pc("G2"), pc("60–89"),  pc("Mildly decreased", align=TA_LEFT),         pc("▮ Yellow-green")],
    [pc("G3a"),pc("45–59"),  pc("Mildly-moderately decreased", align=TA_LEFT), pc("▮ Yellow")],
    [pc("G3b"),pc("30–44"),  pc("Moderately-severely decreased", align=TA_LEFT), pc("▮ Orange")],
    [pc("G4"), pc("15–29"),  pc("Severely decreased", align=TA_LEFT),       pc("▮ Red-orange")],
    [pc("G5"), pc("< 15"),   pc("Kidney failure", align=TA_LEFT),           pc("▮ Dark red")],
]

stage_bg = [LGREEN, LGREEN, colors.HexColor("#f0fdf4"),
            LAMBER, LLORANGE, LRED, colors.HexColor("#ffd7d7")]
stage_cw = [W*0.10, W*0.22, W*0.46, W*0.22]
stage_tbl = Table(stage_data, colWidths=stage_cw, repeatRows=1)
style_cmds = [
    ("BACKGROUND",    (0,0), (-1,0), NAVY),
    ("GRID",          (0,0), (-1,-1), 0.4, MGRAY),
    ("VALIGN",        (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 4),
    ("BOTTOMPADDING", (0,0), (-1,-1), 4),
    ("LEFTPADDING",   (0,0), (-1,-1), 5),
    ("RIGHTPADDING",  (0,0), (-1,-1), 5),
]
for i, bg in enumerate(stage_bg[1:], start=1):
    style_cmds.append(("BACKGROUND", (0,i), (-1,i), bg))

color_map = [colors.HexColor("#16a34a"), colors.HexColor("#65a30d"),
             colors.HexColor("#ca8a04"), colors.HexColor("#ea580c"),
             colors.HexColor("#dc2626"), colors.HexColor("#991b1b")]
for i, c in enumerate(color_map, start=1):
    style_cmds.append(("TEXTCOLOR", (3,i), (3,i), c))

stage_tbl.setStyle(TableStyle(style_cmds))
story.append(stage_tbl)
story.append(Spacer(1, 4))

# ── CLINICAL NOTES ──────────────────────────────────────────────────────────
story.append(section_header("  Clinical Notes & Limitations"))

notes_left = [
    "• <b>No race variable</b> — 2021 update removed the 1.159 Black-race multiplier",
    "• <b>IDMS-traceable creatinine</b> is required for accurate results",
    "• <b>Muscle mass extremes</b>: may over/underestimate in amputees, bodybuilders, malnutrition",
    "• <b>Acute AKI</b>: not valid — eGFR assumes steady-state creatinine",
    "• <b>Dietary factors</b>: high protein intake transiently raises creatinine",
]
notes_right = [
    "• Confirm CKD with <b>≥2 readings >90 days apart</b>",
    "• Add <b>albuminuria (ACR)</b> for full KDIGO risk staging",
    "• Consider <b>cystatin C</b> equation when muscle mass is atypical",
    "• Use <b>CKD-EPI Cr+CysC 2021</b> for greatest accuracy",
    "• Adjust drug doses when eGFR < 60 mL/min/1.73m²",
]

def notes_col(items, width):
    rows = [[Paragraph(i, style(fontSize=7.8, textColor=DKGRAY,
                                 spaceBefore=1, spaceAfter=1))] for i in items]
    t = Table(rows, colWidths=[width])
    t.setStyle(TableStyle([
        ("TOPPADDING",    (0,0), (-1,-1), 2),
        ("BOTTOMPADDING", (0,0), (-1,-1), 2),
        ("LEFTPADDING",   (0,0), (-1,-1), 4),
        ("RIGHTPADDING",  (0,0), (-1,-1), 4),
    ]))
    return t

notes_tbl = Table(
    [[notes_col(notes_left, W*0.49), notes_col(notes_right, W*0.49)]],
    colWidths=[W*0.50, W*0.50]
)
notes_tbl.setStyle(TableStyle([
    ("BACKGROUND",    (0,0), (-1,-1), LGRAY),
    ("BOX",           (0,0), (-1,-1), 0.6, MGRAY),
    ("VALIGN",        (0,0), (-1,-1), "TOP"),
    ("TOPPADDING",    (0,0), (-1,-1), 4),
    ("BOTTOMPADDING", (0,0), (-1,-1), 4),
    ("LEFTPADDING",   (0,0), (-1,-1), 0),
    ("RIGHTPADDING",  (0,0), (-1,-1), 0),
]))
story.append(notes_tbl)
story.append(Spacer(1, 4))

# ── QUICK REFERENCE: eGFR LOOKUP GRID ───────────────────────────────────────
story.append(section_header("  Quick eGFR Lookup — Female, mg/dL  (Age × Creatinine)"))

ages_f  = [25, 35, 45, 55, 65, 75]
scrs_f  = [0.6, 0.7, 0.9, 1.1, 1.3, 1.5, 1.8, 2.0, 2.5, 3.0]

def ckd_epi_2021(scr, age, female=True):
    k = 0.7 if female else 0.9
    a = -0.241 if female else -0.302
    sex_mult = 1.012 if female else 1.0
    ratio = scr / k
    min_part = min(ratio, 1) ** a
    max_part = max(ratio, 1) ** (-1.200)
    return round(142 * min_part * max_part * (0.9938 ** age) * sex_mult, 1)

def egfr_color(v):
    if v >= 90:   return LGREEN
    if v >= 60:   return colors.HexColor("#f0fdf4")
    if v >= 45:   return LAMBER
    if v >= 30:   return LLORANGE
    if v >= 15:   return LRED
    return colors.HexColor("#ffd7d7")

# Header row
lookup_hdr = [pc("Scr↓  Age→", bold=True)] + [pc(str(a), bold=True) for a in ages_f]
lookup_rows = [lookup_hdr]
for scr in scrs_f:
    row = [pc(f"{scr:.1f} mg/dL", bold=True)]
    for age in ages_f:
        v = ckd_epi_2021(scr, age, female=True)
        row.append(pc(str(v)))
    lookup_rows.append(row)

n_cols = 1 + len(ages_f)
col_w = W / n_cols
lookup_tbl = Table(lookup_rows, colWidths=[col_w]*n_cols, repeatRows=1)

lu_style = [
    ("BACKGROUND", (0,0), (-1,0), NAVY),
    ("BACKGROUND", (0,0), (0,-1), TEAL),
    ("GRID",       (0,0), (-1,-1), 0.4, MGRAY),
    ("VALIGN",     (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 3),
    ("RIGHTPADDING",  (0,0), (-1,-1), 3),
]
for r, scr in enumerate(scrs_f, start=1):
    for c, age in enumerate(ages_f, start=1):
        v = ckd_epi_2021(scr, age, female=True)
        lu_style.append(("BACKGROUND", (c,r), (c,r), egfr_color(v)))
        if v < 30:
            lu_style.append(("TEXTCOLOR", (c,r), (c,r), RED))
        elif v < 60:
            lu_style.append(("TEXTCOLOR", (c,r), (c,r), ORANGE))
        elif v >= 90:
            lu_style.append(("TEXTCOLOR", (c,r), (c,r), GREEN))

lookup_tbl.setStyle(TableStyle(lu_style))
story.append(lookup_tbl)
story.append(Spacer(1, 3))

# Male lookup
story.append(section_header("  Quick eGFR Lookup — Male, mg/dL  (Age × Creatinine)"))

ages_m = [25, 35, 45, 55, 65, 75]
scrs_m = [0.7, 0.9, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.5, 3.0]

lookup_hdr_m = [pc("Scr↓  Age→", bold=True)] + [pc(str(a), bold=True) for a in ages_m]
lookup_rows_m = [lookup_hdr_m]
for scr in scrs_m:
    row = [pc(f"{scr:.1f} mg/dL", bold=True)]
    for age in ages_m:
        v = ckd_epi_2021(scr, age, female=False)
        row.append(pc(str(v)))
    lookup_rows_m.append(row)

lookup_tbl_m = Table(lookup_rows_m, colWidths=[col_w]*n_cols, repeatRows=1)

lu_style_m = [
    ("BACKGROUND", (0,0), (-1,0), NAVY),
    ("BACKGROUND", (0,0), (0,-1), TEAL),
    ("GRID",       (0,0), (-1,-1), 0.4, MGRAY),
    ("VALIGN",     (0,0), (-1,-1), "MIDDLE"),
    ("TOPPADDING",    (0,0), (-1,-1), 3),
    ("BOTTOMPADDING", (0,0), (-1,-1), 3),
    ("LEFTPADDING",   (0,0), (-1,-1), 3),
    ("RIGHTPADDING",  (0,0), (-1,-1), 3),
]
for r, scr in enumerate(scrs_m, start=1):
    for c, age in enumerate(ages_m, start=1):
        v = ckd_epi_2021(scr, age, female=False)
        lu_style_m.append(("BACKGROUND", (c,r), (c,r), egfr_color(v)))
        if v < 30:
            lu_style_m.append(("TEXTCOLOR", (c,r), (c,r), RED))
        elif v < 60:
            lu_style_m.append(("TEXTCOLOR", (c,r), (c,r), ORANGE))
        elif v >= 90:
            lu_style_m.append(("TEXTCOLOR", (c,r), (c,r), GREEN))

lookup_tbl_m.setStyle(TableStyle(lu_style_m))
story.append(lookup_tbl_m)
story.append(Spacer(1, 4))

# ── FOOTER ──────────────────────────────────────────────────────────────────
story.append(HRFlowable(width=W, thickness=0.5, color=MGRAY))
footer_text = (
    "Reference: Inker LA et al. <i>N Engl J Med</i> 2021;385:1737–1749. "
    "NKF–ASN Task Force 2021. KDIGO CKD Guidelines 2024. "
    "<b>For clinical use only. Verify with institutional resources.</b>"
)
story.append(Paragraph(footer_text,
    style(fontSize=7, textColor=colors.HexColor("#64748b"),
          alignment=TA_CENTER, spaceBefore=3)))

# ── BUILD ───────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF saved: {OUTPUT}")
Running Command

cd /tmp/workspace/ckd-epi-card && python create_card.py 2>&1

Your printable A4 reference card is ready:

CKD EPI 2021 Reference Card

PDF Document · PDF


Here's what's included on the single-page card:
SectionContents
Formula bannerFull CKD-EPI 2021 equation with superscripts
Parameters tableκ, α, sex multiplier for male and female
SI units tableAll 4 sub-equations with µmol/L thresholds
Worked examplesTwo fully solved step-by-step calculations (female Scr 1.2, male Scr 0.8)
CKD stagingKDIGO G1–G5 with colour coding
Quick eGFR lookup gridsPre-calculated values for common creatinine levels × ages (separate tables for female and male), colour-coded by CKD stage
Clinical notes10 key limitations and practice points
FooterReference to Inker et al. NEJM 2021
The lookup grids are colour-coded: green (eGFR ≥90), pale yellow-green (60–89), amber (45–59), orange (30–44), red (<30) - so you can spot CKD stage at a glance without calculation.
This is a shared conversation. Sign in to Orris to start your own chat.