For my pharmacology exam create a high quality pdf include diagrams and flowcharts for a 10 marks answer 1. Short note on B complex
mkdir -p /tmp/workspace/b-complex-pdf && ls /tmp/workspace/b-complex-pdf/
~/b-complex-pdf/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.lib import colors
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.platypus.flowables import Flowable
from reportlab.graphics.shapes import Drawing, Rect, String, Line, Circle, Polygon, Path
from reportlab.graphics.shapes import Group
from reportlab.graphics import renderPDF
from reportlab.lib.colors import HexColor, Color
import textwrap
# ── Colour palette ──────────────────────────────────────────────────────────
NAVY = HexColor('#1A2E52')
TEAL = HexColor('#00838F')
ORANGE = HexColor('#E65C00')
YELLOW = HexColor('#FFC107')
GREEN = HexColor('#2E7D32')
RED = HexColor('#C62828')
PURPLE = HexColor('#6A1B9A')
LBLUE = HexColor('#E3F2FD')
LTEAL = HexColor('#E0F7FA')
LGREEN = HexColor('#E8F5E9')
LORANGE = HexColor('#FFF3E0')
LPURPLE = HexColor('#F3E5F5')
LGREY = HexColor('#F5F5F5')
WHITE = colors.white
BLACK = colors.black
GREY = HexColor('#607D8B')
PAGE_W, PAGE_H = A4
MARGIN = 1.8 * cm
# ── Styles ───────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def make_style(name, parent='Normal', **kw):
s = ParagraphStyle(name, parent=styles[parent], **kw)
return s
title_style = make_style('DocTitle', 'Normal',
fontSize=26, textColor=WHITE, fontName='Helvetica-Bold',
alignment=1, leading=32)
subtitle_style = make_style('DocSub', 'Normal',
fontSize=13, textColor=HexColor('#B2EBF2'), fontName='Helvetica',
alignment=1, leading=18)
section_style = make_style('Section', 'Normal',
fontSize=14, textColor=WHITE, fontName='Helvetica-Bold',
leading=18, leftIndent=6, spaceBefore=4)
body_style = make_style('Body', 'Normal',
fontSize=10, textColor=HexColor('#212121'), fontName='Helvetica',
leading=15, spaceBefore=3, spaceAfter=3)
bullet_style = make_style('Bullet', 'Normal',
fontSize=10, textColor=HexColor('#212121'), fontName='Helvetica',
leading=14, leftIndent=18, bulletIndent=8, spaceBefore=2)
bold_body = make_style('BoldBody', 'Normal',
fontSize=10, textColor=NAVY, fontName='Helvetica-Bold',
leading=14, spaceBefore=3)
caption_style = make_style('Caption', 'Normal',
fontSize=8.5, textColor=GREY, fontName='Helvetica-Oblique',
alignment=1, leading=12)
table_header_style = make_style('TblHdr', 'Normal',
fontSize=9, textColor=WHITE, fontName='Helvetica-Bold',
alignment=1, leading=12)
table_cell_style = make_style('TblCell', 'Normal',
fontSize=8.5, textColor=HexColor('#212121'), fontName='Helvetica',
leading=12, leftIndent=4)
# ────────────────────────────────────────────────────────────────────────────
# Custom Flowable: Banner header for each section
# ────────────────────────────────────────────────────────────────────────────
class SectionBanner(Flowable):
def __init__(self, text, color=NAVY, width=None, height=32):
super().__init__()
self.text = text
self.color = color
self.width = width or (PAGE_W - 2 * MARGIN)
self.height = height
def wrap(self, aW, aH):
self.width = aW
return aW, self.height + 4
def draw(self):
c = self.canv
w, h = self.width, self.height
c.setFillColor(self.color)
c.roundRect(0, 0, w, h, 6, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 13)
c.drawCentredString(w / 2, h / 2 - 5, self.text)
# ────────────────────────────────────────────────────────────────────────────
# Title page box
# ────────────────────────────────────────────────────────────────────────────
class TitleBox(Flowable):
def __init__(self, width=None, height=220):
super().__init__()
self.width = width or (PAGE_W - 2 * MARGIN)
self.height = height
def wrap(self, aW, aH):
self.width = aW
return aW, self.height
def draw(self):
c = self.canv
w, h = self.width, self.height
# Gradient-like background (two overlapping rects)
c.setFillColor(NAVY)
c.roundRect(0, 0, w, h, 12, fill=1, stroke=0)
c.setFillColor(TEAL)
c.setFillAlpha(0.35)
c.roundRect(w * 0.55, 0, w * 0.45, h, 12, fill=1, stroke=0)
c.setFillAlpha(1)
# Decorative dots
c.setFillColor(WHITE)
c.setFillAlpha(0.08)
for i in range(5):
r = 30 + i * 15
c.circle(w * 0.85, h * 0.6, r, fill=1, stroke=0)
c.setFillAlpha(1)
# Text
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 28)
c.drawCentredString(w / 2, h - 55, 'SHORT NOTE ON B COMPLEX')
c.setFont('Helvetica', 14)
c.setFillColor(HexColor('#B2EBF2'))
c.drawCentredString(w / 2, h - 85, 'Pharmacology | 10 Marks Answer')
c.setFont('Helvetica', 10)
c.setFillColor(HexColor('#80DEEA'))
c.drawCentredString(w / 2, h - 110, 'Water-Soluble Vitamins • Mechanisms • Deficiencies • Clinical Uses')
# Divider
c.setStrokeColor(YELLOW)
c.setLineWidth(1.5)
c.line(w * 0.2, h - 125, w * 0.8, h - 125)
# Tags
tags = ['B1 Thiamine', 'B2 Riboflavin', 'B3 Niacin', 'B5 Pantothenic Acid',
'B6 Pyridoxine', 'B7 Biotin', 'B9 Folate', 'B12 Cobalamin']
tag_w = (w - 20) / 4
tag_h = 22
for i, t in enumerate(tags):
col = i % 4
row = i // 4
x = 10 + col * tag_w
y = 30 + row * 30
c.setFillColor(TEAL if row == 0 else ORANGE)
c.setFillAlpha(0.85)
c.roundRect(x + 2, y, tag_w - 6, tag_h, 4, fill=1, stroke=0)
c.setFillAlpha(1)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 9)
c.drawCentredString(x + tag_w / 2, y + 7, t)
# ────────────────────────────────────────────────────────────────────────────
# Flowchart: Metabolic roles
# ────────────────────────────────────────────────────────────────────────────
class MetabolicFlowchart(Flowable):
def __init__(self, width=None, height=330):
super().__init__()
self.width = width or (PAGE_W - 2 * MARGIN)
self.height = height
def wrap(self, aW, aH):
self.width = aW
return aW, self.height
def _box(self, c, x, y, w, h, text, bg, fg=WHITE, font_size=9, radius=6):
c.setFillColor(bg)
c.roundRect(x, y, w, h, radius, fill=1, stroke=0)
c.setFillColor(fg)
c.setFont('Helvetica-Bold', font_size)
lines = textwrap.wrap(text, width=int(w / 5.5))
total_h = len(lines) * (font_size + 2)
start_y = y + h / 2 + total_h / 2 - font_size
for i, line in enumerate(lines):
c.drawCentredString(x + w / 2, start_y - i * (font_size + 2), line)
def _arrow(self, c, x1, y1, x2, y2, color=GREY):
c.setStrokeColor(color)
c.setLineWidth(1.5)
c.line(x1, y1, x2, y2)
# arrowhead
import math
angle = math.atan2(y2 - y1, x2 - x1)
arr_len = 8
arr_ang = 0.4
c.setFillColor(color)
c.beginPath()
c.moveTo(x2, y2)
c.lineTo(x2 - arr_len * math.cos(angle - arr_ang),
y2 - arr_len * math.sin(angle - arr_ang))
c.lineTo(x2 - arr_len * math.cos(angle + arr_ang),
y2 - arr_len * math.sin(angle + arr_ang))
c.closePath()
c.fill()
def draw(self):
c = self.canv
w, h = self.width, self.height
# Background
c.setFillColor(LGREY)
c.roundRect(0, 0, w, h, 10, fill=1, stroke=0)
# Title
c.setFillColor(NAVY)
c.setFont('Helvetica-Bold', 11)
c.drawCentredString(w / 2, h - 20, 'METABOLIC ROLES OF B VITAMINS')
# Central node: Glucose
cx, cy_top = w / 2, h - 55
box_w, box_h = 130, 30
self._box(c, cx - box_w/2, cy_top, box_w, box_h,
'DIETARY CARBOHYDRATES', NAVY, font_size=9)
# Step 1: Pyruvate
py_y = cy_top - 55
self._box(c, cx - 65, py_y, 130, 28, 'PYRUVATE', TEAL, font_size=9)
self._arrow(c, cx, cy_top, cx, py_y + 28)
# B1 label on arrow
c.setFillColor(ORANGE)
c.roundRect(cx + 4, py_y + 38, 70, 16, 3, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 7.5)
c.drawString(cx + 8, py_y + 42, 'B1-TPP coenzyme')
# Step 2: Acetyl-CoA
ac_y = py_y - 55
self._box(c, cx - 65, ac_y, 130, 28, 'ACETYL-CoA', GREEN, font_size=9)
self._arrow(c, cx, py_y, cx, ac_y + 28)
c.setFillColor(RED)
c.roundRect(cx + 4, ac_y + 38, 65, 16, 3, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 7.5)
c.drawString(cx + 8, ac_y + 42, 'B5 (CoA synthesis)')
# TCA cycle box
tca_y = ac_y - 60
self._box(c, cx - 65, tca_y, 130, 32, 'TCA CYCLE / ETC', PURPLE, font_size=9)
self._arrow(c, cx, ac_y, cx, tca_y + 32)
# B2, B3 label
c.setFillColor(PURPLE)
c.roundRect(cx + 4, tca_y + 40, 90, 16, 3, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 7.5)
c.drawString(cx + 8, tca_y + 44, 'B2 (FAD/FMN) B3 (NAD)')
# ATP
atp_y = tca_y - 50
self._box(c, cx - 50, atp_y, 100, 28, 'ATP (ENERGY)', ORANGE, font_size=9)
self._arrow(c, cx, tca_y, cx, atp_y + 28)
# Side branches
# LEFT: Amino acid metabolism
lx = 60
self._box(c, lx - 55, py_y - 10, 110, 26,
'Amino Acid Metab.', HexColor('#37474F'), font_size=8)
self._arrow(c, cx - 65, py_y + 5, lx + 55, py_y + 5)
c.setFillColor(HexColor('#FF6F00'))
c.roundRect(lx - 35, py_y + 14, 90, 14, 3, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 7)
c.drawString(lx - 30, py_y + 18, 'B6 (transamination)')
# RIGHT: DNA synthesis
rx = w - 60
self._box(c, rx - 55, py_y - 10, 110, 26,
'DNA / Cell Division', HexColor('#1565C0'), font_size=8)
self._arrow(c, cx + 65, py_y + 5, rx - 55, py_y + 5)
c.setFillColor(HexColor('#1565C0'))
c.roundRect(rx - 40, py_y + 14, 80, 14, 3, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 7)
c.drawString(rx - 35, py_y + 18, 'B9/B12 (1C transfer)')
# Fatty acid synthesis (bottom left)
self._box(c, lx - 55, ac_y - 10, 110, 26,
'Fatty Acid Synth.', HexColor('#00695C'), font_size=8)
self._arrow(c, cx - 65, ac_y + 5, lx + 55, ac_y + 5)
c.setFillColor(HexColor('#00695C'))
c.roundRect(lx - 35, ac_y + 14, 80, 14, 3, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 7)
c.drawString(lx - 30, ac_y + 18, 'B7 (carboxylases)')
# Nerve function (bottom right)
self._box(c, rx - 55, ac_y - 10, 110, 26,
'Nerve Function', HexColor('#4527A0'), font_size=8)
self._arrow(c, cx + 65, ac_y + 5, rx - 55, ac_y + 5)
c.setFillColor(HexColor('#4527A0'))
c.roundRect(rx - 35, ac_y + 14, 80, 14, 3, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 7)
c.drawString(rx - 30, ac_y + 18, 'B1/B12 (myelin)')
# ────────────────────────────────────────────────────────────────────────────
# Deficiency flowchart
# ────────────────────────────────────────────────────────────────────────────
class DeficiencyFlowchart(Flowable):
def __init__(self, width=None, height=280):
super().__init__()
self.width = width or (PAGE_W - 2 * MARGIN)
self.height = height
def wrap(self, aW, aH):
self.width = aW
return aW, self.height
def draw(self):
c = self.canv
w, h = self.width, self.height
c.setFillColor(LORANGE)
c.roundRect(0, 0, w, h, 10, fill=1, stroke=0)
c.setFillColor(ORANGE)
c.setFont('Helvetica-Bold', 11)
c.drawCentredString(w/2, h - 20, 'B VITAMIN DEFICIENCY SYNDROMES')
data = [
('B1\nThiamine', 'Beriberi', 'Wet: cardiac failure + oedema\nDry: peripheral neuropathy\nWernicke-Korsakoff (alcoholics)', TEAL),
('B2\nRiboflavin', 'Ariboflavinosis', 'Cheilosis, angular stomatitis\nGlossitis (magenta tongue)\nSeborrhoeic dermatitis', PURPLE),
('B3\nNiacin', 'Pellagra', '3 Ds: Dermatitis, Diarrhoea,\nDementia (+ death if untreated)\nCarcinoid / Hartnup disease', RED),
('B6\nPyridoxine', 'Pyridoxine def.', 'Microcytic anaemia\nEpileptiform convulsions\nPeripheral neuropathy (excess)', GREEN),
('B9\nFolate', 'Folate def.', 'Megaloblastic anaemia\nNeural tube defects (NTD)\nImpaired cell division', NAVY),
('B12\nCobalamin', 'Pernicious anaemia', 'Megaloblastic anaemia\nSubacute combined degeneration\nNeuropsychiatric symptoms', HexColor('#1565C0')),
]
col_w = [70, 90, (w - 200), 0]
row_h = 38
start_y = h - 42
x_start = 10
# Headers
hdrs = ['Vitamin', 'Syndrome', 'Features']
hdr_widths = [70, 90, w - 180]
for i, (hdr, hw) in enumerate(zip(hdrs, hdr_widths)):
c.setFillColor(NAVY)
c.rect(x_start + sum(hdr_widths[:i]), start_y, hw, 20, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 9)
c.drawCentredString(x_start + sum(hdr_widths[:i]) + hw/2, start_y + 6, hdr)
for idx, (vit, syn, feat, col) in enumerate(data):
y = start_y - (idx + 1) * row_h
# Row background alternating
c.setFillColor(WHITE if idx % 2 == 0 else HexColor('#FFF8E1'))
c.rect(x_start, y, w - 20, row_h - 2, fill=1, stroke=0)
# Vitamin cell
c.setFillColor(col)
c.roundRect(x_start + 2, y + 3, 64, row_h - 8, 5, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 8)
lines = vit.split('\n')
for li, line in enumerate(lines):
c.drawCentredString(x_start + 34, y + row_h - 14 - li * 11, line)
# Syndrome cell
c.setFillColor(HexColor('#37474F'))
c.setFont('Helvetica-Bold', 8.5)
c.drawString(x_start + 80, y + row_h // 2 - 4, syn)
# Features cell
c.setFillColor(HexColor('#212121'))
c.setFont('Helvetica', 7.5)
for li, line in enumerate(feat.split('\n')):
c.drawString(x_start + 172, y + row_h - 10 - li * 10, '• ' + line)
# ────────────────────────────────────────────────────────────────────────────
# Clinical Uses diagram
# ────────────────────────────────────────────────────────────────────────────
class ClinicalUsesDiagram(Flowable):
def __init__(self, width=None, height=240):
super().__init__()
self.width = width or (PAGE_W - 2 * MARGIN)
self.height = height
def wrap(self, aW, aH):
self.width = aW
return aW, self.height
def draw(self):
import math
c = self.canv
w, h = self.width, self.height
c.setFillColor(LTEAL)
c.roundRect(0, 0, w, h, 10, fill=1, stroke=0)
c.setFillColor(TEAL)
c.setFont('Helvetica-Bold', 11)
c.drawCentredString(w/2, h - 20, 'CLINICAL USES OF B COMPLEX')
# Central circle
cx, cy = w / 2, h / 2 - 10
cr = 40
c.setFillColor(NAVY)
c.circle(cx, cy, cr, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 9)
c.drawCentredString(cx, cy + 4, 'B COMPLEX')
c.setFont('Helvetica', 7.5)
c.drawCentredString(cx, cy - 8, 'VITAMINS')
# Surrounding uses
uses = [
('Beriberi\n(B1)', 270),
('Pellagra\n(B3)', 225),
('Megaloblastic\nAnaemia (B9/B12)', 180),
('Peripheral\nNeuropathy', 135),
('Alcoholic\nNeuritis (B1)', 90),
('Pregnancy\n(B9/folate)', 45),
('Isoniazid\nneuritis (B6)', 0),
('Hyperlipidaemia\n(B3-Niacin)', 315),
]
radius = 90
box_w, box_h = 80, 32
for text, angle in uses:
rad = math.radians(angle)
bx = cx + radius * math.cos(rad)
by = cy + radius * math.sin(rad)
# line from center to box
c.setStrokeColor(TEAL)
c.setLineWidth(1)
c.line(cx + cr * math.cos(rad), cy + cr * math.sin(rad),
bx - (box_w/2) * math.cos(rad),
by - (box_h/2) * math.sin(rad))
# box
c.setFillColor(TEAL)
c.roundRect(bx - box_w/2, by - box_h/2, box_w, box_h, 5, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 7.5)
lines = text.split('\n')
for li, line in enumerate(lines):
c.drawCentredString(bx, by + 5 - li * 10, line)
# ────────────────────────────────────────────────────────────────────────────
# Coenzyme summary box
# ────────────────────────────────────────────────────────────────────────────
def coenzyme_table(doc_width):
col_w = [70, 90, 100, doc_width - 280]
data = [
[Paragraph('<b>Vitamin</b>', table_header_style),
Paragraph('<b>Coenzyme</b>', table_header_style),
Paragraph('<b>Reaction Type</b>', table_header_style),
Paragraph('<b>Pathway</b>', table_header_style)],
[Paragraph('B1 (Thiamine)', table_cell_style),
Paragraph('TPP (Thiamine PyroPhosphate)', table_cell_style),
Paragraph('Oxidative decarboxylation', table_cell_style),
Paragraph('Pyruvate→Acetyl-CoA; α-KG dehydrogenase; Pentose-P pathway', table_cell_style)],
[Paragraph('B2 (Riboflavin)', table_cell_style),
Paragraph('FAD / FMN', table_cell_style),
Paragraph('Electron carrier (redox)', table_cell_style),
Paragraph('ETC, β-oxidation, citric acid cycle', table_cell_style)],
[Paragraph('B3 (Niacin)', table_cell_style),
Paragraph('NAD⁺ / NADP⁺', table_cell_style),
Paragraph('Hydride transfer (redox)', table_cell_style),
Paragraph('Glycolysis, TCA, fatty acid synth, steroidogenesis', table_cell_style)],
[Paragraph('B5 (Pantothenic acid)', table_cell_style),
Paragraph('Coenzyme A (CoA)', table_cell_style),
Paragraph('Acyl group transfer', table_cell_style),
Paragraph('Acetyl-CoA metabolism, fatty acid synthesis/oxidation', table_cell_style)],
[Paragraph('B6 (Pyridoxine)', table_cell_style),
Paragraph('PLP (Pyridoxal-5-phosphate)', table_cell_style),
Paragraph('Transamination, decarboxylation', table_cell_style),
Paragraph('Amino acid metabolism, neurotransmitter synthesis (GABA, serotonin)', table_cell_style)],
[Paragraph('B7 (Biotin)', table_cell_style),
Paragraph('Biotinyl-enzyme', table_cell_style),
Paragraph('CO₂ fixation (carboxylation)', table_cell_style),
Paragraph('Pyruvate carboxylase, ACC, Propionyl-CoA carboxylase', table_cell_style)],
[Paragraph('B9 (Folate)', table_cell_style),
Paragraph('THF (Tetrahydrofolate)', table_cell_style),
Paragraph('1-carbon transfer', table_cell_style),
Paragraph('Purine synthesis, thymidylate synthesis, methionine cycle', table_cell_style)],
[Paragraph('B12 (Cobalamin)', table_cell_style),
Paragraph('Methylcobalamin / Adenosylcobalamin', table_cell_style),
Paragraph('Methyl transfer, isomerisation', table_cell_style),
Paragraph('Methionine synthesis (with B9), methylmalonyl-CoA→succinyl-CoA', table_cell_style)],
]
ts = TableStyle([
('BACKGROUND', (0,0), (-1,0), NAVY),
('TEXTCOLOR', (0,0), (-1,0), WHITE),
('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, LGREY]),
('GRID', (0,0), (-1,-1), 0.4, HexColor('#B0BEC5')),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
])
t = Table(data, colWidths=col_w, repeatRows=1)
t.setStyle(ts)
return t
# ────────────────────────────────────────────────────────────────────────────
# BUILD DOCUMENT
# ────────────────────────────────────────────────────────────────────────────
output_path = '/tmp/workspace/b-complex-pdf/B_Complex_Pharmacology.pdf'
doc = SimpleDocTemplate(
output_path,
pagesize=A4,
leftMargin=MARGIN, rightMargin=MARGIN,
topMargin=MARGIN, bottomMargin=MARGIN,
title='Short Note on B Complex Vitamins',
author='Pharmacology Notes'
)
story = []
doc_width = PAGE_W - 2 * MARGIN
# ── PAGE 1: Title + Overview ─────────────────────────────────────────────────
story.append(TitleBox(width=doc_width, height=210))
story.append(Spacer(1, 12))
# Introduction
story.append(SectionBanner('1. INTRODUCTION', color=NAVY))
story.append(Spacer(1, 6))
story.append(Paragraph(
'The <b>B-complex vitamins</b> are a group of <b>eight water-soluble vitamins</b> that are '
'essential cofactors in cellular metabolism. Unlike fat-soluble vitamins, they cannot be stored '
'in large amounts and must be regularly consumed in the diet. They primarily function as '
'<b>coenzymes</b> in energy-producing reactions and are collectively critical for the health of '
'the nervous system, red blood cell formation, and DNA synthesis.',
body_style))
story.append(Spacer(1, 6))
# Members box
members_data = [
[Paragraph('<b>Vitamin</b>', table_header_style),
Paragraph('<b>Chemical Name</b>', table_header_style),
Paragraph('<b>Key Source</b>', table_header_style),
Paragraph('<b>RDA (Adult)</b>', table_header_style)],
['B1', 'Thiamine', 'Whole grains, pork, legumes', '1.1–1.2 mg/day'],
['B2', 'Riboflavin', 'Dairy, meat, eggs, green vegetables', '1.1–1.3 mg/day'],
['B3', 'Niacin (Nicotinamide)', 'Meat, fish, peanuts, fortified cereals', '14–16 mg NE/day'],
['B5', 'Pantothenic Acid', 'Meat, avocado, whole grains', '5 mg/day (AI)'],
['B6', 'Pyridoxine', 'Poultry, fish, bananas, potatoes', '1.3–1.7 mg/day'],
['B7', 'Biotin', 'Egg yolk, liver, nuts, legumes', '30 µg/day (AI)'],
['B9', 'Folic Acid / Folate', 'Leafy greens, legumes, citrus fruits', '400 µg DFE/day'],
['B12', 'Cobalamin', 'Animal products only (meat, dairy, eggs)', '2.4 µg/day'],
]
for i in range(1, len(members_data)):
members_data[i] = [Paragraph(str(cell), table_cell_style) for cell in members_data[i]]
members_ts = TableStyle([
('BACKGROUND', (0,0), (-1,0), TEAL),
('TEXTCOLOR', (0,0), (-1,0), WHITE),
('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, LTEAL]),
('GRID', (0,0), (-1,-1), 0.4, HexColor('#B0BEC5')),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
('FONTNAME', (0,1), (0,-1), 'Helvetica-Bold'),
('TEXTCOLOR', (0,1), (0,-1), TEAL),
])
col_widths = [35, 100, 140, doc_width - 295]
members_t = Table(members_data, colWidths=col_widths, repeatRows=1)
members_t.setStyle(members_ts)
story.append(members_t)
story.append(Spacer(1, 10))
# ── PAGE 2: Metabolic Flowchart ──────────────────────────────────────────────
story.append(PageBreak())
story.append(SectionBanner('2. MECHANISMS & METABOLIC ROLES', color=TEAL))
story.append(Spacer(1, 8))
story.append(MetabolicFlowchart(width=doc_width, height=340))
story.append(Spacer(1, 10))
story.append(Paragraph(
'<b>Key Point:</b> B vitamins act as coenzymes - they are the "spark plugs" that activate '
'enzymatic reactions. Without them, cellular respiration, fatty acid oxidation, and nucleotide '
'synthesis come to a halt. Deficiency therefore causes multi-system disease.',
make_style('Note', 'Normal', fontSize=9, textColor=GREEN, fontName='Helvetica-Bold',
leading=13, leftIndent=10, borderPadding=6)))
story.append(Spacer(1, 10))
# Coenzyme table
story.append(SectionBanner('3. COENZYME FORMS & REACTIONS', color=GREEN))
story.append(Spacer(1, 6))
story.append(coenzyme_table(doc_width))
# ── PAGE 3: Deficiencies ─────────────────────────────────────────────────────
story.append(PageBreak())
story.append(SectionBanner('4. DEFICIENCY SYNDROMES', color=RED))
story.append(Spacer(1, 8))
story.append(DeficiencyFlowchart(width=doc_width, height=280))
story.append(Spacer(1, 10))
# Wernicke / B12 notes
story.append(SectionBanner("4a. IMPORTANT DEFICIENCY DETAILS", color=HexColor('#880E4F')))
story.append(Spacer(1, 6))
detail_data = [
[Paragraph('<b>Condition</b>', table_header_style),
Paragraph('<b>Vitamin</b>', table_header_style),
Paragraph('<b>Mechanism</b>', table_header_style),
Paragraph('<b>Treatment</b>', table_header_style)],
[Paragraph('Wernicke Encephalopathy\n→ Korsakoff Psychosis', table_cell_style),
Paragraph('B1 (Thiamine)', table_cell_style),
Paragraph('TPP deficiency → impaired pyruvate dehydrogenase → lactic acidosis + mamillary body necrosis', table_cell_style),
Paragraph('IV thiamine 100 mg BEFORE glucose in alcoholics', table_cell_style)],
[Paragraph('Subacute Combined\nDegeneration of Cord', table_cell_style),
Paragraph('B12 (Cobalamin)', table_cell_style),
Paragraph('Impaired methylmalonyl-CoA conversion → myelin loss in dorsal + lateral columns', table_cell_style),
Paragraph('IM hydroxocobalamin or oral cyanocobalamin (large doses)', table_cell_style)],
[Paragraph('Pellagra (3 Ds)', table_cell_style),
Paragraph('B3 (Niacin)', table_cell_style),
Paragraph('NAD/NADP deficiency; also in carcinoid (tryptophan→5-HT) and isoniazid Rx', table_cell_style),
Paragraph('Nicotinamide 100 mg TDS; treat underlying cause', table_cell_style)],
[Paragraph('Neural Tube Defects', table_cell_style),
Paragraph('B9 (Folate)', table_cell_style),
Paragraph('Impaired thymidylate synthesis → defective neural tube closure in embryogenesis', table_cell_style),
Paragraph('Folic acid 5 mg/day pre-conception and first trimester', table_cell_style)],
[Paragraph('Isoniazid-induced\nNeuropathy', table_cell_style),
Paragraph('B6 (Pyridoxine)', table_cell_style),
Paragraph('INH antagonises PLP (competes for apoenzyme binding) → peripheral neuropathy', table_cell_style),
Paragraph('Pyridoxine 10–50 mg/day with INH as prophylaxis', table_cell_style)],
]
detail_ts = TableStyle([
('BACKGROUND', (0,0), (-1,0), HexColor('#880E4F')),
('TEXTCOLOR', (0,0), (-1,0), WHITE),
('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, LPURPLE]),
('GRID', (0,0), (-1,-1), 0.4, HexColor('#B0BEC5')),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
])
col_w2 = [110, 75, 170, doc_width - 375]
detail_t = Table(detail_data, colWidths=col_w2, repeatRows=1)
detail_t.setStyle(detail_ts)
story.append(detail_t)
# ── PAGE 4: Clinical Uses + Pharmacology ────────────────────────────────────
story.append(PageBreak())
story.append(SectionBanner('5. CLINICAL USES / THERAPEUTIC APPLICATIONS', color=TEAL))
story.append(Spacer(1, 8))
story.append(ClinicalUsesDiagram(width=doc_width, height=240))
story.append(Spacer(1, 10))
# Pharmacology details table
story.append(SectionBanner('6. PHARMACOLOGY OF INDIVIDUAL B VITAMINS', color=PURPLE))
story.append(Spacer(1, 6))
pharma_data = [
[Paragraph('<b>Vitamin</b>', table_header_style),
Paragraph('<b>Absorption</b>', table_header_style),
Paragraph('<b>Special Properties</b>', table_header_style),
Paragraph('<b>Toxicity / Notes</b>', table_header_style)],
[Paragraph('B1', table_cell_style),
Paragraph('Active transport at low doses; passive at high doses', table_cell_style),
Paragraph('Triphosphate form activates chloride channels in nerves', table_cell_style),
Paragraph('Non-toxic; excess excreted in urine', table_cell_style)],
[Paragraph('B2', table_cell_style),
Paragraph('Carrier-mediated; bile salts enhance', table_cell_style),
Paragraph('Generates superoxide radicals (oxidant stress)', table_cell_style),
Paragraph('Urine turns yellow - harmless', table_cell_style)],
[Paragraph('B3 (Niacin)', table_cell_style),
Paragraph('Rapid GI absorption; first-pass hepatic', table_cell_style),
Paragraph('<b>Pharmacological dose (1–3 g)</b>: ↓ LDL, ↓ TG, ↑ HDL; inhibits lipolysis', table_cell_style),
Paragraph('<b>Flushing</b> (prostaglandin-mediated; blocked by aspirin); hepatotoxicity at high dose', table_cell_style)],
[Paragraph('B6', table_cell_style),
Paragraph('Absorbed throughout small intestine', table_cell_style),
Paragraph('PLP required for >100 enzyme reactions; neurotransmitter synthesis', table_cell_style),
Paragraph('<b>Sensory neuropathy</b> with chronic excess (>200 mg/day)', table_cell_style)],
[Paragraph('B9 (Folic acid)', table_cell_style),
Paragraph('Jejunum; PCFT (proton-coupled folate transporter)', table_cell_style),
Paragraph('Given in pregnancy; masks B12 deficiency if given alone', table_cell_style),
Paragraph('Folinic acid (leucovorin) = active form; bypasses DHFR', table_cell_style)],
[Paragraph('B12', table_cell_style),
Paragraph('Requires intrinsic factor (IF) from gastric parietal cells', table_cell_style),
Paragraph('Stored in liver (3–5 yr supply); deficiency takes years to manifest', table_cell_style),
Paragraph('Pernicious anaemia = anti-IF antibodies; give parenterally', table_cell_style)],
]
pharma_ts = TableStyle([
('BACKGROUND', (0,0), (-1,0), PURPLE),
('TEXTCOLOR', (0,0), (-1,0), WHITE),
('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, LPURPLE]),
('GRID', (0,0), (-1,-1), 0.4, HexColor('#B0BEC5')),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING', (0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
])
pharma_t = Table(pharma_data, colWidths=[40, 100, 185, doc_width - 345], repeatRows=1)
pharma_t.setStyle(pharma_ts)
story.append(pharma_t)
story.append(Spacer(1, 12))
# Niacin special section
story.append(SectionBanner('6a. NIACIN AS A HYPOLIPIDAEMIC DRUG', color=ORANGE))
story.append(Spacer(1, 6))
story.append(Paragraph(
'At <b>pharmacological doses (1–3 g/day)</b>, niacin (nicotinic acid) has the following effects:',
body_style))
niacin_bullets = [
'↓ VLDL synthesis → ↓ LDL-cholesterol and ↓ triglycerides',
'↑ HDL-cholesterol (most effective agent for raising HDL)',
'Mechanism: inhibits adipocyte lipolysis via GPR109A receptor → ↓ FFA delivery to liver → ↓ VLDL assembly',
'Side effect: <b>cutaneous flushing</b> (prostaglandin-mediated) - prevented by aspirin or extended-release formulations',
'Hepatotoxicity with sustained-release forms; monitor LFTs',
'May worsen insulin resistance and gout',
]
for b in niacin_bullets:
story.append(Paragraph('• ' + b, bullet_style))
story.append(Spacer(1, 10))
# ── PAGE 5: B9/B12 Folate Cycle ─────────────────────────────────────────────
story.append(PageBreak())
story.append(SectionBanner('7. FOLATE-B12 METHIONINE CYCLE (Key for MCQs)', color=NAVY))
story.append(Spacer(1, 8))
# Draw folate cycle as a table-based diagram
folate_text = [
'The folate-B12 methionine cycle is essential for <b>1-carbon metabolism</b>.',
'',
'<b>Step 1:</b> Dietary folate → dihydrofolate (DHF) → tetrahydrofolate (THF) [enzyme: DHFR, inhibited by methotrexate]',
'<b>Step 2:</b> THF → 5,10-methylene-THF [used for thymidylate synthesis - DNA]',
'<b>Step 3:</b> 5,10-methylene-THF → 5-methyl-THF [irreversible "methyl trap"]',
'<b>Step 4:</b> 5-methyl-THF + homocysteine → methionine + THF [enzyme: methionine synthase; coenzyme: <b>B12</b>]',
'',
'<b>Methyl Trap Hypothesis:</b> In B12 deficiency, 5-methyl-THF accumulates (trapped) → functional folate deficiency → megaloblastic anaemia even with adequate dietary folate.',
'',
'<b>Clinical relevance:</b>',
'• Giving folate alone in B12 deficiency corrects anaemia but NOT the neurological damage → always exclude B12 deficiency before starting folate',
'• Homocysteine rises in both B9 and B12 deficiency → cardiovascular risk marker',
'• Methotrexate blocks DHFR → rescued by folinic acid (leucovorin)',
]
for line in folate_text:
if line == '':
story.append(Spacer(1, 5))
else:
story.append(Paragraph(line, body_style))
story.append(Spacer(1, 12))
# ── Summary / Exam Points ────────────────────────────────────────────────────
story.append(SectionBanner('8. HIGH-YIELD EXAM POINTS', color=HexColor('#E65100')))
story.append(Spacer(1, 6))
exam_points = [
('<b>3 Ds of Pellagra</b> (B3 deficiency):', 'Dermatitis, Diarrhoea, Dementia (+ Death if untreated)'),
('<b>Wernicke-Korsakoff</b>:', 'Give IV thiamine BEFORE glucose in any confused alcoholic - glucose alone can precipitate acute Wernicke\'s'),
('<b>Pernicious Anaemia</b>:', 'Due to anti-IF antibodies; treat with IM B12 (hydroxocobalamin); oral high-dose also works'),
('<b>Neural Tube Defects</b>:', 'Folic acid 5 mg pre-conception + first trimester; mandatory supplementation in epileptics on valproate/carbamazepine'),
('<b>Isoniazid neuropathy</b>:', 'Always co-prescribe pyridoxine B6 with INH, especially in malnourished/diabetic/pregnant patients'),
('<b>Niacin flushing</b>:', 'Mediated by prostaglandins → give aspirin 325 mg 30 min before niacin dose'),
('<b>B7 (Biotin) deficiency</b>:', 'Caused by eating raw egg whites (avidin binds biotin); also complication of long-term TPN without supplementation'),
('<b>B6 toxicity</b>:', 'Sensory peripheral neuropathy (paradox - excess pyridoxine causes the very neuropathy its deficiency also causes)'),
]
for bold_part, detail in exam_points:
story.append(Paragraph(f'{bold_part} {detail}', bullet_style))
story.append(Spacer(1, 3))
story.append(Spacer(1, 10))
story.append(HRFlowable(width=doc_width, thickness=1, color=NAVY, dash=(3,3)))
story.append(Spacer(1, 6))
story.append(Paragraph(
'References: Harper\'s Illustrated Biochemistry 32e | Basic Medical Biochemistry 6e | '
'Henry\'s Clinical Diagnosis & Management by Laboratory Methods',
caption_style))
# ── BUILD ────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF created: {output_path}")
cd /tmp/workspace/b-complex-pdf && python generate_pdf.py 2>&1
~/b-complex-pdf/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/b-complex-pdf/generate_pdf.py'
~/b-complex-pdf/generate_pdf.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/b-complex-pdf/generate_pdf.py'
cd /tmp/workspace/b-complex-pdf && python generate_pdf.py 2>&1
ls -lh /tmp/workspace/b-complex-pdf/B_Complex_Pharmacology.pdf
B Complex Pharmacology
PDF Document · PDF
Define drug interactions discuss various combined effects of drugs such as additive effect , synergism, potentiation, and antagonism with examples
Formula: Effect (A + B) = Effect (A) + Effect (B)
| Drug A | Drug B | Combined Additive Effect |
|---|---|---|
| Aspirin (analgesic) | Paracetamol (analgesic) | Combined analgesia = sum of both |
| Two NSAIDs | (e.g., aspirin + ibuprofen) | Additive GI ulceration and bleeding risk |
| Alcohol (CNS depressant) | Diazepam (CNS depressant) | Additive CNS depression |
| Thiazide diuretic | Loop diuretic | Additive diuresis and electrolyte loss |
Formula: Effect (A + B) > Effect (A) + Effect (B)

| Type | Mechanism | Example |
|---|---|---|
| Bactericidal synergism | Two agents alone are only bacteriostatic, but together they are bactericidal | Penicillin + Aminoglycoside in Enterococcal endocarditis |
| Sequential block synergism | Two drugs block sequential steps in the same pathway | Trimethoprim + Sulfamethoxazole (block sequential steps in folate synthesis) |
| Receptor-effector synergism | Drugs act at different receptors whose downstream effects summate supra-additively | Morphine + Ketamine (pain pathways) |
Formula: Effect (A alone) = 0; Effect (A + B) >> Effect (B) Expressed as: 0 + 1 = 3 (i.e., inactive drug amplifies the active one)
| Inactive Drug (Potentiator) | Active Drug | Effect |
|---|---|---|
| Probenecid (no antimicrobial activity) | Penicillin | Blocks renal tubular secretion of penicillin → prolongs and raises penicillin plasma levels |
| Clavulanate (no antibacterial activity alone) | Amoxicillin | Inhibits β-lactamase → potentiates amoxicillin's antibacterial effect |
| Dantrolene (no NMJ blocking activity) | Neuromuscular blockers | Prevents Ca²⁺ release from sarcoplasmic reticulum → potentiates NMB-induced weakness (Miller's Anesthesia) |
| CYP inhibitor (e.g., ketoconazole) | Statins / Protease inhibitors | Reduces CYP3A4-mediated metabolism → raises plasma levels of active drug (Goodman & Gilman's) |
| Sulfonamide | Warfarin | Inhibits CYP2C9 + displaces warfarin from albumin → potentiates anticoagulant effect (Lippincott Pharmacology) |
Formula: Effect (A + B) < Effect (A) or Effect (B) Expressed as: 1 + 1 < 2 or even 1 + 1 = 0
| Sub-type | Mechanism | Reversibility | Example |
|---|---|---|---|
| Competitive (surmountable) | Antagonist reversibly competes for same binding site; can be overcome by increasing agonist dose | Reversible | Atropine antagonises acetylcholine at muscarinic receptors; Naloxone antagonises morphine at opioid receptors |
| Non-competitive (insurmountable) | Antagonist binds irreversibly to receptor or an allosteric site; cannot be overcome by increasing agonist | Irreversible | Phenoxybenzamine (irreversible α-blocker) antagonises noradrenaline |
| Type | Mathematical Expression | Mechanism | Classic Example |
|---|---|---|---|
| Additive | 1 + 1 = 2 | Same receptor/system; effects sum normally | Aspirin + Paracetamol |
| Synergism | 1 + 1 > 2 | Different mechanisms converge; supra-additive | TMP + SMX; Penicillin + Aminoglycoside |
| Potentiation | 0 + 1 = 3 | Inactive drug amplifies active drug | Probenecid + Penicillin; Clavulanate + Amoxicillin |
| Competitive Antagonism | 1 + 1 → 0 (reversible) | Same receptor, reversible block | Naloxone + Morphine |
| Non-competitive Antagonism | 1 + 1 → 0 (irreversible) | Same receptor, irreversible block | Phenoxybenzamine + NA |
| Physiological Antagonism | 1 + 1 → 0 (different receptors) | Opposing effects, different receptors | Adrenaline + Histamine |
| Chemical Antagonism | 1 + 1 → 0 (direct inactivation) | Direct chemical inactivation | Protamine + Heparin |
Create a detailed study guide PDF on drug interactions with mechanism diagrams
mkdir -p /tmp/workspace/drug-interactions-pdf && ls /tmp/workspace/drug-interactions-pdf/
~/drug-interactions-pdf/build_pdf.py
"""
Drug Interactions - Detailed Study Guide PDF
Pharmacology Exam Preparation
"""
import math, textwrap
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.lib import colors
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether, ListFlowable, ListItem
)
from reportlab.platypus.flowables import Flowable
from reportlab.lib.colors import HexColor
# ── Palette ──────────────────────────────────────────────────────────────────
NAVY = HexColor('#0D2137')
TEAL = HexColor('#006D77')
ORANGE = HexColor('#E07B39')
GREEN = HexColor('#2D6A4F')
RED = HexColor('#AE2012')
PURPLE = HexColor('#5C4B8A')
CRIMSON = HexColor('#C62828')
GOLD = HexColor('#B8860B')
BLUE = HexColor('#1565C0')
DKGREY = HexColor('#37474F')
MDGREY = HexColor('#607D8B')
WHITE = colors.white
BLACK = colors.black
LNAVY = HexColor('#E8EDF3')
LTEAL = HexColor('#E0F5F5')
LORANGE = HexColor('#FFF3E0')
LGREEN = HexColor('#E8F5E9')
LRED = HexColor('#FFEBEE')
LPURPLE = HexColor('#EDE7F6')
LGOLD = HexColor('#FFFDE7')
LBLUE = HexColor('#E3F2FD')
LGREY = HexColor('#F5F5F5')
PAGE_W, PAGE_H = A4
MARGIN = 1.7 * cm
CONTENT_W = PAGE_W - 2 * MARGIN
# ── Styles ───────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
def S(name, parent='Normal', **kw):
return ParagraphStyle(name, parent=styles[parent], **kw)
body = S('body', fontSize=10, leading=15, textColor=DKGREY, spaceBefore=3, spaceAfter=3)
bodyB = S('bodyB', fontSize=10, leading=15, textColor=NAVY, fontName='Helvetica-Bold')
small = S('small', fontSize=8.5, leading=13, textColor=DKGREY)
bullet = S('bullet', fontSize=9.5, leading=14, textColor=DKGREY, leftIndent=16, bulletIndent=6, spaceBefore=2)
caption = S('caption',fontSize=8, leading=12, textColor=MDGREY, fontName='Helvetica-Oblique', alignment=1)
th = S('th', fontSize=9, leading=12, textColor=WHITE, fontName='Helvetica-Bold', alignment=1)
td = S('td', fontSize=8.5, leading=12, textColor=DKGREY)
tdB = S('tdB',fontSize=8.5, leading=12, textColor=NAVY, fontName='Helvetica-Bold')
note = S('note', fontSize=9, leading=13, textColor=GREEN, fontName='Helvetica-Bold',
leftIndent=10, borderPadding=5, backColor=LGREEN)
# ── Helpers ──────────────────────────────────────────────────────────────────
def banner(text, color=NAVY, height=30):
class _Banner(Flowable):
def __init__(self):
super().__init__()
def wrap(self, aW, aH):
self._w = aW
return aW, height + 6
def draw(self):
c = self.canv
c.setFillColor(color)
c.roundRect(0, 0, self._w, height, 7, fill=1, stroke=0)
# left accent strip
c.setFillColor(WHITE)
c.setFillAlpha(0.25)
c.roundRect(0, 0, 8, height, 4, fill=1, stroke=0)
c.setFillAlpha(1)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 12)
c.drawCentredString(self._w / 2, height / 2 - 5, text)
return _Banner()
def sub_banner(text, color=TEAL, height=24):
class _SBanner(Flowable):
def __init__(self):
super().__init__()
def wrap(self, aW, aH):
self._w = aW
return aW, height + 4
def draw(self):
c = self.canv
c.setFillColor(color)
c.setFillAlpha(0.15)
c.roundRect(0, 0, self._w, height, 5, fill=1, stroke=0)
c.setFillAlpha(1)
c.setStrokeColor(color)
c.setLineWidth(2.5)
c.line(0, 0, 0, height)
c.setFillColor(color)
c.setFont('Helvetica-Bold', 11)
c.drawString(14, height / 2 - 5, text)
return _SBanner()
def spacer(h=8):
return Spacer(1, h)
def hr(color=NAVY, dash=None):
return HRFlowable(width=CONTENT_W, thickness=0.7, color=color, dash=dash or (4, 4))
def tbl(data, col_widths, hdr_color=NAVY, alt=None, row_heights=None):
alt_colors = alt or [WHITE, LGREY]
rows = len(data)
ts = TableStyle([
('BACKGROUND', (0,0), (-1,0), hdr_color),
('TEXTCOLOR', (0,0), (-1,0), WHITE),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 9),
('ALIGN', (0,0), (-1,0), 'CENTER'),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('GRID', (0,0), (-1,-1), 0.35, HexColor('#CFD8DC')),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING',(0,0),(-1,-1), 5),
('LEFTPADDING',(0,0), (-1,-1), 6),
('ROWBACKGROUNDS', (0,1), (-1,-1), alt_colors),
])
t = Table(data, colWidths=col_widths, repeatRows=1, rowHeights=row_heights)
t.setStyle(ts)
return t
# ════════════════════════════════════════════════════════════════════════════
# CUSTOM FLOWABLE DIAGRAMS
# ════════════════════════════════════════════════════════════════════════════
# ── 1. Title Page ─────────────────────────────────────────────────────────────
class TitlePage(Flowable):
def __init__(self):
super().__init__()
def wrap(self, aW, aH):
self._w = aW
return aW, 260
def draw(self):
c = self.canv
w, h = self._w, 260
# Background gradient simulation
c.setFillColor(NAVY)
c.roundRect(0, 0, w, h, 14, fill=1, stroke=0)
c.setFillColor(TEAL)
c.setFillAlpha(0.3)
c.roundRect(w*0.6, 0, w*0.4, h, 14, fill=1, stroke=0)
c.setFillAlpha(1)
# Decorative circles
for r, a in [(90,0.04),(60,0.06),(35,0.08)]:
c.setFillColor(WHITE)
c.setFillAlpha(a)
c.circle(w*0.88, h*0.62, r, fill=1, stroke=0)
c.setFillAlpha(1)
# Rx symbol area
c.setFillColor(ORANGE)
c.setFillAlpha(0.9)
c.roundRect(w*0.04, h-70, 52, 52, 8, fill=1, stroke=0)
c.setFillAlpha(1)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 26)
c.drawCentredString(w*0.04+26, h-50, 'Rx')
# Title
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 24)
c.drawString(w*0.04+65, h-48, 'DRUG INTERACTIONS')
c.setFont('Helvetica', 13)
c.setFillColor(HexColor('#80CBC4'))
c.drawString(w*0.04+65, h-68, 'Detailed Study Guide | Pharmacology')
# Divider
c.setStrokeColor(ORANGE)
c.setLineWidth(1.8)
c.line(w*0.04, h-82, w*0.96, h-82)
# Subtitle blocks
topics = ['Definition & Classification','Additive Effect','Synergism',
'Potentiation','Antagonism Types','Pharmacokinetic Interactions',
'CYP450 Interactions','Clinical High-Yield Points']
cols = 4
bw = (w - 20) / cols
bh = 26
for i, t in enumerate(topics):
col = i % cols
row = i // cols
x = 10 + col * bw
y = h - 82 - 16 - row * 32
bg = TEAL if row == 0 else ORANGE
c.setFillColor(bg)
c.setFillAlpha(0.85)
c.roundRect(x+2, y, bw-6, bh, 5, fill=1, stroke=0)
c.setFillAlpha(1)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 7.5)
c.drawCentredString(x + bw/2, y + 8, t)
# Footer
c.setFillColor(HexColor('#B2DFDB'))
c.setFont('Helvetica', 8.5)
c.drawCentredString(w/2, 12,
'Goodman & Gilman\'s | Goldman-Cecil Medicine | Lippincott Pharmacology | Katzung Basic & Clinical Pharmacology')
# ── 2. Definition Mind-Map ────────────────────────────────────────────────────
class DefinitionMindMap(Flowable):
def __init__(self):
super().__init__()
def wrap(self, aW, aH):
self._w = aW
return aW, 220
def _rbox(self, c, x, y, w, h, text, bg, fg=WHITE, fs=9, r=6, bold=True):
c.setFillColor(bg)
c.roundRect(x, y, w, h, r, fill=1, stroke=0)
c.setFillColor(fg)
fn = 'Helvetica-Bold' if bold else 'Helvetica'
c.setFont(fn, fs)
lines = textwrap.wrap(text, width=max(int(w/5.2), 8))
total = len(lines) * (fs + 2)
sy = y + h/2 + total/2 - fs
for i, ln in enumerate(lines):
c.drawCentredString(x + w/2, sy - i*(fs+2), ln)
def _line(self, c, x1, y1, x2, y2, color=MDGREY, lw=1.2):
c.setStrokeColor(color)
c.setLineWidth(lw)
c.line(x1, y1, x2, y2)
def draw(self):
c = self.canv
w, h = self._w, 220
c.setFillColor(LGREY)
c.roundRect(0, 0, w, h, 10, fill=1, stroke=0)
# Central box
cx, cy, bw, bh = w/2, h/2, 140, 44
self._rbox(c, cx-bw/2, cy-bh/2, bw, bh,
'DRUG INTERACTION', NAVY, fs=12)
# Branches
branches = [
# (angle_deg, text, short_desc, color)
(80, 'Pharmacodynamic', 'Additive / Synergism\nPotentiation / Antagonism', TEAL),
(140, 'Pharmacokinetic', 'ADME-based\nCYP450 / Protein binding', BLUE),
(220, 'Pharmaceutical', 'Physical/Chemical\nIncompatibility in syringe', PURPLE),
(310, 'Beneficial', 'Co-trimoxazole\nAMOX-Clavulanate', GREEN),
]
r_inner = 80
for ang, label, desc, col in branches:
rad = math.radians(ang)
tx = cx + r_inner * math.cos(rad)
ty = cy + r_inner * math.sin(rad) - 5
# line from centre
self._line(c, cx + 70*math.cos(rad), cy + 70*math.sin(rad),
tx - 55*math.cos(rad), ty + 5 + 55*math.sin(rad),
color=col, lw=1.5)
# box
bx, by = tx - 75, ty - 28
self._rbox(c, bx, by, 80, 26, label, col, fs=8.5)
# sub-text
c.setFillColor(DKGREY)
c.setFont('Helvetica', 7)
for di, dl in enumerate(desc.split('\n')):
c.drawCentredString(tx - 35, by - 12 - di*10, dl)
# ── 3. Additive Effect Diagram ────────────────────────────────────────────────
class AdditiveBarChart(Flowable):
def __init__(self):
super().__init__()
def wrap(self, aW, aH):
self._w = aW
return aW, 190
def draw(self):
c = self.canv
w, h = self._w, 190
c.setFillColor(LGREEN)
c.roundRect(0, 0, w, h, 10, fill=1, stroke=0)
# Title
c.setFillColor(GREEN)
c.setFont('Helvetica-Bold', 11)
c.drawCentredString(w/2, h-18, 'ADDITIVE EFFECT — 1 + 1 = 2')
# Axes
ox, oy = 60, 35
chart_w = w - 130
chart_h = 120
c.setStrokeColor(DKGREY)
c.setLineWidth(1.2)
c.line(ox, oy, ox, oy+chart_h)
c.line(ox, oy, ox+chart_w, oy)
# Y label
c.setFillColor(DKGREY)
c.setFont('Helvetica', 8)
c.saveState()
c.translate(ox-22, oy+chart_h/2)
c.rotate(90)
c.drawCentredString(0, 0, 'Effect (%)')
c.restoreState()
# X ticks
bars = [
('Drug A\nalone', 40, TEAL),
('Drug B\nalone', 60, BLUE),
('A + B\n(Additive)', 100, GREEN),
]
bar_w = (chart_w - 40) / len(bars)
for i, (lbl, val, col) in enumerate(bars):
x = ox + 20 + i * bar_w
bh_px = val * chart_h / 110
# bar
c.setFillColor(col)
c.roundRect(x, oy, bar_w-10, bh_px, 4, fill=1, stroke=0)
# value label
c.setFillColor(col)
c.setFont('Helvetica-Bold', 10)
c.drawCentredString(x + (bar_w-10)/2, oy + bh_px + 5, f'{val}%')
# x label
c.setFillColor(DKGREY)
c.setFont('Helvetica', 8)
for li, ll in enumerate(lbl.split('\n')):
c.drawCentredString(x + (bar_w-10)/2, oy - 14 - li*10, ll)
# dashed line at 100%
c.setStrokeColor(GREEN)
c.setDash([3,3])
c.setLineWidth(1)
c.line(ox, oy + 100*chart_h/110, ox+chart_w, oy + 100*chart_h/110)
c.setDash([])
# annotation
c.setFillColor(GREEN)
c.setFont('Helvetica-Bold', 7.5)
c.drawString(ox+chart_w+4, oy + 100*chart_h/110 - 3, '= A + B')
# formula box
c.setFillColor(GREEN)
c.roundRect(w-80, h-40, 72, 20, 4, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 9)
c.drawCentredString(w-44, h-27, 'E(A+B) = E(A)+E(B)')
# ── 4. Synergism Isobologram ───────────────────────────────────────────────────
class IsobologramDiagram(Flowable):
def __init__(self):
super().__init__()
def wrap(self, aW, aH):
self._w = aW
return aW, 240
def draw(self):
c = self.canv
w, h = self._w, 240
c.setFillColor(LTEAL)
c.roundRect(0, 0, w, h, 10, fill=1, stroke=0)
c.setFillColor(TEAL)
c.setFont('Helvetica-Bold', 11)
c.drawCentredString(w/2, h-18, 'ISOBOLOGRAM — SYNERGISM vs ADDITIVITY vs SUBADDITIVITY')
# Axes
ox, oy = 65, 35
ax_w, ax_h = w - 140, 168
c.setStrokeColor(DKGREY)
c.setLineWidth(1.4)
c.line(ox, oy, ox, oy+ax_h)
c.line(ox, oy, ox+ax_w, oy)
# Axis labels
c.setFillColor(DKGREY)
c.setFont('Helvetica-Bold', 9)
c.drawCentredString(ox + ax_w/2, oy - 20, '[Drug A] →')
c.saveState()
c.translate(ox - 30, oy + ax_h/2)
c.rotate(90)
c.drawCentredString(0, 0, '[Drug B] →')
c.restoreState()
# EC50 ticks
c.setFillColor(MDGREY)
c.setFont('Helvetica', 8)
c.drawString(ox + ax_w - 6, oy - 14, 'EC₅₀ A')
c.drawString(ox - 30, oy + ax_h - 6, 'EC₅₀ B')
# Additive line (straight diagonal)
c.setStrokeColor(DKGREY)
c.setLineWidth(2)
c.line(ox + ax_w, oy, ox, oy + ax_h)
c.setFillColor(DKGREY)
c.setFont('Helvetica-Bold', 8.5)
mid_x = ox + ax_w*0.55
mid_y = oy + ax_h*0.44
c.saveState()
c.translate(mid_x, mid_y)
c.rotate(math.degrees(math.atan2(ax_h, -ax_w)))
c.drawCentredString(0, 5, 'Additive (line of additivity)')
c.restoreState()
# Synergism curve (bows inward = below additive line)
c.setStrokeColor(GREEN)
c.setLineWidth(2.2)
p = c.beginPath()
p.moveTo(ox + ax_w, oy)
p.curveTo(ox + ax_w*0.65, oy + ax_h*0.15,
ox + ax_w*0.18, oy + ax_h*0.65,
ox, oy + ax_h)
c.drawPath(p, fill=0, stroke=1)
# Fill synergism region
c.setFillColor(GREEN)
c.setFillAlpha(0.12)
p2 = c.beginPath()
p2.moveTo(ox + ax_w, oy)
p2.curveTo(ox + ax_w*0.65, oy + ax_h*0.15,
ox + ax_w*0.18, oy + ax_h*0.65,
ox, oy + ax_h)
p2.lineTo(ox, oy + ax_h)
p2.lineTo(ox + ax_w, oy)
p2.close()
c.drawPath(p2, fill=1, stroke=0)
c.setFillAlpha(1)
# Subadditivity curve (bows outward = above additive line)
c.setStrokeColor(RED)
c.setLineWidth(2.2)
p3 = c.beginPath()
p3.moveTo(ox + ax_w, oy)
p3.curveTo(ox + ax_w*0.9, oy + ax_h*0.35,
ox + ax_w*0.38, oy + ax_h*0.9,
ox, oy + ax_h)
c.drawPath(p3, fill=0, stroke=1)
c.setFillColor(RED)
c.setFillAlpha(0.10)
p4 = c.beginPath()
p4.moveTo(ox + ax_w, oy)
p4.curveTo(ox + ax_w*0.9, oy + ax_h*0.35,
ox + ax_w*0.38, oy + ax_h*0.9,
ox, oy + ax_h)
p4.lineTo(ox, oy + ax_h)
p4.lineTo(ox + ax_w, oy)
p4.close()
c.drawPath(p4, fill=1, stroke=0)
c.setFillAlpha(1)
# Labels
c.setFillColor(GREEN)
c.setFont('Helvetica-Bold', 9)
c.drawString(ox + 15, oy + 30, '✓ Positive Synergism')
c.setFont('Helvetica', 8)
c.drawString(ox + 15, oy + 19, '(Superadditive)')
c.setFillColor(RED)
c.setFont('Helvetica-Bold', 9)
c.drawString(ox + ax_w - 95, oy + ax_h - 20, '✗ Negative Synergism')
c.setFont('Helvetica', 8)
c.drawString(ox + ax_w - 80, oy + ax_h - 31, '(Subadditive)')
# Legend formula boxes
fboxes = [
(ox, oy + ax_h + 12, 'Synergism: 1+1 > 2', GREEN),
(ox + ax_w/2 - 40, oy + ax_h + 12, 'Additive: 1+1 = 2', DKGREY),
]
for fx, fy, ft, fc in fboxes:
c.setFillColor(fc)
c.roundRect(fx, fy, 130, 16, 3, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 8)
c.drawCentredString(fx+65, fy+5, ft)
# ── 5. Potentiation Mechanism Diagram ────────────────────────────────────────
class PotentiationDiagram(Flowable):
def __init__(self):
super().__init__()
def wrap(self, aW, aH):
self._w = aW
return aW, 220
def _box(self, c, x, y, w, h, text, bg, fg=WHITE, fs=9, r=6):
c.setFillColor(bg)
c.roundRect(x, y, w, h, r, fill=1, stroke=0)
c.setFillColor(fg)
c.setFont('Helvetica-Bold', fs)
lines = textwrap.wrap(text, width=max(int(w/5.3),6))
total = len(lines)*(fs+2)
sy = y+h/2+total/2-fs
for i,ln in enumerate(lines):
c.drawCentredString(x+w/2, sy-i*(fs+2), ln)
def _arrow(self, c, x1, y1, x2, y2, color=MDGREY, label='', lw=1.5):
angle = math.atan2(y2-y1, x2-x1)
c.setStrokeColor(color)
c.setLineWidth(lw)
c.line(x1, y1, x2, y2)
arr=8; ang=0.4
c.setFillColor(color)
p = c.beginPath()
p.moveTo(x2, y2)
p.lineTo(x2-arr*math.cos(angle-ang), y2-arr*math.sin(angle-ang))
p.lineTo(x2-arr*math.cos(angle+ang), y2-arr*math.sin(angle+ang))
p.close()
c.drawPath(p, fill=1, stroke=0)
if label:
mx,my = (x1+x2)/2, (y1+y2)/2
c.setFillColor(color)
c.setFont('Helvetica-Bold', 7.5)
c.drawCentredString(mx, my+5, label)
def draw(self):
c = self.canv
w, h = self._w, 220
c.setFillColor(LORANGE)
c.roundRect(0, 0, w, h, 10, fill=1, stroke=0)
c.setFillColor(ORANGE)
c.setFont('Helvetica-Bold', 11)
c.drawCentredString(w/2, h-18, 'POTENTIATION MECHANISM — 0 + 1 = 3')
# Example: Probenecid + Penicillin
# Row 1: Without Probenecid
y1 = h - 55
self._box(c, 10, y1, 100, 30, 'Penicillin (alone)', BLUE, fs=9)
self._arrow(c, 110, y1+15, 190, y1+15, BLUE, 'plasma')
self._box(c, 190, y1, 90, 30, 'Kidney\nTubular Secretion', CRIMSON, fs=8)
self._arrow(c, 280, y1+15, 340, y1+15, CRIMSON, 'excreted')
self._box(c, 340, y1, 80, 30, 'Short t½\nLow levels', CRIMSON, fs=8)
# Label
c.setFillColor(BLUE)
c.setFont('Helvetica-Bold', 8.5)
c.drawString(10, y1+34, 'WITHOUT PROBENECID:')
# Row 2: With Probenecid
y2 = h - 120
self._box(c, 10, y2, 100, 30, 'Penicillin\n+ Probenecid', ORANGE, fs=9)
self._arrow(c, 110, y2+15, 190, y2+15, ORANGE, 'plasma')
self._box(c, 190, y2, 90, 30, 'Kidney\nTubular Secretion', HexColor('#5D4037'), fs=8)
# BLOCKED arrow
c.setStrokeColor(RED)
c.setLineWidth(2.5)
c.line(280, y2+5, 310, y2+25)
c.line(280, y2+25, 310, y2+5)
c.setFillColor(RED)
c.setFont('Helvetica-Bold', 9)
c.drawCentredString(295, y2-8, 'BLOCKED')
self._box(c, 340, y2, 80, 30, 'Prolonged t½\n↑ Plasma levels', GREEN, fs=8)
c.setFillColor(ORANGE)
c.setFont('Helvetica-Bold', 8.5)
c.drawString(10, y2+34, 'WITH PROBENECID (Potentiator):')
# Result box
c.setFillColor(GREEN)
c.roundRect(10, 10, w-20, 28, 6, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 9.5)
c.drawCentredString(w/2, 22,
'Probenecid has NO antibacterial activity but POTENTIATES penicillin by blocking renal tubular secretion')
# ── 6. Antagonism Type Diagrams ───────────────────────────────────────────────
class AntagonismDiagram(Flowable):
def __init__(self):
super().__init__()
def wrap(self, aW, aH):
self._w = aW
return aW, 310
def _receptor(self, c, cx, cy, r=20, color=TEAL, label='R'):
c.setFillColor(color)
c.circle(cx, cy, r, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 11)
c.drawCentredString(cx, cy-4, label)
def _arrow(self, c, x1, y1, x2, y2, color=DKGREY, lw=1.5, dash=None):
if dash:
c.setDash(dash)
c.setStrokeColor(color)
c.setLineWidth(lw)
c.line(x1, y1, x2, y2)
c.setDash([])
angle = math.atan2(y2-y1, x2-x1)
arr=7; ang=0.4
c.setFillColor(color)
p = c.beginPath()
p.moveTo(x2, y2)
p.lineTo(x2-arr*math.cos(angle-ang), y2-arr*math.sin(angle-ang))
p.lineTo(x2-arr*math.cos(angle+ang), y2-arr*math.sin(angle+ang))
p.close()
c.drawPath(p, fill=1, stroke=0)
def _cross(self, c, cx, cy, size=8):
c.setStrokeColor(RED)
c.setLineWidth(2.5)
c.line(cx-size, cy-size, cx+size, cy+size)
c.line(cx-size, cy+size, cx+size, cy-size)
def draw(self):
c = self.canv
w, h = self._w, 310
c.setFillColor(LRED)
c.roundRect(0, 0, w, h, 10, fill=1, stroke=0)
c.setFillColor(RED)
c.setFont('Helvetica-Bold', 11)
c.drawCentredString(w/2, h-18, 'TYPES OF ANTAGONISM')
# ── (A) Competitive ───────────────────────────────────────────
panel_w = w/2 - 15
# Panel A
c.setFillColor(WHITE)
c.roundRect(8, h-160, panel_w, 130, 7, fill=1, stroke=0)
c.setFillColor(RED)
c.setFont('Helvetica-Bold', 9.5)
c.drawString(18, h-44, 'A) COMPETITIVE ANTAGONISM')
c.setFillColor(DKGREY)
c.setFont('Helvetica', 8)
c.drawString(18, h-56, '(Reversible / Surmountable)')
# Receptor
rx, ry = 80, h-110
self._receptor(c, rx, ry, r=18, color=TEAL, label='R')
# Agonist molecule
c.setFillColor(BLUE)
c.roundRect(rx-10, ry+30, 20, 14, 4, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica', 7)
c.drawCentredString(rx, ry+38, 'AG')
# Antagonist competing
c.setFillColor(RED)
c.roundRect(rx+25, ry+30, 20, 14, 4, fill=1, stroke=0)
c.setFillColor(WHITE)
c.drawCentredString(rx+35, ry+38, 'ANT')
# Arrows competing
self._arrow(c, rx, ry+30, rx, ry+18, BLUE)
self._arrow(c, rx+35, ry+30, rx+18, ry+18, RED, dash=[2,2])
# Label
c.setFillColor(BLUE)
c.setFont('Helvetica', 7.5)
c.drawString(rx-18, ry+46, 'Agonist')
c.setFillColor(RED)
c.drawString(rx+22, ry+46, 'Antagonist')
c.setFillColor(DKGREY)
c.setFont('Helvetica', 7.5)
c.drawString(18, h-130, '↑ Agonist dose → overcomes')
c.drawString(18, h-141, 'Ex: Naloxone vs Morphine')
# Panel B - Non-competitive
c.setFillColor(WHITE)
c.roundRect(w/2+7, h-160, panel_w, 130, 7, fill=1, stroke=0)
c.setFillColor(CRIMSON)
c.setFont('Helvetica-Bold', 9.5)
c.drawString(w/2+17, h-44, 'B) NON-COMPETITIVE')
c.setFillColor(DKGREY)
c.setFont('Helvetica', 8)
c.drawString(w/2+17, h-56, '(Irreversible / Insurmountable)')
rx2 = w/2 + 80
self._receptor(c, rx2, ry, r=18, color=PURPLE, label='R')
# Agonist bound
c.setFillColor(BLUE)
c.roundRect(rx2-10, ry+30, 20, 14, 4, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica', 7)
c.drawCentredString(rx2, ry+38, 'AG')
self._arrow(c, rx2, ry+30, rx2, ry+18, BLUE)
# Allosteric site
c.setFillColor(CRIMSON)
c.circle(rx2+18, ry, 10, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica', 6.5)
c.drawCentredString(rx2+18, ry-3, 'ANT\n(allost)')
# Cross on effect
c.setFillColor(DKGREY)
c.roundRect(rx2-12, ry-35, 24, 14, 3, fill=1, stroke=0)
self._cross(c, rx2, ry-28, 5)
c.setFillColor(DKGREY)
c.setFont('Helvetica', 7.5)
c.drawString(w/2+17, h-130, '↑ Agonist dose CANNOT overcome')
c.drawString(w/2+17, h-141, 'Ex: Phenoxybenzamine vs NA')
# ── (C) Physiological ─────────────────────────────────────────
c.setFillColor(WHITE)
c.roundRect(8, 10, w/2-15, 120, 7, fill=1, stroke=0)
c.setFillColor(BLUE)
c.setFont('Helvetica-Bold', 9.5)
c.drawString(18, 118, 'C) PHYSIOLOGICAL ANTAGONISM')
# Two receptors with opposing effects
r1x, r1y = 70, 80
r2x, r2y = 160, 80
self._receptor(c, r1x, r1y, r=15, color=TEAL, label='α')
self._receptor(c, r2x, r2y, r=15, color=RED, label='H')
# Adrenaline
c.setFillColor(TEAL)
c.roundRect(r1x-12, r1y+22, 24, 14, 4, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica', 7)
c.drawCentredString(r1x, r1y+30, 'Adr')
self._arrow(c, r1x, r1y+22, r1x, r1y+15, TEAL)
# Histamine
c.setFillColor(RED)
c.roundRect(r2x-12, r2y+22, 24, 14, 4, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica', 7)
c.drawCentredString(r2x, r2y+30, 'Hist')
self._arrow(c, r2x, r2y+22, r2x, r2y+15, RED)
# BP arrows
c.setFillColor(TEAL)
c.setFont('Helvetica-Bold', 9)
c.drawString(r1x-12, r1y-28, '↑ BP / ↑ HR')
c.setFillColor(RED)
c.drawString(r2x-12, r2y-28, '↓ BP / bronchosp.')
# Balance
c.setFillColor(GREEN)
c.setFont('Helvetica-Bold', 8)
c.drawCentredString((r1x+r2x)/2, 14, '= Balance (Anaphylaxis Rx)')
# (D) Chemical
c.setFillColor(WHITE)
c.roundRect(w/2+7, 10, panel_w, 120, 7, fill=1, stroke=0)
c.setFillColor(GOLD)
c.setFont('Helvetica-Bold', 9.5)
c.drawString(w/2+17, 118, 'D) CHEMICAL ANTAGONISM')
# Protamine + Heparin
cx1, cx2 = w/2+50, w/2+120
cy0 = 75
c.setFillColor(BLUE)
c.roundRect(cx1-22, cy0, 44, 24, 5, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica', 8)
c.drawCentredString(cx1, cy0+12, 'Heparin (–)')
c.setFillColor(ORANGE)
c.roundRect(cx2-22, cy0, 44, 24, 5, fill=1, stroke=0)
c.setFillColor(WHITE)
c.drawCentredString(cx2, cy0+12, 'Protamine (+)')
# Arrow toward complex
midx = (cx1+22+cx2-22)/2
self._arrow(c, cx1+22, cy0+12, midx-5, cy0+12, BLUE)
self._arrow(c, cx2-22, cy0+12, midx+5, cy0+12, ORANGE)
# Complex
c.setFillColor(PURPLE)
c.roundRect(midx-25, cy0-30, 50, 24, 5, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica', 7.5)
c.drawCentredString(midx, cy0-18, 'Inactive\nComplex')
c.setFillColor(DKGREY)
c.setFont('Helvetica', 8)
c.drawString(w/2+17, 14, 'Direct inactivation outside receptors')
# ── 7. CYP450 Interaction Diagram ─────────────────────────────────────────────
class CYPDiagram(Flowable):
def __init__(self):
super().__init__()
def wrap(self, aW, aH):
self._w = aW
return aW, 260
def _arrow(self, c, x1,y1,x2,y2, color=DKGREY, lw=1.5, label='', cross=False):
angle = math.atan2(y2-y1, x2-x1)
c.setStrokeColor(color)
c.setLineWidth(lw)
c.line(x1,y1,x2,y2)
arr=8; ang=0.4
c.setFillColor(color)
p = c.beginPath()
p.moveTo(x2,y2)
p.lineTo(x2-arr*math.cos(angle-ang), y2-arr*math.sin(angle-ang))
p.lineTo(x2-arr*math.cos(angle+ang), y2-arr*math.sin(angle+ang))
p.close()
c.drawPath(p, fill=1, stroke=0)
if label:
mx,my=(x1+x2)/2,(y1+y2)/2
c.setFillColor(color)
c.setFont('Helvetica-Bold',7.5)
c.drawCentredString(mx, my+5, label)
if cross:
mx,my=(x1+x2)/2,(y1+y2)/2
c.setStrokeColor(RED)
c.setLineWidth(2)
c.line(mx-6, my-6, mx+6, my+6)
c.line(mx-6, my+6, mx+6, my-6)
def _box(self, c, x,y,w,h, text, bg, fg=WHITE, fs=9, r=6):
c.setFillColor(bg)
c.roundRect(x,y,w,h,r, fill=1, stroke=0)
c.setFillColor(fg)
c.setFont('Helvetica-Bold', fs)
lines = textwrap.wrap(text, width=max(int(w/5.3),6))
total=len(lines)*(fs+2)
sy=y+h/2+total/2-fs
for i,ln in enumerate(lines):
c.drawCentredString(x+w/2, sy-i*(fs+2), ln)
def draw(self):
c = self.canv
w, h = self._w, 260
c.setFillColor(LBLUE)
c.roundRect(0,0,w,h,10, fill=1, stroke=0)
c.setFillColor(BLUE)
c.setFont('Helvetica-Bold', 11)
c.drawCentredString(w/2, h-18, 'CYP450-MEDIATED PHARMACOKINETIC DRUG INTERACTIONS')
# ── Left panel: Inhibition ──────────────────────────────
px = 10
c.setFillColor(WHITE)
c.roundRect(px, 10, w/2-20, h-35, 7, fill=1, stroke=0)
c.setFillColor(RED)
c.setFont('Helvetica-Bold', 10)
c.drawCentredString(px + (w/2-20)/2, h-38, 'CYP INHIBITION (↑ Drug Levels)')
# Flow
y_flow = h - 80
self._box(c, px+10, y_flow, 80, 28, 'Drug A\n(substrate)', BLUE, fs=8)
self._box(c, px+110, y_flow, 80, 28, 'CYP450\nInhibited', RED, fs=8)
self._box(c, px+210, y_flow-10, 80, 48, '↑ Drug A\nPlasma Levels\n= TOXICITY', RED, fs=8)
self._arrow(c, px+90, y_flow+14, px+110, y_flow+14, BLUE)
self._arrow(c, px+190, y_flow+14, px+210, y_flow+24, RED, cross=False)
# Inhibitor drug
c.setFillColor(CRIMSON)
c.roundRect(px+100, y_flow-35, 100, 24, 5, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 8)
c.drawCentredString(px+150, y_flow-20, 'Drug B (Inhibitor)')
self._arrow(c, px+150, y_flow-11, px+150, y_flow, CRIMSON)
# Examples
c.setFillColor(DKGREY)
c.setFont('Helvetica-Bold', 8)
c.drawString(px+10, y_flow-50, 'Common CYP3A4 Inhibitors:')
examples = [
'Ketoconazole, Erythromycin',
'Grapefruit juice, Ritonavir',
'Ciprofloxacin (CYP1A2)',
'→ Raise statin, warfarin, cyclosporin levels',
]
c.setFont('Helvetica', 7.5)
for i, ex in enumerate(examples):
c.drawString(px+10, y_flow-63 - i*11, '• '+ex)
# ── Right panel: Induction ─────────────────────────────
px2 = w/2 + 10
c.setFillColor(WHITE)
c.roundRect(px2, 10, w/2-20, h-35, 7, fill=1, stroke=0)
c.setFillColor(GREEN)
c.setFont('Helvetica-Bold', 10)
c.drawCentredString(px2 + (w/2-20)/2, h-38, 'CYP INDUCTION (↓ Drug Levels)')
self._box(c, px2+10, y_flow, 80, 28, 'Drug A\n(substrate)', BLUE, fs=8)
self._box(c, px2+110, y_flow, 80, 28, 'CYP450\nUp-regulated', GREEN, fs=8)
self._box(c, px2+210, y_flow-10, 80, 48, '↓ Drug A\nPlasma Levels\n= FAILURE', ORANGE, fs=8)
self._arrow(c, px2+90, y_flow+14, px2+110, y_flow+14, BLUE)
self._arrow(c, px2+190, y_flow+14, px2+210, y_flow+24, GREEN)
c.setFillColor(GREEN)
c.roundRect(px2+100, y_flow-35, 100, 24, 5, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 8)
c.drawCentredString(px2+150, y_flow-20, 'Drug B (Inducer)')
self._arrow(c, px2+150, y_flow-11, px2+150, y_flow, GREEN)
c.setFillColor(DKGREY)
c.setFont('Helvetica-Bold', 8)
c.drawString(px2+10, y_flow-50, 'Common CYP3A4 Inducers:')
examples2 = [
'Rifampicin (strongest inducer)',
'Carbamazepine, Phenytoin',
'St. John\'s Wort, Barbiturates',
'→ ↓ OCP, warfarin, HIV drugs',
]
c.setFont('Helvetica', 7.5)
for i, ex in enumerate(examples2):
c.drawString(px2+10, y_flow-63 - i*11, '• '+ex)
# ── 8. Pharmacokinetic interaction overview flowchart ─────────────────────────
class PKFlowchart(Flowable):
def __init__(self):
super().__init__()
def wrap(self, aW, aH):
self._w = aW
return aW, 200
def _box(self, c, x,y,w,h, text, bg, fg=WHITE, fs=8.5, r=5):
c.setFillColor(bg)
c.roundRect(x,y,w,h,r, fill=1, stroke=0)
c.setFillColor(fg)
c.setFont('Helvetica-Bold', fs)
lines = textwrap.wrap(text, width=max(int(w/5),6))
total=len(lines)*(fs+1.5)
sy=y+h/2+total/2-fs
for i,ln in enumerate(lines):
c.drawCentredString(x+w/2, sy-i*(fs+1.5), ln)
def _arrow(self, c, x1,y1,x2,y2, color=MDGREY, lw=1.4):
angle=math.atan2(y2-y1,x2-x1)
c.setStrokeColor(color); c.setLineWidth(lw); c.line(x1,y1,x2,y2)
arr=7; ang=0.4; c.setFillColor(color)
p=c.beginPath(); p.moveTo(x2,y2)
p.lineTo(x2-arr*math.cos(angle-ang), y2-arr*math.sin(angle-ang))
p.lineTo(x2-arr*math.cos(angle+ang), y2-arr*math.sin(angle+ang))
p.close(); c.drawPath(p, fill=1, stroke=0)
def draw(self):
c = self.canv
w, h = self._w, 200
c.setFillColor(LGREY)
c.roundRect(0,0,w,h,10, fill=1, stroke=0)
c.setFillColor(NAVY)
c.setFont('Helvetica-Bold', 11)
c.drawCentredString(w/2, h-18, 'PHARMACOKINETIC DRUG INTERACTION SITES (ADME)')
# ADME horizontal row
stages = [
('ABSORPTION', TEAL, ['Chelation (Antacid+Tetracycline)',
'pH change (antacids)',
'P-gp (efflux, e.g. digoxin)']),
('DISTRIBUTION', BLUE, ['Protein binding displacement',
'Warfarin displaced by sulfonamide',
'Volume of distribution changes']),
('METABOLISM', RED, ['CYP induction / inhibition',
'Rifampicin (induces CYP3A4)',
'Ketoconazole (inhibits CYP3A4)']),
('EXCRETION', PURPLE, ['Tubular secretion block',
'Probenecid blocks penicillin',
'Lithium + NSAIDs: ↑Li levels']),
]
box_w = (w - 20) / 4
box_h = 32
top_y = h - 52
for i, (stage, col, notes) in enumerate(stages):
bx = 10 + i * box_w
self._box(c, bx+2, top_y, box_w-6, box_h, stage, col, fs=9)
# Connect with arrows
if i < 3:
self._arrow(c, bx+box_w-4, top_y+16, bx+box_w+4, top_y+16, MDGREY)
# Sub notes
c.setFillColor(DKGREY)
c.setFont('Helvetica', 7.5)
for ni, note_txt in enumerate(notes):
c.drawString(bx+4, top_y-18-ni*11, '• '+note_txt)
# Drug molecule journey label
c.setFillColor(ORANGE)
c.roundRect(10, 10, w-20, 18, 4, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont('Helvetica-Bold', 8.5)
c.drawCentredString(w/2, 17, 'Drug molecule travels through all four ADME stages — interaction can occur at ANY stage')
# ════════════════════════════════════════════════════════════════════════════
# BUILD PDF
# ════════════════════════════════════════════════════════════════════════════
output = '/tmp/workspace/drug-interactions-pdf/Drug_Interactions_Study_Guide.pdf'
doc = SimpleDocTemplate(output, pagesize=A4,
leftMargin=MARGIN, rightMargin=MARGIN,
topMargin=MARGIN, bottomMargin=MARGIN,
title='Drug Interactions Study Guide',
author='Pharmacology Study Guide')
story = []
W = CONTENT_W
# ── PAGE 1: Title + Definition + Mind Map ─────────────────────────────────────
story.append(TitlePage())
story.append(spacer(14))
story.append(banner('1. DEFINITION OF DRUG INTERACTION', color=NAVY))
story.append(spacer(6))
story.append(Paragraph(
'A <b>drug interaction</b> occurs when the pharmacological effect of one drug is altered '
'(enhanced, diminished, or qualitatively changed) by the concurrent or sequential '
'administration of another drug, food, herb, or endogenous substance. '
'Drug interactions are clinically significant when they alter <b>efficacy</b> or cause <b>toxicity</b>, '
'particularly with drugs of <b>narrow therapeutic index</b> (warfarin, digoxin, lithium, phenytoin, aminoglycosides).',
body))
story.append(spacer(6))
story.append(sub_banner('Classification of Drug Interactions', TEAL))
story.append(spacer(6))
story.append(DefinitionMindMap())
story.append(spacer(4))
story.append(Paragraph(
'<b>Pharmacodynamic interactions</b> alter the response at the receptor/effector level without '
'changing drug concentrations. <b>Pharmacokinetic interactions</b> alter Absorption, Distribution, '
'Metabolism, or Excretion (ADME), changing plasma drug levels. <b>Pharmaceutical incompatibility</b> '
'refers to chemical or physical changes before drug reaches the body (e.g., precipitation in IV lines).',
body))
# ── PAGE 2: Additive Effect ────────────────────────────────────────────────────
story.append(PageBreak())
story.append(banner('2. ADDITIVE EFFECT', color=GREEN))
story.append(spacer(6))
story.append(Paragraph(
'When two drugs that act on the <b>same receptor or biological system</b> are combined, '
'their effects simply sum together arithmetically. Neither drug alters the sensitivity '
'of the target to the other.', body))
story.append(spacer(4))
# Formula highlight
formula_data = [
[Paragraph('<b>Formula</b>', th),
Paragraph('<b>Expression</b>', th),
Paragraph('<b>Meaning</b>', th)],
[Paragraph('E(A+B) = E(A) + E(B)', tdB),
Paragraph('1 + 1 = 2', tdB),
Paragraph('The total effect equals the sum of each drug\'s individual effect', td)],
]
story.append(tbl(formula_data, [130, 80, W-230], hdr_color=GREEN))
story.append(spacer(8))
story.append(AdditiveBarChart())
story.append(spacer(8))
story.append(sub_banner('Additive Effect Examples', GREEN))
story.append(spacer(5))
additive_ex = [
[Paragraph('<b>Drug A</b>', th),
Paragraph('<b>Drug B</b>', th),
Paragraph('<b>Combined Additive Effect</b>', th),
Paragraph('<b>Clinical Concern</b>', th)],
[Paragraph('Aspirin', td), Paragraph('Paracetamol', td),
Paragraph('Additive analgesia', td), Paragraph('Useful - allows dose reduction of each', td)],
[Paragraph('Aspirin', td), Paragraph('Ibuprofen', td),
Paragraph('Additive GI mucosal damage', td), Paragraph('Avoid combination - peptic ulcer risk', td)],
[Paragraph('Alcohol', td), Paragraph('Diazepam', td),
Paragraph('Additive CNS depression', td), Paragraph('Dangerous - respiratory depression risk', td)],
[Paragraph('Thiazide diuretic', td), Paragraph('Loop diuretic', td),
Paragraph('Additive diuresis', td), Paragraph('Sequential nephron blockade; used in resistant oedema', td)],
[Paragraph('Aminoglycoside', td), Paragraph('Amphotericin B', td),
Paragraph('Additive nephrotoxicity', td), Paragraph('High risk of acute kidney injury', td)],
[Paragraph('Two antihypertensives', td), Paragraph('(same class)', td),
Paragraph('Additive hypotension', td), Paragraph('Dose titration needed', td)],
]
story.append(tbl(additive_ex, [95, 95, 130, W-340], hdr_color=GREEN, alt=[WHITE, LGREEN]))
story.append(spacer(6))
story.append(Paragraph(
'<b>Key Point:</b> Additive interactions are exploited clinically to achieve efficacy at lower individual doses, '
'reducing side effects. However, additive <i>toxicity</i> is a major cause of adverse drug reactions.',
note))
# ── PAGE 3: Synergism ──────────────────────────────────────────────────────────
story.append(PageBreak())
story.append(banner('3. SYNERGISM (SUPRA-ADDITIVE EFFECT)', color=TEAL))
story.append(spacer(6))
story.append(Paragraph(
'Synergism occurs when two drugs produce a combined effect that is <b>greater than the '
'arithmetic sum</b> of their individual effects. This happens because the drugs act at '
'<b>different sites or different mechanisms</b> but converge on the same physiological outcome.',
body))
story.append(spacer(4))
formula2 = [
[Paragraph('<b>Formula</b>', th), Paragraph('<b>Expression</b>', th), Paragraph('<b>Also called</b>', th)],
[Paragraph('E(A+B) > E(A) + E(B)', tdB), Paragraph('1 + 1 > 2', tdB),
Paragraph('Positive synergism / Superadditivity / Supra-additive effect', td)],
]
story.append(tbl(formula2, [130, 80, W-230], hdr_color=TEAL))
story.append(spacer(8))
story.append(IsobologramDiagram())
story.append(spacer(4))
story.append(Paragraph(
'The <b>isobologram</b> (above) is the graphical tool used to detect synergism. The straight diagonal '
'line joining EC₅₀-A and EC₅₀-B represents additivity. Combinations producing a 50% effect that fall '
'<b>below this line</b> (i.e., require less of each drug than expected) indicate positive synergism. '
'Combinations <b>above the line</b> are subadditive.',
caption))
story.append(spacer(8))
story.append(sub_banner('Types of Synergism', TEAL))
story.append(spacer(5))
syn_types = [
[Paragraph('<b>Type</b>', th),
Paragraph('<b>Mechanism</b>', th),
Paragraph('<b>Example</b>', th),
Paragraph('<b>Clinical Use</b>', th)],
[Paragraph('Bactericidal Synergism', tdB),
Paragraph('Each drug alone is bacteriostatic; combination is bactericidal', td),
Paragraph('Penicillin + Aminoglycoside', td),
Paragraph('Enterococcal endocarditis, serious gram-positive infections', td)],
[Paragraph('Sequential Block Synergism', tdB),
Paragraph('Two drugs block consecutive steps in same metabolic pathway', td),
Paragraph('Trimethoprim + Sulfamethoxazole (Co-trimoxazole)', td),
Paragraph('UTIs, PCP, toxoplasmosis; 20-100× greater activity', td)],
[Paragraph('Receptor-Effector Synergism', tdB),
Paragraph('Drugs act at different receptor subtypes converging on same effect', td),
Paragraph('Morphine + Ketamine (pain control)', td),
Paragraph('Post-operative analgesia; allows opioid dose reduction', td)],
[Paragraph('Pharmacokinetic Synergism', tdB),
Paragraph('One drug increases bioavailability/distribution of another', td),
Paragraph('Levodopa + Carbidopa', td),
Paragraph('Carbidopa blocks peripheral decarboxylation → more levodopa reaches brain', td)],
[Paragraph('Enzyme Protection Synergism', tdB),
Paragraph('One drug protects the other from enzymatic destruction', td),
Paragraph('Amoxicillin + Clavulanate', td),
Paragraph('Clavulanate inhibits β-lactamase → protects amoxicillin', td)],
]
story.append(tbl(syn_types, [100, 130, 110, W-360], hdr_color=TEAL, alt=[WHITE, LTEAL]))
# ── PAGE 4: Potentiation ───────────────────────────────────────────────────────
story.append(PageBreak())
story.append(banner('4. POTENTIATION', color=ORANGE))
story.append(spacer(6))
story.append(Paragraph(
'Potentiation occurs when a drug that has <b>NO activity of its own</b> on a particular '
'biological system <b>increases the effect</b> of another drug that does have activity on '
'that system. This is the key distinction from synergism, where both drugs must be active.',
body))
story.append(spacer(4))
formula3 = [
[Paragraph('<b>Formula</b>', th), Paragraph('<b>Expression</b>', th), Paragraph('<b>Key Distinction</b>', th)],
[Paragraph('E(potentiator alone) = 0\nE(A + potentiator) >> E(A)', tdB),
Paragraph('0 + 1 = 3', tdB),
Paragraph('One drug is INACTIVE on the target system; still amplifies the other drug\'s effect', td)],
]
story.append(tbl(formula3, [150, 70, W-240], hdr_color=ORANGE))
story.append(spacer(8))
story.append(PotentiationDiagram())
story.append(spacer(8))
story.append(sub_banner('Potentiation Examples', ORANGE))
story.append(spacer(5))
pot_ex = [
[Paragraph('<b>Potentiator</b>', th),
Paragraph('<b>Active Drug</b>', th),
Paragraph('<b>Mechanism of Potentiation</b>', th),
Paragraph('<b>Clinical Use</b>', th)],
[Paragraph('Probenecid\n(no antibacterial activity)', td),
Paragraph('Penicillin', td),
Paragraph('Blocks OAT (organic anion transporter) in renal tubules → reduces penicillin excretion → prolongs t½', td),
Paragraph('Historically used to extend penicillin action; still used with cephalosporins in gonorrhoea', td)],
[Paragraph('Clavulanate\n(no direct antibacterial effect)', td),
Paragraph('Amoxicillin', td),
Paragraph('Irreversibly inhibits β-lactamase → protects amoxicillin from destruction', td),
Paragraph('Augmentin - broadens spectrum against β-lactamase producers', td)],
[Paragraph('Carbidopa / Benserazide\n(no antiparkinsonian effect alone)', td),
Paragraph('Levodopa', td),
Paragraph('Peripheral DOPA decarboxylase inhibitor → prevents conversion of L-DOPA to dopamine outside CNS', td),
Paragraph('Sinemet / Madopar - allows 75-80% dose reduction of levodopa', td)],
[Paragraph('CYP inhibitor\n(e.g. Ketoconazole)', td),
Paragraph('Statins / Protease inhibitors (CYP3A4 substrates)', td),
Paragraph('Inhibits CYP3A4 → reduces first-pass and systemic metabolism of co-administered drug', td),
Paragraph('DANGEROUS: raises statin levels (myopathy/rhabdomyolysis)', td)],
[Paragraph('Sulfonamide\n(anti-infective)', td),
Paragraph('Warfarin', td),
Paragraph('(1) Inhibits CYP2C9 → ↓ warfarin metabolism. (2) Displaces warfarin from albumin binding', td),
Paragraph('DANGEROUS: major bleeding risk; monitor INR closely or avoid', td)],
[Paragraph('Dantrolene\n(no NMJ blocking effect)', td),
Paragraph('Neuromuscular blockers', td),
Paragraph('Prevents Ca²⁺ release from SR → depresses muscle contraction → potentiates NMB-induced paralysis', td),
Paragraph('Relevance in anaesthesia; used in malignant hyperthermia treatment', td)],
]
story.append(tbl(pot_ex, [110, 90, 150, W-370], hdr_color=ORANGE, alt=[WHITE, LORANGE]))
# ── PAGE 5: Antagonism ─────────────────────────────────────────────────────────
story.append(PageBreak())
story.append(banner('5. ANTAGONISM', color=RED))
story.append(spacer(6))
story.append(Paragraph(
'Antagonism occurs when one drug <b>reduces or abolishes the effect</b> of another. '
'The combined effect is less than that of either drug alone. Antagonism is classified '
'by <b>mechanism</b> into four main types.',
body))
story.append(spacer(6))
formula4 = [
[Paragraph('<b>Formula</b>', th), Paragraph('<b>Expression</b>', th)],
[Paragraph('E(A+B) < E(A) or E(A+B) < E(B)', tdB),
Paragraph('1 + 1 < 2 or even 1 + 1 = 0', tdB)],
]
story.append(tbl(formula4, [200, W-220], hdr_color=RED))
story.append(spacer(8))
story.append(AntagonismDiagram())
story.append(spacer(8))
story.append(sub_banner('Detailed Classification of Antagonism', RED))
story.append(spacer(5))
ant_data = [
[Paragraph('<b>Type</b>', th),
Paragraph('<b>Sub-type</b>', th),
Paragraph('<b>Mechanism</b>', th),
Paragraph('<b>Reversibility</b>', th),
Paragraph('<b>Example</b>', th)],
[Paragraph('Pharmacological\n(Receptor)\nAntagonism', tdB),
Paragraph('Competitive\n(Surmountable)', td),
Paragraph('Antagonist reversibly occupies same active site as agonist; ↑ agonist dose overcomes block; dose-response curve shifts RIGHT (parallel shift); Emax unchanged', td),
Paragraph('Reversible', td),
Paragraph('Naloxone vs Morphine\nAtropine vs ACh\nBeta-blockers vs Adrenaline\nAntihistamines vs Histamine', td)],
[Paragraph('', tdB),
Paragraph('Non-competitive\n(Insurmountable)', td),
Paragraph('Antagonist binds irreversibly to receptor or allosteric site; increasing agonist dose CANNOT restore Emax; dose-response curve shifts RIGHT + Emax DEPRESSED', td),
Paragraph('Irreversible', td),
Paragraph('Phenoxybenzamine (α-blocker) vs NA\nAspirin (irreversible COX inhibition)\nOrganophosphate vs AChE', td)],
[Paragraph('Physiological\n(Functional)\nAntagonism', tdB),
Paragraph('Functional\nOpposition', td),
Paragraph('Two drugs produce OPPOSITE effects on the same physiological endpoint by acting at DIFFERENT receptors or through entirely different mechanisms; effects cancel', td),
Paragraph('Reversible', td),
Paragraph('Adrenaline (↑BP, bronchodilation) vs Histamine (↓BP, bronchoconstriction)\nGlucagon vs Insulin (blood glucose)\nHeparin vs Protamine (anticoagulation)', td)],
[Paragraph('Chemical\nAntagonism', tdB),
Paragraph('Direct\nInactivation', td),
Paragraph('The two drugs interact CHEMICALLY outside the receptor, forming an inactive complex; this occurs in plasma, GIT, or at injection site', td),
Paragraph('Usually\nirreversible', td),
Paragraph('Protamine + Heparin (ionic complex)\nDimercaprol + Heavy metals (chelation)\nActivated charcoal (adsorption)\nEdrophonium antidote for tubocurarine', td)],
[Paragraph('Pharmacokinetic\nAntagonism', tdB),
Paragraph('Altered\nPharmacokinetics', td),
Paragraph('One drug accelerates elimination or reduces absorption of another without directly interacting at receptor; reduces plasma levels of the target drug', td),
Paragraph('Reversible', td),
Paragraph('Rifampicin induces CYP3A4 → ↓ OCP / warfarin levels\nCholestyramine binds digoxin/warfarin in gut\nAntacids chelate tetracyclines/quinolones', td)],
[Paragraph('Partial Agonist\nAntagonism', tdB),
Paragraph('Competitive\nPartial Agonism', td),
Paragraph('Partial agonist competes with full agonist; reduces the overall effect by replacing a high-efficacy agonist with a low-efficacy partial agonist at the same receptor', td),
Paragraph('Reversible', td),
Paragraph('Buprenorphine (partial opioid agonist) displaces morphine → precipitates withdrawal in opioid-dependent patients', td)],
]
story.append(tbl(ant_data, [80, 80, 175, 65, W-420], hdr_color=RED, alt=[WHITE, LRED]))
# ── PAGE 6: PK Interactions ────────────────────────────────────────────────────
story.append(PageBreak())
story.append(banner('6. PHARMACOKINETIC DRUG INTERACTIONS', color=BLUE))
story.append(spacer(6))
story.append(Paragraph(
'Pharmacokinetic interactions alter the <b>plasma concentration</b> of a drug by modifying one '
'or more stages of ADME without any direct receptor-level action. The resulting '
'change in drug concentration then leads to changed pharmacodynamic effects.',
body))
story.append(spacer(8))
story.append(PKFlowchart())
story.append(spacer(8))
story.append(CYPDiagram())
story.append(spacer(8))
story.append(sub_banner('Key CYP450 Drug Interactions Table', BLUE))
story.append(spacer(5))
cyp_data = [
[Paragraph('<b>CYP Enzyme</b>', th),
Paragraph('<b>Important Inducers</b>', th),
Paragraph('<b>Important Inhibitors</b>', th),
Paragraph('<b>Key Substrates (drugs affected)</b>', th)],
[Paragraph('CYP3A4\n(~50% of drugs)', tdB),
Paragraph('Rifampicin, Carbamazepine, Phenytoin, St. John\'s Wort, Barbiturates', td),
Paragraph('Ketoconazole, Erythromycin, Clarithromycin, Ritonavir, Grapefruit juice', td),
Paragraph('Statins, Cyclosporin, Tacrolimus, Midazolam, Sildenafil, Protease inhibitors, OCP, many antihistamines', td)],
[Paragraph('CYP2C9', tdB),
Paragraph('Rifampicin, Carbamazepine', td),
Paragraph('Fluconazole, Amiodarone, Sulfonamides, Metronidazole', td),
Paragraph('Warfarin (S-enantiomer), Phenytoin, NSAIDs, Glibenclamide, Losartan', td)],
[Paragraph('CYP2C19', tdB),
Paragraph('Rifampicin, Carbamazepine', td),
Paragraph('Omeprazole, Fluconazole, Fluvoxamine', td),
Paragraph('Clopidogrel (prodrug - reduced activation), PPIs, TCAs, some SSRIs', td)],
[Paragraph('CYP2D6', tdB),
Paragraph('(Rarely induced)', td),
Paragraph('Fluoxetine, Paroxetine, Haloperidol, Quinidine, Amiodarone', td),
Paragraph('Codeine (prodrug→morphine), Tramadol, TCAs, Beta-blockers, Tamoxifen, Antipsychotics', td)],
[Paragraph('CYP1A2', tdB),
Paragraph('Smoking, Omeprazole, Rifampicin, Cruciferous vegetables', td),
Paragraph('Ciprofloxacin, Fluvoxamine, Amiodarone', td),
Paragraph('Theophylline, Clozapine, Olanzapine, Warfarin (R-enantiomer), Caffeine', td)],
]
story.append(tbl(cyp_data, [75, 110, 110, W-315], hdr_color=BLUE, alt=[WHITE, LBLUE]))
# ── PAGE 7: High-Yield Clinical Examples ──────────────────────────────────────
story.append(PageBreak())
story.append(banner('7. HIGH-YIELD CLINICAL DRUG INTERACTION EXAMPLES', color=CRIMSON))
story.append(spacer(6))
clinical_data = [
[Paragraph('<b>Interaction</b>', th),
Paragraph('<b>Type</b>', th),
Paragraph('<b>Mechanism</b>', th),
Paragraph('<b>Consequence</b>', th),
Paragraph('<b>Management</b>', th)],
[Paragraph('Warfarin + Aspirin', td),
Paragraph('PD + PK', td),
Paragraph('PD: additive anticoagulation\nPK: aspirin inhibits warfarin CYP2C9 metabolism', td),
Paragraph('Major bleeding risk (GI, intracranial)', td),
Paragraph('Avoid; if essential, reduce warfarin dose + monitor INR', td)],
[Paragraph('MAOIs + Pethidine / Tramadol', td),
Paragraph('PD Potentiation', td),
Paragraph('MAOI inhibits MAO-A → ↑ serotonin. Pethidine also releases/blocks reuptake of serotonin', td),
Paragraph('Serotonin Syndrome: hyperthermia, rigidity, seizures, death', td),
Paragraph('ABSOLUTE CONTRAINDICATION. Washout 14 days before switching', td)],
[Paragraph('Rifampicin + OCP', td),
Paragraph('PK Antagonism', td),
Paragraph('Rifampicin induces CYP3A4 and P-gp → ↑ metabolism + ↑ first-pass of oestrogen/progestogen', td),
Paragraph('Contraceptive failure, unwanted pregnancy', td),
Paragraph('Use additional contraception; switch to IUD or injectable', td)],
[Paragraph('Methotrexate + NSAIDs', td),
Paragraph('PK (excretion)', td),
Paragraph('NSAIDs reduce renal blood flow → ↓ GFR + inhibit tubular secretion of MTX', td),
Paragraph('MTX accumulation → bone marrow suppression, mucositis, hepatotoxicity', td),
Paragraph('Avoid concurrent use; if unavoidable, give folinic acid rescue', td)],
[Paragraph('Digoxin + Amiodarone', td),
Paragraph('PK (metabolism + excretion)', td),
Paragraph('Amiodarone inhibits P-gp and CYP2C9 → ↓ digoxin renal and non-renal clearance', td),
Paragraph('Digoxin toxicity: bradycardia, heart block, nausea, xanthopsia', td),
Paragraph('Reduce digoxin dose by 50% when starting amiodarone; monitor levels', td)],
[Paragraph('Lithium + NSAIDs/Thiazides', td),
Paragraph('PK (excretion)', td),
Paragraph('NSAIDs ↓ prostaglandin-mediated renal blood flow; Thiazides deplete Na → kidney compensates by ↑ Li reabsorption', td),
Paragraph('Lithium toxicity: tremor, confusion, seizures, nephrogenic DI', td),
Paragraph('Avoid NSAIDs; use paracetamol. Monitor Li levels when initiating diuretic', td)],
[Paragraph('Linezolid + SSRIs', td),
Paragraph('PD Potentiation', td),
Paragraph('Linezolid is a reversible non-selective MAO inhibitor; SSRIs inhibit serotonin reuptake → combined serotonin excess', td),
Paragraph('Serotonin Syndrome', td),
Paragraph('Avoid; if essential, closely monitor for serotonin toxicity features', td)],
[Paragraph('Co-trimoxazole\n(TMP + SMX)', td),
Paragraph('PD Synergism', td),
Paragraph('Sequential block of folate synthesis: SMX blocks DHPS; TMP blocks DHFR → both steps inhibited', td),
Paragraph('20-100x greater antibacterial activity vs either alone', td),
Paragraph('Therapeutic exploitation; used in UTI, PCP prophylaxis/treatment', td)],
[Paragraph('Succinylcholine + Organophosphates', td),
Paragraph('PD Potentiation', td),
Paragraph('Organophosphates irreversibly inhibit plasma cholinesterase (pseudocholinesterase) → ↓ succinylcholine metabolism', td),
Paragraph('Prolonged neuromuscular blockade → prolonged apnoea', td),
Paragraph('Avoid succinylcholine; use non-depolarising NMB', td)],
]
story.append(tbl(clinical_data, [95, 60, 145, 100, W-420], hdr_color=CRIMSON, alt=[WHITE, LRED]))
# ── PAGE 8: Summary + Exam Points ─────────────────────────────────────────────
story.append(PageBreak())
story.append(banner('8. SUMMARY COMPARISON TABLE', color=NAVY))
story.append(spacer(6))
summary = [
[Paragraph('<b>Type</b>', th),
Paragraph('<b>Math</b>', th),
Paragraph('<b>Both Drugs Active?</b>', th),
Paragraph('<b>Mechanism</b>', th),
Paragraph('<b>Classic Exam Example</b>', th)],
[Paragraph('Additive', tdB),
Paragraph('1+1=2', tdB),
Paragraph('Yes (same system)', td),
Paragraph('Same receptor/pathway; effects sum', td),
Paragraph('Aspirin + Paracetamol', td)],
[Paragraph('Synergism\n(Supra-additive)', tdB),
Paragraph('1+1>2', tdB),
Paragraph('Yes (different mechanisms)', td),
Paragraph('Different sites, convergent outcome; isobologram bows inward', td),
Paragraph('TMP + SMX; Penicillin + Aminoglycoside', td)],
[Paragraph('Potentiation', tdB),
Paragraph('0+1=3', tdB),
Paragraph('No — one is inactive', td),
Paragraph('Inactive drug amplifies active drug (PK or enzymatic)', td),
Paragraph('Probenecid + Penicillin; Carbidopa + Levodopa', td)],
[Paragraph('Competitive\nAntagonism', tdB),
Paragraph('1+1→0\n(reversible)', tdB),
Paragraph('Agonist active;\nantagonist blocks', td),
Paragraph('Same receptor, reversible; parallel right-shift; Emax unchanged', td),
Paragraph('Naloxone + Morphine; Atropine + ACh', td)],
[Paragraph('Non-competitive\nAntagonism', tdB),
Paragraph('1+1→0\n(irreversible)', tdB),
Paragraph('Agonist active;\nantagonist blocks', td),
Paragraph('Same receptor, irreversible; right-shift + ↓ Emax', td),
Paragraph('Phenoxybenzamine + Noradrenaline', td)],
[Paragraph('Physiological\nAntagonism', tdB),
Paragraph('1+1→0\n(different R)', tdB),
Paragraph('Both active (opposing)', td),
Paragraph('Different receptors, opposing physiological effects', td),
Paragraph('Adrenaline + Histamine (anaphylaxis)', td)],
[Paragraph('Chemical\nAntagonism', tdB),
Paragraph('1+1→0\n(no receptor)', tdB),
Paragraph('Direct chemical\nreaction', td),
Paragraph('In vitro or in vivo chemical inactivation', td),
Paragraph('Protamine + Heparin; EDTA + heavy metals', td)],
[Paragraph('Pharmacokinetic\nAntagonism', tdB),
Paragraph('1+1<2\n(ADME)', tdB),
Paragraph('Both active; one reduces the other\'s levels', td),
Paragraph('CYP induction / ↑ excretion / ↓ absorption of co-drug', td),
Paragraph('Rifampicin + Warfarin; Antacid + Tetracycline', td)],
]
story.append(tbl(summary, [80, 48, 75, 140, W-363], hdr_color=NAVY))
story.append(spacer(10))
story.append(banner('9. HIGH-YIELD EXAM POINTS', color=HexColor('#7B1FA2')))
story.append(spacer(6))
exam_pts = [
('Narrow therapeutic index drugs', 'Interactions are most dangerous with warfarin, digoxin, lithium, phenytoin, theophylline, aminoglycosides, cyclosporin — monitor plasma levels when adding/removing drugs'),
('Isobologram', 'Below the line of additivity = positive synergism (superadditive); above the line = subadditivity (negative synergism)'),
('Competitive vs Non-competitive', 'Competitive: right-shift of DRC, Emax unchanged; Non-competitive: right-shift + Emax depressed — this is the most tested distinction'),
('Serotonin Syndrome triad', 'Mental change + neuromuscular abnormality + autonomic instability. Caused by MAOIs + pethidine/tramadol/SSRIs/linezolid. Life-threatening.'),
('Rifampicin', 'Most potent CYP3A4 inducer — causes failure of warfarin, OCP, protease inhibitors, immunosuppressants. Always check interactions when starting TB therapy.'),
('Grapefruit juice', 'CYP3A4 inhibitor (furanocoumarins) — raises levels of statins, calcium channel blockers, immunosuppressants. Single glass can inhibit CYP for 24-72h.'),
('Protamine + Heparin', 'Classic chemical antagonism — protamine (cationic) neutralises heparin (anionic) 1mg per 100 units of heparin. Used post-cardiac surgery.'),
('TMP/SMX sequential block', 'Textbook example of synergism — two drugs blocking consecutive enzymatic steps in same pathway; 20-100x more effective than either alone.'),
('Probenecid + Penicillin', 'Classic potentiation — probenecid has NO antibacterial activity but prolongs penicillin half-life by blocking renal tubular secretion (OAT transporter).'),
('Linezolid caution', 'Reversible MAOI. Must avoid SSRIs, TCAs, pethidine — risk of serotonin syndrome. Also causes myelosuppression — additive with other bone marrow suppressants.'),
]
for bold_t, detail_t in exam_pts:
story.append(Paragraph(f'<b>• {bold_t}:</b> {detail_t}', bullet))
story.append(spacer(2))
story.append(spacer(8))
story.append(hr(color=NAVY))
story.append(spacer(4))
story.append(Paragraph(
'References: Goodman & Gilman\'s Pharmacological Basis of Therapeutics 14e | '
'Goldman-Cecil Medicine | Lippincott Illustrated Reviews: Pharmacology | '
'Katzung Basic & Clinical Pharmacology 16e | Miller\'s Anesthesia 10e',
caption))
doc.build(story)
print(f"PDF generated: {output}")
cd /tmp/workspace/drug-interactions-pdf && python build_pdf.py 2>&1
ls -lh /tmp/workspace/drug-interactions-pdf/Drug_Interactions_Study_Guide.pdf
Drug Interactions Study Guide
PDF Document · PDF
Complete
The ongoing pdf