autogaita 0.0.5__tar.gz → 0.0.6__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 (32) hide show
  1. {autogaita-0.0.5 → autogaita-0.0.6}/PKG-INFO +3 -1
  2. {autogaita-0.0.5 → autogaita-0.0.6}/README.md +16 -9
  3. autogaita-0.0.6/autogaita/__init__.py +20 -0
  4. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/autogaita.py +1 -1
  5. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/autogaita_dlc.py +127 -34
  6. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/autogaita_dlc_gui.py +199 -89
  7. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/autogaita_group.py +95 -57
  8. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/autogaita_group_gui.py +31 -10
  9. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/autogaita_simi.py +74 -46
  10. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/autogaita_simi_gui.py +27 -23
  11. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/autogaita_utils.py +3 -5
  12. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/batchrun_scripts/autogaita_dlc_multirun.py +42 -33
  13. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/batchrun_scripts/autogaita_dlc_singlerun.py +31 -21
  14. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/batchrun_scripts/autogaita_group_dlcrun.py +3 -2
  15. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/batchrun_scripts/autogaita_group_simirun.py +8 -6
  16. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/batchrun_scripts/autogaita_simi_multirun.py +13 -10
  17. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/batchrun_scripts/autogaita_simi_singlerun.py +10 -7
  18. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita.egg-info/PKG-INFO +3 -1
  19. autogaita-0.0.6/autogaita.egg-info/requires.txt +14 -0
  20. {autogaita-0.0.5 → autogaita-0.0.6}/setup.py +16 -14
  21. autogaita-0.0.5/autogaita/__init__.py +0 -1
  22. autogaita-0.0.5/autogaita.egg-info/requires.txt +0 -11
  23. {autogaita-0.0.5 → autogaita-0.0.6}/LICENSE +0 -0
  24. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/__main__.py +0 -0
  25. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/autogaita_icon.icns +0 -0
  26. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/autogaita_icon.ico +0 -0
  27. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/autogaita_logo.png +0 -0
  28. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita/batchrun_scripts/__init__.py +0 -0
  29. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita.egg-info/SOURCES.txt +0 -0
  30. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita.egg-info/dependency_links.txt +0 -0
  31. {autogaita-0.0.5 → autogaita-0.0.6}/autogaita.egg-info/top_level.txt +0 -0
  32. {autogaita-0.0.5 → autogaita-0.0.6}/setup.cfg +0 -0
@@ -1,8 +1,10 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: autogaita
3
- Version: 0.0.5
3
+ Version: 0.0.6
4
4
  Summary: Automatic Gait Analysis in Python
5
5
  Home-page: https://github.com/mahan-hosseini/AutoGaitA/
6
6
  Author: Mahan Hosseini
7
7
  License: GPLv3
8
+ Requires-Python: >=3.10
9
+ Provides-Extra: dev
8
10
  License-File: LICENSE
