"""
Module with functions to read and write tracking data
"""
import csv
import pathlib
from typing import List, Tuple, Union
# TODO: update this to make it more general
[docs]def read_track_file_csv(path: Union[str, pathlib.Path]) -> List[Tuple]:
"""Function reads track data from a .csv file that has the data format of track files created
by the TrackIt framework and returns the data.
Parameters
----------
path: str or pathlib.Path
Path to the file with track information.
Returns
-------
data: list of tuples
List with tuples, where every tuple contains the information of one part of a track. Every
tuple has the following structure: (f, t, x, y, track_id, disp, intensity, sigma, fit_error).
f (int): frame number
t (float): time
x (float): x-coordinate in um
y (float): y-coordinate in um
track_id (int): id of the track
disp (float): displacement in um between current localization of track and previous one.
The value is -1 if it is the first localization of the track.
intensity (float): TODO is from SOS
sigma (float): TODO is from SOS
fit_error (float): TODO is from SOS
Raises
------
ValueError
If the path suffix does not end with .csv
FileNotFoundError
If the file is not present at path.
"""
if isinstance(path, str):
path = pathlib.Path(path)
if path.suffix != ".csv":
raise ValueError(f"path should end with .csv, but ends with {path.suffix}")
data = []
with open(path, "r") as csvfile:
reader = csv.DictReader(csvfile)
for i, row in enumerate(reader):
if len(row) == 6:
f = int(float(row["frame"]))
t = float(row["t"])
x = float(row["x"])
y = float(row["y"])
track_id = int(float(row["trajectory"]))
# If the track_id is the same as the previous point
# then we can calculate a displacement otherwise set at -1
if i != 0 and track_id == data[-1][3]:
disp = ((x - data[-1][1]) ** 2 + (y - data[-1][2]) ** 2) ** 0.5
else:
disp = -1
intensity = None
sigma = None
fit_error = None
data.append((f, t, x, y, track_id, disp, intensity, sigma, fit_error))
else:
print(
f"Something went wrong at {path}, line {i} does not have 6 values."
)
return data
def write_track_file_csv(path: Union[str, pathlib.Path], data: List[Tuple]):
"""Function writes track data to a .csv file with the data format of track files created
by the TrackIt framework.
Parameters
----------
path: str or pathlib.Path
Path to the file with track information.
data: list of tuples
List with tuples, where every tuple contains the information of one part of a track. Every
tuple has the following structure: (f, t, x, y, track_id, disp, intensity, sigma, fit_error).
f (int): frame number
t (float): time
x (float): x-coordinate in um
y (float): y-coordinate in um
track_id (int): id of the track
disp (float): displacement in um between current localization of track and previous one.
The value is -1 if it is the first localization of the track.
intensity (float): TODO is from SOS
sigma (float): TODO is from SOS
fit_error (float): TODO is from SOS
Returns
-------
None
Raises
------
ValueError
If the path suffix does not end with .csv
"""
if isinstance(path, str):
path = pathlib.Path(path)
if path.suffix != ".csv":
raise ValueError(f"path should end with .csv, but ends with {path.suffix}")
with open(path, "w", newline="") as csvfile:
fieldnames = ["", "frame", "t", "trajectory", "x", "y"]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for i, d in enumerate(data):
f, t, x, y, track_id, disp, intensity, sigma, fit_error = d
writer.writerow(
{"": i, "frame": f, "t": t, "trajectory": track_id, "x": x, "y": y}
)
print(f"Writing data to {path} is finished.")
def read_track_file_txt(path: Union[str, pathlib.Path]) -> List[Tuple]:
"""Function reads track data from a .txt file that has the data format of track files created
by SOS and returns the data.
Parameters
----------
path: str or pathlib.Path
Path to the file with track information.
Returns
-------
data: list of tuples
List with tuples, where every tuple contains the information of one part of a track. Every
tuple has the following structure: (f, t, x, y, track_id, disp, intensity, sigma, fit_error).
f (int): frame number
t (float): time
x (float): x-coordinate in pixel value
y (float): y-coordinate in pixel value
track_id (int): id of the track
disp (float): displacement in pixel values between current localization of track and
previous one. The value is -1 if it is the first localization of the track.
intensity (float): TODO is from SOS
sigma (float): TODO is from SOS
fit_error (float): TODO is from SOS
Raises
------
ValueError
If the path suffix does not end with .txt
FileNotFoundError
If the file is not present at path.
"""
if isinstance(path, str):
path = pathlib.Path(path)
if path.suffix != ".txt":
raise ValueError(f"path should end with .txt, but ends with {path.suffix}")
data = []
# data = [None] * sum(1 for line in open(path, "r"))
i = 0
with open(path, "r") as rf:
for line in rf:
line = line.strip()
values = line.split("\t")
if len(values) == 8:
f = int(float(values[0]))
t = None
x = float(values[1])
y = float(values[2])
track_id = int(float(values[3]))
disp = float(values[4])
intensity = float(values[5])
sigma = float(values[6])
fit_error = float(values[7])
data.append((f, t, x, y, track_id, disp, intensity, sigma, fit_error))
else:
print(
f"Something went wrong at {path}, line {i} does not have 8 values."
)
i += 1
return data