simba-uw-tf-dev 4.6.2__py3-none-any.whl → 4.7.2__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.

Potentially problematic release.


This version of simba-uw-tf-dev might be problematic. Click here for more details.

Files changed (96) hide show
  1. simba/assets/.recent_projects.txt +1 -0
  2. simba/assets/lookups/tooptips.json +6 -1
  3. simba/assets/lookups/yolo_schematics/yolo_mitra.csv +9 -0
  4. simba/data_processors/agg_clf_counter_mp.py +52 -53
  5. simba/data_processors/blob_location_computer.py +1 -1
  6. simba/data_processors/circling_detector.py +30 -13
  7. simba/data_processors/cuda/geometry.py +45 -27
  8. simba/data_processors/cuda/image.py +1648 -1598
  9. simba/data_processors/cuda/statistics.py +72 -26
  10. simba/data_processors/cuda/timeseries.py +1 -1
  11. simba/data_processors/cue_light_analyzer.py +5 -9
  12. simba/data_processors/egocentric_aligner.py +25 -7
  13. simba/data_processors/freezing_detector.py +55 -47
  14. simba/data_processors/kleinberg_calculator.py +61 -29
  15. simba/feature_extractors/feature_subsets.py +14 -7
  16. simba/feature_extractors/mitra_feature_extractor.py +2 -2
  17. simba/feature_extractors/straub_tail_analyzer.py +4 -6
  18. simba/labelling/standard_labeller.py +1 -1
  19. simba/mixins/config_reader.py +5 -2
  20. simba/mixins/geometry_mixin.py +22 -36
  21. simba/mixins/image_mixin.py +24 -28
  22. simba/mixins/plotting_mixin.py +28 -10
  23. simba/mixins/statistics_mixin.py +48 -11
  24. simba/mixins/timeseries_features_mixin.py +1 -1
  25. simba/mixins/train_model_mixin.py +68 -33
  26. simba/model/inference_batch.py +2 -2
  27. simba/model/yolo_seg_inference.py +3 -3
  28. simba/outlier_tools/skip_outlier_correction.py +1 -1
  29. simba/plotting/ROI_feature_visualizer_mp.py +3 -5
  30. simba/plotting/clf_validator_mp.py +4 -5
  31. simba/plotting/cue_light_visualizer.py +6 -7
  32. simba/plotting/directing_animals_visualizer_mp.py +2 -3
  33. simba/plotting/distance_plotter_mp.py +378 -378
  34. simba/plotting/gantt_creator.py +29 -10
  35. simba/plotting/gantt_creator_mp.py +96 -33
  36. simba/plotting/geometry_plotter.py +270 -272
  37. simba/plotting/heat_mapper_clf_mp.py +4 -6
  38. simba/plotting/heat_mapper_location_mp.py +2 -2
  39. simba/plotting/light_dark_box_plotter.py +2 -2
  40. simba/plotting/path_plotter_mp.py +26 -29
  41. simba/plotting/plot_clf_results_mp.py +455 -454
  42. simba/plotting/pose_plotter_mp.py +28 -29
  43. simba/plotting/probability_plot_creator_mp.py +288 -288
  44. simba/plotting/roi_plotter_mp.py +31 -31
  45. simba/plotting/single_run_model_validation_video_mp.py +427 -427
  46. simba/plotting/spontaneous_alternation_plotter.py +2 -3
  47. simba/plotting/yolo_pose_track_visualizer.py +32 -27
  48. simba/plotting/yolo_pose_visualizer.py +35 -36
  49. simba/plotting/yolo_seg_visualizer.py +2 -3
  50. simba/pose_importers/simba_blob_importer.py +3 -3
  51. simba/roi_tools/roi_aggregate_stats_mp.py +5 -4
  52. simba/roi_tools/roi_clf_calculator_mp.py +4 -4
  53. simba/sandbox/analyze_runtimes.py +30 -0
  54. simba/sandbox/cuda/egocentric_rotator.py +374 -374
  55. simba/sandbox/get_cpu_pool.py +5 -0
  56. simba/sandbox/proboscis_to_tip.py +28 -0
  57. simba/sandbox/test_directionality.py +47 -0
  58. simba/sandbox/test_nonstatic_directionality.py +27 -0
  59. simba/sandbox/test_pycharm_cuda.py +51 -0
  60. simba/sandbox/test_simba_install.py +41 -0
  61. simba/sandbox/test_static_directionality.py +26 -0
  62. simba/sandbox/test_static_directionality_2d.py +26 -0
  63. simba/sandbox/verify_env.py +42 -0
  64. simba/third_party_label_appenders/transform/coco_keypoints_to_yolo.py +3 -3
  65. simba/third_party_label_appenders/transform/coco_keypoints_to_yolo_bbox.py +2 -2
  66. simba/third_party_label_appenders/transform/simba_to_yolo.py +8 -5
  67. simba/ui/pop_ups/clf_plot_pop_up.py +2 -2
  68. simba/ui/pop_ups/fsttc_pop_up.py +27 -25
  69. simba/ui/pop_ups/gantt_pop_up.py +31 -6
  70. simba/ui/pop_ups/kleinberg_pop_up.py +39 -40
  71. simba/ui/pop_ups/run_machine_models_popup.py +21 -21
  72. simba/ui/pop_ups/simba_to_yolo_keypoints_popup.py +2 -2
  73. simba/ui/pop_ups/video_processing_pop_up.py +37 -29
  74. simba/ui/pop_ups/yolo_inference_popup.py +1 -1
  75. simba/ui/pop_ups/yolo_pose_train_popup.py +1 -1
  76. simba/ui/tkinter_functions.py +3 -0
  77. simba/utils/custom_feature_extractor.py +1 -1
  78. simba/utils/data.py +90 -14
  79. simba/utils/enums.py +1 -0
  80. simba/utils/errors.py +441 -440
  81. simba/utils/lookups.py +1203 -1203
  82. simba/utils/printing.py +124 -124
  83. simba/utils/read_write.py +3769 -3721
  84. simba/utils/yolo.py +10 -1
  85. simba/video_processors/blob_tracking_executor.py +2 -2
  86. simba/video_processors/clahe_ui.py +1 -1
  87. simba/video_processors/egocentric_video_rotator.py +44 -41
  88. simba/video_processors/multi_cropper.py +1 -1
  89. simba/video_processors/video_processing.py +75 -33
  90. simba/video_processors/videos_to_frames.py +43 -33
  91. {simba_uw_tf_dev-4.6.2.dist-info → simba_uw_tf_dev-4.7.2.dist-info}/METADATA +4 -3
  92. {simba_uw_tf_dev-4.6.2.dist-info → simba_uw_tf_dev-4.7.2.dist-info}/RECORD +96 -85
  93. {simba_uw_tf_dev-4.6.2.dist-info → simba_uw_tf_dev-4.7.2.dist-info}/LICENSE +0 -0
  94. {simba_uw_tf_dev-4.6.2.dist-info → simba_uw_tf_dev-4.7.2.dist-info}/WHEEL +0 -0
  95. {simba_uw_tf_dev-4.6.2.dist-info → simba_uw_tf_dev-4.7.2.dist-info}/entry_points.txt +0 -0
  96. {simba_uw_tf_dev-4.6.2.dist-info → simba_uw_tf_dev-4.7.2.dist-info}/top_level.txt +0 -0
