boris-behav-obs 8.27.10__py2.py3-none-any.whl → 9.0.1__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. boris/about.py +7 -5
  2. boris/add_modifier.py +35 -35
  3. boris/add_modifier_ui.py +229 -129
  4. boris/advanced_event_filtering.py +3 -3
  5. boris/analysis_plugins/__init__.py +0 -0
  6. boris/analysis_plugins/number_of_occurences.py +60 -0
  7. boris/analysis_plugins/number_of_occurences_by_independent_variable.py +72 -0
  8. boris/analysis_plugins/time_budget.py +95 -0
  9. boris/behav_coding_map_creator.py +103 -108
  10. boris/behavior_binary_table.py +1 -1
  11. boris/behaviors_coding_map.py +8 -8
  12. boris/coding_pad.py +6 -6
  13. boris/config.py +6 -0
  14. boris/config_file.py +1 -1
  15. boris/connections.py +4 -2
  16. boris/converters.py +2 -3
  17. boris/converters_ui.py +187 -110
  18. boris/cooccurence.py +2 -2
  19. boris/core.py +340 -94
  20. boris/core_qrc.py +16088 -13246
  21. boris/core_ui.py +922 -812
  22. boris/dialog.py +14 -13
  23. boris/duration_widget.py +5 -5
  24. boris/edit_event.py +1 -1
  25. boris/edit_event_ui.py +162 -88
  26. boris/event_operations.py +4 -25
  27. boris/events_cursor.py +17 -9
  28. boris/events_snapshots.py +5 -5
  29. boris/exclusion_matrix.py +1 -1
  30. boris/export_events.py +38 -28
  31. boris/export_observation.py +1 -1
  32. boris/external_processes.py +3 -5
  33. boris/geometric_measurement.py +49 -26
  34. boris/gui_utilities.py +31 -30
  35. boris/import_observations.py +2 -4
  36. boris/irr.py +1 -1
  37. boris/latency.py +1 -1
  38. boris/map_creator.py +77 -89
  39. boris/measurement_widget.py +4 -4
  40. boris/media_file.py +2 -4
  41. boris/menu_options.py +1 -3
  42. boris/modifiers_coding_map.py +4 -4
  43. boris/mpv2.py +0 -2
  44. boris/observation.py +124 -29
  45. boris/observation_operations.py +18 -40
  46. boris/observation_ui.py +566 -374
  47. boris/observations_list.py +6 -6
  48. boris/param_panel.py +2 -2
  49. boris/param_panel_ui.py +246 -141
  50. boris/player_dock_widget.py +16 -21
  51. boris/plot_data_module.py +6 -6
  52. boris/plot_events_rt.py +7 -8
  53. boris/plot_spectrogram_rt.py +7 -8
  54. boris/plot_waveform_rt.py +6 -7
  55. boris/plugins.py +79 -0
  56. boris/preferences.py +127 -17
  57. boris/preferences_ui.py +464 -240
  58. boris/project.py +69 -72
  59. boris/project_functions.py +233 -31
  60. boris/project_import_export.py +59 -67
  61. boris/project_ui.py +672 -440
  62. boris/qrc_boris.py +6 -3
  63. boris/qrc_boris5.py +6 -3
  64. boris/select_modifiers.py +2 -2
  65. boris/select_observations.py +2 -2
  66. boris/select_subj_behav.py +3 -3
  67. boris/state_events.py +1 -1
  68. boris/subjects_pad.py +5 -5
  69. boris/synthetic_time_budget.py +2 -2
  70. boris/time_budget_functions.py +15 -0
  71. boris/time_budget_widget.py +4 -4
  72. boris/transitions.py +34 -25
  73. boris/utilities.py +95 -2
  74. boris/version.py +2 -2
  75. boris/video_equalizer.py +4 -4
  76. boris/video_equalizer_ui.py +199 -130
  77. boris/video_operations.py +1 -1
  78. boris/view_df.py +106 -0
  79. boris/view_df_ui.py +75 -0
  80. boris/write_event.py +9 -1
  81. {boris_behav_obs-8.27.10.dist-info → boris_behav_obs-9.0.1.dist-info}/METADATA +5 -5
  82. boris_behav_obs-9.0.1.dist-info/RECORD +103 -0
  83. {boris_behav_obs-8.27.10.dist-info → boris_behav_obs-9.0.1.dist-info}/WHEEL +1 -1
  84. boris/qdarkstyle/__init__.py +0 -479
  85. boris/qdarkstyle/__main__.py +0 -66
  86. boris/qdarkstyle/colorsystem.py +0 -38
  87. boris/qdarkstyle/dark/__init__.py +0 -1
  88. boris/qdarkstyle/dark/darkstyle_rc.py +0 -11379
  89. boris/qdarkstyle/dark/palette.py +0 -38
  90. boris/qdarkstyle/example/__init__.py +0 -4
  91. boris/qdarkstyle/example/__main__.py +0 -386
  92. boris/qdarkstyle/example/ui/__init__.py +0 -4
  93. boris/qdarkstyle/light/__init__.py +0 -1
  94. boris/qdarkstyle/light/lightstyle_rc.py +0 -11305
  95. boris/qdarkstyle/light/palette.py +0 -37
  96. boris/qdarkstyle/palette.py +0 -102
  97. boris/qdarkstyle/utils/__init__.py +0 -73
  98. boris/qdarkstyle/utils/__main__.py +0 -96
  99. boris/qdarkstyle/utils/images.py +0 -449
  100. boris/qdarkstyle/utils/scss.py +0 -318
  101. boris/vlc_local.py +0 -83
  102. boris_behav_obs-8.27.10.dist-info/RECORD +0 -114
  103. {boris_behav_obs-8.27.10.dist-info → boris_behav_obs-9.0.1.dist-info}/LICENSE.TXT +0 -0
  104. {boris_behav_obs-8.27.10.dist-info → boris_behav_obs-9.0.1.dist-info}/entry_points.txt +0 -0
  105. {boris_behav_obs-8.27.10.dist-info → boris_behav_obs-9.0.1.dist-info}/top_level.txt +0 -0
