pydicom command-line interface

# Command-line Interface Guide

Added in version 2.2.

## Introduction

Starting in v2.2, pydicom offers a useful command-line interface (CLI) for exploring DICOM files, and access to the codify option for creating pydicom Python code. Additional subcommands may be added over time.

Example at the command line in a terminal window:

    $ pydicom show pydicom::rtplan.dcm
    Dataset.file_meta -------------------------------
    (0002, 0000) File Meta Information Group Length  UL: 156
    (0002, 0001) File Meta Information Version       OB: b'\x00\x01'
    (0002, 0002) Media Storage SOP Class UID         UI: RT Plan Storage
    (0002, 0003) Media Storage SOP Instance UID      UI: 1.2.999.999.99.9.9999.9999.20030903150023
    (0002, 0010) Transfer Syntax UID                 UI: Implicit VR Little Endian
    (0002, 0012) Implementation Class UID            UI: 1.2.888.888.88.8.8.8
    -------------------------------------------------
    (0008, 0012) Instance Creation Date              DA: '20030903'
    (0008, 0013) Instance Creation Time              TM: '150031'
    (0008, 0016) SOP Class UID                       UI: RT Plan Storage
    (0008, 0018) SOP Instance UID                    UI: 1.2.777.777.77.7.7777.7777.20030903150023
    (0008, 0020) Study Date                          DA: '20030716'
    ...

Note that prefixing the file specification with `pydicom::` will read the file from the pydicom test data files rather than from the normal file system. The following examples will use that so that you can replicate these examples exactly. In normal use, you would leave the `pydicom::` prefix off when working with your files.

You can also show just parts of the DICOM file by specifying a data element using the usual pydicom keyword notation:

    $ pydicom show pydicom::rtplan.dcm::FractionGroupSequence[0]
    (300a, 0071) Fraction Group Number               IS: "1"
    (300a, 0078) Number of Fractions Planned         IS: "30"
    (300a, 0080) Number of Beams                     IS: "1"
    (300a, 00a0) Number of Brachy Application Setups IS: "0"
    (300c, 0004)  Referenced Beam Sequence  1 item(s) ----
    (300a, 0082) Beam Dose Specification Point       DS: [239.531250000000, 239.531250000000, -751.87000000000]
    (300a, 0084) Beam Dose                           DS: "1.0275401"
    (300a, 0086) Beam Meterset                       DS: "116.0036697"
    (300c, 0006) Referenced Beam Number              IS: "1"
    ---------

You can see the available subcommands by simply typing `pydicom` with no arguments, or with `pydicom help`:

    $ pydicom help
    Use pydicom help [subcommand] to show help for a subcommand
    Available subcommands: codify, show

And, as noted in the block above, you get help for a particular subcommand by typing `pydicom help [subcommand]`. For example:

    $ pydicom help show
    usage: pydicom show [-h] [-x] [-t] [-q] filespec

    Display all or part of a DICOM file

    positional arguments:
    filespec              File specification, in format [pydicom::]filename[::element]. If `pydicom::`
                            prefix is used, then show the pydicom test file with that name. If `element`
                            is given, use only that data element within the file. Examples:
                            path/to/your_file.dcm, your_file.dcm::StudyDate,
                            pydicom::rtplan.dcm::BeamSequence[0], yourplan.dcm::BeamSequence[0].BeamNumber

    optional arguments:
    -h, --help            show this help message and exit
    -x, --exclude-private
                            Don't show private data elements
    -t, --top             Only show top level
    -q, --quiet           Only show basic information

### Installing the pydicom CLI

The `pydicom` command should automatically be available after you pip install pydicom. It should not require any updates to the system path or environment variables.

If you are helping develop pydicom code, and are using git clones, you will have to `pip install -e .` or `python setup.py develop` from the pydicom repository root. This has to be repeated for any changes to setup.py (e.g. to add a new subcommand).

If you are developing subcommands within your own package, you will need to reinstall your package similar to the above as you add entry points.

