Simple-Track 2.0.4__tar.gz → 2.0.5__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 (29) hide show
  1. {simple_track-2.0.4 → simple_track-2.0.5}/PKG-INFO +9 -7
  2. {simple_track-2.0.4 → simple_track-2.0.5}/README.md +8 -6
  3. {simple_track-2.0.4 → simple_track-2.0.5}/pyproject.toml +1 -1
  4. {simple_track-2.0.4 → simple_track-2.0.5}/src/Simple_Track.egg-info/PKG-INFO +9 -7
  5. {simple_track-2.0.4 → simple_track-2.0.5}/src/simpletrack/feature.py +21 -8
  6. {simple_track-2.0.4 → simple_track-2.0.5}/src/simpletrack/frame.py +5 -1
  7. {simple_track-2.0.4 → simple_track-2.0.5}/src/simpletrack/track.py +1 -1
  8. {simple_track-2.0.4 → simple_track-2.0.5}/tests/test_frame.py +28 -3
  9. {simple_track-2.0.4 → simple_track-2.0.5}/LICENSE +0 -0
  10. {simple_track-2.0.4 → simple_track-2.0.5}/setup.cfg +0 -0
  11. {simple_track-2.0.4 → simple_track-2.0.5}/src/Simple_Track.egg-info/SOURCES.txt +0 -0
  12. {simple_track-2.0.4 → simple_track-2.0.5}/src/Simple_Track.egg-info/dependency_links.txt +0 -0
  13. {simple_track-2.0.4 → simple_track-2.0.5}/src/Simple_Track.egg-info/entry_points.txt +0 -0
  14. {simple_track-2.0.4 → simple_track-2.0.5}/src/Simple_Track.egg-info/requires.txt +0 -0
  15. {simple_track-2.0.4 → simple_track-2.0.5}/src/Simple_Track.egg-info/top_level.txt +0 -0
  16. {simple_track-2.0.4 → simple_track-2.0.5}/src/run_simple_track.py +0 -0
  17. {simple_track-2.0.4 → simple_track-2.0.5}/src/simpletrack/__init__.py +0 -0
  18. {simple_track-2.0.4 → simple_track-2.0.5}/src/simpletrack/exceptions.py +0 -0
  19. {simple_track-2.0.4 → simple_track-2.0.5}/src/simpletrack/flow_solver.py +0 -0
  20. {simple_track-2.0.4 → simple_track-2.0.5}/src/simpletrack/frame_output.py +0 -0
  21. {simple_track-2.0.4 → simple_track-2.0.5}/src/simpletrack/frame_tracker.py +0 -0
  22. {simple_track-2.0.4 → simple_track-2.0.5}/src/simpletrack/load.py +0 -0
  23. {simple_track-2.0.4 → simple_track-2.0.5}/src/simpletrack/utils.py +0 -0
  24. {simple_track-2.0.4 → simple_track-2.0.5}/tests/test_feature.py +0 -0
  25. {simple_track-2.0.4 → simple_track-2.0.5}/tests/test_flow_solver.py +0 -0
  26. {simple_track-2.0.4 → simple_track-2.0.5}/tests/test_frame_tracker.py +0 -0
  27. {simple_track-2.0.4 → simple_track-2.0.5}/tests/test_mwe_output.py +0 -0
  28. {simple_track-2.0.4 → simple_track-2.0.5}/tests/test_simple_track_and_load.py +0 -0
  29. {simple_track-2.0.4 → simple_track-2.0.5}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Simple-Track
3
- Version: 2.0.4
3
+ Version: 2.0.5
4
4
  Summary: Threshold-based object tracking algorithm for 2D data
5
5
  Author-email: Adam Gainford <adam.gainford@reading.ac.uk>, Thorwald Stein <t.h.m.stein@reading.ac.uk>
6
6
  License-Expression: MPL-2.0
@@ -33,13 +33,15 @@ Features are tracked between consecutive frames of data by projecting feature fi
33
33
 
34
34
  # Installation
35
35
 
36
- Simple-Track can be installed using PyPi:
36
+ Simple-Track can be installed using PyPi or conda-forge:
37
37
 
38
38
  ```
39
39
  python3 -m pip install simple-track
40
40
  ```
41
-
42
- Coming soon to conda-forge and uv
41
+ ```
42
+ conda install conda-forge::simple-track
43
+ ```
44
+ Coming soon to uv
43
45
 
44
46
  # User Guide
45
47
 
@@ -177,10 +179,10 @@ Fields (`.field` files):
177
179
 
178
180
  Features (`.csv` or `.txt` files):
179
181
  * ID: Unique feature identifier that persists between frames (i.e., a feature retains the same id across all frames that it is tracked).
180
- * Centroid: (y, x) tuple containing central location of feature.
181
- * Size: Number of pixels spanned by the feature.
182
+ * centroid: (y, x) tuple containing central location of feature.
183
+ * size: Number of pixels spanned by the feature.
182
184
  * dydx: (dy, dx) tuple containing motion vector that translated feature to its location in the current frame from the previous frame.
