petpal 0.5.8__py3-none-any.whl → 0.5.10__py3-none-any.whl

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.
@@ -59,7 +59,6 @@ def main():
59
59
  parser_multitac = subparsers.add_parser('graphical-analysis-multitac')
60
60
  _add_common_args(parser_multitac)
61
61
  parser_multitac.add_argument("-r", "--roi-tacs-dir", required=True, help="Path to directory containing ROI TTACs")
62
- parser_multitac.add_argument("-x","--excel", action='store_true',help='Set to output an excel-compatible table in a single file.',default=False)
63
62
 
64
63
  args = parser.parse_args()
65
64
  command = str(args.command).replace('-','_')
@@ -90,7 +89,7 @@ def main():
90
89
  output_filename_prefix=args.output_filename_prefix,
91
90
  method=method,
92
91
  fit_thresh_in_mins=args.threshold_in_mins)
93
- graphical_analysis(one_file_per_region=not args.excel, **run_kwargs)
92
+ graphical_analysis(output_as_tsv=True, output_as_json=False, **run_kwargs)
94
93
 
95
94
  if args.print:
96
95
  for key, val in graphical_analysis.analysis_props.items():
@@ -1103,13 +1103,13 @@ class MultiTACGraphicalAnalysis(GraphicalAnalysis, MultiTACAnalysisMixin):
1103
1103
  if self.analysis_props[0]['RSquared'] is None:
1104
1104
  raise RuntimeError("'run_analysis' method must be called before 'save_analysis'.")
1105
1105
 
1106
- if output_as_tsv:
1106
+ if output_as_json:
1107
1107
  km_multifit_analysis_to_jsons(analysis_props=self.analysis_props,
1108
1108
  output_directory=self.output_directory,
1109
1109
  output_filename_prefix=self.output_filename_prefix,
1110
1110
  method=self.method,
1111
1111
  inferred_seg_labels=self.inferred_seg_labels)