@@ -14,7 +14,7 @@ from simba.data_processors.spontaneous_alternation_calculator import \
14
14
  from simba.mixins.config_reader import ConfigReader
15
15
  from simba.utils.checks import (check_file_exist_and_readable, check_float,
16
16
  check_int, check_str, check_valid_lst)
17
- from simba.utils.data import detect_bouts
17
+ from simba.utils.data import detect_bouts, terminate_cpu_pool
18
18
  from simba.utils.enums import Formats, Paths, TextOptions
19
19
  from simba.utils.errors import AnimalNumberError, InvalidInputError
20
20
  from simba.utils.printing import stdout_success
@@ -296,8 +296,7 @@ class SpontaneousAlternationsPlotter(ConfigReader):
296
296
  pool.imap(constants, frm_index, chunksize=self.multiprocess_chunksize)
297
297
  ):
298
298
  print(f"Section {cnt} complete...")
299
- pool.terminate()
300
- pool.join()
299
+ terminate_cpu_pool(pool=pool, force=False)
301
300
  print(f"Joining {sa_computer.video_name} multiprocessed video...")
302
301
  concatenate_videos_in_folder(in_folder=self.temp_folder, save_path=save_path)
303
302
  self.timer.stop_timer()
@@ -13,9 +13,11 @@ from simba.mixins.plotting_mixin import PlottingMixin
13
13
  from simba.utils.checks import (check_file_exist_and_readable, check_float,
14
14
  check_if_dir_exists, check_int,
15
15
  check_valid_boolean, check_valid_dataframe)
