Welcome to the documentation for DVHA MLC Analyzer!

DVHA MLC Analyzer

DVHA logo

build Documentation Status PyPI PyPI lgtm lgtm code quality Codecov Lines of code Repo Size Code style: black

Batch analyze DICOM-RT Plan files to calculate complexity scores

DVH Analytics (DVHA) is a software application for building a local database of radiation oncology treatment planning data. It imports data from DICOM-RT files (i.e., plan, dose, and structure), creates a SQL database, provides customizable plots, and provides tools for generating linear, multi-variable, and machine learning regressions.

DVHA-MLCA is a stand-alone command-line script to batch analyze DICOM-RT Plans using the MLC Analyzer code from DVHA.

Complexity score based on: Younge KC, Matuszak MM, Moran JM, McShan DL, Fraass BA, Roberts DA. Penalization of aperture complexity in inversely planned volumetric modulated arc therapy. Med Phys. 2012;39(11):7160–70.

Installation

To install via pip:

$ pip install dvha-mlca

If you’ve installed via pip or setup.py, launch from your terminal with:

$ mlca <init-scanning-directory>

If you’ve cloned the project, but did not run the setup.py installer, launch DVHA-MLCA with:

$ python mlca/main.py <init-scanning-directory>

Command line usage

usage: mlca [-h] [-of OUTPUT_FILE] [-xw COMPLEXITY_WEIGHT_X]
            [-yw COMPLEXITY_WEIGHT_Y] [-xs MAX_FIELD_SIZE_X]
            [-ys MAX_FIELD_SIZE_Y] [-ver] [-v] [-n PROCESSES]
            [init_dir]

Command line DVHA MLC Analyzer

positional arguments:
  init_dir              Directory containing DICOM-RT Plan files

optional arguments:
  -h, --help            show this help message and exit
  -of OUTPUT_FILE, --output-file OUTPUT_FILE
                        Output will be saved as
                        dvha_mlca_<version>_results_<time-stamp>.csv by
                        default.
  -xw COMPLEXITY_WEIGHT_X, --x-weight COMPLEXITY_WEIGHT_X
                        Complexity coefficient for x-dimension: default = 1.0
  -yw COMPLEXITY_WEIGHT_Y, --y-weight COMPLEXITY_WEIGHT_Y
                        Complexity coefficient for y-dimension: default = 1.0
  -xs MAX_FIELD_SIZE_X, --x-max-field-size MAX_FIELD_SIZE_X
                        Maximum field size in the x-dimension: default = 400.0
                        (mm)
  -ys MAX_FIELD_SIZE_Y, --y-max-field-size MAX_FIELD_SIZE_Y
                        Maximum field size in the y-dimension: default = 400.0
                        (mm)
  -ver, --version       Print the DVHA-MLCA version
  -v, --verbose         Print final results and plan summaries as they are
                        analyzed
  -n PROCESSES, --processes PROCESSES
                        Enable multiprocessing, set number of parallel
                        processes

For example:

$ mlca "C:\PatientDicom" -n 8
Directory: C:\PatientDicom
Begin file tree scan ...
File tree scan complete
Searching for DICOM-RT Plan files ...
     100%|██████████████████████████████| 9087/9087 [00:59<00:00, 153.52it/s]
1650 DICOM-RT Plan file(s) found
Analyzing 1650 file(s) ...
      10%|███                           | 169/1650 [02:02<13:35,  1.82it/s]

Dependencies

Support

If you like DVHA-MLCA and would like to support our mission, all we ask is that you cite us if we helped your publication, or help the DVHA community by submitting bugs, issues, feature requests, or solutions on the issues page.

Cite

DOI: https://doi.org/10.1002/acm2.12401 Cutright D, Gopalakrishnan M, Roy A, Panchal A, and Mittal BB. “DVH Analytics: A DVH database for clinicians and researchers.” Journal of Applied Clinical Medical Physics 19.5 (2018): 413-427.

Usage

Plan Summary

A simple example is below. Check out the module references for details about every method and property available.

>>> from mlca.mlc_analyzer import Plan
>>> plan = Plan('rtplan.dcm')
>>> plan

Output will look like:

