"diabetic ketoacidosis"[MeSH Terms] AND "management"
| Parameter | Result | Comment |
|---|---|---|
| pH | 6.823 | Severe acidemia (below 6.9) |
| HCO3 | 4.9 mmol/L | Profoundly low |
| Base excess | -29 | Severe metabolic acidosis |
| pCO2 | 30.7 mmHg | Low, but not low enough (see below) |
| Glucose | 562 | Very high. The unit is printed as mmol/L, but this is almost certainly mg/dL (about 31 mmol/L) |
| Lactate | 4.41 mmol/L | Mildly raised |
| K+ | 5.35 mmol/L | Mildly high, caused by the acidosis |
| Na+ / Cl- | 139.6 / 104 mmol/L | |
| SO2 / pO2 | 75.7% / 57.5 mmHg | Likely a venous or mixed sample |
| Parameter | 09:13 | 11:40 | Comment |
|---|---|---|---|
| pH | 6.823 | 7.035 | Better, but still severe |
| pCO2 | 30.7 | 14.6 | Now appropriately low |
| HCO3 | 4.9 | 3.8 | Slightly worse |
| Base excess | -29 | -25 | |
| Na+ | 139.6 | 143.4 | |
| Cl- | 104 | 113 | Rising, and now above normal |
| K+ | 5.35 | 4.48 | Falling, as expected on insulin |
| Glucose | 562 | 416 | Falling (about 58/h if mg/dL) |
| Lactate | 4.41 | 4.21 | Unchanged |
| Hb / Hct | 14.8 / 44 | 12.6 / 37 | Dilution from fluids |
| Ionized Ca | 1.25 | 1.0 | Now low |
| pO2 | 57.5 | 137.9 | The first sample was likely venous. This one looks arterial, or the patient is on oxygen |
Make a DKA management protocol slide deck for teaching
2024 consensus report hyperglycemic crises adults DKA HHS ADA EASD JBDS management insulin potassium bicarbonate
https://consultqd.clevelandclinic.org/hyperglycemic-crises-i…
ls -la /tmp/workspace/ && mkdir -p /tmp/workspace/dka-deck/src /tmp/workspace/dka-deck/output && ls /tmp/skills/pptx/scripts 2>/dev/null
~/dka-deck/src/build.py
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
from pptx.oxml.ns import qn
from lxml import etree
NAVY = RGBColor(0x0B, 0x25, 0x45)
TEAL = RGBColor(0x1B, 0x99, 0x8B)
RED = RGBColor(0xC0, 0x39, 0x2B)
AMBER = RGBColor(0xE0, 0x8E, 0x1B)
GREEN = RGBColor(0x2E, 0x8B, 0x57)
LIGHT = RGBColor(0xF1, 0xF5, 0xF9)
GREY = RGBColor(0x55, 0x60, 0x6E)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
DARK = RGBColor(0x22, 0x2B, 0x36)
FONT = "Calibri"
prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)
BLANK = prs.slide_layouts[6]
state = {"n": 0}
def rect(slide, x, y, w, h, fill, shape=MSO_SHAPE.RECTANGLE, line=None):
s = slide.shapes.add_shape(shape, Inches(x), Inches(y), Inches(w), Inches(h))
s.fill.solid()
s.fill.fore_color.rgb = fill
if line is None:
s.line.fill.background()
else:
s.line.color.rgb = line
s.line.width = Pt(1)
s.shadow.inherit = False
return s
def text(slide, x, y, w, h, txt, size=18, bold=False, color=DARK, align=PP_ALIGN.LEFT,
anchor=MSO_ANCHOR.TOP):
tb = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
tf = tb.text_frame
tf.word_wrap = True
tf.vertical_anchor = anchor
tf.margin_left = tf.margin_right = Inches(0.05)
tf.margin_top = tf.margin_bottom = Inches(0.03)
p = tf.paragraphs[0]
p.alignment = align
r = p.add_run()
r.text = txt
r.font.size = Pt(size)
r.font.bold = bold
r.font.name = FONT
r.font.color.rgb = color
return tb
def bullets(slide, x, y, w, h, items, size=18, color=DARK, gap=6):
tb = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h))
tf = tb.text_frame
tf.word_wrap = True
tf.margin_left = tf.margin_right = Inches(0.05)
first = True
for it in items:
sub = False
if isinstance(it, tuple):
it, sub = it[0], True
p = tf.paragraphs[0] if first else tf.add_paragraph()
first = False
p.space_after = Pt(gap)
pPr = p._p.get_or_add_pPr()
indent = 0.5 if sub else 0.25
pPr.set("marL", str(int(Inches(indent + (0.1 if sub else 0)))))
pPr.set("indent", str(int(-Inches(0.25))))
bu = etree.SubElement(pPr, qn("a:buChar"))
bu.set("char", "-" if sub else "\u2022")
r = p.add_run()
r.text = it
r.font.size = Pt(size - (2 if sub else 0))
r.font.name = FONT
r.font.color.rgb = GREY if sub else color
return tb
def new_slide(title, notes=None, subtitle=None):
s = prs.slides.add_slide(BLANK)
state["n"] += 1
rect(s, 0, 0, 13.333, 1.15, NAVY)
rect(s, 0, 1.15, 13.333, 0.06, TEAL)
text(s, 0.5, 0.15, 12.3, 0.85, title, 32, True, WHITE, anchor=MSO_ANCHOR.MIDDLE)
text(s, 0.5, 7.05, 10, 0.3, "DKA management protocol | Teaching deck | Based on 2024 ADA/EASD/JBDS/AACE/DTS consensus",
10, False, GREY)
text(s, 12.0, 7.05, 0.9, 0.3, str(state["n"]), 10, False, GREY, PP_ALIGN.RIGHT)
if notes:
s.notes_slide.notes_text_frame.text = notes
return s
def card(slide, x, y, w, h, head, body, color=TEAL, size=15, head_size=17):
rect(slide, x, y, w, h, LIGHT)
rect(slide, x, y, 0.09, h, color)
text(slide, x + 0.2, y + 0.08, w - 0.3, 0.45, head, head_size, True, color)
if isinstance(body, list):
bullets(slide, x + 0.15, y + 0.55, w - 0.3, h - 0.6, body, size, gap=4)
else:
text(slide, x + 0.2, y + 0.55, w - 0.3, h - 0.6, body, size, False, DARK)
def table(slide, x, y, w, col_w, rows, size=14, row_h=0.45, head_fill=NAVY, first_col_bold=True,
fills=None):
nr, nc = len(rows), len(rows[0])
gs = slide.shapes.add_table(nr, nc, Inches(x), Inches(y), Inches(w), Inches(row_h * nr))
tbl = gs.table
tblPr = tbl._tbl.tblPr
# remove default style banding look
tblPr.set("bandRow", "0")
tblPr.set("firstRow", "0")
for i, cw in enumerate(col_w):
tbl.columns[i].width = Inches(cw)
for r in range(nr):
tbl.rows[r].height = Inches(row_h)
for c in range(nc):
cell = tbl.cell(r, c)
cell.margin_left = cell.margin_right = Inches(0.08)
cell.margin_top = cell.margin_bottom = Inches(0.04)
cell.vertical_anchor = MSO_ANCHOR.MIDDLE
cell.fill.solid()
if r == 0:
cell.fill.fore_color.rgb = head_fill
elif fills and fills.get((r, c)) is not None:
cell.fill.fore_color.rgb = fills[(r, c)]
else:
cell.fill.fore_color.rgb = WHITE if r % 2 else LIGHT
tf = cell.text_frame
tf.word_wrap = True
p = tf.paragraphs[0]
run = p.add_run()
run.text = rows[r][c]
run.font.size = Pt(size)
run.font.name = FONT
if r == 0:
run.font.bold = True
run.font.color.rgb = WHITE
else:
run.font.bold = (c == 0 and first_col_bold)
run.font.color.rgb = DARK
return tbl
# ---------------------------------------------------------------- 1 Title
s = prs.slides.add_slide(BLANK)
state["n"] += 1
rect(s, 0, 0, 13.333, 7.5, NAVY)
rect(s, 0.8, 3.55, 2.2, 0.08, TEAL)
text(s, 0.8, 1.7, 11.5, 1.0, "Diabetic Ketoacidosis (DKA)", 48, True, WHITE)
text(s, 0.8, 2.7, 11.5, 0.8, "Management protocol for adults", 30, False, RGBColor(0xBF, 0xE3, 0xDE))
text(s, 0.8, 3.85, 11.5, 1.2,
"Recognition, severity, fluids, potassium, insulin, monitoring, resolution and pitfalls\nIncludes a worked blood gas case",
20, False, WHITE)
text(s, 0.8, 6.3, 11.5, 0.8,
"Teaching material. Always follow your local hospital protocol and the treating team's judgment.",
14, False, RGBColor(0xA9, 0xB7, 0xC6))
s.notes_slide.notes_text_frame.text = (
"Teaching deck built around the 2024 ADA/EASD/JBDS/AACE/DTS consensus report on hyperglycemic crises in adults. "
"Local protocols differ in some thresholds and doses; present this as a framework.")
# ---------------------------------------------------------------- 2 Objectives
s = new_slide("Learning objectives",
"Set expectations. The case at slide 15 ties together acid-base interpretation and treatment monitoring.")
bullets(s, 0.7, 1.7, 11.9, 5, [
"Diagnose DKA using the 2024 D-K-A criteria and grade severity",
"Distinguish DKA from HHS and mixed presentations",
"Apply the stepwise protocol: fluids, potassium check, insulin, monitoring, treat the cause",
"Interpret the blood gas: anion gap, Winter's formula, delta-delta, hyperchloremic acidosis",
"Recognize resolution criteria and transition safely to subcutaneous insulin",
"Avoid the common errors: stopping insulin early, ignoring potassium, over-trusting glucose or pH",
], 22, gap=14)
# ---------------------------------------------------------------- 3 Pathophysiology
s = new_slide("Pathophysiology in one picture",
"Absolute or relative insulin deficiency plus raised counter-regulatory hormones. Liver converts free fatty acids to ketone bodies, mostly beta-hydroxybutyrate. "
"Osmotic diuresis causes volume depletion and total body losses of sodium, potassium, phosphate and magnesium.")
steps = [("Insulin deficiency\n+ glucagon, cortisol,\ncatecholamines", NAVY),
("Lipolysis and\nhepatic ketogenesis", TEAL),
("Beta-hydroxybutyrate\nand acetoacetate\naccumulate", AMBER),
("High anion gap\nmetabolic acidosis", RED)]
x = 0.6
for i, (t, c) in enumerate(steps):
b = rect(s, x, 1.7, 2.7, 1.5, c, MSO_SHAPE.ROUNDED_RECTANGLE)
tf = b.text_frame
tf.word_wrap = True
tf.vertical_anchor = MSO_ANCHOR.MIDDLE
for j, line in enumerate(t.split("\n")):
p = tf.paragraphs[0] if j == 0 else tf.add_paragraph()
p.alignment = PP_ALIGN.CENTER
r = p.add_run()
r.text = line
r.font.size = Pt(16)
r.font.bold = True
r.font.name = FONT
r.font.color.rgb = WHITE
if i < 3:
a = rect(s, x + 2.75, 2.25, 0.45, 0.4, GREY, MSO_SHAPE.RIGHT_ARROW)
x += 3.2
card(s, 0.6, 3.6, 5.9, 3.2, "Glucose side",
["Gluconeogenesis and glycogenolysis rise, glucose uptake falls",
"Hyperglycemia causes osmotic diuresis",
"Losses of water, sodium, potassium, phosphate, magnesium",
"Dehydration reduces GFR and worsens hyperglycemia"], TEAL, 16)
card(s, 6.8, 3.6, 5.9, 3.2, "Clinical consequences",
["Polyuria, polydipsia, vomiting, abdominal pain",
"Kussmaul breathing as respiratory compensation",
"Altered consciousness in severe cases",
"Total body potassium depleted even if serum K+ is normal or high"], RED, 16)
# ---------------------------------------------------------------- 4 Precipitants
s = new_slide("Always look for the trigger",
"Treat the precipitant in parallel. Euglycemic DKA is increasingly seen with SGLT2 inhibitors, so do not exclude DKA on glucose alone.")
card(s, 0.6, 1.6, 4.0, 2.55, "Common", ["Infection (pneumonia, UTI, sepsis)", "Insulin omission or pump failure", "New-onset diabetes"], TEAL, 17)
card(s, 4.7, 1.6, 4.0, 2.55, "Acute illness", ["Myocardial infarction", "Stroke", "Pancreatitis, trauma, surgery"], AMBER, 17)
card(s, 8.8, 1.6, 4.0, 2.55, "Drugs", ["SGLT2 inhibitors", "Corticosteroids", "Some antipsychotics, immune checkpoint inhibitors"], RED, 17)
card(s, 0.6, 4.4, 12.2, 2.4, "Work-up for the cause",
["ECG and troponin, chest X-ray, urinalysis, blood and urine cultures, lipase if abdominal pain",
"Pregnancy test in women of childbearing age",
"Euglycemic DKA (glucose below 200 mg/dL) can occur with SGLT2 inhibitors, pregnancy, fasting, alcohol, liver disease"],
NAVY, 16)
# ---------------------------------------------------------------- 5 Diagnosis
s = new_slide("Diagnosis: the D-K-A criteria (2024 consensus)",
"All three criteria are needed. The 2024 report recommends direct beta-hydroxybutyrate measurement and no longer uses the anion gap as a diagnostic or severity criterion. "
"Nitroprusside tests detect only acetoacetate, so they can underestimate ketosis at presentation and overestimate it during resolution.")
cols = [("D", "Diabetes / hyperglycemia", "Glucose 200 mg/dL (11.1 mmol/L) or higher, or known diabetes", TEAL),
("K", "Ketosis", "Beta-hydroxybutyrate 3.0 mmol/L or higher, or urine ketones 2+ or more", AMBER),
("A", "Acidosis", "Venous pH below 7.3 and/or bicarbonate below 18 mmol/L", RED)]
x = 0.6
for letter, head, body, c in cols:
rect(s, x, 1.6, 3.95, 3.3, LIGHT)
rect(s, x, 1.6, 3.95, 0.09, c)
text(s, x, 1.8, 3.95, 1.0, letter, 54, True, c, PP_ALIGN.CENTER)
text(s, x + 0.15, 2.9, 3.65, 0.5, head, 20, True, DARK, PP_ALIGN.CENTER)
text(s, x + 0.2, 3.45, 3.55, 1.4, body, 17, False, DARK, PP_ALIGN.CENTER)
x += 4.15
bullets(s, 0.6, 5.2, 12.2, 1.7, [
"Measure beta-hydroxybutyrate directly where available; the anion gap is a fallback surrogate",
"Normal glucose does not exclude DKA (SGLT2 inhibitors, pregnancy, starvation)",
"A venous gas is enough for pH and bicarbonate in most patients",
], 18, gap=6)
# ---------------------------------------------------------------- 6 Severity
s = new_slide("Severity classification",
"Not every criterion must be met. Clinical judgment and local resources decide the level of care. Mild DKA can sometimes be managed on a general ward with subcutaneous rapid-acting insulin protocols.")
rows = [["", "Mild", "Moderate", "Severe"],
["Venous pH", "7.25 to <7.30", "7.00 to <7.25", "<7.00"],
["Bicarbonate (mmol/L)", "15 to <18", "10 to <15", "<10"],
["Beta-hydroxybutyrate (mmol/L)", "3.0 to 6.0", "3.0 to 6.0", ">6.0"],
["Mental status", "Alert", "Alert or drowsy", "Stupor or coma"],
["Suggested setting", "Ward / ED observation", "Step-down / high dependency", "ICU"]]
fills = {}
for r in range(1, 6):
fills[(r, 1)] = RGBColor(0xFD, 0xF1, 0xD8)
fills[(r, 2)] = RGBColor(0xFB, 0xDF, 0xC4)
fills[(r, 3)] = RGBColor(0xF6, 0xC9, 0xC4)
table(s, 0.6, 1.7, 12.1, [3.7, 2.8, 2.8, 2.8], rows, 17, 0.7, fills=fills)
text(s, 0.6, 6.0, 12.1, 0.8,
"Anion gap is no longer a severity criterion. Cutoffs are guides; adjust level of care to age, comorbidity and trajectory.",
16, False, GREY)
# ---------------------------------------------------------------- 7 DKA vs HHS
s = new_slide("DKA versus HHS",
"Overlap is common. Roughly a third of hyperglycemic crises have features of both. Effective osmolality = 2 x Na (mmol/L) + glucose (mmol/L).")
rows = [["Feature", "DKA", "HHS"],
["Glucose", "200 mg/dL or higher (can be normal)", "600 mg/dL (33.3 mmol/L) or higher"],
["Ketones", "Beta-hydroxybutyrate 3.0 mmol/L or higher", "Absent or minimal"],
["pH / bicarbonate", "Below 7.3 / below 18 mmol/L", "Above 7.3 / above 18 mmol/L"],
["Effective osmolality", "Variable", "Above 300 mOsm/kg"],
["Onset and typical patient", "Hours to days; type 1, also type 2", "Days to weeks; older, type 2"],
["Fluid deficit", "About 6 L", "About 8 to 12 L"],
["Mental status", "Variable with severity", "Often obtunded"]]
table(s, 0.6, 1.6, 12.1, [3.0, 4.6, 4.5], rows, 16, 0.6)
# ---------------------------------------------------------------- 8 Initial workup
s = new_slide("Initial assessment: first 30 minutes",
"Check potassium before insulin. A bedside ECG gives a quick look at hyper- or hypokalemia while labs are pending.")
card(s, 0.6, 1.6, 6.0, 5.2, "Bedside",
["ABC, vital signs, GCS, volume status",
"Two IV lines, cardiac monitor",
"Capillary glucose and blood ketone (beta-hydroxybutyrate)",
"12-lead ECG (potassium, ischemia)",
"Weight for insulin dosing",
"Urinary catheter if shocked or oliguric"], TEAL, 18)
card(s, 6.9, 1.6, 5.8, 5.2, "Laboratory",
["Venous or arterial blood gas",
"Sodium, potassium, chloride, bicarbonate",
"Urea, creatinine, phosphate, magnesium, calcium",
"Beta-hydroxybutyrate, lactate",
"Full blood count, CRP, cultures",
"Troponin, lipase, HbA1c as indicated",
"Calculate: anion gap, effective osmolality, corrected sodium"], NAVY, 18)
# ---------------------------------------------------------------- 9 Algorithm
s = new_slide("Management at a glance",
"Order matters: fluids first, potassium known before insulin, insulin continued until ketones clear, with dextrose added so the infusion never has to stop for hypoglycemia.")
flow = [("1", "Fluids", "Isotonic crystalloid\n500 to 1000 mL/h\nfor 2 to 4 h", TEAL),
("2", "Check K+", "Before insulin\nReplace as needed", AMBER),
("3", "Insulin", "IV 0.1 U/kg/h\nfixed rate", NAVY),
("4", "Monitor", "Glucose 1 to 2 hourly\nLabs 4 hourly", GREEN),
("5", "Resolve", "BHB below 0.6\nand pH 7.3 or higher\nor HCO3 18 or higher", RED)]
x = 0.45
for num, head, body, c in flow:
rect(s, x, 1.7, 2.35, 3.4, LIGHT)
rect(s, x, 1.7, 2.35, 0.09, c)
circ = rect(s, x + 0.85, 1.95, 0.65, 0.65, c, MSO_SHAPE.OVAL)
tf = circ.text_frame
tf.vertical_anchor = MSO_ANCHOR.MIDDLE
p = tf.paragraphs[0]
p.alignment = PP_ALIGN.CENTER
r = p.add_run()
r.text = num
r.font.size = Pt(22)
r.font.bold = True
r.font.name = FONT
r.font.color.rgb = WHITE
text(s, x, 2.75, 2.35, 0.5, head, 20, True, c, PP_ALIGN.CENTER)
text(s, x + 0.1, 3.3, 2.15, 1.7, body, 15, False, DARK, PP_ALIGN.CENTER)
if num != "5":
rect(s, x + 2.37, 3.2, 0.2, 0.3, GREY, MSO_SHAPE.RIGHT_ARROW)
x += 2.5
card(s, 0.45, 5.35, 12.4, 1.55, "In parallel throughout",
"Find and treat the precipitant. Add dextrose when glucose falls to about 200 to 250 mg/dL and keep insulin running. "
"Prevent complications: hypoglycemia, hypokalemia, thromboembolism.", NAVY, 16)
# ---------------------------------------------------------------- 10 Fluids
s = new_slide("Step 1: Fluid resuscitation",
"Fluids come before insulin. Balanced crystalloids may lower the risk of hyperchloremic acidosis; evidence from subgroup analyses suggests faster DKA resolution. "
"Be cautious in heart failure, renal failure and the elderly.")
card(s, 0.6, 1.6, 6.0, 2.6, "Initial phase",
["Isotonic saline or balanced crystalloid",
"500 to 1000 mL/h for the first 2 to 4 hours",
"Goal: restore circulating volume and perfusion"], TEAL, 18)
card(s, 6.9, 1.6, 5.8, 2.6, "Subsequent phase",
["Tailor rate to hemodynamics, urine output, sodium",
"Corrected Na high: consider hypotonic saline",
"Corrected Na normal or low: continue isotonic fluid"], NAVY, 18)
card(s, 0.6, 4.45, 12.1, 2.35, "Teaching points",
["Corrected sodium = measured Na + 1.6 x (glucose mg/dL - 100) / 100",
"Saline in large volumes causes hyperchloremic non-gap acidosis; use a balanced solution when possible",
"Fixed-dose insulin is not a substitute for adequate fluid replacement"], AMBER, 16)
# ---------------------------------------------------------------- 11 Potassium
s = new_slide("Step 2: Potassium. Check it before insulin",
"2024 consensus thresholds. Older protocols (ADA 2009, some textbooks) use 3.3 mmol/L to delay insulin and 5.3 mmol/L to start potassium. Know your local protocol. "
"Check K+ at baseline, 2 hours after starting insulin, then 4 hourly.")
rows = [["Serum K+ (mmol/L)", "Action"],
["Above 5.0", "No potassium yet. Start insulin. Recheck K+ in 2 hours."],
["3.5 to 5.0", "Add potassium to fluids (about 10 mmol/h, or 20 to 30 mmol per liter). Start insulin. Target K+ 4 to 5."],
["Below 3.5", "Give potassium 10 mmol/h first. Delay insulin until K+ is above 3.5."]]
fills = {(1, 0): RGBColor(0xF6, 0xC9, 0xC4), (2, 0): RGBColor(0xD6, 0xEF, 0xE4), (3, 0): RGBColor(0xFB, 0xDF, 0xC4)}
table(s, 0.6, 1.6, 12.1, [3.0, 9.1], rows, 18, 0.85, fills=fills)
bullets(s, 0.6, 5.2, 12.1, 1.7, [
"Total body potassium is depleted even when serum K+ is high; insulin and rehydration will drive it down quickly",
"Check K+ at baseline, at 2 hours, then every 4 hours until resolution",
"Severe hypokalemia causes arrhythmias and respiratory muscle weakness",
], 17, gap=6)
# ---------------------------------------------------------------- 12 Insulin
s = new_slide("Step 3: Insulin",
"The aim is to suppress ketogenesis, not just to lower glucose. If glucose does not fall by about 50 mg/dL in the first hour, check hydration and increase the rate. "
"Dextrose lets you keep insulin running until ketones clear.")
card(s, 0.6, 1.6, 6.0, 3.0, "Intravenous regimen",
["Regular insulin 0.1 U/kg/h, fixed rate",
"Bolus is optional, not required",
"Target glucose fall 50 to 75 mg/dL per hour",
"If glucose fall is less than 50 in hour 1: check fluids, then increase rate"], NAVY, 17)
card(s, 6.9, 1.6, 5.8, 3.0, "Add dextrose",
["When glucose reaches about 200 to 250 mg/dL",
"5% or 10% dextrose with continued insulin",
"Do not stop or pause insulin for low-normal glucose while ketones persist"], TEAL, 17)
card(s, 0.6, 4.85, 12.1, 1.95, "Mild DKA",
"Selected patients may be treated with subcutaneous rapid-acting insulin analogs in a monitored ward setting, according to local protocol. "
"Severe or unstable DKA needs IV insulin in a high-dependency area.", AMBER, 16)
# ---------------------------------------------------------------- 13 Bicarb phosphate
s = new_slide("Bicarbonate, phosphate, magnesium",
"Routine bicarbonate is not recommended. The 2024 report limits it to severe acidemia. Bicarbonate can worsen hypokalemia, cause paradoxical CNS acidosis and delay ketone clearance. "
"A recent meta-analysis (Endocrinol Diabetes Metab 2026, PMID 41797565) addressed this question; read it before changing practice.")
card(s, 0.6, 1.6, 4.0, 4.9, "Bicarbonate",
["Not routine",
"Consider only if pH is below 7.0",
"Give with potassium monitoring",
"No proven benefit on outcomes in studies of moderate acidosis"], RED, 16)
card(s, 4.7, 1.6, 4.0, 4.9, "Phosphate",
["Not routine",
"Replace if below 1.0 mmol/L (about 3 mg/dL)",
"Especially with muscle weakness, cardiac or respiratory impairment",
"Monitor calcium after replacement"], AMBER, 16)
card(s, 8.8, 1.6, 4.0, 4.9, "Magnesium and calcium",
["Check magnesium; replace if low (e.g., 1 to 2 g magnesium sulfate)",
"Low magnesium makes hypokalemia refractory",
"Check ionized calcium; treat if symptomatic or QT prolonged"], TEAL, 16)
# ---------------------------------------------------------------- 14 Monitoring
s = new_slide("Monitoring schedule",
"Beta-hydroxybutyrate is the preferred marker of response. In settings without it, normalization of the anion gap is a reasonable surrogate, but it is unreliable if hyperchloremic acidosis develops.")
rows = [["Parameter", "Frequency", "Why"],
["Capillary glucose", "Every 1 to 2 hours", "Avoid hypoglycemia, guide dextrose"],
["Potassium", "Baseline, 2 h after insulin, then every 4 h", "Prevent hypokalemia"],
["Venous pH, bicarbonate", "Every 4 hours", "Track acid-base recovery"],
["Beta-hydroxybutyrate", "Every 4 hours (or hourly bedside meter)", "Best measure of ketone clearance"],
["Na, urea, creatinine, phosphate, Mg", "Every 4 hours", "Fluid choice, AKI, replacement"],
["Vitals, mental status, urine output", "Hourly", "Detect deterioration, fluid overload, cerebral edema"]]
table(s, 0.6, 1.6, 12.1, [3.8, 4.3, 4.0], rows, 16, 0.7)
text(s, 0.6, 6.65, 12.1, 0.4, "Escalate if pH is not improving at 4 to 6 hours or if mental status worsens.", 15, False, GREY)
# ---------------------------------------------------------------- 15 Acid-base steps
s = new_slide("Acid-base interpretation: 5 steps",
"Work through these steps with every gas. The caveat on step 4: after saline resuscitation a non-gap component often appears, so a delta ratio below 1 is common during treatment.")
rows = [["Step", "Formula", "Interpretation"],
["1. pH and HCO3", "pH below 7.35, HCO3 low", "Metabolic acidosis"],
["2. Anion gap", "Na - (Cl + HCO3); normal about 12", "Raised: unmeasured anions (ketones, lactate)"],
["3. Winter's formula", "Expected pCO2 = 1.5 x HCO3 + 8 (+/- 2)", "Higher than expected: inadequate compensation, respiratory failure risk"],
["4. Delta-delta", "(AG - 12) / (24 - HCO3)", "About 1: pure gap. Below 1: added non-gap acidosis. Above 2: added metabolic alkalosis"],
["5. Effective osmolality", "2 x Na + glucose / 18", "Above 300 suggests HHS component"]]
table(s, 0.6, 1.6, 12.1, [2.6, 4.2, 5.3], rows, 16, 0.78)
text(s, 0.6, 6.4, 12.1, 0.6,
"Correct anion gap for albumin when albumin is low (add about 2.5 mmol/L per 1 g/dL fall).", 15, False, GREY)
# ---------------------------------------------------------------- 16 Case 1
s = new_slide("Case: 63-year-old with hyperglycemia and Kussmaul breathing",
"Two blood gases 2.5 hours apart from the same patient (de-identified). Ask learners to compute the anion gap, Winter's expected pCO2 and delta ratio before revealing the answers on the next slide. "
"The first sample appears venous (pO2 57.5); the second looks arterial (pO2 137.9), so compare pCO2 with caution.")
rows = [["Parameter", "Gas 1 (09:13)", "Gas 2 (11:40)", "Reference"],
["pH", "6.823", "7.035", "7.35 to 7.45"],
["pCO2 (mmHg)", "30.7", "14.6", "35 to 45"],
["HCO3 (mmol/L)", "4.9", "3.8", "19 to 26"],
["Base excess", "-29", "-25", ""],
["Na / K / Cl (mmol/L)", "139.6 / 5.35 / 104", "143.4 / 4.48 / 113", ""],
["Glucose (mg/dL)", "562", "416", "70 to 110"],
["Lactate (mmol/L)", "4.41", "4.21", "1 to 1.8"],
["Hct (%) / Ca++ (mmol/L)", "44 / 1.25", "37 / 1.00", ""]]
table(s, 0.6, 1.6, 8.2, [2.8, 1.9, 1.9, 1.6], rows, 15, 0.55)
card(s, 9.1, 1.6, 3.7, 4.95, "Your turn",
["Anion gap at each time point?",
"Is compensation adequate?",
"Delta ratio and what it means?",
"What changed in chloride and hematocrit, and why?",
"What would you do next?"], TEAL, 15)
# ---------------------------------------------------------------- 17 Case answers
s = new_slide("Case: worked answers",
"Key teaching message: pH improvement came from hyperventilation, not from metabolic recovery. Bicarbonate fell. Insulin must continue, and fluids should be balanced crystalloid.")
card(s, 0.6, 1.6, 6.0, 2.55, "Gas 1: severe high gap acidosis",
["Anion gap about 31; Winter's expected pCO2 15 +/- 2, measured 30.7",
"Inadequate compensation: tiring or concurrent respiratory acidosis",
"Delta ratio about 1: pure gap acidosis"], RED, 15)
card(s, 6.9, 1.6, 5.8, 2.55, "Gas 2: improving but mixed",
["Anion gap about 27; expected pCO2 about 14, measured 14.6: appropriate",
"Delta ratio about 0.7: added hyperchloremic acidosis (Cl 104 to 113)",
"HCO3 fell; pH rose only because pCO2 fell"], AMBER, 15)
card(s, 0.6, 4.35, 12.1, 2.5, "Next steps",
["Continue IV insulin; add dextrose when glucose is about 200 to 250 mg/dL",
"Add potassium (K+ 4.48 and falling); check phosphate, magnesium, ionized calcium (1.00)",
"Switch to balanced crystalloid; track beta-hydroxybutyrate, not glucose or pH alone",
"Hct fell 44 to 37 from rehydration; lactate unchanged at 4.2, so reassess perfusion and look for sepsis"], NAVY, 15)
# ---------------------------------------------------------------- 18 Resolution
s = new_slide("Resolution and transition to subcutaneous insulin",
"Stopping IV insulin without basal cover is a classic cause of recurrent DKA. Give basal insulin before stopping the infusion. Involve the diabetes team before discharge.")
card(s, 0.6, 1.6, 5.9, 2.7, "Resolution criteria (2024)",
["Beta-hydroxybutyrate below 0.6 mmol/L",
"AND venous pH 7.3 or higher OR bicarbonate 18 mmol/L or higher",
"Patient able to eat"], GREEN, 17)
card(s, 6.8, 1.6, 5.9, 2.7, "Transition",
["Give subcutaneous basal insulin 2 to 4 hours before stopping the infusion",
"Start rapid-acting insulin with meals",
"Re-establish the patient's full regimen, adjust for the cause"], NAVY, 17)
card(s, 0.6, 4.55, 12.1, 2.3, "Before discharge",
["Identify and treat the trigger; review SGLT2 inhibitor use (stop in most cases after DKA)",
"Education: sick-day rules, ketone testing, never omit basal insulin",
"Arrange early follow-up with the diabetes team"], TEAL, 16)
# ---------------------------------------------------------------- 19 Complications
s = new_slide("Complications and common pitfalls",
"Cerebral edema is mainly a pediatric concern, but changes in mental status in adults should still prompt reassessment. Offer VTE prophylaxis to all admitted patients unless contraindicated.")
card(s, 0.6, 1.6, 6.0, 5.2, "Treatment complications",
["Hypoglycemia: add dextrose, do not stop insulin",
"Hypokalemia: check K+ before insulin; replace",
"Hyperchloremic acidosis: use balanced fluids",
"Fluid overload and pulmonary edema in heart or renal disease",
"Thromboembolism: pharmacologic prophylaxis",
"Cerebral edema: rare in adults; watch for headache, falling GCS"], RED, 16)
card(s, 6.9, 1.6, 5.8, 5.2, "Pitfalls to avoid",
["Starting insulin before knowing potassium",
"Stopping insulin when glucose normalizes but ketones remain",
"Judging recovery by pH or glucose alone",
"Giving bicarbonate routinely",
"Missing the precipitant (infection, MI)",
"Intubating without necessity: loss of respiratory drive can worsen acidemia",
"Stopping IV insulin without basal cover"], AMBER, 16)
# ---------------------------------------------------------------- 20 Summary
s = new_slide("Take-home points",
"Review and invite questions.")
bullets(s, 0.7, 1.7, 11.9, 5, [
"DKA = glucose or diabetes + ketosis (BHB 3.0 or higher) + acidosis (pH below 7.3 or HCO3 below 18)",
"Fluids first, potassium known before insulin, then fixed-rate IV insulin 0.1 U/kg/h",
"Add potassium once K+ is 5.0 or lower; delay insulin if K+ is below 3.5",
"Add dextrose at glucose about 200 to 250 mg/dL; keep insulin going until ketones clear",
"Bicarbonate only for pH below 7.0; phosphate only if below 1.0 mmol/L with symptoms",
"Resolution = BHB below 0.6 plus pH 7.3 or higher or HCO3 18 or higher; give basal insulin before stopping the drip",
"Find the trigger, prevent recurrence",
], 20, gap=12)
# ---------------------------------------------------------------- 21 References
s = new_slide("Sources",
"Check local protocols before applying doses and thresholds.")
bullets(s, 0.7, 1.6, 11.9, 5.2, [
"Umpierrez GE, Davis GM, ElSayed NA, et al. Hyperglycemic crises in adults with diabetes: a consensus report. Diabetes Care 2024;47:1257-1275 (also Diabetologia 2024;67:1455-1479).",
"Rosen's Emergency Medicine: Concepts and Clinical Practice. Box: Summary of treatment of diabetic ketoacidosis.",
"Goldman-Cecil Medicine. Treatment of diabetic ketoacidosis (fixed-rate IV insulin, potassium regimen).",
"Comprehensive Clinical Nephrology, 7th ed. Mixed metabolic acidosis and delta-delta assessment.",
"Omayer A, Kc A, Sharif A. The role of bicarbonate therapy in diabetic ketoacidosis: systematic review and meta-analysis. Endocrinol Diabetes Metab 2026 (PMID 41797565). Not reviewed in detail for this deck.",
"Note: the 2024 consensus uses potassium thresholds of 5.0 and 3.5 mmol/L and a bicarbonate cutoff of pH below 7.0. Older protocols use 5.3, 3.3 and pH below 6.9.",
], 16, gap=10)
prs.save("/tmp/workspace/dka-deck/output/DKA_Management_Protocol_Teaching_Deck.pptx")
print("saved", state["n"])
cd /tmp/workspace/dka-deck && python src/build.py
cd /tmp/workspace/dka-deck && cat > src/check.py <<'EOF' from pptx import Presentation from pptx.util import Emu import math prs = Presentation("output/DKA_Management_Protocol_Teaching_Deck.pptx") for i, s in enumerate(prs.slides, 1): for sh in s.shapes: if sh.has_text_frame and sh.text_frame.text.strip() and sh.shape_type == 17: w = Emu(sh.width).inches - 0.2 h = Emu(sh.height).inches tot = 0 for p in sh.text_frame.paragraphs: if not p.runs: continue sz = p.runs[0].font.size.pt txt = "".join(r.text for r in p.runs) indent = 0.3 if p._p.pPr is not None and p._p.pPr.get("marL") else 0 cpl = max(1, (w - indent) * 72 / (sz * 0.48)) lines = sum(max(1, math.ceil(len(t) / cpl)) for t in txt.split("\n")) sp = (p.space_after.pt if p.space_after else 0) tot += lines * sz * 1.2 + sp need = tot / 72 + 0.1 if need > h + 0.02: print(f"slide {i}: need {need:.2f} have {h:.2f} :: {sh.text_frame.text[:50]!r}") for sh in s.shapes: if sh.has_table: t = sh.table tot = 0 for r in t.rows: mx = 0 for ci, c in enumerate(r.cells): w = Emu(t.columns[ci].width).inches - 0.16 run = c.text_frame.paragraphs[0].runs if not run: continue sz = run[0].font.size.pt cpl = w * 72 / (sz * 0.48) lines = math.ceil(len(c.text_frame.text) / cpl) mx = max(mx, lines * sz * 1.2 / 72 + 0.1) tot += max(mx, Emu(r.height).inches) print(f"slide {i}: table top {Emu(sh.top).inches:.2f} est bottom {Emu(sh.top).inches + tot:.2f}") EOF python src/check.py
cd /tmp/workspace/dka-deck && sed -i 's/Case: 63-year-old with hyperglycemia and Kussmaul breathing/Case: two blood gases, 2.5 hours apart/' src/build.py && python - <<'EOF' p="src/build.py" t=open(p).read() t=t.replace('''"Corrected Na normal or low: continue isotonic fluid"], NAVY, 18)''','''"Corrected Na normal or low: continue isotonic fluid"], NAVY, 17)''') open(p,"w").write(t) EOF python src/build.py && python src/check.py | grep -v table; ls -la output
DKA Management Protocol Teaching Deck
Presentation · PPTX