PyPlanAnalysis.plan

Main user-facing API: PatientPlan loads DICOM data and runs the analysis; AnalysisResults holds the metrics, plots, and NTCP outputs and exports them.

PyPlanAnalysis.plan

Main user-facing API: PatientPlan (loads DICOM data and runs the analysis) and AnalysisResults (metrics, plots, NTCP, and exports). See the project README for usage examples.

class PatientPlan(patient_id=None, plan_file=None, dose_file=None, let_file=None, rtstruct=None, CT_folder_path=None, n_fractions=None)[source]

Bases: object

Represents a single patient’s proton therapy plan.

Parameters:
  • patient_id (str) – Identifier used in output filenames and CSV column.

  • dose_file (str or Path) – DICOM RT Dose file containing physical dose [Gy].

  • let_file (str or Path) – DICOM RT Dose file containing LETd [keV/µm] stored as dose grid.

  • rtstruct (str or Path) – DICOM RT Struct file.

  • CT (str or Path) – folder of DICOM CT files

  • method (Class)

  • ------------

  • PatientPlan.from_folder(folder – Auto-discover DICOM files from a folder.

  • patient_id=None) – Auto-discover DICOM files from a folder.

  • plan_file (str | Path | None)

  • CT_folder_path (str | Path | None)

  • n_fractions (int | None)

classmethod from_folder(folder, n_fractions=None, rad_type='PROTON')[source]

Create a PatientPlan by auto-discovering DICOM files in folder.

Parameters:
  • folder (path containing .dcm files)

  • patient_id (if None, uses the folder name)

  • n_fractions (int | None)

  • rad_type (str)

Return type:

PatientPlan

load()[source]

Load and cache all DICOM data. Called automatically by analyse().

property structure_names: list

List of all structure names in the RT Struct.

property voxel_volume_cc: float

Volume of one dose voxel in cc.

get_roi_mask(struct_name, rtstruct_ds, grid_origin, grid_spacing, grid_shape, grid_z_positions, use_fractional=False, supersample=4, max_supersample=12)[source]
build_alpha_beta_map(rtstruct_ds, structures, grid_origin, grid_spacing, grid_shape, grid_z_positions, radiobio_cfg, use_fractional, supersample, max_supersample)[source]
compute_vRBE(model, structures=None, metric_cfg=None, radiobio_cfg=None, resample_on_CT=False, resample_on_custom_grid=False, use_fractional=False, supersample=4, max_supersample=12)[source]

Compute a voxel-wise variable-RBE dose volume for the whole patient grid. It Works independently of analyse() — no DVH metrics are computed, only the 3D RBE-weighted dose map and the α/β map used to produce it. It works independetly of RBEConfig

Parameters:
  • model (str — RBE model to apply: "linear", "mcnamara", "wedenberg", or "carabe")

  • structures (list of structure name strings used to build the α/β map, or None (= all).) – Voxels not inside any listed structure receive the default α/β.

  • metric_cfg (MetricConfig — only New_grid is used, when resample_on_custom_grid=True)

  • radiobio_cfg (RadiobiologyConfig — supplies per-structure α/β values and overlap) – priority for building the voxel-wise α/β map

  • resample_on_CT (if True, resample dose and LET onto the CT grid before computing RBE.) – Requires CT to have been loaded (ct_dir passed to PatientPlan)

  • resample_on_custom_grid (if True, resample dose and LET onto the isotropic grid defined) – by metric_cfg.New_grid [mm]. Mutually exclusive with resample_on_CT.

  • use_fractional (if True, use fractional voxel membership for the α/β map boundary voxels.) – More accurate for small structures. Default: False.

  • supersample (baseline in-plane supersampling factor (N×N sub-points per voxel).) – Only used when use_fractional=True. Scaled up automatically for small structures — see io._adaptive_supersample. Default: 4.

  • max_supersample (hard cap on the adaptive in-plane supersampling factor, to bound) – compute cost for very small ROIs. Default: 12.

Returns:

  • vRBEResults

  • A container holding the 3D vRBE dose array, the α/β map, grid geometry,

  • and a to_nii() method to save both volumes as NIfTI files.

analyse(structures=None, rbe_cfg=None, metric_cfg=None, radiobio_cfg=None, resample_on_CT=False, resample_on_custom_grid=False, use_fractional=False, supersample=4, max_supersample=12)[source]

Run the full analysis pipeline for this patient.

