autogaita 1.1.0__tar.gz → 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. {autogaita-1.1.0 → autogaita-1.2.0}/PKG-INFO +1 -1
  2. {autogaita-1.1.0 → autogaita-1.2.0}/README.md +1 -1
  3. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/batchrun_scripts/dlc_multirun.py +1 -0
  4. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/batchrun_scripts/dlc_singlerun.py +4 -1
  5. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/batchrun_scripts/sleap_singlerun.py +1 -0
  6. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/batchrun_scripts/universal3D_multirun.py +1 -0
  7. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/batchrun_scripts/universal3D_singlerun.py +1 -0
  8. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/common2D/common2D_1_preparation.py +26 -7
  9. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/common2D/common2D_2_sc_extraction.py +8 -4
  10. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/common2D/common2D_utils.py +44 -2
  11. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/dlc/dlc_main.py +1 -1
  12. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/common2D_advanced_config_gui.py +25 -12
  13. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/common2D_gui_constants.py +1 -0
  14. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/dlc_gui_config.json +1 -0
  15. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/gui_utils.py +6 -6
  16. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/sleap_gui_config.json +1 -0
  17. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/universal3D_gui.py +24 -11
  18. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/universal3D_gui_config.json +1 -0
  19. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/resources/utils.py +154 -1
  20. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/sleap/sleap_main.py +1 -1
  21. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/universal3D/universal3D_1_preparation.py +17 -4
  22. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita.egg-info/PKG-INFO +1 -1
  23. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita.egg-info/SOURCES.txt +2 -1
  24. {autogaita-1.1.0 → autogaita-1.2.0}/setup.py +1 -1
  25. {autogaita-1.1.0 → autogaita-1.2.0}/tests/test_common2D_unit_1_preparation.py +1 -0
  26. {autogaita-1.1.0 → autogaita-1.2.0}/tests/test_common2D_unit_2_sc_extraction.py +38 -9
  27. {autogaita-1.1.0 → autogaita-1.2.0}/tests/test_common2D_unit_3_analysis.py +4 -1
  28. {autogaita-1.1.0 → autogaita-1.2.0}/tests/test_dlc_approval.py +1 -0
  29. {autogaita-1.1.0 → autogaita-1.2.0}/tests/test_dlc_unit_1_preparation.py +1 -0
  30. {autogaita-1.1.0 → autogaita-1.2.0}/tests/test_universal3D_approval.py +1 -0
  31. {autogaita-1.1.0 → autogaita-1.2.0}/tests/test_universal3D_unit_3_analysis.py +1 -0
  32. autogaita-1.2.0/tests/test_utils.py +297 -0
  33. {autogaita-1.1.0 → autogaita-1.2.0}/LICENSE +0 -0
  34. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/__init__.py +0 -0
  35. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/__main__.py +0 -0
  36. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/batchrun_scripts/__init__.py +0 -0
  37. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/batchrun_scripts/group_dlcrun.py +0 -0
  38. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/batchrun_scripts/group_dlcrun_forpaper.py +0 -0
  39. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/batchrun_scripts/group_universal3Drun.py +0 -0
  40. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/common2D/__init__.py +0 -0
  41. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/common2D/common2D_3_analysis.py +0 -0
  42. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/common2D/common2D_4_plots.py +0 -0
  43. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/common2D/common2D_constants.py +0 -0
  44. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/dlc/__init__.py +0 -0
  45. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/group/__init__.py +0 -0
  46. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/group/group_1_preparation.py +0 -0
  47. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/group/group_2_data_processing.py +0 -0
  48. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/group/group_3_PCA.py +0 -0
  49. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/group/group_4_stats.py +0 -0
  50. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/group/group_5_plots.py +0 -0
  51. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/group/group_constants.py +0 -0
  52. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/group/group_main.py +0 -0
  53. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/group/group_utils.py +0 -0
  54. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/__init__.py +0 -0
  55. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/common2D_columninfo_gui.py +0 -0
  56. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/common2D_gui_utils.py +0 -0
  57. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/common2D_main_gui.py +0 -0
  58. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/common2D_run_and_done_gui.py +0 -0
  59. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/dlc_gui.py +0 -0
  60. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/first_level_gui_utils.py +0 -0
  61. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/gaita_widgets.py +0 -0
  62. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/group_gui.py +0 -0
  63. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/group_gui_config.json +0 -0
  64. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/gui_constants.py +0 -0
  65. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/main_gui.py +0 -0
  66. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/gui/sleap_gui.py +0 -0
  67. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/resources/__init__.py +0 -0
  68. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/resources/constants.py +0 -0
  69. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/resources/icon.icns +0 -0
  70. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/resources/icon.ico +0 -0
  71. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/resources/logo.png +0 -0
  72. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/resources/pic_to_demo_for_repo.png +0 -0
  73. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/sleap/__init__.py +0 -0
  74. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/universal3D/__init__.py +0 -0
  75. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/universal3D/universal3D_2_sc_extraction.py +0 -0
  76. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/universal3D/universal3D_3_analysis.py +0 -0
  77. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/universal3D/universal3D_4_plots.py +0 -0
  78. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/universal3D/universal3D_constants.py +0 -0
  79. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/universal3D/universal3D_datafile_preparation.py +0 -0
  80. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/universal3D/universal3D_main.py +0 -0
  81. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita/universal3D/universal3D_utils.py +0 -0
  82. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita.egg-info/dependency_links.txt +0 -0
  83. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita.egg-info/requires.txt +0 -0
  84. {autogaita-1.1.0 → autogaita-1.2.0}/autogaita.egg-info/top_level.txt +0 -0
  85. {autogaita-1.1.0 → autogaita-1.2.0}/setup.cfg +0 -0
  86. {autogaita-1.1.0 → autogaita-1.2.0}/tests/__init__.py +0 -0
  87. {autogaita-1.1.0 → autogaita-1.2.0}/tests/test_group_approval.py +0 -0
  88. {autogaita-1.1.0 → autogaita-1.2.0}/tests/test_group_unit.py +0 -0
  89. {autogaita-1.1.0 → autogaita-1.2.0}/tests/test_universal3D_unit_1_preparation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: autogaita
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: Automatic Gait Analysis in Python. A toolbox to streamline and standardise the analysis of kinematics across species after ML-based body posture tracking. Despite being optimised for gait analyses, AutoGaitA has the potential to be used for any kind of kinematic analysis.
5
5
  Home-page: https://github.com/mahan-hosseini/AutoGaitA/
