From ac4b8998f5fa7e69f0ea5d2f6c6cf564a1d496e7 Mon Sep 17 00:00:00 2001 From: Andrey Fedorov Date: Mon, 16 Feb 2026 12:27:13 -0500 Subject: [PATCH] check notebooks conform to general expectations --- .../workflows/check_notebook_standards.yml | 30 ++ .../collections_demos/nlst_exploration.ipynb | 4 +- notebooks/labs/idc_mhub_miccai23.ipynb | 342 +++++++++--------- ...tting_started_with_digital_pathology.ipynb | 3 +- .../microscopy_dicom_ann_intro.ipynb | 7 +- test/src/check_notebook_standards.py | 117 ++++++ 6 files changed, 328 insertions(+), 175 deletions(-) create mode 100644 .github/workflows/check_notebook_standards.yml create mode 100644 test/src/check_notebook_standards.py diff --git a/.github/workflows/check_notebook_standards.yml b/.github/workflows/check_notebook_standards.yml new file mode 100644 index 0000000..cc4c3b6 --- /dev/null +++ b/.github/workflows/check_notebook_standards.yml @@ -0,0 +1,30 @@ +name: Check Notebook Standards + +on: + push: + branches: [ "master" ] + paths: + - "notebooks/**/*.ipynb" + - ".github/workflows/check_notebook_standards.yml" + - "test/src/check_notebook_standards.py" + pull_request: + branches: [ "master" ] + paths: + - "notebooks/**/*.ipynb" + - ".github/workflows/check_notebook_standards.yml" + - "test/src/check_notebook_standards.py" + +jobs: + check_standards: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Check notebook standards + run: python test/src/check_notebook_standards.py diff --git a/notebooks/collections_demos/nlst_exploration.ipynb b/notebooks/collections_demos/nlst_exploration.ipynb index 4ce09e6..2de04cd 100644 --- a/notebooks/collections_demos/nlst_exploration.ipynb +++ b/notebooks/collections_demos/nlst_exploration.ipynb @@ -43,7 +43,9 @@ "\n", "Initial release: Sept 2024\n", "\n", - "Prepared by: Andrey Fedorov" + "Prepared by: Andrey Fedorov\n", + "\n", + "Updated: Feb 2026" ], "metadata": { "id": "xHaCamADy1Q_" diff --git a/notebooks/labs/idc_mhub_miccai23.ipynb b/notebooks/labs/idc_mhub_miccai23.ipynb index a10f61a..e42b863 100644 --- a/notebooks/labs/idc_mhub_miccai23.ipynb +++ b/notebooks/labs/idc_mhub_miccai23.ipynb @@ -157,7 +157,7 @@ "description": "", "description_tooltip": null, "layout": "IPY_MODEL_3caf93bf09324ea6a273b18db9cd22a6", - "placeholder": "​", + "placeholder": "\u200b", "style": "IPY_MODEL_bb9a313d95fd49309348f2dd77fb7655", "value": "Job ID caf8ce9e-3042-487c-a64b-bea3d31c9048 successfully executed: 100%" } @@ -202,7 +202,7 @@ "description": "", "description_tooltip": null, "layout": "IPY_MODEL_ea80d2a28f674116957eb6589cc86652", - "placeholder": "​", + "placeholder": "\u200b", "style": "IPY_MODEL_6b4d29ad5d764160bf407c5e72521738", "value": "" } @@ -499,7 +499,7 @@ "description": "", "description_tooltip": null, "layout": "IPY_MODEL_730bb281b784483fad025fb9ca1531d9", - "placeholder": "​", + "placeholder": "\u200b", "style": "IPY_MODEL_c728b926dbe14960b32fa834ccf0729f", "value": "Downloading: 100%" } @@ -544,7 +544,7 @@ "description": "", "description_tooltip": null, "layout": "IPY_MODEL_c789637704394d6cabb948e21ab7976c", - "placeholder": "​", + "placeholder": "\u200b", "style": "IPY_MODEL_1ed4fa49c6354706b5341903f231175a", "value": "" } @@ -825,7 +825,9 @@ "\n", "This notebook demonstrates how to run models from [MHub.ai](https://mhub.ai) using [Imaging Data Commons (IDC)](https://portal.imaging.datacommons.cancer.gov/) data.\n", "\n", - "MHub is a novel platform, providing standardized medical imaging models with a harmonized I/O interface. MHub models are originally containerized to provide platform agnostic models that can be run locally or in the cloud without additional environmental setup. However, as it is not possible to run Docker images from within a Colab notebook, we instead setup the environment in the notebook based on the instructions outlined in the Dockerfile.\n" + "MHub is a novel platform, providing standardized medical imaging models with a harmonized I/O interface. MHub models are originally containerized to provide platform agnostic models that can be run locally or in the cloud without additional environmental setup. However, as it is not possible to run Docker images from within a Colab notebook, we instead setup the environment in the notebook based on the instructions outlined in the Dockerfile.\n", + "\n", + "Updated: Feb 2026" ], "metadata": { "id": "fZ6lYPDutv-t" @@ -1240,7 +1242,7 @@ "output_type": "display_data", "data": { "text/plain": [ - "Dropdown(index=1, options=('gc_lunglobes', 'lungmask', 'nnunet_pancreas', 'totalsegmentator', 'platipy', 'casu…" + "Dropdown(index=1, options=('gc_lunglobes', 'lungmask', 'nnunet_pancreas', 'totalsegmentator', 'platipy', 'casu\u2026" ], "application/vnd.jupyter.widget-view+json": { "version_major": 2, @@ -1330,7 +1332,7 @@ "output_type": "stream", "name": "stdout", "text": [ - "mkdir: cannot create directory ‘/app’: File exists\n", + "mkdir: cannot create directory \u2018/app\u2019: File exists\n", "Hit:1 http://archive.ubuntu.com/ubuntu jammy InRelease\n", "Get:2 http://security.ubuntu.com/ubuntu jammy-security InRelease [110 kB]\n", "Get:3 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [119 kB]\n", @@ -1934,30 +1936,30 @@ "Requirement already satisfied: pandas in /usr/local/lib/python3.10/dist-packages (from pyplastimatch) (2.1.1)\n", "Collecting pydicom (from pyplastimatch)\n", " Downloading pydicom-2.4.3-py3-none-any.whl (1.8 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.8/1.8 MB\u001b[0m \u001b[31m20.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m1.8/1.8 MB\u001b[0m \u001b[31m20.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hRequirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (from pyplastimatch) (2.31.0)\n", "Requirement already satisfied: scikit-image in /usr/local/lib/python3.10/dist-packages (from pyplastimatch) (0.19.3)\n", "Collecting SimpleITK (from pyplastimatch)\n", " Downloading SimpleITK-2.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (52.6 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m52.6/52.6 MB\u001b[0m \u001b[31m32.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m52.6/52.6 MB\u001b[0m \u001b[31m32.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting itk-core==5.3.0 (from itk->pyplastimatch)\n", " Downloading itk_core-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl (81.2 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m81.2/81.2 MB\u001b[0m \u001b[31m8.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m81.2/81.2 MB\u001b[0m \u001b[31m8.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting itk-numerics==5.3.0 (from itk->pyplastimatch)\n", " Downloading itk_numerics-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl (58.8 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m58.8/58.8 MB\u001b[0m \u001b[31m11.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m58.8/58.8 MB\u001b[0m \u001b[31m11.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting itk-io==5.3.0 (from itk->pyplastimatch)\n", " Downloading itk_io-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl (25.6 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m25.6/25.6 MB\u001b[0m \u001b[31m19.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m25.6/25.6 MB\u001b[0m \u001b[31m19.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting itk-filtering==5.3.0 (from itk->pyplastimatch)\n", " Downloading itk_filtering-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl (73.5 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m73.5/73.5 MB\u001b[0m \u001b[31m24.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m73.5/73.5 MB\u001b[0m \u001b[31m24.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting itk-registration==5.3.0 (from itk->pyplastimatch)\n", " Downloading itk_registration-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl (26.6 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m26.6/26.6 MB\u001b[0m \u001b[31m24.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m26.6/26.6 MB\u001b[0m \u001b[31m24.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting itk-segmentation==5.3.0 (from itk->pyplastimatch)\n", " Downloading itk_segmentation-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl (16.5 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m16.5/16.5 MB\u001b[0m \u001b[31m26.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m16.5/16.5 MB\u001b[0m \u001b[31m26.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hRequirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->pyplastimatch) (1.1.1)\n", "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib->pyplastimatch) (0.12.0)\n", "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->pyplastimatch) (4.43.0)\n", @@ -1996,7 +1998,7 @@ "Requirement already satisfied: pip in /usr/local/lib/python3.10/dist-packages (23.1.2)\n", "Collecting pip\n", " Downloading pip-23.2.1-py3-none-any.whl (2.1 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.1/2.1 MB\u001b[0m \u001b[31m21.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m2.1/2.1 MB\u001b[0m \u001b[31m21.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hInstalling collected packages: pip\n", " Attempting uninstall: pip\n", " Found existing installation: pip 23.1.2\n", @@ -2006,7 +2008,7 @@ "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.10/dist-packages (4.5.0)\n", "Collecting Pillow==9.5.0\n", " Downloading Pillow-9.5.0-cp310-cp310-manylinux_2_28_x86_64.whl (3.4 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m3.4/3.4 MB\u001b[0m \u001b[31m35.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m3.4/3.4 MB\u001b[0m \u001b[31m35.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hRequirement already satisfied: h5py in /usr/local/lib/python3.10/dist-packages (3.9.0)\n", "Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (1.23.5)\n", "Requirement already satisfied: pandas in /usr/local/lib/python3.10/dist-packages (2.1.1)\n", @@ -2022,7 +2024,7 @@ "Requirement already satisfied: pyplastimatch in /usr/local/lib/python3.10/dist-packages (0.4.3)\n", "Collecting SimpleITK==2.2.1\n", " Downloading SimpleITK-2.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (52.7 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m52.7/52.7 MB\u001b[0m \u001b[31m3.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m52.7/52.7 MB\u001b[0m \u001b[31m3.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting thedicomsort\n", " Downloading thedicomsort-1.0.1-py3-none-any.whl (8.2 kB)\n", "Collecting colorspacious\n", @@ -2033,30 +2035,30 @@ "Requirement already satisfied: click in /usr/local/lib/python3.10/dist-packages (from panimg) (8.1.7)\n", "Collecting construct (from panimg)\n", " Downloading construct-2.10.68.tar.gz (57 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m57.9/57.9 kB\u001b[0m \u001b[31m220.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m57.9/57.9 kB\u001b[0m \u001b[31m220.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", "Collecting imagecodecs>=2023.3.16 (from panimg)\n", " Obtaining dependency information for imagecodecs>=2023.3.16 from https://files.pythonhosted.org/packages/9d/df/e5bfe235e0098a445b022979d67cb2ce5fa5dd058f4f871cbb01124717c0/imagecodecs-2023.9.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n", " Downloading imagecodecs-2023.9.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (20 kB)\n", "Collecting openslide-python (from panimg)\n", " Downloading openslide-python-1.3.0.tar.gz (358 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m358.9/358.9 kB\u001b[0m \u001b[31m371.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m358.9/358.9 kB\u001b[0m \u001b[31m371.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", "Collecting pydantic>=2 (from panimg)\n", " Obtaining dependency information for pydantic>=2 from https://files.pythonhosted.org/packages/73/66/0a72c9fcde42e5650c8d8d5c5c1873b9a3893018020c77ca8eb62708b923/pydantic-2.4.2-py3-none-any.whl.metadata\n", " Downloading pydantic-2.4.2-py3-none-any.whl.metadata (158 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m158.6/158.6 kB\u001b[0m \u001b[31m349.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m158.6/158.6 kB\u001b[0m \u001b[31m349.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting pylibjpeg (from panimg)\n", " Downloading pylibjpeg-1.4.0-py3-none-any.whl (28 kB)\n", "Collecting pylibjpeg-libjpeg (from panimg)\n", " Downloading pylibjpeg_libjpeg-1.3.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.3 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m4.3/4.3 MB\u001b[0m \u001b[31m183.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m4.3/4.3 MB\u001b[0m \u001b[31m183.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting pylibjpeg-openjpeg (from panimg)\n", " Downloading pylibjpeg_openjpeg-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.4/1.4 MB\u001b[0m \u001b[31m340.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m1.4/1.4 MB\u001b[0m \u001b[31m340.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting pyvips (from panimg)\n", " Downloading pyvips-2.2.1.tar.gz (633 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m633.6/633.6 kB\u001b[0m \u001b[31m235.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m633.6/633.6 kB\u001b[0m \u001b[31m235.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", "Requirement already satisfied: tifffile in /usr/local/lib/python3.10/dist-packages (from panimg) (2023.9.26)\n", "Collecting wsidicom>=0.10.0 (from panimg)\n", @@ -2064,7 +2066,7 @@ " Downloading wsidicom-0.12.0-py3-none-any.whl.metadata (13 kB)\n", "Collecting jsonschema<4.0.0,>=3.2.0 (from pydicom-seg)\n", " Downloading jsonschema-3.2.0-py2.py3-none-any.whl (56 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m56.3/56.3 kB\u001b[0m \u001b[31m263.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m56.3/56.3 kB\u001b[0m \u001b[31m263.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hRequirement already satisfied: opencv-python in /usr/local/lib/python3.10/dist-packages (from rt_utils) (4.8.0.76)\n", "Collecting dataclasses (from rt_utils)\n", " Downloading dataclasses-0.6-py3-none-any.whl (14 kB)\n", @@ -2076,7 +2078,7 @@ "Requirement already satisfied: attrs>=17.4.0 in /usr/local/lib/python3.10/dist-packages (from jsonschema<4.0.0,>=3.2.0->pydicom-seg) (23.1.0)\n", "Collecting pyrsistent>=0.14.0 (from jsonschema<4.0.0,>=3.2.0->pydicom-seg)\n", " Downloading pyrsistent-0.19.3-py3-none-any.whl (57 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m57.5/57.5 kB\u001b[0m \u001b[31m222.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m57.5/57.5 kB\u001b[0m \u001b[31m222.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hRequirement already satisfied: setuptools in /usr/local/lib/python3.10/dist-packages (from jsonschema<4.0.0,>=3.2.0->pydicom-seg) (67.7.2)\n", "Requirement already satisfied: six>=1.11.0 in /usr/local/lib/python3.10/dist-packages (from jsonschema<4.0.0,>=3.2.0->pydicom-seg) (1.16.0)\n", "Collecting annotated-types>=0.4.0 (from pydantic>=2->panimg)\n", @@ -2090,7 +2092,7 @@ " Downloading typing_extensions-4.8.0-py3-none-any.whl.metadata (3.0 kB)\n", "Collecting dicomweb-client<0.60.0,>=0.59.1 (from wsidicom>=0.10.0->panimg)\n", " Downloading dicomweb_client-0.59.1-py3-none-any.whl (60 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m60.9/60.9 kB\u001b[0m \u001b[31m292.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m60.9/60.9 kB\u001b[0m \u001b[31m292.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hRequirement already satisfied: itk-core==5.3.0 in /usr/local/lib/python3.10/dist-packages (from itk->pyplastimatch) (5.3.0)\n", "Requirement already satisfied: itk-numerics==5.3.0 in /usr/local/lib/python3.10/dist-packages (from itk->pyplastimatch) (5.3.0)\n", "Requirement already satisfied: itk-io==5.3.0 in /usr/local/lib/python3.10/dist-packages (from itk->pyplastimatch) (5.3.0)\n", @@ -2118,16 +2120,16 @@ "Collecting retrying>=1.3.3 (from dicomweb-client<0.60.0,>=0.59.1->wsidicom>=0.10.0->panimg)\n", " Downloading retrying-1.3.4-py3-none-any.whl (11 kB)\n", "Downloading panimg-0.13.1-py3-none-any.whl (50 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m50.8/50.8 kB\u001b[0m \u001b[31m259.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m50.8/50.8 kB\u001b[0m \u001b[31m259.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hDownloading imagecodecs-2023.9.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (37.3 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m37.3/37.3 MB\u001b[0m \u001b[31m187.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m37.3/37.3 MB\u001b[0m \u001b[31m187.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hDownloading pydantic-2.4.2-py3-none-any.whl (395 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m395.8/395.8 kB\u001b[0m \u001b[31m295.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m395.8/395.8 kB\u001b[0m \u001b[31m295.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hDownloading pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.0 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.0/2.0 MB\u001b[0m \u001b[31m377.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m2.0/2.0 MB\u001b[0m \u001b[31m377.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hDownloading typing_extensions-4.8.0-py3-none-any.whl (31 kB)\n", "Downloading wsidicom-0.12.0-py3-none-any.whl (101 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m101.5/101.5 kB\u001b[0m \u001b[31m262.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m101.5/101.5 kB\u001b[0m \u001b[31m262.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hDownloading annotated_types-0.5.0-py3-none-any.whl (11 kB)\n", "Building wheels for collected packages: construct, openslide-python, pyvips\n", " Building wheel for construct (setup.py) ... \u001b[?25l\u001b[?25hdone\n", @@ -2222,11 +2224,11 @@ "Connecting to objects.githubusercontent.com (objects.githubusercontent.com)|185.199.108.133|:443... connected.\n", "HTTP request sent, awaiting response... 200 OK\n", "Length: 21102129 (20M) [application/octet-stream]\n", - "Saving to: ‘/app/dcmqi-1.2.5-linux.tar.gz’\n", + "Saving to: \u2018/app/dcmqi-1.2.5-linux.tar.gz\u2019\n", "\n", "/app/dcmqi-1.2.5-li 100%[===================>] 20.12M 37.5MB/s in 0.5s \n", "\n", - "2023-10-05 23:08:40 (37.5 MB/s) - ‘/app/dcmqi-1.2.5-linux.tar.gz’ saved [21102129/21102129]\n", + "2023-10-05 23:08:40 (37.5 MB/s) - \u2018/app/dcmqi-1.2.5-linux.tar.gz\u2019 saved [21102129/21102129]\n", "\n", "dcmqi-1.2.5-linux/bin/\n", "dcmqi-1.2.5-linux/bin/itkimage2segimage\n", @@ -2280,9 +2282,9 @@ "Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.10/dist-packages (from sympy->torch->lungmask==0.2.16) (1.3.0)\n", "Downloading lungmask-0.2.16-py3-none-any.whl (19 kB)\n", "Downloading fill_voids-2.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.3 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.3/1.3 MB\u001b[0m \u001b[31m20.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m1.3/1.3 MB\u001b[0m \u001b[31m20.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hDownloading fastremap-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (6.0 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m6.0/6.0 MB\u001b[0m \u001b[31m5.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u001b[0m \u001b[32m6.0/6.0 MB\u001b[0m \u001b[31m5.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hInstalling collected packages: fastremap, fill-voids, lungmask\n", "Successfully installed fastremap-1.14.0 fill-voids-2.0.5 lungmask-0.2.16\n", "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", @@ -2303,11 +2305,11 @@ "Connecting to objects.githubusercontent.com (objects.githubusercontent.com)|185.199.109.133|:443... connected.\n", "HTTP request sent, awaiting response... 200 OK\n", "Length: 124340403 (119M) [application/octet-stream]\n", - "Saving to: ‘/root/.cache/torch/hub/checkpoints/unet_r231-d5d2fc3d.pth’\n", + "Saving to: \u2018/root/.cache/torch/hub/checkpoints/unet_r231-d5d2fc3d.pth\u2019\n", "\n", "unet_r231-d5d2fc3d. 100%[===================>] 118.58M 37.1MB/s in 3.4s \n", "\n", - "2023-10-05 23:08:54 (35.3 MB/s) - ‘/root/.cache/torch/hub/checkpoints/unet_r231-d5d2fc3d.pth’ saved [124340403/124340403]\n", + "2023-10-05 23:08:54 (35.3 MB/s) - \u2018/root/.cache/torch/hub/checkpoints/unet_r231-d5d2fc3d.pth\u2019 saved [124340403/124340403]\n", "\n", "--2023-10-05 23:08:54-- https://github.com/JoHof/lungmask/releases/download/v0.0/unet_ltrclobes-3a07043d.pth\n", "Resolving github.com (github.com)... 20.27.177.113\n", @@ -2319,11 +2321,11 @@ "Connecting to objects.githubusercontent.com (objects.githubusercontent.com)|185.199.109.133|:443... connected.\n", "HTTP request sent, awaiting response... 200 OK\n", "Length: 124338462 (119M) [application/octet-stream]\n", - "Saving to: ‘/root/.cache/torch/hub/checkpoints/unet_ltrclobes-3a07043d.pth’\n", + "Saving to: \u2018/root/.cache/torch/hub/checkpoints/unet_ltrclobes-3a07043d.pth\u2019\n", "\n", "unet_ltrclobes-3a07 100%[===================>] 118.58M 43.1MB/s in 2.8s \n", "\n", - "2023-10-05 23:08:57 (43.1 MB/s) - ‘/root/.cache/torch/hub/checkpoints/unet_ltrclobes-3a07043d.pth’ saved [124338462/124338462]\n", + "2023-10-05 23:08:57 (43.1 MB/s) - \u2018/root/.cache/torch/hub/checkpoints/unet_ltrclobes-3a07043d.pth\u2019 saved [124338462/124338462]\n", "\n" ] } @@ -2555,155 +2557,155 @@ "\u001b[96m\u001b[1m DicomImporter:\u001b[0m\n", "\n", ". Instance \u001b[3m\u001b[0m [/app/data/_global]\n", - "├── \u001b[96mid: global\u001b[0m\n", - "├── \u001b[96msid: global\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/DicomImporter.log] ✓\n", - "│ └── \u001b[96mmodule: DicomImporter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96mid: global\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96msid: global\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/DicomImporter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: DicomImporter\u001b[0m\n", ". Instance \u001b[3m\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046]\n", - "├── \u001b[96mid: f62f3665-11a6-42fd-b73c-ac184df726bb\u001b[0m\n", - "├── \u001b[96msid: 1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046\u001b[0m\n", - "├── \u001b[95mDICOM\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/dicom] ✓\n", - "│ └── \u001b[96mmod: ct\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96mid: f62f3665-11a6-42fd-b73c-ac184df726bb\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96msid: 1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mDICOM\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/dicom] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmod: ct\u001b[0m\n", "\n", "\u001b[96m\u001b[1m NiftiConverter:\u001b[0m\n", "\n", ". Instance \u001b[3m\u001b[0m [/app/data/_global]\n", - "├── \u001b[96mid: global\u001b[0m\n", - "├── \u001b[96msid: global\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/DicomImporter.log] ✓\n", - "│ └── \u001b[96mmodule: DicomImporter\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/NiftiConverter.log] ✓\n", - "│ └── \u001b[96mmodule: NiftiConverter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96mid: global\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96msid: global\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/DicomImporter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: DicomImporter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/NiftiConverter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: NiftiConverter\u001b[0m\n", ". Instance \u001b[3m\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046]\n", - "├── \u001b[96mid: f62f3665-11a6-42fd-b73c-ac184df726bb\u001b[0m\n", - "├── \u001b[96msid: 1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046\u001b[0m\n", - "├── \u001b[95mDICOM\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/dicom] ✓\n", - "│ └── \u001b[96mmod: ct\u001b[0m\n", - "├── \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/nifti/dicom.nii.gz] ✓\n", - "│ └── \u001b[96mmod: ct\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/nifti/dicom.pmconv.log] ✓\n", - "│ ├── \u001b[96mmod: ct\u001b[0m\n", - "│ └── \u001b[96mlog-task: conversion\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/NiftiConverter.log] ✓\n", - "│ └── \u001b[96mmodule: NiftiConverter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96mid: f62f3665-11a6-42fd-b73c-ac184df726bb\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96msid: 1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mDICOM\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/dicom] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmod: ct\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/nifti/dicom.nii.gz] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmod: ct\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/nifti/dicom.pmconv.log] \u2713\n", + "\u2502 \u251c\u2500\u2500 \u001b[96mmod: ct\u001b[0m\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mlog-task: conversion\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/NiftiConverter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: NiftiConverter\u001b[0m\n", "\n", "\u001b[96m\u001b[1m LungMaskRunner:\u001b[0m\n", "\n", ". Instance \u001b[3m\u001b[0m [/app/data/_global]\n", - "├── \u001b[96mid: global\u001b[0m\n", - "├── \u001b[96msid: global\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/DicomImporter.log] ✓\n", - "│ └── \u001b[96mmodule: DicomImporter\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/NiftiConverter.log] ✓\n", - "│ └── \u001b[96mmodule: NiftiConverter\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/LungMaskRunner.log] ✓\n", - "│ └── \u001b[96mmodule: LungMaskRunner\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96mid: global\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96msid: global\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/DicomImporter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: DicomImporter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/NiftiConverter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: NiftiConverter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/LungMaskRunner.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: LungMaskRunner\u001b[0m\n", ". Instance \u001b[3m\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046]\n", - "├── \u001b[96mid: f62f3665-11a6-42fd-b73c-ac184df726bb\u001b[0m\n", - "├── \u001b[96msid: 1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046\u001b[0m\n", - "├── \u001b[95mDICOM\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/dicom] ✓\n", - "│ └── \u001b[96mmod: ct\u001b[0m\n", - "├── \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/nifti/dicom.nii.gz] ✓\n", - "│ └── \u001b[96mmod: ct\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/nifti/dicom.pmconv.log] ✓\n", - "│ ├── \u001b[96mmod: ct\u001b[0m\n", - "│ └── \u001b[96mlog-task: conversion\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/NiftiConverter.log] ✓\n", - "│ └── \u001b[96mmodule: NiftiConverter\u001b[0m\n", - "├── \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/model/roi1_lungs.nii.gz] ✓\n", - "│ ├── \u001b[96mmod: seg\u001b[0m\n", - "│ ├── \u001b[96mmodel: LungMask\u001b[0m\n", - "│ └── \u001b[96mroi: RIGHT_LUNG,LEFT_LUNG\u001b[0m\n", - "├── \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/model/roi2_lunglobes.nii.gz] ✓\n", - "│ ├── \u001b[96mmod: seg\u001b[0m\n", - "│ ├── \u001b[96mmodel: LungMask\u001b[0m\n", - "│ └── \u001b[96mroi: LEFT_UPPER_LUNG_LOBE,LEFT_LOWER_LUNG_LOBE,RIGHT_UPPER_LUNG_LOBE,RIGHT_MIDDLE_LUNG_LOBE,RIGHT_LOWER_LUNG_LOBE\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/LungMaskRunner.log] ✓\n", - "│ └── \u001b[96mmodule: LungMaskRunner\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96mid: f62f3665-11a6-42fd-b73c-ac184df726bb\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96msid: 1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mDICOM\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/dicom] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmod: ct\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/nifti/dicom.nii.gz] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmod: ct\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/nifti/dicom.pmconv.log] \u2713\n", + "\u2502 \u251c\u2500\u2500 \u001b[96mmod: ct\u001b[0m\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mlog-task: conversion\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/NiftiConverter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: NiftiConverter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/model/roi1_lungs.nii.gz] \u2713\n", + "\u2502 \u251c\u2500\u2500 \u001b[96mmod: seg\u001b[0m\n", + "\u2502 \u251c\u2500\u2500 \u001b[96mmodel: LungMask\u001b[0m\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mroi: RIGHT_LUNG,LEFT_LUNG\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/model/roi2_lunglobes.nii.gz] \u2713\n", + "\u2502 \u251c\u2500\u2500 \u001b[96mmod: seg\u001b[0m\n", + "\u2502 \u251c\u2500\u2500 \u001b[96mmodel: LungMask\u001b[0m\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mroi: LEFT_UPPER_LUNG_LOBE,LEFT_LOWER_LUNG_LOBE,RIGHT_UPPER_LUNG_LOBE,RIGHT_MIDDLE_LUNG_LOBE,RIGHT_LOWER_LUNG_LOBE\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/LungMaskRunner.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: LungMaskRunner\u001b[0m\n", "\n", "\u001b[96m\u001b[1m DsegConverter:\u001b[0m\n", "\n", ". Instance \u001b[3m\u001b[0m [/app/data/_global]\n", - "├── \u001b[96mid: global\u001b[0m\n", - "├── \u001b[96msid: global\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/DicomImporter.log] ✓\n", - "│ └── \u001b[96mmodule: DicomImporter\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/NiftiConverter.log] ✓\n", - "│ └── \u001b[96mmodule: NiftiConverter\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/LungMaskRunner.log] ✓\n", - "│ └── \u001b[96mmodule: LungMaskRunner\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/DsegConverter.log] ✓\n", - "│ └── \u001b[96mmodule: DsegConverter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96mid: global\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96msid: global\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/DicomImporter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: DicomImporter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/NiftiConverter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: NiftiConverter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/LungMaskRunner.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: LungMaskRunner\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/DsegConverter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: DsegConverter\u001b[0m\n", ". Instance \u001b[3m\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046]\n", - "├── \u001b[96mid: f62f3665-11a6-42fd-b73c-ac184df726bb\u001b[0m\n", - "├── \u001b[96msid: 1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046\u001b[0m\n", - "├── \u001b[95mDICOM\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/dicom] ✓\n", - "│ └── \u001b[96mmod: ct\u001b[0m\n", - "├── \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/nifti/dicom.nii.gz] ✓\n", - "│ └── \u001b[96mmod: ct\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/nifti/dicom.pmconv.log] ✓\n", - "│ ├── \u001b[96mmod: ct\u001b[0m\n", - "│ └── \u001b[96mlog-task: conversion\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/NiftiConverter.log] ✓\n", - "│ └── \u001b[96mmodule: NiftiConverter\u001b[0m\n", - "├── \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/model/roi1_lungs.nii.gz] ✓\n", - "│ ├── \u001b[96mmod: seg\u001b[0m\n", - "│ ├── \u001b[96mmodel: LungMask\u001b[0m\n", - "│ └── \u001b[96mroi: RIGHT_LUNG,LEFT_LUNG\u001b[0m\n", - "├── \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/model/roi2_lunglobes.nii.gz] ✓\n", - "│ ├── \u001b[96mmod: seg\u001b[0m\n", - "│ ├── \u001b[96mmodel: LungMask\u001b[0m\n", - "│ └── \u001b[96mroi: LEFT_UPPER_LUNG_LOBE,LEFT_LOWER_LUNG_LOBE,RIGHT_UPPER_LUNG_LOBE,RIGHT_MIDDLE_LUNG_LOBE,RIGHT_LOWER_LUNG_LOBE\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/LungMaskRunner.log] ✓\n", - "│ └── \u001b[96mmodule: LungMaskRunner\u001b[0m\n", - "├── \u001b[95mDICOMSEG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/seg.dcm] ✓\n", - "│ └── \u001b[96mmod: seg\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/DsegConverter.log] ✓\n", - "│ └── \u001b[96mmodule: DsegConverter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96mid: f62f3665-11a6-42fd-b73c-ac184df726bb\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96msid: 1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mDICOM\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/dicom] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmod: ct\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/nifti/dicom.nii.gz] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmod: ct\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/nifti/dicom.pmconv.log] \u2713\n", + "\u2502 \u251c\u2500\u2500 \u001b[96mmod: ct\u001b[0m\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mlog-task: conversion\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/NiftiConverter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: NiftiConverter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/model/roi1_lungs.nii.gz] \u2713\n", + "\u2502 \u251c\u2500\u2500 \u001b[96mmod: seg\u001b[0m\n", + "\u2502 \u251c\u2500\u2500 \u001b[96mmodel: LungMask\u001b[0m\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mroi: RIGHT_LUNG,LEFT_LUNG\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/model/roi2_lunglobes.nii.gz] \u2713\n", + "\u2502 \u251c\u2500\u2500 \u001b[96mmod: seg\u001b[0m\n", + "\u2502 \u251c\u2500\u2500 \u001b[96mmodel: LungMask\u001b[0m\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mroi: LEFT_UPPER_LUNG_LOBE,LEFT_LOWER_LUNG_LOBE,RIGHT_UPPER_LUNG_LOBE,RIGHT_MIDDLE_LUNG_LOBE,RIGHT_LOWER_LUNG_LOBE\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/LungMaskRunner.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: LungMaskRunner\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mDICOMSEG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/seg.dcm] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmod: seg\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/DsegConverter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: DsegConverter\u001b[0m\n", "\n", "\u001b[96m\u001b[1m DataOrganizer:\u001b[0m\n", "\n", ". Instance \u001b[3m\u001b[0m [/app/data/_global]\n", - "├── \u001b[96mid: global\u001b[0m\n", - "├── \u001b[96msid: global\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/DicomImporter.log] ✓\n", - "│ └── \u001b[96mmodule: DicomImporter\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/NiftiConverter.log] ✓\n", - "│ └── \u001b[96mmodule: NiftiConverter\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/LungMaskRunner.log] ✓\n", - "│ └── \u001b[96mmodule: LungMaskRunner\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/DsegConverter.log] ✓\n", - "│ └── \u001b[96mmodule: DsegConverter\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/DataOrganizer.log] ✓\n", - "│ └── \u001b[96mmodule: DataOrganizer\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96mid: global\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96msid: global\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/DicomImporter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: DicomImporter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/NiftiConverter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: NiftiConverter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/LungMaskRunner.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: LungMaskRunner\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/DsegConverter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: DsegConverter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/_global/mhub_log/DataOrganizer.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: DataOrganizer\u001b[0m\n", ". Instance \u001b[3m\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046]\n", - "├── \u001b[96mid: f62f3665-11a6-42fd-b73c-ac184df726bb\u001b[0m\n", - "├── \u001b[96msid: 1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046\u001b[0m\n", - "├── \u001b[95mDICOM\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/dicom] ✓\n", - "│ └── \u001b[96mmod: ct\u001b[0m\n", - "├── \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/nifti/dicom.nii.gz] ✓\n", - "│ └── \u001b[96mmod: ct\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/nifti/dicom.pmconv.log] ✓\n", - "│ ├── \u001b[96mmod: ct\u001b[0m\n", - "│ └── \u001b[96mlog-task: conversion\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/NiftiConverter.log] ✓\n", - "│ └── \u001b[96mmodule: NiftiConverter\u001b[0m\n", - "├── \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/model/roi1_lungs.nii.gz] ✓\n", - "│ ├── \u001b[96mmod: seg\u001b[0m\n", - "│ ├── \u001b[96mmodel: LungMask\u001b[0m\n", - "│ └── \u001b[96mroi: RIGHT_LUNG,LEFT_LUNG\u001b[0m\n", - "├── \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/model/roi2_lunglobes.nii.gz] ✓\n", - "│ ├── \u001b[96mmod: seg\u001b[0m\n", - "│ ├── \u001b[96mmodel: LungMask\u001b[0m\n", - "│ └── \u001b[96mroi: LEFT_UPPER_LUNG_LOBE,LEFT_LOWER_LUNG_LOBE,RIGHT_UPPER_LUNG_LOBE,RIGHT_MIDDLE_LUNG_LOBE,RIGHT_LOWER_LUNG_LOBE\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/LungMaskRunner.log] ✓\n", - "│ └── \u001b[96mmodule: LungMaskRunner\u001b[0m\n", - "├── \u001b[95mDICOMSEG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/seg.dcm] ✓\n", - "│ └── \u001b[96mmod: seg\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/DsegConverter.log] ✓\n", - "│ └── \u001b[96mmodule: DsegConverter\u001b[0m\n", - "├── \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/DataOrganizer.log] ✓\n", - "│ └── \u001b[96mmodule: DataOrganizer\u001b[0m\n" + "\u251c\u2500\u2500 \u001b[96mid: f62f3665-11a6-42fd-b73c-ac184df726bb\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[96msid: 1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mDICOM\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/dicom] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmod: ct\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/nifti/dicom.nii.gz] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmod: ct\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/nifti/dicom.pmconv.log] \u2713\n", + "\u2502 \u251c\u2500\u2500 \u001b[96mmod: ct\u001b[0m\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mlog-task: conversion\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/NiftiConverter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: NiftiConverter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/model/roi1_lungs.nii.gz] \u2713\n", + "\u2502 \u251c\u2500\u2500 \u001b[96mmod: seg\u001b[0m\n", + "\u2502 \u251c\u2500\u2500 \u001b[96mmodel: LungMask\u001b[0m\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mroi: RIGHT_LUNG,LEFT_LUNG\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mNIFTI\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/model/roi2_lunglobes.nii.gz] \u2713\n", + "\u2502 \u251c\u2500\u2500 \u001b[96mmod: seg\u001b[0m\n", + "\u2502 \u251c\u2500\u2500 \u001b[96mmodel: LungMask\u001b[0m\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mroi: LEFT_UPPER_LUNG_LOBE,LEFT_LOWER_LUNG_LOBE,RIGHT_UPPER_LUNG_LOBE,RIGHT_MIDDLE_LUNG_LOBE,RIGHT_LOWER_LUNG_LOBE\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/LungMaskRunner.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: LungMaskRunner\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mDICOMSEG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/seg.dcm] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmod: seg\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/DsegConverter.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: DsegConverter\u001b[0m\n", + "\u251c\u2500\u2500 \u001b[95mLOG\u001b[0m [/app/data/sorted_data/1.3.6.1.4.1.32722.99.99.298991776521342375010861296712563382046/mhub_log/DataOrganizer.log] \u2713\n", + "\u2502 \u2514\u2500\u2500 \u001b[96mmodule: DataOrganizer\u001b[0m\n" ] } ] @@ -3159,7 +3161,7 @@ " }\n", "\n", " app.addMenuItem({\n", - " label: \"▶️ Run\",\n", + " label: \"\u25b6\ufe0f Run\",\n", " async callback() {\n", " await plugin.api.run({\n", " config: {},\n", @@ -3570,7 +3572,7 @@ " }\n", "\n", " app.addMenuItem({\n", - " label: \"▶️ Run\",\n", + " label: \"\u25b6\ufe0f Run\",\n", " async callback() {\n", " await plugin.api.run({\n", " config: {},\n", diff --git a/notebooks/pathomics/getting_started_with_digital_pathology.ipynb b/notebooks/pathomics/getting_started_with_digital_pathology.ipynb index 0629a68..3609fc4 100644 --- a/notebooks/pathomics/getting_started_with_digital_pathology.ipynb +++ b/notebooks/pathomics/getting_started_with_digital_pathology.ipynb @@ -29,6 +29,7 @@ "If you have any questions, bug reports, or feature requests please feel free to contact us at the [IDC discussion forum](https://discourse.canceridc.dev/)!\n", "\n", "-- *Initial version: August 2024*\\\n", + "Updated: Feb 2026", "-- *Last updated: Feb 2026" ] }, @@ -1544,7 +1545,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "Downloading data: 100%|██████████| 1.61G/1.61G [00:10<00:00, 152MB/s]\n" + "Downloading data: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 1.61G/1.61G [00:10<00:00, 152MB/s]\n" ] } ], diff --git a/notebooks/pathomics/microscopy_dicom_ann_intro.ipynb b/notebooks/pathomics/microscopy_dicom_ann_intro.ipynb index 8180193..1ea697e 100644 --- a/notebooks/pathomics/microscopy_dicom_ann_intro.ipynb +++ b/notebooks/pathomics/microscopy_dicom_ann_intro.ipynb @@ -34,6 +34,7 @@ "----------------------\n", "\n", "Initial version: Jan 2025 \n", + "Updated: Feb 2026", "Last updated: Feb 2026" ] }, @@ -211,7 +212,7 @@ "output_type": "stream", "name": "stderr", "text": [ - "Downloading data: 100%|██████████| 215M/215M [00:02<00:00, 106MB/s]\n" + "Downloading data: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 215M/215M [00:02<00:00, 106MB/s]\n" ] } ], @@ -398,7 +399,7 @@ "id": "AfxGQ-WXNGkj" }, "source": [ - "As previously mentioned, annotations can be accompanied by one or multiple measurements. In highdicom, they are returned as tuple of `(names, values, units)` each of them being a list of coded values. For the Pan-Cancer-Nuclei-Seg-DICOM collection these are each nuclei's area given in µm²." + "As previously mentioned, annotations can be accompanied by one or multiple measurements. In highdicom, they are returned as tuple of `(names, values, units)` each of them being a list of coded values. For the Pan-Cancer-Nuclei-Seg-DICOM collection these are each nuclei's area given in \u00b5m\u00b2." ] }, { @@ -626,7 +627,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "Downloading data: 100%|█████████▉| 492M/492M [00:03<00:00, 163MB/s]\n" + "Downloading data: 100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2589| 492M/492M [00:03<00:00, 163MB/s]\n" ] }, { diff --git a/test/src/check_notebook_standards.py b/test/src/check_notebook_standards.py new file mode 100644 index 0000000..f7bdb56 --- /dev/null +++ b/test/src/check_notebook_standards.py @@ -0,0 +1,117 @@ +""" +Check that all notebooks (excluding deprecated/) follow IDC-Tutorials standards: + 1. Include a "## Support" section + 2. Include a "## Acknowledgments" section + 3. Reference the IDC-Tutorials repository for additional tutorials + 4. Include an "Updated: " field +""" + +import json +import os +import re +import sys +from pathlib import Path + + +NOTEBOOKS_DIR = Path(__file__).resolve().parent.parent.parent / "notebooks" + +# Directories to skip +SKIP_DIRS = {"deprecated"} + +# Pattern for "Updated: " (e.g., "Updated: Feb 2026") +MONTH_PATTERN = ( + r"(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|" + r"Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|" + r"Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)" +) +UPDATED_RE = re.compile(rf"Updated:\s*{MONTH_PATTERN}\s+\d{{4}}") + +IDC_TUTORIALS_URL = "github.com/ImagingDataCommons/IDC-Tutorials" + + +def get_markdown_sources(notebook_path): + """Return a list of concatenated source strings for each markdown cell.""" + with open(notebook_path, "r", encoding="utf-8") as f: + nb = json.load(f) + cells = [] + for cell in nb.get("cells", []): + if cell.get("cell_type") == "markdown": + source = cell.get("source", []) + if isinstance(source, list): + text = "".join(source) + else: + text = source + cells.append(text) + return cells + + +def check_notebook(notebook_path): + """Check a single notebook for required standards. Returns list of issues.""" + issues = [] + cells = get_markdown_sources(notebook_path) + all_text = "\n".join(cells) + + # Check 1: "## Support" section + if "## Support" not in all_text: + issues.append("Missing '## Support' section") + + # Check 2: "## Acknowledgments" section (allow both spellings) + if "## Acknowledgments" not in all_text and "## Acknowledgements" not in all_text: + issues.append("Missing '## Acknowledgments' section") + + # Check 3: Reference to IDC-Tutorials repository + if IDC_TUTORIALS_URL not in all_text: + issues.append( + f"Missing reference to IDC-Tutorials repository ({IDC_TUTORIALS_URL})" + ) + + # Check 4: "Updated: " field + if not UPDATED_RE.search(all_text): + issues.append("Missing 'Updated: ' field (e.g., 'Updated: Feb 2026')") + + return issues + + +def find_notebooks(root_dir): + """Find all .ipynb files, excluding SKIP_DIRS.""" + notebooks = [] + for dirpath, dirnames, filenames in os.walk(root_dir): + # Remove skip dirs so os.walk doesn't descend into them + dirnames[:] = [d for d in dirnames if d not in SKIP_DIRS] + for fname in filenames: + if fname.endswith(".ipynb") and ".ipynb_checkpoints" not in dirpath: + notebooks.append(Path(dirpath) / fname) + return sorted(notebooks) + + +def main(): + notebooks = find_notebooks(NOTEBOOKS_DIR) + if not notebooks: + print("ERROR: No notebooks found!") + sys.exit(1) + + print(f"Checking {len(notebooks)} notebooks for standards compliance...\n") + + failed = {} + for nb_path in notebooks: + rel_path = nb_path.relative_to(NOTEBOOKS_DIR.parent) + issues = check_notebook(nb_path) + if issues: + failed[str(rel_path)] = issues + + if failed: + print("FAILED notebooks:\n") + for path, issues in sorted(failed.items()): + print(f" {path}:") + for issue in issues: + print(f" - {issue}") + print() + print(f"{len(failed)} notebook(s) failed standards checks.") + sys.exit(1) + else: + print("All notebooks passed standards checks.") + sys.exit(0) + + +if __name__ == "__main__": + main()