autogaita 1.5.2__py3-none-any.whl → 1.5.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.
@@ -1,248 +0,0 @@
1
- from autogaita.universal3D.universal3D_3_analysis import (
2
- standardise_y_z_flip_gait_add_features_to_one_step,
3
- add_features,
4
- )
5
- from hypothesis import HealthCheck, given, settings, strategies as st
6
- import pytest
7
- import pandas as pd
8
- import pandas.testing as pdt
9
- import numpy as np
10
- import os
11
-
12
-
13
- # %%................................ fixtures ........................................
14
- @pytest.fixture
15
- def extract_info(tmp_path):
16
- info = {}
17
- info["name"] = "SK"
18
- info["results_dir"] = os.path.join(tmp_path, info["name"])
19
- return info
20
-
21
-
22
- @pytest.fixture
23
- def extract_folderinfo():
24
- folderinfo = {}
25
- folderinfo["root_dir"] = "tests/test_data/universal3D_data/test_data"
26
- folderinfo["sctable_filename"] = "SC Latency Table.xlsx"
27
- folderinfo["postname_string"] = ""
28
- return folderinfo
29
-
30
-
31
- @pytest.fixture
32
- def extract_cfg():
33
- # note space in end of "Midfoot, left " must be here bc. we don't run our fix and
34
- # check cfg function of 1_prep_
35
- cfg = {}
36
- cfg["sampling_rate"] = 100 # base cfg
37
- cfg["dont_show_plots"] = True
38
- cfg["y_acceleration"] = True
39
- cfg["angular_acceleration"] = True
40
- cfg["bin_num"] = 25
41
- cfg["plot_SE"] = True
42
- cfg["standardise_z_at_SC_level"] = True
43
- cfg["standardise_z_to_a_joint"] = True
44
- cfg["z_standardisation_joint"] = ["Midfoot, left "]
45
- cfg["plot_joint_number"] = 5
46
- cfg["color_palette"] = "Set2"
47
- cfg["legend_outside"] = True
48
- cfg["flip_gait_direction"] = True
49
- cfg["analyse_average_y"] = True
50
- cfg["standardise_y_coordinates"] = True
51
- cfg["y_standardisation_joint"] = ["Midfoot, left "]
52
- cfg["coordinate_standardisation_xls"] = ""
53
- cfg["joints"] = [
54
- "Midfoot",
55
- "Ankle",
56
- "Knee",
57
- "Hip",
58
- ]
59
- cfg["angles"] = {
60
- "name": ["Ankle", "Knee"],
61
- "lower_joint": ["Midfoot", "Ankle"],
62
- "upper_joint": ["Knee", "Hip"],
63
- }
64
- cfg["direction_joint"] = "Midfoot, left Y"
65
- return cfg
66
-
67
-
68
- sample_step_len = 10 # 10 datapoints (e.g. time)
69
- sample_step_col_num = 20 # 10 for each Y and Z
70
-
71
-
72
- @pytest.fixture
73
- def sample_step():
74
- joint_strings = [
75
- "Midfoot, left",
76
- "Ankle, left",
77
- "Knee, left",
78
- "Hip, left",
79
- "Midfoot, right",
80
- "Ankle, right",
81
- "Knee, right",
82
- "Hip, right",
83
- "Shoulder",
84
- "Neck",
85
- ]
86
- sample_step = {}
87
- for joint in joint_strings:
88
- for coord in [" Y", " Z"]:
89
- sample_step[joint + coord] = list(
90
- np.random.randint(1, 101, sample_step_len)
91
- )
92
- sample_step["Time"] = np.arange(sample_step_len)
93
- return pd.DataFrame(sample_step)
94
-
95
-
96
- # ............................ for property tests ....................................
97
- # 1. define the sample_steps_data strategy using random ints as data
98
- sample_steps_data_strategy = st.lists(
99
- st.lists(
100
- st.integers(min_value=-1000, max_value=1000),
101
- min_size=sample_step_col_num, # 20 cols (10 for each Y and Z)
102
- max_size=sample_step_col_num,
103
- ),
104
- min_size=sample_step_len, # 10 rows
105
- max_size=sample_step_len,
106
- )
107
-
108
-
109
- # 2. create a custom decorator that can be used instead of writing given/settings
110
- # always
111
- def sample_data_for_property_tests(func):
112
- return settings(suppress_health_check=(HealthCheck.function_scoped_fixture,))(
113
- given(sample_steps_data=sample_steps_data_strategy)(func)
114
- )
115
-
116
-
117
- # .................................. tests .........................................
118
- # %% workflow step #3 - y-flipping, y-stand, features, df-creation & exports
119
-
120
-
121
- def test_standardise_z_at_SC_level(sample_step, extract_info, extract_cfg):
122
- extract_cfg["standardise_z_at_SC_level"] = True
123
- extract_cfg["standardise_z_to_a_joint"] = False
124
- extract_cfg["flip_gait_direction"] = False
125
- extract_cfg["standardise_y_coordinates"] = False
126
- z_cols = [col for col in sample_step.columns if col.endswith("Z")]
127
- function_step = standardise_y_z_flip_gait_add_features_to_one_step(
128
- sample_step, 10, extract_info, extract_cfg
129
- )
130
- sample_step = add_features(
131
- sample_step, extract_info, extract_cfg
132
- ) # otherwise df-shape mismatch
133
- steps_global_z_minimum = sample_step[z_cols].min().min() # global == all joints
134
- expected_step = sample_step.copy()
135
- expected_step[z_cols] -= steps_global_z_minimum
136
- pdt.assert_frame_equal(function_step, expected_step)
137
-
138
-
139
- # because we have random integers in step, we might get a near-zero vectors when
140
- # computing angles - ignore those warnings
141
- @pytest.mark.filterwarnings("ignore:invalid value")
142
- def test_flip_gait_direction(sample_step, extract_info, extract_cfg):
143
- # prepare some vars
144
- extract_cfg["flip_gait_direction"] = True
145
- extract_cfg["standardise_y_coordinates"] = False
146
- global_Y_max = 10
147
- to_be_flipped_step = sample_step.copy()
148
- to_not_be_flipped_step = sample_step.copy()
149
- y_cols = [col for col in sample_step.columns if col.endswith("Y")]
150
- # step sample is random integers, so first fix the direction of y-values, either
151
- # increasing or decreasing (decreasing must be flipped)
152
- for col in y_cols:
153
- to_be_flipped_step[col] = to_be_flipped_step[col].sort_values(
154
- ascending=False, ignore_index=True
155
- )
156
- to_not_be_flipped_step[col] = to_not_be_flipped_step[col].sort_values(
157
- ascending=True, ignore_index=True
158
- )
159
- to_be_flipped_step = standardise_y_z_flip_gait_add_features_to_one_step(
160
- to_be_flipped_step, global_Y_max, extract_info, extract_cfg
161
- )
162
- to_not_be_flipped_step = standardise_y_z_flip_gait_add_features_to_one_step(
163
- to_not_be_flipped_step, global_Y_max, extract_info, extract_cfg
164
- )
165
- # first test if the y-values are flipped (increasing y-cols progressively)
166
- for col in y_cols:
167
- assert to_be_flipped_step[col][0] < to_be_flipped_step[col].mean()
168
- # now, test that if you reverse the impact of global_y_max you get your original df
169
- # 1. reverse subtraction of global y max before comparison for df-equivalence
170
- # => e.g. 10 - 2 = 8 || reverse via: 10 - 8 = 2!
171
- to_be_flipped_step[y_cols] = global_Y_max - to_be_flipped_step[y_cols]
172
- # 2. reverting of 1. changes y-values to now be decreasing (2 4 8 becomes 8 4 2)
173
- # => sooo manually make it so that it is increasing again and then you should have
174
- # equal dfs
175
- for col in y_cols:
176
- to_be_flipped_step[col] = to_be_flipped_step[col].sort_values(
177
- ascending=True, ignore_index=True
178
- )
179
- # 3. remove the cols that were created by add_features, because those won't match
180
- # (understandably)
181
- # fmt:off
182
- cols_to_drop = [col for col in to_be_flipped_step.columns if not (col.endswith("Z") or col.endswith("Y"))]
183
- for df in [to_be_flipped_step, to_not_be_flipped_step]:
184
- df.drop(columns=cols_to_drop, inplace=True)
185
- # fmt:on
186
- pdt.assert_frame_equal(to_be_flipped_step, to_not_be_flipped_step)
187
-
188
-
189
- # because we have random integers in step, we might get a near-zero vectors when
190
- # computing angles - ignore those warnings
191
- @pytest.mark.filterwarnings("ignore:invalid value")
192
- @sample_data_for_property_tests
193
- def test_standardise_y_coordinates_no_gait_flipping(
194
- sample_step, extract_info, extract_cfg, sample_steps_data
195
- ):
196
- extract_cfg["standardise_y_coordinates"] = True
197
- extract_cfg["flip_gait_direction"] = False
198
- y_cols = [col for col in sample_step.columns if col.endswith("Y")]
199
- # prep data
200
- # => because we are property testing, insert the hypothesis-generated data into the
201
- # sample_step df (which has the correct columns)
202
- # => the -1 in pd.df line is because we first want to exclude the time column...
203
- sample_step = pd.DataFrame(columns=sample_step.columns[:-1], data=sample_steps_data)
204
- sample_step["Time"] = np.arange(len(sample_step)) # ... to include it manually
205
- non_stand_step, y_stand_step = standardise_y_z_flip_gait_add_features_to_one_step(
206
- sample_step, 10, extract_info, extract_cfg
207
- )
208
- steps_y_min = (
209
- sample_step[extract_cfg["y_standardisation_joint"][0] + "Y"].min().min()
210
- )
211
- non_stand_step[y_cols] -= steps_y_min
212
- pdt.assert_frame_equal(non_stand_step, y_stand_step)
213
-
214
-
215
- def test_standardise_y_coordinates_gait_flipping(
216
- sample_step, extract_info, extract_cfg
217
- ):
218
- # prep vars
219
- extract_cfg["standardise_y_coordinates"] = True
220
- extract_cfg["flip_gait_direction"] = True
221
- global_Y_max = 10
222
- y_cols = [col for col in sample_step.columns if col.endswith("Y")]
223
-
224
- # ---------------
225
- # NOTE FOR MYSELF
226
- # => look at this again - returned math domain errors if property testing
227
- # => uncomment the sample_step =... line & use the @sample_data.. fixture as in the
228
- # test above to have another look
229
- # => because we are property testing, insert the hypothesis-generated data into the
230
- # sample_step df (which has the correct columns)
231
- # sample_step = pd.DataFrame(columns=sample_step.columns, data=sample_steps_data)
232
- # ---------------
233
-
234
- # run function on a to-be-flipped step
235
- to_be_flipped_step = sample_step.copy()
236
- for col in y_cols:
237
- to_be_flipped_step[col] = to_be_flipped_step[col].sort_values(
238
- ascending=False, ignore_index=True
239
- )
240
- non_stand_step, y_stand_step = standardise_y_z_flip_gait_add_features_to_one_step(
241
- to_be_flipped_step, global_Y_max, extract_info, extract_cfg
242
- )
243
- steps_y_min = (
244
- non_stand_step[extract_cfg["y_standardisation_joint"][0] + "Y"].min().min()
245
- )
246
- reverted_step = y_stand_step.copy()
247
- reverted_step[y_cols] += steps_y_min
248
- pdt.assert_frame_equal(reverted_step, non_stand_step)
tests/test_utils.py DELETED
@@ -1,442 +0,0 @@
1
- from autogaita.resources.utils import (
2
- standardise_primary_joint_coordinates,
3
- compute_angle,
4
- define_bins,
5
- write_angle_warning,
6
- )
7
- from autogaita.common2D.common2D_1_preparation import some_prep as some_prep_2D
8
- from autogaita.universal3D.universal3D_1_preparation import some_prep as some_prep_3D
9
- from autogaita.common2D.common2D_2_sc_extraction import extract_stepcycles
10
- from autogaita.common2D.common2D_3_analysis import analyse_and_export_stepcycles
11
- import os
12
- import math
13
- import numpy as np
14
- import pandas as pd
15
- import pandas.testing as pdt
16
- import pytest
17
-
18
-
19
- # %%........................... 2D GaitA fixtures ....................................
20
- @pytest.fixture
21
- def extract_2D_info(tmp_path):
22
- info = {}
23
- info["mouse_num"] = 15
24
- info["run_num"] = 3
25
- info["name"] = "ID " + str(info["mouse_num"]) + " - Run " + str(info["run_num"])
26
- info["results_dir"] = os.path.join(tmp_path, info["name"])
27
- return info
28
-
29
-
30
- @pytest.fixture
31
- def extract_2D_folderinfo():
32
- folderinfo = {}
33
- folderinfo["root_dir"] = "tests/test_data/dlc_data"
34
- folderinfo["sctable_filename"] = (
35
- "correct_annotation_table.xlsx" # has to be an excel file
36
- )
37
- folderinfo["data_string"] = "SIMINewOct"
38
- folderinfo["beam_string"] = "BeamTraining"
39
- folderinfo["premouse_string"] = "Mouse"
40
- folderinfo["postmouse_string"] = "25mm"
41
- folderinfo["prerun_string"] = "run"
42
- folderinfo["postrun_string"] = "6DLC"
43
- return folderinfo
44
-
45
-
46
- @pytest.fixture
47
- def extract_2D_cfg():
48
- cfg = {}
49
- cfg["sampling_rate"] = 100
50
- cfg["subtract_beam"] = False
51
- cfg["dont_show_plots"] = True
52
- cfg["convert_to_mm"] = False # false!
53
- cfg["pixel_to_mm_ratio"] = 3.76
54
- cfg["x_sc_broken_threshold"] = 200
55
- cfg["y_sc_broken_threshold"] = 50
56
- cfg["x_acceleration"] = True
57
- cfg["angular_acceleration"] = True
58
- cfg["save_to_xls"] = True
59
- cfg["bin_num"] = 25
60
- cfg["plot_SE"] = True
61
- cfg["standardise_y_at_SC_level"] = False
62
- cfg["standardise_y_to_a_joint"] = True
63
- cfg["y_standardisation_joint"] = ["Knee"]
64
- cfg["plot_joint_number"] = 3
65
- cfg["color_palette"] = "viridis"
66
- cfg["legend_outside"] = True
67
- cfg["invert_y_axis"] = True
68
- cfg["flip_gait_direction"] = False
69
- cfg["analyse_average_x"] = True
70
- cfg["standardise_x_coordinates"] = True
71
- cfg["x_standardisation_joint"] = ["Hind paw tao"]
72
- cfg["coordinate_standardisation_xls"] = ""
73
- cfg["hind_joints"] = ["Hind paw tao", "Ankle", "Knee", "Hip", "Iliac Crest"]
74
- cfg["fore_joints"] = [
75
- "Front paw tao ",
76
- "Wrist ",
77
- "Elbow ",
78
- "Lower Shoulder ",
79
- "Upper Shoulder ",
80
- ]
81
- cfg["beam_col_left"] = ["BeamLeft"] # BEAM_COL_LEFT & _RIGHT must be lists of len=1
82
- cfg["beam_col_right"] = ["BeamRight"]
83
- cfg["beam_hind_jointadd"] = ["Tail base ", "Tail center ", "Tail tip "]
84
- cfg["beam_fore_jointadd"] = ["Nose ", "Ear base "]
85
- cfg["angles"] = {
86
- "name": ["Ankle ", "Knee ", "Hip "],
87
- "lower_joint": ["Hind paw tao ", "Ankle ", "Knee "],
88
- "upper_joint": ["Knee ", "Hip ", "Iliac Crest "],
89
- }
90
- return cfg
91
-
92
-
93
- # %%........................... 3D GaitA fixtures ....................................
94
- @pytest.fixture
95
- def extract_3D_info(tmp_path):
96
- info = {}
97
- info["name"] = "TestSubject"
98
- info["results_dir"] = os.path.join(tmp_path, info["name"])
99
- return info
100
-
101
-
102
- @pytest.fixture
103
- def extract_3D_folderinfo():
104
- folderinfo = {}
105
- folderinfo["root_dir"] = "tests/test_data/universal3D_data/test_data/"
106
- folderinfo["sctable_filename"] = "SC Latency Table"
107
- folderinfo["postname_string"] = ""
108
- return folderinfo
109
-
110
-
111
- @pytest.fixture
112
- def extract_3D_cfg():
113
- cfg = {}
114
- cfg["sampling_rate"] = 100
115
- cfg["dont_show_plots"] = True
116
- cfg["y_acceleration"] = True
117
- cfg["angular_acceleration"] = True
118
- cfg["bin_num"] = 25
119
- cfg["plot_SE"] = True
120
- cfg["standardise_z_at_SC_level"] = True
121
- cfg["standardise_z_to_a_joint"] = False
122
- cfg["z_standardisation_joint"] = ["Midfoot, left"]
123
- cfg["plot_joint_number"] = 7
124
- cfg["legend_outside"] = True
125
- cfg["flip_gait_direction"] = False
126
- cfg["color_palette"] = "viridis"
127
- cfg["analyse_average_y"] = False
128
- cfg["standardise_y_coordinates"] = True
129
- cfg["y_standardisation_joint"] = ["Midfoot, left"]
130
- cfg["coordinate_standardisation_xls"] = ""
131
- cfg["joints"] = ["Midfoot", "Ankle", "Knee", "Hip", "Pelvis "]
132
- cfg["angles"] = {
133
- "name": ["Ankle", "Knee", "Hip"],
134
- "lower_joint": ["Midfoot", "Ankle", "Knee"],
135
- "upper_joint": ["Knee", "Hip", "Pelvis "],
136
- }
137
- return cfg
138
-
139
-
140
- # %% ................................. tests .........................................
141
-
142
-
143
- def test_compute_angle():
144
- # Test case 1: Basic case
145
- joint1 = [0, 0]
146
- joint2 = [1, 0]
147
- joint3 = [0, 1]
148
- expected_angle = 90
149
- result, _ = compute_angle(joint1, joint2, joint3)
150
- assert math.isclose(result, expected_angle)
151
- # Test case 2: two joints are equal - this won't happen in autogaita because of the
152
- # test in extract_stepcycles but I want to make sure that the function returns
153
- # broken=True correctly
154
- joint1 = [5, 5]
155
- joint2 = [2, 2]
156
- joint3 = [2, 2]
157
- expected_angle = None
158
- result, broken = compute_angle(joint1, joint2, joint3)
159
- assert result == 0
160
- assert broken is True
161
-
162
-
163
- def test_write_angle_warning(extract_2D_cfg, extract_2D_info):
164
- # prep: remove existing Issues.txt
165
- results_dir = extract_2D_info["results_dir"]
166
- if not os.path.exists(results_dir):
167
- os.makedirs(results_dir)
168
- issues_path = os.path.join(results_dir, "Issues.txt")
169
- if os.path.exists(issues_path):
170
- os.remove(issues_path)
171
- # prep: more vars
172
- step = pd.DataFrame()
173
- step["Time"] = [0.1, 0.2, 0.3]
174
- step["dummy_coord"] = [1, 2, 3] # need this too otherwise stuff breaks
175
- angles = extract_2D_cfg["angles"]
176
- a = 0
177
- broken_angle_idxs = [0, 2]
178
- # run
179
- write_angle_warning(step, a, angles, broken_angle_idxs, extract_2D_info)
180
- # assert
181
- with open(issues_path, "r") as f:
182
- issues = f.read()
183
- assert (
184
- "Angle: Ankle" in issues # bc. of extract_2D_cfg
185
- and "Lower Joint: Hind paw tao" in issues
186
- and "Upper Joint: Knee" in issues
187
- and "Cycle-time: 0.1-0.3s" in issues
188
- )
189
- # run again - test legname works as expected
190
- os.remove(issues_path) # first remove previous textfile
191
- write_angle_warning(
192
- step, a, angles, broken_angle_idxs, extract_2D_info, legname="left"
193
- )
194
- with open(issues_path, "r") as f:
195
- issues = f.read()
196
- assert "Leg: left" in issues
197
-
198
-
199
- def test_correct_coordinate_standardisation(
200
- extract_2D_info,
201
- extract_2D_folderinfo,
202
- extract_2D_cfg,
203
- extract_3D_info,
204
- extract_3D_folderinfo,
205
- extract_3D_cfg,
206
- ):
207
- for tracking_software in ["DLC", "Universal 3D"]:
208
- # prep vars
209
- if tracking_software == "DLC":
210
- info = extract_2D_info
211
- folderinfo = extract_2D_folderinfo
212
- cfg = extract_2D_cfg
213
- else:
214
- info = extract_3D_info
215
- folderinfo = extract_3D_folderinfo
216
- cfg = extract_3D_cfg
217
- # run respective some_prep functions to get dfs
218
- if tracking_software == "DLC":
219
- # unstandardised data
220
- cfg["coordinate_standardisation_xls"] = ""
221
- unstandardised_data = some_prep_2D(tracking_software, info, folderinfo, cfg)
222
- # standardised data
223
- cfg["coordinate_standardisation_xls"] = (
224
- "tests/test_data/utils/Correct DLC CoordStand Table.xlsx"
225
- )
226
- standardised_data = some_prep_2D(tracking_software, info, folderinfo, cfg)
227
- elif tracking_software == "Universal 3D":
228
- # unstandardised data
229
- cfg["coordinate_standardisation_xls"] = ""
230
- unstandardised_data = some_prep_3D(info, folderinfo, cfg)[0] # tuple!
231
- # standardised data
232
- cfg["coordinate_standardisation_xls"] = (
233
- "tests/test_data/utils/Correct Universal 3D CoordStand Table.xlsx"
234
- )
235
- standardised_data, global_Y_max = some_prep_3D(info, folderinfo, cfg)
236
- # revert standardisation
237
- reverted_data = standardised_data.copy()
238
- standardisation_df = pd.read_excel(
239
- cfg["coordinate_standardisation_xls"]
240
- ).astype(str)
241
- if tracking_software == "DLC":
242
- condition = (standardisation_df["ID"] == str(info["mouse_num"])) & (
243
- standardisation_df["Run"] == str(info["run_num"])
244
- )
245
- elif tracking_software == "Universal 3D":
246
- condition = standardisation_df["ID"] == info["name"]
247
- standardisation_value = float(
248
- standardisation_df.loc[condition, "Standardisation Value"]
249
- )
250
- if tracking_software == "DLC":
251
- cols_to_revert = [
252
- col
253
- for col in reverted_data.columns
254
- if (not col.endswith("likelihood"))
255
- and any([joint in col for joint in cfg["hind_joints"]])
256
- ]
257
- elif tracking_software == "Universal 3D":
258
- cols_to_revert = [
259
- col
260
- for col in reverted_data.columns
261
- if any([joint in col for joint in cfg["joints"]])
262
- ]
263
- reverted_data[cols_to_revert] *= standardisation_value
264
-
265
- # compare dataframes
266
- pd.testing.assert_frame_equal(
267
- reverted_data, unstandardised_data, check_exact=False, check_dtype=False
268
- )
269
-
270
-
271
- def test_angles_are_unaffected_by_coordinate_standardisation(
272
- extract_2D_info, extract_2D_folderinfo, extract_2D_cfg
273
- ):
274
- # prep: run dlc_main's first 3 steps to get dfs with angles
275
- # 1) for unstandardised data
276
- data = some_prep_2D("DLC", extract_2D_info, extract_2D_folderinfo, extract_2D_cfg)
277
- all_cycles = extract_stepcycles(
278
- "DLC", data, extract_2D_info, extract_2D_folderinfo, extract_2D_cfg
279
- )
280
- unstandardised_results = analyse_and_export_stepcycles(
281
- data, all_cycles, extract_2D_info, extract_2D_cfg
282
- )
283
- # 2) for standardised data
284
- extract_2D_cfg["coordinate_standardisation_xls"] = (
285
- "autogaita/resources/Coordinate Standardisation Table Template.xlsx"
286
- )
287
- data = some_prep_2D("DLC", extract_2D_info, extract_2D_folderinfo, extract_2D_cfg)
288
- all_cycles = extract_stepcycles(
289
- "DLC", data, extract_2D_info, extract_2D_folderinfo, extract_2D_cfg
290
- )
291
- standardised_results = analyse_and_export_stepcycles(
292
- data, all_cycles, extract_2D_info, extract_2D_cfg
293
- )
294
- # compare angles
295
- cols_to_compare = [
296
- col
297
- for col in unstandardised_results["average_data"].columns
298
- if col.endswith("Angle")
299
- ]
300
- pdt.assert_frame_equal(
301
- unstandardised_results["average_data"][cols_to_compare],
302
- standardised_results["average_data"][cols_to_compare],
303
- )
304
-
305
-
306
- # Parameterized test for error cases
307
- @pytest.mark.parametrize(
308
- "xls_path, expected_error",
309
- [
310
- (
311
- "autogaita/resources/This CoordStand Table is Missing.xlsx",
312
- "No coordinate standardisation xls file found at:",
313
- ),
314
- (
315
- "tests/test_data/utils/This CoordStand Table has wrong columns.xlsx",
316
- "does not have the correct column names",
317
- ),
318
- (
319
- "tests/test_data/utils/This CoordStand Table has wrong Run.xlsx",
320
- "Unable to find",
321
- ),
322
- (
323
- "tests/test_data/utils/This CoordStand Table has multiple Names.xlsx",
324
- "Found multiple entries for",
325
- ),
326
- (
327
- "tests/test_data/utils/This CoordStand Table doesn't have a float as standval.xlsx",
328
- "Unable to convert standardisation value for",
329
- ),
330
- (
331
- "tests/test_data/utils/This CoordStand Table has a value smaller than 1.xlsx",
332
- "smaller than 1!",
333
- ),
334
- ],
335
- )
336
- def test_standardisation_xls_error_cases(
337
- extract_2D_info, extract_2D_folderinfo, extract_2D_cfg, xls_path, expected_error
338
- ):
339
- # prep: remove existing Issues.txt
340
- results_dir = extract_2D_info["results_dir"]
341
- issues_path = os.path.join(results_dir, "Issues.txt")
342
- if os.path.exists(issues_path):
343
- os.remove(issues_path)
344
-
345
- # set the xls path in the config & run some_prep which will run the standardisation
346
- extract_2D_cfg["coordinate_standardisation_xls"] = xls_path
347
- with pytest.raises(Exception):
348
- data = some_prep_2D(
349
- "DLC", extract_2D_info, extract_2D_folderinfo, extract_2D_cfg
350
- )
351
-
352
- # assert the error message - inform about what error failed if it did
353
- with open(issues_path, "r") as f:
354
- issues = f.read()
355
- assert (
356
- expected_error in issues
357
- ), f"Expected error '{expected_error}' not found in Issues.txt"
358
-
359
-
360
- def test_angle_joints_not_in_joints(
361
- extract_2D_info, extract_2D_folderinfo, extract_2D_cfg
362
- ):
363
- # prep cfg stuff
364
- cfg = extract_2D_cfg.copy()
365
- cfg["coordinate_standardisation_xls"] = (
366
- "tests/test_data/utils/Correct DLC CoordStand Table.xlsx"
367
- )
368
- cfg["hind_joints"] = ["Ankle", "Knee", "Hip"]
369
- cfg["angles"] = { # hind paw is to be removed (not in cfg["joints"]!)
370
- "name": ["Hind paw tao", "Knee", "Knee", "Knee"],
371
- "lower_joint": ["Ankle", "Hind paw tao", "Ankle", "Ankle"],
372
- "upper_joint": ["Hip", "Hip", "Hind paw tao", "Hip"],
373
- }
374
- # prep: remove existing Issues.txt
375
- results_dir = extract_2D_info["results_dir"]
376
- issues_path = os.path.join(results_dir, "Issues.txt")
377
- if os.path.exists(issues_path):
378
- os.remove(issues_path)
379
- # run (not just some prep, because we want the cfg, too)
380
- data = some_prep_2D("DLC", extract_2D_info, extract_2D_folderinfo, cfg)
381
- data, cfg = standardise_primary_joint_coordinates(data, "DLC", extract_2D_info, cfg)
382
- # assert error
383
- with open(issues_path, "r") as f:
384
- issues = f.read()
385
- assert "We will update your cfg (!)" in issues
386
- # assert updated cfg
387
- assert cfg["angles"] == {
388
- "name": ["Knee "],
389
- "lower_joint": ["Ankle "],
390
- "upper_joint": ["Hip "],
391
- }
392
-
393
-
394
- def test_define_bins_longer_trial():
395
- # triallength > bin_num: should return a list of lists covering all indices
396
- triallength = 100
397
- bin_num = 25
398
- bins = define_bins(triallength, bin_num)
399
- assert isinstance(bins, list)
400
- assert len(bins) == bin_num
401
- # each element should be a list of indices
402
- assert all(isinstance(b, list) for b in bins)
403
- flattened = [i for sub in bins for i in sub]
404
- assert set(flattened) == set(range(triallength))
405
- assert min(flattened) == 0
406
- assert max(flattened) == triallength - 1
407
- # check indices are correct for moving averages
408
- triallength = 8
409
- bin_num = 3
410
- bins = define_bins(triallength, bin_num)
411
- assert bins == [[0, 1, 2], [3, 4, 5], [6, 7]]
412
-
413
-
414
- def test_define_bins_shorter_trial():
415
- # triallength < bin_num: should return an array (or list) of length bin_num
416
- # with values in the range [0, triallength-1] and max == triallength-1
417
- triallength = 10
418
- bin_num = 25
419
- bins = define_bins(triallength, bin_num)
420
- # allow either numpy array or list-like
421
- bins_list = list(bins)
422
- assert len(bins_list) == bin_num
423
- assert all(0 <= v <= (triallength - 1) for v in bins_list)
424
- assert max(bins_list) == triallength - 1
425
- assert min(bins_list) == 0
426
- # check that values are spaced evenly across the trial
427
- triallength = 5
428
- bin_num = 12
429
- bins = define_bins(triallength, bin_num)
430
- assert bins == [0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 4, 4]
431
-
432
-
433
- def test_define_bins_equal_length():
434
- # triallength == bin_num: should return a list of ints equal to range(triallength)
435
- triallength = 25
436
- bin_num = 25
437
- bins = define_bins(triallength, bin_num)
438
- assert isinstance(bins, list)
439
- assert len(bins) == bin_num
440
- # elements should be ints 0..triallength-1
441
- assert all(isinstance(b, (int, np.integer)) for b in bins)
442
- assert bins == list(range(triallength))