simba-uw-tf-dev 4.5.8__py3-none-any.whl → 4.7.1__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.
Files changed (98) hide show
  1. simba/SimBA.py +2 -2
  2. simba/assets/.recent_projects.txt +1 -0
  3. simba/assets/icons/frames_2.png +0 -0
  4. simba/assets/lookups/tooptips.json +15 -1
  5. simba/data_processors/agg_clf_counter_mp.py +52 -53
  6. simba/data_processors/blob_location_computer.py +1 -1
  7. simba/data_processors/circling_detector.py +30 -13
  8. simba/data_processors/cuda/geometry.py +45 -27
  9. simba/data_processors/cuda/image.py +1648 -1598
  10. simba/data_processors/cuda/statistics.py +72 -26
  11. simba/data_processors/cuda/timeseries.py +1 -1
  12. simba/data_processors/cue_light_analyzer.py +5 -9
  13. simba/data_processors/egocentric_aligner.py +25 -7
  14. simba/data_processors/freezing_detector.py +55 -47
  15. simba/data_processors/kleinberg_calculator.py +61 -29
  16. simba/feature_extractors/feature_subsets.py +14 -7
  17. simba/feature_extractors/mitra_feature_extractor.py +2 -2
  18. simba/feature_extractors/straub_tail_analyzer.py +4 -6
  19. simba/labelling/standard_labeller.py +1 -1
  20. simba/mixins/config_reader.py +5 -2
  21. simba/mixins/geometry_mixin.py +22 -36
  22. simba/mixins/image_mixin.py +24 -28
  23. simba/mixins/plotting_mixin.py +28 -10
  24. simba/mixins/statistics_mixin.py +48 -11
  25. simba/mixins/timeseries_features_mixin.py +1 -1
  26. simba/mixins/train_model_mixin.py +67 -29
  27. simba/model/inference_batch.py +1 -1
  28. simba/model/yolo_seg_inference.py +3 -3
  29. simba/outlier_tools/skip_outlier_correction.py +1 -1
  30. simba/plotting/ROI_feature_visualizer_mp.py +3 -5
  31. simba/plotting/clf_validator_mp.py +4 -5
  32. simba/plotting/cue_light_visualizer.py +6 -7
  33. simba/plotting/directing_animals_visualizer_mp.py +2 -3
  34. simba/plotting/distance_plotter_mp.py +378 -378
  35. simba/plotting/frame_mergerer_ffmpeg.py +137 -196
  36. simba/plotting/gantt_creator.py +29 -10
  37. simba/plotting/gantt_creator_mp.py +96 -33
  38. simba/plotting/geometry_plotter.py +270 -272
  39. simba/plotting/heat_mapper_clf_mp.py +4 -6
  40. simba/plotting/heat_mapper_location_mp.py +2 -2
  41. simba/plotting/light_dark_box_plotter.py +2 -2
  42. simba/plotting/path_plotter_mp.py +26 -29
  43. simba/plotting/plot_clf_results_mp.py +455 -454
  44. simba/plotting/pose_plotter_mp.py +28 -29
  45. simba/plotting/probability_plot_creator_mp.py +288 -288
  46. simba/plotting/roi_plotter_mp.py +31 -31
  47. simba/plotting/single_run_model_validation_video_mp.py +427 -427
  48. simba/plotting/spontaneous_alternation_plotter.py +2 -3
  49. simba/plotting/yolo_pose_track_visualizer.py +32 -27
  50. simba/plotting/yolo_pose_visualizer.py +35 -36
  51. simba/plotting/yolo_seg_visualizer.py +2 -3
  52. simba/pose_importers/simba_blob_importer.py +3 -3
  53. simba/roi_tools/roi_aggregate_stats_mp.py +5 -4
  54. simba/roi_tools/roi_clf_calculator_mp.py +4 -4
  55. simba/sandbox/analyze_runtimes.py +30 -0
  56. simba/sandbox/cuda/egocentric_rotator.py +374 -0
  57. simba/sandbox/get_cpu_pool.py +5 -0
  58. simba/sandbox/proboscis_to_tip.py +28 -0
  59. simba/sandbox/test_directionality.py +47 -0
  60. simba/sandbox/test_nonstatic_directionality.py +27 -0
  61. simba/sandbox/test_pycharm_cuda.py +51 -0
  62. simba/sandbox/test_simba_install.py +41 -0
  63. simba/sandbox/test_static_directionality.py +26 -0
  64. simba/sandbox/test_static_directionality_2d.py +26 -0
  65. simba/sandbox/verify_env.py +42 -0
  66. simba/third_party_label_appenders/transform/coco_keypoints_to_yolo.py +3 -3
  67. simba/third_party_label_appenders/transform/coco_keypoints_to_yolo_bbox.py +2 -2
  68. simba/ui/pop_ups/clf_add_remove_print_pop_up.py +37 -30
  69. simba/ui/pop_ups/clf_plot_pop_up.py +2 -2
  70. simba/ui/pop_ups/egocentric_alignment_pop_up.py +20 -21
  71. simba/ui/pop_ups/fsttc_pop_up.py +27 -25
  72. simba/ui/pop_ups/gantt_pop_up.py +31 -6
  73. simba/ui/pop_ups/interpolate_pop_up.py +2 -4
  74. simba/ui/pop_ups/kleinberg_pop_up.py +39 -40
  75. simba/ui/pop_ups/multiple_videos_to_frames_popup.py +10 -11
  76. simba/ui/pop_ups/single_video_to_frames_popup.py +10 -10
  77. simba/ui/pop_ups/video_processing_pop_up.py +186 -174
  78. simba/ui/tkinter_functions.py +10 -1
  79. simba/utils/custom_feature_extractor.py +1 -1
  80. simba/utils/data.py +90 -14
  81. simba/utils/enums.py +1 -0
  82. simba/utils/errors.py +441 -440
  83. simba/utils/lookups.py +1203 -1203
  84. simba/utils/printing.py +124 -124
  85. simba/utils/read_write.py +3769 -3721
  86. simba/utils/yolo.py +10 -1
  87. simba/video_processors/blob_tracking_executor.py +2 -2
  88. simba/video_processors/clahe_ui.py +66 -23
  89. simba/video_processors/egocentric_video_rotator.py +46 -44
  90. simba/video_processors/multi_cropper.py +1 -1
  91. simba/video_processors/video_processing.py +5264 -5300
  92. simba/video_processors/videos_to_frames.py +43 -32
  93. {simba_uw_tf_dev-4.5.8.dist-info → simba_uw_tf_dev-4.7.1.dist-info}/METADATA +4 -3
  94. {simba_uw_tf_dev-4.5.8.dist-info → simba_uw_tf_dev-4.7.1.dist-info}/RECORD +98 -86
  95. {simba_uw_tf_dev-4.5.8.dist-info → simba_uw_tf_dev-4.7.1.dist-info}/LICENSE +0 -0
  96. {simba_uw_tf_dev-4.5.8.dist-info → simba_uw_tf_dev-4.7.1.dist-info}/WHEEL +0 -0
  97. {simba_uw_tf_dev-4.5.8.dist-info → simba_uw_tf_dev-4.7.1.dist-info}/entry_points.txt +0 -0
  98. {simba_uw_tf_dev-4.5.8.dist-info → simba_uw_tf_dev-4.7.1.dist-info}/top_level.txt +0 -0
