14  Protocol Deviation Listing

Objectives

This guide demonstrates Protocol Deviation (PD) listing showing detailed individual deviation records.

14.1 Setup

import os
import sys
import polars as pl
from pathlib import Path

sys.path.insert(0, 'src')

from rtflite import LibreOfficeConverter
try:
    converter = LibreOfficeConverter()
except Exception:
    converter = None
    print("WARNING: LibreOffice not found. PDF conversion will be skipped.")

from csrlite import load_plan, study_plan_to_pd_listing
from csrlite.pd.pd_listing import pd_listing_ard, pd_listing_rtf, pd_listing

14.2 Protocol Deviation Listing

Shows detailed individual protocol deviations with categories and terms.

14.3 StudyPlan-Driven Workflow

try:
    study_plan = load_plan("studies/xyz123/yaml/plan_xyz123.yaml")
    # Filter for pd_listing analyses
    study_plan.get_plan_df().filter(pl.col("analysis") == "pd_listing")
    output_files = study_plan_to_pd_listing(study_plan)
except Exception as e:
    print(f"Error loading plan or generating listing: {e}")
    output_files = []
2026-02-03 15:27:48,417 - csrlite.common.plan - INFO - Successfully loaded dataset 'adsl' from 'studies/xyz123/yaml/../../../data/adsl.parquet'
2026-02-03 15:27:48,420 - csrlite.common.plan - INFO - Successfully loaded dataset 'adae' from 'studies/xyz123/yaml/../../../data/adae.parquet'
2026-02-03 15:27:48,422 - csrlite.common.plan - INFO - Successfully loaded dataset 'adie' from 'studies/xyz123/yaml/../../../data/adie.parquet'
2026-02-03 15:27:48,423 - csrlite.common.plan - INFO - Successfully loaded dataset 'adpd' from 'studies/xyz123/yaml/../../../data/adpd.parquet'
studies/xyz123/rtf/pd_listing_itt_pd_major.rtf
studies/xyz123/rtf/pd_listing_apat.rtf

14.3.1 pd_listing_itt_pd_major

14.3.2 pd_listing_apat

14.4 Complete Pipeline

data_path = Path("data") if Path("data").exists() else Path("../data")
adsl = pl.read_parquet(data_path / "adsl.parquet")
adpd = pl.read_parquet(data_path / "adpd.parquet")

pd_listing(
    population=adsl,
    observation=adpd,
    population_filter="ITTFL = 'Y'",
    observation_filter="DVCAT = 'Major'",
    id=("USUBJID", "Subject ID"),
    title=[
        "Listing of Major Protocol Deviations",
        "(Intent-to-Treat Population)"
    ],
    footnote=["Protocol deviations are sorted by treatment and subject ID."],
    source=["Source: ADSL and ADPD datasets"],
    output_file="studies/xyz123/rtf/pd_listing_manual.rtf",
    population_columns=[
        ("TRT01A", "Treatment")
    ],
    observation_columns=[
        ("DVCAT", "Category"),
        ("DVTERM", "Term"),
        ("DVDECOD", "Coded Term")
    ],
    sort_columns=["TRT01A", "USUBJID", "DVCAT", "DVTERM"],
    group_by=["USUBJID"],
    page_by=["TRT01A"],
)
studies/xyz123/rtf/pd_listing_manual.rtf
'studies/xyz123/rtf/pd_listing_manual.rtf'

14.5 Step-by-Step Pipeline

14.5.1 Step 1: Generate ARD

_ard = pd_listing_ard(
    population=adsl,
    observation=adpd,
    population_filter="ITTFL = 'Y'",
    observation_filter="DVCAT = 'Major'",
    id=("USUBJID", "Subject ID"),
    population_columns=[("TRT01A", "Treatment")],
    observation_columns=[
        ("DVCAT", "Category"),
        ("DVTERM", "Term"),
        ("DVDECOD", "Coded Term")
    ],
    sort_columns=["TRT01A", "USUBJID", "DVCAT", "DVTERM"],
    page_by=["TRT01A"]
)

_ard.head(5)
shape: (3, 5)
__index__ USUBJID DVCAT DVTERM DVDECOD
str str str str str
"Treatment = Xanomeline Low Dos… "01-701-1097" "Major" "HbA1c > 9% at screening" "Inclusion/Exclusion Criteria"
"Treatment = Xanomeline Low Dos… "01-701-1115" "Major" "Administered 10mg instead of 5… "Study Drug Handling/Dosing"
"Treatment = Xanomeline Low Dos… "01-701-1115" "Major" "ICF signed after lab draw" "Informed Consent Procedure"

14.5.2 Step 2: Generate RTF Output

pd_listing_rtf(
    _ard.head(10),
    column_labels={
        "USUBJID": "Subject ID",
        "TRT01A": "Treatment",
        "DVCAT": "Category",
        "DVTERM": "Term",
        "DVDECOD": "Coded Term",
        "__index__": ""
    },
    title=[
        "Listing of Major Protocol Deviations",
        "(Intent-to-Treat Population)"
    ],
    footnote=["Protocol deviations are sorted by treatment and subject ID."],
    source=["Source: ADSL and ADPD datasets"],
    group_by=["USUBJID"],
    page_by=["__index__"]
).write_rtf("studies/xyz123/rtf/pd_listing_step.rtf")
studies/xyz123/rtf/pd_listing_step.rtf