petpal 0.5.9__tar.gz → 0.5.10__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. {petpal-0.5.9 → petpal-0.5.10}/PKG-INFO +1 -1
  2. {petpal-0.5.9 → petpal-0.5.10}/petpal/preproc/image_operations_4d.py +3 -4
  3. {petpal-0.5.9 → petpal-0.5.10}/petpal/preproc/symmetric_geometric_transfer_matrix.py +63 -17
  4. {petpal-0.5.9 → petpal-0.5.10}/pyproject.toml +1 -1
  5. petpal-0.5.10/tests/test_sgtm.py +53 -0
  6. {petpal-0.5.9 → petpal-0.5.10}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  7. {petpal-0.5.9 → petpal-0.5.10}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  8. {petpal-0.5.9 → petpal-0.5.10}/.github/workflows/publish-to-pypi.yml +0 -0
  9. {petpal-0.5.9 → petpal-0.5.10}/.github/workflows/python-package.yml +0 -0
  10. {petpal-0.5.9 → petpal-0.5.10}/.gitignore +0 -0
  11. {petpal-0.5.9 → petpal-0.5.10}/.readthedocs.yaml +0 -0
  12. {petpal-0.5.9 → petpal-0.5.10}/LICENSE +0 -0
  13. {petpal-0.5.9 → petpal-0.5.10}/README.md +0 -0
  14. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/1tcm/gaussian_noise/tac_1tcm_set-00.txt +0 -0
  15. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/1tcm/gaussian_noise/tac_1tcm_set-01.txt +0 -0
  16. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/1tcm/gaussian_noise/tac_1tcm_set-02.txt +0 -0
  17. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/1tcm/gaussian_noise/tacs.pdf +0 -0
  18. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/1tcm/gaussian_noise/tacs.png +0 -0
  19. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/1tcm/noise_free/tac_1tcm_set-00.txt +0 -0
  20. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/1tcm/noise_free/tac_1tcm_set-01.txt +0 -0
  21. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/1tcm/noise_free/tac_1tcm_set-02.txt +0 -0
  22. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/1tcm/noise_free/tacs.pdf +0 -0
  23. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/1tcm/noise_free/tacs.png +0 -0
  24. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/1tcm/params_1tcm_set-00.json +0 -0
  25. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/1tcm/params_1tcm_set-01.json +0 -0
  26. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/1tcm/params_1tcm_set-02.json +0 -0
  27. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/fdg_plasma_clamp_evenly_resampled.txt +0 -0
  28. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/fdg_plasma_clamp_evenly_resampled_woMax.txt +0 -0
  29. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/fdg_plasma_clamp_tacs.pdf +0 -0
  30. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/fdg_plasma_clamp_tacs.png +0 -0
  31. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/gen_tcms_data.ipynb +0 -0
  32. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/readme.md +0 -0
  33. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm/gaussian_noise/tac_2tcm_set-00.txt +0 -0
  34. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm/gaussian_noise/tac_2tcm_set-01.txt +0 -0
  35. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm/gaussian_noise/tac_2tcm_set-02.txt +0 -0
  36. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm/gaussian_noise/tacs.pdf +0 -0
  37. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm/gaussian_noise/tacs.png +0 -0
  38. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm/noise_free/tac_2tcm_set-00.txt +0 -0
  39. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm/noise_free/tac_2tcm_set-01.txt +0 -0
  40. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm/noise_free/tac_2tcm_set-02.txt +0 -0
  41. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm/noise_free/tacs.pdf +0 -0
  42. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm/noise_free/tacs.png +0 -0
  43. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm/params_serial_2tcm_set-00.json +0 -0
  44. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm/params_serial_2tcm_set-01.json +0 -0
  45. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm/params_serial_2tcm_set-02.json +0 -0
  46. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm_k4zero/gaussian_noise/tac_2tcm_k4zero_set-00.txt +0 -0
  47. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm_k4zero/gaussian_noise/tac_2tcm_k4zero_set-01.txt +0 -0
  48. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm_k4zero/gaussian_noise/tacs.pdf +0 -0
  49. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm_k4zero/gaussian_noise/tacs.png +0 -0
  50. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm_k4zero/noise_free/tac_2tcm_k4zero_set-00.txt +0 -0
  51. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm_k4zero/noise_free/tac_2tcm_k4zero_set-01.txt +0 -0
  52. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm_k4zero/noise_free/tacs.pdf +0 -0
  53. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm_k4zero/noise_free/tacs.png +0 -0
  54. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm_k4zero/params_serial_2tcm_k4zero_set-00.json +0 -0
  55. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/serial_2tcm_k4zero/params_serial_2tcm_k4zero_set-01.json +0 -0
  56. {petpal-0.5.9 → petpal-0.5.10}/data/tcm_tacs/turku_pet_center_fdg_plasma_clamp.txt +0 -0
  57. {petpal-0.5.9 → petpal-0.5.10}/docs/Makefile +0 -0
  58. {petpal-0.5.9 → petpal-0.5.10}/docs/PETPAL_Logo.png +0 -0
  59. {petpal-0.5.9 → petpal-0.5.10}/docs/_templates/index.rst +0 -0
  60. {petpal-0.5.9 → petpal-0.5.10}/docs/_templates/python/attribute.rst +0 -0
  61. {petpal-0.5.9 → petpal-0.5.10}/docs/_templates/python/class.rst +0 -0
  62. {petpal-0.5.9 → petpal-0.5.10}/docs/_templates/python/data.rst +0 -0
  63. {petpal-0.5.9 → petpal-0.5.10}/docs/_templates/python/exception.rst +0 -0
  64. {petpal-0.5.9 → petpal-0.5.10}/docs/_templates/python/function.rst +0 -0
  65. {petpal-0.5.9 → petpal-0.5.10}/docs/_templates/python/method.rst +0 -0
  66. {petpal-0.5.9 → petpal-0.5.10}/docs/_templates/python/module.rst +0 -0
  67. {petpal-0.5.9 → petpal-0.5.10}/docs/_templates/python/package.rst +0 -0
  68. {petpal-0.5.9 → petpal-0.5.10}/docs/_templates/python/property.rst +0 -0
  69. {petpal-0.5.9 → petpal-0.5.10}/docs/conf.py +0 -0
  70. {petpal-0.5.9 → petpal-0.5.10}/docs/index.rst +0 -0
  71. {petpal-0.5.9 → petpal-0.5.10}/docs/make.bat +0 -0
  72. {petpal-0.5.9 → petpal-0.5.10}/docs/requirements.txt +0 -0
  73. {petpal-0.5.9 → petpal-0.5.10}/docs/tutorials/index.rst +0 -0
  74. {petpal-0.5.9 → petpal-0.5.10}/docs/tutorials/pib_example.rst +0 -0
  75. {petpal-0.5.9 → petpal-0.5.10}/petpal/__init__.py +0 -0
  76. {petpal-0.5.9 → petpal-0.5.10}/petpal/cli/__init__.py +0 -0
  77. {petpal-0.5.9 → petpal-0.5.10}/petpal/cli/cli_graphical_analysis.py +0 -0
  78. {petpal-0.5.9 → petpal-0.5.10}/petpal/cli/cli_graphical_plots.py +0 -0
  79. {petpal-0.5.9 → petpal-0.5.10}/petpal/cli/cli_idif.py +0 -0
  80. {petpal-0.5.9 → petpal-0.5.10}/petpal/cli/cli_parametric_images.py +0 -0
  81. {petpal-0.5.9 → petpal-0.5.10}/petpal/cli/cli_pib_processing.py +0 -0
  82. {petpal-0.5.9 → petpal-0.5.10}/petpal/cli/cli_plot_tacs.py +0 -0
  83. {petpal-0.5.9 → petpal-0.5.10}/petpal/cli/cli_preproc.py +0 -0
  84. {petpal-0.5.9 → petpal-0.5.10}/petpal/cli/cli_pvc.py +0 -0
  85. {petpal-0.5.9 → petpal-0.5.10}/petpal/cli/cli_reference_tissue_models.py +0 -0
  86. {petpal-0.5.9 → petpal-0.5.10}/petpal/cli/cli_stats.py +0 -0
  87. {petpal-0.5.9 → petpal-0.5.10}/petpal/cli/cli_tac_fitting.py +0 -0
  88. {petpal-0.5.9 → petpal-0.5.10}/petpal/cli/cli_tac_interpolation.py +0 -0
  89. {petpal-0.5.9 → petpal-0.5.10}/petpal/cli/cli_vat_processing.py +0 -0
  90. {petpal-0.5.9 → petpal-0.5.10}/petpal/input_function/__init__.py +0 -0
  91. {petpal-0.5.9 → petpal-0.5.10}/petpal/input_function/blood_input.py +0 -0
  92. {petpal-0.5.9 → petpal-0.5.10}/petpal/input_function/idif_necktangle.py +0 -0
  93. {petpal-0.5.9 → petpal-0.5.10}/petpal/input_function/pca_guided_idif.py +0 -0
  94. {petpal-0.5.9 → petpal-0.5.10}/petpal/kinetic_modeling/__init__.py +0 -0
  95. {petpal-0.5.9 → petpal-0.5.10}/petpal/kinetic_modeling/fit_tac_with_rtms.py +0 -0
  96. {petpal-0.5.9 → petpal-0.5.10}/petpal/kinetic_modeling/graphical_analysis.py +0 -0
  97. {petpal-0.5.9 → petpal-0.5.10}/petpal/kinetic_modeling/parametric_images.py +0 -0
  98. {petpal-0.5.9 → petpal-0.5.10}/petpal/kinetic_modeling/reference_tissue_models.py +0 -0
  99. {petpal-0.5.9 → petpal-0.5.10}/petpal/kinetic_modeling/rtm_analysis.py +0 -0
  100. {petpal-0.5.9 → petpal-0.5.10}/petpal/kinetic_modeling/tac_fitting.py +0 -0
  101. {petpal-0.5.9 → petpal-0.5.10}/petpal/kinetic_modeling/tac_interpolation.py +0 -0
  102. {petpal-0.5.9 → petpal-0.5.10}/petpal/kinetic_modeling/tac_uncertainty.py +0 -0
  103. {petpal-0.5.9 → petpal-0.5.10}/petpal/kinetic_modeling/tcms_as_convolutions.py +0 -0
  104. {petpal-0.5.9 → petpal-0.5.10}/petpal/meta/__init__.py +0 -0
  105. {petpal-0.5.9 → petpal-0.5.10}/petpal/meta/label_maps.py +0 -0
  106. {petpal-0.5.9 → petpal-0.5.10}/petpal/pipelines/__init__.py +0 -0
  107. {petpal-0.5.9 → petpal-0.5.10}/petpal/pipelines/kinetic_modeling_steps.py +0 -0
  108. {petpal-0.5.9 → petpal-0.5.10}/petpal/pipelines/pca_guided_idif_steps.py +0 -0
  109. {petpal-0.5.9 → petpal-0.5.10}/petpal/pipelines/pipelines.py +0 -0
  110. {petpal-0.5.9 → petpal-0.5.10}/petpal/pipelines/preproc_steps.py +0 -0
  111. {petpal-0.5.9 → petpal-0.5.10}/petpal/pipelines/steps_base.py +0 -0
  112. {petpal-0.5.9 → petpal-0.5.10}/petpal/pipelines/steps_containers.py +0 -0
  113. {petpal-0.5.9 → petpal-0.5.10}/petpal/preproc/__init__.py +0 -0
  114. {petpal-0.5.9 → petpal-0.5.10}/petpal/preproc/decay_correction.py +0 -0
  115. {petpal-0.5.9 → petpal-0.5.10}/petpal/preproc/motion_corr.py +0 -0
  116. {petpal-0.5.9 → petpal-0.5.10}/petpal/preproc/motion_target.py +0 -0
  117. {petpal-0.5.9 → petpal-0.5.10}/petpal/preproc/partial_volume_corrections.py +0 -0
  118. {petpal-0.5.9 → petpal-0.5.10}/petpal/preproc/regional_tac_extraction.py +0 -0
  119. {petpal-0.5.9 → petpal-0.5.10}/petpal/preproc/register.py +0 -0
  120. {petpal-0.5.9 → petpal-0.5.10}/petpal/preproc/segmentation_tools.py +0 -0
  121. {petpal-0.5.9 → petpal-0.5.10}/petpal/preproc/standard_uptake_value.py +0 -0
  122. {petpal-0.5.9 → petpal-0.5.10}/petpal/utils/__init__.py +0 -0
  123. {petpal-0.5.9 → petpal-0.5.10}/petpal/utils/bids_utils.py +0 -0
  124. {petpal-0.5.9 → petpal-0.5.10}/petpal/utils/constants.py +0 -0
  125. {petpal-0.5.9 → petpal-0.5.10}/petpal/utils/data_driven_image_analyses.py +0 -0
  126. {petpal-0.5.9 → petpal-0.5.10}/petpal/utils/decorators.py +0 -0
  127. {petpal-0.5.9 → petpal-0.5.10}/petpal/utils/image_io.py +0 -0
  128. {petpal-0.5.9 → petpal-0.5.10}/petpal/utils/math_lib.py +0 -0
  129. {petpal-0.5.9 → petpal-0.5.10}/petpal/utils/metadata.py +0 -0
  130. {petpal-0.5.9 → petpal-0.5.10}/petpal/utils/scan_timing.py +0 -0
  131. {petpal-0.5.9 → petpal-0.5.10}/petpal/utils/stats.py +0 -0
  132. {petpal-0.5.9 → petpal-0.5.10}/petpal/utils/testing_utils.py +0 -0
  133. {petpal-0.5.9 → petpal-0.5.10}/petpal/utils/time_activity_curve.py +0 -0
  134. {petpal-0.5.9 → petpal-0.5.10}/petpal/utils/useful_functions.py +0 -0
  135. {petpal-0.5.9 → petpal-0.5.10}/petpal/visualizations/__init__.py +0 -0
  136. {petpal-0.5.9 → petpal-0.5.10}/petpal/visualizations/graphical_plots.py +0 -0
  137. {petpal-0.5.9 → petpal-0.5.10}/petpal/visualizations/image_visualization.py +0 -0
  138. {petpal-0.5.9 → petpal-0.5.10}/petpal/visualizations/qc_plots.py +0 -0
  139. {petpal-0.5.9 → petpal-0.5.10}/petpal/visualizations/tac_plots.py +0 -0
  140. {petpal-0.5.9 → petpal-0.5.10}/shared/dseg.tsv +0 -0
  141. {petpal-0.5.9 → petpal-0.5.10}/shared/freesurfer_lmap.json +0 -0
  142. {petpal-0.5.9 → petpal-0.5.10}/shared/freesurfer_lmap_lr.json +0 -0
  143. {petpal-0.5.9 → petpal-0.5.10}/shared/perl_cyno_lmap.json +0 -0
  144. {petpal-0.5.9 → petpal-0.5.10}/shared/perl_cyno_lmap_lr.json +0 -0
  145. {petpal-0.5.9 → petpal-0.5.10}/test_notebooks/explicit_tac_fitting/01_fitting_TCMs.ipynb +0 -0
  146. {petpal-0.5.9 → petpal-0.5.10}/test_notebooks/testing_RTMs/01_testing_RTMs.ipynb +0 -0
  147. {petpal-0.5.9 → petpal-0.5.10}/test_notebooks/testing_graphical_analyses/01_testing_on_tcms_database.ipynb +0 -0
  148. {petpal-0.5.9 → petpal-0.5.10}/test_notebooks/testing_graphical_analyses/02_testing_parametric_images.ipynb +0 -0
  149. {petpal-0.5.9 → petpal-0.5.10}/test_notebooks/testing_graphical_analyses/03_plotting_graphical_anlayses_testbed.ipynb +0 -0
  150. {petpal-0.5.9 → petpal-0.5.10}/tests/test_graphical_analysis.py +0 -0
  151. {petpal-0.5.9 → petpal-0.5.10}/tests/test_importpetpal.py +0 -0
  152. {petpal-0.5.9 → petpal-0.5.10}/tests/test_register.py +0 -0
  153. {petpal-0.5.9 → petpal-0.5.10}/tests/test_scan_timing_decay.py +0 -0
  154. {petpal-0.5.9 → petpal-0.5.10}/tests/test_time_activity_curve.py +0 -0
  155. {petpal-0.5.9 → petpal-0.5.10}/tests/test_weighted_sum.py +0 -0
  156. {petpal-0.5.9 → petpal-0.5.10}/tests/test_write_tacs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: petpal