@@ -156,6 +156,7 @@ class SimBAScaleBar(Frame):
156
156
  def __init__(self,
157
157
  parent: Union[Frame, Canvas, LabelFrame, Toplevel, Tk],
158
158
  label: Optional[str] = None,
159
+ label_width: Optional[int] = None,
159
160
  orient: Literal['horizontal', 'vertical'] = HORIZONTAL,
160
161
  length: int = 200,
161
162
  value: Optional[int] = 95,
@@ -194,7 +195,7 @@ class SimBAScaleBar(Frame):
194
195
  showvalue=showvalue)
195
196
 
196
197
  if label is not None:
197
- self.lbl = SimBALabel(parent=self, txt=label, font=lbl_font, txt_clr=label_clr)
198
+ self.lbl = SimBALabel(parent=self, txt=label, font=lbl_font, txt_clr=label_clr, width=label_width)
198
199
  self.lbl.grid(row=0, column=1, sticky=SW)
199
200
 
200
201
  self.scale.grid(row=0, column=2, sticky=NW)
@@ -207,6 +208,11 @@ class SimBAScaleBar(Frame):
207
208
  def get_value(self) -> Union[int, float]:
208
209
  return self.scale.get()
209
210
 
211
+ def get(self) -> Union[int, float]:
212
+ ## Alternative for ``get_value`` for legacy reasons.
213
+ return self.scale.get()
214
+
215
+
210
216
 
