autogaita 1.4.0__tar.gz → 1.4.1__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 (93) hide show
  1. {autogaita-1.4.0 → autogaita-1.4.1}/PKG-INFO +1 -1
  2. {autogaita-1.4.0 → autogaita-1.4.1}/README.md +9 -6
  3. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/batchrun_scripts/group_dlcrun.py +25 -26
  4. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/common2D/common2D_utils.py +21 -10
  5. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/group/group_4_stats.py +94 -180
  6. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/group/group_constants.py +1 -1
  7. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/group/group_utils.py +29 -0
  8. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/common2D_advanced_config_gui.py +29 -17
  9. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/common2D_main_gui.py +5 -1
  10. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/common2D_run_and_done_gui.py +28 -13
  11. autogaita-1.4.1/autogaita/gui/gaita_widgets.py +179 -0
  12. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/group_gui.py +49 -28
  13. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/gui_utils.py +9 -0
  14. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/universal3D_gui.py +97 -55
  15. autogaita-1.4.1/autogaita/resources/folder.png +0 -0
  16. autogaita-1.4.1/autogaita/resources/pic_to_demo_for_repo.png +0 -0
  17. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita.egg-info/PKG-INFO +1 -1
  18. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita.egg-info/SOURCES.txt +1 -0
  19. {autogaita-1.4.0 → autogaita-1.4.1}/setup.py +1 -1
  20. {autogaita-1.4.0 → autogaita-1.4.1}/tests/test_common2D_unit_1_preparation.py +17 -11
  21. {autogaita-1.4.0 → autogaita-1.4.1}/tests/test_common2D_unit_utils.py +6 -3
  22. autogaita-1.4.0/autogaita/gui/gaita_widgets.py +0 -83
  23. autogaita-1.4.0/autogaita/resources/pic_to_demo_for_repo.png +0 -0
  24. {autogaita-1.4.0 → autogaita-1.4.1}/LICENSE +0 -0
  25. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/__init__.py +0 -0
  26. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/__main__.py +0 -0
  27. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/batchrun_scripts/__init__.py +0 -0
  28. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/batchrun_scripts/dlc_multirun.py +0 -0
  29. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/batchrun_scripts/dlc_singlerun.py +0 -0
  30. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/batchrun_scripts/group_universal3Drun.py +0 -0
  31. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/batchrun_scripts/sleap_singlerun.py +0 -0
  32. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/batchrun_scripts/universal3D_multirun.py +0 -0
  33. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/batchrun_scripts/universal3D_singlerun.py +0 -0
  34. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/common2D/__init__.py +0 -0
  35. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/common2D/common2D_1_preparation.py +0 -0
  36. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/common2D/common2D_2_sc_extraction.py +0 -0
  37. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/common2D/common2D_3_analysis.py +0 -0
  38. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/common2D/common2D_4_plots.py +0 -0
  39. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/common2D/common2D_constants.py +0 -0
  40. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/dlc/__init__.py +0 -0
  41. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/dlc/dlc_main.py +0 -0
  42. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/group/__init__.py +0 -0
  43. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/group/group_1_preparation.py +0 -0
  44. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/group/group_2_data_processing.py +0 -0
  45. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/group/group_3_PCA.py +0 -0
  46. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/group/group_5_plots.py +0 -0
  47. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/group/group_main.py +0 -0
  48. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/__init__.py +0 -0
  49. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/common2D_columninfo_gui.py +0 -0
  50. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/common2D_gui_constants.py +0 -0
  51. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/common2D_gui_utils.py +0 -0
  52. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/dlc_gui.py +0 -0
  53. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/dlc_gui_config.json +0 -0
  54. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/first_level_gui_utils.py +0 -0
  55. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/group_gui_config.json +0 -0
  56. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/gui_constants.py +0 -0
  57. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/main_gui.py +0 -0
  58. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/sleap_gui.py +0 -0
  59. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/sleap_gui_config.json +0 -0
  60. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/gui/universal3D_gui_config.json +0 -0
  61. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/resources/__init__.py +0 -0
  62. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/resources/constants.py +0 -0
  63. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/resources/icon.icns +0 -0
  64. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/resources/icon.ico +0 -0
  65. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/resources/logo.png +0 -0
  66. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/resources/utils.py +0 -0
  67. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/sleap/__init__.py +0 -0
  68. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/sleap/sleap_main.py +0 -0
  69. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/universal3D/__init__.py +0 -0
  70. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/universal3D/universal3D_1_preparation.py +0 -0
  71. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/universal3D/universal3D_2_sc_extraction.py +0 -0
  72. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/universal3D/universal3D_3_analysis.py +0 -0
  73. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/universal3D/universal3D_4_plots.py +0 -0
  74. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/universal3D/universal3D_constants.py +0 -0
  75. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/universal3D/universal3D_datafile_preparation.py +0 -0
  76. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/universal3D/universal3D_main.py +0 -0
  77. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita/universal3D/universal3D_utils.py +0 -0
  78. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita.egg-info/dependency_links.txt +0 -0
  79. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita.egg-info/requires.txt +0 -0
  80. {autogaita-1.4.0 → autogaita-1.4.1}/autogaita.egg-info/top_level.txt +0 -0
  81. {autogaita-1.4.0 → autogaita-1.4.1}/setup.cfg +0 -0
  82. {autogaita-1.4.0 → autogaita-1.4.1}/tests/__init__.py +0 -0
  83. {autogaita-1.4.0 → autogaita-1.4.1}/tests/test_common2D_unit_2_sc_extraction.py +0 -0
  84. {autogaita-1.4.0 → autogaita-1.4.1}/tests/test_common2D_unit_3_analysis.py +0 -0
  85. {autogaita-1.4.0 → autogaita-1.4.1}/tests/test_dlc_approval.py +0 -0
  86. {autogaita-1.4.0 → autogaita-1.4.1}/tests/test_dlc_unit_1_preparation.py +0 -0
  87. {autogaita-1.4.0 → autogaita-1.4.1}/tests/test_group_approval.py +0 -0
  88. {autogaita-1.4.0 → autogaita-1.4.1}/tests/test_group_unit.py +0 -0
  89. {autogaita-1.4.0 → autogaita-1.4.1}/tests/test_universal3D_approval.py +0 -0
  90. {autogaita-1.4.0 → autogaita-1.4.1}/tests/test_universal3D_unit_1_preparation.py +0 -0
  91. {autogaita-1.4.0 → autogaita-1.4.1}/tests/test_universal3D_unit_2_sc_extraction.py +0 -0
  92. {autogaita-1.4.0 → autogaita-1.4.1}/tests/test_universal3D_unit_3_analysis.py +0 -0
  93. {autogaita-1.4.0 → autogaita-1.4.1}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: autogaita