Patient Name:        ANON11264
Patient MRN:         ANON11264
Study Instance UID:  2.16.840.1.114362.1.6.7.4.17517.7693757184.462857971.1073.8123
TPS:                 ADAC Pinnacle3
Plan name:           ANON
# of Fx Group(s):    3
Plan MUs:            776.1, 659.2, 512.3
Beam Count(s):       9, 9, 8
Control Point(s):    140, 120, 100
Complexity Score(s): 1.274, 1.290, 1.127

Beam Data

You can access specific beam information. Some examples are shown below.

>>> beam = plan.fx_group[0].beam[0]
>>> beam.area
    [16172.0, 16172.0, 13398.0, 13398.0, 428.0, 428.0, 787.0, 787.0, 582.0,
    582.0, 1728.0, 1728.0, 3479.0, 3479.0, 502.0, 502.0, 8587.0, 8587.0]
>>> beam.gantry_angle
    [200.0]
>>> beam.meter_set
    90.199996948242
>>> beam.younge_complexity_scores
    array([0.0081077 , 0.        , 0.00878864, 0.        , 0.01600782,
           0.        , 0.02859258, 0.        , 0.02102578, 0.        ,
           0.01606121, 0.        , 0.01505108, 0.        , 0.01389648,
           0.        , 0.0075811 , 0.        ])

dvha-stats

MLC Analyzer

Tools for analyzing beam and control point information from DICOM files Hierarchy of classes: Plan -> FxGroup -> Beam -> ControlPoint

class mlca.mlc_analyzer.Beam(beam_dataset, meter_set, ignore_zero_mu_cp=False, **kwargs)[source]

Bases: object

Collect beam information from a beam in a beam sequence of a pydicom RT Plan dataset. Automatically parses control point data with ControlPoint class

Parameters
  • beam_dataset (Dataset) – element of a BeamSequence (300A,00B0)

  • meter_set (int, float) – the monitor units for beam_dataset

  • ignore_zero_mu_cp (bool) – If True, skip over zero MU control points (e.g., as in Step-N-Shoot beams)

property aperture

Get aperture shapely object for every control point

Returns

ControlPoint.aperture for each control point

Return type

list

property area

Get aperture area for every control point

Returns

ControlPoint.area for each control point

Return type

list

property collimator_angle

Collimator angles for each control point

Returns

A list of float values, defining collimator angles for each control point

Return type

list

property couch_angle

Couch angles for each control point

Returns

A list of float values, defining couch angles for each control point

Return type

list

property cp_count

Get the number of control points in this beam

Returns

Length of ControlPointSequence (300A,0111)

Return type

int

property cp_mu

MU for each control point

Returns

Numpy array of control point MUs

Return type

np.ndarray

property cp_seq

Get the control points

Returns

ControlPointSequence (300A,0111)

Return type

Dataset

property cum_mu

Cumulative monitor units for each control point

Returns

A list of float values representing the cumulative MU

Return type

list

property gantry_angle

Gantry angles for each control point

Returns

A list of float values, defining gantry angles for each control point

Return type

list

property jaws

Jaw positions for each control point

Returns

Each element is a ControlPoint.jaws dict

Return type

list

property leaf_boundaries

Get the leaf boundaries

Returns

LeafPositionBoundaries (300A,00BE)

Return type

DataSet

property mlc_borders

Get the MLC border for each control point

Returns

A list of ControlPoint.mlc_borders describing the boundaries of each leaf

Return type

list

property name

Get the Beam name

Returns

In order of priority, BeamDescription (300A,00C3), BeamName (300A,00C2), or “Unknown”

Return type

str

property perimeter

Get aperture perimeter for every control point

Returns

ControlPoint.perimeter for each control point

Return type

list

property perimeter_x

Get x-component of aperture perimeter for every control point

Returns

ControlPoint.perimeter_x for each control point

Return type

list

property perimeter_y

Get y-component of aperture perimeter for every control point

Returns

ControlPoint.perimeter_y for each control point

Return type

list

property younge_complexity_scores

Complexity score based on Younge et al

Returns

Younge complexity scores for each control point

Return type

np.ndarray

