functions
Pure projection of CriteriaEvaluations into the flat csv_report_df.
Reproduces exactly what criteria_matching + csv_report's filter re-run
produced before: the boolean FILTER_MATCHING_COLUMN, one boolean column per
filter, a comma-joined failure-reason column (rendered against display names),
and the context column. Reasons are regenerated structurally from each outcome
so no filter is ever re-run. The filename column lets csv_report merge the
result onto its freshly-read source data.
Module
Functions
evaluations_to_csv_report_df
def evaluations_to_csv_report_df( evaluations: list[CriteriaEvaluation], rename_columns: Mapping[str, str] | None = None, evaluations_grain: CriterionGrain = scan,) ‑> pandas.core.frame.DataFrame:Project structured evaluations into the flat report df.
Arguments
-
evaluations: OneCriteriaEvaluationper row, fromcriteria_matching. -
rename_columns: Display-name map for the failure-reason strings. -
evaluations_grain: The grain the evaluations were produced on, which selects the merge keycsv_reportuses to carry this projection back onto the patient/scan demographics. The two grains differ only in what identifies a row: -
CriterionGrain.SCAN(file-system source): each identity carries a realscan_id, so rows key onORIGINAL_FILENAME_METADATA_COLUMN(the scan's filename). -
CriterionGrain.PATIENT(non-file-system / EHR source): everyscan_idisNone, so rows key onEHR_BITFOUNT_PATIENT_ID_COL(from each identity'sbitfount_patient_id) instead — keying on the all-Nonefilename column would drop every row in the merge.
Returns
A DataFrame keyed by the grain's merge column (the filename column on
the scan grain, EHR_BITFOUNT_PATIENT_ID_COL on the EHR grain) plus
FILTER_MATCHING_COLUMN and the comma-joined FILTER_FAILED_REASON_COLUMN
— both always present, mirroring legacy criteria_matching, which ran
apply_inclusion_filters (seeding FILTER_FAILED_REASON_COLUMN) and
always set FILTER_MATCHING_COLUMN (to True for every row when no
filter was active). When at least one outcome exists, also: one boolean
column per filter (keyed by column_name), a per-MethodFilter
"Context for {column_name}" column (only when at least one row has
context; mirrors MethodFilter.apply_filter dropping an all-null one),
and FILTER_CONTEXT_COLUMN (only when a MethodFilter outcome whose
required columns were present exists, mirroring MethodFilter.apply_filter
— a ColumnFilter-only evaluation never writes it, and neither does a
MethodFilter whose required columns were entirely absent, since legacy
returns before ever creating FILTER_CONTEXT_COLUMN in that case).
A MethodFilter whose required columns are entirely absent from the row
is out of scope for the per-filter boolean column only (see
TestByteParityWithLegacyApplyFilter): legacy writes a descriptive
string there instead of a bool, which this projection does not
reproduce. FILTER_CONTEXT_COLUMN's presence is still gated correctly
in that case (see above) — it is not conflated with a MethodFilter
outcome whose method simply returned a non-bool (also state=unknown,
context=None, but distinguished by failed_message not matching the
absent-columns "unable to determine ... filter" string).