Make a diet chart of patient age 55 weight 74 height 5 feet 8 inch and he is ckd 4 stage
mkdir -p /home/daytona/workspace/ckd-diet && ls /home/daytona/workspace/ckd-diet/
~/ckd-diet/build_diet_chart.py
from openpyxl import Workbook
from openpyxl.styles import (
Font, PatternFill, Alignment, Border, Side, GradientFill
)
from openpyxl.utils import get_column_letter
from openpyxl.formatting.rule import ColorScaleRule
wb = Workbook()
# ─────────────────────────────────────────────
# COLOURS
# ─────────────────────────────────────────────
TEAL_DARK = "1A5276" # deep teal
TEAL_MED = "1F8E9E" # medium teal
TEAL_LIGHT = "D6EAF8" # very light blue
GREEN_LIGHT = "EAFAF1"
AMBER = "F39C12"
RED_LIGHT = "FDEDEC"
WHITE = "FFFFFF"
GREY_LIGHT = "F2F3F4"
ORANGE_LIGHT= "FEF9E7"
def thick_border():
t = Side(style='medium', color="1A5276")
return Border(left=t, right=t, top=t, bottom=t)
def thin_border():
t = Side(style='thin', color="AAAAAA")
return Border(left=t, right=t, top=t, bottom=t)
def hdr_font(size=11, bold=True, color=WHITE):
return Font(name='Arial', bold=bold, size=size, color=color)
def body_font(size=10, bold=False, color="1C2833"):
return Font(name='Arial', bold=bold, size=size, color=color)
def fill(hex_color):
return PatternFill("solid", start_color=hex_color, fgColor=hex_color)
def center(wrap=True):
return Alignment(horizontal='center', vertical='center', wrap_text=wrap)
def left(wrap=True):
return Alignment(horizontal='left', vertical='center', wrap_text=wrap)
# ─────────────────────────────────────────────────────────────────────────────
# SHEET 1 – PATIENT SUMMARY & NUTRIENT TARGETS
# ─────────────────────────────────────────────────────────────────────────────
ws1 = wb.active
ws1.title = "Patient Profile & Targets"
ws1.sheet_view.showGridLines = False
# Title row
ws1.merge_cells("A1:F1")
ws1["A1"] = "CKD STAGE 4 – PERSONALISED DIET CHART"
ws1["A1"].font = Font(name='Arial', bold=True, size=16, color=WHITE)
ws1["A1"].fill = fill(TEAL_DARK)
ws1["A1"].alignment = center()
ws1.row_dimensions[1].height = 38
# Subtitle
ws1.merge_cells("A2:F2")
ws1["A2"] = "Patient Age: 55 yrs | Weight: 74 kg | Height: 5 ft 8 in (172.7 cm) | BMI: 24.8 | Sex: Male"
ws1["A2"].font = Font(name='Arial', bold=False, size=11, color=WHITE)
ws1["A2"].fill = fill(TEAL_MED)
ws1["A2"].alignment = center()
ws1.row_dimensions[2].height = 22
ws1.row_dimensions[3].height = 8 # spacer
# ── Section A: Nutrient Targets ──
ws1.merge_cells("A4:F4")
ws1["A4"] = "DAILY NUTRIENT TARGETS (based on KDOQI / NKF Primer – CKD Stages 3–5, Non-dialysis)"
ws1["A4"].font = hdr_font(12)
ws1["A4"].fill = fill(TEAL_MED)
ws1["A4"].alignment = left()
ws1.row_dimensions[4].height = 22
headers_a = ["Nutrient", "Target", "Patient Dose", "Unit", "Rationale", "Alert"]
for col, h in enumerate(headers_a, 1):
c = ws1.cell(row=5, column=col, value=h)
c.font = hdr_font(10)
c.fill = fill(TEAL_DARK)
c.alignment = center()
c.border = thin_border()
ws1.row_dimensions[5].height = 20
targets = [
("Energy", "25–35 kcal/kg/day", "=74*30", "kcal/day",
"Prevent protein-energy wasting (PEW)", "Aim 2,220 kcal"),
("Protein", "0.55–0.60 g/kg/day","=74*0.6", "g/day",
"Slow CKD progression; non-diabetic CKD 3-5", "Max 44 g"),
("Phosphorus", "800–1,000 mg/day", "≤1000", "mg/day",
"Prevent hyperphosphataemia & vascular calcification", "Use binders if needed"),
("Potassium", "2,000–3,000 mg/day","≤2500", "mg/day",
"Prevent hyperkalaemia (CKD 4 reduced excretion)", "Monitor serum K+"),
("Sodium", "< 2,300 mg/day", "<2300", "mg/day",
"Blood-pressure & fluid control", "Avoid processed foods"),
("Fluid", "1,500–2,000 mL/day","1500", "mL/day",
"Individualised – based on urine output + 500 mL", "Adjust per oedema"),
("Calcium", "1,000–1,200 mg/day","1000", "mg/day",
"Prevent secondary hyperparathyroidism", "Avoid excess Ca supplements"),
("Iron (dietary)","8–18 mg/day", "8", "mg/day",
"Support haemoglobin (CKD-related anaemia)", "May need EPO/IV iron"),
("Saturated Fat","< 7% of energy", "<154", "mg/day ÷ 9 → g",
"Reduce cardiovascular risk (common comorbidity)", "Choose plant oils"),
("Fibre", "25–38 g/day", "≥25", "g/day",
"Gut microbiome, uraemic toxin reduction", "Soluble fibre preferred"),
]
row = 6
for t in targets:
ws1.cell(row, 1, t[0]).font = body_font(10, True)
ws1.cell(row, 2, t[1]).font = body_font(10)
ws1.cell(row, 3, t[2]).font = body_font(10, True, "1A5276")
ws1.cell(row, 4, t[3]).font = body_font(10)
ws1.cell(row, 5, t[4]).font = body_font(9)
ws1.cell(row, 6, t[5]).font = body_font(9, color=AMBER)
bg = GREY_LIGHT if row % 2 == 0 else WHITE
for col in range(1, 7):
ws1.cell(row, col).fill = fill(bg)
ws1.cell(row, col).alignment = left()
ws1.cell(row, col).border = thin_border()
ws1.row_dimensions[row].height = 24
row += 1
# ── Foods to Avoid ──
row += 1
ws1.merge_cells(f"A{row}:F{row}")
ws1[f"A{row}"] = "FOODS TO AVOID / LIMIT"
ws1[f"A{row}"].font = hdr_font(12)
ws1[f"A{row}"].fill = fill("C0392B")
ws1[f"A{row}"].alignment = left()
ws1.row_dimensions[row].height = 22
row += 1
avoid_headers = ["Category", "Foods to Avoid / Limit", "Reason"]
for col, h in enumerate(avoid_headers, 1):
c = ws1.cell(row, col, h)
c.font = hdr_font(10)
c.fill = fill("922B21")
c.alignment = center()
c.border = thin_border()
ws1.row_dimensions[row].height = 20
row += 1
avoid = [
("High-Potassium Fruits", "Banana, orange, mango, avocado, kiwi, dried fruits",
"Hyperkalemia risk (K > 3.5 mEq/L)"),
("High-Potassium Vegetables","Potato, tomato, spinach, beet, mushroom (raw)",
"Leach potassium by boiling & discarding water"),
("High-Phosphorus Foods", "Dairy (cheese, milk >½ cup/day), nuts, seeds, legumes, cola drinks",
"Hyperphosphatemia → vascular calcification"),
("Processed/Canned Foods", "Canned soups, pickles, processed meats, fast food",
"Excess sodium & phosphate additives"),
("High-Protein Foods (excess)","Red meat, poultry >allowed portion, fish >allowed",
"Accelerates CKD progression & urea load"),
("Whole grains (large qty)","Bran cereals, whole-wheat in excess",
"High phosphorus; moderate use only"),
("Salt & Salt Substitutes", "Table salt, rock salt, KCl salt substitutes",
"Sodium overload / potassium excess"),
("Dark-Coloured Colas", "Pepsi, Coke – contain inorganic phosphate additives",
"100% absorbed – raises PO4 more than organic PO4"),
("Alcohol", "Beer, wine, spirits",
"Worsens hypertension, uric acid, fluid balance"),
]
for a in avoid:
ws1.merge_cells(f"B{row}:C{row}")
ws1.cell(row, 1, a[0]).font = body_font(10, True)
ws1.cell(row, 2, a[1]).font = body_font(10)
ws1.cell(row, 3, a[2]).font = body_font(9)
for col in range(1, 4):
ws1.cell(row, col).fill = fill(RED_LIGHT)
ws1.cell(row, col).alignment = left()
ws1.cell(row, col).border = thin_border()
ws1.row_dimensions[row].height = 22
row += 1
# Column widths
col_widths = [22, 28, 20, 14, 45, 28]
for i, w in enumerate(col_widths, 1):
ws1.column_dimensions[get_column_letter(i)].width = w
# ─────────────────────────────────────────────────────────────────────────────
# SHEET 2 – WEEKLY MEAL PLAN
# ─────────────────────────────────────────────────────────────────────────────
ws2 = wb.create_sheet("7-Day Meal Plan")
ws2.sheet_view.showGridLines = False
# Title
ws2.merge_cells("A1:H1")
ws2["A1"] = "7-DAY MEAL PLAN — CKD Stage 4 | 74 kg Male | ~2,220 kcal/day | Protein ~44 g/day"
ws2["A1"].font = Font(name='Arial', bold=True, size=14, color=WHITE)
ws2["A1"].fill = fill(TEAL_DARK)
ws2["A1"].alignment = center()
ws2.row_dimensions[1].height = 34
meal_cols = ["Day", "Early Morning", "Breakfast", "Mid-Morning Snack",
"Lunch", "Evening Snack", "Dinner", "Bedtime"]
for col, h in enumerate(meal_cols, 1):
c = ws2.cell(2, col, h)
c.font = hdr_font(10)
c.fill = fill(TEAL_MED)
c.alignment = center()
c.border = thin_border()
ws2.row_dimensions[2].height = 22
# Daily meal plans
meal_data = [
("Monday",
"1 glass warm water + ½ tsp cumin",
"2 egg whites scrambled + 1 slice white bread + apple (small)",
"1 cup low-K fruit (pear/apple)",
"1 cup boiled white rice + ½ cup bottle gourd (lauki) curry + 1 chapati (maida)",
"1 cup arrowroot/rice cracker + herbal tea",
"½ cup boiled chicken (50g) + ½ cup cauliflower sabzi + 1 chapati",
"½ cup rice porridge (kanji) or warm milk alternative (rice milk)"),
("Tuesday",
"Warm water + lemon drops (small)",
"Semolina upma (low salt) + 1 small apple",
"Rice puff (murmura) handful",
"2 chapatis + ½ cup ridge gourd curry + 1 egg-white omelette",
"Cucumber slices (boiled/peeled) + herbal tea",
"½ cup steamed fish (50g) + ½ cup stir-fried cabbage + 1 cup rice",
"Arrowroot biscuit + warm water"),
("Wednesday",
"1 glass water + soaked white rice (overnight)",
"Poha (flattened rice) – low salt + coriander + small apple",
"1 low-K fruit (plum/pear)",
"1 cup rice + ½ cup ash gourd (pethha) curry + 50g paneer (small)",
"Rice crackers + herbal lemon tea",
"50g boiled chicken + ½ cup green beans (French beans) + 1 chapati",
"Warm rice water or plain sago"),
("Thursday",
"Warm water with tulsi leaves",
"2 idlis (small) + coconut chutney (small) + pear",
"Cucumber slices (peeled) + rice crackers",
"1 cup rice + ½ cup tinda (round gourd) sabzi + 1 egg-white curry",
"Arrowroot biscuits + herbal tea",
"50g steamed prawn + ½ cup carrot (boiled, drained) + 1 chapati",
"½ cup sago pudding (sabudana kheer, low sugar)"),
("Friday",
"Warm water + small piece ginger",
"Vermicelli upma (low salt) + 1 small apple",
"Pear / plum (1 small)",
"2 chapatis + ½ cup lauki dal (moong, low quantity) + salad (lettuce+cucumber)",
"Rice puff (murmura) + herbal tea",
"50g boiled chicken + ½ cup broad beans (sem, well-boiled) + 1 cup rice",
"Warm low-phosphorus rice milk"),
("Saturday",
"Warm water + cumin",
"Dalia porridge (broken wheat, small) + 1 apple",
"Rice crackers + herbal tea",
"1 cup rice + ½ cup snake gourd curry + 50g paneer",
"1 small pear + rice cracker",
"50g grilled fish + ½ cup drumstick (moringa) sabzi + 1 chapati",
"Arrowroot biscuit + warm water"),
("Sunday",
"Warm water + lemon",
"2 egg-white omelette + 1 white toast + small apple",
"Low-K fruit (pear/apple)",
"1 cup rice + ½ cup bottle-gourd dal + small bowl green salad",
"Rice crackers + herbal lemon tea",
"50g boiled mutton (lean, fat removed) + ½ cup stir-fried cauliflower + 1 chapati",
"Sago porridge or warm rice water"),
]
day_fills = [
"EBF5FB", "E8F8F5", "FEF9E7", "F9EBEA", "F4ECF7", "EAFAF1", "FDF2F8"
]
for r_idx, row_data in enumerate(meal_data, 3):
bg = day_fills[r_idx - 3]
for col_idx, val in enumerate(row_data, 1):
c = ws2.cell(r_idx, col_idx, val)
c.font = body_font(9, bold=(col_idx == 1))
c.fill = fill(bg)
c.alignment = left()
c.border = thin_border()
ws2.row_dimensions[r_idx].height = 60
# Column widths
meal_col_widths = [11, 22, 30, 25, 38, 25, 38, 28]
for i, w in enumerate(meal_col_widths, 1):
ws2.column_dimensions[get_column_letter(i)].width = w
# ─────────────────────────────────────────────────────────────────────────────
# SHEET 3 – FOOD EXCHANGE LIST
# ─────────────────────────────────────────────────────────────────────────────
ws3 = wb.create_sheet("Food Exchange Guide")
ws3.sheet_view.showGridLines = False
ws3.merge_cells("A1:E1")
ws3["A1"] = "FOOD EXCHANGE GUIDE — CKD Stage 4 (Protein, Potassium, Phosphorus Control)"
ws3["A1"].font = Font(name='Arial', bold=True, size=13, color=WHITE)
ws3["A1"].fill = fill(TEAL_DARK)
ws3["A1"].alignment = center()
ws3.row_dimensions[1].height = 30
exch_headers = ["Food Group", "Allowed (Low K / Low P)", "Exchange Qty", "Avoid", "Tips"]
for col, h in enumerate(exch_headers, 1):
c = ws3.cell(2, col, h)
c.font = hdr_font(10)
c.fill = fill(TEAL_MED)
c.alignment = center()
c.border = thin_border()
ws3.row_dimensions[2].height = 20
exchanges = [
("Grains / Cereals",
"White rice, white bread, maida chapati, suji, poha, vermicelli, sabudana",
"1 cup cooked / 1 chapati = 1 exchange",
"Bran, whole wheat (excess), oats (large qty)",
"White grains have less phosphorus than whole grains"),
("Vegetables\n(Low K)",
"Bottle gourd (lauki), ridge gourd, snake gourd, ash gourd, tinda, cauliflower, cabbage, French beans, carrot (½ cup boiled)",
"½ cup cooked = 1 exchange",
"Potato, tomato, spinach, beet, raw banana",
"Boil & discard water to leach potassium by up to 50%"),
("Fruits\n(Low K)",
"Apple, pear, plum, strawberry, blueberry, grapes (small)",
"1 small fruit = 1 exchange",
"Banana, orange, mango, kiwi, avocado, dried fruits",
"Avoid fruit juices – concentrated potassium"),
("Protein – Animal",
"Egg whites (limit yolks), chicken breast (50g), fish (50g), lean mutton (50g, rare)",
"50g cooked = 1 exchange\n(2 exchanges/day max)",
"Organ meats, shellfish in excess, processed meats",
"Boil and drain meat to reduce phosphorus"),
("Protein – Vegetarian",
"Paneer (small qty, ≤30g), tofu (small), moong dal (½ cup, limited)",
"30g paneer = 1 exchange",
"All legumes in excess, soya in large qty",
"Protein from plant sources preferred for CKD progression"),
("Dairy",
"Low-phosphorus rice milk / almond milk (unsupplemented)\nRegular milk ≤½ cup/day",
"½ cup = 1 exchange",
"Cheese, yogurt in excess, flavoured milk, ice cream",
"Dairy is major source of phosphorus in diet"),
("Fats & Oils",
"Olive oil, mustard oil, rice-bran oil\n1–2 tsp/meal",
"1 tsp = 1 exchange",
"Butter, ghee (excess), coconut cream, trans fats",
"Heart-healthy oils reduce CVD risk comorbid in CKD"),
("Fluids",
"Water, herbal tea, lemon water\n1,500–2,000 mL total/day",
"Track ALL fluids including soups",
"Colas, fruit juices, coconut water (high K), alcohol",
"Count fluid in food (soups, curries) toward daily limit"),
("Sweets / Desserts",
"Sago pudding (low sugar), arrowroot biscuits, rice pudding (small)",
"1 small serving = 1 exchange",
"Chocolate, nuts-based sweets, dark sodas",
"Limit sugar; diabetic patients must monitor glycaemia"),
("Spices / Condiments",
"Cumin, coriander, turmeric, ginger, garlic (small), fresh herbs",
"Small quantities freely",
"Salt, soy sauce, pickles, ketchup, canned sauces",
"Use herbs & spices to add flavour without sodium"),
]
for r_idx, ex in enumerate(exchanges, 3):
bg = GREY_LIGHT if r_idx % 2 == 0 else WHITE
for col_idx, val in enumerate(ex, 1):
c = ws3.cell(r_idx, col_idx, val)
c.font = body_font(9, bold=(col_idx == 1))
c.fill = fill(bg)
c.alignment = left()
c.border = thin_border()
ws3.row_dimensions[r_idx].height = 50
exch_col_widths = [18, 40, 26, 35, 42]
for i, w in enumerate(exch_col_widths, 1):
ws3.column_dimensions[get_column_letter(i)].width = w
# ─────────────────────────────────────────────────────────────────────────────
# SHEET 4 – MONITORING CHECKLIST
# ─────────────────────────────────────────────────────────────────────────────
ws4 = wb.create_sheet("Monitoring Checklist")
ws4.sheet_view.showGridLines = False
ws4.merge_cells("A1:D1")
ws4["A1"] = "MONITORING CHECKLIST — CKD Stage 4"
ws4["A1"].font = Font(name='Arial', bold=True, size=13, color=WHITE)
ws4["A1"].fill = fill(TEAL_DARK)
ws4["A1"].alignment = center()
ws4.row_dimensions[1].height = 30
mon_headers = ["Parameter", "Target / Normal Range", "Frequency", "Action if Abnormal"]
for col, h in enumerate(mon_headers, 1):
c = ws4.cell(2, col, h)
c.font = hdr_font(10)
c.fill = fill(TEAL_MED)
c.alignment = center()
c.border = thin_border()
monitors = [
("Serum Potassium (K+)", "3.5–5.0 mEq/L", "Every 1–3 months", "Restrict dietary K; review medications"),
("Serum Phosphorus (PO4)", "2.7–4.6 mg/dL", "Every 1–3 months", "Phosphate binders; reduce dairy/legumes"),
("Serum Creatinine / eGFR", "Monitor trend", "Every 1–3 months", "Refer nephrology if rapid decline"),
("Serum Bicarbonate", "≥22 mEq/L", "Every 1–3 months", "Oral NaHCO3 0.5–1 mEq/kg/day"),
("Haemoglobin", "11.0–12.0 g/dL", "Every 3 months", "EPO injections; oral/IV iron"),
("Serum Albumin", "≥3.5 g/dL", "Every 3 months", "Increase caloric intake; treat inflammation"),
("Blood Pressure", "<130/80 mmHg", "Every visit", "ACE inhibitor/ARB; sodium restriction"),
("Blood Glucose (if DM)", "FBG <130 mg/dL", "Every visit", "Adjust insulin/OHA; dietary counselling"),
("Serum Calcium", "8.4–10.2 mg/dL", "Every 3 months", "Adjust Ca supplements & vitamin D"),
("PTH (iPTH)", "70–110 pg/mL (CKD 4)","Every 6 months", "Calcitriol / cinacalcet if elevated"),
("Body Weight", "Stable; BMI 18.5–25", "Every visit", "Adjust calorie target; rule out fluid overload"),
("24-h Urine Protein", "<500 mg/day ideally", "Every 3–6 months", "ACE inhibitor/ARB uptitration"),
("Urea Nitrogen Appearance", "Matches protein intake","Every 3 months", "Dietary compliance counselling"),
("Fluid Balance", "Neutral/slight deficit","Daily at home", "Adjust fluid restriction; diuretics if needed"),
]
for r_idx, m in enumerate(monitors, 3):
bg = GREEN_LIGHT if r_idx % 2 == 0 else WHITE
for col_idx, val in enumerate(m, 1):
c = ws4.cell(r_idx, col_idx, val)
c.font = body_font(9, bold=(col_idx == 1))
c.fill = fill(bg)
c.alignment = left()
c.border = thin_border()
ws4.row_dimensions[r_idx].height = 24
mon_col_widths = [26, 28, 22, 40]
for i, w in enumerate(mon_col_widths, 1):
ws4.column_dimensions[get_column_letter(i)].width = w
# ─────────────────────────────────────────────────────────────────────────────
# SAVE
# ─────────────────────────────────────────────────────────────────────────────
output_path = "/home/daytona/workspace/ckd-diet/CKD4_Diet_Chart_55yr_74kg.xlsx"
wb.save(output_path)
print(f"Saved: {output_path}")
cd /home/daytona/workspace/ckd-diet && python build_diet_chart.py
~/ckd-diet/build_diet_chart.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/ckd-diet/build_diet_chart.py'