functions
Pure functions for PDF report generation.
Extracted from
bitfount.federated.algorithms.ophthalmology.ga_trial_pdf_algorithm_amethyst
and ga_trial_pdf_algorithm_base so that the same logic can be called from
composable Prefect steps without depending on class inheritance.
PDF rendering is handled by bitfount.steps.pdf_report.pdf_render.
Module
Functions
eligible_filenames_from_evaluations
def eligible_filenames_from_evaluations( evaluations: list[CriteriaEvaluation],) ‑> set[str]:Return the set of filenames whose every criterion passed.
Arguments
evaluations: The structured evaluations fromcriteria_matching.
Returns The eligible scan filenames.
extract_record_info
def extract_record_info( datasource_row: pd.Series, report_metadata: ReportMetadata,) ‑> RecordInfo:Extract text field values from a datasource row for the PDF header.
Parses column values according to their type (datetime, float, int, string).
generate_pdf_for_row
def generate_pdf_for_row( datasource_row: pd.Series, results_df: pd.DataFrame, row_index: Any, ga_metric: GAMetrics | GAMetricsWithFovea, report_metadata: ReportMetadata, base_path: Path, task_id: str, original_filename: str, total_ga_area_lower_bound: float, total_ga_area_upper_bound: float, pdf_filename_columns: list[str] | None = None, filename_prefix: str | None = None, trial_name: str | None = None, eligibility: str | None = None,) ‑> pathlib.Path | None:Generate a complete PDF report for a single patient row.
Orchestrates: scan extraction → record info → path generation → rendering.
Returns Path to the generated PDF, or None if generation failed.
generate_pdf_output_path
def generate_pdf_output_path( base_path: Path, original_filename: str, row: pd.Series, task_id: str, pdf_filename_columns: list[str] | None = None, filename_prefix: str | None = None, trial_name: str | None = None, eligibility: str | None = None,) ‑> pathlib.Path:Generate a unique output path for a PDF report file.
Arguments
base_path: Base output directory.original_filename: The original scan filename.row: The datasource row (for extracting column values for filename).task_id: Task run ID (used as subdirectory).pdf_filename_columns: Columns whose values form the PDF filename.filename_prefix: Optional prefix for the filename.trial_name: Trial name to include in filename.eligibility: Eligibility label to include in filename.
Returns A unique Path that does not conflict with existing files.
get_scan_data
def get_scan_data( datasource_row: pd.Series, results_df: pd.DataFrame, row_index: Any, bscan_idx: int | None, segmentation_labels: dict[str, int] | None = None,) ‑> ScanData:Extract B-scan image, parse mask, overlay segmentation, return scan data.
Arguments
datasource_row: The row from the source DataFrame containing image data.results_df: The predictions DataFrame.row_index: The index of this row in results_df.bscan_idx: Which B-scan slice to use (from ga_metrics.max_ga_bscan_index).segmentation_labels: Label-to-index mapping for mask parsing.
Returns An AltrisScan with images and metadata.
map_subfoveal_indicator
def map_subfoveal_indicator(value: str | None) ‑> str | None:Map raw subfoveal indicator 'Y'/'N' to 'Yes'/'No'.
render_pdf
def render_pdf( output_path: Path, record_info: AltrisRecordInfo, scan: AltrisScan, ga_metrics: GAMetrics | GAMetricsWithFovea, task_id: str, total_ga_area_lower_bound: float, total_ga_area_upper_bound: float, eligibility: str | None = None,) ‑> bool:Render a single patient PDF report.
Arguments
output_path: Where to save the PDF.record_info: Patient/record text fields for the header.scan: B-scan image data with segmentation overlay.ga_metrics: GA metrics for this scan.task_id: Task run ID.total_ga_area_lower_bound: Lower bound for slider visualization.total_ga_area_upper_bound: Upper bound for slider visualization.eligibility: Eligibility label (added to text fields if provided).
Returns True if PDF was generated successfully, False otherwise.
validate_pdf_inputs
def validate_pdf_inputs( filenames: list[str], ga_dict: Mapping[str, Any], results_df: pd.DataFrame,) ‑> None:Validate that PDF generation inputs are consistent.
Raises
ValueError: If lengths don't match.