Create a high-quality medical infographic in a clean MBBS study-note style similar to the reference image. Use a white background with colorful pastel boxes (Red, Blue, Green, Purple, Yellow), hand-drawn medical icons, rounded borders, and bold headings. The layout should be simple, organized, and exam-friendly. At the top, include: Title: "[Nitrates/ Glyceryl trinitrate]" Trick to Remember: Create a short mnemonic (letters, word, or acronym) that helps memorize the drug classes. Then divide the infographic into separate colored sections. For every drug class include: Drug/Class Name Examples (4–6 drugs) Mechanism of Action (Simple arrows ↓ ↑) Main Effects Clinical Uses Important Side Effects Contraindications Special Benefits Important Notes Easy Memory Trick Use icons like: ❤️ Heart 🩸 Blood vessel 🫀 Heart pump 🧠 Brain 🫁 Lungs 💊 Tablet 💉 Injection 💧 Water 🩺 Stethoscope 🧬 Receptor At the bottom include: Quick Recall Box Summarize each class in one line. Use very simple English suitable for MBBS, BDS, Pharm-D, Nursing, and NEET students. Maintain equal spacing, colorful sections, tick marks (✔), arrows (↓ ↑), and a handwritten study-notes appearance. Output should look like a printable A4 medical revision sheet.

Reading File
Finding Sources
Finding Sources
Reading File
Reading File
Reading File
Reading File
Running Command

ls -la /tmp/workspace/ 2>/dev/null || mkdir -p /tmp/workspace/nitrates-infographic

Running Command

mkdir -p /tmp/workspace/nitrates-infographic

Writing File

~/nitrates-infographic/nitrates.py

#!/usr/bin/env python3
"""
Generate a high-quality medical infographic for Nitrates / Glyceryl Trinitrate
using ReportLab - A4 printable study note style.
"""

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm, cm
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import Flowable
from reportlab.lib.colors import HexColor, white, black
from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader
import io

# ── Colour palette ────────────────────────────────────────────────────────────
RED_BG     = HexColor("#FFF0F0")
RED_HDR    = HexColor("#E53935")
BLUE_BG    = HexColor("#F0F4FF")
BLUE_HDR   = HexColor("#1565C0")
GREEN_BG   = HexColor("#F0FFF4")
GREEN_HDR  = HexColor("#2E7D32")
PURPLE_BG  = HexColor("#F8F0FF")
PURPLE_HDR = HexColor("#6A1B9A")
YELLOW_BG  = HexColor("#FFFDE7")
YELLOW_HDR = HexColor("#F57F17")
TEAL_BG    = HexColor("#E0F7FA")
TEAL_HDR   = HexColor("#00695C")
ORANGE_BG  = HexColor("#FFF3E0")
ORANGE_HDR = HexColor("#E65100")
PINK_BG    = HexColor("#FCE4EC")
PINK_HDR   = HexColor("#AD1457")

TITLE_BG   = HexColor("#1A237E")
TITLE_FG   = white
MNEMONIC_BG= HexColor("#FFF8E1")
MNEMONIC_BD= HexColor("#FFB300")

W, H = A4  # 595.27, 841.89 pts

# ── Custom Flowables ──────────────────────────────────────────────────────────

class SectionBox(Flowable):
    """A rounded-rectangle coloured box that wraps a list of Flowables."""

    def __init__(self, header_text, header_icon, body_items,
                 bg_color, hdr_color, width=None, radius=8):
        Flowable.__init__(self)
        self.header_text = header_text
        self.header_icon = header_icon
        self.body_items  = body_items   # list of (label, value) tuples OR plain strings
        self.bg_color    = bg_color
        self.hdr_color   = hdr_color
        self.width       = width or (W - 2*cm)
        self.radius      = radius
        self._height     = 0

    def wrap(self, availWidth, availHeight):
        self.width = availWidth
        # estimate height
        self._height = 28 + len(self.body_items) * 16 + 10
        return (self.width, self._height)

    def draw(self):
        c = self.canv
        w, h = self.width, self._height
        r = self.radius

        # Background rounded rect
        c.setFillColor(self.bg_color)
        c.setStrokeColor(self.hdr_color)
        c.setLineWidth(1.5)
        c.roundRect(0, 0, w, h, r, stroke=1, fill=1)

        # Header bar
        c.setFillColor(self.hdr_color)
        p = c.beginPath()
        p.moveTo(r, h)
        p.lineTo(w-r, h)
        p.arcTo(w-2*r, h-2*r, w, h, 0, 90)
        p.lineTo(w, h-24)
        p.lineTo(0, h-24)
        p.arcTo(0, h-24, 2*r, h, 90, 90)  # top-left arc
        p.close()
        # simpler: just a rect for header
        c.roundRect(0, h-26, w, 26, r, stroke=0, fill=1)
        # patch corners at bottom of header
        c.rect(0, h-26, w, 13, stroke=0, fill=1)

        # Header text
        c.setFillColor(white)
        c.setFont("Helvetica-Bold", 10)
        c.drawString(8, h-18, f"{self.header_icon}  {self.header_text}")

        # Body rows
        y = h - 38
        for item in self.body_items:
            if isinstance(item, tuple):
                label, value = item
                c.setFillColor(self.hdr_color)
                c.setFont("Helvetica-Bold", 8)
                c.drawString(10, y, label)
                c.setFillColor(HexColor("#222222"))
                c.setFont("Helvetica", 8)
                # wrap value
                max_w = w - 14
                lines = self._wrap_text(str(value), "Helvetica", 8, max_w - 80)
                c.drawString(90, y, lines[0] if lines else "")
                for i, extra in enumerate(lines[1:], 1):
                    y -= 11
                    c.drawString(90, y, extra)
            else:
                c.setFillColor(HexColor("#333333"))
                c.setFont("Helvetica", 8)
                lines = self._wrap_text(str(item), "Helvetica", 8, w - 20)
                c.drawString(10, y, lines[0] if lines else "")
                for extra in lines[1:]:
                    y -= 11
                    c.drawString(10, y, extra)
            y -= 14
            if y < 8:
                break

    def _wrap_text(self, text, font, size, maxw):
        words = text.split()
        lines, cur = [], ""
        from reportlab.pdfbase.pdfmetrics import stringWidth
        for w in words:
            test = (cur + " " + w).strip()
            if stringWidth(test, font, size) <= maxw:
                cur = test
            else:
                if cur:
                    lines.append(cur)
                cur = w
        if cur:
            lines.append(cur)
        return lines or [""]


