Dietary guidelines for renal calculi

Reading File
Finding Sources
Finding Sources
Searching PubMed

"kidney stones" AND "dietary" AND "prevention"

Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
Reading File
I now have rich material from multiple textbooks. Let me compile the comprehensive answer.

Dietary Guidelines for Renal Calculi

Dietary management is the first-line approach for preventing stone recurrence and depends on stone composition. The same core principles apply across all types, with specific modifications per stone type.

Universal Dietary Measures (All Stone Types)

1. Fluid Intake - Most Important

The single most effective dietary intervention is increasing urine output to >2 L/day (some guidelines say 2-2.5 L/day). High urine volume reduces supersaturation of calcium oxalate, calcium phosphate, and uric acid, reducing the likelihood of crystal nucleation.
  • Patients should be taught their baseline 24-hour urine volume and advised to drink enough more to reach the 2 L target
  • Maximum risk is at night (physiologic concentration); patients should drink in the evening, induce nocturia, and drink again before returning to bed
  • Avoid sugar-sweetened beverages and fructose-containing drinks - these increase stone risk by raising urinary calcium and uric acid excretion
  • Alcohol (especially beer), dark colas, and energy drinks should be minimized

2. Sodium Restriction

Urinary sodium directly drives urinary calcium excretion (each mmol of extra sodium in urine brings 1-1.25 mg of calcium with it). Limiting sodium intake to <2 g/day (87 mmol/day) reduces hypercalciuria and is synergistic with thiazide diuretics if those are used.

3. Animal Protein Restriction

Excess animal protein increases stone risk by multiple mechanisms:
  • Sulfur-containing amino acids (methionine, cysteine) are metabolized to sulfate, acidifying the urine and reducing calcium solubility
  • Metabolic acidosis causes calcium release from bone, increasing filtered calcium load
  • Acidosis decreases tubular calcium reabsorption, worsening hypercalciuria
  • Animal protein raises uric acid excretion
  • Acid load reduces urinary citrate (the key inhibitor of calcium stone formation)
A landmark RCT demonstrated that a diet with 1200 mg calcium + low sodium + low animal protein significantly reduced stone recurrence versus a low-calcium diet alone in men with recurrent calcium oxalate stones.

4. Potassium and Fruits/Vegetables

Higher potassium intake reduces urinary calcium excretion. Many fruits and vegetables contain organic anions (citrate, malate) that are metabolized to bicarbonate, alkalinizing the urine and increasing urinary citrate excretion - the main inhibitor of calcium stone formation. A plant-rich diet is beneficial for most stone formers.

Stone-Type Specific Recommendations

Calcium Oxalate Stones (most common, ~70-80%)

Urinary AbnormalityDietary Change
HypercalciuriaRestrict sodium and animal protein; maintain adequate (not excessive) calcium; avoid calcium supplements
HyperoxaluriaAvoid high-oxalate foods; maintain adequate dietary calcium; avoid high-dose vitamin C
HypocitraturiaIncrease fruits and vegetables; reduce animal protein
Low volumeIncrease fluid intake
HyperuricosuriaReduce purine intake
Calcium intake - a critical nuance:
  • Dietary calcium should NOT be restricted - this is a common and harmful misconception
  • Low dietary calcium increases intestinal oxalate absorption (less calcium in the gut to bind oxalate), raising urinary oxalate
  • Adequate dietary calcium is 1000-1200 mg/day (age/sex-appropriate)
  • Calcium supplements, however, may increase stone risk unless taken with meals (when they can bind food oxalate)
  • Excessive calcium intake (>1200 mg/day) should be avoided
High-oxalate foods to restrict:
  • Spinach (the highest single source), rhubarb, almonds/nuts, beets, potatoes, wheat bran, chocolate
  • Extreme oxalate restriction is not recommended and may harm overall health; targeted avoidance of the highest sources is sufficient
  • Vitamin C supplementation (>1 g/day) is converted to oxalate endogenously and should be avoided

Calcium Phosphate Stones

Similar to calcium oxalate guidelines, with added emphasis on:
  • Avoiding excess alkali intake (alkaline urine promotes calcium phosphate precipitation)
  • Reducing sodium and animal protein
  • Maintaining adequate fluid intake

Uric Acid Stones (5-10% in the US, up to 75% in some regions)

Three main targets: low urine pH, low urine volume, and elevated urinary uric acid.
  • Reduce purines: limit red meat, organ meats, shellfish, anchovies, sardines, and beer; a plant-based diet rich in legumes and vegetables is ideal
  • Increase urine pH: alkalinizing foods (citrus fruits, vegetables) raise urine pH; potassium citrate pharmacologically is often needed (target urine pH 6.0-6.5)
  • Increase fluid intake: as for all stone types
  • Reduce fructose: high-fructose corn syrup and sugar-sweetened drinks raise uric acid production and excretion
  • Uric acid stones can actually dissolve with sustained urinary alkalinization, unlike calcium stones

Struvite Stones (infection stones)

Dietary modification alone is insufficient. These require treatment of underlying urinary infection (Proteus, Klebsiella, etc.). Urinary acidification with ammonium chloride or methionine is sometimes used. Surgical removal of the stone itself is usually necessary for definitive management.

Cystine Stones

  • Very high fluid intake (target urine volume >3 L/day) - the most important measure
  • Low-sodium diet (reduces cystine excretion because cystine transport is coupled to sodium)
  • Low-methionine diet: limit animal protein (the precursor of cystine)
  • Alkalinizing the urine to pH >7.0 increases cystine solubility (citrus fruits, vegetables; potassium citrate pharmacologically)

Summary Table

