From 420abcb0201456bfb7976777984333ecced48769 Mon Sep 17 00:00:00 2001 From: Ben Lansdell Date: Fri, 2 Feb 2024 14:53:50 -0700 Subject: [PATCH] ruff formatter fixes (#12) --- ethome/config.py | 2 +- ethome/features/cnn1d.py | 31 +++++------ ethome/features/dl_features.py | 52 +++++++++--------- ethome/features/features.py | 8 ++- ethome/features/generic_features.py | 24 ++++++-- ethome/features/mars_features.py | 85 ++++++++++++++++++++++------- ethome/interpolation.py | 2 +- ethome/io.py | 14 ++--- ethome/models.py | 16 +++--- ethome/plot.py | 4 +- ethome/unsupervised.py | 4 +- ethome/video.py | 60 +++++++++++--------- pyproject.toml | 79 +++++++++++++++++++++++++++ 13 files changed, 264 insertions(+), 117 deletions(-) diff --git a/ethome/config.py b/ethome/config.py index 1ce64ab..b9865b3 100644 --- a/ethome/config.py +++ b/ethome/config.py @@ -2,7 +2,7 @@ # TODO # Add support for the user to change these. - + global_config = { "make_movie__y_offset": 60, "make_movie__y_inc": 30, diff --git a/ethome/features/cnn1d.py b/ethome/features/cnn1d.py index 117d9ff..e8c5dd6 100644 --- a/ethome/features/cnn1d.py +++ b/ethome/features/cnn1d.py @@ -8,12 +8,12 @@ def build_baseline_model( input_dim: tuple, - layer_channels: tuple =(512, 256), - dropout_rate: float =0.0, - learning_rate: float =1e-3, - conv_size: int =5, - num_classes: int=4, - class_weight:tuple = None, + layer_channels: tuple = (512, 256), + dropout_rate: float = 0.0, + learning_rate: float = 1e-3, + conv_size: int = 5, + num_classes: int = 4, + class_weight: tuple = None, ): if not check_keras(): raise RuntimeError( @@ -49,7 +49,7 @@ def add_conv_bn_activate(model, out_dim, activation="relu", conv_size=3, drop=0. return model -def make_df(pts, colnames: List[str] =None): # pragma: no cover +def make_df(pts, colnames: List[str] = None): # pragma: no cover df = [] for idx in range(len(pts)): data = pts[idx].flatten() @@ -61,7 +61,6 @@ def make_df(pts, colnames: List[str] =None): # pragma: no cover def features_identity(inputs: np.ndarray): # pragma: no cover - return inputs, inputs.shape[1:] @@ -149,14 +148,14 @@ def __init__( dim: tuple, use_conv: bool, num_classes: int, - augment: bool =False, - class_to_number: dict =None, - past_frames:int=0, - future_frames:int=0, - frame_gap:int=1, - shuffle:bool=False, - mode:str="fit", - featurize:Callable=features_identity, + augment: bool = False, + class_to_number: dict = None, + past_frames: int = 0, + future_frames: int = 0, + frame_gap: int = 1, + shuffle: bool = False, + mode: str = "fit", + featurize: Callable = features_identity, ): self.batch_size = batch_size self.featurize = featurize diff --git a/ethome/features/dl_features.py b/ethome/features/dl_features.py index 4f03711..c12c868 100644 --- a/ethome/features/dl_features.py +++ b/ethome/features/dl_features.py @@ -56,7 +56,7 @@ } -def seed_everything(seed:int=2012): +def seed_everything(seed: int = 2012): np.random.seed(seed) os.environ["PYTHONHASHSEED"] = str(seed) @@ -72,17 +72,17 @@ def __init__( *, feature_dim: list, num_classes: int, - test_data:np.ndarray=None, - class_to_number:dict=None, - past_frames:int=0, - future_frames:int=0, - frame_gap:int=1, - use_conv:bool=False, - build_model:Callable=build_baseline_model, + test_data: np.ndarray = None, + class_to_number: dict = None, + past_frames: int = 0, + future_frames: int = 0, + frame_gap: int = 1, + use_conv: bool = False, + build_model: Callable = build_baseline_model, Generator=MABe_Generator, - use_callbacks:bool=False, - learning_decay_freq:int=10, - featurizer:Callable=features_identity, + use_callbacks: bool = False, + learning_decay_freq: int = 10, + featurizer: Callable = features_identity, ): flat_dim = np.prod(feature_dim) if use_conv: @@ -130,7 +130,9 @@ def _set_model(self, model): """Set an external, provide initialized and compiled keras model""" self.model = model - def inference(self, model_params: dict, class_weight:dict=None, n_folds:int=5): + def inference( + self, model_params: dict, class_weight: dict = None, n_folds: int = 5 + ): kwargs = {} if class_weight is not None: if type(class_weight) is dict: @@ -188,7 +190,7 @@ def get_test_prediction_probabilities(self): return all_test_preds -def normalize_data(orig_pose_dictionary:dict): +def normalize_data(orig_pose_dictionary: dict): for key in orig_pose_dictionary: X = orig_pose_dictionary[key]["keypoints"] X = X.transpose((0, 1, 3, 2)) # last axis is x, y coordinates @@ -200,16 +202,16 @@ def normalize_data(orig_pose_dictionary:dict): def run_task( - vocabulary:dict, - test_data:np.ndarray, - config_name:str, - build_model:Callable, - skip_test_prediction:bool=False, - seed:int=2021, + vocabulary: dict, + test_data: np.ndarray, + config_name: str, + build_model: Callable, + skip_test_prediction: bool = False, + seed: int = 2021, Generator=MABe_Generator, - use_callbacks:bool=False, - params:dict=None, - use_conv:bool=True, + use_callbacks: bool = False, + params: dict = None, + use_conv: bool = True, ): if params is None: if config_name is None: @@ -279,13 +281,13 @@ def run_task( return all_test_probs -def lrs(epoch:int, lr:float, freq:int=10): +def lrs(epoch: int, lr: float, freq: int = 10): if (epoch % freq) == 0 and epoch > 0: lr /= 3 return lr -def convert_to_mars_format(df:pd.DataFrame, colnames:List[str], animal_setup:dict): +def convert_to_mars_format(df: pd.DataFrame, colnames: List[str], animal_setup: dict): n_animals = len(animal_setup["mouse_ids"]) n_body_parts = len(animal_setup["bodypart_ids"]) pose_dict = {} @@ -301,7 +303,7 @@ def convert_to_mars_format(df:pd.DataFrame, colnames:List[str], animal_setup:dic # Basically, undo the change above -def convert_to_pandas_df(data, colnames:List[str]=None): +def convert_to_pandas_df(data, colnames: List[str] = None): dfs = [] for vid in data: df = pd.DataFrame(data[vid], columns=colnames) diff --git a/ethome/features/features.py b/ethome/features/features.py index c264395..c97f817 100644 --- a/ethome/features/features.py +++ b/ethome/features/features.py @@ -59,7 +59,9 @@ def transform(self, df: pd.DataFrame): raise NotImplementedError -def feature_class_maker(name:str, compute_function:Callable, required_columns:List[str]=[]): +def feature_class_maker( + name: str, compute_function: Callable, required_columns: List[str] = [] +): def __init__(self, required_columns=None, **kwargs): """Feature creation object. This houses the feature creation function and the columns that are required to compute the features. Performs some checks on data to make sure has these columns. @@ -72,10 +74,10 @@ def __init__(self, required_columns=None, **kwargs): self.required_columns = required_columns self.kwargs = kwargs - def fit(self, edf:pd.DataFrame, **kwargs): # pragma: no cover + def fit(self, edf: pd.DataFrame, **kwargs): # pragma: no cover return - def transform(self, edf:pd.DataFrame, **kwargs): + def transform(self, edf: pd.DataFrame, **kwargs): """Make the features. This is called internally by the dataset object when running `add_features`. Args: diff --git a/ethome/features/generic_features.py b/ethome/features/generic_features.py index 2be630e..5b2fc6d 100644 --- a/ethome/features/generic_features.py +++ b/ethome/features/generic_features.py @@ -4,7 +4,7 @@ import numpy as np -def _diff_within_group(df, sort_key: str, diff_col:str, **kwargs): +def _diff_within_group(df, sort_key: str, diff_col: str, **kwargs): return df.groupby(sort_key)[diff_col].transform(lambda x: x.diff(**kwargs).bfill()) @@ -45,7 +45,7 @@ def compute_centerofmass_interanimal_distances( def compute_centerofmass_interanimal_speed( - df: pd.DataFrame, raw_col_names: list, n_shifts:int=5, **kwargs + df: pd.DataFrame, raw_col_names: list, n_shifts: int = 5, **kwargs ) -> pd.DataFrame: """Speeds between all animals' centroids""" animal_setup = df.pose.animal_setup @@ -123,7 +123,11 @@ def compute_centerofmass( def compute_centerofmass_velocity( - df: pd.DataFrame, raw_col_names: list, n_shifts:int=5, bodyparts: list = [], **kwargs + df: pd.DataFrame, + raw_col_names: list, + n_shifts: int = 5, + bodyparts: list = [], + **kwargs, ) -> pd.DataFrame: """Velocity of all animals' centroids""" animal_setup = df.pose.animal_setup @@ -161,7 +165,11 @@ def compute_centerofmass_velocity( def compute_part_velocity( - df: pd.DataFrame, raw_col_names: list, n_shifts:int=5, bodyparts: list = [], **kwargs + df: pd.DataFrame, + raw_col_names: list, + n_shifts: int = 5, + bodyparts: list = [], + **kwargs, ) -> pd.DataFrame: """Velocity of all animals' bodyparts""" animal_setup = df.pose.animal_setup @@ -198,7 +206,11 @@ def compute_part_velocity( def compute_part_speed( - df: pd.DataFrame, raw_col_names: list, n_shifts:int=5, bodyparts: list = [], **kwargs + df: pd.DataFrame, + raw_col_names: list, + n_shifts: int = 5, + bodyparts: list = [], + **kwargs, ) -> pd.DataFrame: """Speed of all animals' bodyparts""" animal_setup = df.pose.animal_setup @@ -235,7 +247,7 @@ def compute_part_speed( def compute_speed_features( - df: pd.DataFrame, raw_col_names: list, n_shifts:int=5, **kwargs + df: pd.DataFrame, raw_col_names: list, n_shifts: int = 5, **kwargs ) -> pd.DataFrame: """Speeds between all body parts pairs (within and between animals)""" animal_setup = df.pose.animal_setup diff --git a/ethome/features/mars_features.py b/ethome/features/mars_features.py index 99e895d..dc9c900 100644 --- a/ethome/features/mars_features.py +++ b/ethome/features/mars_features.py @@ -13,9 +13,9 @@ # The decorator maker, so we can provide arguments -def augment_features(window_size:int=5, n_shifts:int=3, mode:str="shift"): +def augment_features(window_size: int = 5, n_shifts: int = 3, mode: str = "shift"): # The decorator - def decorator(feature_function:Callable): + def decorator(feature_function: Callable): # What is called instead of the actual function, assumes the feature making # function returns the names of the columns just made def wrapper(*args, **kwargs): @@ -37,7 +37,10 @@ def wrapper(*args, **kwargs): window_sizes = [1, 5, 10] for ws in window_sizes: data = np.dstack( - [np.array(df[added_cols].shift(p).bfill()) for p in range(-ws, ws + 1)] + [ + np.array(df[added_cols].shift(p).bfill()) + for p in range(-ws, ws + 1) + ] ) min_data = pd.DataFrame( np.min(data, axis=2), @@ -86,7 +89,7 @@ def wrapper(*args, **kwargs): from pandas.api.types import is_numeric_dtype -def boiler_plate(features_df:pd.DataFrame): +def boiler_plate(features_df: pd.DataFrame): reversemap = None to_drop = ["Unnamed: 0"] @@ -102,7 +105,12 @@ def boiler_plate(features_df:pd.DataFrame): @augment_features() def _compute_centroid( - df:pd.DataFrame, name:str, animal_setup:dict, body_parts:list=None, n_shifts:int=3, mode:str="shift" + df: pd.DataFrame, + name: str, + animal_setup: dict, + body_parts: list = None, + n_shifts: int = 3, + mode: str = "shift", ): bodypart_ids = animal_setup["bodypart_ids"] mouse_ids = animal_setup["mouse_ids"] @@ -122,7 +130,13 @@ def _compute_centroid( @augment_features() def _compute_abs_angle( - df:pd.DataFrame, name:str, animal_setup:dict, bps:list, centroid:bool=True, n_shifts:int=3, mode:bool="shift" + df: pd.DataFrame, + name: str, + animal_setup: dict, + bps: list, + centroid: bool = True, + n_shifts: int = 3, + mode: bool = "shift", ): mouse_ids = animal_setup["mouse_ids"] df = df.copy() @@ -143,7 +157,13 @@ def _compute_abs_angle( @augment_features() def _compute_rel_angle( - df:pd.DataFrame, name:str, animal_setup:dict, bps:list, centroid:bool=False, n_shifts:int=3, mode:str="shift" + df: pd.DataFrame, + name: str, + animal_setup: dict, + bps: list, + centroid: bool = False, + n_shifts: int = 3, + mode: str = "shift", ): mouse_ids = animal_setup["mouse_ids"] df = df.copy() @@ -173,7 +193,9 @@ def _compute_rel_angle( @augment_features() -def _compute_ellipsoid(df:pd.DataFrame, animal_setup:dict, n_shifts:int=3, mode:str="shift"): +def _compute_ellipsoid( + df: pd.DataFrame, animal_setup: dict, n_shifts: int = 3, mode: str = "shift" +): bodypart_ids = animal_setup["bodypart_ids"] mouse_ids = animal_setup["mouse_ids"] colnames = animal_setup["colnames"] @@ -214,7 +236,13 @@ def _compute_ellipsoid(df:pd.DataFrame, animal_setup:dict, n_shifts:int=3, mode: # Recall framerate is 30 fps -def _compute_kinematics(df:pd.DataFrame, names:list, animal_setup:dict, window_size:int=5, n_shifts:int=3): +def _compute_kinematics( + df: pd.DataFrame, + names: list, + animal_setup: dict, + window_size: int = 5, + n_shifts: int = 3, +): bodypart_ids = animal_setup["bodypart_ids"] mouse_ids = animal_setup["mouse_ids"] colnames = animal_setup["colnames"] @@ -236,7 +264,11 @@ def _compute_kinematics(df:pd.DataFrame, names:list, animal_setup:dict, window_s @augment_features() def _compute_relative_body_motions( - df:pd.DataFrame, animal_setup:dict, window_size:int=3, n_shifts:int=3, mode:str="shift" + df: pd.DataFrame, + animal_setup: dict, + window_size: int = 3, + n_shifts: int = 3, + mode: str = "shift", ): bodypart_ids = animal_setup["bodypart_ids"] mouse_ids = animal_setup["mouse_ids"] @@ -269,7 +301,9 @@ def _compute_relative_body_motions( @augment_features() -def _compute_relative_body_angles(df:pd.DataFrame, animal_setup:dict, n_shifts:int=3, mode:str="shift"): +def _compute_relative_body_angles( + df: pd.DataFrame, animal_setup: dict, n_shifts: int = 3, mode: str = "shift" +): bodypart_ids = animal_setup["bodypart_ids"] mouse_ids = animal_setup["mouse_ids"] colnames = animal_setup["colnames"] @@ -314,7 +348,9 @@ def _compute_relative_body_angles(df:pd.DataFrame, animal_setup:dict, n_shifts:i @augment_features() -def _compute_iou(df:pd.DataFrame, animal_setup:dict, n_shifts:int=3, mode:str="shift"): +def _compute_iou( + df: pd.DataFrame, animal_setup: dict, n_shifts: int = 3, mode: str = "shift" +): bodypart_ids = animal_setup["bodypart_ids"] mouse_ids = animal_setup["mouse_ids"] colnames = animal_setup["colnames"] @@ -356,7 +392,10 @@ def _compute_iou(df:pd.DataFrame, animal_setup:dict, n_shifts:int=3, mode:str="s # Which can change from video to video, train to test, etc. So perhaps not useful @augment_features() def _compute_cage_distances( - features_df:pd.DataFrame, animal_setup:dict, n_shifts:int=3, mode:bool="shift" + features_df: pd.DataFrame, + animal_setup: dict, + n_shifts: int = 3, + mode: bool = "shift", ): # pragma: no cover bodypart_ids = animal_setup["bodypart_ids"] mouse_ids = animal_setup["mouse_ids"] @@ -389,7 +428,7 @@ def _compute_cage_distances( return features_df -def make_features_distances(df:pd.DataFrame, animal_setup:dict): +def make_features_distances(df: pd.DataFrame, animal_setup: dict): bodypart_ids = animal_setup["bodypart_ids"] mouse_ids = animal_setup["mouse_ids"] colnames = animal_setup["colnames"] @@ -431,7 +470,9 @@ def make_features_distances(df:pd.DataFrame, animal_setup:dict): return features_df -def make_features_mars(df:pd.DataFrame, animal_setup:dict, n_shifts:int=3, mode:str="shift"): +def make_features_mars( + df: pd.DataFrame, animal_setup: dict, n_shifts: int = 3, mode: str = "shift" +): features_df = df.copy() ####################### @@ -542,11 +583,13 @@ def make_features_mars(df:pd.DataFrame, animal_setup:dict, n_shifts:int=3, mode: return features_df -def make_features_mars_distr(df:pd.DataFrame, animal_setup:dict): +def make_features_mars_distr(df: pd.DataFrame, animal_setup: dict): return make_features_mars(df, animal_setup, n_shifts=3, mode="distr") -def make_features_mars_reduced(df:pd.DataFrame, animal_setup:dict, n_shifts:int=2, mode:str="diff"): +def make_features_mars_reduced( + df: pd.DataFrame, animal_setup: dict, n_shifts: int = 2, mode: str = "diff" +): features_df = df.copy() ####################### @@ -642,7 +685,9 @@ def make_features_mars_reduced(df:pd.DataFrame, animal_setup:dict, n_shifts:int= return features_df -def make_features_velocities(df:pd.DataFrame, animal_setup:dict, n_shifts:int=5): # pragma: no cover +def make_features_velocities( + df: pd.DataFrame, animal_setup: dict, n_shifts: int = 5 +): # pragma: no cover bodypart_ids = animal_setup["bodypart_ids"] mouse_ids = animal_setup["mouse_ids"] colnames = animal_setup["colnames"] @@ -700,7 +745,9 @@ def make_features_velocities(df:pd.DataFrame, animal_setup:dict, n_shifts:int=5) return features_df -def make_features_social(df:pd.DataFrame, animal_setup:dict, n_shifts:int=3, mode:str="shift"): +def make_features_social( + df: pd.DataFrame, animal_setup: dict, n_shifts: int = 3, mode: str = "shift" +): features_df = df.copy() colnames = animal_setup["colnames"] diff --git a/ethome/interpolation.py b/ethome/interpolation.py index 76921bf..e6a2cf4 100644 --- a/ethome/interpolation.py +++ b/ethome/interpolation.py @@ -3,7 +3,7 @@ import pandas as pd import numpy as np - + def interpolate_lowconf_points( edf: pd.DataFrame, conf_threshold: float = 0.9, diff --git a/ethome/io.py b/ethome/io.py index e750001..e7e0fac 100644 --- a/ethome/io.py +++ b/ethome/io.py @@ -16,14 +16,14 @@ XYLIKELIHOOD_IDS = ["x", "y", "likelihood"] -def uniquifier(seq:Sequence): +def uniquifier(seq: Sequence): """Return a sequence (e.g. list) with unique elements only, but maintaining original list order""" seen = set() seen_add = seen.add return [x for x in seq if not (x in seen or seen_add(x))] -def _list_replace(ls:list, renamer:dict): +def _list_replace(ls: list, renamer: dict): """Replace elements in a list according to provided dictionary""" for i, word in enumerate(ls): if word in renamer.keys(): @@ -31,7 +31,7 @@ def _list_replace(ls:list, renamer:dict): return ls -def save_sklearn_model(model, fn_out:str): # pragma: no cover +def save_sklearn_model(model, fn_out: str): # pragma: no cover """Save sklearn model to file Args: @@ -153,7 +153,7 @@ def read_sleap_tracks( # POSSIBILITY OF SUCH DAMAGE. -def _load_sleap_data(path:str, multi_animal:bool=False): +def _load_sleap_data(path: str, multi_animal: bool = False): """loads sleap data h5 format from file path and returns it as pd.DataFrame As sleap body parts (nodes) are not ordered in a particular way, we sort them alphabetically. As sleap tracks do not export a score/likelihood but cut off automatically (nan), we are simulating a likelihood @@ -409,7 +409,7 @@ def _read_DLC_tracks( # SOFTWARE. -def _convert_nwb_to_h5_all(nwbfile:str): +def _convert_nwb_to_h5_all(nwbfile: str): """ Convert a NWB data file back to DeepLabCut's h5 data format. @@ -547,7 +547,7 @@ def load_data(fn: str): # pragma: no cover # Only used to making a test dataframe for testing and dev purposes -def _make_sample_dataframe(fn_out:str="sample_dataframe.pkl"): # pragma: no cover +def _make_sample_dataframe(fn_out: str = "sample_dataframe.pkl"): # pragma: no cover from ethome import create_dataset, create_metadata cur_dir = os.path.dirname(os.path.abspath(__file__)) @@ -663,7 +663,7 @@ def read_boris_annotation( return ground_truth -def create_behavior_labels(boris_files:list): +def create_behavior_labels(boris_files: list): """Create behavior labels from BORIS exported csv files. Args: diff --git a/ethome/models.py b/ethome/models.py index ae175e7..34f2bcd 100644 --- a/ethome/models.py +++ b/ethome/models.py @@ -9,7 +9,7 @@ def _logit(p: float): # pragma: no cover return np.log(p / (1 - p)) -def _sample_prob_simplex(n:int=4): # pragma: no cover +def _sample_prob_simplex(n: int = 4): # pragma: no cover x = sorted(np.append(np.random.uniform(size=n - 1), [0, 1])) y = np.diff(np.array(x)) return y @@ -19,7 +19,7 @@ def _sample_prob_simplex(n:int=4): # pragma: no cover import ssm class HMMSklearn(ssm.HMM): # pragma: no cover - def __init__(self, D: int, C: int=11): + def __init__(self, D: int, C: int = 11): """HMM model from Linderman state-space model package ssm, tweaked slightly to fit with sklearn syntax Args: @@ -76,11 +76,11 @@ def predict(self, X: np.ndarray): class F1Optimizer(ClassifierMixin): # pragma: no cover - def __init__(self, N: int=1000, labels: list =[1]): + def __init__(self, N: int = 1000, labels: list = [1]): self.N = N self.labels = labels - def fit(self, X:np.ndarray, y:np.ndarray): # train_labels, train_pred_prob): + def fit(self, X: np.ndarray, y: np.ndarray): # train_labels, train_pred_prob): self.dim_x = X.shape[1] f = lambda w: f1_score( @@ -103,13 +103,13 @@ def fit(self, X:np.ndarray, y:np.ndarray): # train_labels, train_pred_prob): def predict(self, X: np.ndarray): return np.argmax(X * self.w_star, axis=-1) - def predict_proba(self, X:np.ndarray): + def predict_proba(self, X: np.ndarray): return X * self.w_star - def transform(self, X:np.ndarray): + def transform(self, X: np.ndarray): return self.predict_proba(X) - def fit_transform(self, X:np.ndarray, y:np.ndarray=None): + def fit_transform(self, X: np.ndarray, y: np.ndarray = None): self.fit(X, y) return self.transform(X) @@ -131,6 +131,6 @@ def fit(self, X: np.ndarray, y: np.ndarray): def transform(self, X: np.ndarray): return self.model.predict_proba(X) - def fit_transform(self, X: np.ndarray, y: np.ndarray=None): + def fit_transform(self, X: np.ndarray, y: np.ndarray = None): self.fit(X, y) return self.transform(X) diff --git a/ethome/plot.py b/ethome/plot.py index ffc9af7..d159e6a 100644 --- a/ethome/plot.py +++ b/ethome/plot.py @@ -121,7 +121,7 @@ def plot_embedding( class MplColorHelper: # pragma: no cover - def __init__(self, cmap_name: str, start_val:int, stop_val:int): + def __init__(self, cmap_name: str, start_val: int, stop_val: int): self.cmap_name = cmap_name self.cmap = plt.get_cmap(cmap_name) self.norm = mpl.colors.Normalize(vmin=start_val, vmax=stop_val) @@ -344,7 +344,7 @@ def create_sample_videos( labels = labels[labels >= 0] # all_labels = np.unique(labels) - def get_window_size(label_idx: int, sample_row:int, max_size:int=500): + def get_window_size(label_idx: int, sample_row: int, max_size: int = 500): s_m = 0 for idx in range(max_size): try: diff --git a/ethome/unsupervised.py b/ethome/unsupervised.py index 305e554..3365ef5 100644 --- a/ethome/unsupervised.py +++ b/ethome/unsupervised.py @@ -13,8 +13,8 @@ def compute_tsne_embedding( dataset: pd.DataFrame, cols: list, N_rows: int = 20000, - n_components: int=2, - perplexity: int=30, + n_components: int = 2, + perplexity: int = 30, ) -> tuple: """Compute TSNE embedding. Only for a random subset of rows. diff --git a/ethome/video.py b/ethome/video.py index 3e0780e..7ced10f 100644 --- a/ethome/video.py +++ b/ethome/video.py @@ -50,12 +50,12 @@ } -def _add_item_to_dict(tracking_files: list, metadata:dict, k:Any, item:Any): +def _add_item_to_dict(tracking_files: list, metadata: dict, k: Any, item: Any): for fn in tracking_files: metadata[fn][k] = item -def _add_items_to_dict(tracking_files: list, metadata:dict, k:Any, items:Any): +def _add_items_to_dict(tracking_files: list, metadata: dict, k: Any, items: Any): for fn, item in zip(tracking_files, items): metadata[fn][k] = item @@ -96,7 +96,7 @@ def create_metadata(tracking_files: list, **kwargs) -> dict: return metadata -def _convert_units(df:pd.DataFrame): +def _convert_units(df: pd.DataFrame): # if 'frame_width', 'resolution' and 'frame_width_units' are provided, then we convert tracks to these units. if len(df.metadata.details) == 0: return @@ -111,7 +111,7 @@ def _convert_units(df:pd.DataFrame): df.drop(columns="scale_factor", inplace=True) -def _validate_metadata(metadata:dict, req_cols:list): +def _validate_metadata(metadata: dict, req_cols: list): has_all_dim_cols_count = 0 should_rescale = None @@ -216,7 +216,7 @@ def _validate_metadata(metadata:dict, req_cols:list): @pd.api.extensions.register_dataframe_accessor("metadata") class EthologyMetadataAccessor(object): - def __init__(self, pandas_obj:pd.DataFrame): + def __init__(self, pandas_obj: pd.DataFrame): self._obj = pandas_obj if "metadata__details" not in self._obj.attrs: self._obj.attrs["metadata__details"] = {} @@ -232,11 +232,11 @@ def label_key(self): return self._obj.attrs["metadata__label_key"] @details.setter - def details(self, val:Any): + def details(self, val: Any): self._obj.attrs["metadata__details"] = val @label_key.setter - def label_key(self, val:Any): + def label_key(self, val: Any): self._obj.attrs["metadata__label_key"] = val @property @@ -254,7 +254,7 @@ def reverse_label_key(self): @pd.api.extensions.register_dataframe_accessor("features") class EthologyFeaturesAccessor(object): - def __init__(self, pandas_obj:pd.DataFrame): + def __init__(self, pandas_obj: pd.DataFrame): self._obj = pandas_obj if "features__active" not in self._obj.attrs: self._obj.attrs["features__active"] = None @@ -264,7 +264,7 @@ def active(self): return self._obj.attrs["features__active"] @active.setter - def active(self, val:Any): + def active(self, val: Any): self._obj.attrs["features__active"] = val def activate(self, name: str) -> list: @@ -396,7 +396,7 @@ def deactivate_cols(self, col_names: list) -> list: @pd.api.extensions.register_dataframe_accessor("pose") class EthologyPoseAccessor(object): - def __init__(self, pandas_obj:pd.DataFrame): + def __init__(self, pandas_obj: pd.DataFrame): self._obj = pandas_obj if "pose__body_parts" not in self._obj.attrs: @@ -416,7 +416,7 @@ def body_parts(self): return self._obj.attrs["pose__body_parts"] @body_parts.setter - def body_parts(self, val:Any): + def body_parts(self, val: Any): self._obj.attrs["pose__body_parts"] = val @property @@ -424,7 +424,7 @@ def animals(self): return self._obj.attrs["pose__animals"] @animals.setter - def animals(self, val:Any): + def animals(self, val: Any): self._obj.attrs["pose__animals"] = val @property @@ -432,7 +432,7 @@ def animal_setup(self): return self._obj.attrs["pose__animal_setup"] @animal_setup.setter - def animal_setup(self, val:Any): + def animal_setup(self, val: Any): self._obj.attrs["pose__animal_setup"] = val @property @@ -440,13 +440,13 @@ def raw_track_columns(self): return self._obj.attrs["pose__raw_track_columns"] @raw_track_columns.setter - def raw_track_columns(self, val:Any): + def raw_track_columns(self, val: Any): self._obj.attrs["pose__raw_track_columns"] = val @pd.api.extensions.register_dataframe_accessor("ml") class EthologyMLAccessor(object): - def __init__(self, pandas_obj:pd.DataFrame): + def __init__(self, pandas_obj: pd.DataFrame): self._obj = pandas_obj if "ml__label_cols" not in self._obj.attrs: @@ -460,7 +460,7 @@ def label_cols(self): return self._obj.attrs["ml__label_cols"] @label_cols.setter - def label_cols(self, val:Any): + def label_cols(self, val: Any): self._obj.attrs["ml__label_cols"] = val @property @@ -468,7 +468,7 @@ def fold_cols(self): return self._obj.attrs["ml__fold_cols"] @fold_cols.setter - def fold_cols(self, val:Any): + def fold_cols(self, val: Any): self._obj.attrs["ml__fold_cols"] = val @property @@ -515,7 +515,7 @@ def _make_predefined_split(self, folds): # pragma: no cover @pd.api.extensions.register_dataframe_accessor("io") class EthologyIOAccessor(object): - def __init__(self, pandas_obj:pd.DataFrame): + def __init__(self, pandas_obj: pd.DataFrame): self._obj = pandas_obj def save(self, fn_out: str) -> None: @@ -532,7 +532,7 @@ def save(self, fn_out: str) -> None: # file.write(pickle.dumps(df.__dict__, protocol = 4)) file.write(dill.dumps(df.__dict__, protocol=4)) - def to_dlc_csv(self, base_dir: str, save_h5_too:bool=False) -> None: + def to_dlc_csv(self, base_dir: str, save_h5_too: bool = False) -> None: """Save ExperimentDataFrame tracking files to DLC csv format. Only save tracking data, not other computed features. @@ -589,7 +589,7 @@ def load(fn_in: str) -> pd.DataFrame: return load_experiment(fn_in) def save_movie( - self, label_columns:list, path_out: str, video_filenames:list=None + self, label_columns: list, path_out: str, video_filenames: list = None ) -> None: # pragma: no cover """Given columns indicating behavior predictions or whatever else, make a video with these predictions overlaid. @@ -656,7 +656,7 @@ def save_movie( os.system(cmd) -def _create_from_dict(metadata:dict, part_renamer:dict, animal_renamer:dict): +def _create_from_dict(metadata: dict, part_renamer: dict, animal_renamer: dict): df = pd.DataFrame() # req_cols = ['fps'] # Drop requirement this is provided. Just omit addition of time column, if fps omitted @@ -679,7 +679,7 @@ def _create_from_dict(metadata:dict, part_renamer:dict, animal_renamer:dict): return df -def _create_from_list(input:list, part_renamer:dict, animal_renamer:dict, **kwargs): +def _create_from_list(input: list, part_renamer: dict, animal_renamer: dict, **kwargs): if len(input) == 0: return pd.DataFrame() supported_exts = [".csv", ".h5", ".nwb", ".hdf5"] @@ -741,7 +741,9 @@ def create_dataset( return df -def _load_nwb(nwb_files:list, part_renamer:dict, animal_renamer:dict, set_as_label:bool=True): +def _load_nwb( + nwb_files: list, part_renamer: dict, animal_renamer: dict, set_as_label: bool = True +): metadata = {} dfs = [] col_names_old = None @@ -787,7 +789,9 @@ def _load_nwb(nwb_files:list, part_renamer:dict, animal_renamer:dict, set_as_lab return df -def _load_tracks(df:pd.DataFrame, part_renamer:dict, animal_renamer:dict, rescale:bool=False): +def _load_tracks( + df: pd.DataFrame, part_renamer: dict, animal_renamer: dict, rescale: bool = False +): """Add tracks to DataFrame""" dfs = [] col_names_old = None @@ -873,12 +877,14 @@ def _load_tracks(df:pd.DataFrame, part_renamer:dict, animal_renamer:dict, rescal return col_names -def _load_labels(df:pd.DataFrame, col_name:str="label", set_as_label:bool=False): +def _load_labels(df: pd.DataFrame, col_name: str = "label", set_as_label: bool = False): # For the moment only BORIS support return _load_labels_boris(df, col_name, set_as_label) -def _load_labels_boris(df:pd.DataFrame, prefix:str="label", set_as_label:bol=False): +def _load_labels_boris( + df: pd.DataFrame, prefix: str = "label", set_as_label: bol = False +): """Add behavior label data to DataFrame""" label_cols = [] @@ -945,7 +951,7 @@ def get_sample_openfield_data(): return create_dataset(metadata) -def _make_dense_values_into_pairs(predictions:list, rate:int): # pragma: no cover +def _make_dense_values_into_pairs(predictions: list, rate: int): # pragma: no cover # Put into start/stop pairs pairs = [] in_pair = False diff --git a/pyproject.toml b/pyproject.toml index 374b58c..aaa7c9d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,3 +4,82 @@ requires = [ "wheel" ] build-backend = "setuptools.build_meta" + +[tool.ruff] +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".ipynb_checkpoints", + ".mypy_cache", + ".nox", + ".pants.d", + ".pyenv", + ".pytest_cache", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + ".vscode", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "site-packages", + "venv", +] + +# Same as Black. +line-length = 88 +indent-width = 4 + +# Assume Python 3.8 +target-version = "py38" + +[tool.ruff.lint] +# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. +# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or +# McCabe complexity (`C901`) by default. +select = ["E4", "E7", "E9", "F"] +ignore = [] + +# Allow fix for all enabled rules (when `--fix`) is provided. +fixable = ["ALL"] +unfixable = [] + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +[tool.ruff.format] +# Like Black, use double quotes for strings. +quote-style = "double" + +# Like Black, indent with spaces, rather than tabs. +indent-style = "space" + +# Like Black, respect magic trailing commas. +skip-magic-trailing-comma = false + +# Like Black, automatically detect the appropriate line ending. +line-ending = "auto" + +# Enable auto-formatting of code examples in docstrings. Markdown, +# reStructuredText code/literal blocks and doctests are all supported. +# +# This is currently disabled by default, but it is planned for this +# to be opt-out in the future. +docstring-code-format = false + +# Set the line length limit used when formatting code snippets in +# docstrings. +# +# This only has an effect when the `docstring-code-format` setting is +# enabled. +docstring-code-line-length = "dynamic" \ No newline at end of file