xarray-behave 0.37.2__tar.gz → 0.37.3__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 (60) hide show
  1. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/PKG-INFO +1 -1
  2. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/conda/xarray-behave/meta.yaml +1 -2
  3. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/__init__.py +1 -1
  4. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/app.py +133 -52
  5. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/.github/workflows/publish.yaml +0 -0
  6. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/.gitignore +0 -0
  7. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/LICENSE +0 -0
  8. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/README.md +0 -0
  9. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/build_env.yml +0 -0
  10. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/conda/xarray-behave/bld.bat +0 -0
  11. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/conda/xarray-behave/build.sh +0 -0
  12. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/condarc.yml +0 -0
  13. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/doc/demo.ipynb +0 -0
  14. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/doc/demo_behavioral_features.ipynb +0 -0
  15. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/doc/demo_behavioral_features_large_group.ipynb +0 -0
  16. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/doc/ncb.mplstyle +0 -0
  17. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/pyproject.toml +0 -0
  18. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/setup.py +0 -0
  19. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/annot.py +0 -0
  20. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/event_utils.py +0 -0
  21. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/__init__.py +0 -0
  22. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/audio_player.py +0 -0
  23. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/das.py +0 -0
  24. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/formbuilder.py +0 -0
  25. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/forms/das_make.yaml +0 -0
  26. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/forms/das_predict.yaml +0 -0
  27. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/forms/das_train.yaml +0 -0
  28. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/forms/envelope_computation.yaml +0 -0
  29. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/forms/export_for_das.yaml +0 -0
  30. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/forms/from_dir.yaml +0 -0
  31. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/forms/from_file.yaml +0 -0
  32. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/forms/from_zarr.yaml +0 -0
  33. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/forms/spec_freq.yaml +0 -0
  34. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/icon.png +0 -0
  35. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/table.py +0 -0
  36. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/utils.py +0 -0
  37. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/view_dialog.py +0 -0
  38. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/views.py +0 -0
  39. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/gui/widgets.py +0 -0
  40. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/io/__init__.py +0 -0
  41. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/io/annotations.py +0 -0
  42. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/io/annotations_manual.py +0 -0
  43. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/io/audio.py +0 -0
  44. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/io/balltracks.py +0 -0
  45. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/io/movieparams.py +0 -0
  46. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/io/poses.py +0 -0
  47. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/io/samplestamps/__init__.py +0 -0
  48. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/io/samplestamps/samplestamps.py +0 -0
  49. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/io/samplestamps/utils.py +0 -0
  50. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/io/timestamps.py +0 -0
  51. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/io/tracks.py +0 -0
  52. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/loaders.py +0 -0
  53. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/metrics.py +0 -0
  54. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/src/xarray_behave/xarray_behave.py +0 -0
  55. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/tests/test_annot.py +0 -0
  56. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/tests/test_assemble.py +0 -0
  57. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/tests/test_assemble_metrics.py +0 -0
  58. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/tests/test_imports.py +0 -0
  59. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/tests/test_io.py +0 -0
  60. {xarray_behave-0.37.2 → xarray_behave-0.37.3}/tests/test_sampstamps.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: xarray-behave
3
- Version: 0.37.2
3
+ Version: 0.37.3
4
4
  Summary: xarray tools for behavioral data.
5
5
  Author-email: Jan Clemens <clemensjan@googlemail.com>
6
6
  Requires-Python: >3.9
@@ -7,8 +7,7 @@ package:
7
7
  version: "{{ version }}"
8
8
 
9
9
  source:
10
- url: "https://pypi.io/packages/source/{{ name[0] }}/{{ name }}/{{ name }}-{{ version }}.tar.gz"
11
-
10
+ url: https://pypi.org/packages/source/x/xarray-behave/xarray_behave-{{ version }}.tar.gz
12
11
  build:
13
12
  number: 0
14
13
 
@@ -1,6 +1,6 @@
1
1
  """xarray tools for behavioral data."""
2
2
 
3
- __version__ = "0.37.2"
3
+ __version__ = "0.37.3"
4
4
 
5
5
  from .xarray_behave import assemble, assemble_metrics, load, save
6
6
  import os
@@ -15,6 +15,7 @@ import defopt
15
15
  import yaml
16
16
  import h5py