### Combining with other CLIs

CLIs are useful for general exploration while programming, but also can be combined with other command-line filters for additional functionality. The following is an example of piping the output of the pydicom ‘show’ subcommand into ‘grep’, filtering for lines with either “Dose” or “Sequence” in them:

    $ pydicom show pydicom::rtplan.dcm | grep "Dose\|Sequence"
    (300a, 0010)  Dose Reference Sequence  2 item(s) ----
    (300a, 0012) Dose Reference Number               IS: "1"
    (300a, 0014) Dose Reference Structure Type       CS: 'COORDINATES'
    (300a, 0016) Dose Reference Description          LO: 'iso'
    (300a, 0018) Dose Reference Point Coordinates    DS: [239.531250000000, 239.531250000000, -741.87000000000]
    (300a, 0020) Dose Reference Type                 CS: 'ORGAN_AT_RISK'
    (300a, 0023) Delivery Maximum Dose               DS: "75.0"
    (300a, 002c) Organ at Risk Maximum Dose          DS: "75.0"
    (300a, 0012) Dose Reference Number               IS: "2"
    (300a, 0014) Dose Reference Structure Type       CS: 'COORDINATES'
    (300a, 0016) Dose Reference Description          LO: 'PTV'
    (300a, 0018) Dose Reference Point Coordinates    DS: [239.531250000000, 239.531250000000, -751.87000000000]
    (300a, 0020) Dose Reference Type                 CS: 'TARGET'
    (300a, 0026) Target Prescription Dose            DS: "30.826203"
    (300a, 0070)  Fraction Group Sequence  1 item(s) ----
    (300c, 0004)  Referenced Beam Sequence  1 item(s) ----
        (300a, 0082) Beam Dose Specification Point       DS: [239.531250000000, 239.531250000000, -751.87000000000]
        (300a, 0084) Beam Dose                           DS: "1.0275401"
    (300a, 00b0)  Beam Sequence  1 item(s) ----
    (300a, 00b6)  Beam Limiting Device Sequence  2 item(s) ----
    (300a, 0111)  Control Point Sequence  2 item(s) ----
        (300a, 0115) Dose Rate Set                       DS: "650.0"
        (300a, 011a)  Beam Limiting Device Position Sequence  2 item(s) ----
        (300c, 0050)  Referenced Dose Reference Sequence  2 item(s) ----
            (300a, 010c) Cumulative Dose Reference Coefficie DS: "0.0"
            (300c, 0051) Referenced Dose Reference Number    IS: "1"
            (300a, 010c) Cumulative Dose Reference Coefficie DS: "0.0"
            (300c, 0051) Referenced Dose Reference Number    IS: "2"
        (300c, 0050)  Referenced Dose Reference Sequence  2 item(s) ----
            (300a, 010c) Cumulative Dose Reference Coefficie DS: "0.9990268"
            (300c, 0051) Referenced Dose Reference Number    IS: "1"
            (300a, 010c) Cumulative Dose Reference Coefficie DS: "1.0"
            (300c, 0051) Referenced Dose Reference Number    IS: "2"
    (300a, 0180)  Patient Setup Sequence  1 item(s) ----
    (300c, 0002)  Referenced RT Plan Sequence  1 item(s) ----
    (300c, 0060)  Referenced Structure Set Sequence  1 item(s) ----

Using the “or Sequence” (``\|Sequence``) regular expression as above allows you to see any filtered results in relation to their parent Sequences.

See the pydicom show command section for more examples of the show command, its options, and the ability to show only data elements or sequences within the file.

## `pydicom show` command

The pydicom show command displays representation of DICOM files or parts of them from a command-line terminal.

Some examples were already given in the Introduction, but here we will show some additional options.

