Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
178 changes: 178 additions & 0 deletions notebooks/nifti_writer_example.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 3,
"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\n",
"\n",
"# 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": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"TRASH/writer_examples/nifti_writer_examples/\n",
"├── PatientID-AliceSmith/\n",
"│   └── Study-Study003/\n",
"│   ├── CT_SeriesUID-13278.nii.gz\n",
"│   ├── CT_SeriesUID-13278_metadata.csv\n",
"│   ├── RTSTRUCT_SeriesUID-39256.nii.gz\n",
"│   └── RTSTRUCT_SeriesUID-39256_metadata.csv\n",
"├── PatientID-JaneDoe/\n",
"│   └── Study-Study002/\n",
"│   ├── CT_SeriesUID-24592.nii.gz\n",
"│   ├── CT_SeriesUID-24592_metadata.csv\n",
"│   ├── RTSTRUCT_SeriesUID-42098.nii.gz\n",
"│   └── RTSTRUCT_SeriesUID-42098_metadata.csv\n",
"└── PatientID-JohnAdams/\n",
" └── Study-Study001/\n",
" ├── CT_SeriesUID-93810.nii.gz\n",
" ├── CT_SeriesUID-93810_metadata.csv\n",
" ├── RTSTRUCT_SeriesUID-46048.nii.gz\n",
" └── RTSTRUCT_SeriesUID-46048_metadata.csv\n",
"\n",
"7 directories, 12 files\n",
"\n"
]
}
],
"source": [
"ROOT_DIRECTORY = Path(\"TRASH\", \"writer_examples\", \"nifti_writer_examples\")\n",
"FILENAME_FORMAT = \"PatientID-{PatientID}/Study-{Study}/{Modality}_SeriesUID-{SeriesUID}\"\n",
"\n",
"data_sets = []\n",
"random.seed(42) # Set random seed for reproducibility\n",
"\n",
"random_5d = lambda: random.randint(10000, 99999)\n",
"\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\"{FILENAME_FORMAT}.nii.gz\",\n",
" overwrite=True\n",
" ) as nifti_writer,\n",
" CSVWriter(\n",
" root_directory=ROOT_DIRECTORY, \n",
" filename_format=f\"{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": "python3"
},
"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
Loading