17
17
  import functools
18
+ import rich
18
19
 
19
20
  import numpy as np
20
21
  import scipy.interpolate
@@ -45,7 +46,9 @@ except ImportError:
45
46
  try:
46
47
  from . import das
47
48
  except Exception:
48
- logger.warning("Failed to import the das module.\nIgnore if you do not want to use das.\n" "Otherwise follow these instructions to install:\n" "https://janclemenslab.org/das/install.html")
49
+ logger.warning(
50
+ "Failed to import the das module.\nIgnore if you do not want to use das.\nOtherwise follow these instructions to install:\nhttps://janclemenslab.org/das/install.html"
51
+ )
49
52
 
50
53
  sys.setrecursionlimit(10**6) # increase recursion limit to avoid errors when keeping key pressed for a long time
51
54
  package_dir: str = xarray_behave.__path__[0]
@@ -154,7 +157,9 @@ class MainWindow(QtWidgets.QMainWindow):
154
157
 
155
158
  def save_swaps(self, qt_keycode=None):
156
159
  savefilename = self._get_filename_from_ds(suffix="_idswaps.txt")
157
- savefilename, _ = QtWidgets.QFileDialog.getSaveFileName(self, "Save swaps to", str(savefilename), filter="txt files (*.txt);;all files (*)")
160
+ savefilename, _ = QtWidgets.QFileDialog.getSaveFileName(
161
+ self, "Save swaps to", str(savefilename), filter="txt files (*.txt);;all files (*)"
162
+ )
158
163
  if len(savefilename):
159
164
  logger.info(f" Saving list of swap indices to {savefilename}.")
160
165
  os.makedirs(os.path.dirname(savefilename), exist_ok=True)
@@ -163,7 +168,9 @@ class MainWindow(QtWidgets.QMainWindow):
163
168
 
164
169
  def save_definitions(self, qt_keycode=None):
165
170
  savefilename = self._get_filename_from_ds(suffix="_definitions.csv")
166
- savefilename, _ = QtWidgets.QFileDialog.getSaveFileName(self, caption="Save definitions to", dir=str(savefilename), filter="CSV files (*_definitions.csv);;all files (*)")
171
+ savefilename, _ = QtWidgets.QFileDialog.getSaveFileName(
172
+ self, caption="Save definitions to", dir=str(savefilename), filter="CSV files (*_definitions.csv);;all files (*)"
173
+ )
167
174
  if len(savefilename):
168
175
  # get defs from annot and save them to csv
169
176
  logger.info(f" Saving definitions to {savefilename}.")
@@ -403,7 +410,9 @@ class MainWindow(QtWidgets.QMainWindow):
403
410
  self.export_to_h5(savefilename_trunk + ".h5", start_seconds, end_seconds) # , form_data["scale_audio"])
404
411
 
405
412
  logger.info(f" annotations to CSV: {savefilename_trunk + '.csv'}.")
406
- self.export_to_csv(savefilename_trunk + "_annotations.csv", start_seconds, end_seconds, which_events, match_to_samples=True)
413
+ self.export_to_csv(
414
+ savefilename_trunk + "_annotations.csv", start_seconds, end_seconds, which_events, match_to_samples=True
415
+ )
407
416
  logger.info("Done.")
408
417
 
409
418
  def das_make(self, qt_keycode=None):
@@ -504,7 +513,9 @@ class MainWindow(QtWidgets.QMainWindow):
504
513
  return form_data
505
514
 
506
515
  def save(arg):
507
- savefilename, _ = QtWidgets.QFileDialog.getSaveFileName(self, "Save configuration to", "", filter="yaml files (*.yaml);;all files (*)")
516
+ savefilename, _ = QtWidgets.QFileDialog.getSaveFileName(
517
+ self, "Save configuration to", "", filter="yaml files (*.yaml);;all files (*)"
518
+ )
508
519
  if len(savefilename):
509
520
  data = dialog.form.get_form_data()
510
521
  logger.info(f" Saving form fields to {savefilename}.")
@@ -515,7 +526,9 @@ class MainWindow(QtWidgets.QMainWindow):
515
526
  def make_cli(arg):
516
527
  script_ext = "cmd" if os.name == "nt" else "sh"
517
528
  savefilename = "train." + script_ext