To see the available options, in a command-line terminal, type `pydicom help show` or `pydicom show -h`.

    $ pydicom help show
    usage: pydicom show [-h] [-x] [-t] [-q] filespec

    Display all or part of a DICOM file

    positional arguments:
    filespec              File specification, in format [pydicom::]filename[::element]. If `pydicom::`
                            prefix is present, then use the pydicom test file with that name. If `element`
                            is given, use only that data element within the file. Examples:
                            path/to/your_file.dcm, your_file.dcm::StudyDate,
                            pydicom::rtplan.dcm::BeamSequence[0], yourplan.dcm::BeamSequence[0].BeamNumber

    optional arguments:
    -h, --help            show this help message and exit
    -x, --exclude-private
                            Don't show private data elements
    -t, --top             Only show top level
    -q, --quiet           Only show basic information

The basic command with no options shows all data elements and nested sequences:

    $ pydicom show pydicom::CT_small.dcm
    Dataset.file_meta -------------------------------
    (0002, 0000) File Meta Information Group Length  UL: 192
    (0002, 0001) File Meta Information Version       OB: b'\x00\x01'
    (0002, 0002) Media Storage SOP Class UID         UI: CT Image Storage
    (0002, 0003) Media Storage SOP Instance UID      UI: 1.3.6.1.4.1.5962.1.1.1.1.1.20040119072730.12322
    (0002, 0010) Transfer Syntax UID                 UI: Explicit VR Little Endian
    (0002, 0012) Implementation Class UID            UI: 1.3.6.1.4.1.5962.2
    (0002, 0013) Implementation Version Name         SH: 'DCTOOL100'
    (0002, 0016) Source Application Entity Title     AE: 'CLUNIE1'
    -------------------------------------------------
    (0008, 0005) Specific Character Set              CS: 'ISO_IR 100'
    (0008, 0008) Image Type                          CS: ['ORIGINAL', 'PRIMARY', 'AXIAL']
    (0008, 0012) Instance Creation Date              DA: '20040119'
    (0008, 0013) Instance Creation Time              TM: '072731'
    (0008, 0014) Instance Creator UID                UI: 1.3.6.1.4.1.5962.3
    (0008, 0016) SOP Class UID                       UI: CT Image Storage
    (0008, 0018) SOP Instance UID                    UI: 1.3.6.1.4.1.5962.1.1.1.1.1.20040119072730.12322
    (0008, 0020) Study Date                          DA: '20040119'
    .
    .
    .
    (0043, 104b) [DAS xm pattern]                    SL: 0
    (0043, 104c) [TGGC trigger mode]                 SS: 0
    (0043, 104d) [Start scan to X-ray on delay]      FL: 0.0
    (0043, 104e) [Duration of X-ray on]              FL: 10.60060977935791
    (7fe0, 0010) Pixel Data                          OW: Array of 32768 elements
    (fffc, fffc) Data Set Trailing Padding           OB: Array of 126 elements

Note that prefixing the file specification with `pydicom::` will read the file from the pydicom test data files rather than from the file system.

You can also show just parts of the DICOM file by specifying a data element using the usual pydicom keyword notation:

    $ pydicom show pydicom::CT_small.dcm::PatientName
    CompressedSamples^CT1

    $ pydicom show pydicom::rtplan.dcm::FractionGroupSequence
    [(300a, 0071) Fraction Group Number               IS: "1"
    (300a, 0078) Number of Fractions Planned         IS: "30"
    (300a, 0080) Number of Beams                     IS: "1"
    (300a, 00a0) Number of Brachy Application Setups IS: "0"
    (300c, 0004)  Referenced Beam Sequence  1 item(s) ----
    (300a, 0082) Beam Dose Specification Point       DS: [239.531250000000, 239.531250000000, -751.87000000000]
    (300a, 0084) Beam Dose                           DS: "1.0275401"
    (300a, 0086) Beam Meterset                       DS: "116.0036697"
    (300c, 0006) Referenced Beam Number              IS: "1"
    ---------]

