or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration-utilities.mddata-elements.mddataset-manipulation.mdfile-operations.mdindex.mdpixel-data-processing.mdsequences-collections.mdtags-and-uids.mdvalue-representations.md

sequences-collections.mddocs/

0

# Sequences and Collections

1

2

Management of DICOM sequences and multi-value elements providing comprehensive support for nested datasets, proper validation, type-constrained collections, and hierarchical DICOM data structures used in medical imaging workflows.

3

4

## Capabilities

5

6

### Sequence Class

7

8

List-like container for datasets in DICOM sequences with specialized functionality for nested data structures.

9

10

```python { .api }

11

class Sequence(list):

12

"""

13

DICOM Sequence container for nested datasets.

14

15

List-like container that holds Dataset objects in DICOM sequences,

16

providing standard list operations plus DICOM-specific functionality

17

for handling nested medical imaging data structures.

18

"""

19

20

def __init__(self, iterable=None):

21

"""

22

Initialize sequence.

23

24

Parameters:

25

- iterable: list or None - Initial sequence items (Dataset objects)

26

"""

27

28

def append(self, item):

29

"""

30

Add dataset to sequence.

31

32

Parameters:

33

- item: Dataset - Dataset to add to sequence

34

35

Raises:

36

TypeError - If item is not a Dataset

37

"""

38

39

def insert(self, index, item):

40

"""

41

Insert dataset at specific position.

42

43

Parameters:

44

- index: int - Position to insert at

45

- item: Dataset - Dataset to insert

46

47

Raises:

48

TypeError - If item is not a Dataset

49

"""

50

51

def extend(self, items):

52

"""

53

Extend sequence with multiple datasets.

54

55

Parameters:

56

- items: iterable - Datasets to add

57

58

Raises:

59

TypeError - If any item is not a Dataset

60

"""

61

62

def __setitem__(self, index, value):

63

"""

64

Set dataset at index.

65

66

Parameters:

67

- index: int - Index to set

68

- value: Dataset - Dataset to set

69

70

Raises:

71

TypeError - If value is not a Dataset

72

"""

73

74

def __str__(self):

75

"""Return string representation of sequence."""

76

77

def __repr__(self):

78

"""Return detailed representation of sequence."""

79

```

80

81

### MultiValue Class

82

83

Container for multiple values in single data element with type constraints and validation.

84

85

```python { .api }

86

class MultiValue(list):

87

"""

88

Container for multiple values in DICOM data elements.

89

90

Type-constrained list that ensures all values are of the same type,

91

providing validation and conversion for multi-value DICOM elements.

92

"""

93

94

def __init__(self, type_constructor, iterable=None):

95

"""

96

Initialize multi-value container.

97

98

Parameters:

99

- type_constructor: callable - Function to construct/validate element type

100

- iterable: list or None - Initial values

101

102

Raises:

103

TypeError - If any initial value doesn't match type constructor

104

"""

105

106

def append(self, value):

107

"""

108

Add value to multi-value container.

109

110

Parameters:

111

- value: Any - Value to add (will be validated/converted)

112

113

Raises:

114

TypeError - If value cannot be converted to required type

115

"""

116

117

def insert(self, index, value):

118

"""

119

Insert value at specific position.

120

121

Parameters:

122

- index: int - Position to insert at

123

- value: Any - Value to insert (will be validated/converted)

124

125

Raises:

126

TypeError - If value cannot be converted to required type

127

"""

128

129

def extend(self, values):

130

"""

131

Extend with multiple values.

132

133

Parameters:

134

- values: iterable - Values to add (all will be validated/converted)

135

136

Raises:

137

TypeError - If any value cannot be converted to required type

138

"""

139

140

def __setitem__(self, index, value):

141

"""

142

Set value at index.

143

144

Parameters:

145

- index: int - Index to set

146

- value: Any - Value to set (will be validated/converted)

147

148

Raises:

149

TypeError - If value cannot be converted to required type

150

"""

151

152

@property

153

def type_constructor(self):

154

"""callable: Type constructor function for validation."""

155

156

def __str__(self):

157

"""Return string representation suitable for DICOM."""

158

159

def __repr__(self):

160

"""Return detailed representation."""

161

```