518
- savefilename, _ = QtWidgets.QFileDialog.getSaveFileName(self, "Script name", savefilename, filter=f"script (*.{script_ext};;all files (*)")
529
+ savefilename, _ = QtWidgets.QFileDialog.getSaveFileName(
530
+ self, "Script name", savefilename, filter=f"script (*.{script_ext};;all files (*)"
531
+ )
519
532
  if len(savefilename):
520
533
  form_data = dialog.form.get_form_data()
521
534
  form_data = _filter_form_data(form_data, is_cli=True)
@@ -523,7 +536,7 @@ class MainWindow(QtWidgets.QMainWindow):
523
536
  cmd = "python3 -m das.train"
524
537
  # FIXME formatting
525
538
  for key, val in form_data.items():
526
- cmd += f" --{key.replace('_','-')} {val}"
539
+ cmd += f" --{key.replace('_', '-')} {val}"
527
540
  with open(savefilename, "w") as f:
528
541
  f.write(cmd)
529
542
 
@@ -704,27 +717,23 @@ class MainWindow(QtWidgets.QMainWindow):
704
717
 
705
718
  params = das.utils.load_params(model_path)
706
719
  if audio.shape[0] < params["nb_hist"]:
707
- logger.warning(f" Aborting. Audio has fewer samples ({audio.shape[0]}) shorter" f" than network chunk size ({params['nb_hist']})." " Fix by select longer audio.")
720
+ logger.warning(
721
+ f" Aborting. Audio has fewer samples ({audio.shape[0]}) shorter than network chunk size ({params['nb_hist']}). Fix by select longer audio."
722
+ )
708
723
  return
709
724
 
710
725
  # select batch size so that at least 10 batches are run
711
726
  # minimizes loss of annotations from batch size "quantization" errors
712
727
  batch_size = 32
713
- nb_batches = int(np.floor((audio.shape[0] - ((batch_size - 1) + params["nb_hist"])) / (params["stride"] * (batch_size))))
728
+ nb_batches = int(
729
+ np.floor((audio.shape[0] - ((batch_size - 1) + params["nb_hist"])) / (params["stride"] * (batch_size)))
730
+ )
714
731
  while nb_batches < 10 and batch_size > 1:
715
732
  batch_size -= 1
716
733
 
717
734
  logger.info(" Running inference on audio.")
718
735
  logger.info(f" Model from {model_path}.")
719
736
  params = das.utils.load_params(model_path)
720
- fs_model = params["samplerate_x_Hz"]
721
- fs_audio = self.ds.song_raw.attrs["sampling_rate_Hz"]
722
-
723
- if form_data["resample"] and fs_audio and fs_audio != fs_model:
724
- logger.info(f" Resampling. Audio rate is {fs_audio}Hz but model was trained on data with {fs_model}Hz.")
725
- audio = das.utils.resample(audio, fs_audio, fs_model)
726
-
727
- import rich
728
737
 
729
738
  rich.print(form_data)
730
739
  events, segments, _, _ = das.predict.predict(
@@ -742,7 +751,7 @@ class MainWindow(QtWidgets.QMainWindow):
742
751
  bandpass_low_freq=form_data["bandpass_low_freq"],
743
752
  bandpass_up_freq=form_data["bandpass_up_freq"],
744
753
  resample=form_data["resample"],
745
- fs_audio=fs_audio,
754
+ fs_audio=self.fs_song,
746
755
  )
747
756
 
748
757
  # Process detected song
@@ -780,7 +789,11 @@ class MainWindow(QtWidgets.QMainWindow):
780
789
  # segments['sequence'] = [s for s in segments['sequence'] if s is not None]
781
790
  detected_segment_names = np.unique(segments["sequence"])
782
791
  # if these are indices, get corresponding names
783
- if len(detected_segment_names) and type(detected_segment_names[0]) is not str and type(detected_segment_names[0]) is not np.str_:
792
+ if (
793
+ len(detected_segment_names)
794
+ and type(detected_segment_names[0]) is not str
795
+ and type(detected_segment_names[0]) is not np.str_
796
+ ):
784
797
  detected_segment_names = [segments["names"][ii] for ii in detected_segment_names]
785
798
 
786
799
  if len(detected_segment_names) > 0: # and detected_segment_names[0] is not None:
@@ -796,7 +809,9 @@ class MainWindow(QtWidgets.QMainWindow):
796
809
 
797
810
  onsets_seconds = self.ds.sampletime[onsets_samples]
798
811
  offsets_seconds = self.ds.sampletime[offsets_samples]
799
- for name_or_index, onset_seconds, offset_seconds in zip(segments["sequence"], onsets_seconds, offsets_seconds):
812
+ for name_or_index, onset_seconds, offset_seconds in zip(
813
+ segments["sequence"], onsets_seconds, offsets_seconds
814
+ ):
800
815
  if type(name_or_index) is not str and type(detected_segment_names[0]) is not np.str_:
801
816
  segment_name = segments["names"][name_or_index]
802
817
  else:
@@ -845,8 +860,15 @@ class MainWindow(QtWidgets.QMainWindow):
845
860
  except KeyError:
846
861
  pass
847
862
  except KeyError:
848
- logger.info(f"{filename} no sample rate info in NPZ file." f"Need to save 'samplerate' variable with the audio data. Defaulting to {samplerate}")
849
- elif filename.endswith(".h5") or filename.endswith(".hdfs") or filename.endswith(".hdf5") or filename.endswith(".mat"):
863
+ logger.info(
864
+ f"{filename} no sample rate info in NPZ file.Need to save 'samplerate' variable with the audio data. Defaulting to {samplerate}"
865
+ )
866
+ elif (
867
+ filename.endswith(".h5")
868
+ or filename.endswith(".hdfs")
869
+ or filename.endswith(".hdf5")
870
+ or filename.endswith(".mat")
871
+ ):
850
872
  # infer data set (for hdf5) and populate form
851
873
  try:
852
874
  # list all data sets in file and add to list
@@ -950,7 +972,9 @@ class MainWindow(QtWidgets.QMainWindow):
950
972
  if not dirname:
951
973
  dirname = QtWidgets.QFileDialog.getExistingDirectory(parent=None, caption="Select data directory")
952
974
  if dirname:
953
- dialog = YamlDialog(yaml_file=package_dir + "/gui/forms/from_dir.yaml", title=f"Dataset from data directory {dirname}")
975
+ dialog = YamlDialog(
976
+ yaml_file=package_dir + "/gui/forms/from_dir.yaml", title=f"Dataset from data directory {dirname}"
977
+ )
954
978
 
955
979
  # initialize form data with cli args
956
980
  dialog.form["pixel_size_mm"] = pixel_size_mm # and un-disable
@@ -1025,7 +1049,9 @@ class MainWindow(QtWidgets.QMainWindow):
1025
1049
 
1026
1050
  # add event categories if they are missing in the dataset
1027
1051
  if "song_events" in ds and "event_categories" not in ds:
1028
- event_categories = ["segment" if "sine" in evt or "syllable" in evt else "event" for evt in ds.event_types.values]
1052
+ event_categories = [
1053
+ "segment" if "sine" in evt or "syllable" in evt else "event" for evt in ds.event_types.values
1054
+ ]
1029
1055
  ds = ds.assign_coords({"event_categories": (("event_types"), event_categories)})
1030
1056
 
1031
1057
  # add missing song types
@@ -1083,7 +1109,9 @@ class MainWindow(QtWidgets.QMainWindow):
1083
1109
  if not filename:
1084
1110
  filename, _ = QtWidgets.QFileDialog.getOpenFileName(parent=None, caption="Select dataset")
1085
1111
  if filename:
1086
- dialog = YamlDialog(yaml_file=package_dir + "/gui/forms/from_zarr.yaml", title=f"Load dataset from zarr file {filename}")
1112
+ dialog = YamlDialog(
1113
+ yaml_file=package_dir + "/gui/forms/from_zarr.yaml", title=f"Load dataset from zarr file {filename}"
1114
+ )
1087
1115
 
1088
1116
  # initialize form data with cli args
1089
1117
  if spec_freq_min is not None:
@@ -1121,7 +1149,9 @@ class MainWindow(QtWidgets.QMainWindow):
1121
1149
 
1122
1150
  # add event categories if they are missing in the dataset
1123
1151
  if "song_events" in ds and "event_categories" not in ds:
1124
- event_categories = ["segment" if "sine" in evt or "syllable" in evt else "event" for evt in ds.event_types.values]
1152
+ event_categories = [
1153
+ "segment" if "sine" in evt or "syllable" in evt else "event" for evt in ds.event_types.values
1154
+ ]
1125
1155
  ds = ds.assign_coords({"event_categories": (("event_types"), event_categories)})
1126
1156
  logger.info(ds)
1127
1157
  vr = None
@@ -1166,11 +1196,15 @@ class MainWindow(QtWidgets.QMainWindow):
1166
1196
 
1167
1197
  def save_dataset(self, qt_keycode=None):
1168
1198
  try:
1169
- savefilename = Path(self.ds.attrs["root"], self.ds.attrs["dat_path"], self.ds.attrs["datename"], f"{self.ds.attrs['datename']}.zarr")
1199
+ savefilename = Path(
1200
+ self.ds.attrs["root"], self.ds.attrs["dat_path"], self.ds.attrs["datename"], f"{self.ds.attrs['datename']}.zarr"
1201
+ )
1170
1202
  except KeyError:
1171
1203
  savefilename = ""
1172
1204
 
1173
- savefilename, _ = QtWidgets.QFileDialog.getSaveFileName(self, "Save dataset to", str(savefilename), filter="zarr files (*.zarr);;all files (*)")
1205
+ savefilename, _ = QtWidgets.QFileDialog.getSaveFileName(
1206
+ self, "Save dataset to", str(savefilename), filter="zarr files (*.zarr);;all files (*)"
1207
+ )
1174
1208
 
1175
1209
  if len(savefilename):
1176
1210
  file_exists = os.path.exists(savefilename)
@@ -1422,10 +1456,16 @@ class PSV(MainWindow):
1422
1456
  self._add_keyed_menuitem(view_video, "Change other fly", self.change_other_fly, "Z")
1423
1457
  self._add_keyed_menuitem(view_video, "Swap flies", self.swap_flies, "X")
1424
1458
  view_video.addSeparator()
1425
- self._add_keyed_menuitem(view_video, "Move poses", partial(self.toggle, "move_poses"), "B", checkable=True, checked=self.move_poses)
1459
+ self._add_keyed_menuitem(
1460
+ view_video, "Move poses", partial(self.toggle, "move_poses"), "B", checkable=True, checked=self.move_poses
1461
+ )
1426
1462
  view_video.addSeparator()
1427
- self._add_keyed_menuitem(view_video, "Show fly position", partial(self.toggle, "show_dot"), "O", checkable=True, checked=self.show_dot)
1428
- self._add_keyed_menuitem(view_video, "Show poses", partial(self.toggle, "show_poses"), "P", checkable=True, checked=self.show_poses)
1463
+ self._add_keyed_menuitem(
1464
+ view_video, "Show fly position", partial(self.toggle, "show_dot"), "O", checkable=True, checked=self.show_dot
1465
+ )
1466
+ self._add_keyed_menuitem(
1467
+ view_video, "Show poses", partial(self.toggle, "show_poses"), "P", checkable=True, checked=self.show_poses
1468
+ )
1429
1469
 
1430
1470
  view_audio = self.bar.addMenu("Audio")
1431
1471
  self._add_keyed_menuitem(view_audio, "Play waveform through speakers", self.play_audio, "E")
@@ -1449,7 +1489,9 @@ class PSV(MainWindow):
1449
1489
  self._add_keyed_menuitem(view_audio, "Select previous channel", self.set_next_channel, "Up")
1450
1490
  self._add_keyed_menuitem(view_audio, "Select next channel", self.set_prev_channel, "Down")
1451
1491
  view_audio.addSeparator()
1452
- self._add_keyed_menuitem(view_audio, "Show spectrogram", partial(self.toggle, "show_spec"), None, checkable=True, checked=self.show_spec)
1492
+ self._add_keyed_menuitem(
1493
+ view_audio, "Show spectrogram", partial(self.toggle, "show_spec"), None, checkable=True, checked=self.show_spec
1494
+ )
1453
1495
  self._add_keyed_menuitem(view_audio, "Increase frequency resolution", self.inc_freq_res, "R")
1454
1496
  self._add_keyed_menuitem(view_audio, "Increase temporal resolution", self.dec_freq_res, "T")
1455
1497
  view_audio.addSeparator()