The `-q` quiet argument shows a minimal version of some of the information in the file, using just the DICOM keyword and value (not showing the tag numbers and VR). The example below shows the quiet mode with an image slice:

    pydicom show -q pydicom::ct_small.dcm

    SOPClassUID: CT Image Storage
    PatientName: CompressedSamples^CT1
    PatientID: 1CT1
    StudyID: 1CT1
    StudyDate: 20040119
    StudyTime: 072730
    StudyDescription: e+1
    BitsStored: 16
    Modality: CT
    Rows: 128
    Columns: 128
    SliceLocation: -77.2040634155

And the following example shows an RT Plan in quiet mode:

    pydicom show -q pydicom::rtplan.dcm

    SOPClassUID: RT Plan Storage
    PatientName: Last^First^mid^pre
    PatientID: id00001
    StudyID: study1
    StudyDate: 20030716
    StudyTime: 153557
    StudyDescription: N/A
    Plan Label: Plan1  Plan Name: Plan1
    Fraction Group 1  30 fraction(s) planned
    Brachy Application Setups: 0
    Beam 1 Dose 1.02754010000000 Meterset 116.003669700000
    Beam 1 'Field 1' TREATMENT STATIC PHOTON energy 6.00000000000000 gantry 0.0, coll 0.0, couch 0.0 (0 wedges, 0 comps, 0 boli, 0 blocks)

Quiet modes always show the SOP Class UID, patient and study information as shown in the above two examples. After those elements, custom values for different SOP classes are shown. Currently “Image Storage” and “RT Plan Storage” classes have custom extra information. Please submit an issue on the pydicom issues list or a pull request to help us expand the list of custom ‘quiet’ mode SOP Classes.

## `pydicom codify` command

The `pydicom codify` command takes a DICOM file and produces Python code to recreate that file, or, optionally a subset within that file.

See Using Codify for full details of writing a complete file. Here we will review the command-line options in more detail than in that section, and show how to export a dataset within a DICOM file that has sequences.

Warning

The code produced by `codify` will contain all the information in the original file, which may include private health information or other sensitive information.

### A simple example

A simple example of using the `codify` command would be:

    $ pydicom codify pydicom::rtplan.dcm

    # Coded version of DICOM file 'C:\git\pydicom\pydicom\data\test_files\rtplan.dcm'
    # Produced by pydicom codify utility script
    import pydicom
    from pydicom.dataset import Dataset, FileMetaDataset
    from pydicom.sequence import Sequence

    # Main data elements
    ds = Dataset()
    ds.InstanceCreationDate = '20030903'
    ds.InstanceCreationTime = '150031'
    ds.SOPClassUID = '1.2.840.10008.5.1.4.1.1.481.5'
    ds.SOPInstanceUID = '1.2.777.777.77.7.7777.7777.20030903150023'
    ds.StudyDate = '20030716'
    ds.StudyTime = '153557'
    .
    .
    .

Note that prefixing the file specification with `pydicom::` will read the file from the pydicom test data files rather than from the file system.

### Command options

In the above example, the output was directed to screen, because no output file was specified. To see the available command options, use the `help` command:

    pydicom help codify

    usage: pydicom codify [-h] [-e EXCLUDE_SIZE] [-p] [-s SAVE_AS] filespec [outfile]

    Read a DICOM file and produce the *pydicom* (Python) code which can create that file

    positional arguments:
    filespec              File specification, in format [pydicom::]filename[::element]. If `pydicom::`
                            prefix is used, then use the pydicom test file with that name. If `element`
                            is given, use only that data element within the file. Examples:
                            path/to/your_file.dcm, your_file.dcm::StudyDate,
                            pydicom::rtplan.dcm::BeamSequence[0],
                            yourplan.dcm::BeamSequence[0].BeamNumber
    outfile               Filename to write python code to. If not specified, code is written to
                            stdout

    optional arguments:
    -h, --help            show this help message and exit
    -e EXCLUDE_SIZE, --exclude-size EXCLUDE_SIZE
                            Exclude binary data larger than specified (bytes). Default is 100 bytes
    -p, --include-private
                            Include private data elements (default is to exclude them)
    -s SAVE_AS, --save-as SAVE_AS
                            Specify the filename for ds.save_as(save_filename); otherwise the input name
                            + '_from_codify' will be used

    Binary data (e.g. pixels) larger than --exclude-size (default 100 bytes) is not included. A dummy
    line with a syntax error is produced. Private data elements are not included by default.

