data_utils
Composable data utilities for steps.
Decomposes the monolithic initialise_model(data=...) flow into
individually callable functions so that each concern (schema discovery,
column configuration, dataloader creation, model init, inference) can be
used and tested independently.
Also provides shared data-manipulation utilities that multiple steps need
(e.g. get_data_for_files, convert_predictions_to_dataframe,
convert_metrics_to_df, convert_ga_metrics_to_df).
Sub-modules
inference
Model inference pipeline helpers (build_column_config,
create_inference_dataloader, init_model_for_inference,
run_inference).
dataframe
DataFrame conversion and manipulation (convert_predictions_to_dataframe,
get_data_for_files, convert_metrics_to_df, convert_ga_metrics_to_df,
add_age_column).
parsing
Image/mask parsing and the shared prediction-envelope helpers
(parse_mask_json, is_na_prediction, load_prediction_envelope).
datasource
Datasource helpers (resolve_output_path,
use_default_rename_columns).
enrichment
Cache -> patient-grain frame for supplied patient enrichment
(supplied_observations_from_cache).
ga_metrics
Shared GA metrics computation primitives used by both
ga_calculation_with_fovea and ga_calculation_without_fovea steps
(convert_nan_to_zero, get_max_ga_bscan_index, get_lesion_sizes,
get_shortest_distance_from_image_centre, parse_bscan_predictions,
compute_ga_metrics_for_scan).
metric_frame
Shared scan-metrics frame assembly used by both criteria_matching and
biomarker_tabulation (assemble_scan_frame).
fovea
Fovea landmark extraction shared between step packages
(get_central_slice_landmark_point, FOVEA_CENTRE_LANDMARK_INDEX).
morphometry
Pure voxel-scale geometry shared by every en-face and volumetric
biomarker (VoxelScale, has_en_face_scale, has_voxel_scale,
en_face_area_mm2, volume_mm3, volume_nl, label_en_face,
label_volume, en_face_distance_grid).
segmentation_masks
One walk of a scan's segmentation cube, producing per-label en-face
presence and per-GROUP voxel depth (ScanMasks, parse_bscan_masks,
combine_label_mask, group_reports_volume). Depth is combined per group
during the walk because a per-label voxel count cannot be combined into a
group count afterwards.
lesions
Per-lesion extraction and diameter measurement, labelling a group's
footprint into individual lesions and reporting two diameters for the
cube's anisotropic sampling (RawLesion, extract_lesions,
max_base_width_mm, max_feret_mm).
fovea_geometry
Fovea-relative geometry in millimetre space: distance, region of
interest, and angular span (roi_mask, min_distance_from_reference_mm,
angular_occupancy, aggregate_angular_span_deg).
Module
Submodules
- bitfount.steps.data_utils.dataframe - DataFrame conversion and manipulation utilities for steps.
- bitfount.steps.data_utils.datasource - Datasource helper utilities for steps.
- bitfount.steps.data_utils.enrichment - Rebuild the supplied-observations frame from a
patient_enrichmentcache. - bitfount.steps.data_utils.fovea - Fovea landmark extraction, shared between step packages.
- bitfount.steps.data_utils.fovea_geometry - Fovea-relative geometry: distance, region of interest, angular span.
- bitfount.steps.data_utils.ga_metrics - Shared GA metrics computation primitives.
- bitfount.steps.data_utils.inference - Model inference pipeline utilities.
- bitfount.steps.data_utils.lesions - Per-lesion extraction and diameter measurement.
- bitfount.steps.data_utils.metric_frame - Shared scan-metrics frame assembly.
- bitfount.steps.data_utils.morphometry - Voxel geometry for en-face and volumetric biomarker measurement.
- bitfount.steps.data_utils.parsing - Image and segmentation mask parsing utilities for steps.
- bitfount.steps.data_utils.runs - Contiguous-run reduction over a 1-D boolean row.
- bitfount.steps.data_utils.scan_metric_names - Shared canonical naming for CST/GCC/fluid scan-metric columns.
- bitfount.steps.data_utils.segmentation_masks - One scan's segmentation cube, reduced to what the measurements need.
- bitfount.steps.data_utils.thickness_calculation - Shared per-file thickness-calculation runner.
- bitfount.steps.data_utils.thickness_metrics - Shared retinal-layer thickness computation primitives.
Functions
_sort_col_by_list
def _sort_col_by_list( col: pandas.core.series.Series, sort_by: list[str],) ‑> pd.Series[int | float]:Sort helper: maps values to their index in sort_by.
add_age_column
def add_age_column( df: pandas.core.frame.DataFrame, dob_col: str = "Patient's Birth Date", age_col: str = 'Age (yrs)',) ‑> pandas.core.frame.DataFrame:Add an age column to df based on a date-of-birth column.
If age_col already exists and is fully populated the dataframe is
returned unchanged. If the column exists but contains NA / None
values, this function falls through and fills those gaps from dob_col,
leaving any already-populated rows untouched.
Unparseable DOB values (e.g. de-identification placeholders like
"XXXX") are coerced to NaT; age is computed only for rows with
a valid DOB and left as NA for the rest.
If DOB parsing raises OverflowError (e.g. DOB set to
Timestamp.min as a placeholder), a timedelta-based fallback is used.
Returns The same dataframe with the extra age column.
apply_canonical_scan_metric_names
def apply_canonical_scan_metric_names( df: pd.DataFrame, metrics_type: type,) ‑> pandas.core.frame.DataFrame:Rename a scan-metrics frame's columns to their canonical scan-metric names.
CST/GCC descriptor collisions become cst_*/gcc_*; fluid scalars gain the
fluid_ prefix and the per-scan segmentation_volumes dict column is
flattened into fluid_<label>_volume columns (absent label or non-dict cell
→ pd.NA) then dropped. Any other metrics type is returned unchanged. The
ORIGINAL_FILENAME_METADATA_COLUMN merge key is never renamed (it is not in
any rename map).
Arguments
df: The per-scan metrics frame produced byconvert_metrics_to_df.metrics_type: The metrics dataclass the frame's rows conform to.
Returns The frame with canonical column names. A metrics type needing no transform is returned unchanged (and unmutated); otherwise a copy.
assemble_scan_frame
def assemble_scan_frame( base: pandas.core.frame.DataFrame, scan_frames: collections.abc.Sequence[pandas.core.frame.DataFrame], *, key: str = '_original_filename',) ‑> tuple[pandas.core.frame.DataFrame, dict[str, CriterionProvenance]]:Left-merge each non-empty scan frame onto base, tagging SCAN provenance.
Shared scan-metrics merge loop used by both criteria_matching and
biomarker_tabulation. Each already-built metrics frame (e.g. one
per GA/fluid/CST/GCC producer) is merged in turn: colliding columns are
coalesced via _drop_colliding_columns rather than suffixed, so a
left-merge cannot silently orphan a criterion's target column.
Arguments
base: The frame being merged onto (already carries the mergekey).scan_frames: Already-built per-source metrics frames to merge in, in order; a frame with no rows is skipped. Each frame must hold at most one row perkeyvalue — the left-merge fansbase's rows out on a duplicate key. Every current builder satisfies this (cachefile_idis unique per partition;backfill_metricskeys by filename), so the precondition is not re-checked here.key: The shared merge key column.
Returns
(merged_df, column_provenance) — base with every non-empty
scan_frames entry merged in, and a {column: CriterionProvenance.SCAN}
map covering every column each merged-in frame contributed (after
collision coalescing).
build_column_config
def build_column_config( image_prefix: str = 'Pixel Data', selected_cols: Optional[list[str]] = None, selected_cols_prefix: str | None = None, schema_requirements: Any = 'empty', batch_transforms: list[dict[str, typing.Any]] | None = None, image_prefix_batch_transforms: list[dict[str, typing.Any]] | None = None, auto_convert_grayscale_images: bool = True,) ‑> DataStructure:Build a DataStructure suitable for ophthalmology inference.
This is a thin wrapper around the DataStructure constructor with
sensible defaults matching the GA Trial Bronze task YAML.
Arguments
image_prefix: Image column prefix (default"Pixel Data").selected_cols: Explicit list of selected columns. Defaults to["Columns", "Rows"]when None.selected_cols_prefix: Prefix for selected columns (default same as image_prefix).schema_requirements: Schema requirement level.batch_transforms: Optional batch transforms list.image_prefix_batch_transforms: Optional image-specific batch transforms.auto_convert_grayscale_images: Convert grayscale to RGB (default True).
Returns
A DataStructure instance.
canonical_scan_metric_field_specs
def canonical_scan_metric_field_specs( metrics_type: type,) ‑> list[FieldSpec]:FieldSpecs for a scan-metrics type, named to match the canonical frame.
Applies the same rename as apply_canonical_scan_metric_names to each of
the type's field_specs() (so a column_criteria targeting a canonical
name resolves), and for fluid appends the three flattened
fluid_<label>_volume columns (which field_specs_from_dataclass skips
because segmentation_volumes is a container). A type without field_specs
contributes nothing rather than raising.
Arguments
metrics_type: The metrics dataclass ascan_metricssource declares.
Returns
The canonical-named FieldSpec list (empty for an unrecognised type).
compute_ga_metrics_for_scan
def compute_ga_metrics_for_scan( bscan_predictions: tuple[str, ...], slice_thickness: float, pixel_spacing_column: float, all_segmentation_labels: dict[str, int], ga_area_include_segmentations: list[str], ga_area_exclude_segmentations: list[str], n_scan_biomarker_thresholds: Mapping[str, float] | None = None, include_raw_pathology_probabilities: bool = False,) ‑> GAMetrics:Compute GA metrics for a single scan (without fovea).
This encapsulates the per-file computation loop body from
_WorkerSide.run() (lines 268-343 in the original).
Arguments
bscan_predictions: The raw per-B-scan prediction JSON strings.slice_thickness: The distance between B-scans in mm.pixel_spacing_column: The pixel spacing along the B-scan column axis.all_segmentation_labels: All segmentation label names to class index.ga_area_include_segmentations: Segmentation labels to include when computing the GA area column mask.ga_area_exclude_segmentations: Segmentation labels to exclude when computing the GA area column mask.n_scan_biomarker_thresholds: Per-biomarker>=probability threshold used to computen_scan_run_lengths. Keys define which N-scan biomarkers are evaluated; whenNone, every label inN_SCAN_BIOMARKER_LABELSdefaults to0.5.include_raw_pathology_probabilities: Whether to include the raw per-B-scan pathology probability arrays on the returned metrics.
Raises
Exception: Propagates any exception from prediction parsing or metric computation so that the caller can handle/skip.
convert_ga_metrics_to_df
def convert_ga_metrics_to_df( ga_metrics: collections.abc.Mapping[str, typing.Any], additional_pathology_prob_cols: collections.abc.Collection[str] | None = None, additional_area_cols: collections.abc.Collection[str] | None = None, additional_run_length_cols: collections.abc.Collection[str] | None = None, metrics_type: type | None = None,) ‑> pandas.core.frame.DataFrame:Convert a dict of GAMetrics objects into a dataframe.
Thin back-compat wrapper over convert_metrics_to_df; preserves the
GA-specific exemplar-by-type selection between GAMetrics and
GAMetricsWithFovea for expected_cols(), while always guarding record
building on the base GAMetrics type. This matters when ga_metrics
mixes plain GAMetrics and GAMetricsWithFovea values: the resolved
exemplar type may narrow to GAMetricsWithFovea (to pick up the fovea
columns), but a plain GAMetrics entry must still have its base fields
recorded rather than being dropped entirely for failing an isinstance
check against the narrower subclass.
Arguments
ga_metrics: Mapping of filename to GAMetrics instances.additional_pathology_prob_cols: Additional pathology names to extract intomax_<name>_probabilitycolumns.additional_area_cols: Additional biomarker labels to extract into<label>_areacolumns.additional_run_length_cols: Additional N-scan biomarker labels to extract inton_scan_run_<label>columns.metrics_type: Expected type of GAMetrics instances (fallback when all None).
Returns DataFrame with each row representing GAMetrics for a single file.
convert_metrics_to_df
def convert_metrics_to_df( metrics: collections.abc.Mapping[str, typing.Any], metrics_type: type[MetricsLike], additional_pathology_prob_cols: collections.abc.Collection[str] | None = None, additional_area_cols: collections.abc.Collection[str] | None = None, additional_run_length_cols: collections.abc.Collection[str] | None = None, record_isinstance_type: type | None = None,) ‑> pandas.core.frame.DataFrame:Convert a mapping of filename to metrics objects into a wide DataFrame.
Works for any metrics dataclass that exposes to_record() and
expected_cols() (e.g. GAMetrics, GAMetricsWithFovea, or the
fluid-volume/CST/GCC metrics dataclasses). Values that are not instances
of record_isinstance_type (defaulting to metrics_type; e.g.
plain-string error reasons stored in place of a successful result) are
treated as empty records rather than raising, so an error placeholder
still produces a row with all metric columns unset.
Arguments
metrics: Mapping of filename to metrics instances (or non-metrics error values, e.g. strings, which produce an empty record).metrics_type: The metrics dataclass type these records should conform to; used to look upexpected_cols(), and (unless record_isinstance_type is given) also for the record-buildingisinstanceguard.additional_pathology_prob_cols: Additional pathology names to extract intomax_<name>_probabilitycolumns, for metrics types (such asGAMetrics) whoseto_record()supports this argument.additional_area_cols: Additional biomarker labels to extract into<label>_areacolumns, for metrics types (such asGAMetrics) whoseto_record()supports this argument.additional_run_length_cols: Additional N-scan biomarker labels to extract inton_scan_run_<label>columns, for metrics types (such asGAMetrics) whoseto_record()supports this argument.record_isinstance_type: The type used for the record-buildingisinstanceguard, if different from metrics_type. Useful when metrics_type is a subclass (e.g.GAMetricsWithFovea) but values of the base class (e.g.GAMetrics) should still have their base fields recorded rather than being dropped entirely. Defaults toNone, meaning metrics_type is used for both.
Returns
DataFrame with one row per mapping entry, an
ORIGINAL_FILENAME_METADATA_COLUMN column of the mapping keys, and
any missing expected columns added (and logged) as empty columns.
convert_nan_to_zero
def convert_nan_to_zero(value: Any) ‑> float:Convert NaN values to 0.
convert_predictions_to_dataframe
def convert_predictions_to_dataframe(predictions: Any) ‑> pandas.core.frame.DataFrame:Convert PredictReturnType to DataFrame if necessary.
Arguments
predictions: The predictions from the model algorithm.
Returns The predictions as a DataFrame.
create_inference_dataloader
def create_inference_dataloader( datasource: FileSystemIterableSource, schema: BitfountSchema, datastructure: DataStructure, batch_size: int | None = None,) ‑> Any:Create a test-only dataloader for inference, bypassing BitfountDataBunch.
This reproduces the subset of BitfountDataBunch.__init__ that is
relevant for inference:
datastructure.set_training_column_split_by_semantic_type(schema)data_factory.create_dataset(... data_split=TEST, splitter=_InferenceSplitter)data_factory.create_dataloader(dataset, batch_size)
No train/validation splits are created.
Arguments
datasource: The datasource to iterate over.schema: ABitfountSchema(should already have features populated viaBitfountSchema.add_dataframe_features).datastructure: ADataStructure(frombuild_column_config).batch_size: Batch size for the dataloader.
Returns
A BitfountDataLoader wrapping the test dataset.
cst_metrics_from_cache
def cst_metrics_from_cache( accessor: Any,) ‑> dict[str, CSTMetrics | None]:Rebuild a filename→CSTMetrics map from a cst_calculation cache.
Typed wrapper over the shared metrics_from_cache for the CST
background-phase calc cache, mapping an uncomputable file (null
metrics_json) to None.
Arguments
accessor: ACacheAccessorfor thecst_calculationcache partition.
Returns
A {file_id: CSTMetrics | None} map.
extract_bscan_predictions
def extract_bscan_predictions(ga_inferences: Any) ‑> tuple[str, ...]:Extract ordered B-scan prediction strings from a GA inferences dict.
Arguments
ga_inferences: The value of theinferences_json(orinferences_json_ga) field from a merged row. Expected to be a dict keyed by B-scan index (numeric strings or ints).
Returns Tuple of prediction strings sorted by numeric B-scan index, or an empty tuple if the input is not a non-empty dict.
fluid_metrics_from_cache
def fluid_metrics_from_cache( accessor: Any,) ‑> dict[str, FluidVolumeMetrics | None]:Rebuild a filename→FluidVolumeMetrics map from a fluid_calculation cache.
Typed wrapper over the shared metrics_from_cache for the fluid-volume
background-phase calc cache, mapping an uncomputable file (null
metrics_json) to None.
Arguments
accessor: ACacheAccessorfor thefluid_calculationcache partition.
Returns
A {file_id: FluidVolumeMetrics | None} map.
ga_metrics_from_cache
def ga_metrics_from_cache( accessor: Any,) ‑> dict[str, GAMetricsWithFovea | None]:Rebuild a filename→GAMetricsWithFovea map from a ga_calculation cache.
For the v9 flows that run GA calculation in the background, a downstream
interactive step receives the step's .cache accessor rather than the
in-memory metrics. Thin GA-typed wrapper over the shared metrics_from_cache
(which also handles schema-drift tolerance), mapping an uncomputable file
(null metrics_json) to None.
Arguments
accessor: ACacheAccessorfor thega_calculationcache partition.
Returns
A {file_id: GAMetricsWithFovea | None} map suitable for
convert_ga_metrics_to_df.
gcc_metrics_from_cache
def gcc_metrics_from_cache( accessor: Any,) ‑> dict[str, GCCMetrics | None]:Rebuild a filename→GCCMetrics map from a gcc_calculation cache.
Typed wrapper over the shared metrics_from_cache for the GCC
background-phase calc cache, mapping an uncomputable file (null
metrics_json) to None.
Arguments
accessor: ACacheAccessorfor thegcc_calculationcache partition.
Returns
A {file_id: GCCMetrics | None} map.
get_data_for_files
def get_data_for_files( datasource: Any, filenames: list[str], file_key_col: str | None = None, use_cache: bool = True,) ‑> pandas.core.frame.DataFrame:Retrieve data from a datasource for a given list of files.
The dataframe returned will be sorted to match the ordering of the files in
filenames.
get_lesion_sizes
def get_lesion_sizes( num_lesions: int, labeled_array: NDArray[Any], slice_thickness: float, pixel_spacing_column: float,) ‑> list[float]:Calculate the size of each lesion in mm^2.
Arguments
num_lesions: Number of lesions in the image.labeled_array: Numpy array of shape (num_bscans, num_cols) where each pixel is labelled with the lesion number it belongs to.slice_thickness: Thickness of each B-scan in mm.pixel_spacing_column: Spacing between columns in mm.
Returns List of lesion sizes in mm^2.
get_max_ga_bscan_index
def get_max_ga_bscan_index(column_masks_arr: NDArray[Any], ga_area: float) ‑> int | None:Return the index of the B-scan with the largest GA area.
Arguments
column_masks_arr: Numpy array mask of shape (num_bscans, num_cols).ga_area: Total GA area in mm^2.
Returns
Index of the B-scan with the largest GA area, or None if no GA.
get_missing_data_reason
def get_missing_data_reason( slice_thickness: float, pixel_spacing_column: float, original_filename: str | float, pixel_spacing_row: float | None = <object object>,) ‑> str | None:Check required per-row fields and return a skip reason if any are missing.
Arguments
slice_thickness: Value from theSlice Thicknessmetadata column. Will befloat('nan')when the datasource has no value for this file.pixel_spacing_column: Value from thePixel Spacing Columnmetadata column. Will befloat('nan')when the datasource has no value for this file.original_filename: Value from the filename metadata column. Will befloat('nan')when the left-join produced no match.pixel_spacing_row: Optional value from thePixel Spacing Rowmetadata column. Only the fluid-volume calculation requires this axis, so it defaults to the_UNSETsentinel (not checked) — GA callers pass nothing and are unaffected. When a value is supplied it is validated like the other fields, including a genuineNone/NaN cell (reported aspixel_spacing_row).
Returns
A "missing_data:<field>,..." string if one or more fields are NaN /
null, or None if all fields are present.
get_shortest_distance_from_image_centre
def get_shortest_distance_from_image_centre( column_masks_arr: NDArray[Any], labeled_array: NDArray[Any], num_lesions: int, slice_thickness: float, pixel_spacing_column: float,) ‑> float:Calculate the distance from the image centre to the nearest lesion.
Image centre is used as a proxy for the fovea.
Arguments
column_masks_arr: Numpy array mask of shape (num_bscans, num_cols).labeled_array: Numpy array of shape (num_bscans, num_cols) where each pixel is labelled with the lesion number it belongs to.num_lesions: Number of lesions in the image.slice_thickness: Thickness of each B-scan in mm.pixel_spacing_column: Spacing between columns in mm.
Returns Distance from the image centre to the nearest lesion in mm.
init_model_for_inference
def init_model_for_inference(model: Any) ‑> None:Initialise a model for inference without binding any data.
Calls model.initialise_model() with no datasource so that the
model's internal create_model() and weight-loading logic runs,
but no BitfountDataBunch or dataloaders are created.
After this call you can assign model.test_dl directly and run
model._pl_trainer.test().
Arguments
model: A Bitfount model instance (already has weights loaded viadeserialize).
lesion_metrics_from_cache
def lesion_metrics_from_cache( accessor: Any,) ‑> dict[str, LesionMetrics | None]:Rebuild a filename→LesionMetrics map from a lesion_calculation cache.
Typed wrapper over the shared metrics_from_cache for the area
background-phase calc cache, mapping an uncomputable file (null
metrics_json) to None.
Arguments
accessor: ACacheAccessorfor thelesion_calculationcache partition.
Returns
A {file_id: LesionMetrics | None} map.
metrics_from_cache
def metrics_from_cache( cache_df: pandas.core.frame.DataFrame, metrics_type: type[~_MetricT], keep: collections.abc.Collection[str] | None = None,) ‑> dict[str, typing.Optional[~_MetricT]]:Reconstruct a {file_id: metrics instance | None} map from a cache frame.
The single shared reader for every cache-backed sink (GA via
ga_metrics_from_cache, plus the biomarker_tabulation CST/GCC/fluid
builders). Reads each row's schemaless metrics_json blob (via
metrics_json_by_file_id) and rebuilds metrics_type from it directly — the
blob's keys match the dataclass's fields one-to-one (GA persists asdict
minus the raw probability arrays; CST/GCC/fluid persist their to_record()).
A null blob (an uncomputable file) maps to None.
Reconstruction is TOLERANT: the calc caches are task_hash-scoped and
upsert-only (never pruned), so a row written by an older app version can
outlive a change to its dataclass. A blob whose keys no longer match the
current fields is logged and mapped to None (treated as uncomputable)
rather than raising TypeError and aborting the whole step over one file.
Arguments
cache_df: The metric step's cache partition frame (file_id+metrics_jsoncolumns).metrics_type: The metrics dataclass to reconstruct (e.g.CSTMetrics).keep: If given, only thesefile_ids are reconstructed; others are skipped entirely (not just dropped later), so a caller that knows its selection avoids reconstructing an unbounded never-pruned partition.
Returns
A {file_id: metrics_type instance | None} map, insertion-ordered by the
cache frame's rows.
metrics_json_by_file_id
def metrics_json_by_file_id( cache_df: pandas.core.frame.DataFrame,) ‑> dict[str, dict[str, typing.Any] | None]:Map file_id → its metrics_json dict (or None) from a cache frame.
The single reader of a scan-metrics cache partition's schemaless
metrics_json blob, shared by every cache-backed sink (ga_metrics_from_cache
here and the biomarker_tabulation builders). A row whose metrics_json is
null (an uncomputable file the calculation skipped/failed) maps to None;
the caller decides what an absent metric becomes (a reconstructed dataclass,
an all-NA row, ...). An empty frame — or one without a file_id column —
yields an empty map.
Arguments
cache_df: A scan-metrics cache partition frame (file_id+metrics_jsoncolumns), e.g. fromCacheAccessor.to_dataframe().
Returns
A {file_id: metrics_json_dict | None} map, insertion-ordered by the
frame's rows.
parse_bscan_predictions
def parse_bscan_predictions( bscan_prediction_strs: tuple[str, ...], slice_thickness: float, pixel_spacing_column: float, all_segmentation_labels: dict[str, int], ga_area_include_segmentations: list[str], ga_area_exclude_segmentations: list[str],) ‑> ParsedBScanPredictions:Parse raw B-scan prediction strings into columnar masks and probabilities.
This function was extracted from _WorkerSide._parse_bscan_predictions in
ga_trial_calculation_algorithm_base.py. The only change is that
configuration values (segmentation labels) are passed as explicit parameters
instead of being read from self.
Arguments
bscan_prediction_strs: Tuple of JSON prediction strings, one per B-scan.slice_thickness: Thickness of each B-scan in mm.pixel_spacing_column: Spacing between columns in mm.all_segmentation_labels: Mapping of segmentation class name → index.ga_area_include_segmentations: Segmentations used to include GA area.ga_area_exclude_segmentations: Segmentations used to exclude GA area.
Returns
A ParsedBScanPredictions containing columnar masks, class
probabilities, and class areas per B-scan.
parse_mask_json
def parse_mask_json( json_data: Any, labels: dict[str, int],) ‑> numpy.ndarray[typing.Any, typing.Any]:Parse segmentation mask(s) from JSON.
Arguments
json_data: The model output JSON data for the masks.labels: The segmentation classes to generate masks for mapped to their index in the mask data.
Returns
A (num_segmentations, image_height, image_width) uint8 array valued
1 where a class is present and 0 elsewhere.
resolve_output_path
def resolve_output_path( datasource: BaseSource,) ‑> str:Resolve the output directory for reports.
Looks for datasource.out_path (the datasource's configured output_path
kwarg, or settings.paths.cache_dir by default). Falls back to
<cwd>/prefect_reports if unavailable.
run_inference
def run_inference( model: Any, datasource: FileSystemIterableSource, schema: BitfountSchema, datastructure: DataStructure, batch_size: int | None = None,) ‑> PredictReturnType:End-to-end inference: init model, build dataloader, predict.
Composes init_model_for_inference, create_inference_dataloader,
and the model's prediction machinery into a single call.
Arguments
model: A Bitfount model instance with weights loaded.datasource: The datasource to run inference on.schema: A populatedBitfountSchema.datastructure: A configuredDataStructure.batch_size: Batch size for inference.
Returns
PredictReturnType (preds + keys).
Notes Some Hub models aggregate a whole forward batch into a single prediction (e.g. exam-level ophthalmology models). Run at a batch size
1, they emit fewer predictions than input records, tripping the "predictions vs keys" contract check. Since we cannot edit those models (they are fetched from the Hub), we run optimistically at the requested
batch_sizeand, only if that contract fails, transparently retry the same chunk at one record per forward batch — the size at which no model can collapse per-record results. Well-behaved models never hit the retry, so they keep their throughput.
supplied_observations_from_cache
def supplied_observations_from_cache(accessor: Any) ‑> pandas.core.frame.DataFrame:Build the patient-grain supplied-observations frame.
The patient id is emitted under EHR_BITFOUNT_PATIENT_ID_COL so the
existing patient_data merge renames and joins it unchanged.
Arguments
accessor: ACacheAccessorfor thepatient_enrichmentpartition.
Returns A frame with one row per patient: the bitfount patient id and that patient's list of observation entries. Empty (with both columns present) when the partition holds no rows.
use_default_rename_columns
def use_default_rename_columns( datasource: Any, rename_columns: collections.abc.Mapping[str, str] | None = None,) ‑> collections.abc.Mapping[str, str] | None:Sets the default columns to include based on the datasource.