Stone TypeIncreaseRestrict
All typesFluids (>2 L urine/day)Sodium (<2 g/day), sugar-sweetened drinks
Calcium oxalateDietary calcium (1000-1200 mg), fruits, vegetablesAnimal protein, oxalate-rich foods, vitamin C supplements, sodium
Calcium phosphateFruits and vegetables, fluidAnimal protein, sodium, excess alkali
Uric acidFluids, alkaline foods, citrusPurines (meat, shellfish), fructose, alcohol/beer
CystineFluids (>3 L urine/day), alkaline foodsAnimal protein, sodium

Key Points to Emphasize to Patients

  1. Drink more - this is the single highest-yield intervention for every stone type
  2. Do not cut calcium from the diet - it protects against oxalate stones and protects bone
  3. Reduce salt - it drives calcium into the urine
  4. Eat less animal protein - it acidifies urine, raises calcium and uric acid excretion, and reduces citrate
  5. Avoid vitamin C supplements in calcium oxalate stone formers
  6. Dietary changes must be lifelong - stone disease is a chronic condition

Sources: Comprehensive Clinical Nephrology 7th Ed.; Harrison's Principles of Internal Medicine 22E (2025); National Kidney Foundation Primer on Kidney Diseases 8th Ed.
Recent evidence note: A 2024 systematic review (PMID 38814276) on nephrolithiasis risk factors and a 2026 systematic review (PMID 41116039) on anti-urolithiasis approaches are consistent with these textbook guidelines. No major dietary recommendations appear to have been overturned in recent literature.

Pdf with images

Reading File
Running Command

ls -la /home/daytona/workspace/ 2>/dev/null || mkdir -p /home/daytona/workspace

Running Command

mkdir -p /home/daytona/workspace/renal-calculi-pdf && python3 -c "import reportlab; print('reportlab OK')" && python3 -c "import requests; print('requests OK')"

Writing File

~/renal-calculi-pdf/generate_pdf.py

import requests
import os
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, 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.flowables import Flowable
from io import BytesIO

OUTPUT = "/home/daytona/workspace/renal-calculi-pdf/Dietary_Guidelines_Renal_Calculi.pdf"

# ── Colour palette ──────────────────────────────────────────────────────────
TEAL        = colors.HexColor("#0D6E82")
TEAL_LIGHT  = colors.HexColor("#E6F4F7")
AMBER       = colors.HexColor("#D97706")
AMBER_LIGHT = colors.HexColor("#FFF7ED")
GREEN       = colors.HexColor("#15803D")
GREEN_LIGHT = colors.HexColor("#F0FDF4")
RED_LIGHT   = colors.HexColor("#FEF2F2")
RED         = colors.HexColor("#DC2626")
GREY_DARK   = colors.HexColor("#1F2937")
GREY_MID    = colors.HexColor("#6B7280")
GREY_LIGHT  = colors.HexColor("#F3F4F6")
WHITE       = colors.white

# ── Styles ──────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()

def make_style(name, parent="Normal", **kwargs):
    return ParagraphStyle(name, parent=styles[parent], **kwargs)

title_style = make_style("MyTitle",
    fontSize=26, textColor=WHITE, alignment=TA_CENTER,
    fontName="Helvetica-Bold", spaceAfter=4, leading=32)

subtitle_style = make_style("MySubtitle",
    fontSize=13, textColor=colors.HexColor("#B2EBF5"),
    alignment=TA_CENTER, fontName="Helvetica", spaceAfter=0)

h1_style = make_style("H1",
    fontSize=16, textColor=TEAL, fontName="Helvetica-Bold",
    spaceBefore=14, spaceAfter=4, leading=20)

h2_style = make_style("H2",
    fontSize=12, textColor=GREY_DARK, fontName="Helvetica-Bold",
    spaceBefore=10, spaceAfter=3, leading=16)

body_style = make_style("Body",
    fontSize=10, textColor=GREY_DARK, fontName="Helvetica",
    leading=15, spaceAfter=6, alignment=TA_JUSTIFY)

bullet_style = make_style("Bullet",
    fontSize=10, textColor=GREY_DARK, fontName="Helvetica",
    leading=14, leftIndent=14, spaceAfter=3,
    bulletIndent=4, bulletFontName="Helvetica", bulletFontSize=10)

caption_style = make_style("Caption",
    fontSize=8, textColor=GREY_MID, fontName="Helvetica-Oblique",
    alignment=TA_CENTER, spaceAfter=6, leading=11)

table_header_style = make_style("TH",
    fontSize=9, textColor=WHITE, fontName="Helvetica-Bold",
    alignment=TA_CENTER, leading=12)

table_cell_style = make_style("TD",
    fontSize=9, textColor=GREY_DARK, fontName="Helvetica",
    alignment=TA_LEFT, leading=13, leftIndent=4)

small_style = make_style("Small",
    fontSize=8, textColor=GREY_MID, fontName="Helvetica-Oblique",
    alignment=TA_CENTER, leading=10)

# ── Helper: download image ──────────────────────────────────────────────────
def fetch_image_url(url, max_w, max_h):
    """Download URL and return a ReportLab Image flowable, or None on failure."""
    try:
        resp = requests.get(url, timeout=15)
        resp.raise_for_status()
        img_data = BytesIO(resp.content)
        img = Image(img_data, width=max_w, height=max_h, kind="proportional")
        return img
    except Exception as e:
        print(f"  [WARN] Could not fetch {url}: {e}")
        return None

# ── Cover page flowable ─────────────────────────────────────────────────────
class ColorRect(Flowable):
    def __init__(self, w, h, fill_color):
        super().__init__()
        self.w, self.h, self.fill_color = w, h, fill_color
    def wrap(self, *args):
        return self.w, self.h
    def draw(self):
        self.canv.setFillColor(self.fill_color)
        self.canv.rect(0, 0, self.w, self.h, stroke=0, fill=1)

