Can you make pdf in different colours with highlights
mkdir -p /home/daytona/workspace/colorful-study-notes && ls /home/daytona/workspโฆ
~/colorful-study-notes/create_notes.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm, cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, KeepTogether
)
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.pdfgen import canvas
OUTPUT = "/home/daytona/workspace/colorful-study-notes/Science_Study_Notes.pdf"
# โโ Custom colours โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
BLUE_DARK = colors.HexColor("#1a237e")
BLUE_MED = colors.HexColor("#1565c0")
BLUE_LIGHT = colors.HexColor("#e3f2fd")
GREEN_DARK = colors.HexColor("#1b5e20")
GREEN_LIGHT = colors.HexColor("#e8f5e9")
PURPLE_DARK = colors.HexColor("#4a148c")
PURPLE_LIGHT= colors.HexColor("#f3e5f5")
ORANGE_DARK = colors.HexColor("#e65100")
ORANGE_LIGHT= colors.HexColor("#fff3e0")
RED_DARK = colors.HexColor("#b71c1c")
RED_LIGHT = colors.HexColor("#ffebee")
YELLOW_HL = colors.HexColor("#fff176") # classic yellow highlight
CYAN_HL = colors.HexColor("#b2ebf2") # cyan highlight
PINK_HL = colors.HexColor("#f8bbd0") # pink highlight
GREY_LIGHT = colors.HexColor("#f5f5f5")
GREY_MED = colors.HexColor("#e0e0e0")
TEXT_DARK = colors.HexColor("#212121")
# โโ Paragraph styles โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def make_styles():
styles = getSampleStyleSheet()
styles.add(ParagraphStyle(
"DocTitle",
fontName="Helvetica-Bold",
fontSize=26,
textColor=colors.white,
alignment=TA_CENTER,
spaceAfter=4,
))
styles.add(ParagraphStyle(
"DocSubtitle",
fontName="Helvetica",
fontSize=13,
textColor=colors.HexColor("#bbdefb"),
alignment=TA_CENTER,
spaceAfter=10,
))
styles.add(ParagraphStyle(
"SectionHeading",
fontName="Helvetica-Bold",
fontSize=15,
textColor=colors.white,
spaceBefore=14,
spaceAfter=6,
leftIndent=0,
))
styles.add(ParagraphStyle(
"SubHeading",
fontName="Helvetica-Bold",
fontSize=12,
textColor=BLUE_MED,
spaceBefore=10,
spaceAfter=4,
))
styles.add(ParagraphStyle(
"BodyNote",
fontName="Helvetica",
fontSize=10.5,
textColor=TEXT_DARK,
spaceBefore=3,
spaceAfter=3,
leading=15,
alignment=TA_JUSTIFY,
))
styles.add(ParagraphStyle(
"BulletNote",
fontName="Helvetica",
fontSize=10.5,
textColor=TEXT_DARK,
spaceBefore=2,
spaceAfter=2,
leftIndent=14,
leading=14,
bulletIndent=4,
))
styles.add(ParagraphStyle(
"HighlightYellow",
fontName="Helvetica-Bold",
fontSize=10.5,
backColor=YELLOW_HL,
textColor=TEXT_DARK,
spaceBefore=3,
spaceAfter=3,
leading=15,
leftIndent=6,
rightIndent=6,
borderPadding=(4, 6, 4, 6),
))
styles.add(ParagraphStyle(
"HighlightCyan",
fontName="Helvetica",
fontSize=10.5,
backColor=CYAN_HL,
textColor=colors.HexColor("#006064"),
spaceBefore=3,
spaceAfter=3,
leading=15,
leftIndent=6,
rightIndent=6,
borderPadding=(4, 6, 4, 6),
))
styles.add(ParagraphStyle(
"HighlightPink",
fontName="Helvetica",
fontSize=10.5,
backColor=PINK_HL,
textColor=RED_DARK,
spaceBefore=3,
spaceAfter=3,
leading=15,
leftIndent=6,
rightIndent=6,
borderPadding=(4, 6, 4, 6),
))
styles.add(ParagraphStyle(
"Definition",
fontName="Helvetica-Oblique",
fontSize=10,
textColor=PURPLE_DARK,
backColor=PURPLE_LIGHT,
spaceBefore=4,
spaceAfter=4,
leading=14,
leftIndent=10,
rightIndent=10,
borderPadding=(5, 8, 5, 8),
))
styles.add(ParagraphStyle(
"KeyFact",
fontName="Helvetica-Bold",
fontSize=10.5,
textColor=GREEN_DARK,
backColor=GREEN_LIGHT,
spaceBefore=4,
spaceAfter=4,
leading=14,
leftIndent=10,
rightIndent=10,
borderPadding=(5, 8, 5, 8),
))
styles.add(ParagraphStyle(
"Warning",
fontName="Helvetica-Bold",
fontSize=10.5,
textColor=ORANGE_DARK,
backColor=ORANGE_LIGHT,
spaceBefore=4,
spaceAfter=4,
leading=14,
leftIndent=10,
rightIndent=10,
borderPadding=(5, 8, 5, 8),
))
return styles
# โโ Coloured section header block โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def section_block(title_text, bg_color, styles):
"""Returns a table that acts as a coloured heading band."""
p = Paragraph(title_text, styles["SectionHeading"])
t = Table([[p]], colWidths=[170*mm])
t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), bg_color),
("TOPPADDING", (0, 0), (-1, -1), 6),
("BOTTOMPADDING", (0, 0), (-1, -1), 6),
("LEFTPADDING", (0, 0), (-1, -1), 10),
("RIGHTPADDING", (0, 0), (-1, -1), 10),
("ROUNDEDCORNERS", [4, 4, 4, 4]),
]))
return t
# โโ Cover banner โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def cover_banner(styles):
p_title = Paragraph("Science Study Notes", styles["DocTitle"])
p_subtitle = Paragraph("Physics โข Chemistry โข Biology", styles["DocSubtitle"])
t = Table([[p_title], [p_subtitle]], colWidths=[170*mm])
t.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, -1), BLUE_DARK),
("TOPPADDING", (0, 0), (-1, -1), 14),
("BOTTOMPADDING", (0, 0), (-1, -1), 14),
("LEFTPADDING", (0, 0), (-1, -1), 12),
("RIGHTPADDING", (0, 0), (-1, -1), 12),
]))
return t
# โโ Key-term table โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def key_terms_table(rows, header_color, row_colors, styles):
"""rows = list of (term, definition) tuples."""
data = [["Term", "Definition"]]
data += [[r[0], r[1]] for r in rows]
col_w = [55*mm, 115*mm]
t = Table(data, colWidths=col_w, repeatRows=1)
ts = [
("BACKGROUND", (0, 0), (-1, 0), header_color),
("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, 0), 11),
("ALIGN", (0, 0), (-1, 0), "CENTER"),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("FONTNAME", (0, 1), (0, -1), "Helvetica-Bold"),
("FONTSIZE", (0, 1), (-1, -1), 10),
("GRID", (0, 0), (-1, -1), 0.5, GREY_MED),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 8),
("RIGHTPADDING", (0, 0), (-1, -1), 8),
]
for i, rc in enumerate(row_colors):
ts.append(("BACKGROUND", (0, i + 1), (-1, i + 1), rc))
t.setStyle(TableStyle(ts))
return t
# โโ Page footer โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
class FooterCanvas(canvas.Canvas):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._saved_page_states = []
def showPage(self):
self._saved_page_states.append(dict(self.__dict__))
self._startPage()
def save(self):
num_pages = len(self._saved_page_states)
for state in self._saved_page_states:
self.__dict__.update(state)
self._draw_footer(num_pages)
canvas.Canvas.showPage(self)
canvas.Canvas.save(self)
def _draw_footer(self, page_count):
page = self.__dict__.get("_pageNumber", 1)
self.saveState()
self.setFont("Helvetica", 8)
self.setFillColor(colors.grey)
self.drawCentredString(A4[0] / 2, 18, f"Science Study Notes โ Page {page} of {page_count}")
self.setStrokeColor(GREY_MED)
self.line(20*mm, 22*mm, A4[0] - 20*mm, 22*mm)
self.restoreState()
# โโ Main build โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def build():
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
topMargin=18*mm, bottomMargin=28*mm,
leftMargin=20*mm, rightMargin=20*mm,
title="Science Study Notes",
author="Orris AI",
)
styles = make_styles()
S = styles
story = []
# โโ Cover banner โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
story.append(cover_banner(S))
story.append(Spacer(1, 12))
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 1 โ PHYSICS
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
story.append(section_block("โก Section 1: Physics", BLUE_MED, S))
story.append(Spacer(1, 6))
story.append(Paragraph("1.1 Newton's Laws of Motion", S["SubHeading"]))
story.append(Paragraph(
"Isaac Newton formulated three fundamental laws that describe the relationship "
"between the motion of an object and the forces acting on it.",
S["BodyNote"]))
story.append(Paragraph(
"โ
KEY FACT: Newton's First Law โ An object at rest stays at rest, and an object "
"in motion stays in motion unless acted upon by an external force (Inertia).",
S["KeyFact"]))
story.append(Paragraph(
"โ
KEY FACT: Newton's Second Law โ Force = Mass ร Acceleration (F = ma).",
S["KeyFact"]))
story.append(Paragraph(
"โ
KEY FACT: Newton's Third Law โ For every action there is an equal and opposite reaction.",
S["KeyFact"]))
story.append(Spacer(1, 4))
story.append(Paragraph("1.2 Work, Energy & Power", S["SubHeading"]))
story.append(Paragraph(
"<b>Work</b> done on an object equals the force applied multiplied by the distance "
"moved in the direction of the force. W = F ร d (unit: Joule, J).",
S["BodyNote"]))
story.append(Paragraph(
"โ REMEMBER: Energy cannot be created or destroyed โ only converted from one form "
"to another (Law of Conservation of Energy).",
S["Warning"]))
story.append(Paragraph(
"Power is the rate of doing work: P = W / t (unit: Watt, W).",
S["HighlightYellow"]))
story.append(Spacer(1, 4))
story.append(Paragraph("1.3 Waves & Light", S["SubHeading"]))
story.append(Paragraph(
"Light travels at approximately <b>3 ร 10<super>8</super> m/s</b> in a vacuum. "
"It exhibits both wave-like and particle-like behaviour (wave-particle duality).",
S["BodyNote"]))
story.append(Paragraph(
"The electromagnetic spectrum (low โ high frequency): Radio โ Microwave โ Infrared "
"โ Visible light โ Ultraviolet โ X-ray โ Gamma ray.",
S["HighlightCyan"]))
story.append(Spacer(1, 6))
story.append(Paragraph("Physics Key Terms", S["SubHeading"]))
physics_terms = [
("Velocity", "Speed in a given direction (vector quantity)."),
("Acceleration","Rate of change of velocity (m/sยฒ)."),
("Momentum", "Mass ร Velocity (p = mv). Conserved in collisions."),
("Frequency", "Number of wave cycles per second (unit: Hertz, Hz)."),
("Amplitude", "Maximum displacement of a wave from its rest position."),
]
row_colors_phys = [BLUE_LIGHT, GREY_LIGHT, BLUE_LIGHT, GREY_LIGHT, BLUE_LIGHT]
story.append(key_terms_table(physics_terms, BLUE_MED, row_colors_phys, S))
story.append(Spacer(1, 10))
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 2 โ CHEMISTRY
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
story.append(section_block("๐งช Section 2: Chemistry", colors.HexColor("#7b1fa2"), S))
story.append(Spacer(1, 6))
story.append(Paragraph("2.1 Atomic Structure", S["SubHeading"]))
story.append(Paragraph(
"An atom consists of a nucleus containing <b>protons</b> (positive charge) and "
"<b>neutrons</b> (no charge), surrounded by <b>electrons</b> (negative charge) "
"arranged in energy levels (shells).",
S["BodyNote"]))
story.append(Paragraph(
"Definition โ Atomic Number: The number of protons in the nucleus of an atom. "
"It uniquely identifies each element on the Periodic Table.",
S["Definition"]))
story.append(Paragraph(
"Definition โ Isotopes: Atoms of the same element with the same number of protons "
"but a different number of neutrons (e.g., Carbon-12 vs Carbon-14).",
S["Definition"]))
story.append(Spacer(1, 4))
story.append(Paragraph("2.2 Chemical Bonding", S["SubHeading"]))
bond_data = [
["Bond Type", "Between", "Example"],
["Ionic", "Metal + Non-metal", "NaCl (table salt)"],
["Covalent", "Non-metal + Non-metal","HโO (water)"],
["Metallic", "Metal + Metal", "Copper wire"],
["Hydrogen Bond", "Polar molecules", "DNA base pairs"],
]
bond_col_w = [40*mm, 65*mm, 65*mm]
bt = Table(bond_data, colWidths=bond_col_w, repeatRows=1)
bt.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#7b1fa2")),
("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTNAME", (0, 1), (0, -1), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, -1), 10),
("ALIGN", (0, 0), (-1, 0), "CENTER"),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("GRID", (0, 0), (-1, -1), 0.5, GREY_MED),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 8),
("RIGHTPADDING", (0, 0), (-1, -1), 8),
("BACKGROUND", (0, 1), (-1, 1), PURPLE_LIGHT),
("BACKGROUND", (0, 2), (-1, 2), GREEN_LIGHT),
("BACKGROUND", (0, 3), (-1, 3), ORANGE_LIGHT),
("BACKGROUND", (0, 4), (-1, 4), RED_LIGHT),
]))
story.append(bt)
story.append(Spacer(1, 6))
story.append(Paragraph("2.3 Acids, Bases & pH", S["SubHeading"]))
story.append(Paragraph(
"The pH scale runs from <b>0 (strongly acidic)</b> to <b>14 (strongly basic/alkaline)</b>. "
"pH 7 is neutral (pure water at 25 ยฐC).",
S["BodyNote"]))
story.append(Paragraph(
"๐ HIGHLIGHT: Litmus paper test โ turns RED in acid, BLUE in base.",
S["HighlightPink"]))
story.append(Paragraph(
"โ REMEMBER: Strong acids (HCl, HโSOโ, HNOโ) fully dissociate in water. "
"Weak acids (ethanoic acid, carbonic acid) only partially dissociate.",
S["Warning"]))
story.append(Spacer(1, 10))
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 3 โ BIOLOGY
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
story.append(section_block("๐ฟ Section 3: Biology", GREEN_DARK, S))
story.append(Spacer(1, 6))
story.append(Paragraph("3.1 The Cell", S["SubHeading"]))
story.append(Paragraph(
"The cell is the basic unit of life. There are two main types:",
S["BodyNote"]))
cell_data = [
["Feature", "Prokaryotic Cell", "Eukaryotic Cell"],
["Nucleus", "Absent", "Present (membrane-bound)"],
["Size", "1โ10 ยตm", "10โ100 ยตm"],
["DNA", "Circular, no histones", "Linear, with histones"],
["Examples", "Bacteria, Archaea", "Plants, Animals, Fungi"],
]
cell_col_w = [40*mm, 65*mm, 65*mm]
ct = Table(cell_data, colWidths=cell_col_w, repeatRows=1)
ct.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), GREEN_DARK),
("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTNAME", (0, 1), (0, -1), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, -1), 10),
("ALIGN", (0, 0), (-1, 0), "CENTER"),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("GRID", (0, 0), (-1, -1), 0.5, GREY_MED),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 8),
("RIGHTPADDING", (0, 0), (-1, -1), 8),
("BACKGROUND", (0, 1), (-1, 1), GREEN_LIGHT),
("BACKGROUND", (0, 2), (-1, 2), GREY_LIGHT),
("BACKGROUND", (0, 3), (-1, 3), GREEN_LIGHT),
("BACKGROUND", (0, 4), (-1, 4), GREY_LIGHT),
]))
story.append(ct)
story.append(Spacer(1, 6))
story.append(Paragraph("3.2 Photosynthesis & Respiration", S["SubHeading"]))
story.append(Paragraph(
"๐ฑ PHOTOSYNTHESIS (in chloroplasts):",
S["KeyFact"]))
story.append(Paragraph(
"6COโ + 6HโO + Light energy โ CโHโโOโ + 6Oโ",
S["HighlightYellow"]))
story.append(Spacer(1, 4))
story.append(Paragraph(
"๐ฅ AEROBIC RESPIRATION (in mitochondria):",
S["Warning"]))
story.append(Paragraph(
"CโHโโOโ + 6Oโ โ 6COโ + 6HโO + ATP (energy)",
S["HighlightCyan"]))
story.append(Spacer(1, 6))
story.append(Paragraph("3.3 Genetics", S["SubHeading"]))
story.append(Paragraph(
"<b>DNA</b> (deoxyribonucleic acid) carries the genetic information of living organisms. "
"It is a double helix made of nucleotide base pairs: <b>A-T</b> and <b>G-C</b>.",
S["BodyNote"]))
story.append(Paragraph(
"Definition โ Gene: A segment of DNA that codes for a specific protein or trait. "
"Humans have approximately 20,000โ25,000 genes.",
S["Definition"]))
story.append(Paragraph(
"โ REMEMBER: Mitosis produces 2 identical daughter cells (for growth/repair). "
"Meiosis produces 4 genetically unique cells (for sexual reproduction).",
S["Warning"]))
story.append(Paragraph(
"๐ HIGHLIGHT: Dominant alleles mask recessive alleles. "
"A recessive trait only shows when the organism is homozygous recessive (aa).",
S["HighlightPink"]))
story.append(Spacer(1, 10))
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# QUICK REFERENCE BOX
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
story.append(HRFlowable(width="100%", thickness=1.5, color=BLUE_MED, spaceAfter=8))
story.append(Paragraph("Quick Reference: Important Equations", S["SubHeading"]))
eq_data = [
["Subject", "Formula", "Description"],
["Physics", "F = ma", "Newton's Second Law"],
["Physics", "KE = ยฝmvยฒ", "Kinetic Energy"],
["Physics", "v = fฮป", "Wave speed"],
["Chemistry", "n = m / Mr", "Moles = mass / molar mass"],
["Chemistry", "pH = โlog[Hโบ]", "pH definition"],
["Biology", "Energy = Power ร Time", "Energy equation"],
["Biology", "Magnification = image/object","Microscopy"],
]
eq_col_w = [28*mm, 60*mm, 82*mm]
eq_t = Table(eq_data, colWidths=eq_col_w, repeatRows=1)
eq_row_bg = [BLUE_LIGHT, BLUE_LIGHT, BLUE_LIGHT, PURPLE_LIGHT, PURPLE_LIGHT, GREEN_LIGHT, GREEN_LIGHT]
ts = [
("BACKGROUND", (0, 0), (-1, 0), BLUE_DARK),
("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
("FONTNAME", (0, 1), (1, -1), "Helvetica-Bold"),
("FONTSIZE", (0, 0), (-1, -1), 10),
("ALIGN", (0, 0), (-1, 0), "CENTER"),
("ALIGN", (1, 1), (1, -1), "CENTER"),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("GRID", (0, 0), (-1, -1), 0.5, GREY_MED),
("TOPPADDING", (0, 0), (-1, -1), 5),
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
("LEFTPADDING", (0, 0), (-1, -1), 8),
("RIGHTPADDING", (0, 0), (-1, -1), 8),
]
for i, rc in enumerate(eq_row_bg):
ts.append(("BACKGROUND", (0, i + 1), (-1, i + 1), rc))
eq_t.setStyle(TableStyle(ts))
story.append(eq_t)
story.append(Spacer(1, 8))
# โโ Build โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
doc.build(story, canvasmaker=FooterCanvas)
print(f"PDF saved to: {OUTPUT}")
build()
cd /home/daytona/workspace/colorful-study-notes && python create_notes.py 2>&1
~/colorful-study-notes/create_notes.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/colorful-study-notes/create_notes.py'
cd /home/daytona/workspace/colorful-study-notes && sed -i 's/S\["Definition"\]/Sโฆ
python3 -c " content = open('/home/daytona/workspace/colorful-study-notes/createโฆ
Science Study Notes
PDF Document ยท PDF
| Section | Colour theme |
|---|---|
| Physics | Blue |
| Chemistry | Purple |
| Biology | Green |
Now create on ALTS advanced life trauma support
ATLS 10th edition advanced trauma life support primary survey ABCDE guidelines 2024
~/colorful-study-notes/create_atls.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak
)
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_JUSTIFY
from reportlab.pdfgen import canvas as canvasmod
OUTPUT = "/home/daytona/workspace/colorful-study-notes/ATLS_Study_Notes.pdf"
# โโ Colour palette โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
RED_DARK = colors.HexColor("#b71c1c")
RED_MED = colors.HexColor("#c62828")
RED_LIGHT = colors.HexColor("#ffebee")
ORANGE_DARK = colors.HexColor("#e65100")
ORANGE_LIGHT = colors.HexColor("#fff3e0")
AMBER_DARK = colors.HexColor("#ff6f00")
AMBER_LIGHT = colors.HexColor("#fff8e1")
BLUE_DARK = colors.HexColor("#0d47a1")
BLUE_MED = colors.HexColor("#1565c0")
BLUE_LIGHT = colors.HexColor("#e3f2fd")
TEAL_DARK = colors.HexColor("#004d40")
TEAL_MED = colors.HexColor("#00695c")
TEAL_LIGHT = colors.HexColor("#e0f2f1")
GREEN_DARK = colors.HexColor("#1b5e20")
GREEN_MED = colors.HexColor("#2e7d32")
GREEN_LIGHT = colors.HexColor("#e8f5e9")
PURPLE_DARK = colors.HexColor("#4a148c")
PURPLE_MED = colors.HexColor("#6a1b9a")
PURPLE_LIGHT = colors.HexColor("#f3e5f5")
GREY_DARK = colors.HexColor("#37474f")
GREY_LIGHT = colors.HexColor("#f5f5f5")
GREY_MED = colors.HexColor("#e0e0e0")
YELLOW_HL = colors.HexColor("#fff176")
CYAN_HL = colors.HexColor("#b2ebf2")
PINK_HL = colors.HexColor("#f8bbd0")
TEXT_DARK = colors.HexColor("#212121")
WHITE = colors.white
# โโ Styles โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def make_styles():
base = getSampleStyleSheet()
def add(name, **kw):
if name not in base:
base.add(ParagraphStyle(name, **kw))
add("DocTitle", fontName="Helvetica-Bold", fontSize=28, textColor=WHITE,
alignment=TA_CENTER, spaceAfter=2)
add("DocSubtitle", fontName="Helvetica", fontSize=13, textColor=colors.HexColor("#ffcdd2"),
alignment=TA_CENTER, spaceAfter=6)
add("DocEdition", fontName="Helvetica-Oblique",fontSize=10, textColor=colors.HexColor("#ffcdd2"),
alignment=TA_CENTER, spaceAfter=10)
add("SecHead", fontName="Helvetica-Bold", fontSize=14, textColor=WHITE,
spaceBefore=8, spaceAfter=4)
add("SubHead", fontName="Helvetica-Bold", fontSize=12, textColor=BLUE_MED,
spaceBefore=10, spaceAfter=4)
add("BodyTxt", fontName="Helvetica", fontSize=10.5, textColor=TEXT_DARK,
spaceBefore=3, spaceAfter=3, leading=15, alignment=TA_JUSTIFY)
add("BulletTxt", fontName="Helvetica", fontSize=10.5, textColor=TEXT_DARK,
spaceBefore=2, spaceAfter=2, leftIndent=14, leading=14)
add("HLYellow", fontName="Helvetica-Bold", fontSize=10.5, backColor=YELLOW_HL,
textColor=TEXT_DARK, spaceBefore=3, spaceAfter=3, leading=15,
leftIndent=6, rightIndent=6, borderPadding=(4, 6, 4, 6))
add("HLCyan", fontName="Helvetica", fontSize=10.5, backColor=CYAN_HL,
textColor=TEAL_DARK, spaceBefore=3, spaceAfter=3, leading=15,
leftIndent=6, rightIndent=6, borderPadding=(4, 6, 4, 6))
add("HLPink", fontName="Helvetica", fontSize=10.5, backColor=PINK_HL,
textColor=RED_DARK, spaceBefore=3, spaceAfter=3, leading=15,
leftIndent=6, rightIndent=6, borderPadding=(4, 6, 4, 6))
add("BoxGreen", fontName="Helvetica-Bold", fontSize=10.5, backColor=GREEN_LIGHT,
textColor=GREEN_DARK, spaceBefore=4, spaceAfter=4, leading=14,
leftIndent=10, rightIndent=10, borderPadding=(5, 8, 5, 8))
add("BoxOrange", fontName="Helvetica-Bold", fontSize=10.5, backColor=ORANGE_LIGHT,
textColor=ORANGE_DARK, spaceBefore=4, spaceAfter=4, leading=14,
leftIndent=10, rightIndent=10, borderPadding=(5, 8, 5, 8))
add("BoxRed", fontName="Helvetica-Bold", fontSize=10.5, backColor=RED_LIGHT,
textColor=RED_DARK, spaceBefore=4, spaceAfter=4, leading=14,
leftIndent=10, rightIndent=10, borderPadding=(5, 8, 5, 8))
add("BoxPurple", fontName="Helvetica-Oblique",fontSize=10, backColor=PURPLE_LIGHT,
textColor=PURPLE_DARK, spaceBefore=4, spaceAfter=4, leading=14,
leftIndent=10, rightIndent=10, borderPadding=(5, 8, 5, 8))
add("BoxBlue", fontName="Helvetica", fontSize=10.5, backColor=BLUE_LIGHT,
textColor=BLUE_DARK, spaceBefore=4, spaceAfter=4, leading=14,
leftIndent=10, rightIndent=10, borderPadding=(5, 8, 5, 8))
return base
# โโ Helper: coloured section header โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def sec_hdr(title, bg, styles):
p = Paragraph(title, styles["SecHead"])
t = Table([[p]], colWidths=[170*mm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING", (0,0),(-1,-1), 7),
("LEFTPADDING", (0,0),(-1,-1), 12),
("RIGHTPADDING", (0,0),(-1,-1), 12),
]))
return t
# โโ Cover banner โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def cover(styles):
rows = [
[Paragraph("ATLSยฎ Study Notes", styles["DocTitle"])],
[Paragraph("Advanced Trauma Life Support", styles["DocSubtitle"])],
[Paragraph("11th Edition (2025) โ American College of Surgeons", styles["DocEdition"])],
]
t = Table(rows, colWidths=[170*mm])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), RED_DARK),
("TOPPADDING", (0,0),(-1,-1), 12),
("BOTTOMPADDING", (0,0),(-1,-1), 12),
("LEFTPADDING", (0,0),(-1,-1), 14),
("RIGHTPADDING", (0,0),(-1,-1), 14),
]))
return t
# โโ Generic 3-col table โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def make_table(data, col_widths, header_bg, row_bgs=None, font_size=10):
t = Table(data, colWidths=col_widths, repeatRows=1)
ts = [
("BACKGROUND", (0,0),(-1, 0), header_bg),
("TEXTCOLOR", (0,0),(-1, 0), WHITE),
("FONTNAME", (0,0),(-1, 0), "Helvetica-Bold"),
("FONTSIZE", (0,0),(-1,-1), font_size),
("ALIGN", (0,0),(-1, 0), "CENTER"),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("GRID", (0,0),(-1,-1), 0.4, GREY_MED),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 7),
("RIGHTPADDING", (0,0),(-1,-1), 7),
("FONTNAME", (0,1),(0,-1), "Helvetica-Bold"),
]
if row_bgs:
for i, bg in enumerate(row_bgs):
ts.append(("BACKGROUND", (0,i+1),(-1,i+1), bg))
t.setStyle(TableStyle(ts))
return t
# โโ Footer canvas โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
class FooterCanvas(canvasmod.Canvas):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._saved_page_states = []
def showPage(self):
self._saved_page_states.append(dict(self.__dict__))
self._startPage()
def save(self):
n = len(self._saved_page_states)
for state in self._saved_page_states:
self.__dict__.update(state)
self._draw_footer(n)
canvasmod.Canvas.showPage(self)
canvasmod.Canvas.save(self)
def _draw_footer(self, total):
pg = self.__dict__.get("_pageNumber", 1)
self.saveState()
self.setFont("Helvetica", 8)
self.setFillColor(colors.grey)
self.drawCentredString(A4[0]/2, 16, f"ATLSยฎ Study Notes | Page {pg} of {total} | American College of Surgeons 11th Ed. (2025)")
self.setStrokeColor(RED_DARK)
self.setLineWidth(0.8)
self.line(20*mm, 21*mm, A4[0]-20*mm, 21*mm)
self.restoreState()
# โโ BUILD โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def build():
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
topMargin=15*mm, bottomMargin=28*mm,
leftMargin=20*mm, rightMargin=20*mm,
title="ATLS Study Notes", author="Orris AI"
)
S = make_styles()
story = []
# โโ COVER โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
story.append(cover(S))
story.append(Spacer(1, 8))
# โโ INTRO BOX โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
story.append(Paragraph(
"ATLSยฎ is the standardised training program of the American College of Surgeons for "
"managing acute trauma. Its core principle: <b>treat the greatest threat to life first</b>. "
"The 11th edition (2025) introduced the landmark shift from ABCDE to <b>X-ABCDE</b>, "
"prioritising catastrophic external haemorrhage control before airway management.",
S["BoxBlue"]))
story.append(Spacer(1, 6))
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 1 โ X-ABCDE PRIMARY SURVEY
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
story.append(sec_hdr("๐จ Section 1: The Primary Survey โ X-ABCDE", RED_MED, S))
story.append(Spacer(1, 5))
story.append(Paragraph(
"The primary survey rapidly identifies and treats <b>immediately life-threatening</b> "
"conditions. Every step is performed simultaneously with resuscitation.",
S["BodyTxt"]))
story.append(Paragraph(
"๐ NEW (11th Ed.): X-ABCDE replaces ABCDE. 'X' = eXsanguinating haemorrhage "
"control is now the FIRST priority before airway, because catastrophic external "
"bleeding is the leading correctable cause of preventable trauma death.",
S["BoxRed"]))
story.append(Spacer(1, 4))
xabcde = [
["Step", "Stands For", "Action"],
["X", "eXsanguinating\nHaemorrhage",
"Apply direct pressure / tourniquet / wound packing with haemostatic dressing. "
"Control life-threatening external bleeding FIRST."],
["A", "Airway +\nC-spine",
"Jaw thrust / chin lift. OPA/NPA. In-line C-spine immobilisation. "
"RSI/ETT if GCS 3-8 or unable to protect airway."],
["B", "Breathing +\nVentilation",
"Assess for tension pneumothorax, open pneumothorax, flail chest, "
"massive haemothorax. Needle decompression / chest drain / occlusive dressing."],
["C", "Circulation +\nHaemorrhage",
"2 large-bore IVs or IO access. Control internal bleeding. "
"Permissive hypotension (SBP 70-90 mmHg) until definitive haemostasis. "
"MTP if ongoing haemorrhage."],
["D", "Disability\n(Neurology)",
"GCS, pupils (PERRL), blood glucose. GCS < 9 = intubate. "
"Prevent secondary brain injury (avoid hypoxia, hypotension)."],
["E", "Exposure +\nEnvironment",
"Fully undress patient (cut clothes). Log-roll. "
"Prevent hypothermia โ warm blankets, warm IV fluids, warm environment."],
]
row_bgs = [RED_LIGHT, BLUE_LIGHT, TEAL_LIGHT, ORANGE_LIGHT, PURPLE_LIGHT, GREEN_LIGHT]
story.append(make_table(xabcde, [12*mm, 28*mm, 130*mm], RED_MED, row_bgs))
story.append(Spacer(1, 6))
# Life threats identified in primary survey
story.append(Paragraph("Life-Threatening Conditions โ Identified in Primary Survey", S["SubHead"]))
lt_data = [
["Condition", "Step", "Immediate Action"],
["Airway obstruction", "A", "Jaw thrust, suction, OPA/NPA, RSI/ETT"],
["Tension pneumothorax", "B", "Needle decompression (2nd ICS MCL) โ chest drain"],
["Open pneumothorax", "B", "3-sided occlusive dressing โ chest drain"],
["Massive haemothorax", "B/C", "IV/IO access, chest drain, surgery if > 1500 mL"],
["Flail chest", "B", "O2, analgesia, PPV if respiratory failure"],
["Cardiac tamponade", "C", "Pericardiocentesis / emergency thoracotomy"],
["Exsanguinating haemorrhage", "X/C", "Tourniquet, packing, MTP, OR/angio"],
]
lt_bgs = [RED_LIGHT, BLUE_LIGHT, TEAL_LIGHT, TEAL_LIGHT,
ORANGE_LIGHT, RED_LIGHT, RED_LIGHT]
story.append(make_table(lt_data, [55*mm, 14*mm, 101*mm], RED_DARK, lt_bgs))
story.append(Spacer(1, 8))
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 2 โ SHOCK & RESUSCITATION
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
story.append(sec_hdr("๐ฉธ Section 2: Haemorrhagic Shock โ Classification & Resuscitation",
ORANGE_DARK, S))
story.append(Spacer(1, 5))
story.append(Paragraph(
"Haemorrhagic shock is classified into four classes based on estimated blood loss "
"(EBL), vital signs and clinical findings. For a 70 kg adult, total blood volume โ 5 L.",
S["BodyTxt"]))
shock_data = [
["Parameter", "Class I", "Class II", "Class III", "Class IV"],
["Blood loss (mL)","< 750", "750โ1500", "1500โ2000", "> 2000"],
["Blood loss (%)", "< 15%", "15โ30%", "30โ40%", "> 40%"],
["HR (bpm)", "< 100", "100โ120", "120โ140", "> 140"],
["BP", "Normal", "Normal", "Decreased", "Very low"],
["RR (breaths/min)","14โ20", "20โ30", "30โ40", "> 35"],
["Urine output", "> 30 mL/hr", "20โ30 mL/hr", "5โ15 mL/hr", "Negligible"],
["Consciousness", "Anxious", "Agitated", "Confused", "Lethargic/Unconscious"],
["Fluid (initial)","Crystalloid", "Crystalloid", "Blood + cryst.", "Blood + MTP"],
]
shock_bgs = [ORANGE_LIGHT, AMBER_LIGHT, ORANGE_LIGHT, AMBER_LIGHT,
ORANGE_LIGHT, AMBER_LIGHT, ORANGE_LIGHT, AMBER_LIGHT]
story.append(make_table(shock_data, [40*mm, 32*mm, 32*mm, 33*mm, 33*mm],
ORANGE_DARK, shock_bgs, font_size=9.5))
story.append(Spacer(1, 5))
story.append(Paragraph(
"โ REMEMBER: Elderly patients and those on beta-blockers may NOT show tachycardia "
"even with significant blood loss โ do not rely on HR alone!",
S["BoxOrange"]))
story.append(Paragraph(
"๐ HIGHLIGHT: Permissive hypotension โ target SBP 70โ90 mmHg (or palpable radial "
"pulse) in penetrating trauma until definitive haemostasis. Avoid in TBI patients "
"(keep SBP โฅ 110 mmHg to maintain cerebral perfusion).",
S["HLYellow"]))
story.append(Paragraph("Damage Control Resuscitation (DCR)", S["SubHead"]))
story.append(Paragraph(
"DCR combines <b>damage control surgery</b> with targeted resuscitation to break "
"the lethal triad of hypothermia, acidosis and coagulopathy.",
S["BodyTxt"]))
dcr_items = [
("Apply direct pressure / tourniquet / haemostatic dressing to external bleeding sites."),
("Facilitate early transfer to OR or angiography suite for definitive haemorrhage control."),
("Minimise crystalloid infusions. Use controlled resuscitation with permissive hypotension."),
("Massive Transfusion Protocol (MTP): pRBC : FFP : Platelets in 1:1:1 ratio."),
("Tranexamic acid (TXA): 1 g IV over 10 min, then 1 g over 8 hrs โ give within 3 hrs of injury."),
("Correct hypothermia: warm blankets, warm fluids, warm environment."),
("Correct coagulopathy: FFP, cryoprecipitate, calcium supplementation."),
("Prevent and treat acidosis by restoring tissue perfusion."),
]
for item in dcr_items:
story.append(Paragraph(f"โข {item}", S["BulletTxt"]))
story.append(Paragraph(
"๐ MTP RATIO: pRBC : FFP : Platelets = 1:1:1. Strong evidence supports this. "
"Type O-negative blood for females of childbearing age; O-positive acceptable for males.",
S["HLCyan"]))
story.append(Spacer(1, 8))
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 3 โ AIRWAY MANAGEMENT
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
story.append(sec_hdr("๐จ Section 3: Airway Management", BLUE_MED, S))
story.append(Spacer(1, 5))
story.append(Paragraph(
"Airway compromise is rapidly fatal. <b>All trauma patients receive high-flow "
"O2 (15 L/min via NRB mask)</b> until assessment is complete.",
S["BodyTxt"]))
airway_data = [
["Technique", "Indication", "Notes"],
["Chin lift / Jaw thrust", "Unconscious but breathing", "Jaw thrust preferred with C-spine concern"],
["OPA (oral pharyngeal)", "Unconscious, no gag reflex", "Size = corner of mouth to earlobe"],
["NPA (nasal pharyngeal)", "Semi-conscious / active gag", "Avoid in suspected base of skull #"],
["BVM ventilation", "Apnoea / agonal breathing", "2-person technique preferred"],
["RSI + Endotracheal tube", "GCS โค 8, airway protection needed", "Drug-assisted intubation โ ketamine + suxamethonium or rocuronium"],
["Surgical airway (cric)", "Cannot intubate, cannot oxygenate", "Needle cric โ surgical cricothyrotomy"],
["Supraglottic airway (iGel/LMA)", "Failed intubation rescue", "Bridge to definitive airway"],
]
airway_bgs = [BLUE_LIGHT, GREY_LIGHT, BLUE_LIGHT, GREY_LIGHT,
BLUE_LIGHT, RED_LIGHT, GREY_LIGHT]
story.append(make_table(airway_data, [45*mm, 60*mm, 65*mm], BLUE_DARK, airway_bgs))
story.append(Spacer(1, 5))
story.append(Paragraph(
"โ C-SPINE RULE: Maintain in-line immobilisation until spine injury excluded. "
"Use jaw thrust (not chin lift) when C-spine injury suspected.",
S["BoxOrange"]))
story.append(Paragraph(
"๐ HIGHLIGHT: RSI drugs (11th Ed.) โ preference for drug-assisted intubation. "
"Ketamine (1โ2 mg/kg IV) as induction agent is haemodynamically favourable in trauma. "
"Suxamethonium (1.5 mg/kg) or Rocuronium (1.2 mg/kg) as paralytic.",
S["HLPink"]))
story.append(Spacer(1, 8))
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 4 โ SECONDARY SURVEY
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
story.append(sec_hdr("๐ Section 4: Secondary Survey โ Head-to-Toe", TEAL_MED, S))
story.append(Spacer(1, 5))
story.append(Paragraph(
"The secondary survey is a <b>complete head-to-toe examination</b> begun only "
"after the primary survey is complete and resuscitation is initiated. "
"It aims to identify ALL injuries.",
S["BodyTxt"]))
story.append(Paragraph(
"โ
AMPLE History: Allergies | Medications | Past medical history | "
"Last meal | Events leading to injury",
S["BoxGreen"]))
story.append(Spacer(1, 4))
sec_data = [
["Region", "Key Assessments"],
["Head & Scalp", "Lacerations, haematomas, depressed skull fractures, facial fractures"],
["Eyes", "Pupil equality & reactivity, visual acuity, globe injury, periorbital bruising (raccoon eyes)"],
["Ears / Nose", "Haemotympanum, CSF otorrhoea/rhinorrhoea, Battle's sign (mastoid bruising)"],
["Maxillofacial", "Mandible, midface stability, dental injuries, nasal fractures"],
["Neck", "Tracheal deviation, JVD, subcutaneous emphysema, vascular injury, C-spine tenderness"],
["Chest", "Rib tenderness, breath sounds, heart sounds, clavicle/sternum palpation"],
["Abdomen", "Guarding, rigidity, distension, peritonism. FAST scan / CT abdomen"],
["Pelvis", "Single gentle AP compression โ do NOT rock (can worsen bleeding). Pelvic binder if unstable"],
["Perineum/Rectum","Urethral meatus blood, high-riding prostate, rectal tone"],
["Extremities", "Deformity, vascular status (pulses), neurological function, compartment syndrome"],
["Back", "Log-roll: spine tenderness, posterior injuries, rectal exam"],
["Neurological", "Full GCS reassessment, peripheral motor/sensory exam, reflexes"],
]
sec_bgs = [TEAL_LIGHT, GREY_LIGHT]*7
story.append(make_table(sec_data, [35*mm, 135*mm], TEAL_DARK, sec_bgs[:len(sec_data)-1]))
story.append(Spacer(1, 8))
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 5 โ TBI & SPINE
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
story.append(sec_hdr("๐ง Section 5: Traumatic Brain Injury (TBI) & Spine", PURPLE_MED, S))
story.append(Spacer(1, 5))
story.append(Paragraph("<b>Glasgow Coma Scale (GCS)</b>", S["SubHead"]))
gcs_data = [
["Component", "Response", "Score"],
["Eye Opening (E)","Spontaneous", "4"],
["", "To voice", "3"],
["", "To pain", "2"],
["", "None", "1"],
["Verbal (V)", "Oriented", "5"],
["", "Confused", "4"],
["", "Inappropriate words", "3"],
["", "Incomprehensible sounds", "2"],
["", "None", "1"],
["Motor (M)", "Obeys commands", "6"],
["", "Localises pain", "5"],
["", "Withdraws from pain", "4"],
["", "Abnormal flexion (decorticate)","3"],
["", "Extension (decerebrate)", "2"],
["", "None", "1"],
]
gcs_bgs = [PURPLE_LIGHT, GREY_LIGHT]*8
story.append(make_table(gcs_data, [45*mm, 100*mm, 25*mm], PURPLE_DARK,
gcs_bgs[:len(gcs_data)-1], font_size=10))
story.append(Spacer(1, 5))
story.append(Paragraph(
"๐ GCS SCORING: Max = 15 (normal). Min = 3. "
"Mild TBI: GCS 13โ15 | Moderate TBI: GCS 9โ12 | Severe TBI: GCS โค 8 (intubate).",
S["HLYellow"]))
story.append(Paragraph(
"โ SECONDARY BRAIN INJURY PREVENTION: Avoid hypoxia (SpO2 < 90%) and "
"hypotension (SBP < 90 mmHg). These are the two most preventable causes of "
"worsened outcome in TBI. Target SBP โฅ 110 mmHg in TBI.",
S["BoxOrange"]))
story.append(Paragraph(
"Herniation signs (Cushing's triad): bradycardia + hypertension + irregular "
"respirations โ indicates critically raised ICP, requires immediate action "
"(head elevation 30ยฐ, hyperventilate to PaCO2 35-40, mannitol/hypertonic saline, "
"urgent neurosurgery).",
S["BoxPurple"]))
story.append(Spacer(1, 6))
story.append(Paragraph("Spinal Cord Injury", S["SubHead"]))
story.append(Paragraph(
"Maintain in-line immobilisation until radiological clearance. Spinal shock "
"(hypotension + bradycardia) responds to IV fluids ยฑ vasopressors. "
"Neurogenic shock is a diagnosis of exclusion โ haemorrhagic shock must be ruled out first.",
S["BodyTxt"]))
story.append(Paragraph(
"โ IMPORTANT (11th Ed.): Routine corticosteroids for acute spinal cord injury "
"are NO LONGER recommended. Evidence of harm outweighs benefit.",
S["BoxRed"]))
story.append(Spacer(1, 8))
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 6 โ SPECIFIC TRAUMA TYPES
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
story.append(sec_hdr("๐ฆด Section 6: Specific Injury Patterns", GREEN_MED, S))
story.append(Spacer(1, 5))
injuries = [
("Tension Pneumothorax",
"Absent breath sounds + tracheal deviation (AWAY from injury) + haemodynamic collapse. "
"IMMEDIATE needle decompression (2nd ICS mid-clavicular line OR 4th/5th ICS AAL). "
"Do NOT wait for CXR!"),
("Cardiac Tamponade (Beck's Triad)",
"Hypotension + muffled heart sounds + JVD. "
"Mechanism: blunt/penetrating. Echo (FAST) confirms. "
"Rx: pericardiocentesis or emergency thoracotomy."),
("Pelvic Fractures",
"High-energy mechanism. Can lose 3โ4 L blood into retroperitoneum. "
"Apply pelvic binder early. Do NOT rock the pelvis. "
"Angioembolisation or preperitoneal packing for haemorrhage control."),
("Abdominal Trauma โ FAST",
"eFAST (extended FAST): assesses pericardium, hepatorenal, splenorenal spaces, "
"pelvis and pleural cavities. Positive FAST + haemodynamic instability = OR. "
"Stable patient = CT abdomen with contrast."),
("Burns",
"Parkland formula: 4 mL ร weight (kg) ร %TBSA burned. Give half in first 8 hrs "
"(from time of injury), half in next 16 hrs. Use Lactated Ringer's. "
"Ensure urine output 0.5โ1 mL/kg/hr in adults."),
("Paediatric Trauma",
"Weight estimate: (age + 4) ร 2. Preferred fluid: 20 mL/kg warmed crystalloid bolus. "
"Blood pressure less reliable indicator โ HR is more sensitive for shock. "
"Anatomical differences: large head, flexible ribs, protuberant abdomen."),
("Obstetric Trauma",
"Left lateral tilt (15โ30ยฐ) to relieve aortocaval compression from 20 weeks onwards. "
"Kleihauer-Betke test for fetomaternal haemorrhage. Anti-D for Rh-negative mothers. "
"Perimortem C-section if cardiac arrest โฅ 20 weeks gestation."),
("Geriatric Trauma",
"Anticoagulants/beta-blockers mask haemorrhage signs. Lower threshold for CT and ICU admission. "
"Pre-existing conditions complicate resuscitation. Higher morbidity and mortality."),
]
for title, text in injuries:
story.append(Paragraph(f"<b>{title}</b>", S["SubHead"]))
story.append(Paragraph(text, S["BodyTxt"]))
story.append(Spacer(1, 3))
story.append(Spacer(1, 8))
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# SECTION 7 โ QUICK REFERENCE / MNEMONICS
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
story.append(HRFlowable(width="100%", thickness=1.5, color=RED_DARK, spaceAfter=8))
story.append(sec_hdr("๐ Section 7: Quick Reference, Mnemonics & Key Numbers", GREY_DARK, S))
story.append(Spacer(1, 5))
mnem_data = [
["Mnemonic / Rule", "Expanded"],
["X-ABCDE", "eXsanguinating haemorrhage โ Airway โ Breathing โ Circulation โ Disability โ Exposure"],
["AMPLE (history)", "Allergies | Medications | Past history | Last meal | Events of injury"],
["Beck's Triad", "Hypotension | Muffled heart sounds | JVD โ Cardiac tamponade"],
["Cushing's Triad", "Hypertension | Bradycardia | Irregular respirations โ Raised ICP"],
["Lethal Triad", "Hypothermia + Acidosis + Coagulopathy โ mutually worsening, deadly combination"],
["FAST", "Focused Assessment with Sonography in Trauma โ pericardium, liver, spleen, pelvis"],
["eFAST", "Extended FAST adds bilateral lung fields for pneumo/haemothorax"],
["DCR", "Damage Control Resuscitation โ early blood products, permissive hypotension, TXA"],
["MTP ratio", "Massive Transfusion Protocol: pRBC : FFP : Plt = 1:1:1"],
["TXA window", "Tranexamic acid must be given within 3 hours of injury"],
["Parkland (Burns)", "4 mL ร kg ร %TBSA โ half in first 8 hrs, half in next 16 hrs"],
["GCS severe TBI", "GCS โค 8 = intubate to protect airway and prevent secondary injury"],
]
mnem_bgs = [GREY_LIGHT, RED_LIGHT, ORANGE_LIGHT, PURPLE_LIGHT, RED_LIGHT,
TEAL_LIGHT, TEAL_LIGHT, ORANGE_LIGHT, AMBER_LIGHT, AMBER_LIGHT,
GREEN_LIGHT, BLUE_LIGHT]
story.append(make_table(mnem_data, [52*mm, 118*mm], GREY_DARK, mnem_bgs))
story.append(Spacer(1, 6))
# Key numbers
story.append(Paragraph("Critical Numbers at a Glance", S["SubHead"]))
nums_data = [
["Value", "Threshold / Target"],
["SpO2", "โฅ 94% (โฅ 99% in TBI)"],
["SBP โ permissive hypotension", "70โ90 mmHg (penetrating trauma, haemorrhage)"],
["SBP โ TBI", "โฅ 110 mmHg"],
["Urine output (adult)", "โฅ 0.5 mL/kg/hr"],
["Urine output (child)", "1 mL/kg/hr"],
["GCS โ intubation threshold","โค 8"],
["Haemothorax โ surgical", "> 1500 mL initial drain OR > 200 mL/hr ร 2-4 hrs"],
["ICP normal", "< 20 mmHg"],
["CPP target (TBI)", "60โ70 mmHg"],
["TXA โ give within", "3 hours of injury"],
["O-neg blood for", "Females of childbearing age (Rh sensitisation risk)"],
]
nums_bgs = [BLUE_LIGHT, ORANGE_LIGHT, RED_LIGHT, TEAL_LIGHT, TEAL_LIGHT,
PURPLE_LIGHT, RED_LIGHT, ORANGE_LIGHT, BLUE_LIGHT, BLUE_LIGHT,
AMBER_LIGHT]
story.append(make_table(nums_data, [80*mm, 90*mm], BLUE_DARK, nums_bgs))
story.append(Spacer(1, 8))
# โโ BUILD โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
doc.build(story, canvasmaker=FooterCanvas)
print(f"PDF saved โ {OUTPUT}")
build()
python /home/daytona/workspace/colorful-study-notes/create_atls.py 2>&1
ATLS Study Notes
PDF Document ยท PDF
| Section | Colour | Content |
|---|---|---|
| 1. X-ABCDE Primary Survey | Red | Full X-ABCDE table + 7 life-threatening conditions & immediate actions |
| 2. Haemorrhagic Shock | Orange | Class I-IV shock table + Damage Control Resuscitation principles |
| 3. Airway Management | Blue | 7 airway techniques from basic to surgical cric + RSI drugs |
| 4. Secondary Survey | Teal | Head-to-toe 13-region examination table + AMPLE history |
| 5. TBI & Spine | Purple | Full GCS scoring table + secondary brain injury prevention |
| 6. Specific Injury Patterns | Green | Tension pneumo, tamponade, pelvis, FAST, burns, paeds, obstetric, geriatric |
| 7. Quick Reference | Grey | All mnemonics (X-ABCDE, AMPLE, Beck's, Cushing's, lethal triad) + critical numbers table |