183
- * extreme: Maximum value contained within the feature in the input data.
185
+ * max: Maximum value contained within the feature in the input data.
184
186
  * lifetime: Number of timesteps the feature has existed for.
185
187
  * accreted: List of IDs of features that were accreted by this feature, if applicable.
186
188
  * parent: ID of parent feature that this feature split from, if applicable
@@ -11,13 +11,15 @@ Features are tracked between consecutive frames of data by projecting feature fi
11
11
 
12
12
  # Installation
13
13
 
14
- Simple-Track can be installed using PyPi:
14
+ Simple-Track can be installed using PyPi or conda-forge:
15
15
 
16
16
  ```
17
17
  python3 -m pip install simple-track
18
18
  ```
19
-
20
- Coming soon to conda-forge and uv
19
+ ```
20
+ conda install conda-forge::simple-track
21
+ ```
22
+ Coming soon to uv
21
23
 
22
24
  # User Guide
23
25
 
@@ -155,10 +157,10 @@ Fields (`.field` files):
155
157
 
156
158
  Features (`.csv` or `.txt` files):
157
159
  * ID: Unique feature identifier that persists between frames (i.e., a feature retains the same id across all frames that it is tracked).
158
- * Centroid: (y, x) tuple containing central location of feature.
159
- * Size: Number of pixels spanned by the feature.
160
+ * centroid: (y, x) tuple containing central location of feature.
161
+ * size: Number of pixels spanned by the feature.
160
162
  * dydx: (dy, dx) tuple containing motion vector that translated feature to its location in the current frame from the previous frame.
161
- * extreme: Maximum value contained within the feature in the input data.
163
+ * max: Maximum value contained within the feature in the input data.
162
164
  * lifetime: Number of timesteps the feature has existed for.
163
165
  * accreted: List of IDs of features that were accreted by this feature, if applicable.