# ── Build story ─────────────────────────────────────────────────────────────
def build_story():
    W, H = A4
    story = []

    # ── COVER ────────────────────────────────────────────────────────────────
    story.append(Spacer(1, 2*cm))
    # Teal header band via table background
    cover_data = [[Paragraph(
        "Dietary Guidelines for<br/>Renal Calculi",
        ParagraphStyle("CoverTitle", fontSize=28, textColor=WHITE,
                       fontName="Helvetica-Bold", alignment=TA_CENTER, leading=36))]]
    cover_tbl = Table(cover_data, colWidths=[W - 4*cm])
    cover_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), TEAL),
        ("TOPPADDING",    (0,0), (-1,-1), 22),
        ("BOTTOMPADDING", (0,0), (-1,-1), 22),
        ("LEFTPADDING",   (0,0), (-1,-1), 18),
        ("RIGHTPADDING",  (0,0), (-1,-1), 18),
        ("ROUNDEDCORNERS", [6]),
    ]))
    story.append(cover_tbl)
    story.append(Spacer(1, 0.4*cm))

    story.append(Paragraph(
        "Evidence-based nutritional strategies for prevention and management of kidney stones",
        ParagraphStyle("CoverSub", fontSize=12, textColor=GREY_MID,
                       fontName="Helvetica-Oblique", alignment=TA_CENTER, leading=16)))
    story.append(Spacer(1, 0.5*cm))
    story.append(HRFlowable(width="100%", thickness=1, color=TEAL_LIGHT))
    story.append(Spacer(1, 0.3*cm))
    story.append(Paragraph(
        "Sources: Harrison's Principles of Internal Medicine 22E (2025) · Comprehensive Clinical Nephrology 7th Ed. · "
        "NKF Primer on Kidney Diseases 8th Ed. · Campbell-Walsh-Wein Urology",
        small_style))
    story.append(Spacer(1, 1.5*cm))

    # ── SECTION 1: Overview ──────────────────────────────────────────────────
    story.append(Paragraph("Overview", h1_style))
    story.append(HRFlowable(width="100%", thickness=1.5, color=TEAL, spaceAfter=6))
    story.append(Paragraph(
        "Renal calculi (kidney stones) are a chronic condition with a lifetime prevalence of approximately 10%. "
        "Dietary modification is the cornerstone of prevention and recurrence reduction. Recommendations must be "
        "tailored to stone composition, identified urinary abnormalities (from 24-hour urine collection), and individual "
        "risk factors. The 'stone clinic effect' - a substantial decrease in recurrence seen simply by consulting a "
        "stone specialist - is largely attributable to dietary and fluid intake modifications.",
        body_style))

    # Stone type distribution box
    dist_data = [
        [Paragraph("<b>Stone Type</b>", table_header_style),
         Paragraph("<b>Frequency</b>", table_header_style),
         Paragraph("<b>Key Feature</b>", table_header_style)],
        [Paragraph("Calcium oxalate", table_cell_style),
         Paragraph("70-80%", table_cell_style),
         Paragraph("Most common; radiopaque", table_cell_style)],
        [Paragraph("Calcium phosphate", table_cell_style),
         Paragraph("~10%", table_cell_style),
         Paragraph("Associated with high urine pH", table_cell_style)],
        [Paragraph("Uric acid", table_cell_style),
         Paragraph("5-10%", table_cell_style),
         Paragraph("Radiolucent; dissolves with alkalinization", table_cell_style)],
        [Paragraph("Struvite", table_cell_style),
         Paragraph("~5%", table_cell_style),
         Paragraph("Infection stones; Proteus/Klebsiella", table_cell_style)],
        [Paragraph("Cystine", table_cell_style),
         Paragraph("~1%", table_cell_style),
         Paragraph("Genetic; requires very high fluid intake", table_cell_style)],
    ]
    dist_tbl = Table(dist_data, colWidths=[5.5*cm, 3.5*cm, 8.0*cm])
    dist_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), TEAL),
        ("BACKGROUND", (0,1), (-1,1), TEAL_LIGHT),
        ("BACKGROUND", (0,2), (-1,2), WHITE),
        ("BACKGROUND", (0,3), (-1,3), TEAL_LIGHT),
        ("BACKGROUND", (0,4), (-1,4), WHITE),
        ("BACKGROUND", (0,5), (-1,5), TEAL_LIGHT),
        ("ROWBACKGROUNDS", (0,1), (-1,-1), [TEAL_LIGHT, WHITE]),
        ("GRID",        (0,0), (-1,-1), 0.4, colors.HexColor("#CBD5E1")),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 6),
        ("RIGHTPADDING",  (0,0), (-1,-1), 6),
        ("VALIGN",      (0,0), (-1,-1), "MIDDLE"),
    ]))
    story.append(dist_tbl)
    story.append(Spacer(1, 0.4*cm))

    # ── SECTION 2: Universal Dietary Measures ───────────────────────────────
    story.append(Paragraph("Universal Dietary Measures (All Stone Types)", h1_style))
    story.append(HRFlowable(width="100%", thickness=1.5, color=TEAL, spaceAfter=6))

    # 2a Fluid intake
    story.append(Paragraph("1. Fluid Intake - The Most Important Intervention", h2_style))
    story.append(Paragraph(
        "The single most effective dietary measure is increasing urine output to <b>more than 2 L/day</b>. "
        "High urine volume dilutes all stone-forming solutes, reducing supersaturation of calcium oxalate, "
        "calcium phosphate, and uric acid. Patients with cystine stones require even higher targets (>3 L/day).",
        body_style))

    fluid_bullets = [
        "Target: urine output <b>>2 L/day</b> (not simply drinking 2 L - insensible losses vary)",
        "Risk is highest at night (physiologic concentration); drink in the evening, induce nocturia, drink again before returning to bed",
        "<b>Avoid</b> sugar-sweetened beverages and fructose-containing drinks - increase urinary calcium and uric acid",
        "Avoid dark colas (high phosphoric acid), energy drinks, and excess alcohol",
        "Water, diluted citrus juices (lemon/lime), and herbal teas are preferred",
        "Educate patients on their 24-hour urine volume baseline and how much more they need to drink",
    ]
    for b in fluid_bullets:
        story.append(Paragraph(f"• {b}", bullet_style))
    story.append(Spacer(1, 0.3*cm))

    # 2b Sodium
    story.append(Paragraph("2. Sodium Restriction", h2_style))
    story.append(Paragraph(
        "Urinary sodium directly drives urinary calcium excretion. Each increase in sodium intake "
        "raises calcium excretion in the urine. Restricting sodium to <b>&lt;2 g/day (87 mmol/day)</b> "
        "reduces hypercalciuria and potentiates thiazide diuretics when used pharmacologically. "
        "Sodium restriction is effective for calcium stones of all subtypes.",
        body_style))

    # 2c Animal protein
    story.append(Paragraph("3. Animal Protein Restriction", h2_style))
    story.append(Paragraph(
        "Excess animal protein increases stone risk through several parallel mechanisms:",
        body_style))
    protein_bullets = [
        "Sulfur amino acids (methionine, cysteine) are metabolized to sulfate, acidifying urine and reducing calcium solubility",
        "Metabolic acidosis causes calcium release from bone, increasing filtered calcium load",
        "Acid load decreases tubular calcium reabsorption, worsening hypercalciuria",
        "Protein catabolism raises uric acid excretion",
        "Acid load reduces urinary citrate - the primary endogenous inhibitor of stone formation",
    ]
    for b in protein_bullets:
        story.append(Paragraph(f"• {b}", bullet_style))
    story.append(Paragraph(
        "A landmark RCT showed that a diet with <b>1200 mg calcium + low sodium + low animal protein</b> "
        "significantly reduced stone recurrence compared with a low-calcium diet alone in men with "
        "recurrent calcium oxalate stones.",
        body_style))

    # 2d Potassium
    story.append(Paragraph("4. Fruits, Vegetables, and Potassium", h2_style))
    story.append(Paragraph(
        "Higher potassium intake reduces urinary calcium excretion. Many fruits and vegetables contain organic "
        "anions (citrate, malate) metabolized to bicarbonate, which alkalinizes urine and increases citrate "
        "excretion - the key inhibitor of calcium crystal nucleation. A plant-rich diet benefits most stone formers.",
        body_style))

    # ── SECTION 3: Stone-Type Specific ──────────────────────────────────────
    story.append(PageBreak())
    story.append(Paragraph("Stone-Type Specific Recommendations", h1_style))
    story.append(HRFlowable(width="100%", thickness=1.5, color=TEAL, spaceAfter=8))

    # --- 3a Calcium oxalate ---
    ca_data = [[Paragraph("CALCIUM OXALATE STONES (~70-80%)", 
                           ParagraphStyle("StoneHead", fontSize=12, textColor=WHITE,
                                          fontName="Helvetica-Bold", alignment=TA_CENTER))]]
    ca_hdr = Table(ca_data, colWidths=[W - 4*cm])
    ca_hdr.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), TEAL),
        ("TOPPADDING",    (0,0), (-1,-1), 8),
        ("BOTTOMPADDING", (0,0), (-1,-1), 8),
    ]))
    story.append(ca_hdr)
    story.append(Spacer(1, 0.2*cm))

    # Critical calcium nuance box
    cal_box_data = [[
        Paragraph(
            "<b>Key Nuance: Do NOT Restrict Dietary Calcium</b><br/><br/>"
            "Restricting dietary calcium is a common but harmful misconception. "
            "Low dietary calcium increases intestinal oxalate absorption (less calcium in the gut to bind oxalate), "
            "raising urinary oxalate and stone risk. It also promotes bone demineralization.<br/><br/>"
            "<b>Recommended intake:</b> 1000-1200 mg/day (age- and sex-appropriate dietary calcium)<br/>"
            "<b>Calcium supplements:</b> May increase stone risk - if needed, take with meals to bind food oxalate. "
            "Check 24-hr urine calcium with and without supplement.",
            ParagraphStyle("NuanceBox", fontSize=10, textColor=GREY_DARK,
                           fontName="Helvetica", leading=15, leftIndent=4))
    ]]
    cal_box_tbl = Table(cal_box_data, colWidths=[W - 4*cm])
    cal_box_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), AMBER_LIGHT),
        ("BOX",        (0,0), (-1,-1), 1.5, AMBER),
        ("TOPPADDING",    (0,0), (-1,-1), 10),
        ("BOTTOMPADDING", (0,0), (-1,-1), 10),
        ("LEFTPADDING",   (0,0), (-1,-1), 12),
        ("RIGHTPADDING",  (0,0), (-1,-1), 12),
    ]))
    story.append(cal_box_tbl)
    story.append(Spacer(1, 0.3*cm))

    # Calcium oxalate dietary table
    co_table_data = [
        [Paragraph("<b>Urinary Abnormality</b>", table_header_style),
         Paragraph("<b>Dietary Change</b>", table_header_style),
         Paragraph("<b>Avoid</b>", table_header_style)],
        [Paragraph("Hypercalciuria", table_cell_style),
         Paragraph("Restrict sodium; maintain adequate dietary Ca (1000-1200 mg/day)", table_cell_style),
         Paragraph("Calcium supplements; excess Na; sucrose", table_cell_style)],
        [Paragraph("Hyperoxaluria", table_cell_style),
         Paragraph("Maintain adequate dietary Ca to bind gut oxalate", table_cell_style),
         Paragraph("Spinach, rhubarb, almonds, beets, wheat bran, chocolate; vitamin C supplements", table_cell_style)],
        [Paragraph("Hypocitraturia", table_cell_style),
         Paragraph("Increase fruits and vegetables; lemon juice", table_cell_style),
         Paragraph("Animal protein; low-potassium diets", table_cell_style)],
        [Paragraph("Hyperuricosuria", table_cell_style),
         Paragraph("Reduce purine intake", table_cell_style),
         Paragraph("Red meat, organ meats, shellfish, beer", table_cell_style)],
        [Paragraph("Low urine volume", table_cell_style),
         Paragraph("Increase total fluid to achieve >2 L urine/day", table_cell_style),
         Paragraph("Sugar-sweetened drinks, dark colas", table_cell_style)],
    ]
    co_tbl = Table(co_table_data, colWidths=[4*cm, 7*cm, 6*cm])
    co_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), TEAL),
        ("ROWBACKGROUNDS", (0,1), (-1,-1), [TEAL_LIGHT, WHITE]),
        ("GRID",        (0,0), (-1,-1), 0.4, colors.HexColor("#CBD5E1")),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
        ("RIGHTPADDING",  (0,0), (-1,-1), 5),
        ("VALIGN",      (0,0), (-1,-1), "TOP"),
    ]))
    story.append(co_tbl)
    story.append(Spacer(1, 0.4*cm))

    # High oxalate foods list (visual)
    story.append(Paragraph("High-Oxalate Foods to Restrict:", h2_style))
    oxalate_data = [
        [Paragraph("<b>Very High</b><br/>(avoid)", 
                   ParagraphStyle("ox1", fontSize=9, textColor=RED, fontName="Helvetica-Bold",
                                  alignment=TA_CENTER)),
         Paragraph("<b>High</b><br/>(limit)", 
                   ParagraphStyle("ox2", fontSize=9, textColor=AMBER, fontName="Helvetica-Bold",
                                  alignment=TA_CENTER)),
         Paragraph("<b>Moderate</b><br/>(use in moderation)", 
                   ParagraphStyle("ox3", fontSize=9, textColor=GREEN, fontName="Helvetica-Bold",
                                  alignment=TA_CENTER))],
        [Paragraph("Spinach\nRhubarb\nBeets\nPeanuts\nSwiss chard", table_cell_style),
         Paragraph("Almonds\nChocolate\nWheat bran\nSweet potatoes\nBlueberries", table_cell_style),
         Paragraph("Oranges\nTomatoes\nBroccoli\nCoffee\nBeer", table_cell_style)],
    ]
    ox_tbl = Table(oxalate_data, colWidths=[(W-4*cm)/3]*3)
    ox_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (0,0), RED_LIGHT),
        ("BACKGROUND", (1,0), (1,0), AMBER_LIGHT),
        ("BACKGROUND", (2,0), (2,0), GREEN_LIGHT),
        ("BACKGROUND", (0,1), (0,1), RED_LIGHT),
        ("BACKGROUND", (1,1), (1,1), AMBER_LIGHT),
        ("BACKGROUND", (2,1), (2,1), GREEN_LIGHT),
        ("BOX",        (0,0), (-1,-1), 0.5, GREY_MID),
        ("INNERGRID",  (0,0), (-1,-1), 0.4, colors.HexColor("#CBD5E1")),
        ("TOPPADDING",    (0,0), (-1,-1), 6),
        ("BOTTOMPADDING", (0,0), (-1,-1), 6),
        ("LEFTPADDING",   (0,0), (-1,-1), 8),
        ("RIGHTPADDING",  (0,0), (-1,-1), 8),
        ("VALIGN",      (0,0), (-1,-1), "TOP"),
        ("ALIGN",       (0,0), (-1,0), "CENTER"),
    ]))
    story.append(ox_tbl)
    story.append(Spacer(1, 0.5*cm))

    # --- 3b Uric acid ---
    ua_data = [[Paragraph("URIC ACID STONES (5-10%)",
                           ParagraphStyle("UaHead", fontSize=12, textColor=WHITE,
                                          fontName="Helvetica-Bold", alignment=TA_CENTER))]]
    ua_hdr = Table(ua_data, colWidths=[W - 4*cm])
    ua_hdr.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), AMBER),
        ("TOPPADDING",    (0,0), (-1,-1), 8),
        ("BOTTOMPADDING", (0,0), (-1,-1), 8),
    ]))
    story.append(ua_hdr)
    story.append(Spacer(1, 0.2*cm))
    story.append(Paragraph(
        "Three major factors drive uric acid stone formation: <b>low urine pH</b> (principal factor), "
        "<b>low urine volume</b>, and <b>elevated urinary uric acid</b>. Unlike calcium stones, uric acid "
        "stones can actually <b>dissolve</b> with sustained urinary alkalinization.",
        body_style))

    ua_bullets = [
        "<b>Reduce purines:</b> limit red meat, organ meats, shellfish, anchovies, sardines, and beer",
        "<b>Reduce fructose:</b> high-fructose corn syrup and sugar-sweetened drinks raise uric acid production",
        "<b>Alkalinize urine:</b> eat citrus fruits and vegetables; target urine pH 6.0-6.5 (potassium citrate pharmacologically)",
        "<b>Increase fluid intake</b> to achieve >2 L urine/day",
        "Obesity and insulin resistance promote uric acid stones via impaired ammoniagenesis and urinary acidosis",
        "A plant-rich, low-purine diet (legumes, whole grains, vegetables) is ideal",
    ]
    for b in ua_bullets:
        story.append(Paragraph(f"• {b}", bullet_style))
    story.append(Spacer(1, 0.4*cm))

    # --- 3c Cystine ---
    cy_data = [[Paragraph("CYSTINE STONES (~1%)",
                           ParagraphStyle("CyHead", fontSize=12, textColor=WHITE,
                                          fontName="Helvetica-Bold", alignment=TA_CENTER))]]
    cy_hdr = Table(cy_data, colWidths=[W - 4*cm])
    cy_hdr.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), GREEN),
        ("TOPPADDING",    (0,0), (-1,-1), 8),
        ("BOTTOMPADDING", (0,0), (-1,-1), 8),
    ]))
    story.append(cy_hdr)
    story.append(Spacer(1, 0.2*cm))

    cy_bullets = [
        "<b>Very high fluid intake</b> - target >3 L urine/day (highest requirement of all stone types)",
        "<b>Low sodium</b> - reduces cystine excretion (cystine transport is coupled to sodium)",
        "<b>Low methionine (animal protein)</b> - methionine is the metabolic precursor of cystine",
        "<b>Alkalinize urine to pH >7.0</b> - increases cystine solubility; citrus, vegetables; potassium citrate pharmacologically",
    ]
    for b in cy_bullets:
        story.append(Paragraph(f"• {b}", bullet_style))
    story.append(Spacer(1, 0.4*cm))

    # --- 3d Struvite ---
    st_data = [[Paragraph("STRUVITE STONES (INFECTION STONES, ~5%)",
                           ParagraphStyle("StHead", fontSize=12, textColor=WHITE,
                                          fontName="Helvetica-Bold", alignment=TA_CENTER))]]
    st_hdr = Table(st_data, colWidths=[W - 4*cm])
    st_hdr.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), RED),
        ("TOPPADDING",    (0,0), (-1,-1), 8),
        ("BOTTOMPADDING", (0,0), (-1,-1), 8),
    ]))
    story.append(st_hdr)
    story.append(Spacer(1, 0.2*cm))
    story.append(Paragraph(
        "Dietary modification alone is insufficient for struvite stones. These form due to urease-producing "
        "organisms (Proteus, Klebsiella, Pseudomonas) that alkalinize urine. Management requires eradication "
        "of infection and surgical stone removal. Urinary acidification (ammonium chloride, methionine) is "
        "sometimes used adjunctively.",
        body_style))
    story.append(Spacer(1, 0.5*cm))

    # ── SECTION 4: Summary Table ─────────────────────────────────────────────
    story.append(PageBreak())
    story.append(Paragraph("Summary: Dietary Recommendations by Stone Type", h1_style))
    story.append(HRFlowable(width="100%", thickness=1.5, color=TEAL, spaceAfter=8))

    summary_data = [
        [Paragraph("<b>Stone Type</b>", table_header_style),
         Paragraph("<b>Increase</b>", table_header_style),
         Paragraph("<b>Restrict</b>", table_header_style),
         Paragraph("<b>Target pH</b>", table_header_style)],
        [Paragraph("All types", table_cell_style),
         Paragraph("Fluids (>2 L urine/day)\nFruits and vegetables", table_cell_style),
         Paragraph("Sodium (<2 g/day)\nSugar-sweetened drinks", table_cell_style),
         Paragraph("Varies", table_cell_style)],
        [Paragraph("Calcium\nOxalate", table_cell_style),
         Paragraph("Dietary Ca (1000-1200 mg)\nFruits, vegetables\nLemon juice", table_cell_style),
         Paragraph("Animal protein\nOxalate-rich foods\nVitamin C supplements\nCalcium supplements", table_cell_style),
         Paragraph("Neutral\n(insensitive to pH)", table_cell_style)],
        [Paragraph("Calcium\nPhosphate", table_cell_style),
         Paragraph("Fluids\nFruits, vegetables", table_cell_style),
         Paragraph("Animal protein\nSodium\nExcess alkali", table_cell_style),
         Paragraph("Slightly acid\n(<6.5)", table_cell_style)],
        [Paragraph("Uric Acid", table_cell_style),
         Paragraph("Fluids\nAlkaline foods\nCitrus", table_cell_style),
         Paragraph("Purines (meat, shellfish)\nFructose\nAlcohol/beer", table_cell_style),
         Paragraph("Alkaline\n(6.0-6.5)", table_cell_style)],
        [Paragraph("Cystine", table_cell_style),
         Paragraph("Fluids (>3 L urine/day)\nAlkaline foods", table_cell_style),
         Paragraph("Animal protein\nSodium", table_cell_style),
         Paragraph("Alkaline\n(>7.0)", table_cell_style)],
    ]
    summary_tbl = Table(summary_data, colWidths=[3*cm, 5.5*cm, 6*cm, 2.5*cm])
    summary_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), TEAL),
        ("ROWBACKGROUNDS", (0,1), (-1,-1), [GREY_LIGHT, WHITE]),
        ("GRID",        (0,0), (-1,-1), 0.4, colors.HexColor("#CBD5E1")),
        ("TOPPADDING",    (0,0), (-1,-1), 6),
        ("BOTTOMPADDING", (0,0), (-1,-1), 6),
        ("LEFTPADDING",   (0,0), (-1,-1), 6),
        ("RIGHTPADDING",  (0,0), (-1,-1), 6),
        ("VALIGN",      (0,0), (-1,-1), "TOP"),
        ("ALIGN",       (3,1), (3,-1), "CENTER"),
    ]))
    story.append(summary_tbl)
    story.append(Spacer(1, 0.5*cm))

    # ── SECTION 5: Key Points ────────────────────────────────────────────────
    story.append(Paragraph("Key Points for Patient Education", h1_style))
    story.append(HRFlowable(width="100%", thickness=1.5, color=TEAL, spaceAfter=8))

    key_points = [
        ("<b>Drink more</b>", "This is the single highest-yield intervention for every stone type. Aim for >2 L urine output/day. Educate patients using their actual 24-hour urine volume."),
        ("<b>Do NOT cut dietary calcium</b>", "Dietary calcium restriction is harmful - it increases oxalate absorption and stone risk. Maintain 1000-1200 mg/day from food sources."),
        ("<b>Reduce salt</b>", "Sodium drives calcium into the urine. A low-sodium diet (&lt;2 g/day) reduces urinary calcium excretion and potentiates thiazide therapy."),
        ("<b>Eat less animal protein</b>", "Animal protein acidifies urine, raises calcium and uric acid excretion, and reduces citrate - the stone inhibitor."),
        ("<b>Avoid vitamin C supplements</b>", "In calcium oxalate stone formers, vitamin C &gt;1 g/day is converted to oxalate endogenously and increases stone risk."),
        ("<b>Lifestyle changes must be lifelong</b>", "Stone disease is a chronic condition. Short-term compliance is insufficient; patients must understand this is permanent prevention."),
    ]

    for i, (title, detail) in enumerate(key_points):
        num_data = [[
            Paragraph(str(i+1), ParagraphStyle(
                "Num", fontSize=14, textColor=WHITE, fontName="Helvetica-Bold",
                alignment=TA_CENTER, leading=18)),
            Paragraph(f"{title}<br/>{detail}",
                      ParagraphStyle("KP", fontSize=10, textColor=GREY_DARK,
                                     fontName="Helvetica", leading=14, leftIndent=4))
        ]]
        num_tbl = Table(num_data, colWidths=[1*cm, W-5.5*cm])
        num_tbl.setStyle(TableStyle([
            ("BACKGROUND", (0,0), (0,0), TEAL),
            ("BACKGROUND", (1,0), (1,0), TEAL_LIGHT),
            ("TOPPADDING",    (0,0), (-1,-1), 8),
            ("BOTTOMPADDING", (0,0), (-1,-1), 8),
            ("LEFTPADDING",   (0,0), (0,0), 4),
            ("RIGHTPADDING",  (0,0), (0,0), 4),
            ("LEFTPADDING",   (1,0), (1,0), 10),
            ("RIGHTPADDING",  (1,0), (1,0), 10),
            ("VALIGN",      (0,0), (-1,-1), "MIDDLE"),
            ("BOX",         (0,0), (-1,-1), 0.5, TEAL),
        ]))
        story.append(num_tbl)
        story.append(Spacer(1, 0.2*cm))

    story.append(Spacer(1, 0.5*cm))

    # ── SECTION 6: 24-hr Urine Treatment Table ───────────────────────────────
    story.append(Paragraph("Dietary Changes Indexed to 24-Hour Urine Abnormalities", h1_style))
    story.append(HRFlowable(width="100%", thickness=1.5, color=TEAL, spaceAfter=6))
    story.append(Paragraph(
        "A 24-hour urine collection (performed on usual diet, at least 6 weeks after a stone event) guides "
        "targeted dietary therapy. Two collections are recommended due to day-to-day variability. "
        "Key measurements: volume, calcium, oxalate, citrate, uric acid, sodium, potassium, phosphorus, pH, creatinine.",
        body_style))

    urine_data = [
        [Paragraph("<b>Abnormality</b>", table_header_style),
         Paragraph("<b>Dietary Change</b>", table_header_style),
         Paragraph("<b>Pharmacologic Option</b>", table_header_style)],
        [Paragraph("High Ca concentration", table_cell_style),
         Paragraph("Avoid excess Ca supplements; maintain dietary Ca; reduce animal protein; reduce Na <3 g/day; reduce sucrose", table_cell_style),
         Paragraph("Thiazide diuretic", table_cell_style)],
        [Paragraph("High oxalate", table_cell_style),
         Paragraph("Avoid high-oxalate foods; maintain adequate dietary Ca; avoid vitamin C supplements", table_cell_style),
         Paragraph("Pyridoxine, cholestyramine, Ca/Mg supplements", table_cell_style)],
        [Paragraph("High uric acid", table_cell_style),
         Paragraph("Reduce purine intake (meat, poultry, fish, shellfish)", table_cell_style),
         Paragraph("Allopurinol (xanthine oxidase inhibitor)", table_cell_style)],
        [Paragraph("Low citrate", table_cell_style),
         Paragraph("Increase fruits and vegetables; lemon juice; reduce animal protein", table_cell_style),
         Paragraph("Potassium citrate or potassium bicarbonate", table_cell_style)],
        [Paragraph("Low volume", table_cell_style),
         Paragraph("Increase total fluid intake to reach >2 L urine/day", table_cell_style),
         Paragraph("Not applicable", table_cell_style)],
    ]
    urine_tbl = Table(urine_data, colWidths=[4*cm, 7.5*cm, 5.5*cm])
    urine_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,0), TEAL),
        ("ROWBACKGROUNDS", (0,1), (-1,-1), [TEAL_LIGHT, WHITE]),
        ("GRID",        (0,0), (-1,-1), 0.4, colors.HexColor("#CBD5E1")),
        ("TOPPADDING",    (0,0), (-1,-1), 5),
        ("BOTTOMPADDING", (0,0), (-1,-1), 5),
        ("LEFTPADDING",   (0,0), (-1,-1), 5),
        ("RIGHTPADDING",  (0,0), (-1,-1), 5),
        ("VALIGN",      (0,0), (-1,-1), "TOP"),
    ]))
    story.append(urine_tbl)
    story.append(Spacer(1, 0.5*cm))

    # ── SECTION 7: Textbook Images ───────────────────────────────────────────
    story.append(PageBreak())
    story.append(Paragraph("Illustrations from Medical Literature", h1_style))
    story.append(HRFlowable(width="100%", thickness=1.5, color=TEAL, spaceAfter=8))

    images_to_fetch = [
        (
            "https://cdn.orris.care/cdss_images/3de0e068e3d950d5efaee2dc555b2256527591ef3450e2db5a2a637a9c3092cc.png",
            "Fig 1. The gut-kidney axis in nephrolithiasis. Antibiotics disrupt the microbiome, altering "
            "intestinal and urinary metabolite profiles, which can influence stone formation risk. "
            "(Source: NKF Primer on Kidney Diseases 8th Ed.)"
        ),
        (
            "https://cdn.orris.care/cdss_images/3201a2026e058cba2d904fee7a0c486973a0cb2319a846a0a848d1e97eae30ed.png",
            "Fig 2. Uric acid stone on imaging. Uric acid stones are radiolucent and poorly visible on plain "
            "radiographs but detectable on ultrasound and CT, often appearing as filling defects. "
            "(Source: Comprehensive Clinical Nephrology 7th Ed.)"
        ),
    ]

    for url, caption in images_to_fetch:
        print(f"  Fetching: {url[:60]}...")
        img = fetch_image_url(url, max_w=13*cm, max_h=8*cm)
        if img:
            img_tbl_data = [[img]]
            img_tbl = Table(img_tbl_data, colWidths=[W - 4*cm])
            img_tbl.setStyle(TableStyle([
                ("ALIGN",       (0,0), (-1,-1), "CENTER"),
                ("VALIGN",      (0,0), (-1,-1), "MIDDLE"),
                ("TOPPADDING",  (0,0), (-1,-1), 8),
                ("BOTTOMPADDING",(0,0),(-1,-1), 8),
                ("BOX",         (0,0), (-1,-1), 0.5, colors.HexColor("#CBD5E1")),
                ("BACKGROUND",  (0,0), (-1,-1), GREY_LIGHT),
            ]))
            story.append(img_tbl)
            story.append(Paragraph(caption, caption_style))
            story.append(Spacer(1, 0.5*cm))
        else:
            story.append(Paragraph(f"[Image unavailable: {caption}]", caption_style))

    # ── REFERENCES ──────────────────────────────────────────────────────────
    story.append(Spacer(1, 0.5*cm))
    story.append(HRFlowable(width="100%", thickness=0.8, color=GREY_MID))
    story.append(Spacer(1, 0.2*cm))
    story.append(Paragraph("References", h2_style))
    refs = [
        "1. Harrison's Principles of Internal Medicine, 22nd Edition (2025). McGraw-Hill Medical.",
        "2. Comprehensive Clinical Nephrology, 7th Edition. Elsevier.",
        "3. National Kidney Foundation Primer on Kidney Diseases, 8th Edition. Elsevier.",
        "4. Campbell-Walsh-Wein Urology. Elsevier.",
        "5. Brenner and Rector's The Kidney, 2-Volume Set. Elsevier.",
        "6. Ma Y et al. Risk factors for nephrolithiasis formation: an umbrella review. Int J Surg. 2024;[PMID: 38814276]",
        "7. Allam AT et al. A guide to effective prevention and treatment for kidney stones: a systematic review. "
           "Naunyn Schmiedebergs Arch Pharmacol. 2026;[PMID: 41116039]",
    ]
    for ref in refs:
        story.append(Paragraph(ref,
            ParagraphStyle("Ref", fontSize=8.5, textColor=GREY_DARK,
                           fontName="Helvetica", leading=13, spaceAfter=3, leftIndent=12,
                           firstLineIndent=-12)))

    return story