# ── Build the PDF ─────────────────────────────────────────────────────────────

def build_pdf(path):
    doc = SimpleDocTemplate(
        path,
        pagesize=A4,
        rightMargin=1.2*cm,
        leftMargin=1.2*cm,
        topMargin=1.2*cm,
        bottomMargin=1.2*cm,
    )

    styles = getSampleStyleSheet()

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

    title_style = ps("Title2",
        fontSize=20, textColor=white, fontName="Helvetica-Bold",
        alignment=TA_CENTER, spaceAfter=4, leading=24)

    subtitle_style = ps("Subtitle2",
        fontSize=11, textColor=HexColor("#BBDEFB"), fontName="Helvetica-Oblique",
        alignment=TA_CENTER, spaceAfter=2, leading=14)

    mnem_label = ps("MnemLabel",
        fontSize=10, textColor=HexColor("#5D4037"), fontName="Helvetica-Bold",
        alignment=TA_CENTER, spaceAfter=2)

    mnem_text = ps("MnemText",
        fontSize=13, textColor=HexColor("#E65100"), fontName="Helvetica-Bold",
        alignment=TA_CENTER, spaceAfter=1, leading=18)

    mnem_expand = ps("MnemExpand",
        fontSize=9, textColor=HexColor("#333333"), fontName="Helvetica",
        alignment=TA_CENTER, spaceAfter=2, leading=12)

    section_hdr = ps("SHdr",
        fontSize=11, textColor=white, fontName="Helvetica-Bold",
        alignment=TA_LEFT, leading=14)

    body_bold = ps("BB",
        fontSize=9, textColor=HexColor("#1A237E"), fontName="Helvetica-Bold",
        leading=13)

    body_norm = ps("BN",
        fontSize=9, textColor=HexColor("#222222"), fontName="Helvetica",
        leading=12)

    small_note = ps("SN",
        fontSize=8, textColor=HexColor("#444444"), fontName="Helvetica-Oblique",
        leading=11)

    recall_hdr = ps("RecallHdr",
        fontSize=11, textColor=white, fontName="Helvetica-Bold",
        alignment=TA_CENTER, leading=14)

    recall_item = ps("RecallItem",
        fontSize=9, textColor=HexColor("#1B5E20"), fontName="Helvetica",
        leading=13, leftIndent=6)

    content_width = W - 2.4*cm

    # ── Helper: coloured cell paragraph ──────────────────────────────────────
    def cp(text, style, bg=None):
        return Paragraph(text, style)

    def hdr_para(icon, text, color):
        return Paragraph(f'<font color="white"><b>{icon} {text}</b></font>',
                         ps("hp", fontSize=10, fontName="Helvetica-Bold",
                            textColor=white, leading=13))

    def bullet(text, tick=True):
        mark = "✔ " if tick else "→ "
        return Paragraph(f"{mark}{text}", body_norm)

    def arrow_item(label, val):
        return Paragraph(f'<b>{label}:</b> {val}', body_norm)

    # ════════════════════════════════════════════════════════════════════════
    # TITLE BLOCK
    # ════════════════════════════════════════════════════════════════════════
    story = []

    # Title table (dark blue header)
    title_data = [[
        Paragraph(
            '<font color="white"><b>💊 NITRATES / GLYCERYL TRINITRATE (GTN)</b></font>',
            ps("T", fontSize=18, fontName="Helvetica-Bold", textColor=white,
               alignment=TA_CENTER, leading=22)
        )
    ]]
    title_tbl = Table(title_data, colWidths=[content_width])
    title_tbl.setStyle(TableStyle([
        ("BACKGROUND", (0,0), (-1,-1), TITLE_BG),
        ("ROUNDEDCORNERS", [8]),
        ("TOPPADDING",   (0,0), (-1,-1), 10),
        ("BOTTOMPADDING",(0,0), (-1,-1), 10),
        ("LEFTPADDING",  (0,0), (-1,-1), 12),
        ("RIGHTPADDING", (0,0), (-1,-1), 12),
    ]))
    story.append(title_tbl)
    story.append(Spacer(1, 4))

    # Subtitle row
    subtitle_data = [[
        Paragraph(
            '<font color="#1565C0"><i>Organic Nitrate Vasodilator | Anti-Anginal | Smooth Muscle Relaxant</i></font>',
            ps("sub", fontSize=9, fontName="Helvetica-Oblique",
               textColor=HexColor("#1565C0"), alignment=TA_CENTER)
        ),
        Paragraph(
            '<font color="#444444">📚 For MBBS · BDS · Pharm-D · Nursing · NEET</font>',
            ps("sub2", fontSize=9, fontName="Helvetica",
               textColor=HexColor("#444444"), alignment=TA_CENTER)
        )
    ]]
    sub_tbl = Table(subtitle_data, colWidths=[content_width*0.6, content_width*0.4])
    sub_tbl.setStyle(TableStyle([
        ("TOPPADDING",   (0,0),(-1,-1), 2),
        ("BOTTOMPADDING",(0,0),(-1,-1), 2),
    ]))
    story.append(sub_tbl)
    story.append(Spacer(1, 6))

    # ════════════════════════════════════════════════════════════════════════
    # MNEMONIC BOX
    # ════════════════════════════════════════════════════════════════════════
    mnem_data = [[
        Paragraph('🧠 <b>TRICK TO REMEMBER</b>', ps("ml", fontSize=10,
            fontName="Helvetica-Bold", textColor=HexColor("#5D4037"), alignment=TA_CENTER)),
        Paragraph(
            '<b><font color="#E65100" size="14">"VEIN-GO"</font></b>',
            ps("mv", fontSize=12, fontName="Helvetica-Bold",
               textColor=HexColor("#E65100"), alignment=TA_CENTER)
        ),
        Paragraph(
            '<b>V</b>eno-dilation → ↓ Preload  &nbsp;|&nbsp; '
            '<b>E</b>ndogenous NO donor  &nbsp;|&nbsp; '
            '<b>I</b>schaemia relief  &nbsp;|&nbsp; '
            '<b>N</b>itroglycerin first line  &nbsp;|&nbsp; '
            '<b>G</b>uanylate cyclase ↑  &nbsp;|&nbsp; '
            '<b>O</b>vernight patch-free interval',
            ps("me", fontSize=8, fontName="Helvetica",
               textColor=HexColor("#333333"), alignment=TA_CENTER, leading=11)
        )
    ]]
    mnem_tbl = Table(mnem_data, colWidths=[content_width*0.22, content_width*0.2, content_width*0.58])
    mnem_tbl.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,-1), MNEMONIC_BG),
        ("ROUNDEDCORNERS",[8]),
        ("BOX",          (0,0),(-1,-1), 1.5, MNEMONIC_BD),
        ("TOPPADDING",   (0,0),(-1,-1), 8),
        ("BOTTOMPADDING",(0,0),(-1,-1), 8),
        ("LEFTPADDING",  (0,0),(-1,-1), 6),
        ("RIGHTPADDING", (0,0),(-1,-1), 6),
        ("VALIGN",       (0,0),(-1,-1), "MIDDLE"),
    ]))
    story.append(mnem_tbl)
    story.append(Spacer(1, 7))

    # ════════════════════════════════════════════════════════════════════════
    # HELPER: make a section block as a Table
    # ════════════════════════════════════════════════════════════════════════
    def make_section(icon, title, rows, bg, hdr, width=None):
        """rows = list of (label_para, value_para) or single para"""
        w = width or content_width
        header_row = [[
            Paragraph(f'<font color="white"><b>{icon}  {title}</b></font>',
                      ps("sh", fontSize=10, fontName="Helvetica-Bold",
                         textColor=white, leading=13))
        ]]
        body_rows = []
        for row in rows:
            if isinstance(row, (list, tuple)) and len(row) == 2:
                body_rows.append([row[0], row[1]])
            else:
                body_rows.append([row, ""])

        all_rows = header_row + body_rows
        col_widths = [w*0.32, w*0.68] if body_rows and len(body_rows[0]) == 2 else [w]
        # If header is full width
        tbl_data = [header_row[0]] + body_rows

        # build as merged header + 2-col body
        flat = [[Paragraph(f'<font color="white"><b>{icon}  {title}</b></font>',
                           ps("sh2", fontSize=10, fontName="Helvetica-Bold",
                              textColor=white, leading=13)),""]
                ] + body_rows
        tbl = Table(flat, colWidths=[w*0.30, w*0.70])
        style = [
            ("BACKGROUND",   (0,0),(-1,0), hdr),
            ("SPAN",         (0,0),(-1,0)),
            ("BACKGROUND",   (0,1),(-1,-1), bg),
            ("ROUNDEDCORNERS",[6]),
            ("BOX",          (0,0),(-1,-1), 1.2, hdr),
            ("GRID",         (0,1),(-1,-1), 0.3, HexColor("#DDDDDD")),
            ("TOPPADDING",   (0,0),(-1,-1), 5),
            ("BOTTOMPADDING",(0,0),(-1,-1), 5),
            ("LEFTPADDING",  (0,0),(-1,-1), 7),
            ("RIGHTPADDING", (0,0),(-1,-1), 7),
            ("VALIGN",       (0,0),(-1,-1), "TOP"),
            ("FONTNAME",     (0,1),(0,-1), "Helvetica-Bold"),
            ("FONTSIZE",     (0,1),(0,-1), 8),
            ("TEXTCOLOR",    (0,1),(0,-1), hdr),
            ("FONTNAME",     (1,1),(1,-1), "Helvetica"),
            ("FONTSIZE",     (1,1),(1,-1), 8.5),
        ]
        tbl.setStyle(TableStyle(style))
        return tbl

    def lbl(t, c=None):
        color = c or HexColor("#1A237E")
        return Paragraph(f'<b><font color="{color.hexval() if hasattr(c,"hexval") else "#1A237E"}">{t}</font></b>',
                         ps("lbl", fontSize=8.5, fontName="Helvetica-Bold",
                            textColor=HexColor("#1A237E"), leading=12))

    def val(t):
        return Paragraph(t, ps("val", fontSize=8.5, fontName="Helvetica",
                               textColor=HexColor("#222222"), leading=12))

    def lbl2(t, col):
        return Paragraph(f'<b>{t}</b>',
                         ps("lbl2"+t, fontSize=8.5, fontName="Helvetica-Bold",
                            textColor=col, leading=12))

    # ════════════════════════════════════════════════════════════════════════
    # SECTION 1 – DRUG / CLASS NAME + EXAMPLES  (RED)
    # ════════════════════════════════════════════════════════════════════════
    s1 = make_section(
        "💊", "DRUG CLASS & EXAMPLES",
        [
            (lbl2("Drug Class:", RED_HDR), val("Organic Nitrates (Nitrovasodilators)")),
            (lbl2("Prototype:", RED_HDR),  val("Glyceryl Trinitrate (GTN / Nitroglycerin)")),
            (lbl2("Short-acting:", RED_HDR), val("✔ GTN (sublingual tab/spray) — onset 1–3 min\n✔ Amyl nitrite (inhalation)")),
            (lbl2("Long-acting:", RED_HDR), val("✔ Isosorbide Dinitrate (ISDN) — oral/sublingual\n✔ Isosorbide Mononitrate (ISMN) — oral\n✔ GTN patch / ointment (transdermal)\n✔ Pentaerythritol tetranitrate (PETN)")),
        ],
        RED_BG, RED_HDR
    )
    story.append(s1)
    story.append(Spacer(1, 6))

    # ════════════════════════════════════════════════════════════════════════
    # SECTION 2 – MECHANISM OF ACTION  (BLUE)
    # ════════════════════════════════════════════════════════════════════════
    s2 = make_section(
        "🧬", "MECHANISM OF ACTION",
        [
            (lbl2("Step 1:", BLUE_HDR), val("GTN (prodrug) → metabolised by mitochondrial aldehyde dehydrogenase-2 (ALDH-2) → releases Nitric Oxide (NO)")),
            (lbl2("Step 2:", BLUE_HDR), val("NO → activates soluble Guanylate Cyclase (sGC) → ↑ cGMP")),
            (lbl2("Step 3:", BLUE_HDR), val("↑ cGMP → activates Protein Kinase G (PKG) → dephosphorylates myosin light chain (MLC)")),
            (lbl2("Step 4:", BLUE_HDR), val("↓ intracellular Ca²⁺ + dephosphorylated MLC → Vascular Smooth Muscle RELAXATION → Vasodilation")),
            (lbl2("Net Effect:", BLUE_HDR), val("Veins >> Arteries dilated (at low doses) | Both dilated at high doses")),
            (lbl2("Also:", BLUE_HDR), val("↑ cGMP → inhibits platelet aggregation | Bronchial & GI smooth muscle relaxation")),
        ],
        BLUE_BG, BLUE_HDR
    )
    story.append(s2)
    story.append(Spacer(1, 6))

    # ════════════════════════════════════════════════════════════════════════
    # ROW of 2: MAIN EFFECTS (GREEN) + HAEMODYNAMIC (TEAL)
    # ════════════════════════════════════════════════════════════════════════
    hw = (content_width - 5) / 2

    def make_section_half(icon, title, rows, bg, hdr):
        return make_section(icon, title, rows, bg, hdr, width=hw)

    s3a = make_section_half(
        "❤️", "MAIN EFFECTS",
        [
            (lbl2("Venous:", GREEN_HDR),   val("↑ venous capacitance → ↓ venous return → ↓ Preload")),
            (lbl2("Arterial:", GREEN_HDR), val("↓ peripheral resistance → ↓ Afterload (high dose)")),
            (lbl2("Coronary:", GREEN_HDR), val("Dilates large coronary arteries → relieves vasospasm")),
            (lbl2("O₂ demand:", GREEN_HDR),val("↓ LVEDV → ↓ wall tension → ↓ MVO₂")),
            (lbl2("Collateral:", GREEN_HDR),val("↑ collateral blood flow to ischaemic subendocardium")),
        ],
        GREEN_BG, GREEN_HDR
    )

    s3b = make_section_half(
        "🩸", "HAEMODYNAMIC CHANGES",
        [
            (lbl2("HR:", TEAL_HDR),        val("↑ (reflex tachycardia)")),
            (lbl2("BP:", TEAL_HDR),        val("↓ Systolic & Diastolic")),
            (lbl2("Preload:", TEAL_HDR),   val("↓↓ (main effect)")),
            (lbl2("Afterload:", TEAL_HDR), val("↓ (at higher doses)")),
            (lbl2("LVEDP:", TEAL_HDR),     val("↓ (reduces pulmonary congestion)")),
            (lbl2("CO:", TEAL_HDR),        val("↔ / slight ↑ in heart failure")),
        ],
        TEAL_BG, TEAL_HDR
    )

    row1 = Table([[s3a, s3b]], colWidths=[hw, hw])
    row1.setStyle(TableStyle([
        ("TOPPADDING",    (0,0),(-1,-1), 0),
        ("BOTTOMPADDING", (0,0),(-1,-1), 0),
        ("LEFTPADDING",   (0,0),(-1,-1), 0),
        ("RIGHTPADDING",  (0,0),(0,-1),  3),
        ("RIGHTPADDING",  (1,0),(1,-1),  0),
    ]))
    story.append(row1)
    story.append(Spacer(1, 6))

    # ════════════════════════════════════════════════════════════════════════
    # SECTION 4 – CLINICAL USES  (PURPLE)
    # ════════════════════════════════════════════════════════════════════════
    s4 = make_section(
        "🩺", "CLINICAL USES",
        [
            (lbl2("1.", PURPLE_HDR), val("✔ Acute Angina Attack — sublingual GTN (drug of choice for immediate relief)")),
            (lbl2("2.", PURPLE_HDR), val("✔ Stable Angina — prophylaxis before exertion (ISDN / ISMN long-acting)")),
            (lbl2("3.", PURPLE_HDR), val("✔ Unstable Angina — IV nitroglycerin")),
            (lbl2("4.", PURPLE_HDR), val("✔ Variant (Prinzmetal) Angina — relieves coronary vasospasm")),
            (lbl2("5.", PURPLE_HDR), val("✔ Acute Heart Failure / Pulmonary Oedema — ↓ preload → ↓ pulmonary congestion")),
            (lbl2("6.", PURPLE_HDR), val("✔ Hypertensive Emergency — IV GTN")),
            (lbl2("7.", PURPLE_HDR), val("✔ Acute MI — used with other agents")),
            (lbl2("8.", PURPLE_HDR), val("✔ Esophageal spasm, Anal fissure (topical GTN ointment)")),
        ],
        PURPLE_BG, PURPLE_HDR
    )
    story.append(s4)
    story.append(Spacer(1, 6))

    # ════════════════════════════════════════════════════════════════════════
    # ROW of 2: SIDE EFFECTS (ORANGE) + CONTRAINDICATIONS (RED-dark)
    # ════════════════════════════════════════════════════════════════════════
    s5a = make_section_half(
        "⚠️", "SIDE EFFECTS",
        [
            (lbl2("Common:", ORANGE_HDR),  val("Throbbing headache (most common!) — due to meningeal vasodilation")),
            (lbl2("Common:", ORANGE_HDR),  val("Postural hypotension, Dizziness, Flushing of face")),
            (lbl2("Reflex:", ORANGE_HDR),  val("Tachycardia (baroreceptor reflex)")),
            (lbl2("Serious:", ORANGE_HDR), val("Syncope (especially if upright)")),
            (lbl2("Tolerance:", ORANGE_HDR), val("Develops rapidly with continuous use (nitrate tolerance)")),
            (lbl2("Methaemoglobinaemia:", ORANGE_HDR), val("Rare, with excessive doses")),
        ],
        ORANGE_BG, ORANGE_HDR
    )

    s5b = make_section_half(
        "🚫", "CONTRAINDICATIONS",
        [
            (lbl2("Absolute:", RED_HDR),   val("↔ PDE-5 inhibitors (sildenafil, tadalafil) — risk of fatal hypotension")),
            (lbl2("Absolute:", RED_HDR),   val("Severe hypotension (SBP < 90 mmHg)")),
            (lbl2("Absolute:", RED_HDR),   val("Hypovolaemia / Shock")),
            (lbl2("Caution:", RED_HDR),    val("Raised intracranial pressure (ICP)")),
            (lbl2("Caution:", RED_HDR),    val("Hypertrophic obstructive cardiomyopathy (HOCM)")),
            (lbl2("Caution:", RED_HDR),    val("Right ventricular MI (dependent on preload)")),
            (lbl2("Caution:", RED_HDR),    val("Glaucoma (closed angle) — can ↑ IOP")),
        ],
        RED_BG, RED_HDR
    )

    row2 = Table([[s5a, s5b]], colWidths=[hw, hw])
    row2.setStyle(TableStyle([
        ("TOPPADDING",    (0,0),(-1,-1), 0),
        ("BOTTOMPADDING", (0,0),(-1,-1), 0),
        ("LEFTPADDING",   (0,0),(-1,-1), 0),
        ("RIGHTPADDING",  (0,0),(0,-1),  3),
        ("RIGHTPADDING",  (1,0),(1,-1),  0),
    ]))
    story.append(row2)
    story.append(Spacer(1, 6))

    # ════════════════════════════════════════════════════════════════════════
    # ROW of 2: SPECIAL BENEFITS (YELLOW) + TOLERANCE (PINK)
    # ════════════════════════════════════════════════════════════════════════
    s6a = make_section_half(
        "⭐", "SPECIAL BENEFITS & NOTES",
        [
            (lbl2("★ GTN:", YELLOW_HDR),     val("Acts within 1–3 min SL — fastest antianginal")),
            (lbl2("★ Route:", YELLOW_HDR),   val("SL / Spray — bypasses first-pass metabolism")),
            (lbl2("★ ISMN:", YELLOW_HDR),    val("No first-pass metabolism → 100% oral bioavailability")),
            (lbl2("★ Patch:", YELLOW_HDR),   val("12 h on / 12 h off → prevents tolerance")),
            (lbl2("★ HF use:", YELLOW_HDR),  val("↓ preload → relieves pulmonary oedema rapidly")),
            (lbl2("★ Platelet:", YELLOW_HDR),val("↑ cGMP → mild antiplatelet effect")),
        ],
        YELLOW_BG, YELLOW_HDR
    )

    s6b = make_section_half(
        "🔄", "TOLERANCE & HOW TO PREVENT",
        [
            (lbl2("Cause:", PINK_HDR),   val("Continuous use → generates ROS → inhibits ALDH-2 → ↓ NO production")),
            (lbl2("Also:", PINK_HDR),    val("↑ sympathetic activation, ↑ plasma volume, neurohormonal activation")),
            (lbl2("Prevention:", PINK_HDR), val("✔ Provide 10–12 h nitrate-free interval (overnight) daily")),
            (lbl2("Patch:", PINK_HDR),   val("Remove patch at night, reapply in morning")),
            (lbl2("ISMN:", PINK_HDR),    val("Asymmetric dosing: 8 AM + 3 PM (not evenly spaced)")),
            (lbl2("⚠ Note:", PINK_HDR), val("Variant angina may worsen at night → monitor during free interval")),
        ],
        PINK_BG, PINK_HDR
    )

    row3 = Table([[s6a, s6b]], colWidths=[hw, hw])
    row3.setStyle(TableStyle([
        ("TOPPADDING",    (0,0),(-1,-1), 0),
        ("BOTTOMPADDING", (0,0),(-1,-1), 0),
        ("LEFTPADDING",   (0,0),(-1,-1), 0),
        ("RIGHTPADDING",  (0,0),(0,-1),  3),
        ("RIGHTPADDING",  (1,0),(1,-1),  0),
    ]))
    story.append(row3)
    story.append(Spacer(1, 6))

    # ════════════════════════════════════════════════════════════════════════
    # PHARMACOKINETICS  (BLUE-light)
    # ════════════════════════════════════════════════════════════════════════
    s7 = make_section(
        "⏱️", "PHARMACOKINETICS AT A GLANCE",
        [
            (lbl2("GTN SL:", BLUE_HDR),       val("Onset: 1–3 min | Duration: 20–30 min | Route: Sublingual/Spray/Patch/IV/Topical")),
            (lbl2("ISDN oral:", BLUE_HDR),     val("Onset: 30–60 min | Duration: 4–6 h | Significant first-pass metabolism")),
            (lbl2("ISMN oral:", BLUE_HDR),     val("Onset: 30–60 min | Duration: 6–8 h | NO first-pass loss → bioavailability ~100%")),
            (lbl2("GTN patch:", BLUE_HDR),     val("Onset: 30–60 min | Duration: 12–16 h (worn 12 h then removed)")),
            (lbl2("Metabolism:", BLUE_HDR),    val("Liver (hepatic conjugation + ALDH-2) → inactive glucuronide metabolites")),
            (lbl2("Half-life:", BLUE_HDR),     val("GTN: 1–3 min | ISDN: 45 min | ISMN: 4–5 h")),
        ],
        BLUE_BG, BLUE_HDR
    )
    story.append(s7)
    story.append(Spacer(1, 6))

    # ════════════════════════════════════════════════════════════════════════
    # IMPORTANT EXAM NOTES  (PURPLE-light)
    # ════════════════════════════════════════════════════════════════════════
    s8 = make_section(
        "📝", "IMPORTANT EXAM NOTES",
        [
            (lbl2("★ Note 1:", PURPLE_HDR), val("GTN is NOT a true 'nitro' compound — it is an ESTER of glycerol and nitric acid, but officially called nitroglycerin (erroneously)")),
            (lbl2("★ Note 2:", PURPLE_HDR), val("Main antianginal benefit = ↓ PRELOAD (not primarily coronary dilation) — proven by direct intracoronary injection studies")),
            (lbl2("★ Note 3:", PURPLE_HDR), val("PDE-5 inhibitors (sildenafil, tadalafil, vardenafil) + Nitrates = ABSOLUTELY CONTRAINDICATED → both ↑ cGMP → severe, fatal hypotension")),
            (lbl2("★ Note 4:", PURPLE_HDR), val("Headache due to GTN is a therapeutic end-point in older texts (proves absorption) but is a side effect to manage clinically")),
            (lbl2("★ Note 5:", PURPLE_HDR), val("Alfred Nobel himself (inventor of dynamite/nitroglycerin) was prescribed GTN for his angina in 1890 — he found this ironic")),
            (lbl2("★ Note 6:", PURPLE_HDR), val("1998 Nobel Prize in Medicine awarded for discovery of NO as signalling molecule (Furchgott, Ignarro, Murad)")),
        ],
        PURPLE_BG, PURPLE_HDR
    )
    story.append(s8)
    story.append(Spacer(1, 6))

    # ════════════════════════════════════════════════════════════════════════
    # EASY MEMORY TRICK  (YELLOW bold)
    # ════════════════════════════════════════════════════════════════════════
    trick_data = [[
        Paragraph('🧠 <b>EASY MEMORY TRICK</b>',
                  ps("th", fontSize=10, fontName="Helvetica-Bold", textColor=white, alignment=TA_CENTER)),
    ]]
    trick_hdr = Table(trick_data, colWidths=[content_width])
    trick_hdr.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,-1), YELLOW_HDR),
        ("ROUNDEDCORNERS",[6]),
        ("TOPPADDING",   (0,0),(-1,-1), 6),
        ("BOTTOMPADDING",(0,0),(-1,-1), 6),
    ]))
    story.append(trick_hdr)

    tricks = [
        ('💡 "VEIN GO" mnemonic:', '"V-E-I-N-G-O" — Venodilation, Endogenous NO, Ischaemia relief, Nitroglycerin first, Guanylate cyclase, Overnight patch-free'),
        ('💡 Headache = GTN:', '"Nitrates NAIL the HEAD" — N=Nitroglycerin, A=Acts fast, I=Ischaemia, L=Lowers preload, HEAD = headache side effect'),
        ('💡 Contraindication:', '"NO + VIGRA = DANGER" — Nitrates + Viagra (PDE5i) = NO cGMP overflow = fatal drop in BP'),
        ('💡 Tolerance trick:', '"Night Off for Nitrates" — remove patch at night to prevent tolerance'),
        ('💡 Bioavailability:', '"I-S-M-N = I Shall Make No excuses" — Isosorbide Mononitrate has NO first-pass metabolism'),
    ]
    trick_body_data = [[
        Paragraph(f'<b>{t[0]}</b>', ps("tk", fontSize=8.5, fontName="Helvetica-Bold",
                  textColor=YELLOW_HDR, leading=12)),
        Paragraph(t[1], ps("tv", fontSize=8.5, fontName="Helvetica",
                  textColor=HexColor("#333333"), leading=12))
    ] for t in tricks]

    trick_body = Table(trick_body_data, colWidths=[content_width*0.28, content_width*0.72])
    trick_body.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,-1), YELLOW_BG),
        ("BOX",          (0,0),(-1,-1), 1.2, YELLOW_HDR),
        ("GRID",         (0,0),(-1,-1), 0.3, HexColor("#FFE082")),
        ("TOPPADDING",   (0,0),(-1,-1), 5),
        ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",  (0,0),(-1,-1), 7),
        ("RIGHTPADDING", (0,0),(-1,-1), 7),
        ("VALIGN",       (0,0),(-1,-1), "TOP"),
    ]))
    story.append(trick_body)
    story.append(Spacer(1, 6))

    # ════════════════════════════════════════════════════════════════════════
    # QUICK RECALL BOX (GREEN)
    # ════════════════════════════════════════════════════════════════════════
    qr_data = [[
        Paragraph('⚡ <b>QUICK RECALL BOX — One Line Per Key Point</b>',
                  ps("qh", fontSize=10, fontName="Helvetica-Bold", textColor=white, alignment=TA_CENTER)),
    ]]
    qr_hdr = Table(qr_data, colWidths=[content_width])
    qr_hdr.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,-1), GREEN_HDR),
        ("ROUNDEDCORNERS",[6]),
        ("TOPPADDING",   (0,0),(-1,-1), 7),
        ("BOTTOMPADDING",(0,0),(-1,-1), 7),
    ]))
    story.append(qr_hdr)

    recalls = [
        ("MOA",          "NO → ↑ cGMP → ↓ Ca²⁺ → Vascular smooth muscle relaxation → Vasodilation"),
        ("Best route",   "Sublingual GTN for ACUTE attack (onset 1–3 min, bypasses first-pass)"),
        ("Main use",     "Stable angina, Unstable angina, Variant angina, Acute HF, HTN emergency"),
        ("Key SE",       "Headache (most common), Hypotension, Reflex tachycardia, Tolerance"),
        ("Tolerance",    "Prevent by 10–12 h nitrate-free interval (remove patch overnight)"),
        ("Big contraind","PDE-5 inhibitors (sildenafil) — causes FATAL hypotension"),
        ("ISMN benefit", "100% oral bioavailability — no first-pass effect"),
        ("ISDN",         "Prodrug → active metabolites (IS-2-MN, IS-5-MN); dose twice daily"),
        ("Preload ↓",    "Major antianginal mechanism (not coronary dilation as primary effect)"),
        ("HF use",       "Nitrates + Hydralazine = A-HeFT regimen (alternative to ACEi in Black patients with HFrEF)"),
    ]
    recall_rows = [[
        Paragraph(f'<b><font color="{GREEN_HDR.hexval()}">{r[0]}</font></b>',
                  ps("rlbl", fontSize=8.5, fontName="Helvetica-Bold",
                     textColor=GREEN_HDR, leading=12)),
        Paragraph(f"→ {r[1]}",
                  ps("rval", fontSize=8.5, fontName="Helvetica",
                     textColor=HexColor("#1B5E20"), leading=12))
    ] for r in recalls]

    recall_tbl = Table(recall_rows, colWidths=[content_width*0.18, content_width*0.82])
    recall_tbl.setStyle(TableStyle([
        ("BACKGROUND",   (0,0),(-1,-1), GREEN_BG),
        ("BOX",          (0,0),(-1,-1), 1.2, GREEN_HDR),
        ("GRID",         (0,0),(-1,-1), 0.3, HexColor("#A5D6A7")),
        ("TOPPADDING",   (0,0),(-1,-1), 5),
        ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",  (0,0),(-1,-1), 7),
        ("RIGHTPADDING", (0,0),(-1,-1), 7),
        ("VALIGN",       (0,0),(-1,-1), "MIDDLE"),
    ]))
    story.append(recall_tbl)
    story.append(Spacer(1, 6))

    # ════════════════════════════════════════════════════════════════════════
    # FOOTER
    # ════════════════════════════════════════════════════════════════════════
    footer_data = [[
        Paragraph(
            '📚 Sources: Goodman &amp; Gilman\'s Pharmacology 14e | Katzung Basic &amp; Clinical Pharmacology 16e | Lippincott Pharmacology 8e',
            ps("ft", fontSize=7.5, fontName="Helvetica-Oblique",
               textColor=HexColor("#666666"), alignment=TA_CENTER)
        ),
        Paragraph(
            '🎓 For MBBS · BDS · Pharm-D · Nursing · NEET · USMLE',
            ps("ft2", fontSize=7.5, fontName="Helvetica-Bold",
               textColor=HexColor("#1A237E"), alignment=TA_CENTER)
        )
    ]]
    footer_tbl = Table(footer_data, colWidths=[content_width*0.65, content_width*0.35])
    footer_tbl.setStyle(TableStyle([
        ("TOPPADDING",   (0,0),(-1,-1), 4),
        ("BOTTOMPADDING",(0,0),(-1,-1), 4),
        ("LINEABOVE",    (0,0),(-1,0), 0.5, HexColor("#AAAAAA")),
    ]))
    story.append(footer_tbl)

    doc.build(story)
    print(f"PDF saved to {path}")