162

163

### ConstrainedList Base Class

164

165

Base class for type-constrained lists providing validation framework.

166

167

```python { .api }

168

class ConstrainedList(list):

169

"""

170

Base class for type-constrained list implementations.

171

172

Provides framework for creating lists that enforce type constraints

173

on their elements, used as foundation for MultiValue and similar classes.

174

"""

175

176

def __init__(self, type_constructor, iterable=None):

177

"""

178

Initialize constrained list.

179

180

Parameters:

181

- type_constructor: callable - Type validation/conversion function

182

- iterable: list or None - Initial items

183

"""

184

185

def _validate_item(self, value):

186

"""

187

Validate and convert item using type constructor.

188

189

Parameters:

190

- value: Any - Value to validate/convert

191

192

Returns:

193

Any - Validated/converted value

194

195

Raises:

196

TypeError - If value cannot be converted

197

"""

198

199

def _validate_iterable(self, iterable):

200

"""

201

Validate all items in iterable.

202

203

Parameters:

204

- iterable: list - Items to validate

205

206

Returns:

207

list - Validated items

208

209

Raises:

210

TypeError - If any item cannot be converted

211

"""

212

```

213

214

### Sequence Utility Functions

215

216

Functions for working with sequences and validating sequence structures.

217

218

```python { .api }

219

def is_sequence(value):

220

"""

221

Check if value is a DICOM sequence.

222

223

Parameters:

224

- value: Any - Value to check

225

226

Returns:

227

bool - True if value is Sequence instance

228

"""

229

230

def validate_sequence(sequence):

231

"""

232

Validate sequence structure and contents.

233

234

Parameters:

235

- sequence: Sequence - Sequence to validate

236

237

Returns:

238

list - Validation errors/warnings

239

"""

240

241

def sequence_delimiter():

242

"""

243

Get sequence delimiter data element.

244

245

Returns:

246

DataElement - Sequence delimiter element

247

"""

248

249

def item_delimiter():

250

"""

251

Get item delimiter data element.

252

253

Returns:

254

DataElement - Item delimiter element

255

"""

256

```

257

258

### MultiValue Creation Functions

259

260

Factory functions for creating multi-value containers with appropriate type constructors.

261

262

```python { .api }

263

def create_multivalue(VR, values):

264

"""

265

Create MultiValue container for VR type.

266

267

Parameters:

268

- VR: str - Value Representation

269

- values: list - Initial values

270

271

Returns:

272

MultiValue - Container with appropriate type constructor

273

"""

274

275

def multivalue_from_string(VR, value_string, separator="\\"):

276

"""

277

Create MultiValue from delimited string.

278

279

Parameters:

280

- VR: str - Value Representation

281

- value_string: str - Delimited string of values

282

- separator: str - Value separator (usually backslash)

283

284

Returns:

285

MultiValue - Container with parsed values

286

"""

287

288

def string_from_multivalue(multivalue, separator="\\"):

289

"""

290

Convert MultiValue to delimited string.

291

292

Parameters:

293

- multivalue: MultiValue - Container to convert

294

- separator: str - Value separator

295

296

Returns:

297

str - Delimited string representation

298

"""

299

```

300

301

### Sequence Navigation Functions

302

303

Functions for navigating and manipulating nested sequence structures.

304

305

```python { .api }

306

def find_datasets_in_sequence(sequence, condition):

307

"""

308

Find datasets in sequence matching condition.

309

310

Parameters:

311

- sequence: Sequence - Sequence to search

312

- condition: callable - Function that returns True for matching datasets

313

314

Returns:

315

list - Matching datasets

316

"""

317

318

def walk_sequence_tree(sequence, visit_func):

319

"""

320

Walk through nested sequence tree structure.

321

322

Parameters:

323

- sequence: Sequence - Root sequence to walk

324

- visit_func: callable - Function called for each dataset

325

"""

326

327

def flatten_sequence(sequence, max_depth=None):

328

"""

329

Flatten nested sequences into single list.

330

331

Parameters:

332

- sequence: Sequence - Sequence to flatten

333

- max_depth: int - Maximum nesting depth to flatten

334

335

Returns:

336

list - Flattened list of datasets

337

"""

338

```

