This commit is contained in:
2026-05-21 17:12:18 +02:00
parent 15eed6b4c3
commit c434f270b0
30 changed files with 2823 additions and 21 deletions
+65 -19
View File
@@ -355,12 +355,21 @@ def load_patients(cursor, study):
mid = cursor.fetchone()["mid"]
if mid is None:
raise RuntimeError(f"Žádná data v MySQL pro pacienty {study}")
extra_cols = ""
if study == "77242113UCO3001":
extra_cols = """
rescreened_subject AS `Rescreened Subject`,
adt_ir AS `ADT-IR`,
three_or_more_advanced_therapies AS `3+ Adv. Therapies`,
only_oral_5asa_compounds AS `Only 5-ASA`,
ustekinumab AS `Ustekinumab`,
isolated_proctitis AS `Isolated Proctitis`,"""
sql = f"""
SELECT
subject AS `Subject`,
investigator AS `Investigator`,
age AS `Subject's age collection`,
cohort_per_irt AS `Cohort per IRT`,
cohort_per_irt AS `Cohort per IRT`,{extra_cols}
irt_subject_status AS `IRT Subject Status`,
last_irt_transaction AS `Last Recorded IRT Transaction`,
next_irt_transaction AS `Next Expected IRT Transaction`,
@@ -403,15 +412,30 @@ def _write_prehled(wb, df_raw, study):
ws = wb.create_sheet("Přehled", 0)
ws.sheet_view.showGridLines = False
ws.merge_cells("A1:H1")
is_uco = (study == "77242113UCO3001")
if is_uco:
display_headers = ["Subject", "Investigator", "Věk", "Cohort",
"Rescreened", "ADT-IR", "≥3 Adv.Th.", "5-ASA only",
"Uste.", "Isol.Proct.",
"Status", "Last IRT", "Next Visit", "Next Date"]
col_widths = [14, 22, 6, 12, 11, 8, 11, 10, 8, 12, 14, 12, 12, 13]
status_col = 11
flag_cols = set(range(5, 11)) # 1-indexed sloupce s Yes/No hodnotami
else:
display_headers = ["Subject", "Investigator", "Věk", "Cohort", "Status", "Last IRT", "Next Visit", "Next Date"]
col_widths = [14, 22, 6, 12, 14, 12, 12, 13]
status_col = 5
flag_cols = set()
last_col = get_column_letter(len(display_headers))
ws.merge_cells(f"A1:{last_col}1")
title = ws["A1"]
title.value = f"Subject Summary — {study} ({date.today().strftime('%d-%b-%Y')})"
title.font = Font(name="Arial", bold=True, size=12, color="1F4E79")
title.alignment = Alignment(horizontal="left", vertical="center")
ws.row_dimensions[1].height = 22
display_headers = ["Subject", "Investigator", "Věk", "Cohort", "Status", "Last IRT", "Next Visit", "Next Date"]
col_widths = [14, 22, 6, 12, 14, 12, 12, 13]
for c, (h, w) in enumerate(zip(display_headers, col_widths), 1):
cell = ws.cell(row=2, column=c, value=h)
cell.font = _PAT_HEADER_FONT
@@ -421,16 +445,28 @@ def _write_prehled(wb, df_raw, study):
ws.column_dimensions[get_column_letter(c)].width = w
ws.row_dimensions[2].height = 18
display = pd.DataFrame({
base = {
"Subject": df_raw["Subject"].fillna(""),
"Investigator": df_raw["Investigator"].fillna(""),
"Věk": df_raw["Subject's age collection"].apply(lambda v: "" if pd.isna(v) else int(v)),
"Cohort": df_raw["Cohort per IRT"].apply(_simplify_cohort),
"Status": df_raw["IRT Subject Status"].fillna(""),
"Last IRT": df_raw["Last Recorded IRT Transaction"].fillna(""),
"Next Visit": df_raw["Next Expected IRT Transaction"].fillna(""),
"Next Date": df_raw["Next Expected IRT Transaction Date [Local]"].apply(_fmt_date),
}).sort_values("Subject").reset_index(drop=True)
}
if is_uco:
base.update({
"Rescreened": df_raw["Rescreened Subject"].fillna(""),
"ADT-IR": df_raw["ADT-IR"].fillna(""),
"≥3 Adv.Th.": df_raw["3+ Adv. Therapies"].fillna(""),
"5-ASA only": df_raw["Only 5-ASA"].fillna(""),
"Uste.": df_raw["Ustekinumab"].fillna(""),
"Isol.Proct.": df_raw["Isolated Proctitis"].fillna(""),
})
base.update({
"Status": df_raw["IRT Subject Status"].fillna(""),
"Last IRT": df_raw["Last Recorded IRT Transaction"].fillna(""),
"Next Visit": df_raw["Next Expected IRT Transaction"].fillna(""),
"Next Date": df_raw["Next Expected IRT Transaction Date [Local]"].apply(_fmt_date),
})
display = pd.DataFrame(base).sort_values("Subject").reset_index(drop=True)
for r_idx, row in display.iterrows():
excel_row = r_idx + 3
@@ -440,17 +476,14 @@ def _write_prehled(wb, df_raw, study):
is_adolescent = row["Cohort"] == "Adolescent"
fill = _PAT_EVEN_FILL if r_idx % 2 == 0 else _PAT_ODD_FILL
values = [row["Subject"], row["Investigator"], row["Věk"],
row["Cohort"], row["Status"], row["Last IRT"],
row["Next Visit"], row["Next Date"]]
for c_idx, val in enumerate(values, 1):
for c_idx, val in enumerate(row, 1):
cell = ws.cell(row=excel_row, column=c_idx, value=val if val != "" else None)
cell.fill = fill
cell.border = _PAT_BORDER
cell.alignment = _PAT_CENTER if c_idx == 3 else _PAT_LEFT
cell.alignment = _PAT_CENTER if (c_idx == 3 or c_idx in flag_cols) else _PAT_LEFT
if is_failed:
cell.font = _PAT_STRIKE_FONT
elif c_idx == 5 and is_randomized:
elif c_idx == status_col and is_randomized:
cell.font = _PAT_BOLD_FONT
elif c_idx == 4 and is_adolescent:
cell.font = _PAT_ADOLESC_FONT
@@ -459,10 +492,10 @@ def _write_prehled(wb, df_raw, study):
ws.row_dimensions[excel_row].height = 16
ws.freeze_panes = "A3"
ws.auto_filter.ref = f"A2:H{len(display) + 2}"
ws.auto_filter.ref = f"A2:{last_col}{len(display) + 2}"
def _write_next_visits(wb, df_raw, study):
def _write_next_visits(wb, df_raw, study, visits_df=None):
ws = wb.create_sheet("Next Visits", 1)
ws.sheet_view.showGridLines = False
@@ -491,6 +524,19 @@ def _write_next_visits(wb, df_raw, study):
"Datum": df_raw["Next Expected IRT Transaction Date [Local]"],
"Status": df_raw["IRT Subject Status"].fillna(""),
})
# I-0: datum = screening date + 42 dní
if visits_df is not None and not visits_df.empty:
screen = (
visits_df[visits_df["Visit"].str.contains("Screen", case=False, na=False)]
.groupby("Subject")["Visit Date"].min()
.rename("Screening Date")
)
df = df.join(screen, on="Subject")
mask_i0 = df["Next Visit"].str.contains("I-0", na=False)
df.loc[mask_i0, "Datum"] = df.loc[mask_i0, "Screening Date"] + pd.Timedelta(days=42)
df = df.drop(columns=["Screening Date"])
df = df[df["Datum"].notna()]
df = df[~df["Status"].str.contains("Screen Failed|Discontinued", na=False)]
df = df.sort_values("Datum").reset_index(drop=True)
@@ -579,7 +625,7 @@ def create_study_report(study):
# ── pacienti (Přehled + Next Visits) na začátek ──────────────────────────
_write_prehled(wb, df_patients, study)
_write_next_visits(wb, df_patients, study)
_write_next_visits(wb, df_patients, study, visits_df)
# ── pořadí listů: Patient Visits jako první ──────────────────────────────
names = wb.sheetnames