Source code for simba.plotting.path_plotter_mp

__author__ = "Simon Nilsson; sronilsson@gmail.com"

import functools
import os
import warnings
from copy import deepcopy
from typing import Any, Dict, List, Optional, Union

warnings.filterwarnings("ignore", message=".*global colormaps dictionary.*")
import cv2
import numpy as np

from simba.mixins.config_reader import ConfigReader
from simba.mixins.plotting_mixin import PlottingMixin
from simba.utils.checks import (
    check_all_file_names_are_represented_in_video_log,
    check_file_exist_and_readable, check_if_keys_exist_in_dict,
    check_if_string_value_is_valid_video_timestamp, check_if_valid_rgb_tuple,
    check_instance, check_str, check_that_column_exist,
    check_that_hhmmss_start_is_before_end, check_valid_boolean,
    check_valid_dataframe, check_valid_lst,
    check_video_and_data_frm_count_align)
from simba.utils.data import (create_color_palette,
                              find_frame_numbers_from_time_stamp, get_cpu_pool,
                              slice_roi_dict_for_video, terminate_cpu_pool)
from simba.utils.enums import Formats, Options, TagNames
from simba.utils.errors import (FrameRangeError, InvalidInputError,
                                InvalidVideoFileError, NoSpecifiedOutputError)
from simba.utils.printing import (SimbaTimer, log_event, stdout_information,
                                  stdout_success)
from simba.utils.read_write import (concatenate_videos_in_folder,
                                    create_directory, find_core_cnt,
                                    find_video_of_file, get_current_time,
                                    get_fn_ext, read_df, read_frm_of_video)
from simba.utils.warnings import ROIWarning

STYLE_WIDTH = "width"
STYLE_HEIGHT = "height"
STYLE_LINE_WIDTH = "line width"
STYLE_FONT_SIZE = "font size"
STYLE_FONT_THICKNESS = "font thickness"
STYLE_CIRCLE_SIZE = "circle size"
STYLE_MAX_LINES = "max lines"
STYLE_BG = 'bg'
STYLE_BG_OPACITY = 'bg_opacity'
COLOR = 'color'
SIZE = 'size'
START_TIME = 'start_time'
END_TIME = 'end_time'
BODY_PART = 'body_part'
AUTO = 'AUTO'
ANIMAL_NAME = 'animal_name'

STYLE_KEYS = [
    STYLE_WIDTH,
    STYLE_HEIGHT,
    STYLE_LINE_WIDTH,
    STYLE_FONT_SIZE,
    STYLE_FONT_THICKNESS,
    STYLE_CIRCLE_SIZE,
    STYLE_MAX_LINES,
    STYLE_BG,
    STYLE_BG_OPACITY
]