1112
- if output_as_json:
1112
+ if output_as_tsv:
1113
1113
  km_multifit_analysis_to_tsv(analysis_props=self.analysis_props,
1114
1114
  output_directory=self.output_directory,
1115
1115
  output_filename_prefix=self.output_filename_prefix,
@@ -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,
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Regional TAC extraction
3
3
  """
4
+ from warnings import warn
4
5
  import os
5
6
  from collections.abc import Callable
6
7
  import pathlib
@@ -345,6 +346,20 @@ class WriteRegionalTacs:
345
346
  region_name = f'UNK{label:>04}'
346
347
  return region_name
347
348
 
349
+ def is_empty_region(self,pet_masked_region: np.ndarray) -> bool:
350
+ """Check if masked PET region has zero matched voxels, or is all NaNs. In either case,
351
+ return True, otherwise return False.
352
+
353
+ Args:
354
+ pet_masked_region (np.ndarray): Array of PET voxels masked to a specific region.
355
+
356
+ Returns:
357
+ pet_masked_region_is_empty (bool): If True, input region is empty."""
358
+ if pet_masked_region.size==0:
359
+ return True
360
+ if np.all(np.isnan(pet_masked_region)):
361
+ return True
362
+ return False
348
363
 
349
364
  def extract_tac(self,region_mapping: int | list[int], **tac_calc_kwargs) -> TimeActivityCurve:
350
365
  """
@@ -359,15 +374,46 @@ class WriteRegionalTacs:
359
374
  """
360
375
  region_mask = combine_regions_as_mask(segmentation_img=self.seg_arr,
361
376
  label=region_mapping)
377
+
362
378
  pet_masked_region = apply_mask_4d(input_arr=self.pet_arr,
363
379
  mask_arr=region_mask)
364
- extracted_tac, uncertainty = self.tac_extraction_func(pet_voxels=pet_masked_region,
365
- **tac_calc_kwargs)
380
+
381
+ is_region_empty = self.is_empty_region(pet_masked_region=pet_masked_region)
382
+ if is_region_empty:
383
+ extracted_tac = np.empty_like(self.scan_timing.center_in_mins)
384
+ extracted_tac.fill(np.nan)
385
+ uncertainty = extracted_tac.copy()
386
+ else:
387
+ extracted_tac, uncertainty = self.tac_extraction_func(pet_voxels=pet_masked_region,
388
+ **tac_calc_kwargs)
366
389
  region_tac = TimeActivityCurve(times=self.scan_timing.center_in_mins,
367
390
  activity=extracted_tac,
368
391
  uncertainty=uncertainty)
369
392
  return region_tac
370
393
 
394
+ def gen_tacs_data_frame(self) -> pd.DataFrame:
395
+ """Get empty data frame to store TACs. Sets first two columns to frame start and end
396
+ times, and remaining columns are named by region activity and uncertainty, based on the
397
+ regions included in the label map.
398
+
399
+ Returns:
400
+ tacs_data (pd.DataFrame): Data frame with columns set for frame start and end time,
401
+ and activity and uncertainty for each included region. Frame start and end time
402
+ columns filled with scan timing data.
403
+ """
404
+ activity_uncertainty_column_names = []
405
+ for region_name in self.region_names:
406
+ activity_uncertainty_column_names.append(region_name)
407
+ activity_uncertainty_column_names.append(f'{region_name}_unc')
408
+ cols_list = ['frame_start(min)','frame_end(min)'] + activity_uncertainty_column_names
409
+ tacs_data = pd.DataFrame(columns=cols_list)
410
+
411
+ tacs_data['frame_start(min)'] = self.scan_timing.start_in_mins
412
+ tacs_data['frame_end(min)'] = self.scan_timing.end_in_mins
413
+
414
+ return tacs_data
415
+
416
+
371
417
 
372
418
  def write_tacs(self,
373
419
  out_tac_prefix: str,
@@ -378,7 +424,8 @@ class WriteRegionalTacs:
378
424
  Function to write Tissue Activity Curves for each region, given a segmentation,
379
425
  4D PET image, and label map. Computes the average of the PET image within each
380
426
  region. Writes TACs in TSV format with region name, frame start time, frame end time, and
381
- activity and uncertainty within each region.
427
+ activity and uncertainty within each region. Skips writing regions without any matched
428
+ voxels.
382
429
 
383
430
  Args:
384
431
  out_tac_prefix (str): Prefix for the output files, usually the BIDS subject and
@@ -387,22 +434,34 @@ class WriteRegionalTacs:
387
434
  one_tsv_per_region (bool): If True, write one TSV TAC file for each region in the
388
435
  image. If False, write one TSV file with all TACs in the image.
389
436
  **tac_calc_kwargs: Additional keywords passed onto tac_extraction_func.
390
- """
391
- tacs_data = pd.DataFrame()
392
437
 
393
- tacs_data['frame_start(min)'] = self.scan_timing.start_in_mins
394
- tacs_data['frame_end(min)'] = self.scan_timing.end_in_mins
438
+ Raises:
439
+ Warning: for each region without any matched voxels, warn user that TAC is skipped.
440
+ """
441
+ tacs_data = self.gen_tacs_data_frame()
395
442
 
443
+ empty_regions = []
396
444
  for i,region_name in enumerate(self.region_names):
397
445
  mappings = self.region_maps[i]
398
446
  tac = self.extract_tac(region_mapping=mappings, **tac_calc_kwargs)
447
+ if tac.contains_any_nan:
448
+ empty_regions.append(region_name)
449
+ continue
399
450
  if one_tsv_per_region:
451
+ os.makedirs(out_tac_dir, exist_ok=True)
400
452
  tac.to_tsv(filename=f'{out_tac_dir}/{out_tac_prefix}_seg-{region_name}_tac.tsv')
401
453
  else:
402
454
  tacs_data[region_name] = tac.activity
403
455
  tacs_data[f'{region_name}_unc'] = tac.uncertainty
404
456
 
457
+ if len(empty_regions)>0:
458
+ warn("Empty regions were found during tac extraction. TACs for the following regions "
459
+ f"were not saved: {empty_regions}")
460
+ tacs_data.drop(empty_regions,axis=1,inplace=True)
461
+ tacs_data.drop([f'{region}_unc' for region in empty_regions],axis=1,inplace=True)
462
+
405
463
  if not one_tsv_per_region:
464
+ os.makedirs(out_tac_dir, exist_ok=True)
406
465
  tacs_data.to_csv(f'{out_tac_dir}/{out_tac_prefix}_multitacs.tsv', sep='\t', index=False)
407
466
 
408
467
  def __call__(self,
@@ -14,7 +14,9 @@ import nibabel
14
14
  from nibabel import processing
15
15
  import pandas as pd
16
16
 
17
- from ..utils.useful_functions import gen_nd_image_based_on_image_list
17
+ from ..utils.useful_functions import (gen_nd_image_based_on_image_list,
18
+ check_physical_space_for_ants_image_pair,
19
+ get_average_of_timeseries)
18
20
  from ..utils import math_lib
19
21
 
20
22
 
@@ -571,3 +573,28 @@ def unique_segmentation_labels(segmentation_img: ants.core.ANTsImage | np.ndarra
571
573
  if not zeroth_roi:
572
574
  labels = labels[labels != 0]
573
575
  return labels
576
+
577
+ def seg_crop_to_pet_fov(pet_img: ants.ANTsImage,
578
+ segmentation_img: ants.ANTsImage,
579
+ pet_thresh_value: float=np.finfo(float).eps) -> ants.ANTsImage:
580
+ """Zero out segmentation values that lie outside of the PET FOV.
581
+
582
+ Especially applicable to scanners with limited FOV (field of view). PET voxels with values less
583
+ than 1e-36 are considered outside of the FOV.
584
+
585
+ Args:
586
+ pet_img (ants.ANTsImage): PET image in anatomical space used to crop segmentation
587
+ segmentation_img (ants.ANTsImage): Segmentation image in anatomical space such as
588
+ FreeSurfer to which FOV cropping is applied.
589
+ pet_thresh_value (float): Lower threshold for the PET image by which the segmentation image
590
+ is masked. Should be <<1. Default machine epsilon for `float`.
591
+
592
+ Returns:
593
+ segmentation_masked_img (ants.ANTsImage): Segmentation image masked to PET FOV.
594
+ """
595
+ if not check_physical_space_for_ants_image_pair(pet_img, segmentation_img):
596
+ raise ValueError("PET and segmentation image must share physical space.")
597
+ pet_mean_img = get_average_of_timeseries(input_image=pet_img)
598
+ pet_mask = ants.threshold_image(pet_mean_img, pet_thresh_value)
599
+ seg_masked = ants.mask_image(segmentation_img, pet_mask)
600
+ return seg_masked
@@ -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)
@@ -75,6 +75,7 @@ class TimeActivityCurve:
75
75
  return len(self.times)
76
76
 
77
77
  def __post_init__(self):
78
+ self.validate_activity()
78
79
  if self.uncertainty.size == 0:
79
80
  self.uncertainty = np.empty_like(self.times)
80
81
  self.uncertainty[:] = np.nan
@@ -82,6 +83,33 @@ class TimeActivityCurve:
82
83
  f"TAC fields must have the same shapes.\ntimes:{self.times.shape}"
83
84
  "activity:{self.activity.shape} uncertainty:{self.uncertainty.shape}")
84
85
 
86
+ def validate_activity(self):
87
+ """Validates that the activity attribute is defined correctly.
88
+
89
+ `self.activity` must have the following properties:
90
+ 1) It must exist and not be None
91
+ 2) It must be a numpy array
92
+ 3) It must have dtype float
93
+ 4) It must be 1D
94
+
95
+ This function raises a ValueError if self.activity does not meet the first criteria, and
96
+ attempts to coerce self.activity into a 1D, numeric numpy array with dtype float if
97
+ criteria 2-4 are not met.
98
+ """
99
+ if not hasattr(self, "activity") or self.activity is None:
100
+ raise ValueError("TimeActivityCurve.activity must be provided and not be None")
101
+
102
+ try:
103
+ arr = np.asarray(self.activity, dtype=float)
104
+ except (TypeError, ValueError) as exc:
105
+ error_message = "TimeActivityCurve.activity must be numeric or convertible to numeric"
106
+ raise TypeError(error_message) from exc
107
+
108
+ if arr.ndim != 1:
109
+ arr = arr.ravel()
110
+
111
+ self.activity = arr
112
+
85
113
  @classmethod
86
114
  def from_tsv(cls, filename: str):
87
115
  """