class mlca.mlc_analyzer.ControlPoint(cp_elem, leaf_boundaries, **kwargs)[source]

Bases: object

Collect control point information from a ControlPointSequence in a beam dataset of a pydicom RT Plan dataset

Parameters
  • cp_elem (DataElement) – element of a ControlPointSequence (300A,0111)

  • leaf_boundaries (Dataset) – LeafPositionBoundaries (300A,00BE)

property aperture

This function will return the outline of MLCs within jaws

Returns

a shapely object of the complete MLC aperture as one shape (including MLC overlap)

Return type

Polygon

property cum_mu

Cumulative MU for this ControlPoint

Returns

CumulativeMetersetWeight (300A,0134)

Return type

float

property jaws

Get the jaw positions of a control point

Returns

jaw positions (or max field size in lieu of a jaw). Keys are ‘x_min’, ‘x_max’, ‘y_min’, ‘y_max’

Return type

dict

property leaf_type

Get the MLC orientation

Returns

Returns ‘mlcx’, ‘mlcy’ or None

Return type

str, None

property mlc

Get the MLC orientation

Returns

Returns ‘mlcx’, ‘mlcy’ or None

Return type

str, None

property mlc_borders

This function returns the boundaries of each MLC leaf for purposes of displaying a beam’s eye view using bokeh’s quad() glyph

Returns

the boundaries of each leaf within the control point with keys of ‘top’, ‘bottom’, ‘left’, ‘right

Return type

dict

property perimeter

Perimeter of the aperture

Returns

Aperture perimeter

Return type

float

property perimeter_x

x-component of the aperture perimeter

Returns

x-component of the Aperture perimeter

Return type

float

property perimeter_y

y-component of the aperture perimeter

Returns

y-component of the Aperture perimeter

Return type

float

class mlca.mlc_analyzer.FxGroup(fx_grp_seq, plan_beam_sequences, **kwargs)[source]

Bases: object

Collect fraction group information from fraction group and beam sequences of a pydicom RT Plan dataset. Automatically parses beam data with Beam class

Parameters
  • fx_grp_seq (Dataset) – element of FractionGroupSequence (300A,0070)

  • plan_beam_sequences (BeamSequence) – BeamSequence (300A,00B0)

property beam_count

Get the number of beams

Returns

Length of FxGroup.beams

Return type

int

property beam_mu

Get the monitor units for each beam

Returns

Beam.meter_set for each beam

Return type

list

property beam_names

Get the beam names

Returns

Beam.name for each beam

Return type

list

property cp_counts

Get the number of control points for all beams

Returns

Beam.cp_count for each beam

Return type

list

property fx_mu

Get the number of MU for for this fraction

Returns

The sum of FxGroup.beam_mu

Return type

float

update_missing_jaws()[source]

In plans with static jaws, jaw positions may not be found in each control point

property younge_complexity_score

Get the Younge complexity score this fraction

Returns

The sum of Beam.younge_complexity_scores for all beams

Return type

float

class mlca.mlc_analyzer.Plan(rt_plan, **kwargs)[source]

Bases: object

Collect plan information from an RT Plan DICOM file. Automatically parses fraction data with FxGroup class

Parameters

rt_plan (str, Dataset) – file path of a DICOM RT Plan file or a pydicom Dataset

property patient_id

Get the patient id

Returns

PatientID (0010,0020)

Return type

str

property patient_name

Get the patient name

Returns

PatientName (0010,0010)

Return type

str

property plan_name

Get the plan name

Returns

RTPlanLabel (300A,0002)

Return type

str

property sop_instance_uid

Get the patient study instance UID

Returns

SOPInstanceUID (0008,0018)

Return type

str

property study_instance_uid

Get the patient study instance UID

Returns

StudyInstanceUID (0020,000D)

Return type

str

property tps

Get the treatment planning system

Returns

Manufacturer (0008,0070) and ManufacturerModelName (0008,1090)

Return type

str

property younge_complexity_scores

Get the Younge complexity scores for each FxGroup

Returns

FxGroup.younge_complexity_score for each fraction group

Return type

list

class mlca.mlc_analyzer.PlanSet(file_paths, verbose=False, processes=1, **kwargs)[source]