@@ -1,5 +1,7 @@
1
1
  ![AutoGaitA](https://github.com/mahan-hosseini/AutoGaitA/blob/main/res/autogaita_logo.png?raw=true)
2
- ![Python](https://img.shields.io/badge/python-v3.6+-blue.svg)
2
+ [![PyPI version](https://badge.fury.io/py/autogaita.svg)](https://badge.fury.io/py/autogaita)
3
+ [![Test AutoGaitA](https://github.com/mahan-hosseini/AutoGaitA/actions/workflows/auto_test_gaita.yml/badge.svg)](https://github.com/mahan-hosseini/AutoGaitA/actions/workflows/auto_test_gaita.yml)
4
+ ![Python](https://img.shields.io/badge/python-v3.10+-blue.svg)
3
5
  ![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)
4
6
  ![Black](https://img.shields.io/badge/code%20style-black-000000.svg)
5
7
  # Automated Gait Analysis in Python 🐸
@@ -13,17 +15,18 @@
13
15
 
14
16
  ***Note!** Our documentation provides step-by-step walkthroughs of how to install autogaita for **[Windows](https://docs.google.com/document/d/1Y4wrrsjs0ybLDKPzE2LAatqPDq9jtwjIuk4M0jRZ3wE/edit#heading=h.28j6wu2vamre)** and **[Mac](https://docs.google.com/document/d/1Y4wrrsjs0ybLDKPzE2LAatqPDq9jtwjIuk4M0jRZ3wE/edit)***
15
17
 
16
- It is strongly recommended that a separate virtual environment for AutoGaitA is created via
18
+ It is strongly recommended that a separate virtual environment for AutoGaitA is created (note that the approach below creates the virtual environment to your current directory):
17
19
 
18
- `python -m venv env_gaita`
20
+ - Create the virtual environment
21
+ - `python -m venv env_gaita`
19
22
 
20
- After creating and activating the virtual environment, AutoGaitA can be installed via pip
23
+ - After creation, activate the virtual environment via:
24
+ - *Windows:* `env_gaita\Scripts\activate`
25
+ - *Mac:* `source env_gaita/bin/activate`
21
26
 
22
- `pip install autogaita`
27
+ - Once activated, install AutoGaitA in the virtual environment via pip: `pip install autogaita`.
23
28
 
24
- The main user interface can then be accessed via
25
-
26
- `python -m autogaita`
29
+ - Access the main user interface via `python -m autogaita`.
27
30
 
28
31
  ## Tutorials and Examples
29
32
 
@@ -54,9 +57,13 @@ By default, *AutoGaitA DLC* and *AutoGaitA Simi* implement standard values for m
54
57
  - [Documentation - AutoGaitA DLC](https://docs.google.com/document/d/1Y4wrrsjs0ybLDKPzE2LAatqPDq9jtwjIuk4M0jRZ3wE/edit#heading=h.20bg7b7ymt0b)
55
58
  - [Documentation - AutoGaitA Simi](https://docs.google.com/document/d/1Y4wrrsjs0ybLDKPzE2LAatqPDq9jtwjIuk4M0jRZ3wE/edit#heading=h.uz61bpmua7qz)
56
59
 
60
+ ## Reference
61
+ If you use this code or data please [cite our preprint](https://www.biorxiv.org/content/10.1101/2024.04.14.589409v1).
62
+
57
63
  ## License
64
+ AutoGaitA is licensed under [GPL v3.0](https://github.com/mahan-hosseini/AutoGaitA/blob/main/LICENSE) and Forschungszentrum Jülich GmbH holds all copyrights.
58
65
 
59
- AutoGaitA is licensed under [GPL v3.0](https://github.com/mahan-hosseini/AutoGaitA/blob/main/LICENSE) and Forschungszentrum Jülich GmbH holds all copyrights.
66
+ The AutoGaitA software is provided without warranty of any kind, express or implied, including, but not limited to, the implied warranty of fitness for a particular purpose.
60
67
 
61
68
  ## Authors
62
69
  Mahan Hosseini
@@ -0,0 +1,20 @@
1
+ # main gui
2
+ from .autogaita import gui # autogaita.gui()
3
+
4
+ # 3 sub-guis
5
+ from .autogaita_dlc_gui import dlc_gui # autogaita.dlc_gui()
6
+ from .autogaita_simi_gui import simi_gui # autogaita.simi_gui()
7
+ from .autogaita_group_gui import group_gui # autogaita.group_gui()
8
+
9
+ # 3 main functions
10
+ from .autogaita_dlc import dlc # autogaita.dlc(info, folderinfo, cfg)
11
+ from .autogaita_simi import simi # autogaita.simi(info, folderinfo, cfg)
12
+ from .autogaita_group import group # autogaita.group(folderinfo, cfg)
13
+
14
+ # 6 batchrun functions - call via e.g. autogaita.dlc_singlerun()
15
+ from .batchrun_scripts.autogaita_dlc_singlerun import dlc_singlerun
16
+ from .batchrun_scripts.autogaita_dlc_multirun import dlc_multirun
17
+ from .batchrun_scripts.autogaita_simi_singlerun import simi_singlerun
18
+ from .batchrun_scripts.autogaita_simi_multirun import simi_multirun
19
+ from .batchrun_scripts.autogaita_group_dlcrun import group_dlcrun
20
+ from .batchrun_scripts.autogaita_group_simirun import group_simirun
@@ -124,7 +124,7 @@ def configure_the_icon(root):
124
124
  try:
125
125
  from Cocoa import NSApplication, NSImage
126
126
  except ImportError:
127
- print('Unable to import pyobjc modules')
127
+ print("Unable to import pyobjc modules")
128
128
  else:
129
129
  with resources.path("autogaita", "autogaita_icon.icns") as icon_path:
130
130
  ns_application = NSApplication.sharedApplication()
@@ -1,9 +1,9 @@
1
1
  # %% imports
2
2
  import os
3
3
  import sys
4
- import pdb
5
4
  import shutil
6
5
  import json
6
+ import warnings
7
7
  import pandas as pd
8
8
  import numpy as np
9
9
  import math
@@ -17,8 +17,17 @@ TIME_COL = "Time"
17
17
  ISSUES_TXT_FILENAME = "Issues.txt" # filename to which we write issues-info
18
18
  CONFIG_JSON_FILENAME = "config.json" # filename to which we write cfg-infos
19
19
  SCXLS_MOUSECOLS = [
20
- "Mouse", "mouse", "Fly", "fly", "Animal", "animal", "Subject", "subject", "ID", "id"
21
- ] # SC XLS info
20
+ "Mouse",
21
+ "mouse",
22
+ "Fly",
23
+ "fly",
24
+ "Animal",
25
+ "animal",
26
+ "Subject",
27
+ "subject",
28
+ "ID",
29
+ "id",
30
+ ] # SC XLS info
22
31
  SCXLS_RUNCOLS = ["Run", "run", "Runs", "runs", "Trial", "trial", "Trials", "trials"]
23
32
  SCXLS_SCCOLS = ["SC Number", "SC number", "sc number", "SC Num", "sc num", "SC num"]
24
33
  SWINGSTART_COL = "Swing (ti)"
@@ -235,7 +244,7 @@ def some_prep(info, folderinfo, cfg):
235
244
  # if wanted: fix that deeplabcut inverses y
236
245
  if invert_y_axis:
237
246
  for col in data.columns:
238
- if col.endswith("y"):
247
+ if col.endswith(" y"):
239
248
  data[col] = data[col] * -1
240
249
  # if we don't have a beam to subtract, normalise y to global y minimum being 0
241
250
  if not subtract_beam:
@@ -259,16 +268,18 @@ def some_prep(info, folderinfo, cfg):
259
268
  # pushing it towards zero.
260
269
  # => using list(set()) to ensure that we don't have duplicate values (if users
261
270
  # should have provided them in both cfg vars by misstake)
271
+ # => beam_col_left and right is provided by users
262
272
  if subtract_beam:
273
+ # note beam_col_left/right are always lists in cfg!
274
+ beam_col_left = cfg["beam_col_left"][0]
275
+ beam_col_right = cfg["beam_col_right"][0]
263
276
  for joint in list(set(hind_joints + beam_hind_jointadd)):
264
- data[joint + "y"] = data[joint + "y"] - data["BeamLeft y"]
277
+ data[joint + "y"] = data[joint + "y"] - data[beam_col_left + "y"]
265
278
  for joint in list(set(fore_joints + beam_fore_jointadd)):
266
- data[joint + "y"] = data[joint + "y"] - data["BeamRight y"]
267
- dropcols = [c for c in data.columns if "Beam" in c]
268
- data.drop(columns=dropcols, inplace=True) # beamcols not needed anymore
279
+ data[joint + "y"] = data[joint + "y"] - data[beam_col_right + "y"]
280
+ data.drop(columns=list(beamdf.columns), inplace=True) # beam not needed anymore
269
281
  # add Time and round based on sampling rate
270
282
  data[TIME_COL] = data.index * (1 / sampling_rate)
271
- pdb.set_trace()
272
283
  if sampling_rate <= 100:
273
284
  data[TIME_COL] = round(data[TIME_COL], 2)
274
285
  elif 100 < sampling_rate <= 1000:
@@ -343,13 +354,16 @@ def test_and_expand_cfg(data, cfg, info):
343
354
  Check that all features are present in the dataset
344
355
  Add plot_joints & direction_joint
345
356
  Make sure to set dont_show_plots to True if Python is not in interactive mode
357
+ If users subtract a beam, set normalise @ sc level to False
346
358
  """
347
359
 
348
- # run the 3 tests first
360
+ # run the tests first
349
361
  for cfg_key in [
350
362
  "angles",
351
363
  "hind_joints",
352
364
  "fore_joints",
365
+ "beam_col_left", # note beamcols are lists even though len=1 bc. of
366
+ "beam_col_right", # check function's procedure
353
367
  "beam_hind_jointadd",
354
368
  "beam_fore_jointadd",
355
369
  ]:
@@ -373,19 +387,42 @@ def test_and_expand_cfg(data, cfg, info):
373
387
  else:
374
388
  cfg["plot_joints"] = hind_joints[: cfg["plot_joint_number"]]
375
389
 
376
- # add direction_joint - used to determine gait direction
390
+ # check hindlimb joints & add direction_joint - used to determine gait direction
377
391
  if not hind_joints: # no valid string after above cleaning
378
392
  no_hind_joint_message = (
379
393
  "\n******************\n! CRITICAL ERROR !\n******************\n"
380
394
  + "After testing your hind limb joint names, no valid joint was left to "
381
395
  + "perform gait direction checks on.\nPlease make sure that at least one "
382
396
  + "hind limb joint is provided & try again!"
383
- )
397
+ )
384
398
  write_issues_to_textfile(no_hind_joint_message, info)
385
399
  print(no_hind_joint_message)
386
400
  return
387
401
  cfg["direction_joint"] = hind_joints[0]
388
402
 
403
+ # if subtracting beam, check that its colnames were valid.
404
+ if cfg["subtract_beam"]:
405
+ beam_col_error_message = (
406
+ "\n******************\n! CRITICAL ERROR !\n******************\n"
407
+ + "It seems like you want to normalise heights to a baseline (beam)."
408
+ + "\nUnfortunately we were unable to find the y-columns you listed in "
409
+ + "your beam's csv-file.\nPlease try again.\nInvalid beam side(s) was/were:"
410
+ )
411
+ beam_error = False # check 3 possible cases
412
+ if (cfg["beam_col_left"]) and (not cfg["beam_col_right"]):
413
+ beam_error = True
414
+ beam_col_error_message += "\n right beam!"
415
+ elif (not cfg["beam_col_left"]) and (cfg["beam_col_right"]):
416
+ beam_error = True
417
+ beam_col_error_message += "\n left beam!"
418
+ elif (not cfg["beam_col_left"]) and (not cfg["beam_col_right"]):
419
+ beam_error = True
420
+ beam_col_error_message += "\n both beams!"
421
+ if beam_error: # if any case was True, stop everything
422
+ write_issues_to_textfile(beam_col_error_message, info)
423
+ print(beam_col_error_message)
424
+ return
425
+
389
426
  # dont show plots
390
427
  # !!! If users should complain that they dont get figures but they should, it might
391
428
  # be because these lines wrongly determine user to be in non-interactive mode
@@ -394,6 +431,10 @@ def test_and_expand_cfg(data, cfg, info):
394
431
  cfg["dont_show_plots"] = True
395
432
  matplotlib.use("agg")
396
433
 
434
+ # never normalise @ SC level if user subtracted a beam
435
+ if cfg["subtract_beam"]:
436
+ cfg["normalise_height_at_SC_level"] = False
437
+
397
438
  return cfg
398
439
 
399
440
 
@@ -438,7 +479,7 @@ def check_and_fix_cfg_strings(data, cfg, cfg_key, info):
438
479
  clean_strings_message += "\n" + string
439
480
  clean_strings_message += (
440
481
  "\n\nNote that capitalisation matters."
441
- + "\nIf you are running a group analysis, we'll use this updated cfg "
482
+ + "\nIf you are running a batch analysis, we'll use this updated cfg "
442
483
  + "throughout\nCheck out the config.json file for the full cfg used."
443
484
  )
444
485
  print(clean_strings_message)
@@ -446,6 +487,23 @@ def check_and_fix_cfg_strings(data, cfg, cfg_key, info):
446
487
 
447
488
  # things are more involved for angle dicts
448
489
  elif type(string_variable) is dict:
490
+ # 1) test if the lists of all keys are equally long, if not throw out last idxs
491
+ key_lengths = [len(string_variable[key]) for key in string_variable.keys()]
492
+ if not all(key_length == key_lengths[0] for key_length in key_lengths):
493
+ min_length = min(key_lengths)
494
+ for key in string_variable: # remove invalid idxs
495
+ string_variable[key] = string_variable[key][:min_length]
496
+ key_length_mismatch_message = ( # inform user
497
+ "\n***********\n! WARNING !\n***********\n"
498
+ + "\nLength-mismatch in angle configuration!"
499
+ + "\nCheck angles' name/upper/lower-joint entries."
500
+ + "\nOnly processing first "
501
+ + str(min_length)
502
+ + " entries."
503
+ )
504
+ print(key_length_mismatch_message)
505
+ write_issues_to_textfile(key_length_mismatch_message, info)
506
+ # 2) check if all strings in the angle dict are valid columns
449
507
  invalid_angletrio_message = ""
450
508
  invalid_idxs = [] # these idxs hold across the 3 keys of our angles-dict
451
509
  for key in string_variable:
@@ -460,7 +518,7 @@ def check_and_fix_cfg_strings(data, cfg, cfg_key, info):
460
518
  invalid_idxs.append(idx)
461
519
  if not this_keys_missing_strings: # first occurance
462
520
  this_keys_missing_strings += "\nAngle's " + key + " key: "
463
- this_keys_missing_strings += (string + "(#" + str(idx+1) + ") / ")
521
+ this_keys_missing_strings += string + "(#" + str(idx + 1) + ") / "
464
522
  # string concat outside of idx-forloop above please
465
523
  invalid_angletrio_message += this_keys_missing_strings
466
524
  # if we have to remove idxs from all keys of our angles dict
@@ -497,7 +555,7 @@ def check_and_fix_cfg_strings(data, cfg, cfg_key, info):
497
555
  )
498
556
  clean_angles_message += (
499
557
  "\n\nNote that capitalisation matters."
500
- + "\nIf you are running a group analysis, we'll use this updated cfg "
558
+ + "\nIf you are running a batch analysis, we'll use this updated cfg "
501
559
  + "throughout\nCheck out the config.json file for the full cfg used."
502
560
  )
503
561
  print(clean_angles_message)
@@ -627,7 +685,7 @@ def extract_stepcycles(data, info, folderinfo, cfg):
627
685
  SCdf = pd.read_excel(os.path.join(root_dir, sctable_filename))
628
686
  else:
629
687
  raise FileNotFoundError(
630
- "No SC XLS table found! sctable_filename has to be @ root_dir"
688
+ "No Annotation Table found! sctable_filename has to be @ root_dir"
631
689
  )
632
690
  else:
633
691
  # in cases below use string-concat (+) - otherwise xls added as path
@@ -637,7 +695,7 @@ def extract_stepcycles(data, info, folderinfo, cfg):
637
695
  SCdf = pd.read_excel(os.path.join(root_dir, sctable_filename + ".xlsx"))
638
696
  else:
639
697
  raise FileNotFoundError(
640
- "No SC XLS table found! sctable_filename has to be @ root_dir"
698
+ "No Annotation Table found! sctable_filename has to be @ root_dir"
641
699
  )
642
700
  # see if table columns are labelled correctly (try a couple to allow user typos)
643
701
  valid_col_flags = [False, False, False]
@@ -770,6 +828,7 @@ def extract_stepcycles(data, info, folderinfo, cfg):
770
828
  all_cycles = check_DLC_tracking(data, info, all_cycles, cfg)
771
829
  return all_cycles
772
830
 
831
+
773
832
  # .............................. helper functions ....................................
774
833
  def check_cycle_out_of_bounds(all_cycles):
775
834
  """Check if user provided SC latencies that were not in video/data bounds"""
@@ -817,7 +876,7 @@ def check_cycle_order(all_cycles, info):
817
876
  this_message = (
818
877
  "\n***********\n! WARNING !\n***********\n"
819
878
  + "SC #"
820
- + str(c+1)
879
+ + str(c + 1)
821
880
  + " has a later start than end latency - Skipping!"
822
881
  )
823
882
  print(this_message)
@@ -826,7 +885,7 @@ def check_cycle_order(all_cycles, info):
826
885
  this_message = (
827
886
  "\n***********\n! WARNING !\n***********\n"
828
887
  + "SC #"
829
- + str(c+1)
888
+ + str(c + 1)
830
889
  + " has an earlier start than previous SC's end latency - Skipping!"
831
890
  )
832
891
  print(this_message)
@@ -930,7 +989,7 @@ def handle_issues(condition, info):
930
989
  # ----
931
990
  # There is quite a lot going on in this function. We:
932
991
  # 1) loop through all step cycles for one leg at a time and extract data
933
- # 2) for each step's data we normalise all y (height) values to the hind paw's minimum
992
+ # 2) for each step's data we normalise all y (height) values to the body's minimum
934
993
  # if wanted
935
994
  # 3) we compute and add features (angles, velocities, accelerations)
936
995
  # ==> see norm_y_and_add_features_to_one_step & helper functions a
@@ -958,7 +1017,7 @@ def analyse_and_export_stepcycles(data, all_cycles, info, folderinfo, cfg):
958
1017
  normalised_steps_data = normalise_one_steps_data(all_steps_data, bin_num)
959
1018
  # 2 or more steps - build dataframe
960
1019
  elif len(all_cycles) > 1:
961
- # first step is added manually
1020
+ # first- step is added manually
962
1021
  first_step = data_copy.loc[all_cycles[0][0] : all_cycles[0][1]]
963
1022
  first_step = norm_y_and_add_features_to_one_step(first_step, cfg)
964
1023
  all_steps_data = first_step
@@ -966,12 +1025,18 @@ def analyse_and_export_stepcycles(data, all_cycles, info, folderinfo, cfg):
966
1025
  # some prep for addition of further steps
967
1026
  sc_num = len(all_cycles)
968
1027
  nanvector = data_copy.loc[[1]]
969
- nanvector[:] = np.nan
1028
+ with warnings.catch_warnings():
1029
+ warnings.simplefilter("ignore")
1030
+ nanvector[:] = np.nan
970
1031
  # .............................. step-loop ...................................
971
1032
  for s in range(1, sc_num, 1):
972
1033
  # get step separators
973
1034
  numvector = data_copy.loc[[1]]
974
- numvector[:] = s + 1
1035
+ # we are ignoring this because we wont work with the incompatible dtypes ourselves much anymore (just export as xlsx and plot) - so its fine
1036
+ # https://docs.python.org/3/library/warnings.html#temporarily-suppressing-warnings
1037
+ with warnings.catch_warnings():
1038
+ warnings.simplefilter("ignore")
1039
+ numvector[:] = s + 1
975
1040
  all_steps_data = add_step_separators(all_steps_data, nanvector, numvector)
976
1041
  # this_step
977
1042
  this_step = data_copy.loc[all_cycles[s][0] : all_cycles[s][1]]
@@ -1273,7 +1338,7 @@ def plot_results(info, results, folderinfo, cfg):
1273
1338
  angular_acceleration = cfg["angular_acceleration"]
1274
1339
  dont_show_plots = cfg["dont_show_plots"]
1275
1340
  if dont_show_plots:
1276
- plt.switch_backend('Agg')
1341
+ plt.switch_backend("Agg")
1277
1342
 
1278
1343
  # ....................0 - extract SCs from all_steps_data...........................
1279
1344
  sc_idxs = extract_sc_idxs(all_steps_data)
@@ -1397,9 +1462,19 @@ def plot_joint_y_by_x(all_steps_data, sc_idxs, info, cfg):
1397
1462
  else:
1398
1463
  float_precision = 4
1399
1464
  this_label = (
1400
- str(round(all_steps_data.iloc[sc_idxs[s][0], time_col_idx], float_precision))
1465
+ str(
1466
+ round(
1467
+ all_steps_data.iloc[sc_idxs[s][0], time_col_idx],
1468
+ float_precision,
1469
+ )
1470
+ )
1401
1471
  + "-"
1402
- + str(round(all_steps_data.iloc[sc_idxs[s][-1], time_col_idx], float_precision))
1472
+ + str(
1473
+ round(
1474
+ all_steps_data.iloc[sc_idxs[s][-1], time_col_idx],
1475
+ float_precision,
1476
+ )
1477
+ )
1403
1478
  + "s"
1404
1479
  )
1405
1480
  ax[j].plot(this_x, this_y, label=this_label)
@@ -1412,7 +1487,9 @@ def plot_joint_y_by_x(all_steps_data, sc_idxs, info, cfg):
1412
1487
  figure_file_string = " - Foot y by x coordinates"
1413
1488
  else:
1414
1489
  figure_file_string = " - " + joint + "y by x coordinates"
1415
- f[j].savefig(results_dir + name + figure_file_string + ".png", bbox_inches="tight")
1490
+ f[j].savefig(
1491
+ results_dir + name + figure_file_string + ".png", bbox_inches="tight"
1492
+ )
1416
1493
  save_as_svg(f[j], results_dir, name, figure_file_string)
1417
1494
  if dont_show_plots:
1418
1495
  plt.close(f[j])
@@ -1448,7 +1525,9 @@ def plot_angles_by_time(all_steps_data, sc_idxs, info, cfg):
1448
1525
  this_y = all_steps_data.iloc[sc_idxs[s], y_col_idx]
1449
1526
  ax[a].plot(this_x, this_y)
1450
1527
  figure_file_string = " - " + angle + " Angle by Time"
1451
- f[a].savefig(results_dir + name + figure_file_string + ".png", bbox_inches="tight")
1528
+ f[a].savefig(
1529
+ results_dir + name + figure_file_string + ".png", bbox_inches="tight"
1530
+ )
1452
1531
  save_as_svg(f[a], results_dir, name, figure_file_string)
1453
1532
  if dont_show_plots:
1454
1533
  plt.close(f[a])
@@ -1481,9 +1560,15 @@ def plot_hindlimb_stickdiagram(all_steps_data, sc_idxs, info, cfg):
1481
1560
  else:
1482
1561
  float_precision = 4
1483
1562
  this_label = (
1484
- str(round(all_steps_data.iloc[sc_idxs[s][0], time_col_idx], float_precision))
1563
+ str(
1564
+ round(all_steps_data.iloc[sc_idxs[s][0], time_col_idx], float_precision)
1565
+ )
1485
1566
  + "-"
1486
- + str(round(all_steps_data.iloc[sc_idxs[s][-1], time_col_idx], float_precision))
1567
+ + str(
1568
+ round(
1569
+ all_steps_data.iloc[sc_idxs[s][-1], time_col_idx], float_precision
1570
+ )
1571
+ )
1487
1572
  + "s"
1488
1573
  )
1489
1574
  for i in sc_idxs[s]: # loop over timepoints of current SC
@@ -1537,9 +1622,15 @@ def plot_forelimb_stickdiagram(all_steps_data, sc_idxs, info, cfg):
1537
1622
  else:
1538
1623
  float_precision = 4
1539
1624
  this_label = (
1540
- str(round(all_steps_data.iloc[sc_idxs[s][0], time_col_idx], float_precision))
1625
+ str(
1626
+ round(all_steps_data.iloc[sc_idxs[s][0], time_col_idx], float_precision)
1627
+ )
1541
1628
  + "-"
1542
- + str(round(all_steps_data.iloc[sc_idxs[s][-1], time_col_idx], float_precision))
1629
+ + str(
1630
+ round(
1631
+ all_steps_data.iloc[sc_idxs[s][-1], time_col_idx], float_precision
1632
+ )
1633
+ )
1543
1634
  + "s"
1544
1635
  )
1545
1636
  for i in sc_idxs[s]:
@@ -1827,7 +1918,9 @@ def save_as_svg(figure, results_dir, name, figure_file_string):
1827
1918
  svg_dir = os.path.join(results_dir, "SVG Figures")
1828
1919
  if not os.path.exists(svg_dir):
1829
1920
  os.makedirs(svg_dir)
1830
- figure.savefig(svg_dir + "/" + name + figure_file_string + ".svg", bbox_inches="tight")
1921
+ figure.savefig(
1922
+ svg_dir + "/" + name + figure_file_string + ".svg", bbox_inches="tight"
1923
+ )
1831
1924
 
1832
1925
 
1833
1926
  def tickconvert_mm_to_cm(axis, whichlabel):
@@ -1872,5 +1965,5 @@ if __name__ == "__main__":
1872
1965
  + "possible.\nIf you prefer a non-GUI approach, please either: "
1873
1966
  + "\n1. Call this as a function, i.e. autogaita.dlc(info, folderinfo, cfg)"
1874
1967
  + "\n2. Use the single or multirun scripts in the batchrun_scripts folder"
1875
- )
1968
+ )
1876
1969
  print(dlc_info_message)