simba-uw-tf-dev 4.6.3__py3-none-any.whl → 4.6.4__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.
@@ -38,5 +38,10 @@
38
38
  "EGOCENTRIC_ANCHOR": "This body-part will be placed in the center of the video",
39
39
  "EGOCENTRIC_DIRECTION_ANCHOR": "This body-part will be placed at N degrees relative to the anchor",
40
40
  "EGOCENTRIC_DIRECTION": "The anchor body-part will always be placed at these degrees relative to the center anchor",
41
- "CORE_COUNT": "Higher core counts speeds up processing but may require more RAM memory"
41
+ "CORE_COUNT": "Higher core counts speeds up processing but may require more RAM memory",
42
+ "KLEINBERG_SIGMA": "Higher values (e.g., 2-3) produce fewer but longer bursts; lower values (e.g., 1.1-1.5) detect more frequent, shorter bursts. Must be > 1.01",
43
+ "KLEINBERG_GAMMA": "Higher values (e.g., 0.5-1.0) reduce total burst count by making downward transitions costly; lower values (e.g., 0.1-0.3) allow more flexible state changes",
44
+ "KLEINBERG_HIERARCHY": "Hierarchy level to extract bursts from (0=lowest, higher=more selective).\n Level 0 captures all bursts; level 1-2 typically filters noise; level 3+ selects only the most prominent, sustained bursts.\nHigher levels yield fewer but more confident detections",
45
+ "KLEINBERG_HIERARCHY_SEARCH": "If True, searches for target hierarchy level within detected burst periods,\n falling back to lower levels if target not found. If False, extracts only bursts at the exact specified hierarchy level.\n Recommended when target hierarchy may be sparse.",
46
+ "KLEINBERG_SAVE_ORIGINALS": "If True, saves the original data in a new sub-directory of \nthe project_folder/csv/machine_results directory"
42
47
  }
@@ -13,10 +13,10 @@ from simba.data_processors.pybursts_calculator import kleinberg_burst_detection
13
13
  from simba.mixins.config_reader import ConfigReader
14
14
  from simba.utils.checks import (check_float, check_if_dir_exists,
15
15
  check_if_filepath_list_is_empty, check_int,
16
- check_that_column_exist, check_valid_lst)
16
+ check_that_column_exist, check_valid_lst, check_valid_boolean)
17
17
  from simba.utils.enums import Paths, TagNames
18
18
  from simba.utils.printing import SimbaTimer, log_event, stdout_success
19
- from simba.utils.read_write import get_fn_ext, read_df, write_df
19
+ from simba.utils.read_write import get_fn_ext, read_df, write_df, get_current_time, find_files_of_filetypes_in_directory, remove_a_folder, copy_files_to_directory
20
20
  from simba.utils.warnings import KleinbergWarning
21
21
 
22
22
 
@@ -38,12 +38,13 @@ class KleinbergCalculator(ConfigReader):
38
38
 
39
39
  :param str config_path: path to SimBA project config file in Configparser format
40
40
  :param List[str] classifier_names: Classifier names to apply Kleinberg smoothing to.
41
- :param float sigma: Burst detection sigma value. Higher sigma values and fewer, longer, behavioural bursts will be recognised. Default: 2.
42
- :param float gamma: Burst detection gamma value. Higher gamma values and fewer behavioural bursts will be recognised. Default: 0.3.
43
- :param int hierarchy: Burst detection hierarchy level. Higher hierarchy values and fewer behavioural bursts will to be recognised. Default: 1.
44
- :param bool hierarchical_search: See `Tutorial <https://github.com/sgoldenlab/simba/blob/master/docs/kleinberg_filter.md#hierarchical-search-example>`_ Default: False.
41
+ :param float sigma: State transition cost for moving to higher burst levels. Higher values (e.g., 2-3) produce fewer but longer bursts; lower values (e.g., 1.1-1.5) detect more frequent, shorter bursts. Must be > 1.01. Default: 2.
42
+ :param float gamma: State transition cost for moving to lower burst levels. Higher values (e.g., 0.5-1.0) reduce total burst count by making downward transitions costly; lower values (e.g., 0.1-0.3) allow more flexible state changes. Must be >= 0. Default: 0.3.
43
+ :param int hierarchy: Hierarchy level to extract bursts from (0=lowest, higher=more selective). Level 0 captures all bursts; level 1-2 typically filters noise; level 3+ selects only the most prominent, sustained bursts. Higher levels yield fewer but more confident detections. Must be >= 0. Default: 1.
44
+ :param bool hierarchical_search: If True, searches for target hierarchy level within detected burst periods, falling back to lower levels if target not found. If False, extracts only bursts at the exact specified hierarchy level. Recommended when target hierarchy may be sparse. Default: False.
45
45
  :param Optional[Union[str, os.PathLike]] input_dir: The directory with files to perform kleinberg smoothing on. If None, defaults to `project_folder/csv/machine_results`
46
46
  :param Optional[Union[str, os.PathLike]] output_dir: Location to save smoothened data in. If None, defaults to `project_folder/csv/machine_results`
