From 2c040440a7b5130c3dd1e2b43e875adfd7ba1bc9 Mon Sep 17 00:00:00 2001 From: Jermiah Joseph Date: Sat, 16 Mar 2024 15:48:02 -0400 Subject: [PATCH] feat: progressBar option --- docs/querying_api/DownloadSeries.rst | 77 +++++++++++++++++++++++++++ docs/querying_api/ExploringSeries.rst | 6 +-- src/nbiatoolkit/nbia.py | 13 +++-- 3 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 docs/querying_api/DownloadSeries.rst diff --git a/docs/querying_api/DownloadSeries.rst b/docs/querying_api/DownloadSeries.rst new file mode 100644 index 0000000..3ecfd1b --- /dev/null +++ b/docs/querying_api/DownloadSeries.rst @@ -0,0 +1,77 @@ +Download Series +^^^^^^^^^^^^^^ + + +The :meth:`downloadSeries` method is used to download an entire SeriesInstanceUID +from the NBIA Database. + +One of the features provided by the `nbiatoolkit` is the ability to configure +the folder structure of the downloaded files. This functionality is handled internally +by the `DICOMSorter` class. + +Configuration of the folder structure is done by passing a **`filePattern`** argument to the +:meth:`downloadSeries` method. The **`filePattern`** argument is a string constructed from +tags in the DICOM header. Tags are enclosed in `%` characters. For example, the following +**`filePattern`** string: + +.. code-block:: python + + filePattern = '%PatientID/%StudyInstanceUID/%SeriesInstanceUID/%InstanceNumber.dcm' + +will create a folder structure that looks like this: + +.. code-block:: bash + + PatientID + ├── StudyInstanceUID + │ └── SeriesInstanceUID + │ ├── 1.dcm + │ ├── 2.dcm + │ └── ... + ├── StudyInstanceUID + │ └── SeriesInstanceUID + │ ├── 1.dcm + │ ├── 2.dcm + │ └── ... + └── ... + +The **`filePattern`** string can be constructed from any DICOM tag. The following tags are +good candidates for constructing a **`filePattern`** string: + +- PatientID +- BodyPartExamined +- Modality +- StudyInstanceUID +- SeriesInstanceUID +- InstanceNumber +- SOPInstanceUID + + +To download a SeriesInstanceUID from the NBIA Database, use the :meth:`downloadSeries` method. + +.. automethod:: nbiatoolkit.NBIAClient.downloadSeries + + +.. tabs:: + .. tab:: Python + .. exec_code:: + + # --- hide: start --- + from nbiatoolkit import NBIAClient + # --- hide: stop --- + + filePattern = '%PatientID/%StudyInstanceUID/%SeriesInstanceUID/%InstanceNumber.dcm' + downloadDir = './NBIA-Download' + nParallel = 5 + + with NBIAClient(return_type="dataframe") as client: + series = client.getSeries( + PatientID='TCGA-G2-A2EK' + ) + + client.downloadSeries( + series.SeriesInstanceUID, + downloadDir, + filePattern, + nParallel + ) diff --git a/docs/querying_api/ExploringSeries.rst b/docs/querying_api/ExploringSeries.rst index 8c5aeb6..038c89a 100644 --- a/docs/querying_api/ExploringSeries.rst +++ b/docs/querying_api/ExploringSeries.rst @@ -23,7 +23,7 @@ The following examples demonstrate using the :meth:`getSeries`. .. tabs:: .. tab:: Python .. tabs:: - .. tab:: Filter by Collection + .. tab:: Filter by Collection .. exec_code:: # --- hide: start --- @@ -31,11 +31,11 @@ The following examples demonstrate using the :meth:`getSeries`. # --- hide: stop --- with NBIAClient(return_type="dataframe") as client: - series = client.Series( + series = client.getSeries( Collection = "TCGA-BLCA" ) - print(series.iloc[0]) + print(series.iloc[0]) .. tab:: Filter by Collection and PatientID .. exec_code:: diff --git a/src/nbiatoolkit/nbia.py b/src/nbiatoolkit/nbia.py index 43d7831..21160ad 100644 --- a/src/nbiatoolkit/nbia.py +++ b/src/nbiatoolkit/nbia.py @@ -42,6 +42,7 @@ def downloadSingleSeries( api_headers: dict[str, str], base_url: NBIA_BASE_URLS, log: Logger, + Progressbar: bool = False, ): """ Downloads a single series from the NBIA server. @@ -54,6 +55,7 @@ def downloadSingleSeries( api_headers (dict[str, str]): The headers to be included in the API request. base_url (NBIA_ENDPOINTS): The base URL of the NBIA server. log (Logger): The logger object for logging messages. + Progressbar (bool, optional): Flag indicating whether to display a progress bar. Defaults to False. Returns: bool: True if the series is downloaded and sorted successfully, False otherwise. @@ -89,7 +91,10 @@ def downloadSingleSeries( ) # sorter.sortDICOMFiles(option="move", overwrite=overwrite) if not sorter.sortDICOMFiles( - shutil_option="move", overwrite=overwrite, progressbar=False, n_parallel=1 + shutil_option="move", + overwrite=overwrite, + progressbar=Progressbar, + n_parallel=1, ): log.error( f"Error sorting DICOM files for series {SeriesInstanceUID}\n \ @@ -616,6 +621,7 @@ def downloadSeries( filePattern: str = "%PatientName/%Modality-%SeriesNumber-%SeriesInstanceUID/%InstanceNumber.dcm", overwrite: bool = False, nParallel: int = 1, + Progressbar: bool = False, ) -> bool: if isinstance(SeriesInstanceUID, str): SeriesInstanceUID = [SeriesInstanceUID] @@ -627,8 +633,8 @@ def downloadSeries( results = [] for series in SeriesInstanceUID: result = pool.apply_async( - downloadSingleSeries, - ( + func=downloadSingleSeries, + args=( series, downloadDir, filePattern, @@ -636,6 +642,7 @@ def downloadSeries( self._api_headers, self._base_url, self._log, + Progressbar, ), ) results.append(result)