3
- Version: 0.5.9
3
+ Version: 0.5.10
4
4
  Summary: PET-PAL (Positron Emission Tomography Processing and Analysis Library)
5
5
  Project-URL: Repository, https://github.com/PETPAL-WUSM/PETPAL.git
6
6
  Author-email: Noah Goldman <noahg@wustl.edu>, Bradley Judge <bjudge@wustl.edu>, Furqan Dar <dar@wustl.edu>, Kenan Oestreich <kenan.oestreich@wustl.edu>
@@ -64,10 +64,9 @@ def stitch_broken_scans(input_image_path: str,
64
64
  try:
65
65
  noninitial_time_zeroes = [meta['TimeZero'] for meta in noninitial_image_metadata_dicts]
66
66
  actual_time_zero = initial_image_metadata['TimeZero']
67
- except KeyError:
68
- raise KeyError(f'.json sidecar for one of your input images does not contain required BIDS key "TimeZero". '
69
- f'Aborting...')
70
-
67
+ except KeyError as exc:
68
+ raise KeyError('.json sidecar for one of your input images does not contain required BIDS '
69
+ 'key "TimeZero".') from exc
71
70
  initial_scan_time = datetime.time.fromisoformat(actual_time_zero)
72
71
  placeholder_date = datetime.date.today()
73
72
  initial_scan_datetime = datetime.datetime.combine(date=placeholder_date,
@@ -9,6 +9,7 @@ import warnings
9
9
  import numpy as np
10
10
  from scipy.ndimage import gaussian_filter
11
11
  import ants
12
+ import pandas as pd
12
13
 
13
14
  from ..meta.label_maps import LabelMapLoader
14
15
  from ..utils.useful_functions import check_physical_space_for_ants_image_pair
@@ -92,24 +93,33 @@ class Sgtm:
92
93
  elif self.input_image.dimension == 4:
93
94
  self.sgtm_result = self.run_sgtm_4d()
94
95
 
95
- def save(self, output_path: str, out_tac_prefix: str | None = None):
96
+ def save(self, output_path: str, out_tac_prefix: str | None = None, one_tsv_per_region: bool = False):
96
97
  r"""Save sGTM results by writing the resulting array to one or more files.
97
98
 
98
- The behavior depends on the input iamge provided. If input image is 3D, saves the average sGTM value for each
99
+ The behavior depends on the input image provided. If input image is 3D, saves the average sGTM value for each
99
100
  region in a TSV with one row per region. If input image is 4D, saves time series average values for each frame
100
- within each region as a TAC file.
101
+ within each region. 4D operation saves a single file unless `one_tsv_per_region` is set to True.
101
102
 
102
103
  Args:
103
- output_path (str): Path to save sGTM results. For 3D images, this should typically be a full path to a
104
- .tsv file. For 4D images, this is the directory where the sGTM TACs will be saved.
104
+ output_path (str): Path to save sGTM results. For 3D images, this should typically be
105
+ the full path to a .tsv file. For 4D images, this is the directory where the sGTM
106
+ TACs will be saved.
105
107
  out_tac_prefix (Optional, str): Prefix of the TAC files. Typically, something like
106
108
  ``'sub-001_ses-001_desc-sGTM'``. Defaults to None.
109
+ one_tsv_per_region (bool): If True, saves one tsv file for each unique region, as
110
+ opposed to one file containing all TACs if False. Default False.
107
111
  """
108
112
  if self.input_image.dimension == 3:
109
113
  self.save_results_3d(sgtm_result=self.sgtm_result, out_tsv_path=output_path)
110
114
  elif self.input_image.dimension == 4:
111
- self.save_results_4d_tacs(sgtm_result=self.sgtm_result, out_tac_dir=output_path,
112
- out_tac_prefix=out_tac_prefix)
115
+ if one_tsv_per_region:
116
+ self.save_results_4d_tacs(sgtm_result=self.sgtm_result,
117
+ out_tac_dir=output_path,
118
+ out_tac_prefix=out_tac_prefix)
119
+ else:
120
+ self.save_results_4d_multitacs(sgtm_result=self.sgtm_result,
121
+ out_tac_dir=output_path,
122
+ out_tac_prefix=out_tac_prefix)
113
123
 
114
124
  def __call__(self, output_path: str, out_tac_prefix: str | None = None):
115
125
  r"""Run sGTM and save results.
@@ -162,8 +172,20 @@ class Sgtm:
162
172
  "segmentation to ensure this criteria is met, or use sGTM without "
163
173
  "label map for automated complete region mapping.")
164
174
  seg_label_map = LabelMapLoader(label_map_option=self.label_map_option).label_map
165
- region_index_map = list(seg_label_map.values())
166
- region_short_names = list(seg_label_map.keys())
175
+ unique_mappings = unique_segmentation_labels(segmentation_img=self.segmentation_image,
176
+ zeroth_roi=self.zeroth_roi)
177
+ region_index_map = []
178
+ region_short_names = []
179
+ label_map_labels = list(seg_label_map.keys())
180
+ label_map_mappings = list(seg_label_map.values())
181
+ for mapping in unique_mappings:
182
+ if mapping in label_map_mappings:
183
+ id_mapping_index = label_map_mappings.index(mapping)
184
+ region_index_map.append(label_map_mappings[id_mapping_index])
185
+ region_short_names.append(label_map_labels[id_mapping_index])
186
+ else:
187
+ region_index_map.append(mapping)
188
+ region_short_names.append(f'UNK{mapping:05d}')
167
189
  return (region_index_map, region_short_names)
168
190
 
169
191
 
@@ -291,7 +313,6 @@ class Sgtm:
291
313
 
292
314
  return unique_labels, t_corrected, condition_number
293
315
 
294
-
295
316
  def run_sgtm_4d(self) -> np.ndarray:
296
317
  r"""Calculated partial volume corrected TACs on a 4D image by running sGTM on each frame in
297
318
  the 4D image.
@@ -326,7 +347,6 @@ class Sgtm:
326
347
 
327
348
  return np.asarray(frame_results)
328
349
 
329
-
330
350
  def save_results_3d(self, sgtm_result: tuple, out_tsv_path: str):
331
351
  r"""Saves the result of an sGTM calculation.
332
352
 
@@ -337,12 +357,10 @@ class Sgtm:
337
357
  sgtm_result (tuple): Output of :meth:`run_sgtm_3d`
338
358
  out_tsv_path (str): File path to which results are saved.
339
359
  """
340
- sgtm_result_array = np.array([sgtm_result[0], sgtm_result[1]]).T
341
- np.savetxt(out_tsv_path,sgtm_result_array,
342
- header='Region\tMean',
343
- fmt=['%.0f','%.2f'],
344
- comments='')
345
-
360
+ sgtm_result_to_write = pd.DataFrame(columns=['Region','Mean'])
361
+ sgtm_result_to_write['Region'] = self.unique_labels[1]
362
+ sgtm_result_to_write['Mean'] = sgtm_result[1]
363
+ sgtm_result_to_write.to_csv(out_tsv_path,sep='\t',index=False)
346
364
 
347
365
  def save_results_4d_tacs(self,
348
366
  sgtm_result: np.ndarray,
@@ -368,3 +386,31 @@ class Sgtm:
368
386
  activity=tac_array[i,:])
369
387
  out_tac_path = os.path.join(f'{out_tac_dir}', f'{out_tac_prefix}_seg-{name}_tac.tsv')
370
388
  pvc_tac.to_tsv(filename=out_tac_path)
389
+
390
+ def save_results_4d_multitacs(self,
391
+ sgtm_result: np.ndarray,
392
+ out_tac_dir: str,
393
+ out_tac_prefix: str):
394
+ """Like :meth:`save_results_4d_tacs`, but saves all TACs to a single file.
395
+
396
+ Args:
397
+ sgtm_result (np.ndarray): Array of results from :meth:`run_sgtm_4d`
398
+ out_tac_dir (str): Path to folder where regional TACs will be saved.
399
+ out_tac_prefix (str): Prefix of the TAC files.
400
+ """
401
+ os.makedirs(out_tac_dir, exist_ok=True)
402
+ input_image_path = self.input_image_path
403
+ scan_timing = ScanTimingInfo.from_nifti(image_path=input_image_path)
404
+ tac_time_starts = scan_timing.start_in_mins
405
+ tac_time_ends = scan_timing.end_in_mins
406
+
407
+ tac_array = np.asarray(sgtm_result).T
408
+ tacs_data_columns = ['frame_start(min)','frame_end(min)']+self.unique_labels[1]
409
+ tacs_data = pd.DataFrame(columns=tacs_data_columns)
410
+
411
+ tacs_data['frame_start(min)'] = tac_time_starts
412
+ tacs_data['frame_end(min)'] = tac_time_ends
413
+ for i, (_label, name) in enumerate(zip(*self.unique_labels)):
414
+ tacs_data[name] = tac_array[i,:]
415
+ tacs_data[f'{name}_unc'] = np.full(tac_array.shape[1],np.nan)
416
+ tacs_data.to_csv(f'{out_tac_dir}/{out_tac_prefix}_multitacs.tsv', sep='\t', index=False)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "petpal"
7
- version = "0.5.9"
7
+ version = "0.5.10"
8
8
  description = "PET-PAL (Positron Emission Tomography Processing and Analysis Library)"
9
9
  authors = [
10
10
  {name = "Noah Goldman", email = "noahg@wustl.edu"},
@@ -0,0 +1,53 @@
1
+ import pytest
2
+ from petpal.preproc.symmetric_geometric_transfer_matrix import Sgtm
3
+
4
+ class DummyImage:
5
+ def __init__(self, dimension):
6
+ self.dimension = dimension
7
+
8
+ def make_sgtm_with_dimension(dim, sgtm_result=None):
9
+ sgtm = object.__new__(Sgtm)
10
+ sgtm.input_image = DummyImage(dimension=dim)
11
+ sgtm.sgtm_result = sgtm_result
12
+ return sgtm
13
+
14
+ def test_save_calls_save_results_3d_for_3d_image():
15
+ sgtm = make_sgtm_with_dimension(3, sgtm_result=("labels", "vals", 1.0))
16
+ called = {}
17
+ def fake_save_results_3d(sgtm_result, out_tsv_path):
18
+ called['args'] = (sgtm_result, out_tsv_path)
19
+ sgtm.save_results_3d = fake_save_results_3d
20
+
21
+ sgtm.save(output_path="out.tsv")
22
+
23
+ assert 'args' in called
24
+ assert called['args'][0] is sgtm.sgtm_result
25
+ assert called['args'][1] == "out.tsv"
26
+
27
+ def test_save_calls_save_results_4d_tacs_when_one_tsv_per_region_true():
28
+ sgtm = make_sgtm_with_dimension(4, sgtm_result="frame_results")
29
+ called = {}
30
+ def fake_save_results_4d_tacs(sgtm_result, out_tac_dir, out_tac_prefix):
31
+ called['args'] = (sgtm_result, out_tac_dir, out_tac_prefix)
32
+ sgtm.save_results_4d_tacs = fake_save_results_4d_tacs
33
+
34
+ sgtm.save(output_path="/tmp/dir", out_tac_prefix="pref", one_tsv_per_region=True)
35
+
36
+ assert 'args' in called
37
+ assert called['args'][0] is sgtm.sgtm_result
38
+ assert called['args'][1] == "/tmp/dir"
39
+ assert called['args'][2] == "pref"
40
+
41
+ def test_save_calls_save_results_4d_multitacs_when_one_tsv_per_region_false():
42
+ sgtm = make_sgtm_with_dimension(4, sgtm_result="frame_results")
43
+ called = {}
44
+ def fake_save_results_4d_multitacs(sgtm_result, out_tac_dir, out_tac_prefix):
45
+ called['args'] = (sgtm_result, out_tac_dir, out_tac_prefix)
46
+ sgtm.save_results_4d_multitacs = fake_save_results_4d_multitacs
47
+
48
+ sgtm.save(output_path="/tmp/dir2", out_tac_prefix="pref2", one_tsv_per_region=False)
49
+
50
+ assert 'args' in called
51
+ assert called['args'][0] is sgtm.sgtm_result
52
+ assert called['args'][1] == "/tmp/dir2"
53
+ assert called['args'][2] == "pref2"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes