Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion config/ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ include = [
"src/readii/loaders.py",
"src/readii/feature_extraction.py",
"src/readii/negative_controls_refactor/**.py",
"src/readii/io/writers/**.py",
]

# extend-exclude is used to exclude directories from the flake8 checks
Expand All @@ -15,7 +16,9 @@ extend-exclude = [
"src/readii/image_processing.py",
"src/readii/metadata.py",
"src/readii/negative_controls.py",
"src/readii/pipeline.py",]
"src/readii/pipeline.py",
"notebooks/*",
]

# Same as Black.
line-length = 100
Expand Down
218 changes: 218 additions & 0 deletions notebooks/nifti_writer_example.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Example subclass for writing NIFTI files"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Import the NIFTIWriter class created in READII along with other necessary imports"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from readii.io.writers.nifti_writer import NIFTIWriter\n",
"from readii.io.writers.base_writer import BaseWriter\n",
"from pathlib import Path\n",
"import subprocess\n",
"import SimpleITK as sitk\n",
"import pandas as pd\n",
"import uuid\n",
"import random\n",
"import sys\n",
"from readii.utils import logger"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Define a writer subclass for writing .csv files"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"# copy this writer from the other notebook:\n",
"class CSVWriter(BaseWriter): # noqa\n",
"\n",
" # The save method is the only method that needs to be implemented for the subclasses of BaseWriter\n",
" def save(self, data: list, **kwargs) -> Path: # noqa\n",
" output_path = self.resolve_path(**kwargs)\n",
" with output_path.open('w') as f: # noqa\n",
" pd.DataFrame(data).to_csv(f, index=False)\n",
" return output_path\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Show how the NIFTI Writer can be used on SimpleITK images"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"TRASH/writer_examples/nifti_writer_examples/\n",
"├── PatientID-AliceSmith/\n",
"│   ├── AliceSmith_metadata.csv\n",
"│   └── Study-Study003/\n",
"│   ├── CT/\n",
"│   │   └── CT_SeriesUID-13278.nii.gz\n",
"│   └── RTSTRUCT/\n",
"│   └── RTSTRUCT_SeriesUID-39256.nii.gz\n",
"├── PatientID-JaneDoe/\n",
"│   ├── JaneDoe_metadata.csv\n",
"│   └── Study-Study002/\n",
"│   ├── CT/\n",
"│   │   └── CT_SeriesUID-24592.nii.gz\n",
"│   └── RTSTRUCT/\n",
"│   └── RTSTRUCT_SeriesUID-42098.nii.gz\n",
"└── PatientID-JohnAdams/\n",
" ├── JohnAdams_metadata.csv\n",
" └── Study-Study001/\n",
" ├── CT/\n",
" │   └── CT_SeriesUID-93810.nii.gz\n",
" └── RTSTRUCT/\n",
" └── RTSTRUCT_SeriesUID-46048.nii.gz\n",
"\n",
"13 directories, 9 files\n",
"\n"
]
}
],
"source": [
"ROOT_DIRECTORY = Path(\"TRASH\", \"writer_examples\", \"nifti_writer_examples\")\n",
"IMAGE_FILENAME_FORMAT = \"PatientID-{PatientID}/Study-{Study}/{Modality}/{Modality}_SeriesUID-{SeriesUID}\"\n",
"METADATA_FILENAME_FORMAT = \"PatientID-{PatientID}/{PatientID}\"\n",
"\n",
"data_sets = []\n",
"random.seed(42) # Set random seed for reproducibility\n",
"\n",
"random_5d = lambda: random.randint(10000, 99999)\n",
"\n",
"# Set up some dummy images to save as NIFTI files\n",
"for MODALITY in [\"CT\", \"RTSTRUCT\"]:\n",
" data_sets.extend([\n",
" {\n",
" \"image\": sitk.Image(10, 10, 10, sitk.sitkInt16),\n",
" \"metadata\": pd.DataFrame({\"PatientID\": [\"JohnAdams\"], \"Study\": [\"Study001\"]}),\n",
" \"PatientID\": \"JohnAdams\",\n",
" \"Study\": \"Study001\",\n",
" \"Modality\": MODALITY,\n",
" \"SeriesUID\": random_5d(),\n",
" },\n",
" {\n",
" \"image\": sitk.Image(20, 20, 20, sitk.sitkInt16),\n",
" \"metadata\": pd.DataFrame({\"PatientID\": [\"JaneDoe\"], \"Study\": [\"Study002\"]}),\n",
" \"PatientID\": \"JaneDoe\",\n",
" \"Study\": \"Study002\",\n",
" \"Modality\": MODALITY,\n",
" \"SeriesUID\": random_5d(),\n",
" },\n",
" {\n",
" \"image\": sitk.Image(30, 30, 30, sitk.sitkInt16),\n",
" \"metadata\": pd.DataFrame({\"PatientID\": [\"AliceSmith\"], \"Study\": [\"Study003\"]}),\n",
" \"PatientID\": \"AliceSmith\",\n",
" \"Study\": \"Study003\",\n",
" \"Modality\": MODALITY,\n",
" \"SeriesUID\": random_5d(),\n",
" }\n",
" ])\n",
"\n",
"# Create a writer with the specified root directory and filename format\n",
"with (\n",
" NIFTIWriter(\n",
" root_directory=ROOT_DIRECTORY, \n",
" filename_format=f\"{IMAGE_FILENAME_FORMAT}.nii.gz\",\n",
" overwrite=True\n",
" ) as nifti_writer,\n",
" CSVWriter(\n",
" root_directory=ROOT_DIRECTORY, \n",
" filename_format=f\"{METADATA_FILENAME_FORMAT}_metadata.csv\",\n",
" ) as metadata_writer\n",
"):\n",
" # Iterate over the data sets and save them\n",
" for data_set in data_sets:\n",
"\n",
" # The actual data being saved is image or data, but the rest of the kwargs are \n",
" # only for resolving the filename\n",
" try:\n",
" nifti_writer.save(\n",
" image=data_set[\"image\"],\n",
" PatientID=data_set[\"PatientID\"],\n",
" Study=data_set[\"Study\"],\n",
" Modality=data_set[\"Modality\"],\n",
" SeriesUID=data_set[\"SeriesUID\"]\n",
" )\n",
" metadata_writer.save(\n",
" data=data_set[\"metadata\"],\n",
" PatientID=data_set[\"PatientID\"],\n",
" Study=data_set[\"Study\"],\n",
" Modality=data_set[\"Modality\"],\n",
" SeriesUID=data_set[\"SeriesUID\"]\n",
" )\n",
" except FileExistsError as e:\n",
" logger.exception(f\"Error saving data set: {e}\")\n",
" sys.exit(1)\n",
"\n",
"output = subprocess.check_output([\"tree\", \"-nF\", ROOT_DIRECTORY])\n",
"print(output.decode(\"utf-8\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "dev",
"language": "python",
"name": "dev"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.7"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Binary file added notebooks/nifti_writer_example.pdf
Binary file not shown.
Loading