164
166
  * parent: ID of parent feature that this feature split from, if applicable
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "Simple-Track"
7
- version = "2.0.4"
7
+ version = "2.0.5"
8
8
  authors = [
9
9
  { name="Adam Gainford", email="adam.gainford@reading.ac.uk" },
10
10
  { name="Thorwald Stein", email="t.h.m.stein@reading.ac.uk"}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Simple-Track
3
- Version: 2.0.4
3
+ Version: 2.0.5
4
4
  Summary: Threshold-based object tracking algorithm for 2D data
5
5
  Author-email: Adam Gainford <adam.gainford@reading.ac.uk>, Thorwald Stein <t.h.m.stein@reading.ac.uk>
6
6
  License-Expression: MPL-2.0
@@ -33,13 +33,15 @@ Features are tracked between consecutive frames of data by projecting feature fi
33
33
 
34
34
  # Installation
35
35
 
36
- Simple-Track can be installed using PyPi:
36
+ Simple-Track can be installed using PyPi or conda-forge:
37
37
 
38
38
  ```
39
39
  python3 -m pip install simple-track
40
40
  ```
41
-
42
- Coming soon to conda-forge and uv
41
+ ```
42
+ conda install conda-forge::simple-track
43
+ ```
44
+ Coming soon to uv
43
45
 
44
46
  # User Guide
45
47
 
@@ -177,10 +179,10 @@ Fields (`.field` files):
177
179
 
178
180
  Features (`.csv` or `.txt` files):
179
181
  * ID: Unique feature identifier that persists between frames (i.e., a feature retains the same id across all frames that it is tracked).
180
- * Centroid: (y, x) tuple containing central location of feature.
181
- * Size: Number of pixels spanned by the feature.
182
+ * centroid: (y, x) tuple containing central location of feature.
183
+ * size: Number of pixels spanned by the feature.
182
184
  * dydx: (dy, dx) tuple containing motion vector that translated feature to its location in the current frame from the previous frame.
183
- * extreme: Maximum value contained within the feature in the input data.
185
+ * max: Maximum value contained within the feature in the input data.
184
186
  * lifetime: Number of timesteps the feature has existed for.
185
187
  * accreted: List of IDs of features that were accreted by this feature, if applicable.
186
188
  * parent: ID of parent feature that this feature split from, if applicable
@@ -9,7 +9,7 @@ from simpletrack.utils import check_arrays, check_valid_ids, native
9
9
  class Feature:
10
10
  """
11
11
  Object containing details about a specific feature, including its id, time,
12
- centroid, extreme value, lifetime, and whether it has undergone any
12
+ centroid, maximum value, lifetime, and whether it has undergone any
13
13
  mergers of splits in the current timestep.
14
14
  """
15
15
 
@@ -30,7 +30,8 @@ class Feature:
30
30
  self._parent = None
31
31
  self._children = []
32
32
  self._dydx = ()
33
- self._extreme = None
33
+ self._max = None
34
+ self._mean = None
34
35
 
35
36
  def __repr__(self) -> str:
36
37
  repr_str = f"Feature id: {self._id} (provisionally {self._provisional_id}), "
@@ -140,11 +141,18 @@ class Feature:
140
141
  return native(self._dydx)
141
142
 
142
143
  @property
143
- def extreme(self) -> float:
144
+ def max(self) -> float:
144
145
  """
145
146
  Maximum value of the Feature in the raw input data
146
147
  """
147
- return self._extreme
148
+ return self._max
149
+
150
+ @property
151
+ def mean(self) -> float:
152
+ """
153
+ Mean value of the Feature in the raw input data
154
+ """
155
+ return self._mean
148
156
 
149
157
  @coords.setter
150
158
  def coords(self, new_coords: NDArray[np.integer]) -> None:
@@ -184,9 +192,13 @@ class Feature:
184
192
  id_of_accreting_feature = check_valid_ids(id_of_accreting_feature)
185
193
  self._accreted_in_next_frame_by = id_of_accreting_feature
186
194
 
187
- @extreme.setter
188
- def extreme(self, extreme_val: float) -> None:
189
- self._extreme = extreme_val
195
+ @max.setter
196
+ def max(self, max_val: float) -> None:
197
+ self._max = max_val
198
+
199
+ @mean.setter
200
+ def mean(self, mean_val: float) -> None:
201
+ self._mean = mean_val
190
202
 
191
203
  def calculate_centroid(self) -> tuple:
192
204
  """
@@ -279,7 +291,8 @@ class Feature:
279
291
  "size": self.get_size(),
280
292
  # native() does not convert dydx to python type for some reason
281
293
  "dydx": tuple([val.item() for val in self._dydx]),
282
- "extreme": self._extreme,
294
+ "max": self._max,
295
+ "mean": self._mean,
283
296
  "lifetime": self._lifetime,
284
297
  "accreted": self._accreted,
285
298
  # This will not be output properly in the current workflow, since each
@@ -211,7 +211,8 @@ class Frame:
211
211
  )
212
212
  # If raw field is not None, use this to find max value within Feature
213
213
  if self.raw_field is not None:
214
- feature.extreme = max(self.raw_field[feature_mask])
214
+ feature.max = np.max(self.raw_field[feature_mask])
215
+ feature.mean = np.mean(self.raw_field[feature_mask])
215
216
  self._features[feature_id] = feature
216
217
 
217
218
  def assign_displacements(self, y_flow: NDArray, x_flow: NDArray) -> None:
@@ -387,6 +388,9 @@ class Timeline:
387
388
  def __init__(self):
388
389
  self.timeline = {}
389
390
 
391
+ def __len__(self) -> int:
392
+ return len(self.timeline)
393
+
390
394
  def add_to_timelime(self, frame: Frame) -> None:
391
395
  """
392
396
  Add the input frame to the timeline, using the frame.get_time() to
@@ -58,7 +58,7 @@ class Tracker:
58
58
  self.frame_tracker = FrameTracker()
59
59
 
60
60
  if "OUTPUT" in self.config:
61
- self.skip_tracking = self.config["TRACKING"].get("skip_tracking", False)
61
+ self.skip_tracking = self.config["OUTPUT"].get("skip_tracking", False)
62
62
  output_path = self.config["OUTPUT"].get("path", "./output")
63
63
  expt_name = self.config["OUTPUT"].get(
64
64
  "experiment_name", "Simple-Track Experiment"
@@ -103,7 +103,7 @@ def test_populate_features_valid_feature_field():
103
103
  assert test_frame.features == expected_dict
104
104
 
105
105
 
106
- def test_populate_features_sets_extreme_property():
106
+ def test_populate_features_sets_max_property():
107
107
  test_time = dt.datetime.now()
108
108
  test_frame = Frame()
109
109
  test_frame.time = test_time
@@ -123,8 +123,33 @@ def test_populate_features_sets_extreme_property():
123
123
  test_frame.raw_field = test_raw_field
124
124
  test_frame.populate_features()
125
125
 
126
- assert test_frame.get_feature(1).extreme == 10
127
- assert test_frame.get_feature(2).extreme == 20
126
+ assert test_frame.get_feature(1).max == 10
127
+ assert test_frame.get_feature(2).max == 20
128
+
129
+
130
+ def test_populate_features_sets_mean_property():
131
+ test_time = dt.datetime.now()
132
+ test_frame = Frame()
133
+ test_frame.time = test_time
134
+
135
+ test_feature_field = test_field.copy()
136
+ test_feature_field[2:6, 2:6] = 1
137
+ test_feature_field[6:9, 6:9] = 2
138
+
139
+ test_raw_field = test_field.copy()
140
+ test_raw_field[2:6, 2:6] = 10
141
+ test_raw_field[2:6, 4:6] = 50
142
+ test_raw_field[6:9, 6:9] = 20
143
+ # Set another higher maximum within the field to check mean
144
+ # only picks up the values within the feature mask
145
+ test_raw_field[0:2, 0:2] = 100
146
+
147
+ test_frame.feature_field = test_feature_field
148
+ test_frame.raw_field = test_raw_field
149
+ test_frame.populate_features()
150
+
151
+ assert test_frame.get_feature(1).mean == 30
152
+ assert test_frame.get_feature(2).mean == 20
128
153
 
129
154
 
130
155
  def test_populate_features_invalid_negative_features():
File without changes
File without changes