Skill Tracer
Skills › Scientific Agent Skills › imaging-data-commons › digital_pathology_guide.md

digital_pathology_guide.md

404 lines · skills/imaging-data-commons/references/digital_pathology_guide.md at 5f2bc03

Open on GitHub
1# Digital Pathology Guide for IDC
2
3**Tested with:** idc-index 0.12.5 (IDC data version v24)
4
5For general IDC queries and downloads, use `idc-index` (see main SKILL.md). This guide covers slide microscopy (SM) imaging, microscopy bulk simple annotations (ANN), and segmentations (SEG) in the context of digital pathology in IDC.
6

Digital Pathology Guide for IDC

Tested with: idc-index 0.12.5 (IDC data version v24)

For general IDC queries and downloads, use idc-index (see main SKILL.md). This guide covers slide microscopy (SM) imaging, microscopy bulk simple annotations (ANN), and segmentations (SEG) in the context of digital pathology in IDC.

Raw lines 1 to 6
7## Index Tables for Digital Pathology
8
9Five specialized index tables provide curated metadata without needing BigQuery:
11| Table | Row Granularity | Description |
12|-------|-----------------|-------------|
13| `sm_index` | 1 row = 1 SM series | Slide Microscopy series metadata: container/slide ID, tissue type, anatomic structure, diagnosis, lens power, pixel spacing, image dimensions |
14| `sm_instance_index` | 1 row = 1 SM instance | Instance-level (SOPInstanceUID) metadata for individual slide images |
15| `seg_index` | 1 row = 1 SEG series | DICOM Segmentation metadata: algorithm, segment count, reference to source series. Used for both radiology and pathology — filter by source Modality to find pathology-specific segmentations |
16| `ann_index` | 1 row = 1 ANN series | Microscopy Bulk Simple Annotations series metadata; includes `referenced_SeriesInstanceUID` linking to the annotated slide |
17| `ann_group_index` | 1 row = 1 annotation group | Annotation group details: `AnnotationGroupLabel`, `GraphicType`, `NumberOfAnnotations`, `AlgorithmName`, property codes |
19All require `client.fetch_index("table_name")` before querying. Use `client.indices_overview` to inspect column schemas programmatically.

Index Tables for Digital Pathology

Five specialized index tables provide curated metadata without needing BigQuery:

TableRow GranularityDescription
sm_index1 row = 1 SM seriesSlide Microscopy series metadata: container/slide ID, tissue type, anatomic structure, diagnosis, lens power, pixel spacing, image dimensions
sm_instance_index1 row = 1 SM instanceInstance-level (SOPInstanceUID) metadata for individual slide images
seg_index1 row = 1 SEG seriesDICOM Segmentation metadata: algorithm, segment count, reference to source series. Used for both radiology and pathology — filter by source Modality to find pathology-specific segmentations
ann_index1 row = 1 ANN seriesMicroscopy Bulk Simple Annotations series metadata; includes referenced_SeriesInstanceUID linking to the annotated slide
ann_group_index1 row = 1 annotation groupAnnotation group details: AnnotationGroupLabel, GraphicType, NumberOfAnnotations, AlgorithmName, property codes

All require client.fetch_index("table_name") before querying. Use client.indices_overview to inspect column schemas programmatically.

Raw lines 7 to 20
21## Slide Microscopy Queries

Slide Microscopy Queries

Raw lines 21 to 22
23### Basic SM metadata
25```python
26from idc_index import IDCClient
27client = IDCClient()
29# sm_index has detailed metadata; join with index for collection_id
30client.fetch_index("sm_index")
31client.sql_query("""
32 SELECT i.collection_id, COUNT(*) as slides,
33 MIN(s.min_PixelSpacing_2sf) as min_resolution
34 FROM sm_index s
35 JOIN index i ON s.SeriesInstanceUID = i.SeriesInstanceUID
36 GROUP BY i.collection_id
37 ORDER BY slides DESC
38""")
39```

Basic SM metadata

from idc_index import IDCClient
client = IDCClient()