3
- Version: 1.4.0
3
+ Version: 1.4.1
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
@@ -7,11 +7,12 @@
7
7
  [![paper: biorxiv](https://img.shields.io/badge/paper-biorxiv-blue)](https://doi.org/10.1101/2024.04.14.589409)
8
8
 
9
9
  ![Black](https://img.shields.io/badge/code%20style-black-000000.svg)
10
+ [![Tutorials](https://img.shields.io/badge/YouTube-red?style=for-the-badge&logo=youtube&logoColor=white)](https://youtube.com/playlist?list=PLCn5T7K_H8K56NIcEsfDK664OP7cN_Bad&feature=shared)
10
11
  [![X URL](https://img.shields.io/twitter/url?url=https%3A%2F%2Fx.com%2Fautogaita&style=social&label=updates)](https://x.com/autogaita)
11
12
 
12
13
  # Automated Gait Analysis in Python 🐸
13
14
 
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
+ - 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 methods for obtaining 3D coordinates.
15
16
  - 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
17
  - AutoGaitA enables comparisons to be made across experimental conditions, species, disease states or genotypes.
17
18
  - Despite being developed with gait data, AutoGaitA can be utilised for the analysis of any motor behaviour.
@@ -46,7 +47,7 @@ It is strongly recommended that a separate virtual environment for AutoGaitA is
46
47
 
47
48
  **[The AutoGaitA YouTube Channel](https://youtube.com/playlist?list=PLCn5T7K_H8K56NIcEsfDK664OP7cN_Bad&si=mV5p2--nYvbofkPh) provides tutorials for file preparation and instructions on how to use AutoGaitA. This includes in-depth explanations of all details, (main & advanced) configurations, possibilities, and outputs.**
48
49
 
49
- *Please note that tutorial videos might not always reflect the most up-to-date version of our toolbox, especially in the beginning when things are regularly changing. We will make sure to record new videos whenever there are major changes though. Last tutorial-update was with v0.4.0. (August 2024).*
50
+ *Please note that tutorial videos might not always reflect the most up-to-date version of our toolbox, especially in the beginning when things are regularly changing. We will make sure to record new videos whenever there are major changes though. If updates are just minor we refer to them in the notes below each video. Last tutorial-update was with v1.4.0. (September 2025).*
50
51
 
51
52
  ### Example Data
52
53
  We provide an example dataset in the **example data** folder of this repository, with a set of mice walking over differently wide beams and both the beam as well as body coordinates being tracked with DLC. Note that this dataset was used in our tutorial videos introducing *AutoGaitA DLC*, *AutoGaitA Group* and in our video explaining file preparation for *AutoGaitA DLC*. We further provide a **group** folder there that can be used alongside the *AutoGaitA Group* tutorial to confirm that users generate the same set of results following our instructions.
@@ -68,9 +69,9 @@ Users are advised to read the **General Recommendations** section of that folder
68
69
  By default, *AutoGaitA DLC* and *AutoGaitA Universal 3D* implement standard values for mouse and human locomotion, respectively. If your analysis deviates from these standards (e.g. by focussing on another behaviour or a different species) **you must change these values!**
69
70
 
70
71
  **Find out more about *AutoGaitA's custom joints and angles:***
71
- - [YouTube - AutoGaitA DLC Advanced Configuration](https://youtu.be/MP9g9kXRE_Q?feature=shared)
72
- - [YouTube - AutoGaitA Universal 3D (prev. called Simi)](https://youtu.be/rTG-Fc9XI9g?feature=shared)
73
- - [Documentation - AutoGaitA DLC](https://docs.google.com/document/d/1iQxSwqBW3VdIXHm-AtV4TGlgpJPDldogVx6qzscsGxA/edit?tab=t.0#heading=h.20bg7b7ymt0b)
72
+ - [YouTube - AutoGaitA DLC/SLEAP Advanced Configuration](https://youtu.be/MP9g9kXRE_Q?feature=shared)
73
+ - [YouTube - AutoGaitA Universal 3D](https://youtu.be/vZyWmPcI6ao)
74
+ - [Documentation - AutoGaitA DLC/SLEAP](https://docs.google.com/document/d/1iQxSwqBW3VdIXHm-AtV4TGlgpJPDldogVx6qzscsGxA/edit?tab=t.0#heading=h.20bg7b7ymt0b)
74
75
  - [Documentation - AutoGaitA Universal 3D](https://docs.google.com/document/d/1iQxSwqBW3VdIXHm-AtV4TGlgpJPDldogVx6qzscsGxA/edit?tab=t.0#heading=h.uz61bpmua7qz)
75
76
 
76
77
  ### Bin number of step cycle normalisation
@@ -95,7 +96,7 @@ AutoGaitA's cfg files and dictionaries sometimes change as a result, which means
95
96
  We document each version's cfg-changes in [AutoGaitA Releases](https://github.com/mahan-hosseini/AutoGaitA/releases), which is particularly relevant for users wrapping custom scripts around AutoGaitA's functions.
96
97
 
97
98
  ## Reference
98
- If you use this code or data please [cite our preprint](https://www.biorxiv.org/content/10.1101/2024.04.14.589409v1).
99
+ If you use this code or data please [cite our preprint](https://doi.org/10.1101/2024.04.14.589409).
99
100
 
100
101
  ## License
101
102
  AutoGaitA is licensed under [GPL v3.0](https://github.com/mahan-hosseini/AutoGaitA/blob/main/LICENSE) and Forschungszentrum Jülich GmbH holds all copyrights.
@@ -106,6 +107,8 @@ The AutoGaitA software is provided without warranty of any kind, express or impl
106
107
  [Mahan Hosseini](https://github.com/mahan-hosseini)
107
108
 
108
109
  ## Contributors
110
+ [Sarah Sabbagh](https://github.com/sarahhsabbagh) - Undergraduate Student
111
+
109
112
  [Luca Flemming](https://github.com/luca-flemming) - Undergraduate Student
110
113
 
111
114
  [Nicholas del Grosso](https://github.com/nickdelgrosso) - RSE Advisor
@@ -15,22 +15,18 @@ def group_dlcrun():
15
15
  "5mm",
16
16
  "12mm",
17
17
  "25mm",
18
- # Interaction Issue Dataset
19
- # "Control",
20
- # "Silenced",
21
18
  # Testing Dataset
22
19
  # "one",
23
20
  # "two",
21
+ # 6 Group Dataset
22
+ # "36w_5mm",
23
+ # "36w_12mm",
24
+ # "36w_25mm",
25
+ # "104w_5mm",
26
+ # "104w_12mm",
27
+ # "104w_25mm",
24
28
  ]
25
29
  folderinfo["group_dirs"] = [
26
- # --------------------------
27
- # Full Dataset (39 subjects)
28
- # "/Users/mahan/sciebo/Research/AutoGaitA/Mouse/Sanity Test Interaction Graziana/Result 10 joints/Control Full",
29
- # "/Users/mahan/sciebo/Research/AutoGaitA/Mouse/Sanity Test Interaction Graziana/Result 10 joints/Silenced Full/",
30
- # --------------------------
31
- # Reduced Dataset (5 subjects)
32
- # "/Users/mahan/sciebo/Research/AutoGaitA/Mouse/Sanity Test Interaction Graziana/Result 10 joints/Control",
33
- # "/Users/mahan/sciebo/Research/AutoGaitA/Mouse/Sanity Test Interaction Graziana/Result 10 joints/Silenced/",
34
30
  # --------------------------
35
31
  # Testing Dataset
36
32
  # "/Users/mahan/sciebo/Research/AutoGaitA/Mouse/Testing/Group 1/",
@@ -40,17 +36,23 @@ def group_dlcrun():
40
36
  "/Users/mahan/sciebo/PythonCode/gaita_repo/example data/5mm/Results/",
41
37
  "/Users/mahan/sciebo/PythonCode/gaita_repo/example data/12mm/Results/",
42
38
  "/Users/mahan/sciebo/PythonCode/gaita_repo/example data/25mm/Results/",
39
+ # --------------------------
40
+ # 6 Group Dataset (nothing needed)
43
41
  ]
44
42
  folderinfo["results_dir"] = (
45
- "/Users/mahan/sciebo/Research/AutoGaitA/Mouse/example_data_results/"
46
- # "/Users/mahan/sciebo/Research/AutoGaitA/Mouse/Sanity Test Interaction Graziana/Result 10 joints/Mahan Results/"
47
- # "/Users/mahan/sciebo/Research/AutoGaitA/Mouse/Testing/GroupResults/"
43
+ # "/Users/mahan/sciebo/Research/AutoGaitA/Mouse/example_data_results/"
44
+ "/Users/mahan/sciebo/Research/AutoGaitA/Mouse/Testing/GroupResults/"
45
+ # "/Users/mahan/Desktop/Test6GroupResults/"
46
+ )
47
+ folderinfo["load_dir"] = (
48
+ ""
49
+ # "/Users/mahan/sciebo/Research/AutoGaitA/Mouse/Final Mouse Results/AdultElder3BeamsForPaper" # for 6 group analysis example
48
50
  )
49
- folderinfo["load_dir"] = ""
50
51
  # cfg
51
52
  cfg = {}
52
- cfg["do_permtest"] = False # True
53
+ cfg["do_permtest"] = True
53
54
  cfg["do_anova"] = True
55
+ cfg["anova_design"] = "RM ANOVA"
54
56
  cfg["permutation_number"] = 100
55
57
  cfg["PCA_n_components"] = 6
56
58
  # cfg["PCA_n_components"] = 0.33
@@ -59,14 +61,11 @@ def group_dlcrun():
59
61
  cfg["PCA_save_3D_video"] = False # True
60
62
  cfg["PCA_bins"] = "" # "0-10,24,50-75"
61
63
  cfg["stats_threshold"] = 0.05
62
- cfg["plot_SE"] = False
63
- cfg["color_palette"] = "viridis"
64
+ cfg["plot_SE"] = True
65
+ cfg["color_palette"] = "Set2"
64
66
  cfg["dont_show_plots"] = True
65
67
  cfg["legend_outside"] = True
66
68
  cfg["which_leg"] = "left"
67
- cfg["anova_design"] = "RM ANOVA"
68
- # cfg["anova_design"] = "Mixed ANOVA"
69
- cfg["permutation_number"] = 100
70
69
  cfg["PCA_variables"] = [
71
70
  # "Hind paw tao y",
72
71
  # "Ankle y",
@@ -84,14 +83,14 @@ def group_dlcrun():
84
83
  # "Hip Angle",
85
84
  ]
86
85
  cfg["stats_variables"] = [
87
- "Hind paw tao y",
88
- # "Ankle y",
89
- "Knee y",
86
+ # "Hind paw tao y",
87
+ "Ankle y",
88
+ # "Knee y",
90
89
  # "Ankle Angle",
91
- "Knee Angle",
90
+ # "Knee Angle",
92
91
  # "Nose x",
93
92
  # "Knee y",
94
- "Knee x",
93
+ # "Knee x",
95
94
  # "Knee Velocity",
96
95
  # "Knee Acceleration",
97
96
  # "Knee Angle",
@@ -16,7 +16,14 @@ def run_singlerun_in_multirun(tracking_software, idx, info, folderinfo, cfg):
16
16
  this_info = {}
17
17
  keynames = info.keys()
18
18
  for keyname in keynames:
19
- this_info[keyname] = info[keyname][idx]
19
+ # if the key is leading mouse/run num zeros, only pass it if it is not False
20
+ # => we want these to not be keys in this_info if it is False due to how
21
+ # leading zeros are handled in the prep script
22
+ if "leading_" in keyname:
23
+ if info[keyname][idx] is not False:
24
+ this_info[keyname] = info[keyname][idx]
25
+ else: # pass as is for all other keys
26
+ this_info[keyname] = info[keyname][idx]
20
27
  if cfg["results_dir"]:
21
28
  this_info["results_dir"] = os.path.join(
22
29
  cfg["results_dir"], this_info["name"]
@@ -51,7 +58,13 @@ def extract_info(tracking_software, folderinfo, in_GUI=False):
51
58
  elif tracking_software == "SLEAP":
52
59
  file_type = ".h5"
53
60
  # prepare output info dict and run
54
- info = {"name": [], "mouse_num": [], "run_num": []}
61
+ info = {
62
+ "name": [],
63
+ "mouse_num": [],
64
+ "run_num": [],
65
+ "leading_mouse_num_zeros": [],
66
+ "leading_run_num_zeros": [],
67
+ }
55
68
  for filename in os.listdir(folderinfo["root_dir"]):
56
69
  # make sure we don't get wrong files
57
70
  if (
@@ -109,14 +122,10 @@ def extract_info(tracking_software, folderinfo, in_GUI=False):
109
122
  info["name"].append(this_name)
110
123
  info["mouse_num"].append(this_mouse_num)
111
124
  info["run_num"].append(this_run_num)
112
- # if we had to fix leading zeros, make sure to save them so we can use them in
113
- # move_data_to_folders function later
114
- # => make sure it's lists of strings because this is needed by the
115
- # run_singlerun_in_multiruns function later
116
- if leading_mouse_num_zeros:
117
- info["leading_mouse_num_zeros"] = [leading_mouse_num_zeros]
118
- if leading_run_num_zeros:
119
- info["leading_run_num_zeros"] = [leading_run_num_zeros]
125
+ # note that leading_zeros are always appended but only transfered
126
+ # to this_info dicts in singlerun_from_multi if not False
127
+ info["leading_mouse_num_zeros"].append(leading_mouse_num_zeros)
128
+ info["leading_run_num_zeros"].append(leading_run_num_zeros)
120
129
  # this might happen if user entered wrong identifiers or folder
121
130
  if len(info["name"]) < 1:
122
131
  no_files_message = (
@@ -159,6 +168,8 @@ def find_number(fullstring, prestring, poststring):
159
168
  while fullstring[start_idx] == "0" and start_idx < end_idx - 1:
160
169
  start_idx += 1
161
170
  leading_zeros += "0"
171
+ if leading_zeros == "":
172
+ leading_zeros = False # important that it is False if none present
162
173
  return int(fullstring[start_idx:end_idx]), leading_zeros
163
174
 
164
175
 
@@ -5,6 +5,7 @@ from autogaita.group.group_utils import (
5
5
  save_figures,
6
6
  ytickconvert_mm_to_cm,
7
7
  ylabel_velocity_and_acceleration,
8
+ setup_stats_plots_vars,
8
9
  )
9
10
  import os
10
11
  import sys
@@ -38,8 +39,6 @@ from autogaita.group.group_constants import (
38
39
  MULTCOMP_RESULT_P_IDENTIFIER,
39
40
  MULTCOMP_RESULT_SPLIT_STR,
40
41
  MULTCOMP_EXCEL_COLS,
41
- STATS_PLOT_LEGEND_SIZE, # PLOTS
42
- STATS_PLOTS_SUPLABEL_SIZE,
43
42
  BOX_COLOR,
44
43
  BOX_ALPHA,
45
44
  STD_ALPHA,
@@ -324,12 +323,10 @@ def plot_permutation_test_results(
324
323
  dont_show_plots = cfg["dont_show_plots"]
325
324
  legend_outside = cfg["legend_outside"]
326
325
 
327
- if len(contrasts) > 3: # if we have 4 groups or more, N/2x2 subplot layout
328
- f, ax = plt.subplots(int(round(len(contrasts) / 2)), 2, layout="constrained")
329
- ax = ax.ravel()
330
- else:
331
- f, ax = plt.subplots(len(contrasts), 1, layout="constrained")
332
- x = np.linspace(0, 100, bin_num)
326
+ # call preparation function for vars and loop over contrasts to plot subplots
327
+ f, ax, stats_plots_legend_size, stats_plots_suplabel_size, x = (
328
+ setup_stats_plots_vars(contrasts, bin_num)
329
+ )
333
330
  for c, contrast in enumerate(contrasts):
334
331
  # prepare group strings and (importantly!) index of current groups from _NAMES
335
332
  groups = [group_name for group_name in contrast.split(CONTRAST_SPLIT_STR)]
@@ -347,82 +344,46 @@ def plot_permutation_test_results(
347
344
  else:
348
345
  std = g_std_dfs[group_idx].iloc[:, y_col]
349
346
  this_color = group_color_dict[group_name]
350
- if type(ax) == np.ndarray: # so we can do 2-group contrasts
351
- ax[c].plot(x, y, color=this_color, label=group_name, zorder=1)
352
- ax[c].fill_between(
353
- x,
354
- y - std,
355
- y + std,
356
- color=this_color,
357
- alpha=STD_ALPHA,
358
- lw=STD_LW,
359
- zorder=1,
360
- )
361
- else:
362
- ax.plot(x, y, color=this_color, label=group_name, zorder=1)
363
- ax.fill_between(
364
- x,
365
- y - std,
366
- y + std,
367
- color=this_color,
368
- alpha=STD_ALPHA,
369
- lw=STD_LW,
370
- zorder=1,
371
- )
347
+ # plot line and fill between for error
348
+ ax[c].plot(x, y, color=this_color, label=group_name, zorder=1)
349
+ ax[c].fill_between(
350
+ x,
351
+ y - std,
352
+ y + std,
353
+ color=this_color,
354
+ alpha=STD_ALPHA,
355
+ lw=STD_LW,
356
+ zorder=1,
357
+ )
372
358
  # adjust legend & convert to cm (if needed) before plotting clusters
373
- if type(ax) == np.ndarray:
374
- if legend_outside is True:
375
- ax[c].legend(
376
- fontsize=STATS_PLOT_LEGEND_SIZE,
377
- loc="center left",
378
- bbox_to_anchor=(1, 0.5),
379
- )
380
- elif legend_outside is False:
381
- ax[c].legend(fontsize=STATS_PLOT_LEGEND_SIZE)
382
- if check_mouse_conversion(feature, cfg, stats_var=stats_var):
383
- ytickconvert_mm_to_cm(ax[c])
384
- else:
385
- if legend_outside is True:
386
- ax.legend(
387
- fontsize=STATS_PLOT_LEGEND_SIZE + 4,
388
- loc="center left",
389
- bbox_to_anchor=(1, 0.5),
390
- )
391
- elif legend_outside is False:
392
- ax.legend(fontsize=STATS_PLOT_LEGEND_SIZE + 4)
393
- if check_mouse_conversion(feature, cfg, stats_var=stats_var):
394
- ytickconvert_mm_to_cm(ax)
359
+ if legend_outside is True:
360
+ ax[c].legend(
361
+ fontsize=stats_plots_legend_size,
362
+ loc="center left",
363
+ bbox_to_anchor=(1, 0.5),
364
+ )
365
+ elif legend_outside is False:
366
+ ax[c].legend(fontsize=stats_plots_legend_size)
367
+ if check_mouse_conversion(feature, cfg, stats_var=stats_var):
368
+ ytickconvert_mm_to_cm(ax[c])
395
369
  # plot significant clusters
396
370
  # => note that clusters is a list of list with idxs between 0 & bin_num-1
397
371
  clusters = extract_all_clusters(trueobs_results_df, contrast)
398
- if type(ax) == np.ndarray:
399
- ymin = ax[c].get_ylim()[0]
400
- ymax = ax[c].get_ylim()[1]
401
- else:
402
- ymin = ax.get_ylim()[0]
403
- ymax = ax.get_ylim()[1]
372
+ ymin = ax[c].get_ylim()[0]
373
+ ymax = ax[c].get_ylim()[1]
404
374
  for cluster in x[clusters]: # index x with clusters == cluster has correct val
405
375
  x_coords = [cluster[0], cluster[1], cluster[1], cluster[0]]
406
376
  y_coords = [ymin, ymin, ymax, ymax]
407
- if type(ax) == np.ndarray:
408
- ax[c].fill(
409
- x_coords,
410
- y_coords,
411
- color=BOX_COLOR,
412
- alpha=BOX_ALPHA,
413
- lw=STD_LW,
414
- zorder=0,
415
- )
416
- else:
417
- ax.fill(
418
- x_coords,
419
- y_coords,
420
- color=BOX_COLOR,
421
- alpha=BOX_ALPHA,
422
- lw=STD_LW,
423
- zorder=0,
424
- )
425
- f.supxlabel("Percentage", fontsize=STATS_PLOTS_SUPLABEL_SIZE)
377
+ ax[c].fill(
378
+ x_coords,
379
+ y_coords,
380
+ color=BOX_COLOR,
381
+ alpha=BOX_ALPHA,
382
+ lw=STD_LW,
383
+ zorder=0,
384
+ )
385
+ # plotting is done: now do figure-level stuff (suplabels, save, add to GUI)
386
+ f.supxlabel("Percentage", fontsize=stats_plots_suplabel_size)
426
387
  # ylabels depend on whether we converted mm to cm and on the feature
427
388
  # code below calls the ylabel function for all possible cases:
428
389
  # 1) (DLC only) converted velocity & acceleration
@@ -434,10 +395,10 @@ def plot_permutation_test_results(
434
395
  if feature in ["Velocity", "Acceleration"]:
435
396
  f.supylabel(
436
397
  ylabel_velocity_and_acceleration(feature, "x in cm", sampling_rate),
437
- fontsize=STATS_PLOTS_SUPLABEL_SIZE,
398
+ fontsize=stats_plots_suplabel_size,
438
399
  )
439
400
  else:
440
- f.supylabel(feature + " (cm)", fontsize=STATS_PLOTS_SUPLABEL_SIZE)
401
+ f.supylabel(feature + " (cm)", fontsize=stats_plots_suplabel_size)
441
402
  else:
442
403
  if feature in ["Velocity", "Acceleration"]:
443
404
  if "Angle" in stats_var:
@@ -449,14 +410,13 @@ def plot_permutation_test_results(
449
410
  unit = "Y"
450
411
  f.supylabel(
451
412
  ylabel_velocity_and_acceleration(feature, unit, sampling_rate),
452
- fontsize=STATS_PLOTS_SUPLABEL_SIZE,
413
+ fontsize=stats_plots_suplabel_size,
453
414
  )
454
415
  else:
455
- f.supylabel(feature, fontsize=STATS_PLOTS_SUPLABEL_SIZE)
416
+ f.supylabel(feature, fontsize=stats_plots_suplabel_size)
456
417
  figure_file_string = stats_var + " - Cluster-extent Test"
457
- f.suptitle(figure_file_string, fontsize=STATS_PLOTS_SUPLABEL_SIZE)
418
+ f.suptitle(figure_file_string, fontsize=stats_plots_suplabel_size)
458
419
  save_figures(f, results_dir, figure_file_string)
459
-
460
420
  # add figure to plot panel figures list
461
421
  if dont_show_plots is False: # -> show plot panel
462
422
  plot_panel_instance.figures.append(f)
@@ -757,8 +717,10 @@ def plot_multcomp_results(
757
717
  dont_show_plots = cfg["dont_show_plots"]
758
718
  legend_outside = cfg["legend_outside"]
759
719
 
760
- f, ax = plt.subplots(len(contrasts), 1, layout="constrained")
761
- x = np.linspace(0, 100, bin_num)
720
+ # call preparation function for vars and loop over contrasts to plot subplots
721
+ f, ax, stats_plots_legend_size, stats_plots_suplabel_size, x = (
722
+ setup_stats_plots_vars(contrasts, bin_num)
723
+ )
762
724
  for c, contrast in enumerate(contrasts):
763
725
  # prepare group strings and (importantly!) index of current groups from _NAMES
764
726
  groups = [group_name for group_name in contrast.split(CONTRAST_SPLIT_STR)]
@@ -776,103 +738,56 @@ def plot_multcomp_results(
776
738
  else:
777
739
  std = g_std_dfs[group_idx].iloc[:, y_col]
778
740
  this_color = group_color_dict[group_name]
779
- if type(ax) == np.ndarray: # so we can do a 2-way contrast
780
- ax[c].plot(x, y, color=this_color, label=group_name, zorder=1)
781
- ax[c].fill_between(
782
- x,
783
- y - std,
784
- y + std,
785
- color=this_color,
786
- alpha=STD_ALPHA,
787
- lw=STD_LW,
788
- zorder=1,
789
- )
790
- else:
791
- ax.plot(x, y, color=this_color, label=group_name, zorder=1)
792
- ax.fill_between(
793
- x,
794
- y - std,
795
- y + std,
796
- color=this_color,
797
- alpha=STD_ALPHA,
798
- lw=STD_LW,
799
- zorder=1,
800
- )
741
+ # plot line and fill between for error
742
+ ax[c].plot(x, y, color=this_color, label=group_name, zorder=1)
743
+ ax[c].fill_between(
744
+ x,
745
+ y - std,
746
+ y + std,
747
+ color=this_color,
748
+ alpha=STD_ALPHA,
749
+ lw=STD_LW,
750
+ zorder=1,
751
+ )
801
752
  # adjust legend & convert to cm (if needed) before plotting clusters
802
- if type(ax) == np.ndarray:
803
- if legend_outside is True:
804
- ax[c].legend(
805
- fontsize=STATS_PLOT_LEGEND_SIZE,
806
- loc="center left",
807
- bbox_to_anchor=(1, 0.5),
808
- )
809
- elif legend_outside is False:
810
- ax[c].legend(fontsize=STATS_PLOT_LEGEND_SIZE)
811
- if check_mouse_conversion(feature, cfg, stats_var=stats_var):
812
- ytickconvert_mm_to_cm(ax[c])
813
- else:
814
- if legend_outside is True:
815
- ax.legend(
816
- fontsize=STATS_PLOT_LEGEND_SIZE + 4,
817
- loc="center left",
818
- bbox_to_anchor=(1, 0.5),
819
- )
820
- elif legend_outside is False:
821
- ax.legend(fontsize=STATS_PLOT_LEGEND_SIZE + 4)
822
- if check_mouse_conversion(feature, cfg, stats_var=stats_var):
823
- ytickconvert_mm_to_cm(ax)
753
+ if legend_outside is True:
754
+ ax[c].legend(
755
+ fontsize=stats_plots_legend_size,
756
+ loc="center left",
757
+ bbox_to_anchor=(1, 0.5),
758
+ )
759
+ elif legend_outside is False:
760
+ ax[c].legend(fontsize=stats_plots_legend_size)
761
+ if check_mouse_conversion(feature, cfg, stats_var=stats_var):
762
+ ytickconvert_mm_to_cm(ax[c])
824
763
  # plot significant clusters
825
764
  clusters = extract_multcomp_significance_clusters(
826
765
  multcomp_df, contrast, stats_threshold
827
766
  )
828
- if type(ax) == np.ndarray:
829
- ymin = ax[c].get_ylim()[0]
830
- ymax = ax[c].get_ylim()[1]
831
- else:
832
- ymin = ax.get_ylim()[0]
833
- ymax = ax.get_ylim()[1]
767
+ ymin = ax[c].get_ylim()[0]
768
+ ymax = ax[c].get_ylim()[1]
834
769
  for cluster in x[clusters]: # index x with clusters == cluster has correct val
835
770
  x_coords = [cluster[0], cluster[1], cluster[1], cluster[0]]
836
771
  y_coords = [ymin, ymin, ymax, ymax]
837
- if type(ax) == np.ndarray:
838
- ax[c].fill(
839
- x_coords,
840
- y_coords,
841
- color=BOX_COLOR,
842
- alpha=BOX_ALPHA,
843
- lw=STD_LW,
844
- zorder=0,
845
- )
846
- else:
847
- ax.fill(
848
- x_coords,
849
- y_coords,
850
- color=BOX_COLOR,
851
- alpha=BOX_ALPHA,
852
- lw=STD_LW,
853
- zorder=0,
854
- )
855
- if type(ax) == np.ndarray:
856
- # legend adjustments
857
- if legend_outside is True:
858
- ax[c].legend(
859
- fontsize=STATS_PLOT_LEGEND_SIZE,
860
- loc="center left",
861
- bbox_to_anchor=(1, 0.5),
862
- )
863
- elif legend_outside is False:
864
- ax[c].legend(fontsize=STATS_PLOT_LEGEND_SIZE)
865
- else:
866
- # legend adjustments
867
- if legend_outside is True:
868
- ax.legend(
869
- fontsize=STATS_PLOT_LEGEND_SIZE + 4,
870
- loc="center left",
871
- bbox_to_anchor=(1, 0.5),
872
- )
873
- elif legend_outside is False:
874
- ax.legend(fontsize=STATS_PLOT_LEGEND_SIZE + 4)
875
- f.supxlabel("Percentage", fontsize=STATS_PLOTS_SUPLABEL_SIZE)
772
+ ax[c].fill(
773
+ x_coords,
774
+ y_coords,
775
+ color=BOX_COLOR,
776
+ alpha=BOX_ALPHA,
777
+ lw=STD_LW,
778
+ zorder=0,
779
+ )
780
+ # legend adjustments
781
+ if legend_outside is True:
782
+ ax[c].legend(
783
+ fontsize=stats_plots_legend_size,
784
+ loc="center left",
785
+ bbox_to_anchor=(1, 0.5),
786
+ )
787
+ elif legend_outside is False:
788
+ ax[c].legend(fontsize=stats_plots_legend_size)
789
+ # plotting is done: now do figure-level stuff (suplabels, save, add to GUI)
790
+ f.supxlabel("Percentage", fontsize=stats_plots_suplabel_size)
876
791
  # ylabels depend on whether we converted mm to cm and on the feature
877
792
  # code below calls the ylabel function for all possible cases:
878
793
  # 1) (DLC only) converted velocity & acceleration
@@ -884,10 +799,10 @@ def plot_multcomp_results(
884
799
  if feature in ["Velocity", "Acceleration"]:
885
800
  f.supylabel(
886
801
  ylabel_velocity_and_acceleration(feature, "x in cm", sampling_rate),
887
- fontsize=STATS_PLOTS_SUPLABEL_SIZE,
802
+ fontsize=stats_plots_suplabel_size,
888
803
  )
889
804
  else:
890
- f.supylabel(feature + " (cm)", fontsize=STATS_PLOTS_SUPLABEL_SIZE)
805
+ f.supylabel(feature + " (cm)", fontsize=stats_plots_suplabel_size)
891
806
  else:
892
807
  if feature in ["Velocity", "Acceleration"]:
893
808
  if "Angle" in stats_var:
@@ -899,17 +814,16 @@ def plot_multcomp_results(
899
814
  unit = "Y"
900
815
  f.supylabel(
901
816
  ylabel_velocity_and_acceleration(feature, unit, sampling_rate),
902
- fontsize=STATS_PLOTS_SUPLABEL_SIZE,
817
+ fontsize=stats_plots_suplabel_size,
903
818
  )
904
819
  else:
905
- f.supylabel(feature, fontsize=STATS_PLOTS_SUPLABEL_SIZE)
820
+ f.supylabel(feature, fontsize=stats_plots_suplabel_size)
906
821
  figure_file_string = stats_var + " - Tukey's Multiple Comparison Test"
907
822
  f.suptitle(
908
823
  figure_file_string,
909
- fontsize=STATS_PLOTS_SUPLABEL_SIZE,
824
+ fontsize=stats_plots_suplabel_size,
910
825
  )
911
826
  save_figures(f, results_dir, figure_file_string)
912
-
913
827
  # add figure to plot panel figures list
914
828
  if dont_show_plots is False: # -> show plot panel
915
829
  plot_panel_instance.figures.append(f)
@@ -48,7 +48,7 @@ PCA_BARPLOT_BARCOLOR = "#c74767" # deep rose
48
48
  PCA_BARPLOT_LINECOLOR = "#005f6a" # petrol
49
49
  PCA_CUSTOM_SCATTER_OUTER_SEPARATOR = ";"
50
50
  PCA_CUSTOM_SCATTER_INNER_SEPARATOR = ","
51
- STATS_PLOT_LEGEND_SIZE = 6
51
+ STATS_PLOTS_LEGEND_SIZE = 6
52
52
  STATS_PLOTS_SUPLABEL_SIZE = 12
53
53
  BOX_COLOR = "#fe420f" # significance boxes - col = orangered
54
54
  BOX_ALPHA = 0.1
@@ -4,7 +4,11 @@ from autogaita.resources.constants import INFO_TEXT_WIDTH
4
4
  from autogaita.group.group_constants import (
5
5
  GROUP_CONFIG_TXT_FILENAME,
6
6
  PCA_CUSTOM_SCATTER_OUTER_SEPARATOR,
7
+ STATS_PLOTS_LEGEND_SIZE,
8
+ STATS_PLOTS_SUPLABEL_SIZE,
7
9
  )
10
+ import numpy as np
11
+ import matplotlib.pyplot as plt
8
12
 
9
13
 
10
14
  # %% ......................... print start and finish ................................
@@ -202,3 +206,28 @@ def check_mouse_conversion(feature, cfg, **kwargs):
202
206
  elif "Angle" not in kwargs["stats_var"]:
203
207
  return True
204
208
  return False
209
+
210
+
211
+ def setup_stats_plots_vars(contrasts, bin_num):
212
+ """Set up variables for all stats plots"""
213
+ if len(contrasts) <= 5:
214
+ f, ax = plt.subplots(len(contrasts), 1, layout="constrained")
215
+ stats_plots_suplabel_size = STATS_PLOTS_SUPLABEL_SIZE
216
+ if len(contrasts) == 1:
217
+ stats_plots_legend_size = STATS_PLOTS_LEGEND_SIZE + 4
218
+ ax = np.atleast_1d(ax) # quick hack so we can index ax as a list
219
+ else:
220
+ stats_plots_legend_size = STATS_PLOTS_LEGEND_SIZE
221
+ else:
222
+ if len(contrasts) == 6: # 4 groups
223
+ f, ax = plt.subplots(3, 2, layout="constrained", figsize=(15, 10))
224
+ elif len(contrasts) == 10: # 5 groups
225
+ f, ax = plt.subplots(5, 2, layout="constrained", figsize=(15, 10))
226
+ elif len(contrasts) == 15: # 6 groups
227
+ f, ax = plt.subplots(5, 3, layout="constrained", figsize=(15, 10))
228
+ ax = ax.ravel() # so we can index it as 1D array
229
+ stats_plots_suplabel_size = STATS_PLOTS_SUPLABEL_SIZE + 5
230
+ stats_plots_legend_size = STATS_PLOTS_LEGEND_SIZE + 1
231
+ # x is linear space between 0 and 100% with bin_num steps
232
+ x = np.linspace(0, 100, bin_num)
233
+ return f, ax, stats_plots_legend_size, stats_plots_suplabel_size, x