if __name__ == "__main__":
    out = "/tmp/workspace/nitrates-infographic/Nitrates_GTN_Infographic.pdf"
    build_pdf(out)
Running Command

cd /tmp/workspace/nitrates-infographic && python nitrates.py 2>&1

Generating Image

A clean, printable A4 medical study note infographic titled "NITRATES / GLYCERYL TRINITRATE (GTN)" in bold white text on a dark navy blue header bar. Below the title a yellow mnemonic box labeled "TRICK TO REMEMBER: VEIN-GO" with the letters expanded. The infographic has 8 colorful pastel sections with rounded corners: 1. RED section "DRUG CLASS & EXAMPLES" with icons, listing GTN, ISDN, ISMN, amyl nitrite, PETN 2. BLUE section "MECHANISM OF ACTION" with arrows showing: GTN → NO → ↑cGMP → ↓MLC phosphorylation → VSM relaxation 3. GREEN section "MAIN EFFECTS" and TEAL section "HAEMODYNAMIC CHANGES" side by side 4. PURPLE section "CLINICAL USES" with tick marks: angina, heart failure, hypertensive emergency, esophageal spasm 5. ORANGE section "SIDE EFFECTS" and RED section "CONTRAINDICATIONS" (PDE5 inhibitors = DANGER) side by side 6. YELLOW section "SPECIAL BENEFITS & NOTES" 7. PINK section "TOLERANCE & PREVENTION" (12h patch-free interval) 8. GREEN "QUICK RECALL BOX" at bottom summarizing each point in one line Uses icons: heart, blood vessel, brain, lungs, tablet, injection, stethoscope, receptor. White background. Handwritten study-notes appearance. Bold headings, arrows (↓↑), tick marks (✔). Suitable for MBBS/NEET/Pharm-D students. A4 printable revision sheet style.