Bases: object

Parse DICOM-RT Plan files, analyze MLCs

Parameters
  • file_paths (list) – A list of file paths to DICOM-RT Plan files

  • verbose (bool, optional) – Set to true to print detailed information (ignored if multiprocessing enabled)

  • processes (int) – Number of parallel processes allowed

mlca.mlc_analyzer.get_options(over_rides)[source]

Get MLC Analyzer options

Parameters

over_rides (dict) – Over rides, keys may be ‘max_field_size_x’, ‘max_field_size_y’, ‘complexity_weight_x’, or ‘complexity_weight_y’

Returns

Options for field size and complexity weights. Default values are 400 and 1.

Return type

dict

Utilities

Utilities for DVHA-MLCA

mlca.utilities.create_cmd_parser()[source]

Get an argument parser for mlca.main

Returns

argument parser

Return type

argparse.ArgumentParser

mlca.utilities.flatten_list_of_lists(some_list, remove_duplicates=False, sort=False)[source]

Convert a list of lists into one list of all values

Parameters
  • some_list (list) – a list such that each element is a list

  • remove_duplicates (bool, optional) – if True, return a unique list, otherwise keep duplicated values

  • sort (bool, optional) – if True, sort the list

Returns

A new list containing all values in some_list

Return type

list

mlca.utilities.get_default_output_filename()[source]

Get the default output file name for mlca.main.process

Returns

dvha_mlca_<version>_results_<timestamp>.csv

Return type

str

mlca.utilities.get_dicom_files(file_paths, modality=None, verbose=False, processes=1)[source]

Find all DICOM-RT Plan files in a list of file paths

Parameters
  • file_paths (list) – A list of file paths

  • modality (str, optional) – Specify Modality (0008,0060)

  • verbose (bool, optional) – Print results to terminal

  • processes (int) – Number of processes for multiprocessing.

Returns

Absolute file paths to DICOM-RT Plans

Return type

list

mlca.utilities.get_file_paths(init_dir)[source]

Find all files in a directory and sub-directories

Parameters

init_dir (str) – Top-level directory to search for files

Returns

Absolute file paths

Return type

list

mlca.utilities.get_xy_path_lengths(shapely_object)[source]

Get the x and y path lengths of a Shapely object

Parameters

shapely_object (GeometryCollection, MultiPolygon, Polygon) – A shapely polygon-like object

Returns

Perimeter lengths in the x and y directions

Return type

list

mlca.utilities.is_file_dicom(file_path, modality=None, verbose=False)[source]
Parameters
  • file_path (str) – File path to potential DICOM file

  • modality (str, optional) – Return False if file is not this Modality (0008,0060)

  • verbose (bool, optional) – Print results to terminal

Returns

True if file_path points to a DICOM file, will return False if SOPClassUID (0008,0016) is not found

Return type

bool

mlca.utilities.run_multiprocessing(worker, queue, processes)[source]

Parallel processing

Parameters
  • worker (callable) – single parameter function to be called on each item in queue

  • queue (iterable) – A list of arguments for worker

  • processes (int) – Number of processes for multiprocessing.Pool

Returns

List of returns from worker

Return type

list

mlca.utilities.write_csv(file_path, rows, mode='w', newline='')[source]

Create csv.writer, call writerows(rows)

file_pathstr

path to file

rowslist, iterable

Items to be written to file_pointer (input for csv.writer.writerows)

modestr

optional string that specifies the mode in which the file is opened

newlinestr

controls how universal newlines mode works. It can be None, ‘’, ‘

‘, ‘ ‘, and ‘ ‘

Credits

Development Lead

  • Dan Cutright

History

v0.2.3 (2021.01.27)

  • Use csv standard library for CSV writing

v0.2.2 (2021.01.16)

  • Multiprocessing support

v0.2.1 (2021.01.15)

  • Fixed issue preventing main run from command line

  • Support for large scale analysis, don’t store full pydicom datasets

  • Added SOPInstanceUID to summary

  • Keyboard Interrupt (CTRL+C) during analysis (after file collection) will write the partial results

v0.2 (2020.12.23)

v0.1rc1 (2020.06.15)

  • Initial release

Indices and tables