Imaging Data Commons
K-DenseCommunityCreated by Andrey Fedorov, @fedorovDistributed by K-Dense
- Skill
- Tool integration
- Science and research
- MIT
- Low risk
- Has scripts
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The Imaging Data Commons (IDC) skill provides a programmatic interface for accessing large-scale public cancer imaging data. It supports discovery, metadata querying, and file downloads for radiology (CT, MR, PET) and pathology datasets. The skill offers multiple access paths, including a Python client for local workflows, a REST API for lightweight metadata retrieval, and an MCP server for interactive discovery. It handles complex data structures, including DICOM hierarchies and derived analysis results, while ensuring users can verify licensing and citation requirements for research and clinical applications.
What it does
- Queries and filters public cancer imaging metadata using SQL or attribute-based selection.
- Downloads DICOM imaging files directly from public cloud storage buckets.
- Provides browser-based visualization URLs for radiology and pathology images.
- Retrieves licensing information and citation formats for selected datasets.
- Supports integration with DICOMweb-compatible tools and PACS systems.
- Enables programmatic cohort building and manifest generation for large-scale data analysis.
When to use it
- When you need to find and download specific cancer imaging datasets for research.
- When you need to perform metadata-driven cohort selection across large imaging collections.
- When you want to visualize medical images without installing local DICOM viewer software.
- When you need to integrate IDC data access into automated Python or shell-based pipelines.
- When you need to verify the licensing terms of specific imaging series before use.
Advantages
- No authentication required for standard public data access.
- Supports both lightweight REST-based metadata queries and heavy-duty local downloads.
- Provides consistent access to versioned data for reproducible research.
- Includes built-in tools for citation and license management.
- Offers flexible directory templating for organized local data storage.
Usage examples
- “Find all MR series for the 'rider_pilot' collection.”
- Returns a list of SeriesInstanceUIDs and metadata for the requested MR images.
- “Download the first 5 CT series from the 'nlst' collection to my local data folder.”
- Downloads the specified DICOM files into the target directory using the default hierarchy.
- “Get a viewer URL for a specific study.”
- Provides a direct link to an OHIF or SLIM viewer instance for the requested study.
- “What are the license terms for the current selection?”
- Returns a breakdown of license types (e.g., CC BY, CC BY-NC) for the selected series.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/k-dense-ai/imaging-data-commons/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip imaging-data-commons.zip -d .agents/skills
Documentation by Andrey Fedorov, @fedorov
Imaging Data Commons
Overview
Query and download public cancer imaging data from the National Cancer Institute Imaging Data Commons (IDC). No authentication required for data access.
Expected network access: IDC metadata is reachable three ways — a bundled local DuckDB index (offline after installation; additional indices are fetched from GitHub and clinical tables from S3), or the hosted IDC service over MCP or REST (api.imaging.datacommons.cancer.gov, no authentication). File downloads use public GCS (storage.googleapis.com) and AWS S3 (s3.amazonaws.com) — no authentication required. DICOMweb access uses either the public IDC proxy (proxy.imaging.datacommons.cancer.gov, no auth) or the Google Cloud Healthcare API (healthcare.googleapis.com, requires GCP authentication). Optional BigQuery queries (bigquery.googleapis.com) also require GCP authentication. Citation resolution contacts DOI services. Public IDC routes require no credentials; optional Google clients use Application Default Credentials.
Reviewed 2026-09-30: idc-index 0.12.5, idc-index-data 24.2.2, IDC v24; hosted API 3.0.0b3. Recheck at use time.
Choose the access path first. There is no single default: the cheapest correct path depends on the session and the task.
Session already has the IDC MCP server? Route discovery and metadata there — see IDC MCP Server.
Otherwise, is
idc-indexinstalled and current? Runpython scripts/check_version.py. If it passes, useidc-indexfor everything.Not installed, and the task is read-only metadata — counts, attribute values, collection lookups, SQL under 10 000 rows, licenses, citations, viewer URLs? Use the REST API over
curl; do not install anything. Installing costs ~77 MB of packaged index data plus pandas, pyarrow, and duckdb, which a metadata question does not need. See Data Access Options.Not installed, and the task needs more than metadata — downloading files, pandas or plotting, pydicom/SimpleITK, pathology tiling, results past 10 000 rows, or a version-pinned script the user re-runs? Install
idc-index:check_version.pyexits non-zero and prints the exact install command for the running interpreter. Prefer a virtual environment, then restart Python.
idc-index (GitHub) is still the most
capable Python path, with query and download helpers in one client. check_version.py never installs anything itself — it also flags a newer
idc-index or skill release when one exists.
Setup for the idc-index path: use the intended interpreter for scripts/check_version.py
and confirm its meets pinned minimum message before continuing. A launch failure is not a pass.
from idc_index import IDCClient
client = IDCClient()
# Verify IDC data version (should be "v24")
print(f"IDC data version: {client.get_idc_version()}")Download and image-processing examples are illustrative unless noted; see the reference review notes for verification scope.
Core workflow: query metadata with client.sql_query() → download with
client.download_from_selection() → visualize with client.get_viewer_URL(). Python examples
below assume this client; Data Access Options has the REST equivalents. For current data
scale, run the summary query in references/sql_patterns.md or GET /v3/stats.
IDC MCP Server
IDC operates a hosted MCP server at https://api.imaging.datacommons.cancer.gov/mcp
(streamable HTTP, no authentication). Where it is available it complements — it does not
replace — the idc-index workflow below.
Identify it by the MCP resource idc://guide, or by three or more of the tool names
build_cohort, get_cohort_urls, list_analysis_results, and get_idc_version. Generic
names such as run_sql are not evidence on their own. If identification is ambiguous, use
idc-index.
If this session has the server, treat it as authoritative for discovery and metadata —
IDC version, counts, attribute values, cohort building, metadata SQL — and follow the
server's own instructions rather than re-deriving them from this file. Its data version is
whatever the server reports: call get_idc_version instead of relying on the version pinned
in this file.
Return here for what the server does not do: downloading files, local pandas/notebook
analysis, DICOMweb, BigQuery, digital pathology tiling, and reproducible scripts. Hand off by
passing SeriesInstanceUIDs from the server to client.download_from_selection(...), and run
scripts/check_version.py at that point.
If it is not available, the identical service is reachable with no configuration as a REST
API at https://api.imaging.datacommons.cancer.gov/v3 — use it for read-only metadata rather
than installing idc-index, per the routing gate in Overview. Suggest connecting the MCP
server at most once, only for repeated interactive discovery, and never change the user's
configuration yourself.
See references/mcp_guide.md for the tool inventory, handoff patterns, and per-host notes.
When to Use This Skill
Finding publicly available radiology (CT, MR, PET) or pathology (slide microscopy) images
Selecting image subsets by cancer type, modality, anatomical site, or other metadata
Downloading DICOM data from IDC
Checking data licenses before use in research or commercial applications
Visualizing medical images in a browser without local DICOM viewer software
Quick Navigation
Inline below: the MCP/REST routing rules, the IDC data model, the index tables and how they join, the core API patterns (query, download, visualize, license, cite), best practices, and troubleshooting.
Reference Guides (load on demand):
| Guide | When to Load |
|---|---|
index_tables_guide.md | Complex JOINs, schema discovery, DataFrame access |
use_cases.md | End-to-end workflows: training datasets, batch downloads, DICOM reading with pydicom/SimpleITK, pipeline integration |
sql_patterns.md | Quick SQL patterns for filter discovery, annotations, size estimation |
clinical_data_guide.md | Clinical/tabular data, imaging+clinical joins, value mapping |
licensing_and_citation.md | Commercial-use questions, mixed-license cohorts, citation formats |
cloud_storage_guide.md | Direct S3/GCS access, versioning, UUID mapping |
dicomweb_guide.md | DICOMweb endpoints, PACS integration |
digital_pathology_guide.md | Slide microscopy (SM), annotations (ANN), pathology workflows |
bigquery_guide.md | Full DICOM metadata, private elements (requires GCP) |
cli_guide.md | Command-line tools (idc download, manifest files) |
parquet_access_guide.md | Direct Parquet queries via GCS (no idc-index install needed) |
mcp_guide.md | Hosted IDC MCP server: tool inventory, identification, handoff to idc-index |
rest_api_guide.md | Hosted IDC REST API: endpoints, filter syntax, SQL over HTTP, manifests |
IDC Data Model
IDC adds two grouping levels above the standard DICOM hierarchy (Patient → Study → Series → Instance):
collection_id: Groups patients by disease, modality, or research focus (e.g.,
tcga_luad,nlst). Treat(collection_id, PatientID)as the patient key; do not assume PatientID is globally unique.analysis_result_id: Identifies derived objects (segmentations, annotations, radiomics features) across one or more original collections. Use it to find AI-generated or expert annotations, while
collection_idfinds original imaging data (which may itself include deposited annotations).
Key identifiers for queries:
| Identifier | Scope | Use for |
|---|---|---|
collection_id | Dataset grouping | Filtering by project/study |
PatientID | Patient | Grouping images by patient |
StudyInstanceUID | DICOM study | Grouping of related series, visualization |
SeriesInstanceUID | DICOM series | Grouping of related series, visualization |
Index Tables
The idc-index package provides multiple metadata index tables, accessible via SQL or as pandas DataFrames. The REST API exposes the same tables through GET /tables and POST /sql.
Important: client.indices_overview is the authoritative source for current table descriptions, available columns, and their types — query it when writing SQL or exploring data structure. It also answers "which table contains column X"; see references/index_tables_guide.md for that search pattern and full schema discovery.
Available Tables
Always call client.fetch_index("table_name") before querying any index table — it is safe and idempotent for all tables, including those loaded automatically at startup.
| Family | Tables | Granularity |
|---|---|---|
| Core | index (primary metadata for all current data), collections_index, analysis_results_index | series / collection / analysis result |
| Modality acquisition parameters | ct_index, mr_index, pt_index, contrast_index | 1 row = 1 series of that modality |
| Derived objects | seg_index, rtstruct_index, ann_index, ann_group_index | 1 row = 1 series (or annotation group) |
| Microscopy | sm_index, sm_instance_index | 1 row = 1 SM series / instance |
| Geometry, clinical, history | volume_geometry_index, clinical_index, version_metadata_index, prior_versions_index | see guide |
references/index_tables_guide.md has the full inventory with each table's columns and
contents — load it when you need to know what a specialized table actually holds.
prior_versions_index contains historical series versions, including revised versions
whose DICOM SeriesInstanceUID still occurs in index. Pin crdc_series_uuid for historical
content. For "what's new" in the current release use
series_init_idc_version / series_revised_idc_version in the main index table, which are
not equivalent to this table's min_idc_version / max_idc_version.
Joining Tables
SeriesInstanceUID is the universal join key for all series-level specialized tables: sm_index, sm_instance_index, seg_index, ann_index, ann_group_index, contrast_index, volume_geometry_index, rtstruct_index, ct_index, mr_index, pt_index. Always join these to index on SeriesInstanceUID. The exceptions below use different column names.
| Join Column | Tables | Use Case |
|---|---|---|
collection_id | index, prior_versions_index, collections_index, clinical_index | Link series to collection metadata or clinical data |
analysis_result_id | index, analysis_results_index | Link series to analysis result metadata (annotations, segmentations) |
source_DOI | index, analysis_results_index | Link by publication DOI |
segmented_SeriesInstanceUID | seg_index → index | Link segmentation to its source image series (seg_index.segmented_SeriesInstanceUID = index.SeriesInstanceUID) |
referenced_SeriesInstanceUID | ann_index → index, rtstruct_index → index | Link annotation or RTSTRUCT to its source image series |
Note: subjects, updated, and description appear in multiple tables but have different meanings (counts vs identifiers, different update contexts). A UID-only join to prior_versions_index can match several historical revisions; use CRDC UUIDs to distinguish them.
For detailed join examples, schema discovery patterns, key columns reference, and DataFrame access, see references/index_tables_guide.md.
Clinical Data Access
Clinical (non-imaging) attributes — staging, demographics, therapy — live in per-collection
tables. client.fetch_index("clinical_index") loads the dictionary mapping columns to
collections; client.get_clinical_table(name) returns one table as a DataFrame.
See references/clinical_data_guide.md for the discovery workflow, coded-value mapping, and
joining clinical data with imaging.
Data Access Options
| Method | Auth | Best For | Reference |
|---|---|---|---|
idc-index | No | Downloads, pandas analysis, unbounded queries — the most capable path | This document |
| IDC MCP server | No | Discovery, cohort building, metadata when the session already has it | mcp_guide.md |
| IDC REST API | No | Metadata with no install, from any language or shell — the default when idc-index is absent | rest_api_guide.md |
| Direct Parquet (GCS) | No | Version-pinned queries, or results past the REST row cap | parquet_access_guide.md |
| Cloud storage (S3/GCS) | No | Direct file access, bulk transfer, custom pipelines | cloud_storage_guide.md |
| DICOMweb via IDC proxy | No | Tool and PACS integration; daily quota, so testing and moderate use | dicomweb_guide.md |
| DICOMweb via Google Healthcare | Yes (GCP) | The same DICOMweb API at production volume, without the proxy quota | dicomweb_guide.md |
| SlicerIDCBrowser | No | 3D visualization and analysis in 3D Slicer | https://github.com/ImagingDataCommons/SlicerIDCBrowser |
| BigQuery | Yes (GCP) | Full DICOM metadata, private elements, SR measurements — last resort | bigquery_guide.md |
The IDC Portal (https://portal.imaging.datacommons.cancer.gov/) is interactive only — browser-based exploration, manual cohort selection, and download. Unlike every option above it has no programmatic interface, so point a user there to browse or click through data themselves; never use it as a step in a script or workflow.
REST API — the no-install metadata path
https://api.imaging.datacommons.cancer.gov/v3, no authentication: discovery, cohort counts and
manifests, read-only SQL, clinical tables, viewer URLs, licenses, citations. It is the same
service as the MCP server over plain HTTP, so it needs no configuration. It never moves image
bytes — switch to idc-index to download, to get a DataFrame, or for results past 10 000 rows.
B=https://api.imaging.datacommons.cancer.gov/v3
curl -s $B/version # idc_version, idc_index_data_version, api_version
curl -s $B/stats # collections, patients, studies, series, instances, size_TB
curl -s "$B/attributes/Modality/values?limit=5" # real filter values, with counts
curl -s $B/sql -H 'content-type: application/json' \
-d '{"sql":"SELECT collection_id, COUNT(*) n FROM index GROUP BY 1 ORDER BY n DESC LIMIT 3"}'
curl -s $B/cohort/counts -H 'content-type: application/json' \
-d '{"filters":{"terms":{"collection_id":["rider_pilot"]}}}'The filter object always goes under filters — on cohort/counts, cohort/manifest,
cohort/manifest.txt, licenses, and citations alike. A bare filter or an unrecognized key is
a 422 naming the fix; an unfiltered series-enumerating request is a 400, not the whole archive.
Filtered JSON responses echo filters_applied and warnings (inside counts for manifests) — read them, because they name
any predicate the server dropped. A zero count with empty warnings therefore means the filter
matched nothing, not that a value was miscased; miscasing produces a warning that says so.
POST /sql takes one read-only SELECT/WITH over the tables idc-index exposes plus
clinical.<table>; max_rows defaults to 5 000, caps at 10 000, and truncated flags clipping.
GET /attributes lists the 19 filterable attributes — clinical values, segmented anatomy, and
acquisition parameters are not among them and need SQL. Request limits still apply. Use
v3 only: V1 and V2 are superseded and scheduled for shutdown, so port any /v1/- or
Modality_btw-style example a user brings rather than extending it.
Both sides build on idc-index-data, so compare the API's idc_index_data_version against local
idc_index_data.__version__ before mixing them: the major is the IDC data release (24.x.y
serves v24); minor/patch index builds may correct metadata. If the API is a whole
release ahead, idc-index cannot download the extra series — mixed selections can omit
unrecognized UIDs, while wholly unmatched selections raise — so either upgrade it (run scripts/check_version.py for the right command)
or transfer directly from the bucket with s5cmd --no-sign-request.
See references/rest_api_guide.md for the endpoint reference, filter grounding, limits, and the
manifest-based download flow.
Cloud storage organization
All DICOM files live in public buckets mirrored between AWS S3 and GCS, organized by CRDC UUIDs
(not DICOM UIDs) to support versioning, as <crdc_series_uuid>/<crdc_instance_uuid>.dcm. Access
is free (no egress fees) via AWS CLI, gsutil, or s5cmd with anonymous access; use the
series_aws_url column for S3 URLs. Bucket names do not establish a license; query license_short_name for each selected series. See references/cloud_storage_guide.md for the full
bucket list and UUID mapping.
DICOMweb access
IDC data is available via DICOMweb (Google Cloud Healthcare API) for PACS integration and
DICOMweb-compatible tools: a public proxy (no auth, daily quota) for testing and moderate
queries, or Google Healthcare (GCP auth) for production volumes. See
references/dicomweb_guide.md.
Direct Parquet access
The idc-index metadata tables are also published as Parquet on a public GCS bucket
(idc-index-data-artifacts), queryable with DuckDB or pandas. This needs DuckDB installed
For ad-hoc metadata prefer REST /sql; choose Parquet for pinned versions or large results.
A separate public S3 export also includes clinical tables and full BigQuery metadata. See
references/parquet_access_guide.md.
Core Capabilities
The patterns below are the ones that go wrong when recalled from memory rather than checked. Worked examples for each area live in the reference guides named inline.
1. Discovery — enumerate values before filtering on them
Filtering on a guessed Modality or BodyPartExamined string is the most common cause of an
empty result set. Enumerate first:
modalities = client.sql_query("""
SELECT DISTINCT Modality, COUNT(*) as series_count
FROM index
GROUP BY Modality
ORDER BY series_count DESC
""")
print(modalities)The same pattern works for any filter column, optionally narrowed by another —
BodyPartExamined within a Modality, Manufacturer, collection_id. On the REST path this
grounding is a single call — GET /attributes/{attr}/values returns values with counts — and the
cohort endpoints report a miscased value in warnings rather than as an empty result.
Two indices carry curated collection-level metadata the primary index does not, both
requiring client.fetch_index(...) first: collections_index (cancer types, tumor locations,
species, subject counts) and analysis_results_index (derived datasets — AI segmentations,
expert annotations, radiomics — with their source collections and modalities).
Cancer type lives in collections_index.cancer_types, not in index — filtering by
cancer type requires a join:
client.fetch_index("collections_index")
results = client.sql_query("""
SELECT i.collection_id, i.PatientID, i.SeriesInstanceUID, i.Modality
FROM index i
JOIN collections_index c ON i.collection_id = c.collection_id
WHERE c.cancer_types LIKE '%Breast%'
AND i.Modality = 'MR'
LIMIT 20
""")client.sql_query() returns a pandas DataFrame. Confirm column names with
client.get_index_schema('index') or client.indices_overview before writing a query rather
than assuming them.
See references/sql_patterns.md for filter-value discovery, annotation and segmentation
queries, size estimation, clinical linking, and version tracking ("what's new in vX" — use
series_init_idc_version / series_revised_idc_version in index; historical objects use
prior_versions_index).
2. Downloading DICOM files
The two download methods take their first two arguments in opposite order. This is the most common source of broken IDC code — check it rather than recalling it:
| Method | First arg | Second arg | Use when |
|---|---|---|---|
download_from_selection | downloadDir (required) | filter kwargs (optional) | Filtering by collection, patient, study, or series |
download_dicom_series | seriesInstanceUID (required) | downloadDir (required) | Downloading specific series by UID only |
download_from_selection takes filter keyword arguments, NOT a DataFrame. The name
"from_selection" refers to filtering the IDC index by criteria — not to accepting a pandas
DataFrame. To download query results, extract the UIDs into a list first:
# Step 1: Query for series UIDs
series_df = client.sql_query("""
SELECT SeriesInstanceUID
FROM index
WHERE Modality = 'CT'
AND BodyPartExamined = 'CHEST'
AND collection_id = 'nlst'
LIMIT 5
""")
# Step 2: Extract UIDs as a list from the DataFrame
uids = list(series_df['SeriesInstanceUID'].values)
# Step 3: Pass the list to download_from_selection (NOT the DataFrame itself)
client.download_from_selection(
downloadDir="./data/lung_ct",
seriesInstanceUID=uids # list of strings, not a DataFrame
)
# Alternative: download_dicom_series has seriesInstanceUID as FIRST arg (different order!)
client.download_dicom_series(
seriesInstanceUID=uids, # FIRST arg here
downloadDir="./data/lung_ct"
)
# Whole collection: downloadDir is still the FIRST positional argument
client.download_from_selection(downloadDir="./data/rider", collection_id="rider_pilot")Both default to AWS; use source_bucket_location="gcs" for Google. In 0.12.5 the most-specific
selector wins, so use SQL first for intersecting criteria and verify every requested UID exists.
Downloaded files are named <crdc_instance_uuid>.dcm, not by SOPInstanceUID. The DICOM
UIDs are preserved inside the file metadata, not in the filename. Read DICOM headers for the
series UID; crdc_instance_uuid is not a column of the series-level index.
idc download <collection|series-uid|manifest> --download-dir ./data does the same from a
shell. See references/cli_guide.md for the dirTemplate hierarchy options (Python default:
%collection_id/%PatientID/%StudyInstanceUID/%Modality_%SeriesInstanceUID; dirTemplate=""
flattens), manifest downloads with resume, and dry-run size estimation.
3. Visualizing IDC images
viewer_url = client.get_viewer_URL(seriesInstanceUID=uid) # one series
viewer_url = client.get_viewer_URL(studyInstanceUID=study_uid) # all series in a studyReturns a browser URL — nothing is downloaded. The method selects OHIF v3 for radiology or SLIM for slide microscopy automatically. Viewing by study is useful when a single DICOM Study holds several Series (T1, T2, and DWI from one MRI session).
4. Licenses and citations — obligations, not optional steps
IDC data carries license terms and attribution requirements that follow it into any downstream publication or product, and neither is inferable from the pixel data. Check the license before use, and generate citations for whatever you download.
# License breakdown for a selection
licenses = client.sql_query("""
SELECT DISTINCT collection_id, license_short_name,
COUNT(DISTINCT SeriesInstanceUID) as series_count
FROM index GROUP BY collection_id, license_short_name
""")
# Citations for the same selection you downloaded (APA by default)
for citation in client.citations_from_selection(collection_id="rider_pilot"):
print(citation)In the reviewed v24 snapshot, about 97% of IDC data by size is CC BY (commercial use allowed with attribution) and about 3% is CC BY-NC (non-commercial only). Licenses attach to series, not collections — 39 of 176 collections carry more than one — so check the selection you actually intend to use, and note that each component retains its license obligations.
Both tasks are available from all three access paths, so stay on whichever one the session is
already using: idc-index as above, POST /v3/licenses and POST /v3/citations over REST,
or the get_licenses and get_citations MCP tools. See
references/licensing_and_citation.md for the full license inventory, all three routes, the
citation formats (APA, BibTeX, CSL JSON, RDF Turtle), and what to include when publishing.
5. Reaching past the index
Pick the access path with the routing gate in Overview; Data Access Options above is the full routing table.
Before reaching for BigQuery (which needs a Google Cloud project and access), check whether a
specialized index table already has the column you want: search client.indices_overview,
then client.fetch_index(...) and query locally for free. Full instance metadata, per-segment
rows, and SR measurement tables require BigQuery or its public Parquet exports; these are
outside the compact idc-index tables.
Best Practices
Check schema before writing queries — Use
client.get_index_schema('index')(reads cached metadata, no SQL executed) orclient.indices_overviewto see all available columns and their descriptions. The version-tracking columnsseries_init_idc_versionandseries_revised_idc_versionin the mainindextable directly answer "what's new / when was this added" questions without touchingprior_versions_index.Use the index for IDC data content questions - Query the IDC index directly, via
client.sql_query()locally orPOST /v3/sqlover HTTP. Web sources (release notes, blog posts, documentation pages) are frequently out of date and will produce incorrect answers. The index is the authoritative source; use it even when web search is available.Verify the IDC data version at the start of a session -
client.get_idc_version(),GET /v3/version, or the MCPget_idc_versiontool, depending on the path in use (currently v24). For a stale local index, runscripts/check_version.pyand use the upgrade command it printsCheck licenses and generate citations - Query
license_short_nameand respect CC BY vs CC BY-NC terms; usecitations_from_selection()to produce citations fromsource_DOIfor publicationsExplore small, then commit - Use
LIMIT(or a lowmax_rows) while exploring, and check collection size before downloading — some collections are terabytes. Seereferences/cli_guide.mdKeep downloads reproducible - Organize with
dirTemplate(e.g.%collection_id/%PatientID/%Modality) and save the Series UIDs or manifest behind any dataset you build
Troubleshooting
Issue: ModuleNotFoundError: No module named 'idc_index'
Cause: idc-index package not installed
Solution: If the task is read-only metadata, do not install it — use the REST API instead (Data Access Options). Otherwise run
scripts/check_version.pyand use the install command it prints, which targets the running interpreter and pins the vetted version. For data analysis also add pandas, numpy, and pydicom (tested with pandas>=1.5, numpy>=1.23, pydicom>=2.3)
Issue: Download fails with connection timeout
Cause: Network instability or large download size
Solution: Download in smaller batches (10-20 series); see
references/cli_guide.mdfor--use-s5cmd-syncresume and retry guidance
Issue: BigQuery quota exceeded or billing errors
Cause: Project quotas, sandbox limits, or billing configuration prevent the query
Solution: Use idc-index mini-index for simple queries (no billing required), or see
references/bigquery_guide.mdfor cost optimization tips
Issue: Series UID not found or no data returned
Cause: Typo in UID, data not in the current IDC version, or wrong field name
Solution: Test with
LIMIT 5first, check field names againstclient.indices_overview, and confirm the series is in the current version (some old data is deprecated)
Issue: Column not found in index table (e.g., SliceThickness, PixelSpacing, KVP, EchoTime, InjectedDose)
Cause: The
indextable contains series-level metadata only; modality-specific acquisition and reconstruction parameters live in dedicated tables (ct_index,mr_index,pt_index)Solution: Search
client.indices_overviewfor the column to find its table — the loop is under Finding which table contains a column inreferences/index_tables_guide.md— then fetch and join onSeriesInstanceUID:client.fetch_index("ct_index") result = client.sql_query(""" SELECT i.SeriesInstanceUID, i.Modality, c.SliceThickness, c.KVP, c.PixelSpacing_row_mm FROM index i JOIN ct_index c USING (SeriesInstanceUID) WHERE i.collection_id = 'your_collection' """)
Issue: Downloaded DICOM files won't open
Cause: Corrupted download, or an object type the viewer does not handle — SEG, RTSTRUCT, SR, and slide microscopy all need specialized tools
Solution: Inspect
Modality,SOPClassUID, and transfer syntax with normalpydicom.dcmread; forced parsing is not validation. Check download integrity and decoder/viewer support before re-downloading; reserveforce=Truefor diagnosed non-Part-10 inputs.
Resources
Reference guides and their decision triggers are listed in Quick Navigation above.
IDC Portal: https://portal.imaging.datacommons.cancer.gov/explore/
Documentation: https://learn.canceridc.dev/ — Tutorials: https://github.com/ImagingDataCommons/IDC-Tutorials
User Forum: https://discourse.canceridc.dev/ — idc-index: https://github.com/ImagingDataCommons/idc-index
indices_reference — external index-table docs (may be ahead of the installed version)
Citation: Fedorov, A., et al. "National Cancer Institute Imaging Data Commons: Toward Transparency, Reproducibility, and Scalability in Imaging Artificial Intelligence." RadioGraphics 43.12 (2023). https://doi.org/10.1148/rg.230180
Skill updates: releases page; watch the repository (Watch → Custom → Releases)
Files
- ATTRIBUTION.mdAdded by AutoGineer1019 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md30.7 KiB
- references/bigquery_guide.md35.4 KiB
- references/cli_guide.md9.3 KiB
- references/clinical_data_guide.md12.1 KiB
- references/cloud_storage_guide.md14.2 KiB
- references/dicomweb_guide.md16.1 KiB
- references/digital_pathology_guide.md15.3 KiB
- references/index_tables_guide.md12.1 KiB
- references/licensing_and_citation.md10.0 KiB
- references/mcp_guide.md9.4 KiB
- references/parquet_access_guide.md9.8 KiB
- references/rest_api_guide.md33.3 KiB
- references/sql_patterns.md16.9 KiB
- references/use_cases.md8.5 KiB
- scripts/check_version.pyScript5.5 KiB
references/digital_pathology_guide.md
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.
Index Tables for Digital Pathology
Five specialized index tables provide curated metadata without needing BigQuery:
| Table | Row Granularity | Description |
|---|---|---|
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 |
sm_instance_index | 1 row = 1 SM instance | Instance-level (SOPInstanceUID) metadata for individual slide images |
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 |
ann_index | 1 row = 1 ANN series | Microscopy Bulk Simple Annotations series metadata; includes referenced_SeriesInstanceUID linking to the annotated slide |
ann_group_index | 1 row = 1 annotation group | Annotation 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.
Slide Microscopy Queries
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
""")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
""")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
""")Identifying Tumor vs Normal Slides
The sm_index table provides two ways to identify tissue type:
| Column | Use Case |
|---|---|
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. |
ContainerIdentifier | Slide/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. |
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)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).
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.
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
""")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
""")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
""")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
""")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
""")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.
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.
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
""")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
""")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
""")Join Patterns
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
""")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
""")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.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs an MCP server, Needs Python
The author says: Requires network access for hosted APIs, index fetching, citations, and downloads. Local Python workflows target idc-index 0.12.5; BigQuery and Google Healthcare require Google credentials.
Security
What our scanner noticed· Low risk
- Instructions that use the network
- Scripts that your agent may run
This skill includes scripts that your agent may run. Read them before you use it.
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Andrey Fedorov, @fedorov
- Publisher
- K-Dense (Community)
- Distributed by
- K-Dense
- Source
- K-Dense-AI/scientific-agent-skills · skills/imaging-data-commons · commit a25cf9e
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.md)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Andrey Fedorov, @fedorov or K-Dense.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download imaging-data-commons.zip