# sm_index has detailed metadata; join with index for collection_id
client.fetch_index("sm_index")
client.sql_query("""
    SELECT i.collection_id, COUNT(*) as slides,
           MIN(s.min_PixelSpacing_2sf) as min_resolution
    FROM sm_index s
    JOIN index i ON s.SeriesInstanceUID = i.SeriesInstanceUID
    GROUP BY i.collection_id
    ORDER BY slides DESC
""")
Raw lines 23 to 40
41### Find SM series with specific properties
43```python
44# Find high-resolution slides with specific objective lens power
45client.fetch_index("sm_index")
46client.sql_query("""
47 SELECT
48 i.collection_id,
49 i.PatientID,
50 s.ObjectiveLensPower,
51 s.min_PixelSpacing_2sf
52 FROM sm_index s
53 JOIN index i ON s.SeriesInstanceUID = i.SeriesInstanceUID
54 WHERE s.ObjectiveLensPower >= 40
55 ORDER BY s.min_PixelSpacing_2sf
56 LIMIT 20
57""")
58```

Find SM series with specific properties

# Find high-resolution slides with specific objective lens power
client.fetch_index("sm_index")
client.sql_query("""
    SELECT
        i.collection_id,
        i.PatientID,
        s.ObjectiveLensPower,
        s.min_PixelSpacing_2sf
    FROM sm_index s
    JOIN index i ON s.SeriesInstanceUID = i.SeriesInstanceUID
    WHERE s.ObjectiveLensPower >= 40
    ORDER BY s.min_PixelSpacing_2sf
    LIMIT 20
""")
Raw lines 41 to 59
60### Filter by specimen preparation
62The `sm_index` includes staining, embedding, and fixative metadata. These columns are **arrays** (e.g., `[hematoxylin stain, water soluble eosin stain]` for H&E) — use `array_to_string()` with `LIKE` or `list_contains()` to filter.
64```python
65# Find H&E-stained slides in a collection
66client.fetch_index("sm_index")
67client.sql_query("""
68 SELECT
69 i.PatientID,
70 s.staining_usingSubstance_CodeMeaning as staining,
71 s.embeddingMedium_CodeMeaning as embedding,
72 s.tissueFixative_CodeMeaning as fixative
73 FROM sm_index s
74 JOIN index i ON s.SeriesInstanceUID = i.SeriesInstanceUID
75 WHERE i.collection_id = 'tcga_brca'
76 AND array_to_string(s.staining_usingSubstance_CodeMeaning, ', ') LIKE '%hematoxylin%'
77 LIMIT 10
78""")
79```
81```python
82# Compare FFPE vs frozen slides across collections
83client.sql_query("""
84 SELECT
85 i.collection_id,
86 s.embeddingMedium_CodeMeaning as embedding,
87 COUNT(*) as slide_count
88 FROM sm_index s
89 JOIN index i ON s.SeriesInstanceUID = i.SeriesInstanceUID
90 GROUP BY i.collection_id, embedding
91 ORDER BY i.collection_id, slide_count DESC
92""")
93```

Filter by specimen preparation

The sm_index includes staining, embedding, and fixative metadata. These columns are arrays (e.g., [hematoxylin stain, water soluble eosin stain] for H&E) — use array_to_string() with LIKE or list_contains() to filter.