Here is your complete medical infographic for Nitrates / Glyceryl Trinitrate (GTN):

Nitrates / GTN Medical Infographic

📄 Downloadable Printable A4 PDF Version

Nitrates GTN Infographic

PDF Document · PDF


What's Included in the Infographic

Title + Mnemonic:
  • 🧠 "VEIN-GO" - Veno-dilation, Endogenous NO donor, Ischaemia relief, Nitroglycerin first, Guanylate cyclase ↑, Overnight patch-free interval
8 Colorful Sections:
ColorSection
🔴 RedDrug Class & Examples (GTN, ISDN, ISMN, PETN, Amyl Nitrite)
🔵 BlueMechanism of Action (NO → ↑cGMP → ↓Ca²⁺ → VSM Relaxation)
🟢 GreenMain Effects + Haemodynamic Changes
🟣 PurpleClinical Uses (8 indications with ✔ marks)
🟠 Orange + RedSide Effects & Contraindications
🟡 YellowSpecial Benefits & Exam Notes
🩷 PinkTolerance & How to Prevent (12 h nitrate-free interval)
💚 GreenQuick Recall Box (10 one-liners)
Key Memory Tricks included:
  • 💡 "NO + VIGRA = DANGER" (Nitrates + PDE5i = fatal BP drop)
  • 💡 "Night Off for Nitrates" (tolerance prevention)
  • 💡 "I-S-M-N = No first-pass excuse" (100% bioavailability)
Sources: Goodman & Gilman 14e | Katzung 16e | Lippincott Pharmacology 8e
This is a shared conversation. Sign in to Orris to start your own chat.