6
6
  Author: Mahan Hosseini
@@ -11,7 +11,7 @@
11
11
 
12
12
  # Automated Gait Analysis in Python 🐸
13
13
 
14
- - AutoGaitA simplifies, accelerates, and standardises gait analyses after body posture tracking in 2D with [DeepLabCut](https://github.com/DeepLabCut/DeepLabCut) and [SLEAP](https://github.com/talmolab/sleap) or marker-based (such as [Simi Motion](http://www.simi.com/en/products/movement-analysis/simi-motion-2d3d.html?type=rss%2F)) as well as marker-less methods for obtaining 3D coordinates.
14
+ - AutoGaitA simplifies, accelerates, and standardises gait analyses (as well as the analysis of other rhythmic behaviours) after body posture tracking in 2D with [DeepLabCut](https://github.com/DeepLabCut/DeepLabCut) and [SLEAP](https://github.com/talmolab/sleap) or marker-based as well as marker-less (such as [Simi Motion](http://www.simi.com/en/products/movement-analysis/simi-motion-2d3d.html?type=rss%2F)) methods for obtaining 3D coordinates.
15
15
  - AutoGaitA's first-level tools provide a wide range of automated kinematic analyses for each input video and AutoGaitA Group allows the comparison of up to six groups.
16
16
  - AutoGaitA enables comparisons to be made across experimental conditions, species, disease states or genotypes.
17
17
  - Despite being developed with gait data, AutoGaitA can be utilised for the analysis of any motor behaviour.
@@ -43,6 +43,7 @@ def dlc_multirun():
43
43
  cfg["analyse_average_x"] = True
44
44
  cfg["standardise_x_coordinates"] = True
45
45
  cfg["x_standardisation_joint"] = ["Hind paw tao"]
46
+ cfg["coordinate_standardisation_xls"] = ""
46
47
  cfg["results_dir"] = ""
47
48
  cfg["hind_joints"] = ["Hind paw tao", "Ankle", "Knee", "Hip", "Iliac Crest"]
48
49
  cfg["fore_joints"] = [
@@ -23,7 +23,7 @@ def dlc_singlerun():
23
23
  cfg = {}
24
24
  cfg["sampling_rate"] = 100 # base cfg
25
25
  cfg["subtract_beam"] = True
26
- cfg["dont_show_plots"] = False
26
+ cfg["dont_show_plots"] = True
27
27
  cfg["convert_to_mm"] = True
28
28
  cfg["pixel_to_mm_ratio"] = 3.76
29
29
  cfg["x_sc_broken_threshold"] = 200 # optional cfg
@@ -44,6 +44,9 @@ def dlc_singlerun():
44
44
  cfg["analyse_average_x"] = True
45
45
  cfg["standardise_x_coordinates"] = True
46
46
  cfg["x_standardisation_joint"] = ["Hind paw tao"]
47
+ cfg["coordinate_standardisation_xls"] = (
48
+ "/Users/mahan/sciebo/PythonCode/gaita_repo/autogaita/resources/Coordinate Standardisation Table Template.xlsx"
49
+ )
47
50
  cfg["hind_joints"] = ["Hind paw tao", "Ankle", "Knee", "Hip", "Iliac Crest"]
48
51
  cfg["fore_joints"] = [
49
52
  "Front paw tao ",
@@ -49,6 +49,7 @@ def sleap_singlerun():
49
49
  cfg["analyse_average_x"] = False
50
50
  cfg["standardise_x_coordinates"] = False
51
51
  cfg["x_standardisation_joint"] = ["Midfoot"]
52
+ cfg["coordinate_standardisation_xls"] = ""
52
53
  cfg["hind_joints"] = ["Midfoot", "Ankle", "Knee", "Hip"]
53
54
  cfg["fore_joints"] = []
54
55
  cfg["beam_col_left"] = [] # list of len == 1
@@ -34,6 +34,7 @@ def universal3D_multirun():
34
34
  cfg["analyse_average_y"] = True
35
35
  cfg["standardise_y_coordinates"] = True
36
36
  cfg["y_standardisation_joint"] = ["Foot"]
37
+ cfg["coordinate_standardisation_xls"] = ""
37
38
  cfg["joints"] = ["Midfoot", "Ankle", "Knee", "Hip", "Pelvis", "Shoulder", "Neck"]
38
39
  cfg["angles"] = {
39
40
  "name": ["Ankle", "Knee"],
@@ -33,6 +33,7 @@ def universal3D_singlerun():
33
33
  cfg["analyse_average_y"] = True
34
34
  cfg["standardise_y_coordinates"] = True
35
35
  cfg["y_standardisation_joint"] = ["Midfoot, left"]
36
+ cfg["coordinate_standardisation_xls"] = ""
36
37
  cfg["joints"] = [
37
38
  # "R1-ThCx",
38
39
  "Midfoot",
@@ -1,5 +1,8 @@
1
1
  # %% imports
2
- from autogaita.resources.utils import write_issues_to_textfile
2
+ from autogaita.resources.utils import (
3
+ write_issues_to_textfile,
4
+ standardise_primary_joint_coordinates,
5
+ )
3
6
  from autogaita.common2D.common2D_constants import FILE_ID_STRING_ADDITIONS
4
7
  import os
5
8
  import shutil
@@ -48,6 +51,7 @@ def some_prep(tracking_software, info, folderinfo, cfg):
48
51
  analyse_average_x = cfg["analyse_average_x"]
49
52
  standardise_x_coordinates = cfg["standardise_x_coordinates"]
50
53
  standardise_y_to_a_joint = cfg["standardise_y_to_a_joint"]
54
+ coordinate_standardisation_xls = cfg["coordinate_standardisation_xls"]
51
55
 
52
56
  # ............................. move data ........................................
53
57
  # => slightly different for DLC or SLEAP (see local functions below)
@@ -198,6 +202,7 @@ def some_prep(tracking_software, info, folderinfo, cfg):
198
202
  "x_standardisation_joint": x_standardisation_joint,
199
203
  "standardise_y_to_a_joint": standardise_y_to_a_joint,
200
204
  "y_standardisation_joint": y_standardisation_joint,
205
+ "coordinate_standardisation_xls": coordinate_standardisation_xls,
201
206
  "hind_joints": hind_joints,
202
207
  "fore_joints": fore_joints,
203
208
  "angles": angles,
@@ -236,7 +241,7 @@ def some_prep(tracking_software, info, folderinfo, cfg):
236
241
  )
237
242
  print(cols_are_weird_message)
238
243
  write_issues_to_textfile(cols_are_weird_message, info)
239
- # if wanted: fix that deeplabcut inverses y
244
+ # if wanted: fix that deeplabcut & SLEAP inverse y
240
245
  if invert_y_axis:
241
246
  for col in data.columns:
242
247
  if col.endswith(" y"):
@@ -250,11 +255,6 @@ def some_prep(tracking_software, info, folderinfo, cfg):
250
255
  else:
251
256
  y_min = data[y_cols].min().min()
252
257
  data[y_cols] -= y_min
253
- # convert pixels to millimeters
254
- if convert_to_mm:
255
- for column in data.columns:
256
- if not column.endswith("likelihood"):
257
- data[column] = data[column] / pixel_to_mm_ratio
258
258
  # quick warning if cfg is set to not flip gait direction but to standardise x
259
259
  if not flip_gait_direction and standardise_x_coordinates:
260
260
  message = (
@@ -295,6 +295,25 @@ def some_prep(tracking_software, info, folderinfo, cfg):
295
295
  # reorder the columns we added
296
296
  cols = [TIME_COL, "Flipped"]
297
297
  data = data[cols + [c for c in data.columns if c not in cols]]
298
+ # ------------------------------------------------------------------------
299
+ # IMPORTANT
300
+ # Next two things must be the last that are done in this function, since
301
+ # joint-standardisation must be done after beam-subtraction & non-beam-height-stand
302
+ # and pixel-standardisation must be done after joint-standardisation!
303
+ # ------------------------------------------------------------------------
304
+ # 1) standardise all primary joint (!) coordinates
305
+ # => all dimensions are divided by a fixed user-provided value
306
+ # => note this function has proper errors raised if things should be wrongly
307
+ # configured by user!
308
+ if len(coordinate_standardisation_xls) > 0:
309
+ data, cfg = standardise_primary_joint_coordinates(
310
+ data, tracking_software, info, cfg
311
+ )
312
+ # 2) convert pixels to millimeters
313
+ if convert_to_mm:
314
+ for column in data.columns:
315
+ if column.endswith((" x", " y")): # if tuple: endswith any of these
316
+ data[column] = data[column] / pixel_to_mm_ratio
298
317
  return data
299
318
 
300
319
 
@@ -4,7 +4,8 @@ from autogaita.common2D.common2D_utils import (
4
4
  check_cycle_out_of_bounds,
5
5
  check_cycle_duplicates,
6
6
  check_cycle_order,
7
- check_tracking,
7
+ check_tracking_xy_thresholds,
8
+ check_tracking_SLEAP_nans,
8
9
  handle_issues,
9
10
  )
10
11
  import os
@@ -23,7 +24,7 @@ from autogaita.common2D.common2D_constants import (
23
24
  # %% workflow step #2 - SC extraction (reading user-provided SC Table)
24
25
 
25
26
 
26
- def extract_stepcycles(data, info, folderinfo, cfg):
27
+ def extract_stepcycles(tracking_software, data, info, folderinfo, cfg):
27
28
  """Read XLS file with SC annotations, find correct row & return all_cycles"""
28
29
 
29
30
  # ............................... preparation ....................................
@@ -212,6 +213,9 @@ def extract_stepcycles(data, info, folderinfo, cfg):
212
213
  all_cycles = check_cycle_duplicates(all_cycles)
213
214
  # check if user input progressively later latencies
214
215
  all_cycles = check_cycle_order(all_cycles, info)
215
- # check if tracking broke for any SCs - if so remove them
216
- all_cycles = check_tracking(data, info, all_cycles, cfg)
216
+ # check if tracking broke for any SCs using user-provided x and y thresholds
217
+ all_cycles = check_tracking_xy_thresholds(data, info, all_cycles, cfg)
218
+ # for SLEAP - check if there were any NaNs in any joints/angle-joints in SCs
219
+ if tracking_software == "SLEAP":
220
+ all_cycles = check_tracking_SLEAP_nans(data, info, all_cycles, cfg)
217
221
  return all_cycles
@@ -210,7 +210,7 @@ def check_cycle_order(all_cycles, info):
210
210
  return clean_cycles
211
211
 
212
212
 
213
- def check_tracking(data, info, all_cycles, cfg):
213
+ def check_tracking_xy_thresholds(data, info, all_cycles, cfg):
214
214
  """Check if any x/y column of any joint has broken datapoints"""
215
215
  # unpack
216
216
  convert_to_mm = cfg["convert_to_mm"]
@@ -241,7 +241,49 @@ def check_tracking(data, info, all_cycles, cfg):
241
241
  exclude_this_cycle = True
242
242
  if exclude_this_cycle == True:
243
243
  this_message = (
244
- "\n...excluding SC #" + str(c + 1) + " - DLC tracking failed!"
244
+ "\n...excluding SC #"
245
+ + str(c + 1)
246
+ + " - Tracking failed (coordinate-jump larger than x/y threshold)!"
247
+ )
248
+ print(this_message)
249
+ write_issues_to_textfile(this_message, info)
250
+ else:
251
+ if clean_cycles == None:
252
+ clean_cycles = [cycle] # also makes a 2xscs list of lists
253
+ else:
254
+ clean_cycles.append(cycle)
255
+ return clean_cycles
256
+
257
+
258
+ def check_tracking_SLEAP_nans(data, info, all_cycles, cfg):
259
+ """In SLEAP if tracking fails it generates NaNs - make sure we don't have those in any SC in any joint or angle-joint"""
260
+ # unpack
261
+ hind_joints = cfg["hind_joints"]
262
+ angles = cfg["angles"]
263
+ # all joints to test for NaNs
264
+ all_joints = hind_joints
265
+ for key in angles.keys():
266
+ all_joints += angles[key]
267
+ # columns to check
268
+ columns = []
269
+ for joint in all_joints:
270
+ columns.append(joint + "x")
271
+ columns.append(joint + "y")
272
+ # check for NaNs
273
+ clean_cycles = None
274
+ for c, cycle in enumerate(all_cycles):
275
+ exclude_this_cycle = False # reset
276
+ for col in columns:
277
+ this_data = data.loc[cycle[0] : cycle[1], col]
278
+ if any(this_data.isna()):
279
+ exclude_this_cycle = True
280
+ NaN_joint = col
281
+ break
282
+ if exclude_this_cycle == True:
283
+ this_message = (
284
+ "\n...excluding SC #"
285
+ + str(c + 1)
286
+ + f" - Tracking failed (NaN found at {NaN_joint})!"
245
287
  )
246
288
  print(this_message)
247
289
  write_issues_to_textfile(this_message, info)
@@ -47,7 +47,7 @@ def dlc(info, folderinfo, cfg):
47
47
  return
48
48
 
49
49
  # ......................... step-cycle extraction ................................
50
- all_cycles = extract_stepcycles(data, info, folderinfo, cfg)
50
+ all_cycles = extract_stepcycles(tracking_software, data, info, folderinfo, cfg)
51
51
  if all_cycles is None:
52
52
  handle_issues("scs_invalid", info)
53
53
  if cfg["dont_show_plots"] is False: # otherwise stuck at loading
@@ -203,6 +203,19 @@ def build_cfg_window(root, cfg, widget_cfg, root_dimensions):
203
203
  )
204
204
  invert_y_axis_box.grid(row=12, column=0, columnspan=2)
205
205
 
206
+ # Standardise all (primary) joint coordinates by a fixed decimal value
207
+ coordinate_standardisation_xls_label, coordinate_standardisation_xls_entry = (
208
+ gaita_widgets.label_and_entry_pair(
209
+ cfg_window,
210
+ "Excel file for primary-joint coordinate standardisation:",
211
+ cfg["coordinate_standardisation_xls"],
212
+ widget_cfg,
213
+ adv_cfg_textsize=True,
214
+ )
215
+ )
216
+ coordinate_standardisation_xls_label.grid(row=13, column=0, columnspan=2)
217
+ coordinate_standardisation_xls_entry.grid(row=14, column=0, columnspan=2)
218
+
206
219
  # ............................. advanced output .................................
207
220
  # advanced analysis header
208
221
  adv_cfg_output_header_label = gaita_widgets.header_label(
@@ -211,7 +224,7 @@ def build_cfg_window(root, cfg, widget_cfg, root_dimensions):
211
224
  widget_cfg,
212
225
  )
213
226
  adv_cfg_output_header_label.grid(
214
- row=13, column=0, rowspan=2, columnspan=2, sticky="nsew"
227
+ row=15, column=0, rowspan=2, columnspan=2, sticky="nsew"
215
228
  )
216
229
 
217
230
  # number of hindlimb (primary) joints to plot
@@ -222,8 +235,8 @@ def build_cfg_window(root, cfg, widget_cfg, root_dimensions):
222
235
  widget_cfg,
223
236
  adv_cfg_textsize=True,
224
237
  )
225
- plot_joint_num__label.grid(row=15, column=0, columnspan=2)
226
- plot_joint_num_entry.grid(row=16, column=0, columnspan=2)
238
+ plot_joint_num__label.grid(row=17, column=0, columnspan=2)
239
+ plot_joint_num_entry.grid(row=18, column=0, columnspan=2)
227
240
 
228
241
  # save to xls
229
242
  save_to_xls_box = gaita_widgets.checkbox(
@@ -233,7 +246,7 @@ def build_cfg_window(root, cfg, widget_cfg, root_dimensions):
233
246
  widget_cfg,
234
247
  adv_cfg_textsize=True,
235
248
  )
236
- save_to_xls_box.grid(row=17, column=0, columnspan=2)
249
+ save_to_xls_box.grid(row=19, column=0, columnspan=2)
237
250
 
238
251
  # plot SE
239
252
  plot_SE_box = gaita_widgets.checkbox(
@@ -243,7 +256,7 @@ def build_cfg_window(root, cfg, widget_cfg, root_dimensions):
243
256
  widget_cfg,
244
257
  adv_cfg_textsize=True,
245
258
  )
246
- plot_SE_box.grid(row=18, column=0, columnspan=2)
259
+ plot_SE_box.grid(row=20, column=0, columnspan=2)
247
260
 
248
261
  # color palette
249
262
  color_palette_string = "Choose figures' color palette"
@@ -252,7 +265,7 @@ def build_cfg_window(root, cfg, widget_cfg, root_dimensions):
252
265
  text=color_palette_string,
253
266
  font=(TEXT_FONT_NAME, ADV_CFG_TEXT_FONT_SIZE),
254
267
  )
255
- color_palette_label.grid(row=19, column=0, columnspan=2)
268
+ color_palette_label.grid(row=21, column=0, columnspan=2)
256
269
  color_palette_entry = ctk.CTkOptionMenu(
257
270
  cfg_window,
258
271
  values=COLOR_PALETTES_LIST,
@@ -262,7 +275,7 @@ def build_cfg_window(root, cfg, widget_cfg, root_dimensions):
262
275
  button_hover_color=HOVER_COLOR,
263
276
  font=(TEXT_FONT_NAME, ADV_CFG_TEXT_FONT_SIZE),
264
277
  )
265
- color_palette_entry.grid(row=20, column=0, columnspan=2)
278
+ color_palette_entry.grid(row=22, column=0, columnspan=2)
266
279
 
267
280
  # legend outside
268
281
  legend_outside_checkbox = gaita_widgets.checkbox(
@@ -272,18 +285,18 @@ def build_cfg_window(root, cfg, widget_cfg, root_dimensions):
272
285
  widget_cfg,
273
286
  adv_cfg_textsize=True,
274
287
  )
275
- legend_outside_checkbox.grid(row=21, column=0, columnspan=2)
288
+ legend_outside_checkbox.grid(row=23, column=0, columnspan=2)
276
289
 
277
290
  # results dir
278
291
  results_dir_label, results_dir_entry = gaita_widgets.label_and_entry_pair(
279
292
  cfg_window,
280
- "Save Results subfolders to directory below instead of to data's",
293
+ "Save Results subfolders to directory below instead of to data's:",
281
294
  cfg["results_dir"],
282
295
  widget_cfg,
283
296
  adv_cfg_textsize=True,
284
297
  )
285
- results_dir_label.grid(row=22, column=0, columnspan=2)
286
- results_dir_entry.grid(row=23, column=0, columnspan=2)
298
+ results_dir_label.grid(row=24, column=0, columnspan=2)
299
+ results_dir_entry.grid(row=25, column=0, columnspan=2)
287
300
 
288
301
  # done button
289
302
  adv_cfg_done_button = ctk.CTkButton(
@@ -295,7 +308,7 @@ def build_cfg_window(root, cfg, widget_cfg, root_dimensions):
295
308
  command=lambda: cfg_window.destroy(),
296
309
  )
297
310
  adv_cfg_done_button.grid(
298
- row=24, column=0, columnspan=2, rowspan=2, sticky="nsew", padx=10, pady=(10, 5)
311
+ row=26, column=0, columnspan=2, rowspan=2, sticky="nsew", padx=10, pady=(10, 5)
299
312
  )
300
313
  # maximise widgets
301
314
  cfg_window.columnconfigure(list(range(2)), weight=1, uniform="Silent_Creme")
@@ -56,6 +56,7 @@ TK_STR_VARS = [
56
56
  "plot_joint_number",
57
57
  "color_palette",
58
58
  "results_dir",
59
+ "coordinate_standardisation_xls",
59
60
  ]
60
61
  GUI_SPECIFIC_VARS = {
61
62
  "FLOAT_VARS": FLOAT_VARS,
@@ -40,6 +40,7 @@
40
40
  "color_palette": "Set2",
41
41
  "legend_outside": true,
42
42
  "results_dir": "",
43
+ "coordinate_standardisation_xls": "",
43
44
  "hind_joints": [
44
45
  "Hind paw tao",
45
46
  "Ankle",
@@ -43,9 +43,9 @@ def maximise_widgets(window):
43
43
  # .............................. change widget states ................................
44
44
 
45
45
 
46
- def change_widget_state_based_on_checkbox(cfg, key_of_checkbox, entry_to_change):
47
- """Change the state of an entry widget based on whether a checkbox is checked."""
48
- if cfg[key_of_checkbox].get() is True:
49
- entry_to_change.configure(state="normal")
50
- elif cfg[key_of_checkbox].get() is False:
51
- entry_to_change.configure(state="disabled")
46
+ def change_widget_state_based_on_checkbox(cfg, key_to_check, widget_to_change):
47
+ """Change the state of a widget based on state of another widget."""
48
+ if cfg[key_to_check].get() is True:
49
+ widget_to_change.configure(state="normal")
50
+ elif cfg[key_to_check].get() is False:
51
+ widget_to_change.configure(state="disabled")
@@ -40,6 +40,7 @@
40
40
  "color_palette": "Set2",
41
41
  "legend_outside": true,
42
42
  "results_dir": "",
43
+ "coordinate_standardisation_xls": "",
43
44
  "hind_joints": [
44
45
  "Midfoot",
45
46
  "Ankle",
@@ -71,6 +71,7 @@ TK_STR_VARS = [
71
71
  "sctable_filename",
72
72
  "postname_string",
73
73
  "color_palette",
74
+ "coordinate_standardisation_xls",
74
75
  "fileprep_root_dir", # for datafile prep window only
75
76
  "fileprep_filetype",
76
77
  "fileprep_postname_string",
@@ -696,6 +697,18 @@ def build_cfg_window(root, cfg):
696
697
  gui_utils.change_widget_state_based_on_checkbox(
697
698
  cfg, "standardise_y_coordinates", y_standardisation_joint_entry
698
699
  )
700
+ # standardise all (primary) joint coordinates by a fixed decimal value
701
+ coordinate_standardisation_xls_label, coordinate_standardisation_xls_entry = (
702
+ gaita_widgets.label_and_entry_pair(
703
+ cfg_window,
704
+ "Excel file for primary-joint coordinate standardisation:",
705
+ cfg["coordinate_standardisation_xls"],
706
+ WIDGET_CFG,
707
+ adv_cfg_textsize=True,
708
+ )
709
+ )
710
+ coordinate_standardisation_xls_label.grid(row=12, column=0, columnspan=2)
711
+ coordinate_standardisation_xls_entry.grid(row=13, column=0, columnspan=2)
699
712
 
700
713
  # ............................. advanced output .................................
701
714
  # advanced output header
@@ -703,7 +716,7 @@ def build_cfg_window(root, cfg):
703
716
  cfg_window, "Output", WIDGET_CFG
704
717
  )
705
718
  adv_cfg_output_header_label.grid(
706
- row=12, column=0, rowspan=2, columnspan=2, sticky="nsew"
719
+ row=14, column=0, rowspan=2, columnspan=2, sticky="nsew"
707
720
  )
708
721
  # number of joints to plot
709
722
  plot_joint_num_label, plot_joint_num_entry = gaita_widgets.label_and_entry_pair(
@@ -713,8 +726,8 @@ def build_cfg_window(root, cfg):
713
726
  WIDGET_CFG,
714
727
  adv_cfg_textsize=True,
715
728
  )
716
- plot_joint_num_label.grid(row=14, column=0, sticky="e")
717
- plot_joint_num_entry.grid(row=14, column=1, sticky="w")
729
+ plot_joint_num_label.grid(row=16, column=0, sticky="e")
730
+ plot_joint_num_entry.grid(row=16, column=1, sticky="w")
718
731
  # plot plots to python
719
732
  showplots_checkbox = gaita_widgets.checkbox(
720
733
  cfg_window,
@@ -723,7 +736,7 @@ def build_cfg_window(root, cfg):
723
736
  WIDGET_CFG,
724
737
  adv_cfg_textsize=True,
725
738
  )
726
- showplots_checkbox.grid(row=15, column=0, columnspan=2)
739
+ showplots_checkbox.grid(row=17, column=0, columnspan=2)
727
740
  # plot SE
728
741
  plot_SE_box = gaita_widgets.checkbox(
729
742
  cfg_window,
@@ -732,7 +745,7 @@ def build_cfg_window(root, cfg):
732
745
  WIDGET_CFG,
733
746
  adv_cfg_textsize=True,
734
747
  )
735
- plot_SE_box.grid(row=16, column=0, columnspan=2)
748
+ plot_SE_box.grid(row=18, column=0, columnspan=2)
736
749
  # color palette
737
750
  color_palette_string = "Choose figures' color palette"
738
751
  color_palette_label = ctk.CTkLabel(
@@ -740,7 +753,7 @@ def build_cfg_window(root, cfg):
740
753
  text=color_palette_string,
741
754
  font=(TEXT_FONT_NAME, ADV_CFG_TEXT_FONT_SIZE),
742
755
  )
743
- color_palette_label.grid(row=17, column=0, columnspan=2)
756
+ color_palette_label.grid(row=19, column=0, columnspan=2)
744
757
  color_palette_entry = ctk.CTkOptionMenu(
745
758
  cfg_window,
746
759
  values=COLOR_PALETTES_LIST,
@@ -750,7 +763,7 @@ def build_cfg_window(root, cfg):
750
763
  button_hover_color=HOVER_COLOR,
751
764
  font=(TEXT_FONT_NAME, ADV_CFG_TEXT_FONT_SIZE),
752
765
  )
753
- color_palette_entry.grid(row=18, column=0, columnspan=2)
766
+ color_palette_entry.grid(row=20, column=0, columnspan=2)
754
767
  # legend outside
755
768
  legend_outside_checkbox = gaita_widgets.checkbox(
756
769
  cfg_window,
@@ -759,7 +772,7 @@ def build_cfg_window(root, cfg):
759
772
  WIDGET_CFG,
760
773
  adv_cfg_textsize=True,
761
774
  )
762
- legend_outside_checkbox.grid(row=19, column=0, columnspan=2)
775
+ legend_outside_checkbox.grid(row=21, column=0, columnspan=2)
763
776
 
764
777
  # results dir
765
778
  results_dir_label, results_dir_entry = gaita_widgets.label_and_entry_pair(
@@ -769,8 +782,8 @@ def build_cfg_window(root, cfg):
769
782
  WIDGET_CFG,
770
783
  adv_cfg_textsize=True,
771
784
  )
772
- results_dir_label.grid(row=20, column=0, columnspan=2)
773
- results_dir_entry.grid(row=21, column=0, columnspan=2)
785
+ results_dir_label.grid(row=22, column=0, columnspan=2)
786
+ results_dir_entry.grid(row=23, column=0, columnspan=2)
774
787
 
775
788
  # done button
776
789
  adv_cfg_done_button = ctk.CTkButton(
@@ -782,7 +795,7 @@ def build_cfg_window(root, cfg):
782
795
  command=lambda: cfg_window.destroy(),
783
796
  )
784
797
  adv_cfg_done_button.grid(
785
- row=22, column=0, rowspan=2, columnspan=2, sticky="nsew", padx=10, pady=(10, 5)
798
+ row=24, column=0, rowspan=2, columnspan=2, sticky="nsew", padx=10, pady=(10, 5)
786
799
  )
787
800
  # maximise widgets
788
801
  cfg_window.columnconfigure(list(range(2)), weight=1, uniform="Silent_Creme")
@@ -29,6 +29,7 @@
29
29
  "color_palette": "Set2",
30
30
  "legend_outside": true,
31
31
  "results_dir": "",
32
+ "coordinate_standardisation_xls": "",
32
33
  "joints": [
33
34
  "Midfoot",
34
35
  "Ankle ",