[docs]def path_plot_mp(data: np.ndarray, line_data: np.array, colors: list, video_setting: bool, frame_setting: bool, video_save_dir: str, video_name: str, frame_folder_dir: str, style_attr: dict, roi: Union[dict, None], animal_names: Union[None, List[str]], fps: Union[int, float], clf_attr: dict, verbose: bool): batch_id, frm_cnt_rng, frm_id_rng = data[0], data[1], data[2] if video_setting: video_save_path = os.path.join(video_save_dir, f"{batch_id}.mp4") FOURCC = cv2.VideoWriter_fourcc(*Formats.MP4_CODEC.value) video_writer = cv2.VideoWriter(video_save_path, FOURCC, int(fps), (style_attr[STYLE_WIDTH], style_attr[STYLE_HEIGHT])) for frm_cnt, frm_id in zip(frm_cnt_rng, frm_id_rng): if isinstance(style_attr[STYLE_BG], str): bg = read_frm_of_video(video_path=style_attr[STYLE_BG], opacity=style_attr[STYLE_BG_OPACITY], frame_index=frm_id) else: bg = deepcopy(style_attr[STYLE_BG]) plot_arrs = [x[:frm_cnt, :] for x in line_data] # make_path_plot expects list of lists of (R,G,B) tuples; normalize in case colors are lists from create_color_palette plot_clrs = [[tuple(e) for e in x[:frm_cnt]] for x in colors] clf_attr_cpy = deepcopy(clf_attr) if clf_attr is not None: for k, v in clf_attr.items(): clf_attr_cpy[k]["clfs"][frm_id + 1 :] = 0 img = PlottingMixin.make_path_plot(data=plot_arrs, colors=plot_clrs, width=style_attr[STYLE_WIDTH], height=style_attr[STYLE_HEIGHT], max_lines=style_attr[STYLE_MAX_LINES], bg_clr=bg, circle_size=style_attr[STYLE_CIRCLE_SIZE], font_size=style_attr[STYLE_FONT_SIZE], font_thickness=style_attr[STYLE_FONT_THICKNESS], line_width=style_attr[STYLE_LINE_WIDTH], animal_names=animal_names, clf_attr=clf_attr_cpy, save_path=None) if roi is not None: img = PlottingMixin.roi_dict_onto_img(img=img, roi_dict=roi, show_tags=False, show_center=False) if video_setting: video_writer.write(np.uint8(img)) if frame_setting: frm_name = os.path.join(frame_folder_dir, f"{frm_id}.png") cv2.imwrite(frm_name, np.uint8(img)) if verbose: print(f"Path frame created: {frm_id}, Video: {video_name}, Processing core: {batch_id}") if video_setting: video_writer.release() return batch_id
[docs]class PathPlotterMulticore(ConfigReader, PlottingMixin): """ Class for creating "path plots" videos and/or images detailing the movement paths of individual animals in SimBA. Uses multiprocessing. :param str config_path: Path to SimBA project config file in Configparser format :param bool frame_setting: If True, individual frames will be created. :param bool video_setting: If True, compressed videos will be created. :param bool last_frame: If True, png of the last frame will be created. :param List[str] files_found: Data paths to create path plots for (e.g., ['project_folder/csv/machine_results/MyVideo.csv']) :param dict animal_attr: Animal body-parts to use when creating paths and their colors. :param Optional[dict] input_style_attr: Plot sttributes (line thickness, color, etc..). If None, then autocomputed. Max lines will be set to 2s. :param Optional[dict] input_clf_attr: Dict reprenting classified behavior locations, their color and size. If None, then no classified behavior locations are shown. :param Optional[dict] slicing: If Dict, start time and end time of video slice to create path plot from. E.g., {'start_time': '00:00:01', 'end_time': '00:00:03'}. If None, creates path plot for entire video. :param Optional[bool] roi: If True, also plots the ROIs associated with the video. Default False. :param int cores: Number of cores to use. .. note:: `Visualization tutorials <https://github.com/sgoldenlab/simba/blob/master/docs/tutorial.md#step-11-visualizations>`__. .. image:: _static/img/path_plot.png :alt: Path plot :width: 300 :align: center .. video:: _static/img/path_plot_mp.webm :width: 500 :autoplay: :loop: :muted: :align: center .. image:: _static/img/path_plot_1.png :alt: Path plot 1 :width: 500 :align: center :example: >>> input_style_attr = {'width': 'As input', 'height': 'As input', 'line width': 5, 'font size': 5, 'font thickness': 2, 'circle size': 5, 'bg color': 'White', 'max lines': 100} >>> animal_attr = {0: ['Ear_right_1', 'Red']} >>> input_clf_attr = {0: ['Attack', 'Black', 'Size: 30'], 1: ['Sniffing', 'Red', 'Size: 30']} >>> path_plotter = PathPlotterMulticore(config_path=r'MyConfigPath', frame_setting=False, video_setting=True, style_attr=style_attr, animal_attr=animal_attr, files_found=['project_folder/csv/machine_results/MyVideo.csv'], cores=5, clf_attr=clf_attr, print_animal_names=True) >>> path_plotter.run() References ---------- .. [1] Battivelli, Dorian, Lucas Boldrini, Mohit Jaiswal, Pradnya Patil, Sofia Torchia, Elizabeth Engelen, Luca Spagnoletti, Sarah Kaspar, and Cornelius T. Gross. β€œInduction of Territorial Dominance and Subordination Behaviors in Laboratory Mice.” Scientific Reports 14, no. 1 (November 19, 2024): 28655. https://doi.org/10.1038/s41598-024-75545-4. """ def __init__(self, config_path: Union[str, os.PathLike], data_paths: List[Union[str, os.PathLike]], animal_attr: dict, style_attr: Optional[Union[Dict[str, Any], None]] = None, clf_attr: Optional[dict] = None, frame_setting: bool = False, video_setting: bool = False, last_frame: bool = False, print_animal_names: bool = True, slicing: Optional[Dict] = None, core_cnt: int = -1, roi: bool = False, verbose: bool = True): log_event(logger_name=str(__class__.__name__), log_type=TagNames.CLASS_INIT.value, msg=self.create_log_msg_from_init_args(locals=locals())) if (not frame_setting) and (not video_setting) and (not last_frame): raise NoSpecifiedOutputError(msg="SIMBA ERROR: Please choice to create path frames and/or video path plots", source=self.__class__.__name__) check_valid_lst(data=data_paths, source=self.__class__.__name__, valid_dtypes=(str,), min_len=1) _ = [check_file_exist_and_readable(x) for x in data_paths] check_file_exist_and_readable(file_path=config_path) if style_attr is not None: check_if_keys_exist_in_dict(data=style_attr, key=STYLE_KEYS, name=f'{self.__class__.__name__} style_attr') check_valid_boolean(value=[frame_setting, video_setting, last_frame,print_animal_names, roi], source=self.__class__.__name__) if slicing is not None: check_if_keys_exist_in_dict(data=slicing, key=[START_TIME, END_TIME], name=f'{self.__class__.__name__} slicing') check_if_string_value_is_valid_video_timestamp(value=slicing[START_TIME], name="Video slicing START TIME") check_if_string_value_is_valid_video_timestamp(value=slicing[END_TIME], name="Video slicing END TIME") check_that_hhmmss_start_is_before_end(start_time=slicing[START_TIME], end_time=slicing[END_TIME], name="SLICE TIME STAMPS") ConfigReader.__init__(self, config_path=config_path) PlottingMixin.__init__(self) if roi: check_file_exist_and_readable(file_path=self.roi_coordinates_path) self.read_roi_data() if not video_setting and not frame_setting and not last_frame: raise NoSpecifiedOutputError(msg='Video, last frame, and frame are all False', source=self.__class__.__name__) self.clf_names = None if clf_attr is not None: check_instance(source=f'{self.__class__.__name__} clf_attr', instance=clf_attr, accepted_types=(dict,)) for k, v in clf_attr.items(): check_if_keys_exist_in_dict(data=v, key=[COLOR, SIZE], name=f'{self.__class__.__name__} clf_attr') self.clf_names = list(clf_attr.keys()) self.fourcc = cv2.VideoWriter_fourcc(*Formats.MP4_CODEC.value) if not os.path.exists(self.path_plot_dir): os.makedirs(self.path_plot_dir) self.video_setting, self.frame_setting, self.style_attr, self.data_paths, self.animal_attr, self.clf_attr, self.last_frame, self.roi = video_setting, frame_setting, style_attr, data_paths, animal_attr, clf_attr, last_frame, roi self.print_animal_names, self.slicing, self.verbose = print_animal_names, slicing, verbose self.bp_data, self.data_cols, self.animal_names, self.colors = self.__get_bp_data() self.animal_names = None if not self.print_animal_names else self.animal_names self.core_cnt = find_core_cnt()[0] if core_cnt == -1 or core_cnt > find_core_cnt()[0] else core_cnt def __get_bp_data(self): bp_data, data_cols, animal_names, colors = {}, [], [], [], for cnt, (k, v) in enumerate(self.animal_attr.items()): check_if_keys_exist_in_dict(data=v, key=[COLOR, BODY_PART], name=f'{self.__class__.__name__} animal_attr') check_str(name=f'{self.__class__.__name__} animal {k} body_part', value=v[BODY_PART], options=self.body_parts_lst) name = self.find_animal_name_from_body_part_name(bp_name=v[BODY_PART], bp_dict=self.animal_bp_dict) if check_if_valid_rgb_tuple(data=v[COLOR], raise_error=False, source=f'{self.__class__.__name__} animal_attr {cnt}'): colors.append(v[COLOR]) elif v[COLOR] in Options.PALETTE_OPTIONS.value: colors.append(v[COLOR]) else: raise InvalidInputError(msg=f'The color {v[COLOR]} for animal {cnt} ({name}) is not a valid color palette or valid rgb color tuple.', source=self.__class__.__name__) bp_data[cnt] = {ANIMAL_NAME: name, 'x': f'{v[BODY_PART]}_x', 'y': f'{v[BODY_PART]}_y', 'p': f'{v[BODY_PART]}_p', COLOR: v[COLOR]} data_cols.extend([f'{v[BODY_PART]}_x', f'{v[BODY_PART]}_y']) animal_names.append(name) return bp_data, data_cols, animal_names, colors def __get_styles(self, style_attr): video_styles = {} res_w = int(self.video_info["Resolution_width"].iloc[0]) res_h = int(self.video_info["Resolution_height"].iloc[0]) optimal_font_size, _, _ = PlottingMixin().get_optimal_font_scales(text='MY LONG TEXT STRING', accepted_px_width=int(res_w / 10), accepted_px_height=int(res_w / 10)) optimal_circle_size = PlottingMixin().get_optimal_circle_size(frame_size=(res_w, res_h), circle_frame_ratio=100) video_styles[STYLE_WIDTH] = res_w if style_attr[STYLE_WIDTH] == None else int(style_attr[STYLE_WIDTH]) video_styles[STYLE_HEIGHT] = res_h if style_attr[STYLE_HEIGHT] == None else int(style_attr[STYLE_HEIGHT]) video_styles[STYLE_CIRCLE_SIZE] = optimal_circle_size if style_attr[STYLE_CIRCLE_SIZE] == None else int(style_attr[STYLE_CIRCLE_SIZE]) video_styles[STYLE_LINE_WIDTH] = 2 if style_attr[STYLE_LINE_WIDTH] == None else int(style_attr[STYLE_LINE_WIDTH]) video_styles[STYLE_FONT_THICKNESS] = 2 if style_attr[STYLE_FONT_THICKNESS] == None else int(style_attr[STYLE_FONT_THICKNESS]) video_styles[STYLE_FONT_SIZE] = optimal_font_size if style_attr[STYLE_FONT_SIZE] == None else int(style_attr[STYLE_FONT_SIZE]) video_styles[STYLE_MAX_LINES] = len(self.data_df) if style_attr[STYLE_MAX_LINES] == None else int(self.fps * int(style_attr[STYLE_MAX_LINES])) video_styles[STYLE_BG_OPACITY] = None if style_attr[STYLE_BG_OPACITY] == None else float(style_attr[STYLE_BG_OPACITY]) if isinstance(self.style_attr[STYLE_BG], tuple): video_styles[STYLE_BG] = self.style_attr[STYLE_BG] if isinstance(self.style_attr[STYLE_BG], (str, int)): video_path = find_video_of_file(video_dir=self.video_dir, filename=self.video_name, raise_error=False, warning=True) if video_path is None: raise InvalidVideoFileError(msg=f'Could not find video in expected location. If using frame or video as background, make sure the data file {self.video_name} is represented in the {self.video_dir} directory', source=self.__class__.__name__) if isinstance(self.style_attr[STYLE_BG], (int,)): video_styles[STYLE_BG] = read_frm_of_video(video_path=video_path, frame_index=self.style_attr[STYLE_BG], opacity=video_styles[STYLE_BG_OPACITY]) else: if self.slicing is None: check_video_and_data_frm_count_align(video=video_path, data=self.data_df, name=self.video_name, raise_error=False) video_styles[STYLE_BG] = video_path return video_styles
[docs] def run(self): check_all_file_names_are_represented_in_video_log(video_info_df=self.video_info_df, data_paths=self.data_paths) stdout_information(msg=f"Processing path plots for {len(self.data_paths)} video(s)...") if self.video_setting or self.frame_setting: self.pool = get_cpu_pool(core_cnt=self.core_cnt, source=self.__class__.__name__, ) else: self.pool = None for file_cnt, file_path in enumerate(self.data_paths): video_timer = SimbaTimer(start=True) _, self.video_name, _ = get_fn_ext(file_path) self.video_info, _, self.fps = self.read_video_info(video_name=self.video_name) self.in_df = read_df(file_path, self.file_type) check_valid_dataframe(df=self.in_df, source=file_path, valid_dtypes=Formats.NUMERIC_DTYPES.value, required_fields=self.data_cols) if self.clf_attr is not None: check_valid_dataframe(df=self.in_df, source=file_path, valid_dtypes=Formats.NUMERIC_DTYPES.value, required_fields=self.clf_names) self.save_frm_dir = None if self.slicing: frm_numbers = find_frame_numbers_from_time_stamp(start_time=self.slicing[START_TIME], end_time=self.slicing[END_TIME], fps=self.fps) if len(set(frm_numbers) - set(self.in_df.index)) > 0: raise FrameRangeError(msg=f'The chosen time-period ({self.slicing[START_TIME]} - {self.slicing[END_TIME]}) does not exist in {self.video_name}.', source=self.__class__.__name__) self.in_df = self.in_df.loc[frm_numbers] else: frm_numbers = list(range(0, len(self.in_df))) self.data_df = self.in_df[self.data_cols] video_styles = self.__get_styles(self.style_attr) if self.video_setting: self.video_save_path = os.path.join(self.path_plot_dir, f"{self.video_name}.mp4") self.video_temp_dir = os.path.join(self.path_plot_dir, self.video_name) create_directory(paths=self.video_temp_dir, overwrite=True) if self.frame_setting: self.save_frm_dir = os.path.join(self.path_plot_dir, self.video_name) create_directory(paths=self.save_frm_dir, overwrite=True) video_rois, video_roi_names = None, None if self.roi: video_rois, video_roi_names = slice_roi_dict_for_video(data=self.roi_dict, video_name=self.video_name) if len(video_roi_names) == 0: ROIWarning(msg=f'NO ROI data found for video {self.video_name}. Skipping ROI plotting for this video.') if self.clf_attr is not None: clf_attr = {} for k, v in self.clf_attr.items(): check_that_column_exist(df=self.in_df, column_name=k, file_name=file_path) clf_attr[k] = {COLOR: v[COLOR], SIZE: v[SIZE], 'clfs': self.in_df[k].values.astype(np.int8), 'positions': self.data_df[[self.bp_data[0]['x'], self.bp_data[0]['y']]].values} else: clf_attr = None line_data = [] for k, v in self.bp_data.items(): data = self.data_df[[v['x'], v['y']]] bad_cols = (data.isna().any() | data.isin([np.inf, -np.inf]).any() | (data < 0).any()) bad_cols = bad_cols[bad_cols].index.tolist() if len (bad_cols) > 0: raise InvalidInputError(msg=f'The columns {v} contains None, NaN, infinity, and/or negative values in file {file_path}', source=self.__class__.__name__) line_data.append(self.data_df[[v['x'], v['y']]].values.astype(np.int32)) if self.last_frame: last_frame_save_path = os.path.join(self.path_plot_dir, f"{self.video_name}_final_frame.png") if isinstance(video_styles[STYLE_BG], str): bg = read_frm_of_video(video_path=video_styles[STYLE_BG], opacity=video_styles[STYLE_BG_OPACITY], frame_index=len(self.data_df)-1) else: bg = deepcopy(video_styles[STYLE_BG]) last_frm = PlottingMixin.make_path_plot(data=line_data, colors=self.colors, width=video_styles[STYLE_WIDTH], height=video_styles[STYLE_HEIGHT], max_lines=video_styles[STYLE_MAX_LINES], bg_clr=bg, circle_size=video_styles[STYLE_CIRCLE_SIZE], font_size=video_styles[STYLE_FONT_SIZE], font_thickness=video_styles[STYLE_FONT_THICKNESS], line_width=video_styles[STYLE_LINE_WIDTH], animal_names=self.animal_names, clf_attr=clf_attr, save_path=None) if video_rois is not None: last_frm = PlottingMixin.roi_dict_onto_img(img=last_frm, roi_dict=video_rois, show_tags=False, show_center=False) cv2.imwrite(filename=last_frame_save_path, img=last_frm) stdout_success(msg=f'Last path plot frame saved at {last_frame_save_path}') if self.video_setting or self.frame_setting: frm_cnt_range = np.arange(1, line_data[0].shape[0]) frm_cnt_range = np.array_split(frm_cnt_range, self.core_cnt) frm_id_range = np.array_split(frm_numbers, self.core_cnt) frm_range = [(cnt, x, y) for cnt, (x, y) in enumerate(zip(frm_cnt_range, frm_id_range))] plot_clrs = [] for cnt, color in enumerate(self.colors): if check_if_valid_rgb_tuple(data=color, raise_error=False): plot_clrs.append([color] * line_data[cnt].shape[0]) elif color in Options.PALETTE_OPTIONS.value: plot_clrs.append(create_color_palette(pallete_name=color, increments=line_data[cnt].shape[0], as_int=True)) stdout_information(msg=f"Creating path plots, multiprocessing (chunksize: {self.multiprocess_chunksize}, cores: {self.core_cnt})...") constants = functools.partial(path_plot_mp, line_data=line_data, colors=plot_clrs, video_setting=self.video_setting, video_name=self.video_name, frame_setting=self.frame_setting, video_save_dir=self.video_temp_dir, frame_folder_dir=self.save_frm_dir, style_attr=video_styles, clf_attr=clf_attr, animal_names=self.animal_names, fps=self.fps, roi=video_rois, verbose=self.verbose) for cnt, result in enumerate(self.pool.imap(constants, frm_range, chunksize=self.multiprocess_chunksize)): print(f"[{get_current_time()}] Path batch {result+1}/{self.core_cnt} complete...") if self.video_setting: stdout_information(msg=f"Joining {self.video_name} multi-processed video...", source=self.__class__.__name__) concatenate_videos_in_folder(in_folder=self.video_temp_dir, save_path=self.video_save_path, remove_splits=True) video_timer.stop_timer() stdout_information(msg=f'Path plot video {self.video_name} complete...', source=self.__class__.__name__, elapsed_time=video_timer.elapsed_time_str) self.timer.stop_timer() if self.pool is not None: terminate_cpu_pool(pool=self.pool, force=False, source=self.__class__.__name__) stdout_success(msg=f"Path plot visualizations for {len(self.data_paths)} video(s) created in {self.path_plot_dir} directory", elapsed_time=self.timer.elapsed_time_str, source=self.__class__.__name__)
# # # if __name__ == "__main__": # style_attr = {STYLE_WIDTH: None, # STYLE_HEIGHT: None, # STYLE_LINE_WIDTH: 3, # STYLE_FONT_SIZE: 5, # STYLE_FONT_THICKNESS: 2, # STYLE_CIRCLE_SIZE: 5, # STYLE_BG: (255, 255, 255), # STYLE_BG_OPACITY: 100, # STYLE_MAX_LINES: None} # # animal_attr = {0: {'body_part': 'center', 'color': 'jet'}} # clf_attr = None # test = PathPlotterMulticore(config_path=r"E:\troubleshooting\mitra_emergence_hour\project_folder\project_config.ini", # frame_setting=False, # video_setting=True, # last_frame=False, # slicing=None,#{'start_time': '00:00:00', 'end_time': '00:00:05'},#{'start_time': '00:00:00', 'end_time': '00:00:05'}, #{'start_time': '00:00:00', 'end_time': '00:00:50'}, #{'start_time': '00:00:00', 'end_time': '00:00:01'},, #{'start_time': '00:00:00', 'end_time': '00:00:01'}, #{'start_time': '00:00:00', 'end_time': '00:00:01'}, # style_attr=style_attr, # animal_attr=animal_attr, # clf_attr=clf_attr, # print_animal_names=False, # core_cnt=10, # roi=False, # data_paths=[r"E:\troubleshooting\mitra_emergence_hour\project_folder\csv\outlier_corrected_movement_location\Box2_180mISOeme_Males.csv"]) # test.run() # if __name__ == "__main__": # style_attr = {STYLE_WIDTH: None, # STYLE_HEIGHT: None, # STYLE_LINE_WIDTH: 2, # STYLE_FONT_SIZE: 5, # STYLE_FONT_THICKNESS: 1, # STYLE_CIRCLE_SIZE: 5, # STYLE_BG: (255, 255, 255), # STYLE_BG_OPACITY: 100, # STYLE_MAX_LINES: None} # # animal_attr = {0: {'body_part': 'center', 'color': 'coolwarm'}} #, 1: {'body_part': 'Center', 'color': (0, 0, 255)}} #['Ear_right_1', 'Red'], 1: ['Ear_right_2', 'Green']} # clf_attr = None # test = PathPlotterMulticore(config_path=r"F:\troubleshooting\sam\sam\project_folder\project_config.ini", # frame_setting=False, # video_setting=False, # last_frame=True, # slicing=None,#{'start_time': '00:00:00', 'end_time': '00:00:05'},#{'start_time': '00:00:00', 'end_time': '00:00:05'}, #{'start_time': '00:00:00', 'end_time': '00:00:50'}, #{'start_time': '00:00:00', 'end_time': '00:00:01'},, #{'start_time': '00:00:00', 'end_time': '00:00:01'}, #{'start_time': '00:00:00', 'end_time': '00:00:01'}, # style_attr=style_attr, # animal_attr=animal_attr, # clf_attr=clf_attr, # print_animal_names=False, # core_cnt=10, # roi=False, # data_paths=[r"F:\troubleshooting\sam\sam\project_folder\csv\outlier_corrected_movement_location\20251204_171113_751_cam1_CROPPED.csv"]) # test.run() # # animal_attr = {0: {'bp': 'Ear_right', 'color': (255, 0, 0)}, 1: {'bp': 'Tail_base', 'color': (0, 0, 255)}} #['Ear_right_1', 'Red'], 1: ['Ear_right_2', 'Green']} # style_attr = {'width': 'As input', # 'height': 'As input', # 'line width': 2, # 'font size': 0.9, # 'font thickness': 2, # 'circle size': 5, # 'bg color': {'type': 'moving', 'opacity': 50, 'frame_index': 200}, #{'type': 'static', 'opacity': 100, 'frame_index': 200} # 'max lines': 'entire video'} # clf_attr = {'Nose to Nose': {'color': (155, 1, 10), 'size': 30}, 'Nose to Tailbase': {'color': (155, 90, 10), 'size': 30}} # clf_attr=None # # path_plotter = PathPlotterMulticore(config_path='/Users/simon/Desktop/envs/simba/troubleshooting/RAT_NOR/project_folder/project_config.ini', # frame_setting=False, # video_setting=True, # last_frame=True, # clf_attr=clf_attr, # input_style_attr=None, # animal_attr=animal_attr, # roi=True, # files_found=['/Users/simon/Desktop/envs/simba/troubleshooting/RAT_NOR/project_folder/csv/outlier_corrected_movement_location/2022-06-20_NOB_DOT_4.csv'], # cores=-1, # slicing = {'start_time': '00:00:00', 'end_time': '00:00:05'}, # {'start_time': '00:00:00', 'end_time': '00:00:05'}, # , #None, # print_animal_names=False) # path_plotter.run() # style_attr = {'width': 'As input', # 'height': 'As input', # 'line width': 5, 'font size': 5, 'font thickness': 2, 'circle size': 5, 'bg color': {'type': 'static', 'opacity': 100, 'frame_index': 100}, 'max lines': 'entire video'} # animal_attr = {0: ['Ear_right_1', 'Red'], 1: ['Ear_right_2', 'Green']} # # clf_attr = {0: ['Attack', 'Black', 'Size: 30']} # # # # # clf_attr = None # style_attr = None # # path_plotter = PathPlotterMulticore(config_path='/Users/simon/Desktop/envs/troubleshooting/two_black_animals_14bp/project_folder/project_config.ini', # frame_setting=False, # video_setting=True, # last_frame=True, # input_clf_attr=clf_attr, # input_style_attr=style_attr, # animal_attr=animal_attr, # files_found=['/Users/simon/Desktop/envs/troubleshooting/two_black_animals_14bp/project_folder/csv/machine_results/Together_1.csv'], # cores=5, # slicing = None) # path_plotter.run() # # # # #style_attr = None # style_attr = {'width': None, # 'height': None, # 'line width': 5, # 'font size': 5, # 'font thickness': 2, # 'circle size': 5, # 'bg': (0, 0, 0), # 'bg_opacity': 0, # 'max lines': None} # animal_attr = {0: {'color': (255, 0, 0), 'body_part': 'Nose'}} # #clf_attr = {0: ['Freezing', 'Black', 'Size: 10'], 1: ['Normal Swimming', 'Red', 'Size: 10']} # # # # clf_attr = None # # #if __name__ == "__main__": # path_plotter = PathPlotterMulticore(config_path=r"D:\troubleshooting\path_plotx\project_folder\project_config.ini", # frame_setting=False, # video_setting=False, # last_frame=True, # clf_attr=None, # style_attr=style_attr, # animal_attr=animal_attr, # print_animal_names=False, # data_paths=[r"D:\troubleshooting\path_plotx\project_folder\csv\outlier_corrected_movement_location\Hyb_P2_VMHvl-Syn_B11_C2_B.csv"], # core_cnt=8, # verbose=True) # path_plotter.run()