# Find H&E-stained slides in a collection
client.fetch_index("sm_index")
client.sql_query("""
    SELECT
        i.PatientID,
        s.staining_usingSubstance_CodeMeaning as staining,
        s.embeddingMedium_CodeMeaning as embedding,
        s.tissueFixative_CodeMeaning as fixative
    FROM sm_index s
    JOIN index i ON s.SeriesInstanceUID = i.SeriesInstanceUID
    WHERE i.collection_id = 'tcga_brca'
      AND array_to_string(s.staining_usingSubstance_CodeMeaning, ', ') LIKE '%hematoxylin%'
    LIMIT 10
""")
# Compare FFPE vs frozen slides across collections
client.sql_query("""
    SELECT
        i.collection_id,
        s.embeddingMedium_CodeMeaning as embedding,
        COUNT(*) as slide_count
    FROM sm_index s
    JOIN index i ON s.SeriesInstanceUID = i.SeriesInstanceUID
    GROUP BY i.collection_id, embedding
    ORDER BY i.collection_id, slide_count DESC
""")
Raw lines 60 to 94
95## Identifying Tumor vs Normal Slides
97The `sm_index` table provides two ways to identify tissue type:
99| Column | Use Case |
100|--------|----------|
101| `primaryAnatomicStructureModifier_CodeMeaning` | Structured tissue type from DICOM specimen metadata (e.g., `Neoplasm, Primary`, `Normal`, `Tumor`, `Neoplasm, Metastatic`). Availability depends on the collection; missing values do not establish normal tissue. |
102| `ContainerIdentifier` | Slide/container identifier. For TCGA collections, contains the [TCGA barcode](https://docs.gdc.cancer.gov/Encyclopedia/pages/TCGA_Barcode/) where the [sample type code](https://gdc.cancer.gov/resources-tcga-users/tcga-code-tables/sample-type-codes) (positions 14-15) encodes tissue origin: `01`-`09` = tumor, `10`-`19` = normal. |

Identifying Tumor vs Normal Slides

The sm_index table provides two ways to identify tissue type:

ColumnUse Case
primaryAnatomicStructureModifier_CodeMeaningStructured tissue type from DICOM specimen metadata (e.g., Neoplasm, Primary, Normal, Tumor, Neoplasm, Metastatic). Availability depends on the collection; missing values do not establish normal tissue.
ContainerIdentifierSlide/container identifier. For TCGA collections, contains the TCGA barcode where the sample type code (positions 14-15) encodes tissue origin: 01-09 = tumor, 10-19 = normal.
Raw lines 95 to 103
104### Using structured tissue type metadata
106```python
107from idc_index import IDCClient
108client = IDCClient()
109client.fetch_index("sm_index")
111# Discover tissue type values across all SM data
112client.sql_query("""
113 SELECT
114 s.primaryAnatomicStructureModifier_CodeMeaning as tissue_type,
115 COUNT(*) as slide_count
116 FROM sm_index s
117 WHERE s.primaryAnatomicStructureModifier_CodeMeaning IS NOT NULL
118 GROUP BY tissue_type
119 ORDER BY slide_count DESC
120""")
121```
123#### Example: Tumor vs normal slides in TCGA-BRCA
125```python
126# Tissue type breakdown for TCGA-BRCA
127client.sql_query("""
128 SELECT
129 s.primaryAnatomicStructureModifier_CodeMeaning as tissue_type,
130 COUNT(*) as slide_count,
131 COUNT(DISTINCT i.PatientID) as patient_count
132 FROM sm_index s
133 JOIN index i ON s.SeriesInstanceUID = i.SeriesInstanceUID
134 WHERE i.collection_id = 'tcga_brca'
135 GROUP BY tissue_type
136 ORDER BY slide_count DESC
137""")
138# Returns: Neoplasm, Primary (2704 slides), Normal (399 slides)
139```

Using structured tissue type metadata

from idc_index import IDCClient
client = IDCClient()
client.fetch_index("sm_index")

# Discover tissue type values across all SM data
client.sql_query("""
    SELECT
        s.primaryAnatomicStructureModifier_CodeMeaning as tissue_type,
        COUNT(*) as slide_count
    FROM sm_index s
    WHERE s.primaryAnatomicStructureModifier_CodeMeaning IS NOT NULL
    GROUP BY tissue_type
    ORDER BY slide_count DESC
""")

Example: Tumor vs normal slides in TCGA-BRCA

# Tissue type breakdown for TCGA-BRCA
client.sql_query("""
    SELECT
        s.primaryAnatomicStructureModifier_CodeMeaning as tissue_type,
        COUNT(*) as slide_count,
        COUNT(DISTINCT i.PatientID) as patient_count
    FROM sm_index s
    JOIN index i ON s.SeriesInstanceUID = i.SeriesInstanceUID
    WHERE i.collection_id = 'tcga_brca'
    GROUP BY tissue_type
    ORDER BY slide_count DESC
""")
# Returns: Neoplasm, Primary (2704 slides), Normal (399 slides)
Raw lines 104 to 140
141### Using TCGA barcode (TCGA collections only)
143For TCGA collections, `ContainerIdentifier` contains the slide barcode (e.g., `TCGA-E9-A3X8-01A-03-TSC`). Extract the sample type code to classify tissue:
145```python
146# Parse sample type from TCGA barcode
147client.sql_query("""
148 SELECT
149 SUBSTRING(SPLIT_PART(s.ContainerIdentifier, '-', 4), 1, 2) as sample_type_code,
150 s.primaryAnatomicStructureModifier_CodeMeaning as tissue_type,
151 COUNT(*) as slide_count
152 FROM sm_index s
153 JOIN index i ON s.SeriesInstanceUID = i.SeriesInstanceUID
154 WHERE i.collection_id = 'tcga_brca'
155 GROUP BY sample_type_code, tissue_type
156 ORDER BY sample_type_code
157""")
158# Returns: 01 → Neoplasm, Primary (2704), 06 → None (8), 11 → Normal (399)
159```
161The barcode approach catches cases where structured metadata is NULL (e.g., `06` = Metastatic slides have `primaryAnatomicStructureModifier_CodeMeaning` = NULL in TCGA-BRCA).

Using TCGA barcode (TCGA collections only)

For TCGA collections, ContainerIdentifier contains the slide barcode (e.g., TCGA-E9-A3X8-01A-03-TSC). Extract the sample type code to classify tissue:

# Parse sample type from TCGA barcode
client.sql_query("""
    SELECT
        SUBSTRING(SPLIT_PART(s.ContainerIdentifier, '-', 4), 1, 2) as sample_type_code,
        s.primaryAnatomicStructureModifier_CodeMeaning as tissue_type,
        COUNT(*) as slide_count
    FROM sm_index s
    JOIN index i ON s.SeriesInstanceUID = i.SeriesInstanceUID
    WHERE i.collection_id = 'tcga_brca'
    GROUP BY sample_type_code, tissue_type
    ORDER BY sample_type_code
""")
# Returns: 01 → Neoplasm, Primary (2704), 06 → None (8), 11 → Normal (399)

The barcode approach catches cases where structured metadata is NULL (e.g., 06 = Metastatic slides have primaryAnatomicStructureModifier_CodeMeaning = NULL in TCGA-BRCA).

Raw lines 141 to 162
163## Annotation Queries (ANN)
165DICOM Microscopy Bulk Simple Annotations (Modality = 'ANN') are annotations **on** slide microscopy images. They appear in `ann_index` (series-level) and `ann_group_index` (group-level detail). Each ANN series references the slide it annotates via `referenced_SeriesInstanceUID`.

Annotation Queries (ANN)

DICOM Microscopy Bulk Simple Annotations (Modality = 'ANN') are annotations on slide microscopy images. They appear in ann_index (series-level) and ann_group_index (group-level detail). Each ANN series references the slide it annotates via referenced_SeriesInstanceUID.

Raw lines 163 to 166
167### Basic annotation discovery
169```python
170# Find annotation series and their referenced images
171client.fetch_index("ann_index")
172client.fetch_index("ann_group_index")
174client.sql_query("""
175 SELECT
176 a.SeriesInstanceUID as ann_series,
177 a.AnnotationCoordinateType,
178 a.referenced_SeriesInstanceUID as source_series
179 FROM ann_index a
180 LIMIT 10
181""")
182```

Basic annotation discovery

# Find annotation series and their referenced images
client.fetch_index("ann_index")
client.fetch_index("ann_group_index")

client.sql_query("""
    SELECT
        a.SeriesInstanceUID as ann_series,
        a.AnnotationCoordinateType,
        a.referenced_SeriesInstanceUID as source_series
    FROM ann_index a
    LIMIT 10
""")
Raw lines 167 to 183
184### Annotation group statistics
186```python
187# Get annotation group details (graphic types, counts, algorithms)
188client.sql_query("""
189 SELECT
190 GraphicType,
191 SUM(NumberOfAnnotations) as total_annotations,
192 COUNT(*) as group_count
193 FROM ann_group_index
194 GROUP BY GraphicType
195 ORDER BY total_annotations DESC
196""")
197```

Annotation group statistics

# Get annotation group details (graphic types, counts, algorithms)
client.sql_query("""
    SELECT
        GraphicType,
        SUM(NumberOfAnnotations) as total_annotations,
        COUNT(*) as group_count
    FROM ann_group_index
    GROUP BY GraphicType
    ORDER BY total_annotations DESC
""")
Raw lines 184 to 198
199### Find annotations with source slide context
201```python
202# Find annotations with their source slide microscopy context
203client.sql_query("""
204 SELECT
205 i.collection_id,
206 g.GraphicType,
207 g.AnnotationPropertyType_CodeMeaning,
208 g.AlgorithmName,
209 g.NumberOfAnnotations
210 FROM ann_group_index g
211 JOIN ann_index a ON g.SeriesInstanceUID = a.SeriesInstanceUID
212 JOIN index i ON a.referenced_SeriesInstanceUID = i.SeriesInstanceUID
213 WHERE g.AlgorithmName IS NOT NULL
214 LIMIT 10
215""")
216```

Find annotations with source slide context

# Find annotations with their source slide microscopy context
client.sql_query("""
    SELECT
        i.collection_id,
        g.GraphicType,
        g.AnnotationPropertyType_CodeMeaning,
        g.AlgorithmName,
        g.NumberOfAnnotations
    FROM ann_group_index g
    JOIN ann_index a ON g.SeriesInstanceUID = a.SeriesInstanceUID
    JOIN index i ON a.referenced_SeriesInstanceUID = i.SeriesInstanceUID
    WHERE g.AlgorithmName IS NOT NULL
    LIMIT 10
""")
Raw lines 199 to 217
218## Segmentations on Slide Microscopy
220DICOM Segmentations (Modality = 'SEG') are used for both radiology (e.g., organ segmentations on CT) and pathology (e.g., tissue region segmentations on whole slide images). Use `seg_index.segmented_SeriesInstanceUID` to find the source series, then filter by source Modality to isolate pathology segmentations.
222```python
223# Find segmentations whose source is a slide microscopy image
224client.fetch_index("seg_index")
225client.fetch_index("sm_index")
226client.sql_query("""
227 SELECT
228 seg.SeriesInstanceUID as seg_series,
229 seg.AlgorithmName,
230 seg.total_segments,
231 src.collection_id,
232 src.Modality as source_modality
233 FROM seg_index seg
234 JOIN index src ON seg.segmented_SeriesInstanceUID = src.SeriesInstanceUID
235 WHERE src.Modality = 'SM'
236 LIMIT 20
237""")
238```

Segmentations on Slide Microscopy

DICOM Segmentations (Modality = 'SEG') are used for both radiology (e.g., organ segmentations on CT) and pathology (e.g., tissue region segmentations on whole slide images). Use seg_index.segmented_SeriesInstanceUID to find the source series, then filter by source Modality to isolate pathology segmentations.

# Find segmentations whose source is a slide microscopy image
client.fetch_index("seg_index")
client.fetch_index("sm_index")
client.sql_query("""
    SELECT
        seg.SeriesInstanceUID as seg_series,
        seg.AlgorithmName,
        seg.total_segments,
        src.collection_id,
        src.Modality as source_modality
    FROM seg_index seg
    JOIN index src ON seg.segmented_SeriesInstanceUID = src.SeriesInstanceUID
    WHERE src.Modality = 'SM'
    LIMIT 20
""")
Raw lines 218 to 239
240## Finding Pre-Computed Analysis Results
242IDC hosts derived datasets (nuclei segmentations, TIL maps, AI annotations) identified by `analysis_result_id` in the main `index` table. Use `analysis_results_index` to discover what's available for pathology.
244```python
245from idc_index import IDCClient
246client = IDCClient()
247client.fetch_index("analysis_results_index")
249# Find analysis results that include pathology annotations or segmentations
250client.sql_query("""
251 SELECT
252 ar.analysis_result_id,
253 ar.analysis_result_title,
254 ar.modalities,
255 ar.subjects,
256 ar.collections
257 FROM analysis_results_index ar
258 WHERE ar.modalities LIKE '%ANN%' OR ar.modalities LIKE '%SEG%'
259 ORDER BY ar.subjects DESC
260""")
261```

Finding Pre-Computed Analysis Results

IDC hosts derived datasets (nuclei segmentations, TIL maps, AI annotations) identified by analysis_result_id in the main index table. Use analysis_results_index to discover what's available for pathology.

from idc_index import IDCClient
client = IDCClient()
client.fetch_index("analysis_results_index")

# Find analysis results that include pathology annotations or segmentations
client.sql_query("""
    SELECT
        ar.analysis_result_id,
        ar.analysis_result_title,
        ar.modalities,
        ar.subjects,
        ar.collections
    FROM analysis_results_index ar
    WHERE ar.modalities LIKE '%ANN%' OR ar.modalities LIKE '%SEG%'
    ORDER BY ar.subjects DESC
""")
Raw lines 240 to 262
263### Find analysis results for a specific slide
265```python
266# Find ANN groups for TCGA-BRCA slides
267client.fetch_index("ann_index")
268client.fetch_index("ann_group_index")
269client.sql_query("""
270 SELECT
271 i.analysis_result_id,
272 i.PatientID,
273 a.referenced_SeriesInstanceUID as source_slide,
274 g.AnnotationGroupLabel,
275 g.NumberOfAnnotations,
276 g.AlgorithmName
277 FROM ann_group_index g
278 JOIN ann_index a ON g.SeriesInstanceUID = a.SeriesInstanceUID
279 JOIN index i ON a.SeriesInstanceUID = i.SeriesInstanceUID
280 WHERE i.collection_id = 'tcga_brca'
281 LIMIT 10
282""")
283```
285Annotation objects can also contain per-annotation **measurements** (e.g., nucleus area, eccentricity) stored within the DICOM file. These are not in the index tables — extract them after download using [highdicom](https://github.com/ImagingDataCommons/highdicom) (`ann.get_annotation_groups()`, `group.get_measurements()`; see the [official ANN guide](https://highdicom.readthedocs.io/en/latest/ann.html)). See the [microscopy_dicom_ann_intro](https://github.com/ImagingDataCommons/IDC-Tutorials/blob/master/notebooks/pathomics/microscopy_dicom_ann_intro.ipynb) tutorial for a worked example including spatial analysis and cellularity computation.

Find analysis results for a specific slide

# Find ANN groups for TCGA-BRCA slides
client.fetch_index("ann_index")
client.fetch_index("ann_group_index")
client.sql_query("""
    SELECT
        i.analysis_result_id,
        i.PatientID,
        a.referenced_SeriesInstanceUID as source_slide,
        g.AnnotationGroupLabel,
        g.NumberOfAnnotations,
        g.AlgorithmName
    FROM ann_group_index g
    JOIN ann_index a ON g.SeriesInstanceUID = a.SeriesInstanceUID
    JOIN index i ON a.SeriesInstanceUID = i.SeriesInstanceUID
    WHERE i.collection_id = 'tcga_brca'
    LIMIT 10
""")

Annotation objects can also contain per-annotation measurements (e.g., nucleus area, eccentricity) stored within the DICOM file. These are not in the index tables — extract them after download using highdicom (ann.get_annotation_groups(), group.get_measurements(); see the official ANN guide). See the microscopy_dicom_ann_intro tutorial for a worked example including spatial analysis and cellularity computation.

Raw lines 263 to 286
287## Filter by AnnotationGroupLabel
289`AnnotationGroupLabel` is the most direct column for finding annotation groups by name or semantic content. Use `LIKE` with wildcards for text search.

Filter by AnnotationGroupLabel

AnnotationGroupLabel is the most direct column for finding annotation groups by name or semantic content. Use LIKE with wildcards for text search.

Raw lines 287 to 290
291### Simple label filtering
293```python
294# Find annotation groups by label (e.g., groups mentioning "blast")
295client.fetch_index("ann_group_index")
296client.sql_query("""
297 SELECT
298 g.SeriesInstanceUID,
299 g.AnnotationGroupLabel,
300 g.GraphicType,
301 g.NumberOfAnnotations,
302 g.AlgorithmName
303 FROM ann_group_index g
304 WHERE LOWER(g.AnnotationGroupLabel) LIKE '%blast%'
305 ORDER BY g.NumberOfAnnotations DESC
306""")
307```

Simple label filtering

# Find annotation groups by label (e.g., groups mentioning "blast")
client.fetch_index("ann_group_index")
client.sql_query("""
    SELECT
        g.SeriesInstanceUID,
        g.AnnotationGroupLabel,
        g.GraphicType,
        g.NumberOfAnnotations,
        g.AlgorithmName
    FROM ann_group_index g
    WHERE LOWER(g.AnnotationGroupLabel) LIKE '%blast%'
    ORDER BY g.NumberOfAnnotations DESC
""")
Raw lines 291 to 308
309### Label filtering with collection context
311```python
312# Find annotation groups matching a label within a specific collection
313client.fetch_index("ann_index")
314client.fetch_index("ann_group_index")
315client.sql_query("""
316 SELECT
317 i.collection_id,
318 g.AnnotationGroupLabel,
319 g.GraphicType,
320 g.NumberOfAnnotations,
321 g.AnnotationPropertyType_CodeMeaning
322 FROM ann_group_index g
323 JOIN ann_index a ON g.SeriesInstanceUID = a.SeriesInstanceUID
324 JOIN index i ON a.SeriesInstanceUID = i.SeriesInstanceUID
325 WHERE i.collection_id = 'your_collection_id'
326 AND LOWER(g.AnnotationGroupLabel) LIKE '%keyword%'
327 ORDER BY g.NumberOfAnnotations DESC
328""")
329```

Label filtering with collection context

# Find annotation groups matching a label within a specific collection
client.fetch_index("ann_index")
client.fetch_index("ann_group_index")
client.sql_query("""
    SELECT
        i.collection_id,
        g.AnnotationGroupLabel,
        g.GraphicType,
        g.NumberOfAnnotations,
        g.AnnotationPropertyType_CodeMeaning
    FROM ann_group_index g
    JOIN ann_index a ON g.SeriesInstanceUID = a.SeriesInstanceUID
    JOIN index i ON a.SeriesInstanceUID = i.SeriesInstanceUID
    WHERE i.collection_id = 'your_collection_id'
      AND LOWER(g.AnnotationGroupLabel) LIKE '%keyword%'
    ORDER BY g.NumberOfAnnotations DESC
""")
Raw lines 309 to 330
331## Annotations on Slide Microscopy (SM + ANN Cross-Reference)
333When looking for annotations related to slide microscopy data, use both SM and ANN tables together. The `ann_index.referenced_SeriesInstanceUID` links each annotation series to its source slide.
335```python
336# Find slide microscopy images and their annotations in a collection
337client.fetch_index("sm_index")
338client.fetch_index("ann_index")
339client.fetch_index("ann_group_index")
340client.sql_query("""
341 SELECT
342 i.collection_id,
343 s.ObjectiveLensPower,
344 g.AnnotationGroupLabel,
345 g.NumberOfAnnotations,
346 g.GraphicType
347 FROM ann_group_index g
348 JOIN ann_index a ON g.SeriesInstanceUID = a.SeriesInstanceUID
349 JOIN sm_index s ON a.referenced_SeriesInstanceUID = s.SeriesInstanceUID
350 JOIN index i ON a.SeriesInstanceUID = i.SeriesInstanceUID
351 WHERE i.collection_id = 'your_collection_id'
352 ORDER BY g.NumberOfAnnotations DESC
353""")
354```

Annotations on Slide Microscopy (SM + ANN Cross-Reference)

When looking for annotations related to slide microscopy data, use both SM and ANN tables together. The ann_index.referenced_SeriesInstanceUID links each annotation series to its source slide.

# Find slide microscopy images and their annotations in a collection
client.fetch_index("sm_index")
client.fetch_index("ann_index")
client.fetch_index("ann_group_index")
client.sql_query("""
    SELECT
        i.collection_id,
        s.ObjectiveLensPower,
        g.AnnotationGroupLabel,
        g.NumberOfAnnotations,
        g.GraphicType
    FROM ann_group_index g
    JOIN ann_index a ON g.SeriesInstanceUID = a.SeriesInstanceUID
    JOIN sm_index s ON a.referenced_SeriesInstanceUID = s.SeriesInstanceUID
    JOIN index i ON a.SeriesInstanceUID = i.SeriesInstanceUID
    WHERE i.collection_id = 'your_collection_id'
    ORDER BY g.NumberOfAnnotations DESC
""")
Raw lines 331 to 355
356## Join Patterns
358### SM join (slide microscopy details with collection context)
360```python
361client.fetch_index("sm_index")
362result = client.sql_query("""
363 SELECT i.collection_id, i.PatientID, s.ObjectiveLensPower, s.min_PixelSpacing_2sf
364 FROM index i
365 JOIN sm_index s ON i.SeriesInstanceUID = s.SeriesInstanceUID
366 LIMIT 10
367""")
368```

SM join (slide microscopy details with collection context)

client.fetch_index("sm_index")
result = client.sql_query("""
    SELECT i.collection_id, i.PatientID, s.ObjectiveLensPower, s.min_PixelSpacing_2sf
    FROM index i
    JOIN sm_index s ON i.SeriesInstanceUID = s.SeriesInstanceUID
    LIMIT 10
""")
Raw lines 358 to 369
370### ANN join (annotation groups with collection context)
372```python
373client.fetch_index("ann_index")
374client.fetch_index("ann_group_index")
375result = client.sql_query("""
376 SELECT
377 i.collection_id,
378 g.AnnotationGroupLabel,
379 g.GraphicType,
380 g.NumberOfAnnotations,
381 a.referenced_SeriesInstanceUID as source_series
382 FROM ann_group_index g
383 JOIN ann_index a ON g.SeriesInstanceUID = a.SeriesInstanceUID
384 JOIN index i ON a.SeriesInstanceUID = i.SeriesInstanceUID
385 LIMIT 10
386""")
387```

ANN join (annotation groups with collection context)

client.fetch_index("ann_index")
client.fetch_index("ann_group_index")
result = client.sql_query("""
    SELECT
        i.collection_id,
        g.AnnotationGroupLabel,
        g.GraphicType,
        g.NumberOfAnnotations,
        a.referenced_SeriesInstanceUID as source_series
    FROM ann_group_index g
    JOIN ann_index a ON g.SeriesInstanceUID = a.SeriesInstanceUID
    JOIN index i ON a.SeriesInstanceUID = i.SeriesInstanceUID
    LIMIT 10
""")
Raw lines 370 to 388
389## Related Tools
391The following tools work with DICOM format for digital pathology workflows:
393**Python Libraries:**
394- [highdicom](https://github.com/ImagingDataCommons/highdicom) - High-level DICOM abstractions for Python. Create and read DICOM Segmentations (SEG), Structured Reports (SR), and parametric maps for pathology and radiology. Developed by IDC.
395- [wsidicom](https://github.com/imi-bigpicture/wsidicom) - Python package for reading DICOM WSI datasets. Parses metadata into easy-to-use dataclasses for whole slide image analysis.
396- [TIA-Toolbox](https://github.com/TissueImageAnalytics/tiatoolbox) - End-to-end computational pathology library with DICOM support via `DICOMWSIReader`. Provides tile extraction, feature extraction, and pretrained deep learning models.
397- [EZ-WSI-DICOMweb](https://github.com/GoogleCloudPlatform/EZ-WSI-DICOMweb) - Extract image patches from DICOM whole slide images via DICOMweb. Designed for AI/ML workflows with Google Healthcare DICOM stores; the IDC tutorial requires the authenticated Google-maintained endpoint for this library.
399**Viewers:**
400- [Slim](https://github.com/ImagingDataCommons/slim) - Web-based DICOM slide microscopy viewer and annotation tool. Supports brightfield and multiplexed immunofluorescence imaging via DICOMweb. Developed by IDC.
401- [QuPath](https://qupath.github.io/) - Cross-platform open source software for whole slide image analysis. DICOM WSI support depends on the installed image-server backend; verify the exact QuPath/OpenSlide build before promising compatibility.
403**Conversion:**
404- [dicom_wsi](https://github.com/Steven-N-Hart/dicom_wsi) - Python implementation for converting proprietary WSI formats to DICOM-compliant files.

Related Tools

The following tools work with DICOM format for digital pathology workflows:

Python Libraries:

  • highdicom - High-level DICOM abstractions for Python. Create and read DICOM Segmentations (SEG), Structured Reports (SR), and parametric maps for pathology and radiology. Developed by IDC.
  • wsidicom - Python package for reading DICOM WSI datasets. Parses metadata into easy-to-use dataclasses for whole slide image analysis.
  • TIA-Toolbox - End-to-end computational pathology library with DICOM support via DICOMWSIReader. Provides tile extraction, feature extraction, and pretrained deep learning models.
  • EZ-WSI-DICOMweb - Extract image patches from DICOM whole slide images via DICOMweb. Designed for AI/ML workflows with Google Healthcare DICOM stores; the IDC tutorial requires the authenticated Google-maintained endpoint for this library.

Viewers:

  • Slim - Web-based DICOM slide microscopy viewer and annotation tool. Supports brightfield and multiplexed immunofluorescence imaging via DICOMweb. Developed by IDC.
  • QuPath - Cross-platform open source software for whole slide image analysis. DICOM WSI support depends on the installed image-server backend; verify the exact QuPath/OpenSlide build before promising compatibility.

Conversion:

  • dicom_wsi - Python implementation for converting proprietary WSI formats to DICOM-compliant files.
Raw lines 389 to 404