boris/export_events.py CHANGED
@@ -38,7 +38,7 @@ from . import project_functions
38
38
  from . import dialog
39
39
  from . import db_functions
40
40
 
41
- from PyQt5.QtWidgets import QApplication, QFileDialog, QMessageBox, QInputDialog
41
+ from PySide6.QtWidgets import QApplication, QFileDialog, QMessageBox, QInputDialog
42
42
 
43
43
 
44
44
  def export_events_as_behavioral_sequences(self, separated_subjects=False, timed=False):
@@ -93,28 +93,28 @@ def export_events_as_behavioral_sequences(self, separated_subjects=False, timed=
93
93
  QMessageBox.warning(None, cfg.programName, "Select subject(s) and behavior(s) to analyze")
94
94
  return
95
95
 
96
- fn = QFileDialog().getSaveFileName(self, "Export events as behavioral sequences", "", "Text files (*.txt);;All files (*)")
97
- file_name = fn[0] if type(fn) is tuple else fn
98
-
99
- if file_name:
100
- r, msg = export_observation.observation_to_behavioral_sequences(
101
- pj=self.pj,
102
- selected_observations=selected_observations,
103
- parameters=parameters,
104
- behaviors_separator=self.behav_seq_separator,
105
- separated_subjects=separated_subjects,
106
- timed=timed,
107
- file_name=file_name,
96
+ file_name, _ = QFileDialog.getSaveFileName(self, "Export events as behavioral sequences", "", "Text files (*.txt);;All files (*)")
97
+
98
+ if not file_name:
99
+ return
100
+ r, msg = export_observation.observation_to_behavioral_sequences(
101
+ pj=self.pj,
102
+ selected_observations=selected_observations,
103
+ parameters=parameters,
104
+ behaviors_separator=self.behav_seq_separator,
105
+ separated_subjects=separated_subjects,
106
+ timed=timed,
107
+ file_name=file_name,
108
+ )
109
+ if not r:
110
+ logging.critical(f"Error while exporting events as behavioral sequences: {msg}")
111
+ QMessageBox.critical(
112
+ None,
113
+ cfg.programName,
114
+ f"Error while exporting events as behavioral sequences:<br>{msg}",
115
+ QMessageBox.Ok | QMessageBox.Default,
116
+ QMessageBox.NoButton,
108
117
  )
109
- if not r:
110
- logging.critical(f"Error while exporting events as behavioral sequences: {msg}")
111
- QMessageBox.critical(
112
- None,
113
- cfg.programName,
114
- f"Error while exporting events as behavioral sequences:<br>{msg}",
115
- QMessageBox.Ok | QMessageBox.Default,
116
- QMessageBox.NoButton,
117
- )
118
118
 
119
119
 
120
120
  def export_tabular_events(self, mode: str = "tabular") -> None:
@@ -215,7 +215,12 @@ def export_tabular_events(self, mode: str = "tabular") -> None:
215
215
  return
216
216
 
217
217
  if len(selected_observations) == 1:
218
- file_name, filter_ = QFileDialog().getSaveFileName(self, "Export events", "", ";;".join(available_formats))
218
+ file_dialog_options = QFileDialog.Options()
219
+ file_dialog_options |= QFileDialog.DontConfirmOverwrite
220
+
221
+ file_name, filter_ = QFileDialog().getSaveFileName(
222
+ self, "Export events", "", ";;".join(available_formats), options=file_dialog_options
223
+ )
219
224
  if not file_name:
220
225
  return
221
226
 
@@ -223,7 +228,7 @@ def export_tabular_events(self, mode: str = "tabular") -> None:
223
228
  if pl.Path(file_name).suffix != "." + output_format:
224
229
  file_name = str(pl.Path(file_name)) + "." + output_format
225
230
  # check if file with new extension already exists
226
- if pl.Path(file_name).is_file():
231
+ if pl.Path(file_name).exists():
227
232
  if (
228
233
  dialog.MessageDialog(cfg.programName, f"The file {file_name} already exists.", [cfg.CANCEL, cfg.OVERWRITE])
229
234
  == cfg.CANCEL
@@ -398,7 +403,12 @@ def export_aggregated_events(self):
398
403
  cfg.RDS,
399
404
  )
400
405
 
401
- fileName, filter_ = QFileDialog().getSaveFileName(self, "Export aggregated events", "", ";;".join(file_formats))
406
+ file_dialog_options = QFileDialog.Options()
407
+ file_dialog_options |= QFileDialog.DontConfirmOverwrite
408
+
409
+ fileName, filter_ = QFileDialog().getSaveFileName(
410
+ self, "Export aggregated events", "", ";;".join(file_formats), options=file_dialog_options
411
+ )
402
412
 
403
413
  if not fileName:
404
414
  return
@@ -407,7 +417,7 @@ def export_aggregated_events(self):
407
417
  if pl.Path(fileName).suffix != "." + outputFormat:
408
418
  # check if file with new extension already exists
409
419
  fileName = str(pl.Path(fileName)) + "." + outputFormat
410
- if pl.Path(fileName).is_file():
420
+ if pl.Path(fileName).exists():
411
421
  if dialog.MessageDialog(cfg.programName, f"The file {fileName} already exists.", [cfg.CANCEL, cfg.OVERWRITE]) == cfg.CANCEL:
412
422
  return
413
423
 
@@ -671,8 +681,8 @@ def export_events_as_textgrid(self) -> None:
671
681
  QMessageBox.warning(None, cfg.programName, "Select subject(s) and behavior(s) to export")
672
682
  return
673
683
 
674
- export_dir = QFileDialog(self).getExistingDirectory(
675
- self, "Export events as Praat TextGrid", os.path.expanduser("~"), options=QFileDialog(self).ShowDirsOnly
684
+ export_dir = QFileDialog.getExistingDirectory(
685
+ self, "Export events as Praat TextGrid", os.path.expanduser("~"), options=QFileDialog.ShowDirsOnly
676
686
  )
677
687
  if not export_dir:
678
688
  return
@@ -601,7 +601,7 @@ def dataset_write(dataset: tablib.Dataset, file_name: str, output_format: str, d
601
601
  if output_format == cfg.PANDAS_DF_EXT:
602
602
  df.to_pickle(file_name)
603
603
 
604
- if flag_pyreadr_loaded and output_format == cfg.RDS_EXT:
604
+ if output_format == cfg.RDS_EXT and flag_pyreadr_loaded:
605
605
  pyreadr.write_rds(file_name, df)
606
606
 
607
607
  return True, ""
@@ -20,14 +20,13 @@ This file is part of BORIS.
20
20
 
21
21
  """
22
22
 
23
-
24
23
  import os
25
24
  import tempfile
26
25
  import pathlib as pl
27
26
  import logging
28
27
 
29
- from PyQt5.QtWidgets import QFileDialog, QMessageBox, QInputDialog
30
- from PyQt5.QtCore import (
28
+ from PySide6.QtWidgets import QFileDialog, QMessageBox, QInputDialog
29
+ from PySide6.QtCore import (
31
30
  Qt,
32
31
  QProcess,
33
32
  )
@@ -101,8 +100,7 @@ def ffmpeg_process(self, action: str):
101
100
  else:
102
101
  msg = f"Select one or more video files to {action.replace('_', ' and ')}"
103
102
  file_type = "Video files (*)"
104
- fn = QFileDialog().getOpenFileNames(self, msg, "", file_type)
105
- file_names = fn[0] if type(fn) is tuple else fn
103
+ file_names, _ = QFileDialog().getOpenFileNames(self, msg, "", file_type)
106
104
 
107
105
  if not file_names:
108
106
  return
@@ -33,9 +33,9 @@ except ModuleNotFoundError:
33
33
  flag_pyreadr_loaded = False
34
34
 
35
35
 
36
- from PyQt5.QtCore import QPoint, Qt, pyqtSignal, QEvent
37
- from PyQt5.QtGui import QColor, QPainter, QPolygon, QPixmap
38
- from PyQt5.QtWidgets import (
36
+ from PySide6.QtCore import QPoint, Qt, Signal, QEvent
37
+ from PySide6.QtGui import QColor, QPainter, QPolygon, QPixmap, QAction, QPen
38
+ from PySide6.QtWidgets import (
39
39
  QApplication,
40
40
  QCheckBox,
41
41
  QFileDialog,
@@ -51,7 +51,6 @@ from PyQt5.QtWidgets import (
51
51
  QColorDialog,
52
52
  QSpacerItem,
53
53
  QSizePolicy,
54
- QAction,
55
54
  QDialog,
56
55
  )
57
56
 
@@ -67,10 +66,10 @@ class wgMeasurement(QDialog):
67
66
  widget for geometric measurements
68
67
  """
69
68
 
70
- closeSignal = pyqtSignal()
71
- send_event_signal = pyqtSignal(QEvent)
72
- reload_image_signal = pyqtSignal()
73
- save_picture_signal = pyqtSignal(str)
69
+ closeSignal = Signal()
70
+ send_event_signal = Signal(QEvent)
71
+ reload_image_signal = Signal()
72
+ save_picture_signal = Signal(str)
74
73
  mark_color: str = cfg.ACTIVE_MEASUREMENTS_COLOR
75
74
  flag_saved = True # store if measurements are saved
76
75
  draw_mem: dict = {}
@@ -452,15 +451,24 @@ def draw_point(self, x: int, y: int, color: str, n_player: int = 0) -> None:
452
451
  """
453
452
  draw point on frame-by-frame image
454
453
  """
454
+
455
+ logging.debug("draw_point function")
456
+
455
457
  RADIUS = 6
456
- painter = QPainter()
457
- painter.begin(self.dw_player[n_player].frame_viewer.pixmap())
458
- painter.setPen(QColor(color))
459
- painter.drawEllipse(QPoint(x, y), RADIUS, RADIUS)
460
- # cross inside circle
461
- painter.drawLine(x - RADIUS, y, x + RADIUS, y)
462
- painter.drawLine(x, y - RADIUS, x, y + RADIUS)
463
- painter.end()
458
+
459
+ pixmap_copy = self.dw_player[n_player].frame_viewer.pixmap().copy()
460
+
461
+ painter = QPainter(pixmap_copy)
462
+ try:
463
+ painter.setPen(QPen(QColor(color), 1))
464
+ painter.drawEllipse(QPoint(x, y), RADIUS, RADIUS)
465
+ # cross inside circle
466
+ painter.drawLine(x - RADIUS, y, x + RADIUS, y)
467
+ painter.drawLine(x, y - RADIUS, x, y + RADIUS)
468
+ finally:
469
+ painter.end()
470
+
471
+ self.dw_player[n_player].frame_viewer.setPixmap(pixmap_copy)
464
472
  self.dw_player[n_player].frame_viewer.update()
465
473
 
466
474
 
@@ -468,11 +476,17 @@ def draw_line(self, x1: int, y1: int, x2: int, y2: int, color: str, n_player: in
468
476
  """
469
477
  draw line on frame-by-frame image
470
478
  """
471
- painter = QPainter()
472
- painter.begin(self.dw_player[n_player].frame_viewer.pixmap())
473
- painter.setPen(QColor(color))
474
- painter.drawLine(x1, y1, x2, y2)
475
- painter.end()
479
+
480
+ pixmap_copy = self.dw_player[n_player].frame_viewer.pixmap().copy()
481
+ painter = QPainter(pixmap_copy)
482
+
483
+ try:
484
+ painter.setPen(QColor(color))
485
+ painter.drawLine(x1, y1, x2, y2)
486
+ finally:
487
+ painter.end()
488
+
489
+ self.dw_player[n_player].frame_viewer.setPixmap(pixmap_copy)
476
490
  self.dw_player[n_player].frame_viewer.update()
477
491
 
478
492
 
@@ -520,6 +534,8 @@ def image_clicked(self, n_player: int, event) -> None:
520
534
 
521
535
  x, y = event.pos().x(), event.pos().y()
522
536
 
537
+ logging.debug(f"clicked on {x} {y}")
538
+
523
539
  # convert label coordinates in pixmap coordinates
524
540
  pixmap_x = int(x - (self.dw_player[n_player].frame_viewer.width() - self.dw_player[n_player].frame_viewer.pixmap().width()) / 2)
525
541
  pixmap_y = int(y - (self.dw_player[n_player].frame_viewer.height() - self.dw_player[n_player].frame_viewer.pixmap().height()) / 2)
@@ -892,11 +908,18 @@ def redraw_measurements(self):
892
908
  for x, y in element["coordinates"]:
893
909
  x, y = scale_coord([x, y])
894
910
  polygon.append(QPoint(x, y))
895
- painter = QPainter()
896
- painter.begin(self.dw_player[idx].frame_viewer.pixmap())
897
- painter.setPen(QColor(elements_color))
898
- painter.drawPolygon(polygon)
899
- painter.end()
911
+
912
+ pixmap_copy = self.dw_player[idx].frame_viewer.pixmap().copy()
913
+ painter = QPainter(pixmap_copy)
914
+
915
+ try:
916
+ painter.setPen(QColor(elements_color))
917
+ painter.drawPolygon(polygon)
918
+ finally:
919
+ painter.end()
920
+
921
+ self.dw_player[idx].frame_viewer.setPixmap(pixmap_copy)
922
+
900
923
  dw.frame_viewer.update()
901
924
 
902
925
  if element["object_type"] == cfg.POLYLINE_OBJECT:
boris/gui_utilities.py CHANGED
@@ -21,9 +21,9 @@ Copyright 2012-2024 Olivier Friard
21
21
 
22
22
  import pathlib as pl
23
23
  import logging
24
- from PyQt5.QtCore import QSettings
25
- from PyQt5.QtWidgets import QWidget
26
- from PyQt5.QtGui import QIcon
24
+ from PySide6.QtCore import QSettings
25
+ from PySide6.QtWidgets import QWidget
26
+ from PySide6.QtGui import QIcon
27
27
 
28
28
 
29
29
  def save_geometry(widget: QWidget, widget_name: str):
@@ -59,43 +59,44 @@ def restore_geometry(widget: QWidget, widget_name: str, default_geometry):
59
59
  logging.warning("Error during restoring default")
60
60
 
61
61
 
62
- def set_icons(self):
62
+ def set_icons(self, theme_mode: str) -> None:
63
63
  """
64
64
  set icons of actions
65
65
  """
66
66
 
67
67
  # menu
68
- self.actionTime_budget.setIcon(QIcon(":/time_budget"))
69
- self.actionPlot_events2.setIcon(QIcon(":/plot_events"))
70
- self.action_advanced_event_filtering.setIcon(QIcon(":/filter"))
71
- self.actionPreferences.setIcon(QIcon(":/preferences"))
68
+ self.action_obs_list.setIcon(QIcon(f":/observations_list_{theme_mode}"))
72
69
 
73
- self.action_obs_list.setIcon(QIcon(":/observations_list"))
70
+ self.actionTime_budget.setIcon(QIcon(f":/time_budget_{theme_mode}"))
71
+ self.actionPlot_events2.setIcon(QIcon(f":/plot_events_{theme_mode}"))
72
+ self.action_advanced_event_filtering.setIcon(QIcon(f":/filter_{theme_mode}"))
74
73
 
75
- self.actionPlay.setIcon(QIcon(":/play"))
76
- self.actionReset.setIcon(QIcon(":/reset"))
77
- self.actionJumpBackward.setIcon(QIcon(":/jump_backward"))
78
- self.actionJumpForward.setIcon(QIcon(":/jump_forward"))
74
+ self.actionPreferences.setIcon(QIcon(f":/preferences_{theme_mode}"))
79
75
 
80
- self.actionFaster.setIcon(QIcon(":/faster"))
81
- self.actionSlower.setIcon(QIcon(":/slower"))
82
- self.actionNormalSpeed.setIcon(QIcon(":/normal_speed"))
76
+ self.actionPlay.setIcon(QIcon(f":/play_{theme_mode}"))
77
+ self.actionReset.setIcon(QIcon(f":/reset_{theme_mode}"))
78
+ self.actionJumpBackward.setIcon(QIcon(f":/jump_backward_{theme_mode}"))
79
+ self.actionJumpForward.setIcon(QIcon(f":/jump_forward_{theme_mode}"))
83
80
 
84
- self.actionPrevious.setIcon(QIcon(":/previous"))
85
- self.actionNext.setIcon(QIcon(":/next"))
81
+ self.actionFaster.setIcon(QIcon(f":/faster_{theme_mode}"))
82
+ self.actionSlower.setIcon(QIcon(f":/slower_{theme_mode}"))
83
+ self.actionNormalSpeed.setIcon(QIcon(f":/normal_speed_{theme_mode}"))
86
84
 
87
- self.actionSnapshot.setIcon(QIcon(":/snapshot"))
85
+ self.actionPrevious.setIcon(QIcon(f":/previous_{theme_mode}"))
86
+ self.actionNext.setIcon(QIcon(f":/next_{theme_mode}"))
88
87
 
89
- self.actionFrame_backward.setIcon(QIcon(":/frame_backward"))
90
- self.actionFrame_forward.setIcon(QIcon(":/frame_forward"))
91
- self.actionCloseObs.setIcon(QIcon(":/close_observation"))
92
- self.actionCurrent_Time_Budget.setIcon(QIcon(":/time_budget"))
93
- self.actionPlot_current_observation.setIcon(QIcon(":/plot_events"))
88
+ self.actionSnapshot.setIcon(QIcon(f":/snapshot_{theme_mode}"))
94
89
 
95
- self.actionPlot_events_in_real_time.setIcon(QIcon(":/plot_real_time"))
90
+ self.actionFrame_backward.setIcon(QIcon(f":/frame_backward_{theme_mode}"))
91
+ self.actionFrame_forward.setIcon(QIcon(f":/frame_forward_{theme_mode}"))
92
+ self.actionCloseObs.setIcon(QIcon(f":/close_observation_{theme_mode}"))
93
+ self.actionCurrent_Time_Budget.setIcon(QIcon(f":/time_budget_{theme_mode}"))
94
+ self.actionPlot_current_observation.setIcon(QIcon(f":/plot_events_{theme_mode}"))
96
95
 
97
- self.actionBehavior_bar_plot.setIcon(QIcon(":/plot_time_budget"))
98
- self.actionPlot_current_time_budget.setIcon(QIcon(":/plot_time_budget"))
99
- self.action_geometric_measurements.setIcon(QIcon(":/measurement"))
100
- self.actionFind_in_current_obs.setIcon(QIcon(":/find"))
101
- self.actionExplore_project.setIcon(QIcon(":/explore"))
96
+ self.actionPlot_events_in_real_time.setIcon(QIcon(f":/plot_real_time_{theme_mode}"))
97
+
98
+ self.actionBehavior_bar_plot.setIcon(QIcon(f":/plot_time_budget_{theme_mode}"))
99
+ self.actionPlot_current_time_budget.setIcon(QIcon(f":/plot_time_budget_{theme_mode}"))
100
+ self.action_geometric_measurements.setIcon(QIcon(f":/measurement_{theme_mode}"))
101
+ self.actionFind_in_current_obs.setIcon(QIcon(f":/find_{theme_mode}"))
102
+ self.actionExplore_project.setIcon(QIcon(f":/explore_{theme_mode}"))
@@ -19,13 +19,12 @@ Copyright 2012-2024 Olivier Friard
19
19
  MA 02110-1301, USA.
20
20
  """
21
21
 
22
-
23
22
  import json
24
23
  import datetime
25
24
  from pathlib import Path
26
25
  import pandas as pd
27
26
 
28
- from PyQt5.QtWidgets import (
27
+ from PySide6.QtWidgets import (
29
28
  QMessageBox,
30
29
  QFileDialog,
31
30
  )
@@ -210,10 +209,9 @@ def import_observations(self):
210
209
  import observations from project file
211
210
  """
212
211
 
213
- fn = QFileDialog().getOpenFileName(
212
+ file_name, _ = QFileDialog().getOpenFileName(
214
213
  None, "Choose a file", "", "BORIS project files (*.boris);;Spreadsheet files (*.ods *.xlsx *);;All files (*)"
215
214
  )
216
- file_name = fn[0] if type(fn) is tuple else fn
217
215
 
218
216
  if not file_name:
219
217
  return
boris/irr.py CHANGED
@@ -25,7 +25,7 @@ import logging
25
25
  from decimal import Decimal as dec
26
26
 
27
27
  import numpy as np
28
- from PyQt5.QtWidgets import QInputDialog, QMessageBox
28
+ from PySide6.QtWidgets import QInputDialog, QMessageBox
29
29
 
30
30
  from . import config as cfg
31
31
  from . import db_functions, dialog, project_functions, select_subj_behav
boris/latency.py CHANGED
@@ -29,7 +29,7 @@ from . import dialog
29
29
  from . import select_observations
30
30
  from . import project_functions, observation_operations
31
31
 
32
- from PyQt5.QtWidgets import QMessageBox
32
+ from PySide6.QtWidgets import QMessageBox
33
33
 
34
34
 
35
35
  def get_latency(self):
boris/map_creator.py CHANGED
@@ -24,32 +24,22 @@ import binascii
24
24
  import json
25
25
  import os
26
26
 
27
- from PyQt5.QtCore import (
27
+ from PySide6.QtCore import (
28
28
  Qt,
29
- pyqtSignal,
29
+ Signal,
30
30
  QPoint,
31
31
  QByteArray,
32
32
  QBuffer,
33
33
  QIODevice,
34
34
  QLineF,
35
35
  )
36
- from PyQt5.QtGui import (
37
- QColor,
38
- QBrush,
39
- QMouseEvent,
40
- QPixmap,
41
- QIcon,
42
- QPen,
43
- QPolygon,
44
- QPolygonF,
45
- )
36
+ from PySide6.QtGui import QColor, QBrush, QMouseEvent, QPixmap, QIcon, QPen, QPolygon, QPolygonF, QAction
46
37
 
47
- from PyQt5.QtWidgets import (
38
+ from PySide6.QtWidgets import (
48
39
  QGraphicsPolygonItem,
49
40
  QGraphicsEllipseItem,
50
41
  QGraphicsPixmapItem,
51
42
  QGraphicsLineItem,
52
- QAction,
53
43
  QMainWindow,
54
44
  QGraphicsView,
55
45
  QPushButton,
@@ -80,14 +70,14 @@ selectedBrush.setColor(QColor(255, 255, 0, 255))
80
70
 
81
71
 
82
72
  class ModifiersMapCreatorWindow(QMainWindow):
83
- closed = pyqtSignal()
73
+ closed = Signal()
84
74
 
85
75
  class View(QGraphicsView):
86
76
  """
87
77
  class for handling mousepress event in QGraphicsView
88
78
  """
89
79
 
90
- mousePress = pyqtSignal(QMouseEvent)
80
+ mousePress = Signal(QMouseEvent)
91
81
 
92
82
  def mousePressEvent(self, event):
93
83
  self.mousePress.emit(event)
@@ -527,79 +517,77 @@ class ModifiersMapCreatorWindow(QMainWindow):
527
517
  if response == "Cancel":
528
518
  return
529
519
 
530
- fn = QFileDialog().getOpenFileName(
520
+ fileName, _ = QFileDialog().getOpenFileName(
531
521
  self,
532
522
  "Open a coding map",
533
523
  "",
534
524
  "BORIS coding map (*.boris_map);;All files (*)",
535
525
  )
536
- fileName = fn[0] if type(fn) is tuple else fn
537
526
 
538
- if fileName:
539
- try:
540
- self.codingMap = json.loads(open(fileName, "r").read())
541
- except Exception:
542
- QMessageBox.critical(
543
- self,
544
- cfg.programName,
545
- "The file {} seems not a behaviors coding map...".format(fileName),
546
- )
547
- return
527
+ if not fileName:
528
+ self.statusBar().showMessage("No file", 5000)
529
+ try:
530
+ self.codingMap = json.loads(open(fileName, "r").read())
531
+ except Exception:
532
+ QMessageBox.critical(
533
+ self,
534
+ cfg.programName,
535
+ "The file {} seems not a behaviors coding map...".format(fileName),
536
+ )
537
+ return
548
538
 
549
- self.cancelMap()
539
+ self.cancelMap()
550
540
 
551
- self.mapName = self.codingMap["name"]
541
+ self.mapName = self.codingMap["name"]
552
542
 
553
- self.setWindowTitle(cfg.programName + " - Map creator tool - " + self.mapName)
543
+ self.setWindowTitle(cfg.programName + " - Map creator tool - " + self.mapName)
554
544
 
555
- self.bitmapFileName = True
545
+ self.bitmapFileName = True
556
546
 
557
- self.fileName = fileName
547
+ self.fileName = fileName
558
548
 
559
- self.areasList = self.codingMap["areas"] # dictionary of dictionaries
560
- bitmapContent = binascii.a2b_base64(self.codingMap["bitmap"])
549
+ self.areasList = self.codingMap["areas"] # dictionary of dictionaries
550
+ bitmapContent = binascii.a2b_base64(self.codingMap["bitmap"])
561
551
 
562
- self.pixmap.loadFromData(bitmapContent)
552
+ self.pixmap.loadFromData(bitmapContent)
563
553
 
564
- self.btDeleteArea.setEnabled(False)
554
+ self.btDeleteArea.setEnabled(False)
565
555
 
566
- self.view.setSceneRect(0, 0, self.pixmap.size().width(), self.pixmap.size().height())
567
- pixItem = QGraphicsPixmapItem(self.pixmap)
568
- pixItem.setPos(0, 0)
569
- self.view.scene().addItem(pixItem)
556
+ self.view.setSceneRect(0, 0, self.pixmap.size().width(), self.pixmap.size().height())
557
+ pixItem = QGraphicsPixmapItem(self.pixmap)
558
+ pixItem.setPos(0, 0)
559
+ self.view.scene().addItem(pixItem)
570
560
 
571
- for areaCode in self.areasList:
572
- points = self.areasList[areaCode]["geometry"]
561
+ for areaCode in self.areasList:
562
+ points = self.areasList[areaCode]["geometry"]
573
563
 
574
- newPolygon = QPolygonF()
575
- for p in points:
576
- newPolygon.append(QPoint(p[0], p[1]))
564
+ newPolygon = QPolygonF()
565
+ for p in points:
566
+ newPolygon.append(QPoint(p[0], p[1]))
577
567
 
578
- clr = QColor()
579
- clr.setRgba(self.areasList[areaCode]["color"])
568
+ clr = QColor()
569
+ clr.setRgba(self.areasList[areaCode]["color"])
580
570
 
581
- # draw polygon
582
- polygon = QGraphicsPolygonItem()
571
+ # draw polygon
572
+ polygon = QGraphicsPolygonItem()
583
573
 
584
- polygon.setPolygon(newPolygon)
574
+ polygon.setPolygon(newPolygon)
585
575
 
586
- polygon.setPen(QPen(clr, penWidth, penStyle, Qt.RoundCap, Qt.RoundJoin))
576
+ polygon.setPen(QPen(clr, penWidth, penStyle, Qt.RoundCap, Qt.RoundJoin))
587
577
 
588
- polygon.setBrush(QBrush(clr, Qt.SolidPattern))
578
+ polygon.setBrush(QBrush(clr, Qt.SolidPattern))
589
579
 
590
- self.view.scene().addItem(polygon)
591
- self.polygonsList2[areaCode] = polygon
580
+ self.view.scene().addItem(polygon)
581
+ self.polygonsList2[areaCode] = polygon
592
582
 
593
- self.btNewArea.setVisible(True)
583
+ self.btNewArea.setVisible(True)
594
584
 
595
- self.btLoad.setVisible(False)
585
+ self.btLoad.setVisible(False)
596
586
 
597
- self.saveMapAction.setEnabled(True)
598
- self.saveAsMapAction.setEnabled(True)
599
- self.mapNameAction.setEnabled(True)
600
- self.statusBar().showMessage('Click "New area" to create a new area')
601
- else:
602
- self.statusBar().showMessage("No file", 5000)
587
+ self.saveMapAction.setEnabled(True)
588
+ self.saveAsMapAction.setEnabled(True)
589
+ self.mapNameAction.setEnabled(True)
590
+ self.statusBar().showMessage('Click "New area" to create a new area')
603
591
 
604
592
  def saveMap(self):
605
593
  if self.fileName:
@@ -843,41 +831,41 @@ class ModifiersMapCreatorWindow(QMainWindow):
843
831
 
844
832
  maxSize = 512
845
833
 
846
- fn = QFileDialog().getOpenFileName(self, "Load bitmap", "", "bitmap files (*.png *.jpg);;All files (*)")
847
- fileName = fn[0] if type(fn) is tuple else fn
834
+ fileName, _ = QFileDialog().getOpenFileName(self, "Load bitmap", "", "bitmap files (*.png *.jpg);;All files (*)")
848
835
 
849
- if fileName:
850
- self.bitmapFileName = fileName
836
+ if not fileName:
837
+ return
838
+ self.bitmapFileName = fileName
851
839
 
852
- self.pixmap.load(self.bitmapFileName)
840
+ self.pixmap.load(self.bitmapFileName)
853
841
 
854
- if self.pixmap.size().width() > maxSize or self.pixmap.size().height() > maxSize:
855
- self.pixmap = self.pixmap.scaled(maxSize, maxSize, Qt.KeepAspectRatio)
856
- QMessageBox.information(
857
- self,
858
- cfg.programName,
859
- "The bitmap was resized to %d x %d pixels\nThe original file was not modified"
860
- % (self.pixmap.size().width(), self.pixmap.size().height()),
861
- )
842
+ if self.pixmap.size().width() > maxSize or self.pixmap.size().height() > maxSize:
843
+ self.pixmap = self.pixmap.scaled(maxSize, maxSize, Qt.KeepAspectRatio)
844
+ QMessageBox.information(
845
+ self,
846
+ cfg.programName,
847
+ "The bitmap was resized to %d x %d pixels\nThe original file was not modified"
848
+ % (self.pixmap.size().width(), self.pixmap.size().height()),
849
+ )
862
850
 
863
- # scale image
864
- # pixmap = pixmap.scaled (256, 256, Qt.KeepAspectRatio)
851
+ # scale image
852
+ # pixmap = pixmap.scaled (256, 256, Qt.KeepAspectRatio)
865
853
 
866
- self.view.setSceneRect(0, 0, self.pixmap.size().width(), self.pixmap.size().height())
867
- pixitem = QGraphicsPixmapItem(self.pixmap)
868
- pixitem.setPos(0, 0)
869
- self.view.scene().addItem(pixitem)
854
+ self.view.setSceneRect(0, 0, self.pixmap.size().width(), self.pixmap.size().height())
855
+ pixitem = QGraphicsPixmapItem(self.pixmap)
856
+ pixitem.setPos(0, 0)
857
+ self.view.scene().addItem(pixitem)
870
858
 
871
- self.btNewArea.setVisible(True)
859
+ self.btNewArea.setVisible(True)
872
860
 
873
- self.btLoad.setVisible(False)
874
- self.saveMapAction.setEnabled(True)
875
- self.saveAsMapAction.setEnabled(True)
876
- self.mapNameAction.setEnabled(True)
861
+ self.btLoad.setVisible(False)
862
+ self.saveMapAction.setEnabled(True)
863
+ self.saveAsMapAction.setEnabled(True)
864
+ self.mapNameAction.setEnabled(True)
877
865
 
878
- self.statusBar().showMessage("""Click "New modifier" to create a new modifier""")
866
+ self.statusBar().showMessage("""Click "New modifier" to create a new modifier""")
879
867
 
880
- self.flagMapChanged = True
868
+ self.flagMapChanged = True
881
869
 
882
870
 
883
871
  if __name__ == "__main__":