339

340

### Collection Validation Functions

341

342

Functions for validating collection contents and structure.

343

344

```python { .api }

345

def validate_multivalue(multivalue):

346

"""

347

Validate MultiValue container contents.

348

349

Parameters:

350

- multivalue: MultiValue - Container to validate

351

352

Returns:

353

list - Validation errors/warnings

354

"""

355

356

def check_collection_consistency(collection):

357

"""

358

Check collection for internal consistency.

359

360

Parameters:

361

- collection: Sequence or MultiValue - Collection to check

362

363

Returns:

364

bool - True if collection is consistent

365

"""

366

367

def collection_statistics(collection):

368

"""

369

Get statistics about collection contents.

370

371

Parameters:

372

- collection: Sequence or MultiValue - Collection to analyze

373

374

Returns:

375

dict - Statistics (count, types, sizes, etc.)

376

"""

377

```

378

379

## Usage Examples

380

381

### Creating and Using Sequences

382

383

```python

384

from pydicom import Dataset, Sequence

385

from pydicom.sequence import Sequence

386

387

# Create empty sequence

388

referenced_images = Sequence()

389

390

# Add datasets to sequence

391

for i in range(3):

392

item = Dataset()

393

item.ReferencedSOPClassUID = "1.2.840.10008.5.1.4.1.1.2" # CT Image Storage

394

item.ReferencedSOPInstanceUID = f"1.2.3.4.5.{i}"

395

referenced_images.append(item)

396

397

# Create dataset with sequence

398

dataset = Dataset()

399

dataset.PatientName = "Test Patient"

400

dataset.ReferencedImageSequence = referenced_images

401

402

# Access sequence items

403

print(f"Number of referenced images: {len(dataset.ReferencedImageSequence)}")

404

405

for i, item in enumerate(dataset.ReferencedImageSequence):

406

print(f"Image {i}: {item.ReferencedSOPInstanceUID}")

407

```

408

409

### Working with Nested Sequences

410

411

```python

412

from pydicom import Dataset, Sequence

413

414

# Create nested sequence structure

415

main_dataset = Dataset()

416

417

# Create sequence of study records

418

study_sequence = Sequence()

419

420

for study_num in range(2):

421

study_item = Dataset()

422

study_item.StudyInstanceUID = f"1.2.3.{study_num}"

423

study_item.StudyDescription = f"Study {study_num + 1}"

424

425

# Create nested sequence of series within each study

426

series_sequence = Sequence()

427

428

for series_num in range(3):

429

series_item = Dataset()

430

series_item.SeriesInstanceUID = f"1.2.3.{study_num}.{series_num}"

431

series_item.SeriesDescription = f"Series {series_num + 1}"

432

series_item.Modality = "CT"

433

434

series_sequence.append(series_item)

435

436

study_item.SeriesSequence = series_sequence

437

study_sequence.append(study_item)

438

439

main_dataset.StudySequence = study_sequence

440

441

# Navigate nested structure

442

for study in main_dataset.StudySequence:

443

print(f"Study: {study.StudyDescription}")

444

for series in study.SeriesSequence:

445

print(f" Series: {series.SeriesDescription} ({series.Modality})")

446

```

447

448

### MultiValue Elements

449

450

