boris-behav-obs 8.12__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.
- boris/__init__.py +1 -1
- boris/__main__.py +1 -1
- boris/about.py +28 -39
- boris/add_modifier.py +122 -109
- boris/add_modifier_ui.py +239 -135
- boris/advanced_event_filtering.py +81 -45
- boris/analysis_plugins/__init__.py +0 -0
- boris/analysis_plugins/_latency.py +59 -0
- boris/analysis_plugins/irr_cohen_kappa.py +109 -0
- boris/analysis_plugins/irr_cohen_kappa_with_modifiers.py +112 -0
- boris/analysis_plugins/irr_weighted_cohen_kappa.py +157 -0
- boris/analysis_plugins/irr_weighted_cohen_kappa_with_modifiers.py +162 -0
- boris/analysis_plugins/list_of_dataframe_columns.py +22 -0
- boris/analysis_plugins/number_of_occurences.py +22 -0
- boris/analysis_plugins/number_of_occurences_by_independent_variable.py +54 -0
- boris/analysis_plugins/time_budget.py +61 -0
- boris/behav_coding_map_creator.py +228 -229
- boris/behavior_binary_table.py +33 -50
- boris/behaviors_coding_map.py +17 -18
- boris/boris_cli.py +6 -25
- boris/cmd_arguments.py +12 -1
- boris/coding_pad.py +42 -49
- boris/config.py +141 -65
- boris/config_file.py +58 -67
- boris/connections.py +107 -61
- boris/converters.py +13 -37
- boris/converters_ui.py +187 -110
- boris/cooccurence.py +250 -0
- boris/core.py +2373 -1786
- boris/core_qrc.py +15895 -10743
- boris/core_ui.py +943 -798
- boris/db_functions.py +17 -42
- boris/dev.py +109 -8
- boris/dialog.py +482 -236
- boris/duration_widget.py +9 -14
- boris/edit_event.py +61 -31
- boris/edit_event_ui.py +208 -97
- boris/event_operations.py +408 -293
- boris/events_cursor.py +25 -17
- boris/events_snapshots.py +36 -82
- boris/exclusion_matrix.py +4 -9
- boris/export_events.py +184 -223
- boris/export_observation.py +74 -100
- boris/external_processes.py +123 -98
- boris/geometric_measurement.py +644 -290
- boris/gui_utilities.py +91 -14
- boris/image_overlay.py +4 -4
- boris/import_observations.py +190 -98
- boris/ipc_mpv.py +325 -0
- boris/irr.py +20 -57
- boris/latency.py +31 -24
- boris/measurement_widget.py +14 -18
- boris/media_file.py +17 -19
- boris/menu_options.py +17 -6
- boris/modifier_coding_map_creator.py +1013 -0
- boris/modifiers_coding_map.py +7 -9
- boris/mpv.py +1 -0
- boris/mpv2.py +732 -705
- boris/observation.py +533 -221
- boris/observation_operations.py +1025 -390
- boris/observation_ui.py +572 -362
- boris/observations_list.py +71 -53
- boris/otx_parser.py +74 -68
- boris/param_panel.py +31 -16
- boris/param_panel_ui.py +254 -138
- boris/player_dock_widget.py +90 -60
- boris/plot_data_module.py +25 -33
- boris/plot_events.py +127 -90
- boris/plot_events_rt.py +17 -31
- boris/plot_spectrogram_rt.py +95 -30
- boris/plot_waveform_rt.py +32 -21
- boris/plugins.py +431 -0
- boris/portion/__init__.py +18 -8
- boris/portion/const.py +35 -18
- boris/portion/dict.py +5 -5
- boris/portion/func.py +2 -2
- boris/portion/interval.py +21 -41
- boris/portion/io.py +41 -32
- boris/preferences.py +306 -83
- boris/preferences_ui.py +684 -227
- boris/project.py +448 -293
- boris/project_functions.py +671 -238
- boris/project_import_export.py +213 -222
- boris/project_ui.py +674 -438
- boris/qrc_boris.py +6 -3
- boris/qrc_boris5.py +6 -3
- boris/select_modifiers.py +74 -48
- boris/select_observations.py +20 -198
- boris/select_subj_behav.py +67 -39
- boris/state_events.py +52 -35
- boris/subjects_pad.py +6 -9
- boris/synthetic_time_budget.py +45 -28
- boris/time_budget_functions.py +171 -171
- boris/time_budget_widget.py +84 -114
- boris/transitions.py +41 -47
- boris/utilities.py +627 -236
- boris/version.py +3 -3
- boris/video_equalizer.py +16 -14
- boris/video_equalizer_ui.py +199 -130
- boris/video_operations.py +95 -29
- boris/view_df.py +104 -0
- boris/view_df_ui.py +75 -0
- boris/write_event.py +538 -0
- boris_behav_obs-9.7.6.dist-info/METADATA +139 -0
- boris_behav_obs-9.7.6.dist-info/RECORD +109 -0
- {boris_behav_obs-8.12.dist-info → boris_behav_obs-9.7.6.dist-info}/WHEEL +1 -1
- boris_behav_obs-9.7.6.dist-info/entry_points.txt +2 -0
- boris/README.TXT +0 -22
- boris/add_modifier.ui +0 -323
- boris/converters.ui +0 -289
- boris/core.qrc +0 -36
- boris/core.ui +0 -1556
- boris/edit_event.ui +0 -233
- boris/icons/logo_eye.ico +0 -0
- boris/map_creator.py +0 -850
- boris/observation.ui +0 -814
- boris/param_panel.ui +0 -379
- boris/preferences.ui +0 -537
- boris/project.ui +0 -1069
- boris/project_server.py +0 -236
- boris/vlc.py +0 -10343
- boris/vlc_local.py +0 -90
- boris_behav_obs-8.12.dist-info/LICENSE.TXT +0 -674
- boris_behav_obs-8.12.dist-info/METADATA +0 -128
- boris_behav_obs-8.12.dist-info/RECORD +0 -108
- boris_behav_obs-8.12.dist-info/entry_points.txt +0 -3
- {boris → boris_behav_obs-9.7.6.dist-info/licenses}/LICENSE.TXT +0 -0
- {boris_behav_obs-8.12.dist-info → boris_behav_obs-9.7.6.dist-info}/top_level.txt +0 -0
boris/player_dock_widget.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
BORIS
|
|
3
3
|
Behavioral Observation Research Interactive Software
|
|
4
|
-
Copyright 2012-
|
|
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
|
|
28
|
-
import datetime as dt
|
|
25
|
+
import functools
|
|
29
26
|
|
|
30
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
88
|
-
volume_slider_moved_signal =
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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.
|
|
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
|
|
176
|
+
def mute_action_triggered(self):
|
|
150
177
|
"""
|
|
151
|
-
emit signal when
|
|
178
|
+
emit signal when mute action is triggered
|
|
152
179
|
"""
|
|
153
|
-
|
|
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
|
-
|
|
189
|
+
emit signal when key pressed on dock widget
|
|
159
190
|
"""
|
|
160
|
-
self.
|
|
161
|
-
'''
|
|
191
|
+
self.key_pressed_signal.emit(event)
|
|
162
192
|
|
|
163
|
-
def resizeEvent(self,
|
|
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-
|
|
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
|
|
33
|
-
from
|
|
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 =
|
|
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)
|
|
@@ -135,6 +134,8 @@ class Plot_data(QWidget):
|
|
|
135
134
|
column_converter=column_converter,
|
|
136
135
|
)
|
|
137
136
|
|
|
137
|
+
print(f"{error_msg=}")
|
|
138
|
+
|
|
138
139
|
if not result:
|
|
139
140
|
self.error_msg = error_msg
|
|
140
141
|
return
|
|
@@ -181,7 +182,6 @@ class Plot_data(QWidget):
|
|
|
181
182
|
|
|
182
183
|
# check if sampling rate is not constant
|
|
183
184
|
if len(diff) != 1:
|
|
184
|
-
|
|
185
185
|
"""logging.debug("len diff != 1")"""
|
|
186
186
|
|
|
187
187
|
min_time_step = min(diff)
|
|
@@ -288,19 +288,13 @@ class Plot_data(QWidget):
|
|
|
288
288
|
|
|
289
289
|
# Slot receives data and plots it
|
|
290
290
|
def plot(self, x, y, position_data, position_start, min_value, max_value, position_end):
|
|
291
|
-
|
|
292
|
-
"""
|
|
293
|
-
logging.debug(f"len x (plot): {len(x)}")
|
|
294
|
-
logging.debug(f"len y (plot): {len(y)}")
|
|
295
|
-
"""
|
|
296
|
-
|
|
297
291
|
# print current value
|
|
298
292
|
try:
|
|
299
293
|
if x[0] == 0:
|
|
300
294
|
self.lb_value.setText(str(round(y[position_data], 3)))
|
|
301
295
|
else:
|
|
302
296
|
self.lb_value.setText(str(round(y[len(y) // 2], 3)))
|
|
303
|
-
except:
|
|
297
|
+
except Exception:
|
|
304
298
|
self.lb_value.setText("Read error")
|
|
305
299
|
|
|
306
300
|
try:
|
|
@@ -310,16 +304,15 @@ class Plot_data(QWidget):
|
|
|
310
304
|
self.myplot.axes.set_ylabel(self.y_label, rotation=90, labelpad=10)
|
|
311
305
|
self.myplot.axes.set_ylim((min_value, max_value))
|
|
312
306
|
self.myplot.axes.plot(x, y, self.plot_style)
|
|
313
|
-
self.myplot.axes.axvline(x=position_data, color=
|
|
307
|
+
self.myplot.axes.axvline(x=position_data, color=cfg.REALTIME_PLOT_CURSOR_COLOR, linestyle="-")
|
|
314
308
|
|
|
315
309
|
self.myplot.draw()
|
|
316
|
-
except:
|
|
310
|
+
except Exception:
|
|
317
311
|
logging.debug(f"error in plotting external data: {sys.exc_info()[1]}")
|
|
318
|
-
pass # only for protection against crash
|
|
319
312
|
|
|
320
313
|
|
|
321
314
|
class Plotter(QObject):
|
|
322
|
-
return_fig =
|
|
315
|
+
return_fig = Signal(
|
|
323
316
|
np.ndarray, # x array
|
|
324
317
|
np.ndarray, # y array
|
|
325
318
|
float, # position_data
|
|
@@ -329,9 +322,8 @@ class Plotter(QObject):
|
|
|
329
322
|
float, # position end
|
|
330
323
|
)
|
|
331
324
|
|
|
332
|
-
@
|
|
325
|
+
@Slot(float)
|
|
333
326
|
def replot(self, current_time): # time_ in s
|
|
334
|
-
|
|
335
327
|
logging.debug("current_time: {}".format(current_time))
|
|
336
328
|
|
|
337
329
|
current_discrete_time = round(round(current_time / self.min_time_step) * self.min_time_step, 2)
|
|
@@ -342,7 +334,6 @@ class Plotter(QObject):
|
|
|
342
334
|
freq_interval = int(round(self.interval / self.min_time_step))
|
|
343
335
|
|
|
344
336
|
if self.min_time_value <= current_discrete_time <= self.max_time_value:
|
|
345
|
-
|
|
346
337
|
logging.debug("self.min_time_value <= current_discrete_time <= self.max_time_value")
|
|
347
338
|
|
|
348
339
|
idx = np.where(self.data[:, 0] == current_discrete_time)[0]
|
|
@@ -350,7 +341,6 @@ class Plotter(QObject):
|
|
|
350
341
|
idx = np.where(abs(self.data[:, 0] - current_discrete_time) <= 0.02)[0]
|
|
351
342
|
|
|
352
343
|
if len(idx):
|
|
353
|
-
|
|
354
344
|
position_data = idx[0]
|
|
355
345
|
|
|
356
346
|
logging.debug(f"position data: {position_data}")
|
|
@@ -387,14 +377,9 @@ class Plotter(QObject):
|
|
|
387
377
|
d = np.array([np.nan] * int(self.interval / self.min_time_step)).T
|
|
388
378
|
|
|
389
379
|
elif current_time > self.max_time_value:
|
|
390
|
-
|
|
391
380
|
logging.debug(f"self.interval/self.min_time_step/2: {self.interval / self.min_time_step / 2}")
|
|
392
381
|
|
|
393
|
-
dim_footer = int(
|
|
394
|
-
round(
|
|
395
|
-
(current_time - self.max_time_value) / self.min_time_step + self.interval / self.min_time_step / 2
|
|
396
|
-
)
|
|
397
|
-
)
|
|
382
|
+
dim_footer = int(round((current_time - self.max_time_value) / self.min_time_step + self.interval / self.min_time_step / 2))
|
|
398
383
|
|
|
399
384
|
footer = np.array([np.nan] * dim_footer).T
|
|
400
385
|
logging.debug(f"len footer: {len(footer)}")
|
|
@@ -403,7 +388,6 @@ class Plotter(QObject):
|
|
|
403
388
|
logging.debug(f"a: {a}")
|
|
404
389
|
|
|
405
390
|
if a >= 0:
|
|
406
|
-
|
|
407
391
|
logging.debug("a>=0")
|
|
408
392
|
|
|
409
393
|
st = int(round(len(self.data) - a))
|
|
@@ -429,7 +413,6 @@ class Plotter(QObject):
|
|
|
429
413
|
logging.debug(f"len d a<0: {len(d)}")
|
|
430
414
|
|
|
431
415
|
elif current_time < self.min_time_value:
|
|
432
|
-
|
|
433
416
|
x = (self.min_time_value - current_time) / self.min_time_step
|
|
434
417
|
dim_header = int(round(self.interval / self.min_time_step / 2 + x))
|
|
435
418
|
header = np.array([np.nan] * dim_header).T
|
|
@@ -449,7 +432,11 @@ class Plotter(QObject):
|
|
|
449
432
|
|
|
450
433
|
logging.debug(f"self.min_time_step: {self.min_time_step}")
|
|
451
434
|
|
|
452
|
-
x = np.arange(
|
|
435
|
+
x = np.arange(
|
|
436
|
+
current_time - self.interval // 2,
|
|
437
|
+
current_time + self.interval // 2,
|
|
438
|
+
self.min_time_step,
|
|
439
|
+
)
|
|
453
440
|
|
|
454
441
|
logging.debug(f"len x 1: {len(x)}")
|
|
455
442
|
|
|
@@ -494,7 +481,12 @@ if __name__ == "__main__":
|
|
|
494
481
|
"convert_time_ecg": {
|
|
495
482
|
"name": "convert_time_ecg",
|
|
496
483
|
"description": "convert '%d/%m/%Y %H:%M:%S.%f' in seconds from epoch",
|
|
497
|
-
"code":
|
|
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
|
+
),
|
|
498
490
|
},
|
|
499
491
|
"hhmmss_2_seconds": {
|
|
500
492
|
"name": "hhmmss_2_seconds",
|