211
217
 
212
218
  class Entry_Box(Frame):
@@ -223,6 +229,7 @@ class Entry_Box(Frame):
223
229
  value: Optional[Any] = None,
224
230
  label_font: tuple = Formats.FONT_REGULAR.value,
225
231
  entry_font: tuple = Formats.FONT_REGULAR.value,
232
+ tooltip_key: Optional[str] = None,
226
233
  justify: Literal["left", "center", "right"] = 'left',
227
234
  cmd: Optional[Callable] = None,
228
235
  **kw):
@@ -243,6 +250,8 @@ class Entry_Box(Frame):
243
250
  self.filePath = StringVar()
244
251
  self.lblName = Label(self, text=fileDescription, width=labelwidth, anchor=W, font=label_font, bg=label_bg_clr)
245
252
  self.lblName.grid(row=0, column=1)
253
+ if tooltip_key in TOOLTIPS.keys():
254
+ CreateToolTip(widget=self.lblName, text=TOOLTIPS[tooltip_key])
246
255
  if not entry_box_width:
247
256
  self.entPath = Entry(self, textvariable=self.filePath, state=self.status, validate="key", validatecommand=self.validation_methods.get(validation, None), font=entry_font, justify=justify, bg=entry_box_clr)
248
257
  else:
@@ -30,7 +30,7 @@ class CustomFeatureExtractor(ConfigReader):
30
30
  4. Handle cases of multiple classes and missing configuration arguments.
31
31
  5. Invokes the feature extraction process if conditions are met.
32
32
 
33
- .. notes::
33
+ .. note::
34
34
 
35
35
  `Tutorial <https://github.com/sgoldenlab/simba/blob/master/docs/extractFeatures.md>`_.
36
36
 
simba/utils/data.py CHANGED
@@ -5,6 +5,7 @@ import configparser
5
5
  import gc
6
6
  import io
7
7
  import os
8
+ import platform
8
9
  import subprocess
9
10
  from copy import deepcopy
10
11
  from datetime import datetime
@@ -38,15 +39,18 @@ from simba.utils.checks import (check_file_exist_and_readable, check_float,
38
39
  check_if_valid_rgb_tuple, check_instance,
39
40
  check_int, check_str, check_that_column_exist,
40
41
  check_that_hhmmss_start_is_before_end,
41
- check_valid_array, check_valid_cpu_pool,
42
- check_valid_dataframe, check_valid_lst)
43
- from simba.utils.enums import ConfigKey, Dtypes, Formats, Keys, Options
42
+ check_valid_array, check_valid_boolean,
43
+ check_valid_cpu_pool, check_valid_dataframe,
44
+ check_valid_lst)
45
+ from simba.utils.enums import (OS, ConfigKey, Defaults, Dtypes, Formats, Keys,
46
+ Options)
44
47
  from simba.utils.errors import (BodypartColumnNotFoundError, CountError,
45
48
  InvalidFileTypeError, InvalidInputError,
46
49
  NoFilesFoundError, NoROIDataError,
47
50
  SimBAModuleNotFoundError)
48
51
  from simba.utils.printing import stdout_success, stdout_warning