```python

451

from pydicom.multival import MultiValue

452

from pydicom.valuerep import DS, IS

453

454

# Create multi-value numeric elements

455

# Window Centers - multiple DS values

456

window_centers = MultiValue(DS, ["200", "400", "600"])

457

print(f"Window Centers: {window_centers}")

458

print(f"First center: {window_centers[0]}")

459

print(f"All centers: {list(window_centers)}")

460

461

# Image Position Patient - three DS values for x, y, z

462

image_position = MultiValue(DS, ["-125.0", "-125.0", "100.0"])

463

print(f"Image Position: {image_position}")

464

465

# Instance Numbers - multiple IS values

466

instance_numbers = MultiValue(IS, ["1", "2", "3", "4", "5"])

467

print(f"Instance Numbers: {instance_numbers}")

468

469

# Add values to existing MultiValue

470

window_centers.append("800")

471

print(f"Updated centers: {window_centers}")

472

473

# Slice through MultiValue

474

first_three = window_centers[:3]

475

print(f"First three centers: {first_three}")

476

```

477

478

### String-based MultiValue Creation

479

480

```python

481

from pydicom.multival import multivalue_from_string, string_from_multivalue

482

from pydicom.valuerep import DS

483

484

# Create from delimited string (standard DICOM format)

485

pixel_spacing_str = "0.625\\0.625" # Backslash-delimited

486

pixel_spacing = multivalue_from_string("DS", pixel_spacing_str)

487

print(f"Pixel Spacing: {pixel_spacing}")

488

print(f"X spacing: {pixel_spacing[0]}")

489

print(f"Y spacing: {pixel_spacing[1]}")

490

491

# Convert back to string

492

spacing_str = string_from_multivalue(pixel_spacing)

493

print(f"String representation: '{spacing_str}'")

494

495

# Multiple window values

496

window_values_str = "200\\400\\600\\800"

497

window_values = multivalue_from_string("DS", window_values_str)

498

print(f"Window values: {window_values}")

499

```

500

501

### Sequence Manipulation

502

503

```python

504

from pydicom import Dataset, Sequence

505

506

# Create sequence

507

procedure_sequence = Sequence()

508

509

# Add multiple items

510

procedures = [

511

{"CodeValue": "P001", "CodeMeaning": "CT Head"},

512

{"CodeValue": "P002", "CodeMeaning": "CT Chest"},

513

{"CodeValue": "P003", "CodeMeaning": "CT Abdomen"}

514

]

515

516

for proc in procedures:

517

item = Dataset()

518

item.CodeValue = proc["CodeValue"]

519

item.CodingSchemeDesignator = "LOCAL"

520

item.CodeMeaning = proc["CodeMeaning"]

521

procedure_sequence.append(item)

522

523

# Insert item at specific position

524

new_proc = Dataset()

525

new_proc.CodeValue = "P001.5"

526

new_proc.CodingSchemeDesignator = "LOCAL"

527

new_proc.CodeMeaning = "CT Neck"

528

procedure_sequence.insert(1, new_proc)

529

530

# Remove item

531

del procedure_sequence[0]

532

533

# Iterate and modify

534

for i, proc in enumerate(procedure_sequence):

535

proc.SequenceNumber = i + 1

536

print(f"{proc.SequenceNumber}: {proc.CodeMeaning}")

537

```

538

539

### Complex Sequence Structures

540

541