# ── Generate PDF ─────────────────────────────────────────────────────────────
def main():
    W, H = A4
    doc = SimpleDocTemplate(
        OUTPUT,
        pagesize=A4,
        rightMargin=2*cm, leftMargin=2*cm,
        topMargin=1.8*cm, bottomMargin=2*cm,
        title="Dietary Guidelines for Renal Calculi",
        author="Orris Medical AI",
    )

    story = build_story()
    doc.build(story)
    print(f"\nPDF saved to: {OUTPUT}")


if __name__ == "__main__":
    main()
Running Command

cd /home/daytona/workspace/renal-calculi-pdf && python3 generate_pdf.py

Running Command

cd /home/daytona/workspace/renal-calculi-pdf && python3 -c " import requests, os imgs = [ ('https://cdn.orris.care/cdss_images/3de0e068e3d950d5efaee2dc555b2256527591ef3450e2db5a2a637a9c3092cc.png', 'img1.png'), ('https://cdn.orris.care/cdss_images/3201a2026e058cba2d904fee7a0c486973a0cb2319a846a0a848d1e97eae30ed.png', 'img2.png'), ] for url, fname in imgs: try: r = requests.get(url, timeout=8) r.raise_for_status() with open(fname, 'wb') as f: f.write(r.content) print(f'OK {fname} {len(r.content)} bytes') except Exception as e: print(f'FAIL {fname}: {e}') "

