TimeActivityCurve#
- class petpal.utils.time_activity_curve.TimeActivityCurve#
Class to store time activity curve (TAC) data.
- Variables:
times (np.ndarray) – Frame times for the TAC stored in an array.
activity (np.ndarray) – Activity values at each frame time stored in an array.
uncertainty (np.ndarray) – Uncertainty in the measurement of activity values stored in an array.
Example
from petpal.utils.time_activity_curve import TimeActivityCurve my_tac = TimeActivityCurve.from_tsv('/path/to/tac.tsv') print(f"Frame times: {my_tac.times}") print(f"Activity: {my_tac.activity}") print(f"Uncertainty: {my_tac.uncertainty}") my_tac.times = my_tac.times / 60 # convert time units to hours my_tac.to_tsv(filename='/path/to/new_tac.tsv') # save as new file
- __len__() int#
Returns the number of time points in the time-activity curve (TAC).
This method provides the length of the times attribute, representing the number of discrete time points associated with the TAC.
- Returns:
int – The number of time points in the TAC.
Example
from petpal.utils.time_activity_curve import TimeActivityCurve # Create a TimeActivityCurve object my_tac = TimeActivityCurve( times=np.array([0, 10, 20, 30]), activity=np.array([1.2, 2.3, 3.4, 4.5]) ) # Get the number of time points print(len(my_tac)) # Output: 4
- __post_init__()#
- validate_activity()#
Validates that the activity attribute is defined correctly.
self.activity must have the following properties: 1) It must exist and not be None 2) It must be a numpy array 3) It must have dtype float 4) It must be 1D
This function raises a ValueError if self.activity does not meet the first criteria, and attempts to coerce self.activity into a 1D, numeric numpy array with dtype float if criteria 2-4 are not met.
- classmethod from_tsv(filename: str)#
Load an instance of TimeActivityCurve object from a TSV TAC file.
Reads a TSV file using
safe_load_tac()and instantiates a TimeActivityCurve.- Parameters:
filename (str) – Path to the TSV TAC file.
- Returns:
(TimeActivityCurve) – A TimeActivityCurve object loaded from a TSV TAC file.
- property tac: numpy.ndarray#
Get the TAC array, not including uncertainties.
- Returns:
(np.ndarray) –
- The TAC as a contiguous array, with the first index being time and the
second index being activity.
- property tac_werr: numpy.ndarray#
Get the TAC array, including uncertainties.
- Returns:
(np.ndarray) –
- The TAC as a contiguous array, with the first index being time and the
second index being activity, and the third index being uncertainty.
- property times_in_mins: numpy.ndarray[float]#
Returns the TAC measured 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.
- to_tsv(filename: str, col_names: list[str] = None)#
Writes the TAC object to file, including measurement times, activity, and uncertainty.
- Parameters:
filename (str) – Path to the file that will be written to.
col_names (list[str]) – Custom names for time, activity, and uncertainty columns respectively. See
safe_write_tac(). Default None.
- set_activity_non_negative() TimeActivityCurve#
Ensures that the time-activity curve (TAC) data is physically consistent.
This method modifies the TAC object in place by setting uncertainty to NaN and activity to 0 for time points where the activity values are negative. Such adjustments help maintain data consistency for downstream analysis.
- Returns:
TimeActivityCurve – The updated TAC object with sanitized data.
Note
The method returns self to allow for .-chaining.
Example
from petpal.utils.time_activity_curve import TimeActivityCurve # Create a TimeActivityCurve object with negative activity my_tac = TimeActivityCurve( times=np.array([0, 10, 20, 30]), activity=np.array([1.2, -2.3, 3.4, -4.5]), uncertainty=np.array([0.1, 0.2, 0.3, 0.4]) ) # Sanitize the TAC my_tac.set_activity_non_negative() print(my_tac.activity) # Output: [1.2, 0.0, 3.4, 0.0] print(my_tac.uncertainty) # Output: [0.1, NaN, 0.3, NaN]
- evenly_resampled_tac(num_samples: int = 8192) TimeActivityCurve#
Generates a time-activity curve (TAC) resampled at evenly spaced time points.
This method uses linear interpolation to recreate the TAC with a specified number of evenly spaced samples between the initial and final time points. The resulting TAC is sanitized to ensure physical consistency. Uses
scipy.interpolate.interp1dfor the interpolation withkind=='linear'andfill_value='extrapolate'.Important
If the TAC will be used for convolution later, prefer powers of two for the number of samples.
- Parameters:
num_samples (int, optional) – The number of time points in the resampled TAC. Must be greater than 2. Defaults to 4096.
- Returns:
TimeActivityCurve – A new TimeActivityCurve instance with evenly spaced time points and resampled activity values.
- Raises:
AssertionError – If num_samples is less than or equal to 2.
Example
from petpal.utils.time_activity_curve import TimeActivityCurve # Create a TimeActivityCurve object my_tac = TimeActivityCurve( times=np.array([0, 10, 20, 30]), activity=np.array([1.0, 2.0, 3.0, 4.0]) ) # Resample the TAC with evenly spaced time points resampled_tac = my_tac.evenly_resampled_tac(num_samples=10) print(resampled_tac.times) # Output: Array of 10 evenly spaced times print(resampled_tac.activity) # Output: Interpolated activity values
- evenly_resampled_tac_given_dt(dt: float = 0.1 / 60.0) TimeActivityCurve#
Generates a time-activity curve (TAC) resampled at evenly spaced time intervals.
This method calculates the number of samples required to achieve the specified time interval (dt) and then resamples the TAC using linear interpolation. The resulting TAC is sanitized to ensure physical consistency.
- Parameters:
dt (float, optional) – The desired time interval between consecutive resampled time points (in the same unit as times). Must be greater than 0. Defaults to 0.1 / 60.0 (approximately 0.00167).
- Returns:
TimeActivityCurve – A new TimeActivityCurve instance with evenly spaced time intervals and resampled activity values.
- Raises:
AssertionError – If dt is less than or equal to 0.
Example
from petpal.utils.time_activity_curve import TimeActivityCurve # Create a TimeActivityCurve object my_tac = TimeActivityCurve( times=np.array([0, 10, 20, 30]), activity=np.array([1.0, 2.0, 3.0, 4.0]) ) # Resample the TAC with a given time interval (dt) resampled_tac = my_tac.evenly_resampled_tac_given_dt(dt=0.1) print(resampled_tac.times) # Output: Evenly spaced time points with interval dt print(resampled_tac.activity) # Output: Interpolated activity values
- resampled_tac_on_times(new_times: numpy.ndarray) TimeActivityCurve#
Resamples the time-activity curve (TAC) on specified time points.
This method uses linear interpolation to compute activity values at the provided time points (new_times). The resulting TAC is sanitized to ensure physical consistency.
- Parameters:
new_times (np.ndarray) – An array of time points where the TAC should be resampled. Must be a 1D array of monotonically increasing values.
- Returns:
TimeActivityCurve – A new TimeActivityCurve instance with the specified time points and interpolated activity values.
Example
from petpal.utils.time_activity_curve import TimeActivityCurve import numpy as np # Create a TimeActivityCurve object my_tac = TimeActivityCurve( times=np.array([0, 10, 20, 30]), activity=np.array([1.0, 2.0, 3.0, 4.0]) ) # New time points for resampling new_times = np.array([5, 15, 25]) # Resample TAC on new time points resampled_tac = my_tac.resampled_tac_on_times(new_times=new_times) print(resampled_tac.times) # Output: [5, 15, 25] print(resampled_tac.activity) # Output: Interpolated activity values at [5, 15, 25]
- add_zero_time_and_activity()#
Ensures the time-activity curve (TAC) starts at time 0 with zero activity.
If the first time point in the TAC is not 0.0, this method prepends a time point of 0.0 and assigns it an activity value of 0. The associated uncertainty for this time point is set to NaN. The method modifies the TAC in place and returns the updated instance.
- Returns:
TimeActivityCurve – The updated TimeActivityCurve instance with 0.0 prepended to time, activity, and uncertainty arrays (if needed).
Example
from petpal.utils.time_activity_curve import TimeActivityCurve import numpy as np # Create a TimeActivityCurve object my_tac = TimeActivityCurve( times=np.array([10, 20, 30]), activity=np.array([2.0, 3.0, 4.0]), uncertainty=np.array([0.1, 0.2, 0.3]) ) # Add 0 time and activity if missing my_tac = my_tac.add_zero_time_and_activity() print(my_tac.times) # Output: [ 0, 10, 20, 30 ] print(my_tac.activity) # Output: [ 0, 2.0, 3.0, 4.0 ] print(my_tac.uncertainty) # Output: [ NaN, 0.1, 0.2, 0.3 ]
- shifted_tac(shift_in_mins: float = 10.0 / 60.0, dt: float | None = None) TimeActivityCurve#
Returns a time-activity curve (TAC) shifted in time by a specified amount.
If the shift is positive, the TAC is left-shifted; if negative, the TAC is right-shifted. The shift can be applied at the existing time points of the TAC or at oversampled points, depending on the value of dt.
- Parameters:
shift_in_mins (float, optional) – The amount (in minutes) to shift the TAC. Positive values indicate a left shift; negative values indicate a right shift. Defaults to 10.0 / 60.0 (10 seconds).
dt (float | None, optional) – The time interval for oversampling. If None, the TAC is resampled at its original time points. If a value is provided, the TAC is resampled at an evenly spaced interval of dt.
- Returns:
TimeActivityCurve – A new TimeActivityCurve instance with the shifted activity values.
- Raises:
AssertionError – If dt is equal to 0.
Example
# Left-shifting the TAC shifted_tac = my_tac.shifted_tac(shift_in_mins=5.0 / 60.0) # Right-shifting the TAC with oversampling shifted_tac = my_tac.shifted_tac(shift_in_mins=-2.0 / 60.0, dt=0.1 / 60.0)
See also
- static left_shifted_tac(tac: TimeActivityCurve, shift_in_mins: float = 10.0 / 60.0, dt: float | None = 0.1 / 60.0) TimeActivityCurve#
Produces a TAC left-shifted by a specified amount of time.
The left shift moves activity values earlier in time and fills the trailing values with interpolated data. The shift can either be applied on the original time points or on a time grid determined by dt.
- Parameters:
tac (TimeActivityCurve) – The original TAC to be shifted.
shift_in_mins (float, optional) – The amount (in minutes) to left-shift the TAC. Must be larger than 0. Defaults to 10.0 / 60.0 (10 seconds).
dt (float | None, optional) – The time interval for oversampling. If None, the TAC is resampled at its original time points. If a value is provided, the TAC is resampled at an evenly spaced interval of dt.
- Returns:
TimeActivityCurve – A new TimeActivityCurve instance with the left-shifted activity values.
- Raises:
AssertionError – If shift_in_mins is not greater than 0.
Example
# Perform a left shift on the TAC shifted_tac = TimeActivityCurve.left_shifted_tac(tac=my_tac, shift_in_mins=5.0 / 60.0) # Perform a left shift with oversampling shifted_tac = TimeActivityCurve.left_shifted_tac(tac=my_tac, shift_in_mins=2.0 / 60.0, dt=0.05 / 60.0)
- static right_shifted_tac(tac: TimeActivityCurve, shift_in_mins: float = 10.0 / 60.0, dt: float | None = 0.1 / 60.0) TimeActivityCurve#
Produces a TAC right-shifted by a specified amount of time.
The right shift moves activity values later in time and fills the leading values with interpolated data. The shift can either be applied on the original time points or on a time grid determined by dt.
- Parameters:
tac (TimeActivityCurve) – The original TAC to be shifted.
shift_in_mins (float, optional) – The amount (in minutes) to right-shift the TAC. Must be larger than 0. Defaults to 10.0 / 60.0 (10 seconds).
dt (float | None, optional) – The time interval for oversampling. If None, the TAC is resampled at its original time points. If a value is provided, the TAC is resampled at an evenly spaced interval of dt.
- Returns:
TimeActivityCurve – A new TimeActivityCurve instance with the right-shifted activity values.
- Raises:
AssertionError – If shift_in_mins is not greater than 0.
Example
# Perform a right shift on the TAC shifted_tac = TimeActivityCurve.right_shifted_tac(tac=my_tac, shift_in_mins=5.0 / 60.0) # Perform a right shift with oversampling shifted_tac = TimeActivityCurve.right_shifted_tac(tac=my_tac, shift_in_mins=2.0 / 60.0, dt=0.05 / 60.0)
- static tac_dispersion(tac: TimeActivityCurve, disp_func: Callable[Ellipsis, numpy.ndarray], disp_kwargs: dict, num_samples: int = 4096)#
Applies a dispersion function to a time-activity curve (TAC) and returns the convolved TAC.
This method evaluates the specified dispersion function disp_func at supersampled time points. It performs convolution (using
scipy.signal.convolve()) of the supersampled TAC with the dispersion function, and the result is sampled back at the original TAC time points to form the new convolved TAC.Note
We perform the supersampling to ensure that the TACs are sampled evenly before performing the convolution. Convolving non-evenly sampled arrays produces nonsense values.
- Parameters:
tac (TimeActivityCurve) – The original time-activity curve to be convolved.
disp_func (Callable[..., np.ndarray]) – The dispersion function to be applied. This function must accept an array of times as its first argument, followed by any additional arguments specified in disp_kwargs.
disp_kwargs (dict) – Additional keyword arguments to pass to disp_func.
num_samples (int, optional) – The number of evenly spaced samples for supersampling the TAC before convolution. Defaults to 4096.
- Returns:
TimeActivityCurve – A new TimeActivityCurve instance with the convolved activity values, resampled at the original TAC time points.
Example
from petpal.utils.time_activity_curve import TimeActivityCurve import numpy as np # Define a sample dispersion function def monoexponential_kernel(t:np.ndarray, tau:float) -> np.ndarray: return (1.0/tau) * np.exp(-t / tau) # Original TAC my_tac = TimeActivityCurve( times=np.array([0, 10, 20, 30]), activity=np.array([1.0, 2.0, 3.0, 4.0]) ) # Apply dispersion convolved_tac = TimeActivityCurve.tac_dispersion( tac=my_tac, disp_func=monoexponential_kernel, disp_kwargs={'tau': 5}, num_samples=1024 ) print(convolved_tac.times) # Output: Original TAC time points print(convolved_tac.activity) # Output: Activity after applying dispersion
See also
evenly_resample_tac()
- property contains_any_nan#
Return True if TAC has any NaN activity values.