For example:

    pydicom codify -s savename.dcm dicomfile.dcm pythoncode.py

would read the DICOM file “dicomfile.dcm” and write the Python code to file “pythoncode.py”. In that code, near the end of the file would be a `ds.save_as("savename.dcm", ...)` line.

Note

By default, any private data elements within the file are not translated to code. If you want to include them, use the `-p` parameter.

### Codifying a part of a DICOM file

Note that the `filespec` argument to the `codify` command, as for the show command, allows you to specify a data element within the file, rather than the whole file:

    pydicom codify pydicom::rtplan.dcm::FractionGroupSequence[0]

    # Coded version of non-file dataset
    ...

    # Main data elements
    ds = Dataset()
    ds.FractionGroupNumber = "1"
    ds.NumberOfFractionsPlanned = "30"
    ds.NumberOfBeams = "1"
    ds.NumberOfBrachyApplicationSetups = "0"

    # Referenced Beam Sequence
    refd_beam_sequence = Sequence()
    ds.ReferencedBeamSequence = refd_beam_sequence

    # Referenced Beam Sequence: Referenced Beam 1
    refd_beam1 = Dataset()
    refd_beam1.BeamDoseSpecificationPoint = [239.531250000000, 239.531250000000, -751.87000000000]
    ...

Currently, only a data element which is a `Dataset` (an item within a `Sequence`) is accepted. The resulting code would not on its own produce a correct DICOM file, but could be useful as a model when creating more complete code. For example, issuing code for one item in a `Sequence` could be the starting point towards a loop producing a number of sequence items.

## Extending the CLI

Developers can create their own ‘subcommands’ for the `pydicom` command, by adding entry points to their package’s setup.py file, specifying a callback function to register the subcommand and its arguments.

If you wanted to create two subcommands, ‘command1’ and ‘command2’, your setup.py file should include something like:

    from setuptools import setup

    if __name__ == '__main__':
        setup(
            name="yourpackage",
            # various setup options...,
            entry_points = {
                "pydicom_subcommands": [
                    "command1 = yourpackage.command1module.add_subparser",
                    "command2 = yourpackage.command2module.add_subparser"
                ]
            }
        )

The `"pydicom_subcommands"` is a literal string; this must not be changed or pydicom will not find your subcommand.

The `add_subparser` function name could be changed if you wish, but usually would be used by convention, and is assumed in the following examples.

In the module you have specified, create the `add_subparser` function, which takes a single argument `subparsers`, and a `do_command` function, which will take the call when you subcommand is actually used at the command line:

    from pydicom.cli.main import filespec_help, filespec_parser

    def add_subparser(subparsers):
        # Register the sub-parser
        subparser = subparsers.add_parser(
            "subcommandname",
            description="Summary of your subcommand"
        )

        subparser.add_argument(
            "filespec",
            help=filespec_help,
            type=filespec_parser
        )
        subparser.add_argument(
        ...
        )

        subparser.set_defaults(func=do_command)

And define your command function:

    def do_command(args):
        for ds, element_val in args.filespec:
            if args.yourarg:
                # Do something...

            # work with the dataset ds or element as needed...

The `pydicom` command uses Python’s argparse library to process commands.

The above code snippets show adding the `filespec` argument, and processing the resulting dataset-element_value pairs in the `do_command()` function. This is recommended if you wish to use the filespec as was seen in the pydicom show command and pydicom codify command sections. If not, you can just create a normal arg with the type set to `argparse.FileType` to open files yourself.

The above has been shown in relation to a different package than pydicom; however, if you think your command has general use, please consider contributing it to pydicom: in that case, change the entry points in the pydicom `setup.py` script, and add a module under `pydicom.cli` and create a pull request.