import polars as pl
import rtflite as rtf
from importlib.resources import files
= pl.read_parquet(files("rtflite.data").joinpath("adsl.parquet"))
adsl = pl.read_parquet(files("rtflite.data").joinpath("adae.parquet"))
adae = ["Placebo", "Xanomeline Low Dose", "Xanomeline High Dose"] treatments
6 Specific Adverse Events Table
This article demonstrates how to create a specific adverse events table by System Organ Class and Preferred Term.
6.1 Setup
6.2 Prepare AE Summary Data
# Get safety population counts and AE data
= adsl.filter(pl.col("SAFFL") == "Y").select(["USUBJID", "TRT01A"])
adsl_safety = adae.join(adsl_safety, on="USUBJID", how="inner")
adae_safety = adsl_safety.group_by("TRT01A").agg(N=pl.len()).sort("TRT01A")
pop_counts
# Calculate AE counts by SOC and term
= (
ae_counts "AEDECOD").str.to_titlecase())
adae_safety.with_columns(pl.col("TRT01A", "AEBODSYS", "AEDECOD"])
.group_by([=pl.col("USUBJID").n_unique())
.agg(n"AEBODSYS", "AEDECOD", "TRT01A"])
.sort([
)
# Build table rows
= [
table_data "Participants in population"] + [str(pop_counts.filter(pl.col("TRT01A") == t)["N"][0]) for t in treatments],
[""] * 4 # Blank row
[
]
# Add SOC and AE term rows
for soc in ae_counts["AEBODSYS"].unique().sort():
+ [""] * 3)
table_data.append([soc] = ae_counts.filter(pl.col("AEBODSYS") == soc)
soc_data
for ae in soc_data["AEDECOD"].unique().sort():
= [f" {ae}"]
row for trt in treatments:
= soc_data.filter((pl.col("AEDECOD") == ae) & (pl.col("TRT01A") == trt))
count str(count["n"][0]) if count.height > 0 else "0")
row.append(
table_data.append(row)
= pl.DataFrame(table_data, schema=[""] + treatments, orient="row") df_ae_specific
6.3 Create RTF Output
= rtf.RTFDocument(
doc_ae_specific =df_ae_specific,
df=rtf.RTFTitle(text=["Specific Adverse Events", "(Safety Analysis Population)"]),
rtf_title=rtf.RTFColumnHeader(
rtf_column_header=["", "Placebo\nn", "Xanomeline Low Dose\nn", "Xanomeline High Dose\nn"],
text=[4, 1, 1, 1],
col_rel_width=["l", "c", "c", "c"],
text_justification
),=rtf.RTFBody(
rtf_body=[4, 1, 1, 1],
col_rel_width=["l", "c", "c", "c"],
text_justification=lambda df, i, j: "bold" if j == 0 and " " not in str(df[i, j]) else "",
text_font_style
),=rtf.RTFFootnote(text=["Number of participants with specific adverse events."]),
rtf_footnote=rtf.RTFSource(text=["Source: ADSL and ADAE datasets"])
rtf_source
)
"../rtf/tlf_ae_specific.rtf") doc_ae_specific.write_rtf(