47
+ :param Optional[bool] save_originals: If True, saves the original data in sub-directory of the ouput directory.`
47
48
 
48
49
  :example I:
49
50
  >>> kleinberg_calculator = KleinbergCalculator(config_path='MySimBAConfigPath', classifier_names=['Attack'], sigma=2, gamma=0.3, hierarchy=2, hierarchical_search=False)
@@ -68,10 +69,12 @@ class KleinbergCalculator(ConfigReader):
68
69
 
69
70
  def __init__(self,
70
71
  config_path: Union[str, os.PathLike],
71
- classifier_names: List[str],
72
- sigma: Optional[int] = 2,
73
- gamma: Optional[float] = 0.3,
72
+ classifier_names: Optional[List[str]] = None,
73
+ sigma: float = 2,
74
+ gamma: float = 0.3,
74
75
  hierarchy: Optional[int] = 1,
76
+ verbose: bool = True,
77
+ save_originals: bool = True,
75
78
  hierarchical_search: Optional[bool] = False,
76
79
  input_dir: Optional[Union[str, os.PathLike]] = None,
77
80
  output_dir: Optional[Union[str, os.PathLike]] = None):
@@ -81,25 +84,31 @@ class KleinbergCalculator(ConfigReader):
81
84
  check_float(value=sigma, name=f'{self.__class__.__name__} sigma', min_value=1.01)
82
85
  check_float(value=gamma, name=f'{self.__class__.__name__} gamma', min_value=0)
83
86
  check_int(value=hierarchy, name=f'{self.__class__.__name__} hierarchy', min_value=0)
84
- check_valid_lst(data=classifier_names, source=f'{self.__class__.__name__} classifier_names', valid_dtypes=(str,), min_len=1)
87
+ if isinstance(classifier_names, list):
88
+ check_valid_lst(data=classifier_names, source=f'{self.__class__.__name__} classifier_names', valid_dtypes=(str,), min_len=1)
89
+ else:
90
+ classifier_names = deepcopy(self.clf_names)
91
+ check_valid_boolean(value=verbose, source=f'{self.__class__.__name__} verbose', raise_error=True)
92
+ check_valid_boolean(value=save_originals, source=f'{self.__class__.__name__} save_originals', raise_error=True)
85
93
  self.hierarchical_search, sigma, gamma, hierarchy, self.output_dir = (hierarchical_search, float(sigma), float(gamma), int(hierarchy), output_dir)
86
- self.sigma, self.gamma, self.hierarchy, self.clfs = ( float(sigma), float(gamma), float(hierarchy), classifier_names)
94
+ self.sigma, self.gamma, self.hierarchy, self.clfs = ( float(sigma), float(gamma), int(hierarchy), classifier_names)
95
+ self.verbose, self.save_originals = verbose, save_originals
87
96
  if input_dir is None:
88
- self.data_paths, self.output_dir = self.machine_results_paths, self.machine_results_dir
89
- check_if_filepath_list_is_empty(filepaths=self.machine_results_paths, error_msg=f"SIMBA ERROR: No data files found in {self.machine_results_dir}. Cannot perform Kleinberg smoothing")
90
- original_data_files_folder = os.path.join(self.project_path, Paths.MACHINE_RESULTS_DIR.value, f"Pre_Kleinberg_{self.datetime}")
91
- if not os.path.exists(original_data_files_folder):
92
- os.makedirs(original_data_files_folder)
93
- for file_path in self.machine_results_paths:
94
- _, file_name, ext = get_fn_ext(file_path)
95
- shutil.copyfile(file_path, os.path.join(original_data_files_folder, file_name + ext))
97
+ self.input_dir = os.path.join(self.project_path, Paths.MACHINE_RESULTS_DIR.value)
96
98
  else:
97
99
  check_if_dir_exists(in_dir=input_dir)
98
- self.data_paths = glob.glob(input_dir + f"/*.{self.file_type}")
99
- check_if_filepath_list_is_empty(filepaths=self.data_paths, error_msg=f"SIMBA ERROR: No data files found in {input_dir}. Cannot perform Kleinberg smoothing")
100
- if not os.path.isdir(output_dir):
101
- os.makedirs(output_dir)
102
- print(f"Processing Kleinberg burst detection for {len(self.data_paths)} file(s) and {len(classifier_names)} classifier(s)...")
100
+ self.input_dir = deepcopy(input_dir)
101
+ self.data_paths = find_files_of_filetypes_in_directory(directory=self.input_dir, extensions=[f'.{self.file_type}'], sort_alphabetically=True, raise_error=True)
102
+ if output_dir is None:
103
+ self.output_dir = deepcopy(self.input_dir)
104
+ else:
105
+ check_if_dir_exists(in_dir=output_dir)
106
+ self.output_dir = deepcopy(output_dir)
107
+ self.original_data_files_folder = os.path.join(self.output_dir, f"Pre_Kleinberg_{self.datetime}")
108
+ remove_a_folder(folder_dir=self.original_data_files_folder, ignore_errors=True)
109
+ os.makedirs(self.original_data_files_folder)
110
+ copy_files_to_directory(file_paths=self.data_paths, dir=self.original_data_files_folder, verbose=False, integer_save_names=False)
111
+ if self.verbose: print(f"Processing Kleinberg burst detection for {len(self.data_paths)} file(s) and {len(classifier_names)} classifier(s)...")
103
112
 
104
113
  def hierarchical_searcher(self):
105
114
  if (len(self.kleinberg_bouts["Hierarchy"]) == 1) and (int(self.kleinberg_bouts.at[0, "Hierarchy"]) == 0):
@@ -135,7 +144,7 @@ class KleinbergCalculator(ConfigReader):
135
144
  for file_cnt, file_path in enumerate(self.data_paths):
136
145
  _, video_name, _ = get_fn_ext(file_path)
137
146
  video_timer = SimbaTimer(start=True)
138
- print(f"Performing Kleinberg burst detection for video {video_name} (Video {file_cnt+1}/{len(self.data_paths)})...")
147
+ if self.verbose: print(f"[{get_current_time()}] Performing Kleinberg burst detection for video {video_name} (Video {file_cnt+1}/{len(self.data_paths)})...")
139
148
  data_df = read_df(file_path, self.file_type).reset_index(drop=True)
140
149
  video_out_df = deepcopy(data_df)
141
150
  check_that_column_exist(df=data_df, column_name=self.clfs, file_name=video_name)
@@ -150,7 +159,7 @@ class KleinbergCalculator(ConfigReader):
150
159
  self.kleinberg_bouts.insert(loc=0, column="Video", value=video_name)
151
160
  detailed_df_lst.append(self.kleinberg_bouts)
152
161
  if self.hierarchical_search:
153
- print(f"Applying hierarchical search for video {video_name}...")
162
+ if self.verbose: print(f"[{get_current_time()}] Applying hierarchical search for video {video_name}...")
154
163
  self.hierarchical_searcher()
155
164
  else:
156
165
  self.clf_bouts_in_hierarchy = self.kleinberg_bouts[self.kleinberg_bouts["Hierarchy"] == self.hierarchy]
@@ -160,19 +169,38 @@ class KleinbergCalculator(ConfigReader):
160
169
  video_out_df.loc[hierarchy_idx, clf] = 1
161
170
  write_df(video_out_df, self.file_type, save_path)
162
171
  video_timer.stop_timer()
163
- print(f'Kleinberg analysis complete for video {video_name} (saved at {save_path}), elapsed time: {video_timer.elapsed_time_str}s.')
172
+ if self.verbose: print(f'[{get_current_time()}] Kleinberg analysis complete for video {video_name} (saved at {save_path}), elapsed time: {video_timer.elapsed_time_str}s.')
164
173
 
165
174
  self.timer.stop_timer()
175
+ if not self.save_originals:
176
+ remove_a_folder(folder_dir=self.original_data_files_folder, ignore_errors=False)
177
+ else:
178
+ if self.verbose: stdout_success(msg=f"Original, un-smoothened data, saved in {self.original_data_files_folder} directory", elapsed_time=self.timer.elapsed_time_str, source=self.__class__.__name__)
166
179
  if len(detailed_df_lst) > 0:
167
180
  self.detailed_df = pd.concat(detailed_df_lst, axis=0)
168
181
  detailed_save_path = os.path.join(self.logs_path, f"Kleinberg_detailed_log_{self.datetime}.csv")
169
182
  self.detailed_df.to_csv(detailed_save_path)
170
- stdout_success(msg=f"Kleinberg analysis complete. See {detailed_save_path} for details of detected bouts of all classifiers in all hierarchies", elapsed_time=self.timer.elapsed_time_str, source=self.__class__.__name__)
183
+ if self.verbose: stdout_success(msg=f"Kleinberg analysis complete for {len(self.data_paths)} files. Results stored in {self.output_dir} directory. See {detailed_save_path} for details of detected bouts of all classifiers in all hierarchies", elapsed_time=self.timer.elapsed_time_str, source=self.__class__.__name__)
171
184
  else:
172
- print("Kleinberg analysis complete.")
185
+ if self.verbose: print(f"[{get_current_time()}] Kleinberg analysis complete for {len(self.data_paths)} files. Results stored in {self.output_dir} directory.")
173
186
  KleinbergWarning(msg="All behavior bouts removed following kleinberg smoothing", source=self.__class__.__name__)
174
187
 
175
188
 
189
+
190
+
191
+ # test = KleinbergCalculator(config_path=r"C:\troubleshooting\mitra\project_folder\project_config.ini",
192
+ # classifier_names=['straub_tail'],
193
+ # sigma=1.1,
194
+ # gamma=0.1,
195
+ # hierarchy=1,
196
+ # save_originals=False,
197
+ # hierarchical_search=False)
198
+ #
199
+ # test.run()
200
+ #
201
+
202
+
203
+
176
204
  # test = KleinbergCalculator(config_path='/Users/simon/Desktop/envs/simba/troubleshooting/levi/project_folder/project_config.ini',
177
205
  # classifier_names=['No_Seizure_(0)'],
178
206
  # sigma=1.1,
@@ -4,17 +4,18 @@ import warnings
4
4
 
5
5
  warnings.simplefilter(action="ignore", category=FutureWarning)
6
6
  import functools
7
+ import gc
7
8
  import multiprocessing
8
9
  import os
9
10
  import platform
10
- from typing import List, Optional, Union
11
11
  from copy import deepcopy
12
+ from typing import List, Optional, Union
12
13
 
13
- import gc
14
14
  import cv2
15
+ import matplotlib
15
16
  import numpy as np
16
17
  import pandas as pd
17
- import matplotlib
18
+
18
19
  matplotlib.use('Agg')
19
20
 
20
21
  from simba.mixins.config_reader import ConfigReader
@@ -23,13 +24,14 @@ from simba.utils.checks import (
23
24
  check_all_file_names_are_represented_in_video_log,
24
25
  check_file_exist_and_readable, check_int, check_str,
25
26
  check_that_column_exist, check_valid_boolean, check_valid_lst)
26
- from simba.utils.data import (create_color_palette, detect_bouts, terminate_cpu_pool, get_cpu_pool)
27
+ from simba.utils.data import (create_color_palette, detect_bouts, get_cpu_pool,
28
+ terminate_cpu_pool)
27
29
  from simba.utils.enums import Formats, Options
28
30
  from simba.utils.errors import NoSpecifiedOutputError
29
31
  from simba.utils.printing import SimbaTimer, stdout_success
30
32
  from simba.utils.read_write import (concatenate_videos_in_folder,
31
33
  create_directory, find_core_cnt,
32
- get_fn_ext, read_df, get_current_time)
34
+ get_current_time, get_fn_ext, read_df)
33
35
 
34
36
  HEIGHT = "height"
35
37
  WIDTH = "width"
@@ -12,15 +12,19 @@ import pandas as pd
12
12
  from simba.mixins.config_reader import ConfigReader
13
13
  from simba.mixins.geometry_mixin import GeometryMixin
14
14
  from simba.mixins.plotting_mixin import PlottingMixin
15
- from simba.utils.checks import (check_instance, check_int, check_nvidea_gpu_available, check_str, check_that_column_exist, check_valid_boolean)
16
- from simba.utils.data import create_color_palette, terminate_cpu_pool, get_cpu_pool
15
+ from simba.utils.checks import (check_instance, check_int,
16
+ check_nvidea_gpu_available, check_str,
17
+ check_that_column_exist, check_valid_boolean)
18
+ from simba.utils.data import (create_color_palette, get_cpu_pool,
19
+ terminate_cpu_pool)
17
20
  from simba.utils.enums import OS, Formats, Options
18
21
  from simba.utils.errors import CountError, InvalidFilepathError
19
22
  from simba.utils.printing import SimbaTimer, stdout_success
20
23
  from simba.utils.read_write import (concatenate_videos_in_folder,
21
24
  find_core_cnt,
22
25
  find_files_of_filetypes_in_directory,
23
- get_fn_ext, get_video_meta_data, read_df, get_current_time)
26
+ get_current_time, get_fn_ext,
27
+ get_video_meta_data, read_df)
24
28
  from simba.utils.warnings import FrameRangeWarning
25
29
 
26
30
 
@@ -24,15 +24,16 @@ from simba.utils.checks import (check_file_exist_and_readable, check_float,
24
24
  check_valid_boolean, check_valid_lst,
25
25
  check_video_and_data_frm_count_align)
26
26
  from simba.utils.data import (create_color_palettes, detect_bouts,
27
- slice_roi_dict_for_video, terminate_cpu_pool, get_cpu_pool)
27
+ get_cpu_pool, slice_roi_dict_for_video,
28
+ terminate_cpu_pool)
28
29
  from simba.utils.enums import ROI_SETTINGS, Formats, Keys, Paths, TextOptions
29
30
  from simba.utils.errors import (BodypartColumnNotFoundError, DuplicationError,
30
31
  NoFilesFoundError, NoROIDataError,
31
32
  ROICoordinatesNotFoundError)
32
33
  from simba.utils.printing import SimbaTimer, stdout_success
33
34
  from simba.utils.read_write import (concatenate_videos_in_folder,
34
- find_core_cnt, get_video_meta_data,
35
- read_df, get_current_time)
35
+ find_core_cnt, get_current_time,
36
+ get_video_meta_data, read_df)
36
37
  from simba.utils.warnings import (DuplicateNamesWarning, FrameRangeWarning,
37
38
  GPUToolsWarning)
38
39
 
@@ -13,10 +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 terminate_cpu_pool, get_cpu_pool
16
+ from simba.utils.data import get_cpu_pool, terminate_cpu_pool
17
17
  from simba.utils.enums import Defaults, Formats
18
18
  from simba.utils.errors import InvalidFilepathError, NoFilesFoundError
19
- from simba.utils.lookups import get_random_color_palette, intermittent_palette, get_current_time
19
+ from simba.utils.lookups import (get_current_time, get_random_color_palette,
20
+ intermittent_palette)
20
21
  from simba.utils.printing import SimbaTimer, stdout_success
21
22
  from simba.utils.read_write import (concatenate_videos_in_folder,
22
23
  create_directory,
@@ -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, terminate_cpu_pool, get_cpu_pool
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,9 +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, get_current_time)
26
+ get_current_time, get_fn_ext,
27
+ get_video_meta_data, read_frm_of_video,
28
+ recursive_file_search, remove_a_folder)
28
29
 
29
30
  FRAME = 'FRAME'
30
31
  CLASS_ID = 'CLASS_ID'
@@ -7,13 +7,13 @@ from typing import Union
7
7
  from simba.data_processors.kleinberg_calculator import KleinbergCalculator
8
8
  from simba.mixins.config_reader import ConfigReader
9
9
  from simba.mixins.pop_up_mixin import PopUpMixin
10
- from simba.ui.tkinter_functions import (CreateLabelFrameWithIcon, Entry_Box,
11
- SimbaButton, SimBADropDown)
10
+ from simba.ui.tkinter_functions import (CreateLabelFrameWithIcon, Entry_Box, SimbaButton, SimBADropDown, SimBALabel)
12
11
  from simba.utils.checks import check_float, check_int
13
12
  from simba.utils.enums import Formats, Keys, Links
14
13
  from simba.utils.errors import NoChoosenClassifierError, NoDataError
15
- from simba.utils.read_write import str_2_bool
14
+ from simba.utils.read_write import str_2_bool, get_current_time
16
15
 
16
+ INSTRUCTIONS_TXT = 'Results in the project_folder/csv/machine_results folder are overwritten.\n If saving the originals, the original un-smoothened data is saved in a subdirectory of \nthe project_folder/csv/machine_results folder'
17
17
 
18
18
  class KleinbergPopUp(PopUpMixin, ConfigReader):
19
19
  def __init__(self,
@@ -24,61 +24,59 @@ class KleinbergPopUp(PopUpMixin, ConfigReader):
24
24
  raise NoDataError(msg=f'Cannot perform Kleinberg smoothing: No data files found in {self.machine_results_dir} directory', source=self.__class__.__name__)
25
25
  PopUpMixin.__init__(self, title="APPLY KLEINBERG BEHAVIOR CLASSIFICATION SMOOTHING", icon='smooth')
26
26
  kleinberg_settings_frm = CreateLabelFrameWithIcon(parent=self.main_frm, header="KLEINBERG SETTINGS", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.KLEINBERG.value)
27
- self.k_sigma = Entry_Box(kleinberg_settings_frm, fileDescription="SIGMA", img='sigma', value='2', justify='center', labelwidth=35, entry_box_width=35)
28
- self.k_gamma = Entry_Box(kleinberg_settings_frm, fileDescription="GAMMA", img='gamma', value='0.3', justify='center', labelwidth=35, entry_box_width=35)
29
- self.k_hierarchy = Entry_Box(kleinberg_settings_frm, fileDescription="HIERARCHY", value=1, img='hierarchy_2', justify='center', labelwidth=35, entry_box_width=35)
30
- self.h_search_dropdown = SimBADropDown(parent=kleinberg_settings_frm, dropdown_options=['TRUE', 'FALSE'], label="HIERACHICAL SEARCH", value='FALSE', img='hierarchy', label_width=35, dropdown_width=35)
27
+ self.k_sigma = Entry_Box(kleinberg_settings_frm, fileDescription="SIGMA", img='sigma', value='2', justify='center', labelwidth=35, entry_box_width=35, tooltip_key='KLEINBERG_SIGMA')
28
+ self.k_gamma = Entry_Box(kleinberg_settings_frm, fileDescription="GAMMA", img='gamma', value='0.3', justify='center', labelwidth=35, entry_box_width=35, tooltip_key='KLEINBERG_GAMMA')
29
+ self.k_hierarchy = Entry_Box(kleinberg_settings_frm, fileDescription="HIERARCHY", value=1, img='hierarchy_2', justify='center', labelwidth=35, entry_box_width=35, validation='numeric', tooltip_key='KLEINBERG_HIERARCHY')
30
+ self.h_search_dropdown = SimBADropDown(parent=kleinberg_settings_frm, dropdown_options=['TRUE', 'FALSE'], label="HIERARCHICAL SEARCH", value='FALSE', img='hierarchy', label_width=35, dropdown_width=35, tooltip_key='KLEINBERG_HIERARCHY_SEARCH')
31
+ self.save_originals_dropdown = SimBADropDown(parent=kleinberg_settings_frm, dropdown_options=['TRUE', 'FALSE'], label="SAVE ORIGINAL DATA:", value='TRUE', img='save', label_width=35, dropdown_width=35, tooltip_key='KLEINBERG_SAVE_ORIGINALS')
32
+ self.instructions_lbl = SimBALabel(parent=kleinberg_settings_frm, txt=INSTRUCTIONS_TXT, justify='center', txt_clr='blue', font=Formats.FONT_REGULAR_ITALICS.value)
31
33
 
32
34
 
33
- kleinberg_table_frame = LabelFrame(self.main_frm, text="CHOOSE CLASSIFIER(S) FOR KLEINBERG SMOOTHING", font=Formats.FONT_HEADER.value)
35
+ kleinberg_table_frame = CreateLabelFrameWithIcon(parent=self.main_frm, header="CHOOSE CLASSIFIER(S) FOR KLEINBERG SMOOTHING", icon_name=Keys.DOCUMENTATION.value, icon_link=Links.KLEINBERG.value)
34
36
  clf_var_dict, clf_cb_dict = {}, {}
35
37
  for clf_cnt, clf in enumerate(self.clf_names):
36
38
  clf_var_dict[clf] = BooleanVar()
37
39
  clf_cb_dict[clf] = Checkbutton(kleinberg_table_frame, text=clf, font=Formats.FONT_REGULAR.value, variable=clf_var_dict[clf])
38
- clf_cb_dict[clf].grid(row=clf_cnt, sticky=NW)
40
+ clf_cb_dict[clf].grid(row=clf_cnt, column=0, sticky=NW)
39
41
 
40
42
  run_kleinberg_btn = SimbaButton(parent=self.main_frm, txt="APPLY KLEINBERG SMOOTHER", img='rocket', txt_clr="blue", font=Formats.FONT_REGULAR.value, cmd=self.run_kleinberg, cmd_kwargs={'behaviors_dict': lambda: clf_var_dict, 'hierarchical_search': lambda: str_2_bool(self.h_search_dropdown.get_value())})
41
- kleinberg_settings_frm.grid(row=0, sticky=W, padx=10)
42
- self.k_sigma.grid(row=0, sticky=W)
43
- self.k_gamma.grid(row=1, sticky=W)
44
- self.k_hierarchy.grid(row=2, sticky=W)
45
- self.h_search_dropdown.grid(row=3, column=0, sticky=W)
46
- kleinberg_table_frame.grid(row=1, pady=10, padx=10)
47
- run_kleinberg_btn.grid(row=2)
43
+ kleinberg_settings_frm.grid(row=0, sticky=W, pady=(15, 0))
44
+ self.instructions_lbl.grid(row=0, sticky=W)
45
+ self.k_sigma.grid(row=1, sticky=W)
46
+ self.k_gamma.grid(row=2, sticky=W)
47
+ self.k_hierarchy.grid(row=3, sticky=W)
48
+ self.h_search_dropdown.grid(row=4, column=0, sticky=W)
49
+ self.save_originals_dropdown.grid(row=5, column=0, sticky=W)
50
+ kleinberg_table_frame.grid(row=1, column=0, sticky=NW, pady=(15, 0))
51
+ run_kleinberg_btn.grid(row=2, column=0, sticky=NW, pady=(15, 0))
48
52
  self.main_frm.mainloop()
49
53
 
50
54
  def run_kleinberg(self, behaviors_dict: dict, hierarchical_search: bool):
51
55
  targets = []
52
56
  for behaviour, behavior_val in behaviors_dict.items():
53
- if behavior_val.get():
54
- targets.append(behaviour)
57
+ if behavior_val.get(): targets.append(behaviour)
55
58
 
56
59
  if len(targets) == 0:
57
60
  raise NoChoosenClassifierError(source=self.__class__.__name__)
58
61
 
59
- check_int(name="Hierarchy", value=self.k_hierarchy.entry_get)
60
- check_float(name="Sigma", value=self.k_sigma.entry_get)
61
- check_float(name="Gamma", value=self.k_gamma.entry_get)
62
-
63
- try:
64
- print(
65
- "Applying kleinberg hyperparameter Setting: Sigma: {}, Gamma: {}, Hierarchy: {}".format(
66
- str(self.k_sigma.entry_get),
67
- str(self.k_gamma.entry_get),
68
- str(self.k_hierarchy.entry_get),
69
- )
70
- )
71
- except:
72
- print("Please insert accurate values for all hyperparameters.")
73
-
74
- kleinberg_analyzer = KleinbergCalculator(
75
- config_path=self.config_path,
76
- classifier_names=targets,
77
- sigma=self.k_sigma.entry_get,
78
- gamma=self.k_gamma.entry_get,
79
- hierarchy=self.k_hierarchy.entry_get,
80
- hierarchical_search=hierarchical_search,
81
- )
62
+ k_hierarchy = self.k_hierarchy.entry_get
63
+ k_sigma = self.k_sigma.entry_get
64
+ k_gamma = self.k_gamma.entry_get
65
+ save_originals = str_2_bool(self.save_originals_dropdown.get_value())
66
+
67
+ check_int(name="Hierarchy", value=k_hierarchy, min_value=1, allow_negative=False, allow_zero=False, raise_error=True)
68
+ check_float(name="Sigma", value=k_sigma, allow_negative=False, allow_zero=False, raise_error=True)
69
+ check_float(name="Gamma", value=k_gamma, allow_negative=False, allow_zero=False, raise_error=True)
70
+
71
+ print(f"[{get_current_time()}] Applying kleinberg hyperparameter Setting: Sigma: {k_sigma}, Gamma: {k_gamma}, Hierarchy: {k_hierarchy}")
72
+
73
+ kleinberg_analyzer = KleinbergCalculator(config_path=self.config_path,
74
+ classifier_names=targets,
75
+ sigma=float(k_sigma),
76
+ gamma=float(k_gamma),
77
+ hierarchy=int(k_hierarchy),
78
+ hierarchical_search=hierarchical_search,
79
+ save_originals=save_originals)
82
80
  kleinberg_analyzer.run()
83
81
 
84
82
 
@@ -229,6 +229,7 @@ class Entry_Box(Frame):
229
229
  value: Optional[Any] = None,
230
230
  label_font: tuple = Formats.FONT_REGULAR.value,
231
231
  entry_font: tuple = Formats.FONT_REGULAR.value,
232
+ tooltip_key: Optional[str] = None,
232
233
  justify: Literal["left", "center", "right"] = 'left',
233
234
  cmd: Optional[Callable] = None,
234
235
  **kw):
@@ -249,6 +250,8 @@ class Entry_Box(Frame):
249
250
  self.filePath = StringVar()
250
251
  self.lblName = Label(self, text=fileDescription, width=labelwidth, anchor=W, font=label_font, bg=label_bg_clr)
251
252
  self.lblName.grid(row=0, column=1)
253
+ if tooltip_key in TOOLTIPS.keys():
254
+ CreateToolTip(widget=self.lblName, text=TOOLTIPS[tooltip_key])
252
255
  if not entry_box_width:
253
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)
254
257
  else:
simba/utils/printing.py CHANGED
@@ -1,125 +1,124 @@
1
- __author__ = "Simon Nilsson; sronilsson@gmail.com"
2
-
3
- try:
4
- from typing import Literal
5
- except:
6
- from typing_extensions import Literal
7
-
8
-
9
- import logging
10
- import time
11
- from typing import Optional
12
- from datetime import datetime
13
-
14
- from simba.utils.enums import Defaults, TagNames
15
-
16
-
17
- def stdout_success(msg: str, source: Optional[str] = "", elapsed_time: Optional[str] = None) -> None:
18
- """
19
- Helper to parse msg of completed operation to SimBA main interface.
20
-
21
- :param str msg: Message to be parsed.
22
- :param Optional[str] source: Optional string indicating the source method or function of the msg for logging.
23
- :param Optional[str] elapsed_time: Optional string indicating the runtime of the completed operation.
24
- :return None:
25
- """
26
-
27
- log_event(logger_name=f"{source}.{stdout_success.__name__}", log_type=TagNames.COMPLETE.value, msg=msg)
28
- if elapsed_time:
29
- print(f"[{datetime.now().strftime('%H:%M:%S')}] SIMBA COMPLETE: {msg} (elapsed time: {elapsed_time}s) {Defaults.STR_SPLIT_DELIMITER.value}{TagNames.COMPLETE.value}")
30
- else:
31
- print(f"[{datetime.now().strftime('%H:%M:%S')}] SIMBA COMPLETE: {msg} {Defaults.STR_SPLIT_DELIMITER.value}{TagNames.COMPLETE.value}")
32
-
33
-
34
- def stdout_warning(msg: str, elapsed_time: Optional[str] = None) -> None:
35
- """
36
- Helper to parse warning msg to SimBA main interface.
37
-
38
- :param str msg: Message to be parsed.
39
- :param Optional[str] source: Optional string indicating the source method or function of the msg for logging.
40
- :param elapsed_time: Optional string indicating the runtime.
41
- :return None:
42
- """
43
-
44
- if elapsed_time:
45
- print(f"[{datetime.now().strftime('%H:%M:%S')}] SIMBA WARNING: {msg} (elapsed time: {elapsed_time}s) {Defaults.STR_SPLIT_DELIMITER.value}{TagNames.WARNING.value}")
46
- else:
47
- print(f"[{datetime.now().strftime('%H:%M:%S')}] SIMBA WARNING: {msg} {Defaults.STR_SPLIT_DELIMITER.value}{TagNames.WARNING.value}")
48
-
49
-
50
- def stdout_trash(msg: str, source: Optional[str] = "", elapsed_time: Optional[str] = None) -> None:
51
- """
52
- Helper to parse msg of delete operation to SimBA main interface.
53
-
54
- :param str msg: Message to be parsed.
55
- :param Optional[str] source: Optional string indicating the source method or function of the operation for logging.
56
- :param elapsed_time: Optional string indicating the runtime.
57
- :return None:
58
- """
59
-
60
- log_event(logger_name=f"{source}.{stdout_trash.__name__}", log_type=TagNames.TRASH.value, msg=msg)
61
- if elapsed_time:
62
- print(f"[{datetime.now().strftime('%H:%M:%S')}] SIMBA COMPLETE: {msg} (elapsed time: {elapsed_time}s) {Defaults.STR_SPLIT_DELIMITER.value}{TagNames.TRASH.value}")
63
- else:
64
- print(f"[{datetime.now().strftime('%H:%M:%S')}] SIMBA COMPLETE: {msg} {Defaults.STR_SPLIT_DELIMITER.value}{TagNames.TRASH.value}")
65
-
66
-
67
- def stdout_information(msg: str, source: Optional[str] = "", elapsed_time: Optional[str] = None) -> None:
68
- """
69
- Helper to parse information msg to SimBA main interface. E.g., how many monitors and their resolutions which is available.
70
-
71
- :param str msg: Message to be parsed.
72
- :param Optional[str] source: Optional string indicating the source method or function of the operation for logging.
73
- :param elapsed_time: Optional string indicating the runtime.
74
- :return None:
75
- """
76
-
77
- log_event(logger_name=f"{source}.{stdout_trash.__name__}", log_type=TagNames.INFORMATION.value, msg=msg)
78
- if elapsed_time:
79
- print(f"[{datetime.now().strftime('%H:%M:%S')}] SIMBA COMPLETE: {msg} (elapsed time: {elapsed_time}s) {Defaults.STR_SPLIT_DELIMITER.value}{TagNames.INFORMATION.value}")
80
- else:
81
- print(f"[{datetime.now().strftime('%H:%M:%S')}] {msg} {Defaults.STR_SPLIT_DELIMITER.value}{TagNames.INFORMATION.value}")
82
-
83
-
84
- class SimbaTimer(object):
85
- """Timer class for keeping track of start and end-times of calls"""
86
-
87
- def __init__(self, start: bool = False):
88
- if start:
89
- self.start_timer()
90
-
91
- def start_timer(self):
92
- self.timer = time.time()
93
-
94
- def stop_timer(self):
95
- if not hasattr(self, "timer"):
96
- self.elapsed_time = -1
97
- self.elapsed_time_str = "-1"
98
- else:
99
- self.elapsed_time = round(time.time() - self.timer, 4)
100
- self.elapsed_time_str = str(self.elapsed_time)
101
-
102
-
103
- def log_event(logger_name: str, log_type: Literal["CLASS_INIT", "error", "warning"], msg: str):
104
- logger = logging.getLogger(str(logger_name))
105
- if log_type == TagNames.CLASS_INIT.value:
106
- logger.info(f"{TagNames.CLASS_INIT.value}||{msg}")
107
- elif log_type == TagNames.ERROR.value:
108
- logger.error(f"{TagNames.ERROR.value}||{msg}")
109
- elif log_type == TagNames.WARNING.value:
110
- logger.warning(f"{TagNames.WARNING.value}||{msg}")
111
- elif log_type == TagNames.TRASH.value:
112
- logger.info(f"{TagNames.TRASH.value}||{msg}")
113
- elif log_type == TagNames.COMPLETE.value:
114
- logger.info(f"{TagNames.COMPLETE.value}||{msg}")
115
-
116
-
117
- def perform_timing(func):
118
- def decorator(*args, **kwargs):
119
- timer = SimbaTimer(start=True)
120
- results = func(*args, **kwargs, _timer=timer)
121
- timer.stop_timer()
122
- results["timer"] = timer.elapsed_time_str
123
- return results
124
-
125
- return decorator
1
+ __author__ = "Simon Nilsson; sronilsson@gmail.com"
2
+
3
+ try:
4
+ from typing import Literal
5
+ except:
6
+ from typing_extensions import Literal
7
+
8
+ import logging
9
+ import time
10
+ from datetime import datetime
11
+ from typing import Optional
12
+
13
+ from simba.utils.enums import Defaults, TagNames
14
+
15
+
16
+ def stdout_success(msg: str, source: Optional[str] = "", elapsed_time: Optional[str] = None) -> None:
17
+ """
18
+ Helper to parse msg of completed operation to SimBA main interface.
19
+
20
+ :param str msg: Message to be parsed.
21
+ :param Optional[str] source: Optional string indicating the source method or function of the msg for logging.
22
+ :param Optional[str] elapsed_time: Optional string indicating the runtime of the completed operation.
23
+ :return None:
24
+ """
25
+
26
+ log_event(logger_name=f"{source}.{stdout_success.__name__}", log_type=TagNames.COMPLETE.value, msg=msg)
27
+ if elapsed_time:
28
+ print(f"[{datetime.now().strftime('%H:%M:%S')}] SIMBA COMPLETE: {msg} (elapsed time: {elapsed_time}s) {Defaults.STR_SPLIT_DELIMITER.value}{TagNames.COMPLETE.value}")
29
+ else:
30
+ print(f"[{datetime.now().strftime('%H:%M:%S')}] SIMBA COMPLETE: {msg} {Defaults.STR_SPLIT_DELIMITER.value}{TagNames.COMPLETE.value}")
31
+
32
+
33
+ def stdout_warning(msg: str, elapsed_time: Optional[str] = None) -> None:
34
+ """
35
+ Helper to parse warning msg to SimBA main interface.
36
+
37
+ :param str msg: Message to be parsed.
38
+ :param Optional[str] source: Optional string indicating the source method or function of the msg for logging.
39
+ :param elapsed_time: Optional string indicating the runtime.
40
+ :return None:
41
+ """
42
+
43
+ if elapsed_time:
44
+ print(f"[{datetime.now().strftime('%H:%M:%S')}] SIMBA WARNING: {msg} (elapsed time: {elapsed_time}s) {Defaults.STR_SPLIT_DELIMITER.value}{TagNames.WARNING.value}")
45
+ else:
46
+ print(f"[{datetime.now().strftime('%H:%M:%S')}] SIMBA WARNING: {msg} {Defaults.STR_SPLIT_DELIMITER.value}{TagNames.WARNING.value}")
47
+
48
+
49
+ def stdout_trash(msg: str, source: Optional[str] = "", elapsed_time: Optional[str] = None) -> None:
50
+ """
51
+ Helper to parse msg of delete operation to SimBA main interface.
52
+
53
+ :param str msg: Message to be parsed.
54
+ :param Optional[str] source: Optional string indicating the source method or function of the operation for logging.
55
+ :param elapsed_time: Optional string indicating the runtime.
56
+ :return None:
57
+ """
58
+
59
+ log_event(logger_name=f"{source}.{stdout_trash.__name__}", log_type=TagNames.TRASH.value, msg=msg)
60
+ if elapsed_time:
61
+ print(f"[{datetime.now().strftime('%H:%M:%S')}] SIMBA COMPLETE: {msg} (elapsed time: {elapsed_time}s) {Defaults.STR_SPLIT_DELIMITER.value}{TagNames.TRASH.value}")
62
+ else:
63
+ print(f"[{datetime.now().strftime('%H:%M:%S')}] SIMBA COMPLETE: {msg} {Defaults.STR_SPLIT_DELIMITER.value}{TagNames.TRASH.value}")
64
+
65
+
66
+ def stdout_information(msg: str, source: Optional[str] = "", elapsed_time: Optional[str] = None) -> None:
67
+ """
68
+ Helper to parse information msg to SimBA main interface. E.g., how many monitors and their resolutions which is available.
69
+
70
+ :param str msg: Message to be parsed.
71
+ :param Optional[str] source: Optional string indicating the source method or function of the operation for logging.
72
+ :param elapsed_time: Optional string indicating the runtime.
73
+ :return None:
74
+ """
75
+
76
+ log_event(logger_name=f"{source}.{stdout_trash.__name__}", log_type=TagNames.INFORMATION.value, msg=msg)
77
+ if elapsed_time:
78
+ print(f"[{datetime.now().strftime('%H:%M:%S')}] SIMBA COMPLETE: {msg} (elapsed time: {elapsed_time}s) {Defaults.STR_SPLIT_DELIMITER.value}{TagNames.INFORMATION.value}")
79
+ else:
80
+ print(f"[{datetime.now().strftime('%H:%M:%S')}] {msg} {Defaults.STR_SPLIT_DELIMITER.value}{TagNames.INFORMATION.value}")
81
+
82
+
83
+ class SimbaTimer(object):
84
+ """Timer class for keeping track of start and end-times of calls"""
85
+
86
+ def __init__(self, start: bool = False):
87
+ if start:
88
+ self.start_timer()
89
+
90
+ def start_timer(self):
91
+ self.timer = time.time()
92
+
93
+ def stop_timer(self):
94
+ if not hasattr(self, "timer"):
95
+ self.elapsed_time = -1
96
+ self.elapsed_time_str = "-1"
97
+ else:
98
+ self.elapsed_time = round(time.time() - self.timer, 4)
99
+ self.elapsed_time_str = str(self.elapsed_time)
100
+
101
+
102
+ def log_event(logger_name: str, log_type: Literal["CLASS_INIT", "error", "warning"], msg: str):
103
+ logger = logging.getLogger(str(logger_name))
104
+ if log_type == TagNames.CLASS_INIT.value:
105
+ logger.info(f"{TagNames.CLASS_INIT.value}||{msg}")
106
+ elif log_type == TagNames.ERROR.value:
107
+ logger.error(f"{TagNames.ERROR.value}||{msg}")
108
+ elif log_type == TagNames.WARNING.value:
109
+ logger.warning(f"{TagNames.WARNING.value}||{msg}")
110
+ elif log_type == TagNames.TRASH.value:
111
+ logger.info(f"{TagNames.TRASH.value}||{msg}")
112
+ elif log_type == TagNames.COMPLETE.value:
113
+ logger.info(f"{TagNames.COMPLETE.value}||{msg}")
114
+
115
+
116
+ def perform_timing(func):
117
+ def decorator(*args, **kwargs):
118
+ timer = SimbaTimer(start=True)
119
+ results = func(*args, **kwargs, _timer=timer)
120
+ timer.stop_timer()
121
+ results["timer"] = timer.elapsed_time_str
122
+ return results
123
+
124
+ return decorator
simba/utils/read_write.py CHANGED
@@ -560,7 +560,11 @@ def get_video_info_ffmpeg(video_path: Union[str, os.PathLike]) -> Dict[str, Any]
560
560
 
561
561
  def remove_a_folder(folder_dir: Union[str, os.PathLike], ignore_errors: Optional[bool] = True) -> None:
562
562
  """Helper to remove a directory"""
563
- check_if_dir_exists(in_dir=folder_dir, source=remove_a_folder.__name__)
563
+ valid_dir = check_if_dir_exists(in_dir=folder_dir, source=remove_a_folder.__name__, raise_error=False)
564
+ if not valid_dir and not ignore_errors:
565
+ raise NotDirectoryError(msg=f'Cannot delete directory {folder_dir}: The directory does not exist', source=remove_a_folder.__name__)
566
+ if not valid_dir and ignore_errors:
567
+ return
564
568
  try:
565
569
  shutil.rmtree(folder_dir, ignore_errors=ignore_errors)
566
570
  except Exception as e:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: simba-uw-tf-dev
3
- Version: 4.6.3
3
+ Version: 4.6.4
4
4
  Summary: Toolkit for computer classification and analysis of behaviors in experimental animals
5
5
  Home-page: https://github.com/sgoldenlab/simba
6
6
  Author: Simon Nilsson, Jia Jie Choong, Sophia Hwang
@@ -458,7 +458,7 @@ simba/assets/lookups/critical_values_05.pickle,sha256=bYlqp9T6ehVIjIJr3Uwfulj-kS
458
458
  simba/assets/lookups/feature_extraction_headers.csv,sha256=I5TLfAihpHgzUZ7OUyGge-Yu-XGbQmHbDFAD4vVAc4w,2987
459
459
  simba/assets/lookups/features.csv,sha256=bc6aN2ZRa2J2dxur-Zjcpc4I3q6vd-gN2erwnhdzLIk,14175
460
460
  simba/assets/lookups/model_names.parquet,sha256=hOuvYONO8wZGcAwRNSf_hS_lUaynC8Gt24MLOg3w5ZA,270783
461
- simba/assets/lookups/tooptips.json,sha256=cQUtBr5-Mpy4CqFV7kV-JjLhzMZHhJWWaXZWCyac4GU,5097
461
+ simba/assets/lookups/tooptips.json,sha256=uPFy_Ew53vTtejvup5DsmvEyfZkUeaUyGeDxXrM0crU,6156
462
462
  simba/assets/lookups/unsupervised_example_x.csv,sha256=bc6aN2ZRa2J2dxur-Zjcpc4I3q6vd-gN2erwnhdzLIk,14175
463
463
  simba/assets/lookups/yolo.yaml,sha256=3Omt-t-w555E4oAJsRRblBjzyiTW9e5x-0VuyQ-t9C0,278
464
464
  simba/assets/lookups/yolo_schematics/yolo_1.csv,sha256=TzUzWAtia4P-5FRwLPnjU0zDSkAA-nItNFCcq6nG_iQ,72
@@ -532,7 +532,7 @@ simba/data_processors/gibbs_sampler.py,sha256=Lj3lJJ0LWYLoeMRU2oniTHJSRpdG8oMIEN
532
532
  simba/data_processors/interpolate.py,sha256=GaLvrqS-iVB9TA0eEsCO3dnUCxVD_0KwWqWYZsRlyOM,8006
533
533
  simba/data_processors/interpolate_pose.py,sha256=RME5CxN-oJTiRab4iMQLMRmc7rmdsvXz490wyguDT3Q,7139
534
534
  simba/data_processors/interpolation_smoothing.py,sha256=aeN4klghvxXUDV8yu_tiXVUAV4Bxu_y0jmNGnpJe6vw,39132
535
- simba/data_processors/kleinberg_calculator.py,sha256=vWcyBB3MA99tdI1n2CXN_6a7CDInLyhIUnTraVhMIFM,12401
535
+ simba/data_processors/kleinberg_calculator.py,sha256=bgTK4V83QrB9DC2rxF0YH1nwU7rF4wVvJ1WQtXA_cxU,14592
536
536
  simba/data_processors/light_dark_box_analyzer.py,sha256=FaXBkuAzI2YZToBvswCTjv1epYK6SiysQTepIQ_-qPc,9514
537
537
  simba/data_processors/movement_calculator.py,sha256=tqDzgMIH23iz_U6ABqva2VpG2Yu8GV1__DK6I6-rd7Y,12393
538
538
  simba/data_processors/mutual_exclusivity_corrector.py,sha256=XuLk8gd2oXAunpP3yJTIcfeoWofpO1iv2EFY6QcEEU8,8729
@@ -675,7 +675,7 @@ simba/plotting/distance_plotter_mp.py,sha256=7tbp63Jn9JGkox0fCaqeunE3027pEl0xI7u
675
675
  simba/plotting/ez_path_plot.py,sha256=OSQSniIKdr55iO5-BMqmrgnEOfLIjxq0-ojrJn1y7lE,10350
676
676
  simba/plotting/frame_mergerer_ffmpeg.py,sha256=AqfUQ_Lx83VfOZbz89qa1tM1WK8ETNhNITPTjnTqqeY,8485
677
677
  simba/plotting/gantt_creator.py,sha256=mbTonMIbhdHHGh9e4zzaLljp2haoKWxgwfWwZ2IVh0s,11297
678
- simba/plotting/gantt_creator_mp.py,sha256=wjM-NL-UCGXnl5E3Pc-RcQW4ek2pHge8ShzJCaLdgrA,16635
678
+ simba/plotting/gantt_creator_mp.py,sha256=a5ZBWaV0pl-PcgtePBC4mZR9v6NU8WQ2waD3xBomy5k,16668
679
679
  simba/plotting/gantt_plotly.py,sha256=s727fBblZnMksHvJpmbb4_G_Eq8J3bMhlNzyL1xap_M,8406
680
680
  simba/plotting/geometry_plotter.py,sha256=Jsl_695-ZWcba9_c3MiXq6S8MufWsKUcaGbCv9HYSoo,15499
681
681
  simba/plotting/heat_mapper_clf.py,sha256=rYFWuBS3v8v14EnXhaKKzPml4lJzkPBP5FJ8RxdnKik,10675
@@ -689,18 +689,18 @@ simba/plotting/path_plotter_mp.py,sha256=1N0uR-EoSyKHvppSJNfRhLcTKKWKko_UNKRtO9r
689
689
  simba/plotting/plot_clf_results.py,sha256=MLm_S42RPvVIeng7KyrAa9z0aS5PGFSV4Pm9VCy3M18,22895
690
690
  simba/plotting/plot_clf_results_mp.py,sha256=46qiq9k5dD8wZBRfvCYThkYiPnvmeCEKZy2XEp2N3h4,32340
691
691
  simba/plotting/pose_plotter.py,sha256=aH48s-loMOy7Lyor3Z0hF6q8tgXeGBg-Mm_0ICONz2I,9145
692
- simba/plotting/pose_plotter_mp.py,sha256=VcWp6hP-z1tUYH0sGyIg04YzSTDH3uYLPbqeT7Dr4Xk,13667
692
+ simba/plotting/pose_plotter_mp.py,sha256=RB-KEWuOLL4D0CGj5teqAFEWC01joqY6B_8WLSNzvuo,13803
693
693
  simba/plotting/probability_plot_creator.py,sha256=8BHYtCtPXungLxzI0ZkCKUoDhuYBJsGefsChzHwrDLI,11878
694
694
  simba/plotting/probability_plot_creator_mp.py,sha256=GVa_vaVTeBIBYHycg2UF1G4rOPvZe3BfJPl4cSdWkTs,17380
695
695
  simba/plotting/roi_plotter.py,sha256=ApMdsfeCm5iFbiCZWn7eUfpfXTTzXmcEB_j3nCbod6o,25693
696
- simba/plotting/roi_plotter_mp.py,sha256=xQTGa1niRqkU4EwPc6aFmYuZVmdux3gkxULDi14bOBc,32856
696
+ simba/plotting/roi_plotter_mp.py,sha256=vFSDqFjGvqMkG7SbkFJdjDLsNS1TtOVcz5hzYHT5_Tg,32887
697
697
  simba/plotting/sam_plotter.py,sha256=XAQuFv-GJkTOno-PeEemUaz0CL83QH1SygJ6Cf1UsgI,6507
698
698
  simba/plotting/shap_agg_stats_visualizer.py,sha256=_SqN6vi60JvjTnr2FpxfDdAnGHwuad_ad4TxKQ6tRBY,15614
699
699
  simba/plotting/single_run_model_validation_video.py,sha256=75tP0f6UFK-ZpGDWxqLfaWlLrDybkBlEBoN_eKuRTBg,25973
700
700
  simba/plotting/single_run_model_validation_video_mp.py,sha256=Mzheon7Mqn_tG11mGcGO_HxHTE_VbMOBmTW1B3pDp_8,27507
701
701
  simba/plotting/spontaneous_alternation_plotter.py,sha256=HIgUEMhPCLq7qNXowbFp0bgCPLTvvwf8_DwlOiuWqA8,13117
702
- simba/plotting/yolo_pose_track_visualizer.py,sha256=uNQIHOPY-mEqgWY6ufkloedZGIgRCB9vyueG2bErVBc,17328
703
- simba/plotting/yolo_pose_visualizer.py,sha256=_iYELRtBNs6xJze-fyORdoqvdTtswtTvWYVZCX5sDMs,25510
702
+ simba/plotting/yolo_pose_track_visualizer.py,sha256=N01gWdKFD87eHQs20qvgs65CsqjiwyN3Et2qiP_wU2s,17364
703
+ simba/plotting/yolo_pose_visualizer.py,sha256=1K-LpyI40M_5GJ40akL7necAkX56o3AmWN2JeNdeHfU,25543
704
704
  simba/plotting/yolo_seg_visualizer.py,sha256=JoGvmESNgqJI9nxId-GVt1mIGoF12Jx3seclz6lxmnA,9221
705
705
  simba/plotting/yolo_visualize.py,sha256=6HqMzkboENti6vKrjAzOm19YBrkLFZVbH3SLy-xgBNw,6043
706
706
  simba/plotting/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1355,7 +1355,7 @@ simba/ui/import_videos_frame.py,sha256=i0LnQzPLFne9dA_nvpVWAHYGmi0aTRXpiHzEog_-R
1355
1355
  simba/ui/machine_model_settings_ui.py,sha256=hTfpBxtfYGH9Rsf3JdQ5Sc8z874tYAoZefvjF1JD6gA,38292
1356
1356
  simba/ui/ml_settings_frm.py,sha256=f1-E6pEGjWJVF3I6n0azO9zAnsskpZjInViguHIDntw,3101
1357
1357
  simba/ui/px_to_mm_ui.py,sha256=ETedZPFkloU0l3JeGnhiSIAsGBQzzv0YrDWtiVGOmJ4,9387
1358
- simba/ui/tkinter_functions.py,sha256=p880LwVcmnJgtA9Ya_iQdTBsP7p3dVLfF-zCQ7VnHnM,41222
1358
+ simba/ui/tkinter_functions.py,sha256=u5QXx6iwlRj3UAsuwg2pC567l4-8IXX0cKppWRCT8P0,41392
1359
1359
  simba/ui/user_defined_pose_creator.py,sha256=QAfdp8r225DONLaCgQJe6kXiZZLj20VQCLJEnCvZsKs,9249
1360
1360
  simba/ui/video_info_ui.py,sha256=ld_fN-3vCYJDFv1t9i5B-VVtoaBCspDmiDUIfOSJb_8,17262
1361
1361
  simba/ui/pop_ups/.DS_Store,sha256=4PUcfpTZzBMd8yz2YahGab5mqPUVIpvdxzjvQ2MmsBY,6148
@@ -1407,7 +1407,7 @@ simba/ui/pop_ups/helpers.py,sha256=wjxintf8wqKfm8SqfDDLVqDGlwKkWbXVtF-e5HwauVs,6
1407
1407
  simba/ui/pop_ups/import_roi_csv_popup.py,sha256=k2kL1ZonBe9J70oUligTGFaSwIW0C8OmdNBr4SjilmA,4795
1408
1408
  simba/ui/pop_ups/initialize_blob_tracking_pop_up.py,sha256=8D0SV2pkkNyzTxi9h5h1rcF4ndRLiwe8pQ7EkZTemG0,2400
1409
1409
  simba/ui/pop_ups/interpolate_pop_up.py,sha256=fz360nYiX6YyFDY3VK7quMyx4w_gzVtygaXVc3xey9g,6284
1410
- simba/ui/pop_ups/kleinberg_pop_up.py,sha256=r_QL1t5IYnH5cVsoVUWtISOFbXKX020g1twUmgtTRVc,4860
1410
+ simba/ui/pop_ups/kleinberg_pop_up.py,sha256=aMTWc5OevqKmkpB09NtS3Yxr8R3pNKeFMtLiT1w1PeQ,6196
1411
1411
  simba/ui/pop_ups/labelme_bbox_to_yolo_bbox_popup.py,sha256=iL3g7V5f_Cg_m_D-QA3yPHLRpjMo9vXCPIBwvU4iKn0,3681
1412
1412
  simba/ui/pop_ups/labelme_dir_to_csv_popup.py,sha256=zsObRf09LWCg0X2Wwi7bvfhQT5bXYvfkmUvlIS6k8rM,3611
1413
1413
  simba/ui/pop_ups/labelme_to_df_popup.py,sha256=KE93Dvc-6X44CxnvRFAL5dFkv_i_HC7gwbtaXSZLFhw,4293
@@ -1500,8 +1500,8 @@ simba/utils/data.py,sha256=Zc3BrVGddEgZkm7yvVaBMot8HBz12d_nhHaXhrWB0UM,100827
1500
1500
  simba/utils/enums.py,sha256=ZR2175N06ZHZNiHk8n757T-WGyt1-55LLpcg3Sbb91k,38668
1501
1501
  simba/utils/errors.py,sha256=GeEF9K_9EWHQqZP-ptTM8ABmb9o0SCnec52t0Qw5Tno,18237
1502
1502
  simba/utils/lookups.py,sha256=MTzHIHJpiOtFSTVNQCGMyfY_ItEaurc69QrtCQIfRh8,48918
1503
- simba/utils/printing.py,sha256=L13f5prOnuswDqa4XttEBoQ3y3wNLm0W_ZvyxYQTbYw,5230
1504
- simba/utils/read_write.py,sha256=lKLG-MEgXRtN7NWaLlOa356rUFgdNrWbgtUHrISPa_w,187302
1503
+ simba/utils/printing.py,sha256=2s-uESy1knuPiniqQ-q277uQ2teYM4OHo9Y4L20JQWM,5353
1504
+ simba/utils/read_write.py,sha256=2786DQVZ88EpYPglLlvDZr9Q_kt-ILcMaJ1zV9hTfIw,187576
1505
1505
  simba/utils/warnings.py,sha256=K7w1RiDL4Un7rGaabOVCGc9fHcaKxk66iZyNLS_AtOE,8121
1506
1506
  simba/utils/yolo.py,sha256=4RTC1JYnZ7WgaWmf70cZATbUtjRQfJ1HyhJhglpAEcs,18482
1507
1507
  simba/utils/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1524,9 +1524,9 @@ simba/video_processors/roi_selector_circle.py,sha256=SD_lv6V3MGiIQd0VtUFSKe83ySW
1524
1524
  simba/video_processors/roi_selector_polygon.py,sha256=DMtilt__gGwNu6VV73CWbnPqrPBXkan1_akUqGEzfGw,6742
1525
1525
  simba/video_processors/video_processing.py,sha256=ho9bz1rjl1eEomA4yfndIc46xtnvdgFNv5JJSX28n7w,311986
1526
1526
  simba/video_processors/videos_to_frames.py,sha256=WqAjEa5enrrkKqwDkL8HhFlbgt1Sf67k2zeCQhVKryM,7323
1527
- simba_uw_tf_dev-4.6.3.dist-info/LICENSE,sha256=Sjn362upcvYFypam-b-ziOXU1Wl5GGuTt5ICrGimzyA,1720
1528
- simba_uw_tf_dev-4.6.3.dist-info/METADATA,sha256=PHM_iOtDP2yiUr1qmqFxpmnqxbV1oVWM3D3ukGU7LwE,11375
1529
- simba_uw_tf_dev-4.6.3.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
1530
- simba_uw_tf_dev-4.6.3.dist-info/entry_points.txt,sha256=Nfh_EbfDGdKftLjCnGWtQrBHENiDYMdgupwLyLpU5dc,44
1531
- simba_uw_tf_dev-4.6.3.dist-info/top_level.txt,sha256=ogtimvlqDxDTOBAPfT2WaQ2pGAAbKRXG8z8eUTzf6TU,14
1532
- simba_uw_tf_dev-4.6.3.dist-info/RECORD,,
1527
+ simba_uw_tf_dev-4.6.4.dist-info/LICENSE,sha256=Sjn362upcvYFypam-b-ziOXU1Wl5GGuTt5ICrGimzyA,1720
1528
+ simba_uw_tf_dev-4.6.4.dist-info/METADATA,sha256=r3UPwczfEURMUuMeXr0Gmk10MY5Hf35_Rx61KgLcVAQ,11375
1529
+ simba_uw_tf_dev-4.6.4.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
1530
+ simba_uw_tf_dev-4.6.4.dist-info/entry_points.txt,sha256=Nfh_EbfDGdKftLjCnGWtQrBHENiDYMdgupwLyLpU5dc,44
1531
+ simba_uw_tf_dev-4.6.4.dist-info/top_level.txt,sha256=ogtimvlqDxDTOBAPfT2WaQ2pGAAbKRXG8z8eUTzf6TU,14
1532
+ simba_uw_tf_dev-4.6.4.dist-info/RECORD,,