@@ -1503,20 +1545,34 @@ class PSV(MainWindow):
1503
1545
  self._add_keyed_menuitem(view_annotations, "Generate proposal by envelope thresholding", self.threshold, "I")
1504
1546
  self._add_keyed_menuitem(view_annotations, "Adjust thresholding mode", self.set_envelope_computation)
1505
1547
  view_annotations.addSeparator()
1506
- self._add_keyed_menuitem(view_annotations, "Approve proposals for active song type in view", self.approve_active_proposals, "G")
1507
- self._add_keyed_menuitem(view_annotations, "Approve proposals for all song types in view", self.approve_all_proposals, "H")
1548
+ self._add_keyed_menuitem(
1549
+ view_annotations, "Approve proposals for active song type in view", self.approve_active_proposals, "G"
1550
+ )
1551
+ self._add_keyed_menuitem(
1552
+ view_annotations, "Approve proposals for all song types in view", self.approve_all_proposals, "H"
1553
+ )
1508
1554
 
1509
1555
  view_view = self.bar.addMenu("View")
1510
1556
  self._add_keyed_menuitem(view_view, "Video, waveform, and spectrogram display parameters", self.set_spec_freq)
1511
1557
  view_view.addSeparator()
1512
1558
  # TODO? only show these if tracks and/or video
1513
- self._add_keyed_menuitem(view_view, "Show spectrogram", partial(self.toggle, "show_spec"), None, checkable=True, checked=self.show_spec)
1514
- self._add_keyed_menuitem(view_view, "Show waveform", partial(self.toggle, "show_trace"), None, checkable=True, checked=self.show_trace)
1515
- self._add_keyed_menuitem(view_view, "Show ethogram", partial(self.toggle, "show_annot"), None, checkable=True, checked=self.show_annot)
1559
+ self._add_keyed_menuitem(
1560
+ view_view, "Show spectrogram", partial(self.toggle, "show_spec"), None, checkable=True, checked=self.show_spec
1561
+ )
1562
+ self._add_keyed_menuitem(
1563
+ view_view, "Show waveform", partial(self.toggle, "show_trace"), None, checkable=True, checked=self.show_trace
1564
+ )
1565
+ self._add_keyed_menuitem(
1566
+ view_view, "Show ethogram", partial(self.toggle, "show_annot"), None, checkable=True, checked=self.show_annot
1567
+ )
1516
1568
  if "pose_positions_allo" in self.ds:
1517
- self._add_keyed_menuitem(view_view, "Show tracks", partial(self.toggle, "show_tracks"), None, checkable=True, checked=self.show_tracks)
1569
+ self._add_keyed_menuitem(
1570
+ view_view, "Show tracks", partial(self.toggle, "show_tracks"), None, checkable=True, checked=self.show_tracks
1571
+ )
1518
1572
  if self.vr is not None:
1519
- self._add_keyed_menuitem(view_view, "Show movie", partial(self.toggle, "show_movie"), None, checkable=True, checked=self.show_movie)
1573
+ self._add_keyed_menuitem(
1574
+ view_view, "Show movie", partial(self.toggle, "show_movie"), None, checkable=True, checked=self.show_movie
1575
+ )
1520
1576
 
1521
1577
  self.hl = QtWidgets.QHBoxLayout()
1522
1578
 
@@ -1887,7 +1943,9 @@ class PSV(MainWindow):
1887
1943
 
1888
1944
  def delete_current_events(self, qt_keycode):
1889
1945
  if self.current_event_index is not None:
1890
- deleted_events = self.event_times.delete_range(self.current_event_name, self.time0 / self.fs_song, self.time1 / self.fs_song)
1946
+ deleted_events = self.event_times.delete_range(
1947
+ self.current_event_name, self.time0 / self.fs_song, self.time1 / self.fs_song
1948
+ )
1891
1949
  nb_deleted_events = len(deleted_events)
1892
1950
  if nb_deleted_events:
1893
1951
  logger.info(f" Deleted {nb_deleted_events} annotation(s) of type {self.current_event_name}.")
@@ -1909,7 +1967,9 @@ class PSV(MainWindow):
1909
1967
  def threshold(self, qt_keycode):
1910
1968
  if self.STOP and self.current_event_name is not None:
1911
1969
  if self.event_times.categories[self.current_event_name] == "event":
1912
- indexes = peakutils.indexes(self.envelope, thres=self.slice_view.threshold, min_dist=self.thres_min_dist * self.fs_song, thres_abs=True)
1970
+ indexes = peakutils.indexes(
1971
+ self.envelope, thres=self.slice_view.threshold, min_dist=self.thres_min_dist * self.fs_song, thres_abs=True
1972
+ )
1913
1973
  # add events to current song type
1914
1974
  for t in self.x[indexes]:
1915
1975
  self.event_times.add_time(self.current_event_name, t)
@@ -2061,7 +2121,9 @@ class PSV(MainWindow):
2061
2121
  dialog.exec_()
2062
2122
 
2063
2123
  def set_envelope_computation(self, qt_keycode):
2064
- dialog = YamlDialog(yaml_file=package_dir + "/gui/forms/envelope_computation.yaml", title="Set options for envelope computation")
2124
+ dialog = YamlDialog(
2125
+ yaml_file=package_dir + "/gui/forms/envelope_computation.yaml", title="Set options for envelope computation"
2126
+ )
2065
2127
 
2066
2128
  dialog.form["thres_min_dist"] = self.thres_min_dist
2067
2129
  dialog.form["thres_env_std"] = self.thres_env_std
@@ -2139,7 +2201,9 @@ class PSV(MainWindow):
2139
2201
  i1 = int(self.time1 / self.fs_ratio)
2140
2202
 
2141
2203
  self.x_tracks = self.ds.time.data[i0:i1]
2142
- self.y_tracks = self.ds.pose_positions_allo.data[i0:i1, self.focal_fly, self.track_sel_names, self.track_sel_coords]
2204
+ self.y_tracks = self.ds.pose_positions_allo.data[
2205
+ i0:i1, self.focal_fly, self.track_sel_names, self.track_sel_coords
2206
+ ]
2143
2207
  self.tracks_view.update_trace()
2144
2208
  self.tracks_view.show()
2145
2209
  else:
@@ -2186,9 +2250,13 @@ class PSV(MainWindow):
2186
2250
  if self.event_times.categories[event_name] == "segment":
2187
2251
  for onset, offset in zip(events_in_view[:, 0], events_in_view[:, 1]):
2188
2252
  if self.show_trace:
2189
- self.slice_view.add_segment(onset, offset, event_index, brush=event_brush, pen=event_pen, movable=movable, text=segment_text)
2253
+ self.slice_view.add_segment(
2254
+ onset, offset, event_index, brush=event_brush, pen=event_pen, movable=movable, text=segment_text
2255
+ )
2190
2256
  if self.show_tracks:
2191
- self.tracks_view.add_segment(onset, offset, event_index, brush=event_brush, pen=event_pen, movable=movable, text=segment_text)
2257
+ self.tracks_view.add_segment(
2258
+ onset, offset, event_index, brush=event_brush, pen=event_pen, movable=movable, text=segment_text
2259
+ )
2192
2260
  if self.show_annot:
2193
2261
  self.annot_view.add_segment(
2194
2262
  onset,
@@ -2200,7 +2268,9 @@ class PSV(MainWindow):
2200
2268
  text=segment_text,
2201
2269
  )
2202
2270
  if self.show_spec:
2203
- self.spec_view.add_segment(onset, offset, event_index, brush=event_brush, pen=event_pen, movable=movable, text=segment_text)
2271
+ self.spec_view.add_segment(
2272
+ onset, offset, event_index, brush=event_brush, pen=event_pen, movable=movable, text=segment_text
2273
+ )
2204
2274
  elif self.event_times.categories[event_name] == "event":
2205
2275
  if self.show_trace:
2206
2276
  self.slice_view.add_event(events_in_view[:, 0], event_index, event_pen, movable=movable, text=segment_text)
@@ -2233,7 +2303,9 @@ class PSV(MainWindow):
2233
2303
 
2234
2304
  new_region = region.getRegion()
2235
2305
  self.event_times.move_time(event_name_to_move, region.bounds, new_region)