@@ -509,29 +537,29 @@ class TimeActivityCurve:
509
537
  kind='linear',
510
538
  fill_value='extrapolate')(tac.times)
511
539
  return TimeActivityCurve(tac.times, shifted_vals_on_tac_times)
512
- else:
513
- return shifted_tac
540
+ return shifted_tac
514
541
 
515
542
  @staticmethod
516
543
  def tac_dispersion(tac: 'TimeActivityCurve',
517
- disp_func: Callable[[np.ndarray, ...], np.ndarray],
544
+ disp_func: Callable[..., np.ndarray],
518
545
  disp_kwargs: dict,
519
546
  num_samples: int = 4096):
520
547
  r"""
521
548
  Applies a dispersion function to a time-activity curve (TAC) and returns the convolved TAC.
522
549
 
523
- This method evaluates the specified dispersion function `disp_func` at supersampled time points.
524
- It performs convolution (using :func:`scipy.signal.convolve`)of the supersampled TAC with
525
- the dispersion function, and the result is sampled back at the original TAC time points
526
- to form the new convolved TAC.
550
+ This method evaluates the specified dispersion function `disp_func` at supersampled time
551
+ points. It performs convolution (using :func:`scipy.signal.convolve`) of the supersampled
552
+ TAC with the dispersion function, and the result is sampled back at the original TAC time
553
+ points to form the new convolved TAC.
527
554
 
528
555
  .. note::
529
- We perform the supersampling to ensure that the TACs are sampled evenly before performing
530
- the convolution. Convolving non-evenly sampled arrays produces nonsense values.
556
+ We perform the supersampling to ensure that the TACs are sampled evenly before
557
+ performing the convolution. Convolving non-evenly sampled arrays produces nonsense
558
+ values.
531
559
 
532
560
  Args:
533
561
  tac (TimeActivityCurve): The original time-activity curve to be convolved.
534
- disp_func (Callable[[np.ndarray, ...], np.ndarray]):
562
+ disp_func (Callable[..., np.ndarray]):
535
563
  The dispersion function to be applied. This function must accept an array of
536
564
  times as its first argument, followed by any additional arguments specified
537
565
  in `disp_kwargs`.
@@ -541,8 +569,8 @@ class TimeActivityCurve:
541
569
  Defaults to 4096.
542
570
 
543
571
  Returns:
544
- TimeActivityCurve: A new `TimeActivityCurve` instance with the convolved activity values,
545
- resampled at the original TAC time points.
572
+ TimeActivityCurve: A new `TimeActivityCurve` instance with the convolved activity
573
+ values, resampled at the original TAC time points.
546
574
 
547
575
  Example:
548
576
  .. code-block:: python
@@ -592,6 +620,12 @@ class TimeActivityCurve:
592
620
 
593
621
  return disp_tac.set_activity_non_negative()
594
622
 
623
+ @property
624
+ def contains_any_nan(self):
625
+ """Return True if TAC has any NaN activity values."""
626
+ any_nan = np.isnan(self.activity).any()
627
+ return any_nan
628
+
595
629
  def safe_load_tac(filename: str,
596
630
  with_uncertainty: bool = False,
597
631
  **kwargs) -> np.ndarray:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: petpal
3
- Version: 0.5.8
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>
@@ -1,6 +1,6 @@
1
1
  petpal/__init__.py,sha256=rYYNkBkSkHGE18JIZPeVK8YBP7Z9c4mpQfKN0cdS75k,318
2
2
  petpal/cli/__init__.py,sha256=RiQTAOhSeqw5BTVvdancX3JQj4CG8F9Qe4qWZR9nKio,434
3
- petpal/cli/cli_graphical_analysis.py,sha256=nGb0afMAigJgvbyEj5EXOCt6WNU35LNo3h3KLC8_f84,5529
3
+ petpal/cli/cli_graphical_analysis.py,sha256=L-YhkKkjmf6WLaAt8GDt1VmXaJXOsjMrbVvPhiTViYM,5386
4
4
  petpal/cli/cli_graphical_plots.py,sha256=_2tlGtZ0hIVyEYtGviEzGZMNhFymUPg4ZvSVyMtT_dA,3211
5
5
  petpal/cli/cli_idif.py,sha256=6lh_kJHcGjlHDXZOvbiuHrNqpk5FovVV5_j7_dPHTHU,5145
6
6
  petpal/cli/cli_parametric_images.py,sha256=JBFb8QlxZoGOzqvCJPFuZ7czzGWntJP5ZcfeM5-QF4Y,7385
@@ -19,7 +19,7 @@ petpal/input_function/idif_necktangle.py,sha256=o5kyAqyT4C6o7zELY4EjyHrkJyX1BWcx
19
19
  petpal/input_function/pca_guided_idif.py,sha256=MPB59K5Z5oyIunIWFqFQts61z647xawLNkv8wICrKYM,44821
20
20
  petpal/kinetic_modeling/__init__.py,sha256=tW4yRH3TwaXPwKPqdkrbQmSk9hjrF1yRkV_C59PPboQ,382
21
21
  petpal/kinetic_modeling/fit_tac_with_rtms.py,sha256=HpK7VWVCCNoSQABY9i28vYpZsMRmvgs4vdcM_ZbdaYE,20971
22
- petpal/kinetic_modeling/graphical_analysis.py,sha256=a7IOwYnG3Wao2XTjFgsPK563txm7s4lpMbaqUMQ5wUQ,51003
22
+ petpal/kinetic_modeling/graphical_analysis.py,sha256=e3ZXP8jA3ZgvC2T718-gukeBPlxCmOedCb2KlcGTUp8,51003
23
23
  petpal/kinetic_modeling/parametric_images.py,sha256=sXYracBFUtFyttO-6oiDAldnU8hPN6Y4vKOD1V-DnlE,47301
24
24
  petpal/kinetic_modeling/reference_tissue_models.py,sha256=FkLziIgtpA8tOL2gZJFg_nB8VPEBs40T7RsDAJ3nJ-A,39510
25
25
  petpal/kinetic_modeling/rtm_analysis.py,sha256=e3EuaHXml4PDALEczwyOPpnThINAGh41UKNlOQHAPqc,25945
@@ -38,15 +38,15 @@ petpal/pipelines/steps_base.py,sha256=W7GVN5-tsXe_7fvhoMRIlOk5ggY8V2wpSSmDONphLn
38
38
  petpal/pipelines/steps_containers.py,sha256=TV4LkPK48OnAds10vLcsPI3qtWjHsmwr6XGu3hup59Q,33767
39
39
  petpal/preproc/__init__.py,sha256=HmTVnCiKMxetDT_w-qU_62UOC39_A83LHXhZm07Q81I,504
40
40
  petpal/preproc/decay_correction.py,sha256=jT8X2lmMrdGf9-lo1ooKul_yomPqm1p24gB9On_GHl0,6872
41
- petpal/preproc/image_operations_4d.py,sha256=IqzwxaWxoWC1gmK00uuHIwlhx8e_eQ44C6yVFuu73W4,31371
41
+ petpal/preproc/image_operations_4d.py,sha256=UEaMw9YwnX-TOvmKxsA2qsU5GRR1Tq46l7gQz7TVzdk,31372
42
42
  petpal/preproc/motion_corr.py,sha256=dz10qjXBVTF_RH5RPZ68drUVX2qyj-MnZ674_Ccwz2Y,28670
43
43
  petpal/preproc/motion_target.py,sha256=_OJp3NoYcyD3Ke3wl2KbfOhbJ6dp6ZduR9LLz0rIaC0,3945
44
44
  petpal/preproc/partial_volume_corrections.py,sha256=J06j_Y_lhj3b3b9M5FbB2r2EPWQvoymG3GRUffSlYdE,6799
45
- petpal/preproc/regional_tac_extraction.py,sha256=qQDD9Z9p21DVUKokh_en2chOGP7F01wnDN156_74X8Q,19704
45
+ petpal/preproc/regional_tac_extraction.py,sha256=ZXo2u-EAUg5wZj7GGYLMEaOAfLv8OCOR-Gd0xvih6Y4,22358
46
46
  petpal/preproc/register.py,sha256=NKg8mt_XMGa5HBdxYZh3sMu_KMJ0W41VHlX4Zl8wlyE,14171
47
- petpal/preproc/segmentation_tools.py,sha256=BUy8ij45mmetenvWzODVwNIThDkYiEtY6gTAqI8sIak,25703
47
+ petpal/preproc/segmentation_tools.py,sha256=Xi1ZnBs3sp23MHWPPOLjuXi6qp4-igwIPXFJ4B_Yzsk,27186
48
48
  petpal/preproc/standard_uptake_value.py,sha256=YJIt0fl3fwMLl0tRYHpPPprMTaN4Q5JjQ5dx_CQX1nI,7494
49
- petpal/preproc/symmetric_geometric_transfer_matrix.py,sha256=ELkr7Mo233to1Rwml5YJ-aBvmTSk3LHNSdRhnX0WBDw,17575
49
+ petpal/preproc/symmetric_geometric_transfer_matrix.py,sha256=Sr5qMTiNC76ZRKiGG5So7fceV_Lr0ql7UybO_kJgmNo,20360
50
50
  petpal/utils/__init__.py,sha256=PlxBIKUtNvtSFnNZqz8myszOysaYzS8nSILMK4haVGg,412
51
51
  petpal/utils/bids_utils.py,sha256=3eZAzwGpOBUQ5ShVBUJJpmUBUhr3VcOikR-KpGCsdE0,7664
52
52
  petpal/utils/constants.py,sha256=Bz0HooHVx_8blXrBagS7g6rcMm8PnCzbO0YY4qR0oSo,738
@@ -58,15 +58,15 @@ petpal/utils/metadata.py,sha256=O9exRDlqAmPAEcO9v7dsqzkYcSVLgRA207owEvNXXJ8,6129
58
58
  petpal/utils/scan_timing.py,sha256=CYtYuFquAnOQ2QfjXdeLjWrBDPM_k4vBI9oHQdpmVZ0,13908
59
59
  petpal/utils/stats.py,sha256=paFdwVPIjlAi0wh5xU4x5WeydjKsEHuwzMLcDG_WzPc,6449
60
60
  petpal/utils/testing_utils.py,sha256=eMt1kklxK3rl8tm74I3yVNDotKh1CnYWLINDT7rzboM,9557
61
- petpal/utils/time_activity_curve.py,sha256=gX3PDYbeWblycvtvyiuFtnv1mBml_-93sIXKh2EmglM,39137
61
+ petpal/utils/time_activity_curve.py,sha256=ZjirIVy6rxG1cEZhYzFhbi9FEixlgdBpVqcZXXz6c3U,40379
62
62
  petpal/utils/useful_functions.py,sha256=md2kTLbs45MhrjdMhvDYcbflPTRNPspRSIHiOeIxEqY,21361
63
63
  petpal/visualizations/__init__.py,sha256=bd0NHDVl6Z2BDhisEcob2iIcqfxUfgKJ4DEmlrXJRP4,205
64
64
  petpal/visualizations/graphical_plots.py,sha256=ZCKUeLX2TAQscuHjA4bzlFm1bACHIyCwDuNnjCakVWU,47297
65
65
  petpal/visualizations/image_visualization.py,sha256=Ob6TD4Q0pIrxi0m9SznK1TRWbX1Ea9Pt4wNMdRrTfTs,9124
66
66
  petpal/visualizations/qc_plots.py,sha256=iaCPe-LWWyM3OZzDPZodHZhP-z5fRdpUgaH7QS9VxPM,1243
67
67
  petpal/visualizations/tac_plots.py,sha256=zSGdptL-EnqhfDViAX8LFunln5a1b-NJ5ft7ZDcxQ38,15116
68
- petpal-0.5.8.dist-info/METADATA,sha256=p2q6Rl726zTvyMW39Uw3j4jw0dXYKFhIDvkGG9nXqKk,2617
69
- petpal-0.5.8.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
70
- petpal-0.5.8.dist-info/entry_points.txt,sha256=0SZmyXqBxKzQg2eerDA16n2BdUEXyixEm0_AUo2dFns,653
71
- petpal-0.5.8.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
72
- petpal-0.5.8.dist-info/RECORD,,
68
+ petpal-0.5.10.dist-info/METADATA,sha256=QadOtBFu8TbKNi-WDticmziZXkREKywO0pP4F-AxAcI,2618
69
+ petpal-0.5.10.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
70
+ petpal-0.5.10.dist-info/entry_points.txt,sha256=0SZmyXqBxKzQg2eerDA16n2BdUEXyixEm0_AUo2dFns,653
71
+ petpal-0.5.10.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
72
+ petpal-0.5.10.dist-info/RECORD,,