boris-behav-obs 8.9.16__py3-none-any.whl → 9.7.6__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.

Potentially problematic release.


This version of boris-behav-obs might be problematic. Click here for more details.

Files changed (129) hide show
  1. boris/__init__.py +1 -1
  2. boris/__main__.py +1 -1
  3. boris/about.py +36 -39
  4. boris/add_modifier.py +122 -109
  5. boris/add_modifier_ui.py +239 -135
  6. boris/advanced_event_filtering.py +81 -45
  7. boris/analysis_plugins/__init__.py +0 -0
  8. boris/analysis_plugins/_latency.py +59 -0
  9. boris/analysis_plugins/irr_cohen_kappa.py +109 -0
  10. boris/analysis_plugins/irr_cohen_kappa_with_modifiers.py +112 -0
  11. boris/analysis_plugins/irr_weighted_cohen_kappa.py +157 -0
  12. boris/analysis_plugins/irr_weighted_cohen_kappa_with_modifiers.py +162 -0
  13. boris/analysis_plugins/list_of_dataframe_columns.py +22 -0
  14. boris/analysis_plugins/number_of_occurences.py +22 -0
  15. boris/analysis_plugins/number_of_occurences_by_independent_variable.py +54 -0
  16. boris/analysis_plugins/time_budget.py +61 -0
  17. boris/behav_coding_map_creator.py +228 -229
  18. boris/behavior_binary_table.py +33 -50
  19. boris/behaviors_coding_map.py +17 -18
  20. boris/boris_cli.py +6 -25
  21. boris/cmd_arguments.py +12 -1
  22. boris/coding_pad.py +42 -49
  23. boris/config.py +161 -77
  24. boris/config_file.py +63 -83
  25. boris/connections.py +112 -57
  26. boris/converters.py +13 -37
  27. boris/converters_ui.py +187 -110
  28. boris/cooccurence.py +250 -0
  29. boris/core.py +2511 -1824
  30. boris/core_qrc.py +15895 -10185
  31. boris/core_ui.py +946 -792
  32. boris/db_functions.py +21 -41
  33. boris/dev.py +134 -0
  34. boris/dialog.py +505 -244
  35. boris/duration_widget.py +15 -20
  36. boris/edit_event.py +84 -28
  37. boris/edit_event_ui.py +214 -78
  38. boris/event_operations.py +517 -415
  39. boris/events_cursor.py +25 -17
  40. boris/events_snapshots.py +36 -82
  41. boris/exclusion_matrix.py +4 -9
  42. boris/export_events.py +213 -583
  43. boris/export_observation.py +98 -611
  44. boris/external_processes.py +156 -97
  45. boris/geometric_measurement.py +652 -287
  46. boris/gui_utilities.py +91 -14
  47. boris/image_overlay.py +9 -9
  48. boris/import_observations.py +190 -98
  49. boris/ipc_mpv.py +325 -0
  50. boris/irr.py +26 -63
  51. boris/latency.py +34 -25
  52. boris/measurement_widget.py +14 -18
  53. boris/media_file.py +52 -84
  54. boris/menu_options.py +17 -6
  55. boris/modifier_coding_map_creator.py +1013 -0
  56. boris/modifiers_coding_map.py +7 -9
  57. boris/mpv.py +1 -0
  58. boris/mpv2.py +732 -705
  59. boris/observation.py +655 -310
  60. boris/observation_operations.py +1036 -404
  61. boris/observation_ui.py +584 -356
  62. boris/observations_list.py +71 -53
  63. boris/otx_parser.py +74 -80
  64. boris/param_panel.py +31 -16
  65. boris/param_panel_ui.py +254 -138
  66. boris/player_dock_widget.py +90 -60
  67. boris/plot_data_module.py +43 -46
  68. boris/plot_events.py +127 -90
  69. boris/plot_events_rt.py +17 -31
  70. boris/plot_spectrogram_rt.py +95 -30
  71. boris/plot_waveform_rt.py +32 -21
  72. boris/plugins.py +431 -0
  73. boris/portion/__init__.py +18 -8
  74. boris/portion/const.py +35 -18
  75. boris/portion/dict.py +5 -5
  76. boris/portion/func.py +2 -2
  77. boris/portion/interval.py +21 -41
  78. boris/portion/io.py +41 -32
  79. boris/preferences.py +306 -83
  80. boris/preferences_ui.py +685 -228
  81. boris/project.py +448 -293
  82. boris/project_functions.py +689 -254
  83. boris/project_import_export.py +213 -222
  84. boris/project_ui.py +674 -438
  85. boris/qrc_boris.py +6 -3
  86. boris/qrc_boris5.py +6 -3
  87. boris/select_modifiers.py +74 -48
  88. boris/select_observations.py +20 -199
  89. boris/select_subj_behav.py +67 -39
  90. boris/state_events.py +53 -37
  91. boris/subjects_pad.py +6 -9
  92. boris/synthetic_time_budget.py +45 -28
  93. boris/time_budget_functions.py +171 -171
  94. boris/time_budget_widget.py +84 -114
  95. boris/transitions.py +41 -47
  96. boris/utilities.py +766 -266
  97. boris/version.py +3 -3
  98. boris/video_equalizer.py +16 -14
  99. boris/video_equalizer_ui.py +199 -130
  100. boris/video_operations.py +125 -28
  101. boris/view_df.py +104 -0
  102. boris/view_df_ui.py +75 -0
  103. boris/write_event.py +538 -0
  104. boris_behav_obs-9.7.6.dist-info/METADATA +139 -0
  105. boris_behav_obs-9.7.6.dist-info/RECORD +109 -0
  106. {boris_behav_obs-8.9.16.dist-info → boris_behav_obs-9.7.6.dist-info}/WHEEL +1 -1
  107. boris_behav_obs-9.7.6.dist-info/entry_points.txt +2 -0
  108. boris/README.TXT +0 -22
  109. boris/add_modifier.ui +0 -323
  110. boris/boris_ui.py +0 -886
  111. boris/converters.ui +0 -289
  112. boris/core.qrc +0 -35
  113. boris/core.ui +0 -1543
  114. boris/edit_event.ui +0 -175
  115. boris/icons/logo_eye.ico +0 -0
  116. boris/map_creator.py +0 -850
  117. boris/observation.ui +0 -773
  118. boris/param_panel.ui +0 -379
  119. boris/preferences.ui +0 -537
  120. boris/project.ui +0 -1069
  121. boris/project_server.py +0 -236
  122. boris/vlc.py +0 -10343
  123. boris/vlc_local.py +0 -90
  124. boris_behav_obs-8.9.16.dist-info/LICENSE.TXT +0 -674
  125. boris_behav_obs-8.9.16.dist-info/METADATA +0 -129
  126. boris_behav_obs-8.9.16.dist-info/RECORD +0 -108
  127. boris_behav_obs-8.9.16.dist-info/entry_points.txt +0 -2
  128. {boris → boris_behav_obs-9.7.6.dist-info/licenses}/LICENSE.TXT +0 -0
  129. {boris_behav_obs-8.9.16.dist-info → boris_behav_obs-9.7.6.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  """
2
2
  BORIS
3
3
  Behavioral Observation Research Interactive Software
4
- Copyright 2012-2023 Olivier Friard
4
+ Copyright 2012-2025 Olivier Friard
5
5
 
6
6
  This file is part of BORIS.
7
7
 
@@ -20,44 +20,31 @@ This file is part of BORIS.
20
20
 
21
21
  """
22
22
 
23
- # add misc directory to search path for mpv-1.dll
24
- import os
25
23
  import sys
26
24
  import logging
27
- import pathlib as pl
28
- import datetime as dt
25
+ import functools
29
26
 
30
- os.environ["PATH"] = os.path.dirname(__file__) + os.sep + "misc" + os.pathsep + os.environ["PATH"]
31
-
32
- try:
27
+ if (sys.platform.startswith("win") or sys.platform.startswith("linux")) and ("-i" not in sys.argv) and ("--ipc" not in sys.argv):
33
28
  from . import mpv2 as mpv
34
-
35
- # check if MPV API v. 1
36
- try:
37
- if "libmpv.so.1" in mpv.sofile:
38
- from . import mpv as mpv
39
- except AttributeError:
40
- if "mpv-1.dll" in mpv.dll:
41
- from . import mpv as mpv
42
-
43
- except RuntimeError: # libmpv found but version too old
44
- from . import mpv as mpv
45
-
46
- except OSError: # libmpv not found
47
- msg = "LIBMPV library not found!\n"
48
- logging.critical(msg)
49
- # append to boris.log file
50
- with open(pl.Path("~").expanduser() / "boris.log", "a") as f_out:
51
- f_out.write(f"{dt.datetime.now():%Y-%m-%d %H:%M}\n")
52
- f_out.write(msg)
53
- f_out.write("-" * 80 + "\n")
54
- sys.exit()
55
-
56
-
57
- from PyQt5.QtWidgets import QLabel, QDockWidget, QWidget, QHBoxLayout, QSlider, QSizePolicy, QStackedWidget
58
- from PyQt5.QtCore import pyqtSignal, QEvent, Qt
59
-
60
- import logging
29
+ else:
30
+ import ipc_mpv
31
+ import config as cfg
32
+ import gui_utilities
33
+
34
+
35
+ from PySide6.QtWidgets import (
36
+ QLabel,
37
+ QDockWidget,
38
+ QWidget,
39
+ QHBoxLayout,
40
+ QVBoxLayout,
41
+ QSlider,
42
+ QSizePolicy,
43
+ QStackedWidget,
44
+ QToolButton,
45
+ )
46
+ from PySide6.QtCore import Signal, QEvent, Qt
47
+ from PySide6.QtGui import QIcon, QAction
61
48
 
62
49
 
63
50
  class Clickable_label(QLabel):
@@ -66,7 +53,7 @@ class Clickable_label(QLabel):
66
53
  Label emits a signal when clicked
67
54
  """
68
55
 
69
- mouse_pressed_signal = pyqtSignal(int, QEvent)
56
+ mouse_pressed_signal = Signal(int, QEvent)
70
57
 
71
58
  def __init__(self, id_, parent=None):
72
59
  QLabel.__init__(self, parent)
@@ -76,23 +63,40 @@ class Clickable_label(QLabel):
76
63
  """
77
64
  label clicked
78
65
  """
66
+ logging.debug(f"mousepress event: label {self.id_} clicked {event.pos()}")
79
67
 
80
- logging.debug(f"mousepress event: label {self.id_} clicked")
68
+ """
69
+ super().mousePressEvent(event)
70
+ x, y = event.pos().x(), event.pos().y()
71
+ draw_on_pixmap(self, x, y) # Example usage
72
+ """
81
73
 
82
74
  self.mouse_pressed_signal.emit(self.id_, event)
83
75
 
84
76
 
77
+ def mpv_logger(player_id, loglevel, component, message):
78
+ """
79
+ redirect MPV log messages to general logging system
80
+ """
81
+
82
+ logging.debug(f"MPV player #{player_id}: [{loglevel}] {component}: {message}")
83
+
84
+
85
85
  class DW_player(QDockWidget):
86
+ """
87
+ Define the player class
88
+ """
86
89
 
87
- key_pressed_signal = pyqtSignal(QEvent)
88
- volume_slider_moved_signal = pyqtSignal(int, int)
89
- view_signal = pyqtSignal(int, str, int)
90
- resize_signal = pyqtSignal(int)
90
+ key_pressed_signal = Signal(QEvent)
91
+ volume_slider_moved_signal = Signal(int, int)
92
+ mute_action_triggered_signal = Signal(int)
93
+ view_signal = Signal(int, str, int)
94
+ resize_signal = Signal(int)
91
95
 
92
96
  def __init__(self, id_, parent=None):
93
97
  super().__init__(parent)
98
+ # print("ipc", parent.MPV_IPC_MODE)
94
99
  self.id_ = id_
95
- self.zoomed = False
96
100
  self.setWindowTitle(f"Player #{id_ + 1}")
97
101
  self.setObjectName(f"player{id_ + 1}")
98
102
 
@@ -101,23 +105,46 @@ class DW_player(QDockWidget):
101
105
 
102
106
  self.videoframe = QWidget(self)
103
107
 
104
- self.player = mpv.MPV(
105
- wid=str(int(self.videoframe.winId())),
106
- # vo='x11', # You may not need this
107
- log_handler=None,
108
- loglevel="debug",
109
- )
110
-
111
- self.player.screenshot_format = "png"
108
+ if parent.MPV_IPC_MODE:
109
+ self.player = ipc_mpv.IPC_MPV(socket_path=f"{cfg.MPV_SOCKET}{self.id_}")
110
+ else:
111
+ self.player = mpv.MPV(
112
+ wid=str(int(self.videoframe.winId())),
113
+ vo="x11" if sys.platform.startswith("linux") else "",
114
+ log_handler=functools.partial(mpv_logger, self.id_),
115
+ loglevel="debug",
116
+ )
117
+
118
+ self.player.screenshot_format = "png"
112
119
  self.hlayout.addWidget(self.videoframe)
113
120
 
121
+ # layout volume slider and mute button
122
+ self.vlayout = QVBoxLayout()
123
+
124
+ # volume slider
114
125
  self.volume_slider = QSlider(Qt.Vertical, self)
115
126
  self.volume_slider.setFocusPolicy(Qt.NoFocus)
116
127
  self.volume_slider.setMaximum(100)
117
128
  self.volume_slider.setValue(50)
118
129
  self.volume_slider.sliderMoved.connect(self.volume_slider_moved)
119
130
 
120
- self.hlayout.addWidget(self.volume_slider)
131
+ self.vlayout.addWidget(self.volume_slider)
132
+
133
+ # mute button
134
+ self.mute_button = QToolButton()
135
+ self.mute_button.setFocusPolicy(Qt.NoFocus)
136
+ self.mute_button.setAutoRaise(True)
137
+ self.mute_action = QAction()
138
+
139
+ theme_mode = gui_utilities.theme_mode()
140
+
141
+ self.mute_action.setIcon(QIcon(f":/volume_xmark_{theme_mode}"))
142
+ self.mute_action.triggered.connect(self.mute_action_triggered)
143
+ self.mute_button.setDefaultAction(self.mute_action)
144
+
145
+ self.vlayout.addWidget(self.mute_button)
146
+
147
+ self.hlayout.addLayout(self.vlayout)
121
148
 
122
149
  self.stack1.setLayout(self.hlayout)
123
150
 
@@ -146,21 +173,24 @@ class DW_player(QDockWidget):
146
173
  """
147
174
  self.volume_slider_moved_signal.emit(self.id_, self.volume_slider.value())
148
175
 
149
- def keyPressEvent(self, event):
176
+ def mute_action_triggered(self):
150
177
  """
151
- emit signal when key pressed on dock widget
178
+ emit signal when mute action is triggered
152
179
  """
153
- self.key_pressed_signal.emit(event)
180
+ theme_mode = gui_utilities.theme_mode()
181
+ if self.player.mute:
182
+ self.mute_action.setIcon(QIcon(f":/volume_xmark_{theme_mode}"))
183
+ else:
184
+ self.mute_action.setIcon(QIcon(f":/volume_off_{theme_mode}"))
185
+ self.mute_action_triggered_signal.emit(self.id_)
154
186
 
155
- '''
156
- def view_signal_triggered(self, msg, button):
187
+ def keyPressEvent(self, event):
157
188
  """
158
- transmit signal received by video frame
189
+ emit signal when key pressed on dock widget
159
190
  """
160
- self.view_signal.emit(self.id_, msg, button)
161
- '''
191
+ self.key_pressed_signal.emit(event)
162
192
 
163
- def resizeEvent(self, dummy):
193
+ def resizeEvent(self, _):
164
194
  """
165
195
  emits signal when dockwidget resized
166
196
  """
boris/plot_data_module.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """
2
2
  BORIS
3
3
  Behavioral Observation Research Interactive Software
4
- Copyright 2012-2023 Olivier Friard
4
+ Copyright 2012-2025 Olivier Friard
5
5
 
6
6
 
7
7
  This program is free software; you can redistribute it and/or modify
@@ -29,8 +29,8 @@ from decimal import Decimal as dec
29
29
  import numpy as np
30
30
  from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
31
31
  from matplotlib.figure import Figure
32
- from PyQt5.QtCore import pyqtSignal, QEvent, QThread, QObject, pyqtSlot, QTimer
33
- from PyQt5.QtWidgets import (
32
+ from PySide6.QtCore import Signal, QEvent, QThread, QObject, Slot, QTimer
33
+ from PySide6.QtWidgets import (
34
34
  QSizePolicy,
35
35
  QWidget,
36
36
  QPushButton,
@@ -42,6 +42,7 @@ from PyQt5.QtWidgets import (
42
42
  )
43
43
 
44
44
  from . import utilities as util
45
+ from . import config as cfg
45
46
 
46
47
 
47
48
  class MyMplCanvas(FigureCanvas):
@@ -55,11 +56,10 @@ class MyMplCanvas(FigureCanvas):
55
56
 
56
57
 
57
58
  class Plot_data(QWidget):
58
-
59
- send_fig = pyqtSignal(float)
59
+ send_fig = Signal(float)
60
60
 
61
61
  # send keypress event to mainwindow
62
- sendEvent = pyqtSignal(QEvent)
62
+ sendEvent = Signal(QEvent)
63
63
 
64
64
  def __init__(
65
65
  self,
@@ -75,7 +75,6 @@ class Plot_data(QWidget):
75
75
  column_converter,
76
76
  log_level="",
77
77
  ):
78
-
79
78
  super().__init__()
80
79
 
81
80
  self.installEventFilter(self)
@@ -133,14 +132,18 @@ class Plot_data(QWidget):
133
132
  substract_first_value,
134
133
  converters=converters,
135
134
  column_converter=column_converter,
136
- ) # txt2np_array defined in utilities.py
135
+ )
136
+
137
+ print(f"{error_msg=}")
137
138
 
138
139
  if not result:
139
140
  self.error_msg = error_msg
140
141
  return
141
142
 
143
+ """
142
144
  logging.debug("data[50]: {}".format(data[:50]))
143
145
  logging.debug("shape: {}".format(data.shape))
146
+ """
144
147
 
145
148
  if data.shape == (0,):
146
149
  self.error_msg = "Empty input file"
@@ -150,7 +153,7 @@ class Plot_data(QWidget):
150
153
  data = data[data[:, 0].argsort()]
151
154
 
152
155
  # unique
153
- u, idx = np.unique(data[:, 0], return_index=True)
156
+ _, idx = np.unique(data[:, 0], return_index=True)
154
157
  data = data[idx]
155
158
 
156
159
  # time
@@ -162,24 +165,28 @@ class Plot_data(QWidget):
162
165
  # check if time is linear
163
166
  diff = set(np.round(np.diff(data, axis=0)[:, 0], 4))
164
167
 
168
+ # check if only one time value is available
169
+ if not diff:
170
+ self.error_msg = "only one time value is present"
171
+ return
172
+
165
173
  if min(diff) == 0:
166
174
  self.error_msg = "more values for same time"
167
175
  return
168
176
 
169
- logging.debug(f"diff: {diff}")
177
+ """logging.debug(f"diff: {diff}")"""
170
178
 
171
179
  min_time_step = min(diff)
172
180
 
173
- logging.debug(f"min_time_step: {min_time_step}")
181
+ """logging.debug(f"min_time_step: {min_time_step}")"""
174
182
 
175
183
  # check if sampling rate is not constant
176
184
  if len(diff) != 1:
177
-
178
- logging.debug("len diff != 1")
185
+ """logging.debug("len diff != 1")"""
179
186
 
180
187
  min_time_step = min(diff)
181
188
 
182
- logging.debug(f"min_time_step: {min_time_step}")
189
+ """logging.debug(f"min_time_step: {min_time_step}")"""
183
190
 
184
191
  # increase value for low sampling rate (> 1 s)
185
192
  if min_time_step > 1:
@@ -189,7 +196,7 @@ class Plot_data(QWidget):
189
196
  data = np.array((x2, np.interp(x2, data[:, 0], data[:, 1]))).T
190
197
  del x2
191
198
 
192
- logging.debug(f"data[:,0]: {data[:, 0]}")
199
+ """logging.debug(f"data[:,0]: {data[:, 0]}")"""
193
200
 
194
201
  # time
195
202
  min_time_value, max_time_value = min(data[:, 0]), max(data[:, 0])
@@ -204,9 +211,9 @@ class Plot_data(QWidget):
204
211
  data = data[0 :: int(round(0.04 / min_time_step, 2))]
205
212
  min_time_step = 0.04
206
213
 
207
- logging.debug(f"new data after subsampling: {data[:50]}")
214
+ """logging.debug(f"new data after subsampling: {data[:50]}")"""
208
215
 
209
- min_value, max_value = min(data[:, 1]), max(data[:, 1])
216
+ min_var_value, max_var_value = min(data[:, 1]), max(data[:, 1])
210
217
 
211
218
  max_frequency = 1 / min_time_step
212
219
 
@@ -241,7 +248,7 @@ class Plot_data(QWidget):
241
248
  if min_time_step < 0.2:
242
249
  self.time_out = 200
243
250
  else:
244
- self.time_out = min_time_step * 1000
251
+ self.time_out = round(min_time_step * 1000)
245
252
 
246
253
  def eventFilter(self, receiver, event):
247
254
  """
@@ -281,40 +288,31 @@ class Plot_data(QWidget):
281
288
 
282
289
  # Slot receives data and plots it
283
290
  def plot(self, x, y, position_data, position_start, min_value, max_value, position_end):
284
-
285
- logging.debug(f"len x (plot): {len(x)}")
286
- logging.debug(f"len y (plot): {len(y)}")
287
-
288
291
  # print current value
289
292
  try:
290
293
  if x[0] == 0:
291
294
  self.lb_value.setText(str(round(y[position_data], 3)))
292
295
  else:
293
296
  self.lb_value.setText(str(round(y[len(y) // 2], 3)))
294
- except:
297
+ except Exception:
295
298
  self.lb_value.setText("Read error")
296
299
 
297
300
  try:
298
301
  self.myplot.axes.clear()
299
-
300
302
  self.myplot.axes.set_title(self.plot_title)
301
-
302
303
  self.myplot.axes.set_xlim(position_start, position_end)
303
-
304
304
  self.myplot.axes.set_ylabel(self.y_label, rotation=90, labelpad=10)
305
305
  self.myplot.axes.set_ylim((min_value, max_value))
306
-
307
306
  self.myplot.axes.plot(x, y, self.plot_style)
308
- self.myplot.axes.axvline(x=position_data, color="red", linestyle="-")
307
+ self.myplot.axes.axvline(x=position_data, color=cfg.REALTIME_PLOT_CURSOR_COLOR, linestyle="-")
309
308
 
310
309
  self.myplot.draw()
311
- except:
312
- logging.debug("error")
313
- pass # only for protection agains crash
310
+ except Exception:
311
+ logging.debug(f"error in plotting external data: {sys.exc_info()[1]}")
314
312
 
315
313
 
316
314
  class Plotter(QObject):
317
- return_fig = pyqtSignal(
315
+ return_fig = Signal(
318
316
  np.ndarray, # x array
319
317
  np.ndarray, # y array
320
318
  float, # position_data
@@ -324,9 +322,8 @@ class Plotter(QObject):
324
322
  float, # position end
325
323
  )
326
324
 
327
- @pyqtSlot(float)
325
+ @Slot(float)
328
326
  def replot(self, current_time): # time_ in s
329
-
330
327
  logging.debug("current_time: {}".format(current_time))
331
328
 
332
329
  current_discrete_time = round(round(current_time / self.min_time_step) * self.min_time_step, 2)
@@ -337,7 +334,6 @@ class Plotter(QObject):
337
334
  freq_interval = int(round(self.interval / self.min_time_step))
338
335
 
339
336
  if self.min_time_value <= current_discrete_time <= self.max_time_value:
340
-
341
337
  logging.debug("self.min_time_value <= current_discrete_time <= self.max_time_value")
342
338
 
343
339
  idx = np.where(self.data[:, 0] == current_discrete_time)[0]
@@ -345,7 +341,6 @@ class Plotter(QObject):
345
341
  idx = np.where(abs(self.data[:, 0] - current_discrete_time) <= 0.02)[0]
346
342
 
347
343
  if len(idx):
348
-
349
344
  position_data = idx[0]
350
345
 
351
346
  logging.debug(f"position data: {position_data}")
@@ -382,14 +377,9 @@ class Plotter(QObject):
382
377
  d = np.array([np.nan] * int(self.interval / self.min_time_step)).T
383
378
 
384
379
  elif current_time > self.max_time_value:
385
-
386
380
  logging.debug(f"self.interval/self.min_time_step/2: {self.interval / self.min_time_step / 2}")
387
381
 
388
- dim_footer = int(
389
- round(
390
- (current_time - self.max_time_value) / self.min_time_step + self.interval / self.min_time_step / 2
391
- )
392
- )
382
+ dim_footer = int(round((current_time - self.max_time_value) / self.min_time_step + self.interval / self.min_time_step / 2))
393
383
 
394
384
  footer = np.array([np.nan] * dim_footer).T
395
385
  logging.debug(f"len footer: {len(footer)}")
@@ -398,7 +388,6 @@ class Plotter(QObject):
398
388
  logging.debug(f"a: {a}")
399
389
 
400
390
  if a >= 0:
401
-
402
391
  logging.debug("a>=0")
403
392
 
404
393
  st = int(round(len(self.data) - a))
@@ -424,7 +413,6 @@ class Plotter(QObject):
424
413
  logging.debug(f"len d a<0: {len(d)}")
425
414
 
426
415
  elif current_time < self.min_time_value:
427
-
428
416
  x = (self.min_time_value - current_time) / self.min_time_step
429
417
  dim_header = int(round(self.interval / self.min_time_step / 2 + x))
430
418
  header = np.array([np.nan] * dim_header).T
@@ -444,7 +432,11 @@ class Plotter(QObject):
444
432
 
445
433
  logging.debug(f"self.min_time_step: {self.min_time_step}")
446
434
 
447
- x = np.arange(current_time - self.interval // 2, current_time + self.interval // 2, self.min_time_step)
435
+ x = np.arange(
436
+ current_time - self.interval // 2,
437
+ current_time + self.interval // 2,
438
+ self.min_time_step,
439
+ )
448
440
 
449
441
  logging.debug(f"len x 1: {len(x)}")
450
442
 
@@ -489,7 +481,12 @@ if __name__ == "__main__":
489
481
  "convert_time_ecg": {
490
482
  "name": "convert_time_ecg",
491
483
  "description": "convert '%d/%m/%Y %H:%M:%S.%f' in seconds from epoch",
492
- "code": '\nimport datetime\nepoch = datetime.datetime.utcfromtimestamp(0)\ndatetime_format = "%d/%m/%Y %H:%M:%S.%f"\n\nOUTPUT = (datetime.datetime.strptime(INPUT, datetime_format) - epoch).total_seconds()\n',
484
+ "code": (
485
+ "\nimport datetime\n"
486
+ "epoch = datetime.datetime.utcfromtimestamp(0)\n"
487
+ 'datetime_format = "%d/%m/%Y %H:%M:%S.%f"\n\n'
488
+ "OUTPUT = (datetime.datetime.strptime(INPUT, datetime_format) - epoch).total_seconds()\n"
489
+ ),
493
490
  },
494
491
  "hhmmss_2_seconds": {
495
492
  "name": "hhmmss_2_seconds",