2236
- logger.info(f" Moved {event_name_to_move} from t=[{region.bounds[0]:1.4f}:{region.bounds[1]:1.4f}] to [{new_region[0]:1.4f}:{new_region[1]:1.4f}] seconds.")
2306
+ logger.info(
2307
+ f" Moved {event_name_to_move} from t=[{region.bounds[0]:1.4f}:{region.bounds[1]:1.4f}] to [{new_region[0]:1.4f}:{new_region[1]:1.4f}] seconds."
2308
+ )
2237
2309
 
2238
2310
  # FIXME for moving annotations in ethogram - fails in pyside6
2239
2311
  if self.annot_view.mousePoint is not None:
@@ -2305,7 +2377,10 @@ class PSV(MainWindow):
2305
2377
  fly_pos = self.ds.pose_positions_allo.data[self.index_other, :, self.pose_center_index, :]
2306
2378
  fly_pos = np.array(fly_pos) # in case this is a dask.array
2307
2379
  if self.crop: # transform fly pos to coordinates of the cropped box
2308
- box_center = self.ds.pose_positions_allo.data[self.index_other, self.focal_fly, self.pose_center_index] + self.box_size / 2
2380
+ box_center = (
2381
+ self.ds.pose_positions_allo.data[self.index_other, self.focal_fly, self.pose_center_index]
2382
+ + self.box_size / 2
2383
+ )
2309
2384
  box_center = np.array(box_center) # in case this is a dask.array
2310
2385
  fly_pos = fly_pos - box_center
2311
2386
  fly_dist = np.sum((fly_pos - np.array([mouseY, mouseX])) ** 2, axis=-1)
@@ -2345,7 +2420,9 @@ class PSV(MainWindow):
2345
2420
  if self.event_times.categories[self.current_event_name] == "event":
2346
2421
  logger.info(f" Changed event at {changed_time[0]:1.4f} from {old_name} to {new_name}.")
2347
2422
  else:
2348
- logger.info(f" Changed segment at {changed_time[0]:1.4f}:{changed_time[1]:1.4f} from {old_name} to {new_name}.")
2423
+ logger.info(
2424
+ f" Changed segment at {changed_time[0]:1.4f}:{changed_time[1]:1.4f} from {old_name} to {new_name}."
2425
+ )
2349
2426
  self.update_xy()
2350
2427
  elif mouseButton == QtCore.Qt.MouseButton.LeftButton: # add event
2351
2428
  if self.current_event_index is not None:
@@ -2365,12 +2442,16 @@ class PSV(MainWindow):
2365
2442
  stop_seconds=mouseT,
2366
2443
  channel=self.current_channel_index,
2367
2444
  )
2368
- logger.info(f" Added {self.current_event_name} on channel {self.current_channel_index} at t=[{self.sinet0:1.4f}:{mouseT:1.4f}] seconds.")
2445
+ logger.info(
2446
+ f" Added {self.current_event_name} on channel {self.current_channel_index} at t=[{self.sinet0:1.4f}:{mouseT:1.4f}] seconds."
2447
+ )
2369
2448
  self.sinet0 = None
2370
2449
  if self.event_times.categories[self.current_event_name] == "event":
2371
2450
  self.sinet0 = None
2372
2451
  self.event_times.add_time(self.current_event_name, start_seconds=mouseT, channel=self.current_channel_index)
2373
- logger.info(f" Added {self.current_event_name} on channel {self.current_channel_index} at t={mouseT:1.4f} seconds.")
2452
+ logger.info(
2453
+ f" Added {self.current_event_name} on channel {self.current_channel_index} at t={mouseT:1.4f} seconds."
2454
+ )
2374
2455
  self.update_xy()
2375
2456
  else:
2376
2457
  self.sinet0 = None
@@ -2462,7 +2543,7 @@ class PSV(MainWindow):
2462
2543
  )
2463
2544
  self.event_times.delete_range(name, t0, t1, strict=False)
2464
2545
  if len(within_range_times):
2465
- logger.info(f" {len(within_range_times)} events of {name} to {name[:-len(proposal_suffix)]}")
2546
+ logger.info(f" {len(within_range_times)} events of {name} to {name[: -len(proposal_suffix)]}")
2466
2547
  # update event selector in case the event did not exist yet
2467
2548
  self.nb_eventtypes = len(self.event_times)
2468
2549
  self.eventtype_colors = utils.make_colors(self.nb_eventtypes)
File without changes
File without changes
File without changes