Parameters:
  • structures (list of structure name strings, or None (= all))

  • rbe_cfg (RBEConfig (default: all three models, RBE=1.1))

  • metric_cfg (MetricConfig (default values))

  • radiobio_cfg (RadiobiologyConfig (default per-tissue α/β and gEUD-a))

  • resample (if True, interpolate dose values to the new spacing defined in MetricConfig)

  • use_fractional (if True, use fractional voxel membership mask instead) – of binary mask. More accurate for small structures. Each voxel is weighted by the fraction of its volume inside the contour. Default: False.

  • supersample (baseline in-plane supersampling factor (N x N sub-points) – per voxel). Only used when use_fractional=True. Scaled up automatically for small structures — see io._adaptive_supersample. Default: 4.

  • max_supersample (hard cap on the adaptive in-plane supersampling) – factor, to bound compute cost for very small ROIs.

  • resample_on_CT (bool)

  • resample_on_custom_grid (bool)

Return type:

AnalysisResults

Returns:

AnalysisResults

class AnalysisResults(patient_id, metrics_df, dvh_data, lvh_data, dlvh_data_diff, dlvh_data_cum)[source]

Bases: object

Container for all outputs from PatientPlan.analyse().

Parameters:
  • patient_id (str)

  • metrics_df (DataFrame)

  • dvh_data (dict)

  • lvh_data (dict)

  • dlvh_data_diff (dict)

  • dlvh_data_cum (dict)

patient_id
Type:

str

metrics_df
Type:

pd.DataFrame – all DVH/LVH metrics, one row per structure

dvh_data
Type:

dict {struct: {dose_type: (edges, cum)}} e.g. # {“CTV”: {“Physical”: (edges, cum), “RBE×1.1”: (edges, cum), …}, “Brainstem”: {“Physical”: (edges, cum), …},

lvh_data
Type:

dict {struct: (edges, cum)}

dlvh_data
Type:

dict {struct: (H, dose_edges, let_edges)}

CalcNTCP(NTCPConfig, path_models_xls=None)[source]
Parameters:
to_csv(path=None)[source]

Save metrics to CSV.

Parameters:

path (output path. Default: "<patient_id>/dvh_metrics.csv")

Return type:

Path

to_excel(path=None)[source]

Save metrics to Excel (.xlsx).

Parameters:

path (output path. Default: "<patient_id>/dvh_metrics.xlsx")

Return type:

Path

plot_dvh(save=None, dpi=350)[source]

Generate DVH curve figures.

Creates one figure per dose type (Physical, RBE×1.1, each model) showing all structures, PLUS one per-structure comparison figure.

Parameters:
  • save (path for output PDF. Default: "<patient_id>/dvh_curves.pdf")

  • dpi (figure DPI)

Return type:

list

Returns:

list of matplotlib Figures

plot_lvh(save=None, dpi=150)[source]

Generate LVH curve figure (all structures on one plot).

Parameters:
  • save (path for output PDF. Default: "<patient_id>/lvh_curves.pdf")

  • dpi (int)

Return type:

Figure

Returns:

matplotlib Figure

plot_dlvh(save=None, dpi=150)[source]

Generate 2-D DLVH figures – one PNG per structure.

Parameters:
  • save (output directory. Default: "<patient_id>/dlvh_2d/")

  • dpi (int)

Return type:

list

Returns:

list of (structure_name, Path) tuples

save_all(output_dir=None, csv_name='dvh_metrics.csv', excel_name='dvh_metrics.xlsx', dpi=150)[source]

Convenience method: save CSV, Excel, DVH PDF, LVH PDF, DLVH PNGs.

Parameters:
  • output_dir (base output directory. Default: patient_id/)

  • csv_name (filename for the CSV output)

  • excel_name (filename for the Excel output)

  • dpi (figure DPI for all plots)

class vRBEResults(patient_id, model, dose_arr, let_arr, vRBE, ab_map, geom)[source]

Bases: object

Container for all outputs from PatientPlan.compute_vRBE().

Parameters:
  • patient_id (str)

  • model (str)

  • dose_arr (ndarray)

  • let_arr (ndarray)

  • vRBE (ndarray)

  • ab_map (ndarray)

  • geom (dict)

patient_id
Type:

str

model
Type:

str

dose_arr
Type:

np.array(), of 1.1-weighted dose

let_arr
Type:

np.array(), of Let in kev/um

vRBE
Type:

np.array (float) of variablRBE-weighted dose

ab_map
Type:

np.array (int)?

geom
Type:

dict (órigin,spacing) in (x,y,z). Reminder: SimpleITK uses x-y-z. Numpy uses z-y-x.

to_nii(path, name_vRBE='vRBE.nii.gz', name_ab='ab_map.nii.gz', name_cRBE='cRBE.nii.gz', name_let='LETd.nii.gz')[source]

Save vRBE dose and α/β map as NIfTI files.

Parameters:
  • path (output directory (created if it does not exist))

  • name_vrbe (filename for the vRBE dose volume)

  • name_ab (filename for the α/β map volume)

  • name_vRBE (str)

  • name_cRBE (str)

  • name_let (str)

Return type:

None