Editing File

~/renal-calculi-pdf/generate_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/renal-calculi-pdf/generate_pdf.py'
Running Command

cd /home/daytona/workspace/renal-calculi-pdf && python3 generate_pdf.py

Running Command

ls -lh /home/daytona/workspace/renal-calculi-pdf/Dietary_Guidelines_Renal_Calculi.pdf

Your PDF is ready (1.2 MB, 4 pages with images):

Dietary Guidelines Renal Calculi

PDF Document · PDF

What's included:
  • Cover page with title and source attribution
  • Stone type distribution table (calcium oxalate, uric acid, struvite, cystine, calcium phosphate)
  • Universal measures - fluid intake, sodium restriction, animal protein, fruits/vegetables
  • Stone-type specific sections (calcium oxalate, uric acid, cystine, struvite) each with colour-coded headers
  • High-oxalate foods colour chart (avoid / limit / moderate)
  • Amber warning box on the calcium restriction misconception
  • 24-hour urine abnormality table mapping urinary findings to diet and drug options
  • Summary table by stone type (increase / restrict / target pH)
  • 6 numbered key patient education points
  • 2 textbook images - gut-kidney axis diagram and uric acid stone X-ray
  • References to Harrison's, Campbell-Walsh, NKF Primer, Comprehensive Clinical Nephrology, and recent PubMed systematic reviews
This is a shared conversation. Sign in to Orris to start your own chat.