ScanTimingInfo ======================================= .. py:class:: petpal.utils.scan_timing.ScanTimingInfo A data structure to represent and streamline access to timing information for image scans. This class encapsulates details about a scan's timing, including: - Start and end times of each scan frame. - Duration and center times of the frames. - Decay values (if applicable). Additionally, the class provides properties for easy conversion of timing values to minutes if the times are given in seconds and exceed a threshold (assumed to be 200.0 seconds). :ivar duration: Array of frame durations. :vartype duration: np.ndarray[float] :ivar end: Array of frame end times. :vartype end: np.ndarray[float] :ivar start: Array of frame start times. :vartype start: np.ndarray[float] :ivar center: Array of frame center times (midpoints). :vartype center: np.ndarray[float] :ivar decay: Array of decay coefficients for the scan frames. :vartype decay: np.ndarray[float] Properties: duration_in_mins (np.ndarray[float]): Returns the frame durations converted to minutes if `end` is >= 200.0 seconds. Otherwise, returns the original durations. end_in_mins (np.ndarray[float]): Returns the frame end times converted to minutes if `end` is >= 200.0 seconds. Otherwise, returns the original end times. start_in_mins (np.ndarray[float]): Returns the frame start times converted to minutes if `end` is >= 200.0 seconds. Otherwise, returns the original start times. center_in_mins (np.ndarray[float]): Returns the frame center times converted to minutes if `end` is >= 200.0 seconds. Otherwise, returns the original center times. .. rubric:: Examples .. code-block:: python import numpy as np from petpal.utils.scan_timing import ScanTimingInfo # Explicitly setting the attributes ## Define scan timing information duration = np.array([60.0, 120.0, 180.0]) # seconds start = np.array([0.0, 60.0, 180.0]) end = np.array([60.0, 180.0, 360.0]) center = (start + end) / 2.0 # Calculate the midpoints decay = np.array([1.0, 0.9, 0.8]) # Example decay values ## Create an instance of ScanTimingInfo scan_timing_info = ScanTimingInfo(duration=duration, end=end, start=start, center=center, decay=decay) ## Access original timing information print(scan_timing_info.duration) # [ 60. 120. 180.] print(scan_timing_info.center) # [30. 120. 270.] ## Access timing as minutes (when times exceed 200.0 seconds) print(scan_timing_info.duration_in_mins) # [ 60. 120. 180.] (Unchanged) print(scan_timing_info.center_in_mins) # [30. 120. 270.] (Unchanged) ## Example when `end` is greater than 200.0: scan_timing_info.end = np.array([300.0, 400.0, 500.0]) # Update end times print(scan_timing_info.end_in_mins) # [5. 6.66666667 8.33333333] (Converted to minutes) print(scan_timing_info.start_in_mins) # [0. 1. 3.] (Converted to minutes) # Getting the object directly from a nifti image file # assuming the metadata shares the name scan_timing_info = ScanTimingInfo.from_nifti("/path/to/image.nii.gz") .. py:property:: duration_in_mins :type: numpy.ndarray[float] Returns the frame durations in minutes. Validates values by checking if the final frame value is greater than 200: if so, then assumes values are in seconds and divides by 60. .. py:property:: end_in_mins :type: numpy.ndarray[float] Returns the frame time ends in minutes. Validates values by checking if the final frame value is greater than 200: if so, then assumes values are in seconds and divides by 60. .. py:property:: start_in_mins :type: numpy.ndarray[float] Returns the frame time starts in minutes. Validates values by checking if the final frame value is greater than 200: if so, then assumes values are in seconds and divides by 60. .. py:property:: center_in_mins :type: numpy.ndarray[float] Returns the frame reference times in minutes. Validates values by checking if the final frame value is greater than 200: if so, then assumes values are in seconds and divides by 60. .. py:method:: from_metadata(metadata_dict: dict) -> Self :classmethod: Extracts frame timing information and decay factors from a json metadata. Expects that the JSON metadata has ``FrameDuration`` and ``DecayFactor`` or ``DecayCorrectionFactor`` keys. .. important:: This function tries to infer `FrameTimesEnd` and `FrameTimesStart` from the frame durations if those keys are not present in the metadata file. If the scan is broken, this might generate incorrect results. :param metadata_dict: The metadata dictionary, loaded into memory. :type metadata_dict: dict :returns: :class:`ScanTimingInfo` -- Frame timing information with the following elements: - duration (np.ndarray): Frame durations in seconds. - start (np.ndarray): Frame start times in seconds. - end (np.ndarray): Frame end times in seconds. - center (np.ndarray): Frame center times in seconds. - decay (np.ndarray): Decay factors for each frame. .. py:method:: from_nifti(image_path: str) -> Self :classmethod: Extracts frame timing information and decay factors from a NIfTI image metadata. Expects that the JSON metadata file has ``FrameDuration`` and ``DecayFactor`` or ``DecayCorrectionFactor`` keys. .. important:: This function tries to infer `FrameTimesEnd` and `FrameTimesStart` from the frame durations if those keys are not present in the metadata file. If the scan is broken, this might generate incorrect results. :param image_path: Path to the NIfTI image file. :type image_path: str :returns: :class:`ScanTimingInfo` -- Frame timing information with the following elements: - duration (np.ndarray): Frame durations in seconds. - start (np.ndarray): Frame start times in seconds. - end (np.ndarray): Frame end times in seconds. - center (np.ndarray): Frame center times in seconds. - decay (np.ndarray): Decay factors for each frame. .. py:method:: from_start_end(frame_starts: numpy.ndarray, frame_ends: numpy.ndarray, decay_correction_factor: numpy.ndarray | None = None) -> Self :classmethod: Infer timing properties based on start and end time. :param frame_starts: Start time of each frame. :type frame_starts: np.ndarray :param frame_ends: End time of each frame. :type frame_ends: np.ndarray :param decay_correction_factor: Decay correction factor, which can be optionally provided based on the type of analysis being done. If None, frame decay will be set to ones. Default None. :type decay_correction_factor: np.ndarray | None :returns: *scan_timing_info (ScanTimingInfo)* -- ScanTimingInfo object with the correct start, end, duration, midpoint, and (optionally) decay correction for each frame. :raises ValueError: If frame_starts, frame_ends, and decay_correction_factor (if provided) are not of identical shape.