16
+ from simba.utils.data import get_cpu_pool, terminate_cpu_pool
16
17
  from simba.utils.enums import Defaults, Formats
17
18
  from simba.utils.errors import InvalidFilepathError, NoFilesFoundError
18
- from simba.utils.lookups import get_random_color_palette, intermittent_palette
19
+ from simba.utils.lookups import (get_current_time, get_random_color_palette,
20
+ intermittent_palette)
19
21
  from simba.utils.printing import SimbaTimer, stdout_success
20
22
  from simba.utils.read_write import (concatenate_videos_in_folder,
21
23
  create_directory,
@@ -53,13 +55,12 @@ def _yolo_keypoint_track_visualizer(frm_ids: np.ndarray,
53
55
  video_save_path = os.path.join(save_dir, f'{batch_id}.mp4')
54
56
  video_writer = cv2.VideoWriter(video_save_path, fourcc, video_meta_data["fps"], (video_meta_data["width"], video_meta_data["height"]))
55
57
  while current_frm <= end_frm:
56
- print(f'Processing frame {current_frm}/{video_meta_data["frame_count"]} (batch: {batch_id})...')
58
+ print(f'[{get_current_time()}] Processing frame {current_frm}/{video_meta_data["frame_count"]} (batch: {batch_id}, video name: {video_meta_data["video_name"]})...')
57
59
  img = read_frm_of_video(video_path=video_path, frame_index=current_frm, raise_error=False)
58
60
  if img is not None:
59
61
  frm_data = data.loc[data[FRAME] == current_frm]
60
62
  frm_data = frm_data[frm_data[CONFIDENCE] > threshold]
61
63
  for cnt, (row, row_data) in enumerate(frm_data.iterrows()):
62
-
63
64
  clrs = np.array(palettes[int(row_data[TRACK])]).astype(np.int32)
64
65
  bbox_cords = row_data[BOX_CORD_FIELDS].values.astype(np.int32).reshape(-1, 2)
65
66
  kp_coords = row_data.drop(EXPECTED_COLS).values.astype(np.int32).reshape(-1, 3)[:, :-1]
@@ -159,6 +160,8 @@ class YOLOPoseTrackVisualizer():
159
160
  self.threshold, self.circle_size, self.thickness, self.show_bbox, self.overwrite = threshold, circle_size, thickness, bbox, overwrite
160
161
 
161
162
  def run(self):
163
+ self.pool = get_cpu_pool(core_cnt=self.core_cnt, maxtasksperchild=Defaults.MAXIMUM_MAX_TASK_PER_CHILD.value, source=self.__class__.__name__)
164
+ self.timer = SimbaTimer(start=True)
162
165
  for video_cnt, (video_name, data_path) in enumerate(self.data_paths.items()):
163
166
  print(f'Visualizing YOLO pose tracks in video {video_name} ({video_cnt+1}/{len(self.data_paths.keys())}) ...')
164
167
  video_timer = SimbaTimer(start=True)
@@ -189,23 +192,25 @@ class YOLOPoseTrackVisualizer():
189
192
 
190
193
  frm_batches = np.array_split(np.array(list(range(0, df_frm_cnt))), self.core_cnt)
191
194
  frm_batches = [(i, j) for i, j in enumerate(frm_batches)]
192
- with multiprocessing.Pool(self.core_cnt, maxtasksperchild=Defaults.MAXIMUM_MAX_TASK_PER_CHILD.value) as pool:
193
- constants = functools.partial(_yolo_keypoint_track_visualizer,
194
- data=self.data_df,
195
- threshold=self.threshold,
196
- video_path=self.video_paths[video_name],
197
- save_dir=video_temp_dir,
198
- circle_size=video_circle_size,
199
- thickness=video_thickness,
200
- palettes=video_palettes,
201
- show_bbox=self.show_bbox)
202
- for cnt, result in enumerate(pool.imap(constants, frm_batches, chunksize=1)):
203
- print(f'Video batch {result+1}/{self.core_cnt} complete...')
204
- pool.terminate()
205
- pool.join()
195
+ constants = functools.partial(_yolo_keypoint_track_visualizer,
196
+ data=self.data_df,
197
+ threshold=self.threshold,
198
+ video_path=self.video_paths[video_name],
199
+ save_dir=video_temp_dir,
200
+ circle_size=video_circle_size,
201
+ thickness=video_thickness,
202
+ palettes=video_palettes,
203
+ show_bbox=self.show_bbox)
204
+ for cnt, result in enumerate(self.pool.imap(constants, frm_batches, chunksize=1)):
205
+ print(f'[{get_current_time()}] Video batch {result+1}/{self.core_cnt} complete...')
206
206
  video_timer.stop_timer()
207
207
  concatenate_videos_in_folder(in_folder=video_temp_dir, save_path=save_path, gpu=True)
208
208
  stdout_success(msg=f'YOLO track pose video saved at {save_path}', source=self.__class__.__name__, elapsed_time=video_timer.elapsed_time_str)
209
+ terminate_cpu_pool(pool=self.pool, force=False, source=self.__class__.__name__)
210
+ self.timer.stop_timer()
211
+ stdout_success(msg=f'YOLO track pose video data for {len(self.data_paths.keys())} videos saved in {self.save_dir}', source=self.__class__.__name__, elapsed_time=self.timer.elapsed_time_str)
212
+
213
+
209
214
  #
210
215
  # if __name__ == "__main__" and not hasattr(sys, 'ps1'):
211
216
  # parser = argparse.ArgumentParser(description="Visualize YOLO pose tracking CSV outputs on their source videos.")
@@ -247,13 +252,13 @@ class YOLOPoseTrackVisualizer():
247
252
  # #kp_vis.run()
248
253
 
249
254
 
250
- if __name__ == "__main__":
251
- VIDEO_PATH = r"E:\netholabs_videos\primeintellect_100_videos"
252
- DATA_PATH = r"E:\netholabs_videos\primeintellect_100_largest"
253
- SAVE_DIR = r"E:\netholabs_videos\primeintellect_100_videos\out"
254
- kp_vis = YOLOPoseTrackVisualizer(data_path=DATA_PATH,
255
- video_path=VIDEO_PATH,
256
- save_dir=SAVE_DIR,
257
- core_cnt=8,
258
- bbox=True)
259
- kp_vis.run()
255
+ # if __name__ == "__main__":
256
+ # VIDEO_PATH = r"E:\netholabs_videos\primeintellect_100_videos"
257
+ # DATA_PATH = r"E:\netholabs_videos\primeintellect_100_largest"
258
+ # SAVE_DIR = r"E:\netholabs_videos\primeintellect_100_videos\out"
259
+ # kp_vis = YOLOPoseTrackVisualizer(data_path=DATA_PATH,
260
+ # video_path=VIDEO_PATH,
261
+ # save_dir=SAVE_DIR,
262
+ # core_cnt=8,
263
+ # bbox=True)
264
+ # kp_vis.run()
@@ -14,7 +14,8 @@ from simba.utils.checks import (check_file_exist_and_readable, check_float,
14
14
  check_if_dir_exists, check_int,
15
15
  check_valid_boolean, check_valid_dataframe,
16
16
  check_valid_lst, check_valid_tuple)
17
- from simba.utils.data import create_color_palette
17
+ from simba.utils.data import (create_color_palette, get_cpu_pool,
18
+ terminate_cpu_pool)
18
19
  from simba.utils.enums import Defaults, Options
19
20
  from simba.utils.errors import (CountError, DataHeaderError, FrameRangeError,
20
21
  InvalidInputError, NoDataError)
@@ -22,10 +23,9 @@ from simba.utils.printing import SimbaTimer, stdout_success
22
23
  from simba.utils.read_write import (concatenate_videos_in_folder,
23
24
  create_directory, find_core_cnt,
24
25
  find_files_of_filetypes_in_directory,
25
- get_fn_ext, get_video_meta_data,
26
- read_frm_of_video, recursive_file_search,
27
- remove_a_folder)
28
- from simba.utils.warnings import InvalidValueWarning
26
+ get_current_time, get_fn_ext,
27
+ get_video_meta_data, read_frm_of_video,
28
+ recursive_file_search, remove_a_folder)
29
29
 
30
30
  FRAME = 'FRAME'
31
31
  CLASS_ID = 'CLASS_ID'
@@ -58,7 +58,7 @@ def _yolo_keypoint_visualizer(frm_ids: np.ndarray,
58
58
  if TRACK in data.columns:
59
59
  data = data.drop([TRACK], axis=1)
60
60
  while current_frm <= end_frm:
61
- print(f'Processing frame {current_frm}/{video_meta_data["frame_count"]} (batch: {batch_id}, video: {video_meta_data["video_name"]})...')
61
+ print(f'[{get_current_time()}] Processing frame {current_frm}/{video_meta_data["frame_count"]} (batch: {batch_id}, video: {video_meta_data["video_name"]})...')
62
62
  img = read_frm_of_video(video_path=video_path, frame_index=current_frm)
63
63
  frm_data = data.loc[data[FRAME] == current_frm]
64
64
  frm_data = frm_data[frm_data[CONFIDENCE] > threshold]
@@ -206,6 +206,7 @@ class YOLOPoseVisualizer():
206
206
  self.timer = SimbaTimer(start=True)
207
207
 
208
208
  def run(self):
209
+ self.pool = get_cpu_pool(core_cnt=self.core_cnt, maxtasksperchild=Defaults.MAXIMUM_MAX_TASK_PER_CHILD.value, verbose=True, source=self.__class__.__name__)
209
210
  for video_cnt, (video_name, data_path) in enumerate(self.data_paths.items()):
210
211
  video_timer = SimbaTimer(start=True)
211
212
  self.video_temp_dir = os.path.join(self.save_dir, video_name, "temp")
@@ -248,26 +249,24 @@ class YOLOPoseVisualizer():
248
249
  thickness = deepcopy(self.thickness)
249
250
  frm_batches = np.array_split(np.array(list(range(0, self.df_frm_cnt))), self.core_cnt)
250
251
  frm_batches = [(i, j) for i, j in enumerate(frm_batches)]
251
- if self.verbose: print(f'Visualizing video {self.video_meta_data["video_name"]} (frame count: {self.video_meta_data["frame_count"]})...')
252
- with multiprocessing.Pool(self.core_cnt, maxtasksperchild=Defaults.MAXIMUM_MAX_TASK_PER_CHILD.value) as pool:
253
- constants = functools.partial(_yolo_keypoint_visualizer,
254
- data=self.data_df,
255
- threshold=self.threshold,
256
- video_path=self.video_paths[video_name],
257
- save_dir=self.video_temp_dir,
258
- circle_size=circle_size,
259
- thickness=thickness,
260
- palettes=self.clrs,
261
- bbox=self.bbox,
262
- skeleton=self.skeleton)
263
- for cnt, result in enumerate(pool.imap(constants, frm_batches, chunksize=1)):
264
- print(f'Video batch {result+1}/{self.core_cnt} complete...')
265
- pool.terminate()
266
- pool.join()
252
+ if self.verbose: print(f'[{get_current_time()}] Visualizing video {self.video_meta_data["video_name"]} (frame count: {self.video_meta_data["frame_count"]})...')
253
+ constants = functools.partial(_yolo_keypoint_visualizer,
254
+ data=self.data_df,
255
+ threshold=self.threshold,
256
+ video_path=self.video_paths[video_name],
257
+ save_dir=self.video_temp_dir,
258
+ circle_size=circle_size,
259
+ thickness=thickness,
260
+ palettes=self.clrs,
261
+ bbox=self.bbox,
262
+ skeleton=self.skeleton)
263
+ for cnt, result in enumerate(self.pool.imap(constants, frm_batches, chunksize=1)):
264
+ print(f'[{get_current_time()}] Video batch {result+1}/{self.core_cnt} complete...')
267
265
  video_timer.stop_timer()
268
266
  concatenate_videos_in_folder(in_folder=self.video_temp_dir, save_path=self.save_path, gpu=True)
269
267
  stdout_success(msg=f'YOLO pose video saved at {self.save_path} (Video {video_cnt+1}/{len(list(self.data_paths.keys()))})', source=self.__class__.__name__, elapsed_time=video_timer.elapsed_time_str)
270
268
 
269
+ terminate_cpu_pool(pool=self.pool, force=False, source=self.__class__.__name__)
271
270
  self.timer.stop_timer()
272
271
  stdout_success(msg=f'{len(list(self.data_paths.keys()))} YOLO pose video saved in directory {self.save_dir}', source=self.__class__.__name__, elapsed_time=self.timer.elapsed_time_str)
273
272
 
@@ -413,18 +412,18 @@ class YOLOPoseVisualizer():
413
412
  # kp_vis.run()
414
413
 
415
414
 
416
- # if __name__ == "__main__":
417
- # video_path = r"E:\netholabs_videos\primeintellect_100_videos\cage_1_date_2025_08_28_hour_20_minute_21.avi"
418
- # data_path = r"E:\netholabs_videos\primeintellect_100_largest\cage_1_date_2025_08_28_hour_20_minute_21.csv"
419
- # save_dir = r'E:\netholabs_videos\test_order'
420
- # kp_vis = YOLOPoseVisualizer(data_path=data_path,
421
- # video_path=video_path,
422
- # save_dir=save_dir,
423
- # core_cnt=14,
424
- # palettes=('tab20',),
425
- # recursive=True,
426
- # sample_n=None)
427
- #
428
- #
429
- # kp_vis.run()
415
+ if __name__ == "__main__":
416
+ video_path = r"E:\netholabs_videos\primeintellect_100_videos\cage_1_date_2025_08_28_hour_20_minute_21.avi"
417
+ data_path = r"E:\netholabs_videos\primeintellect_100_largest\cage_1_date_2025_08_28_hour_20_minute_21.csv"
418
+ save_dir = r'E:\netholabs_videos\test_order'
419
+ kp_vis = YOLOPoseVisualizer(data_path=data_path,
420
+ video_path=video_path,
421
+ save_dir=save_dir,
422
+ core_cnt=14,
423
+ palettes=('tab20',),
424
+ recursive=True,
425
+ sample_n=None)
426
+
427
+
428
+ kp_vis.run()
430
429
 
@@ -12,7 +12,7 @@ from simba.utils.checks import (check_file_exist_and_readable, check_float,
12
12
  check_int, check_valid_boolean,
13
13
  check_valid_dataframe, check_valid_lst,
14
14
  check_valid_tuple)
15
- from simba.utils.data import create_color_palette
15
+ from simba.utils.data import create_color_palette, terminate_cpu_pool
16
16
  from simba.utils.enums import Defaults, Options
17
17
  from simba.utils.errors import CountError, DataHeaderError, FrameRangeError
18
18
  from simba.utils.printing import SimbaTimer, stdout_success
@@ -140,8 +140,7 @@ class YOLOSegmentationVisualizer():
140
140
  shape_opacity=self.shape_opacity)
141
141
  for cnt, result in enumerate(pool.imap(constants, frm_batches, chunksize=1)):
142
142
  print(f'Video batch {result+1}/{self.core_cnt} complete...')
143
- pool.terminate()
144
- pool.join()
143
+ terminate_cpu_pool(pool=pool, force=False)
145
144
  video_timer.stop_timer()
146
145
  concatenate_videos_in_folder(in_folder=self.video_temp_dir, save_path=self.save_path, gpu=True)
147
146
  stdout_success(msg=f'YOLO pose video saved at {self.save_path}', source=self.__class__.__name__, elapsed_time=video_timer.elapsed_time_str)
@@ -44,10 +44,10 @@ class SimBABlobImporter(ConfigReader):
44
44
  :param Optional[bool] verbose: If True, prints progress messages. Default: True.
45
45
 
46
46
  :example:
47
- >>> r = SimBABlobImporter(config_path=r"C:\troubleshooting\simba_blob_project\project_folder\project_config.ini", data_path=r'C:\troubleshooting\simba_blob_project\data')
47
+ >>> r = SimBABlobImporter(config_path=r"C:/troubleshooting/simba_blob_project/project_folder/project_config.ini", data_path=r'C:/troubleshooting/simba_blob_project/data')
48
48
  >>> r.run()
49
- >>> r = SimBABlobImporter(config_path=r"C:\troubleshooting\simba_blob_project\project_folder\project_config.ini",
50
- ... data_path=r'C:\troubleshooting\simba_blob_project\data',
49
+ >>> r = SimBABlobImporter(config_path=r"C:/troubleshooting/simba_blob_project/project_folder/project_config.ini",
50
+ ... data_path=r'C:/troubleshooting/simba_blob_project/data',
51
51
  ... smoothing_settings={'method': 'savitzky-golay', 'time_window': 100},
52
52
  ... interpolation_settings={'method': 'nearest', 'type': 'body-parts'})
53
53
  >>> r.run()
@@ -17,7 +17,8 @@ from simba.utils.checks import (
17
17
  check_all_file_names_are_represented_in_video_log,
18
18
  check_file_exist_and_readable, check_float, check_if_dir_exists, check_int,
19
19
  check_that_column_exist, check_valid_boolean, check_valid_lst)
20
- from simba.utils.data import detect_bouts, slice_roi_dict_for_video
20
+ from simba.utils.data import (detect_bouts, slice_roi_dict_for_video,
21
+ terminate_cpu_pool)
21
22
  from simba.utils.enums import ROI_SETTINGS, Formats, Keys
22
23
  from simba.utils.errors import CountError, ROICoordinatesNotFoundError
23
24
  from simba.utils.printing import SimbaTimer, stdout_success
@@ -167,7 +168,7 @@ class ROIAggregateStatisticsAnalyzerMultiprocess(ConfigReader, FeatureExtraction
167
168
  :param save_path (str | os.PathLike, optional): Path to save summary statistics.
168
169
 
169
170
  :example:
170
- >>> analyzer = ROIAggregateStatisticsAnalyzerMultiprocess(config_path=r"C:\troubleshooting\mitra\project_folder\project_config.ini", body_parts=['Center'], first_entry_time=True, threshold=0.0, calculate_distances=True, transpose=False, detailed_bout_data=True)
171
+ >>> analyzer = ROIAggregateStatisticsAnalyzerMultiprocess(config_path=r"C:/troubleshooting/mitra/project_folder/project_config.ini", body_parts=['Center'], first_entry_time=True, threshold=0.0, calculate_distances=True, transpose=False, detailed_bout_data=True)
171
172
  >>> analyzer.run()
172
173
  >>> analyzer.save()
173
174
  """
@@ -297,8 +298,8 @@ class ROIAggregateStatisticsAnalyzerMultiprocess(ConfigReader, FeatureExtraction
297
298
  self.results.append(result); self.detailed_dfs.append(detailed_dfs)
298
299
  print(f"Data batch core {batch_id} / {self.core_cnt} complete...")
299
300
  self.results = pd.concat(self.results, axis=0).reset_index(drop=True)
300
- pool.join()
301
- pool.terminate()
301
+ terminate_cpu_pool(pool=pool, force=False)
302
+
302
303
 
303
304
  def save(self):
304
305
  self.__clean_results()
@@ -16,7 +16,8 @@ from simba.utils.checks import (
16
16
  check_all_file_names_are_represented_in_video_log,
17
17
  check_file_exist_and_readable, check_if_dir_exists, check_int,
18
18
  check_valid_boolean, check_valid_dataframe, check_valid_lst)
19
- from simba.utils.data import detect_bouts, slice_roi_dict_for_video
19
+ from simba.utils.data import (detect_bouts, slice_roi_dict_for_video,
20
+ terminate_cpu_pool)
20
21
  from simba.utils.enums import ROI_SETTINGS, Keys
21
22
  from simba.utils.errors import InvalidInputError, NoROIDataError
22
23
  from simba.utils.lookups import get_current_time
@@ -149,7 +150,7 @@ class ROIClfCalculatorMultiprocess(ConfigReader):
149
150
  'GitHub tutorial <https://github.com/sgoldenlab/simba/blob/master/docs/Scenario2.md#part-4--analyze-machine-results`__.
150
151
 
151
152
  :example:
152
- >>> analyzer = ROIClfCalculatorMultiprocess(config_path=r"D:\troubleshooting\maplight_ri\project_folder\project_config.ini", bp_names=['resident_NOSE'], clf_names=['attack'], clf_time=True, started_bout_cnt=True, ended_bout_cnt=False, bout_table=True, transpose=True, core_cnt=20)
153
+ >>> analyzer = ROIClfCalculatorMultiprocess(config_path=r"D:/troubleshooting/maplight_ri/project_folder/project_config.ini", bp_names=['resident_NOSE'], clf_names=['attack'], clf_time=True, started_bout_cnt=True, ended_bout_cnt=False, bout_table=True, transpose=True, core_cnt=20)
153
154
  >>> analyzer.run()
154
155
  >>> analyzer.save()
155
156
  """
@@ -237,8 +238,7 @@ class ROIClfCalculatorMultiprocess(ConfigReader):
237
238
  self.bouts_results.append(batch_bout_results)
238
239
  print(f"Data batch core {batch_id + 1} / {self.core_cnt} complete...")
239
240
  self.bouts_results = pd.concat(self.bouts_results, axis=0).reset_index(drop=True) if len(self.bouts_results) > 0 else None
240
- pool.join()
241
- pool.terminate()
241
+ terminate_cpu_pool(pool=pool, force=False)
242
242
 
243
243
  def save(self):
244
244
  self.timer.stop_timer()
@@ -0,0 +1,30 @@
1
+ """Analyze runtime statistics for directionality_to_nonstatic_target"""
2
+ import numpy as np
3
+ from collections import defaultdict
4
+
5
+ # Parse the runtime data
6
+ data = {
7
+ 10000: [0.4389, 0.0008, 0.0012],
8
+ 100000: [0.0063, 0.0052, 0.0052],
9
+ 1000000: [0.0768, 0.0306, 0.0239],
10
+ 10000000: [0.2195, 0.2122, 0.2083],
11
+ 50000000: [1.8936, 1.5664, 1.2548]
12
+ }
13
+
14
+ # Calculate statistics
15
+ print("=" * 80)
16
+ print(f"{'Observations':<15} {'Mean (s)':<12} {'Std (s)':<12} {'Min (s)':<12} {'Max (s)':<12} {'Throughput (M obs/s)':<20}")
17
+ print("=" * 80)
18
+
19
+ for obs_count in sorted(data.keys()):
20
+ times = np.array(data[obs_count])
21
+ mean_time = np.mean(times)
22
+ std_time = np.std(times)
23
+ min_time = np.min(times)
24
+ max_time = np.max(times)
25
+ throughput = obs_count / (mean_time * 1_000_000) # Million observations per second
26
+
27
+ print(f"{obs_count:<15,} {mean_time:<12.4f} {std_time:<12.4f} {min_time:<12.4f} {max_time:<12.4f} {throughput:<20.2f}")
28
+
29
+ print("=" * 80)
30
+ print("\nNote: First run typically includes JIT compilation overhead (especially for 10k observations)")