49
- from simba.utils.read_write import (find_video_of_file, get_fn_ext,
52
+ from simba.utils.read_write import (find_core_cnt, find_video_of_file,
53
+ get_current_time, get_fn_ext,
50
54
  get_video_meta_data, read_config_entry,
51
55
  read_config_file, read_df,
52
56
  read_project_path_and_file_type,
@@ -1781,8 +1785,8 @@ def fft_lowpass_filter(data: np.ndarray, cut_off: float = 0.1) -> np.ndarray:
1781
1785
 
1782
1786
  :example:
1783
1787
  >>> from simba.utils.read_write import read_df
1784
- >>> IN_PATH = r"C:\troubleshooting\RAT_NOR\project_folder\csv\outlier_corrected_movement_location\2022-06-20_NOB_DOT_4.csv"
1785
- >>> OUT_PATH = r"C:\troubleshooting\RAT_NOR\project_folder\csv\outlier_corrected_movement_location\2022-06-20_NOB_DOT_4_filtered.csv"
1788
+ >>> IN_PATH = r"C:/troubleshooting/RAT_NOR/project_folder/csv/outlier_corrected_movement_location/2022-06-20_NOB_DOT_4.csv"
1789
+ >>> OUT_PATH = r"C:/troubleshooting/RAT_NOR/project_folder/csv/outlier_corrected_movement_location/2022-06-20_NOB_DOT_4_filtered.csv"
1786
1790
  >>> df = read_df(file_path=IN_PATH)
1787
1791
  >>> data = df.values
1788
1792
  >>> x = fft_lowpass_filter(data=data, cut_off=0.1)
@@ -1813,33 +1817,105 @@ def fft_lowpass_filter(data: np.ndarray, cut_off: float = 0.1) -> np.ndarray:
1813
1817
  return results.astype(data.dtype)
1814
1818
 
1815
1819
 
1816
- def terminate_cpu_pool(pool: Optional[multiprocessing.pool.Pool],
1817
- force: bool = False) -> None:
1820
+ def terminate_cpu_pool(pool: multiprocessing.pool.Pool,
1821
+ force: bool = False,
1822
+ verbose: bool = True,
1823
+ source: Optional[str] = None) -> None:
1818
1824
  """
1819
- Safely terminates a multiprocessing.Pool instance.
1825
+ Safely terminates a multiprocessing.Pool instance with optional graceful shutdown.
1820
1826
 
1821
- :param Optional[multiprocessing.pool.Pool] pool: The pool to terminate. If None, function returns without action.
1822
- :param bool force: If True, skips join() and immediately terminates. Default: False.
1823
- :raises InvalidInputError: If pool is not a valid Pool instance.
1827
+ .. note::
1828
+ If pool is None or invalid, function returns without action. Exceptions during termination are silently caught.
1829
+
1830
+ :param multiprocessing.pool.Pool pool: The multiprocessing pool to terminate. If None, function returns without action.
1831
+ :param bool force: If True, skips graceful shutdown (close/join) and immediately terminates. Default: False.
1832
+ :param bool verbose: If True, prints termination message with timestamp. Default: True.
1833
+ :param Optional[str] source: Optional identifier string for logging purposes (e.g., 'VideoProcessor'). Default: None.
1824
1834
 
1825
1835
  :example:
1826
1836
  >>> import multiprocessing
1827
1837
  >>> pool = multiprocessing.Pool(4)
1828
- >>> terminate_cpu_pool(pool)
1838
+ >>> terminate_cpu_pool(pool=pool, force=False, verbose=True, source='FeatureExtractor')
1829
1839
  """
1830
1840
  if pool is None:
1831
1841
  return
1832
- check_valid_cpu_pool(value=pool, source=terminate_cpu_pool.__name__, raise_error=True)
1842
+ if not check_valid_cpu_pool(value=pool, source=terminate_cpu_pool.__name__, raise_error=False):
1843
+ return
1833
1844
  try:
1845
+ core_cnt = pool._processes if hasattr(pool, '_processes') else None
1834
1846
  if not force:
1835
1847
  pool.close()
1836
1848
  pool.join()
1837
1849
  pool.terminate()
1850
+ if verbose: print(f'[{get_current_time()}] {"" if source is None else f"{core_cnt} core"} SimBA CPU pool {"" if source is None else source} terminated.')
1838
1851
  except (ValueError, AssertionError, AttributeError):
1839
1852
  pass
1840
1853
  gc.collect()
1841
1854
 
1842
1855
 
1856
+
1857
+ def get_cpu_pool(core_cnt: int = -1,
1858
+ maxtasksperchild: int = Defaults.MAXIMUM_MAX_TASK_PER_CHILD.value,
1859
+ context: Literal['fork', 'spawn', 'forkserver'] = None,
1860
+ verbose: bool = True,
1861
+ source: Optional[str] = None) -> multiprocessing.Pool:
1862
+ """
1863
+ Creates and returns a multiprocessing.Pool instance with platform-appropriate defaults and validation.
1864
+
1865
+ :param int core_cnt: Number of worker processes. -1 uses all available cores. Default: -1.
1866
+ :param int maxtasksperchild: Maximum number of tasks a worker process can complete before being replaced. Default: From Defaults.MAXIMUM_MAX_TASK_PER_CHILD.
1867
+ :param Optional[Literal['fork', 'spawn', 'forkserver']] context: Multiprocessing start method. None uses platform default. Default: None.
1868
+ :param bool verbose: If True, prints pool creation message with timestamp. Default: True.
1869
+ :param Optional[str] source: Optional identifier string for logging purposes (e.g., 'VideoProcessor'). Default: None.
1870
+ :return: Configured multiprocessing.Pool instance.
1871
+ :rtype: multiprocessing.Pool
1872
+
1873
+ :example:
1874
+ >>> pool = get_cpu_pool(core_cnt=4, source='FeatureExtractor')
1875
+ >>> pool = get_cpu_pool(core_cnt=-1, context='spawn', verbose=True)
1876
+ >>> pool = get_cpu_pool(core_cnt=8, maxtasksperchild=100, source='VideoProcessor')
1877
+ """
1878
+
1879
+ check_int(name=f'{get_cpu_pool.__name__} core_cnt', min_value=-1, unaccepted_vals=[0], value=core_cnt, raise_error=True)
1880
+ check_int(name=f'{get_cpu_pool.__name__} maxtasksperchild', min_value=1, value=maxtasksperchild, raise_error=True)
1881
+ check_valid_boolean(value=verbose, source=f'{get_cpu_pool.__name__} verbose', raise_error=True)
1882
+ if source is not None: check_str(name=f'{get_cpu_pool.__name__} source', value=source, raise_error=True, allow_blank=True)
1883
+ current_process = multiprocessing.current_process()
1884
+ if current_process.name != 'MainProcess': core_cnt = 1
1885
+ core_cnt = find_core_cnt()[0] if core_cnt == -1 or core_cnt > find_core_cnt()[0] else core_cnt
1886
+ if verbose: print(f'[{get_current_time()}] {core_cnt} core SimBA CPU pool {"" if source is None else source} started.')
1887
+ if context is not None:
1888
+ check_str(name=f'{get_cpu_pool.__name__} context', value=context, options=('fork', 'spawn', 'forkserver'), raise_error=True)
1889
+ else:
1890
+ existing_method = multiprocessing.get_start_method(allow_none=True)
1891
+ if existing_method is not None:
1892
+ context = existing_method
1893
+ else:
1894
+ system = platform.system()
1895
+ if system == OS.WINDOWS.value: context = OS.SPAWN.value
1896
+ elif system == OS.MAC.value: context = OS.SPAWN.value
1897
+ else: context = OS.FORK.value
1898
+
1899
+ if context is not None:
1900
+ try:
1901
+ ctx = multiprocessing.get_context(context)
1902
+ except ValueError:
1903
+ system = platform.system()
1904
+ if system == OS.WINDOWS.value: fallback_context = OS.SPAWN.value
1905
+ elif system == OS.MAC.value: fallback_context = OS.SPAWN.value
1906
+ else: fallback_context = OS.FORK.value
1907
+ try:
1908
+ ctx = multiprocessing.get_context(fallback_context)
1909
+ except ValueError:
1910
+ pool = multiprocessing.Pool(processes=core_cnt, maxtasksperchild=maxtasksperchild)
1911
+ return pool
1912
+ pool = ctx.Pool(processes=core_cnt, maxtasksperchild=maxtasksperchild)
1913
+ else:
1914
+ pool = multiprocessing.Pool(processes=core_cnt, maxtasksperchild=maxtasksperchild)
1915
+ return pool
1916
+
1917
+
1918
+ #get_cpu_pool()
1843
1919
  # run_user_defined_feature_extraction_class(config_path='/Users/simon/Desktop/envs/troubleshooting/circular_features_zebrafish/project_folder/project_config.ini', file_path='/Users/simon/Desktop/fish_feature_extractor_2023_version_5.py')
1844
1920
 
1845
1921
 
simba/utils/enums.py CHANGED
@@ -127,6 +127,7 @@ class OS(Enum):
127
127
  LINUX = "Linux"
128
128
  MAC = "Darwin"
129
129
  SPAWN = 'spawn'
130
+ FORK = 'fork'
130
131
  PYTHON_VER = str(f"{sys.version_info.major}.{sys.version_info.minor}")
131
132
  try:
132
133
  SIMBA_VERSION = pkg_resources.get_distribution("simba-uw-tf-dev").version