```python

542

from pydicom import Dataset, Sequence

543

544

# Create structured report-style sequence

545

measurement_sequence = Sequence()

546

547

# Measurement 1: Length

548

length_item = Dataset()

549

length_item.ConceptNameCodeSequence = Sequence()

550

concept = Dataset()

551

concept.CodeValue = "410668003"

552

concept.CodingSchemeDesignator = "SCT"

553

concept.CodeMeaning = "Length"

554

length_item.ConceptNameCodeSequence.append(concept)

555

556

# Add measured value

557

length_item.MeasuredValueSequence = Sequence()

558

value_item = Dataset()

559

value_item.NumericValue = "25.4"

560

value_item.MeasurementUnitsCodeSequence = Sequence()

561

unit = Dataset()

562

unit.CodeValue = "mm"

563

unit.CodingSchemeDesignator = "UCUM"

564

unit.CodeMeaning = "millimeter"

565

value_item.MeasurementUnitsCodeSequence.append(unit)

566

length_item.MeasuredValueSequence.append(value_item)

567

568

measurement_sequence.append(length_item)

569

570

# Measurement 2: Area

571

area_item = Dataset()

572

area_item.ConceptNameCodeSequence = Sequence()

573

concept2 = Dataset()

574

concept2.CodeValue = "42798000"

575

concept2.CodingSchemeDesignator = "SCT"

576

concept2.CodeMeaning = "Area"

577

area_item.ConceptNameCodeSequence.append(concept2)

578

579

area_item.MeasuredValueSequence = Sequence()

580

value_item2 = Dataset()

581

value_item2.NumericValue = "15.8"

582

value_item2.MeasurementUnitsCodeSequence = Sequence()

583

unit2 = Dataset()

584

unit2.CodeValue = "mm2"

585

unit2.CodingSchemeDesignator = "UCUM"

586

unit2.CodeMeaning = "square millimeter"

587

value_item2.MeasurementUnitsCodeSequence.append(unit2)

588

area_item.MeasuredValueSequence.append(value_item2)

589

590

measurement_sequence.append(area_item)

591

592

print(f"Number of measurements: {len(measurement_sequence)}")

593

for i, measurement in enumerate(measurement_sequence):

594

concept_name = measurement.ConceptNameCodeSequence[0].CodeMeaning

595

value = measurement.MeasuredValueSequence[0].NumericValue

596

unit = measurement.MeasuredValueSequence[0].MeasurementUnitsCodeSequence[0].CodeMeaning

597

print(f"Measurement {i+1}: {concept_name} = {value} {unit}")

598

```

599

600

### Sequence Validation and Search

601

602

```python

603

from pydicom import Dataset, Sequence

604

605

# Create sequence with validation

606

def validate_image_reference(dataset):

607

"""Validate that dataset has required image reference elements."""

608

required = ['ReferencedSOPClassUID', 'ReferencedSOPInstanceUID']

609

return all(hasattr(dataset, attr) for attr in required)

610

611

# Create sequence

612

ref_sequence = Sequence()

613

614

# Add valid items

615

valid_item = Dataset()

616

valid_item.ReferencedSOPClassUID = "1.2.840.10008.5.1.4.1.1.2"

617

valid_item.ReferencedSOPInstanceUID = "1.2.3.4.5"

618

ref_sequence.append(valid_item)

619

620

# Add another valid item

621

valid_item2 = Dataset()

622

valid_item2.ReferencedSOPClassUID = "1.2.840.10008.5.1.4.1.1.1"

623

valid_item2.ReferencedSOPInstanceUID = "1.2.3.4.6"

624

ref_sequence.append(valid_item2)

625

626

# Validate all items

627

valid_items = [validate_image_reference(item) for item in ref_sequence]

628

print(f"All items valid: {all(valid_items)}")

629

630

# Search for specific items

631

def find_ct_images(dataset):

632

"""Find CT image references."""

633

ct_class_uid = "1.2.840.10008.5.1.4.1.1.2"

634

return dataset.ReferencedSOPClassUID == ct_class_uid

635

636

ct_references = [item for item in ref_sequence if find_ct_images(item)]

637

print(f"Found {len(ct_references)} CT image references")

638

```

639

640

### MultiValue Type Safety

641

642

```python

643

from pydicom.multival import MultiValue

644

from pydicom.valuerep import DS, IS

645

646

# Type-safe multi-value container

647

try:

648

# Create DS MultiValue

649

measurements = MultiValue(DS, ["1.5", "2.3", "4.7"])

650

print(f"Measurements: {measurements}")

651

652

# Add valid value

653

measurements.append("3.8") # String that converts to DS

654

measurements.append(5.2) # Float that converts to DS

655

print(f"After additions: {measurements}")

656

657

# Try to add invalid value

658

measurements.append("invalid") # This will raise an error

659

660

except (ValueError, TypeError) as e:

661

print(f"Type validation error: {e}")

662

663

# Ensure consistent types

664

window_levels = MultiValue(IS, [100, 200, 300])

665

print(f"Window levels: {window_levels}")

666

print(f"Type of first element: {type(window_levels[0])}")

667

```