boris-behav-obs 9.1.1__py2.py3-none-any.whl → 9.2.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.
- boris/advanced_event_filtering.py +5 -3
- boris/analysis_plugins/number_of_occurences.py +2 -42
- boris/analysis_plugins/number_of_occurences_by_independent_variable.py +5 -45
- boris/analysis_plugins/time_budget.py +9 -47
- boris/behavior_binary_table.py +3 -1
- boris/cooccurence.py +6 -3
- boris/core.py +27 -100
- boris/export_events.py +7 -5
- boris/gui_utilities.py +19 -11
- boris/observation_operations.py +5 -5
- boris/param_panel.py +6 -0
- boris/plugins.py +170 -2
- boris/project_functions.py +37 -22
- boris/select_subj_behav.py +4 -0
- boris/synthetic_time_budget.py +9 -5
- boris/time_budget_widget.py +5 -3
- boris/version.py +2 -2
- {boris_behav_obs-9.1.1.dist-info → boris_behav_obs-9.2.1.dist-info}/METADATA +1 -1
- {boris_behav_obs-9.1.1.dist-info → boris_behav_obs-9.2.1.dist-info}/RECORD +23 -23
- {boris_behav_obs-9.1.1.dist-info → boris_behav_obs-9.2.1.dist-info}/WHEEL +1 -1
- {boris_behav_obs-9.1.1.dist-info → boris_behav_obs-9.2.1.dist-info}/LICENSE.TXT +0 -0
- {boris_behav_obs-9.1.1.dist-info → boris_behav_obs-9.2.1.dist-info}/entry_points.txt +0 -0
- {boris_behav_obs-9.1.1.dist-info → boris_behav_obs-9.2.1.dist-info}/top_level.txt +0 -0
|
@@ -359,8 +359,10 @@ def event_filtering(self):
|
|
|
359
359
|
selected_observations,
|
|
360
360
|
start_coding=start_coding,
|
|
361
361
|
end_coding=end_coding,
|
|
362
|
-
start_interval=start_interval,
|
|
363
|
-
end_interval=end_interval,
|
|
362
|
+
# start_interval=start_interval,
|
|
363
|
+
# end_interval=end_interval,
|
|
364
|
+
start_interval=None,
|
|
365
|
+
end_interval=None,
|
|
364
366
|
maxTime=max_media_duration_all_obs,
|
|
365
367
|
show_include_modifiers=False,
|
|
366
368
|
show_exclude_non_coded_behaviors=False,
|
|
@@ -368,7 +370,7 @@ def event_filtering(self):
|
|
|
368
370
|
n_observations=len(selected_observations),
|
|
369
371
|
)
|
|
370
372
|
|
|
371
|
-
if parameters
|
|
373
|
+
if not parameters:
|
|
372
374
|
return
|
|
373
375
|
|
|
374
376
|
if not parameters[cfg.SELECTED_SUBJECTS] or not parameters[cfg.SELECTED_BEHAVIORS]:
|
|
@@ -6,8 +6,8 @@ number of occurences of behaviors
|
|
|
6
6
|
|
|
7
7
|
import pandas as pd
|
|
8
8
|
|
|
9
|
-
__version__ = "0.
|
|
10
|
-
__version_date__ = "2025-
|
|
9
|
+
__version__ = "0.3.0"
|
|
10
|
+
__version_date__ = "2025-03-17"
|
|
11
11
|
__plugin_name__ = "Number of occurences of behaviors"
|
|
12
12
|
__author__ = "Olivier Friard - University of Torino - Italy"
|
|
13
13
|
|
|
@@ -20,43 +20,3 @@ def run(df: pd.DataFrame):
|
|
|
20
20
|
df_results: pd.DataFrame = df.groupby(["Subject", "Behavior"])["Behavior"].count().reset_index(name="number of occurences")
|
|
21
21
|
|
|
22
22
|
return df_results
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def main(df: pd.DataFrame, observations_list: list = [], parameters: dict = {}) -> pd.DataFrame:
|
|
26
|
-
"""
|
|
27
|
-
filter by selected observations.
|
|
28
|
-
filter by selected subjects.
|
|
29
|
-
filter by selected behaviors.
|
|
30
|
-
filter by time interval.
|
|
31
|
-
"""
|
|
32
|
-
|
|
33
|
-
# filter selected observations
|
|
34
|
-
if observations_list:
|
|
35
|
-
df = df[df["Observation id"].isin(observations_list)]
|
|
36
|
-
|
|
37
|
-
if parameters:
|
|
38
|
-
# filter selected subjects
|
|
39
|
-
df = df[df["Subject"].isin(parameters["selected subjects"])]
|
|
40
|
-
|
|
41
|
-
# filter selected behaviors
|
|
42
|
-
df = df[df["Behavior"].isin(parameters["selected behaviors"])]
|
|
43
|
-
|
|
44
|
-
# filter selected time interval
|
|
45
|
-
if parameters["start time"] is not None and parameters["end time"] is not None:
|
|
46
|
-
MIN_TIME = parameters["start time"]
|
|
47
|
-
MAX_TIME = parameters["end time"]
|
|
48
|
-
df_interval = df[
|
|
49
|
-
(
|
|
50
|
-
((df["Start (s)"] >= MIN_TIME) & (df["Start (s)"] <= MAX_TIME))
|
|
51
|
-
| ((df["Stop (s)"] >= MIN_TIME) & (df["Stop (s)"] <= MAX_TIME))
|
|
52
|
-
)
|
|
53
|
-
| ((df["Start (s)"] < MIN_TIME) & (df["Stop (s)"] > MAX_TIME))
|
|
54
|
-
]
|
|
55
|
-
df_interval.loc[df["Start (s)"] < MIN_TIME, "Start (s)"] = MIN_TIME
|
|
56
|
-
df_interval.loc[df["Stop (s)"] > MAX_TIME, "Stop (s)"] = MAX_TIME
|
|
57
|
-
|
|
58
|
-
df_interval.loc[:, "Duration (s)"] = df_interval["Stop (s)"] - df_interval["Start (s)"]
|
|
59
|
-
|
|
60
|
-
df = df_interval
|
|
61
|
-
|
|
62
|
-
return run(df)
|
|
@@ -6,8 +6,8 @@ number of occurences of behaviors by independent_variable
|
|
|
6
6
|
|
|
7
7
|
import pandas as pd
|
|
8
8
|
|
|
9
|
-
__version__ = "0.
|
|
10
|
-
__version_date__ = "2025-
|
|
9
|
+
__version__ = "0.3.0"
|
|
10
|
+
__version_date__ = "2025-03-17"
|
|
11
11
|
__plugin_name__ = "Number of occurences of behaviors by subject by independent_variable"
|
|
12
12
|
__author__ = "Olivier Friard - University of Torino - Italy"
|
|
13
13
|
|
|
@@ -15,9 +15,9 @@ __author__ = "Olivier Friard - University of Torino - Italy"
|
|
|
15
15
|
def run(df: pd.DataFrame):
|
|
16
16
|
"""
|
|
17
17
|
Calculate the number of occurrences of behaviors by subject and by independent_variable.
|
|
18
|
-
"""
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
This plugin returns a Pandas dataframe
|
|
20
|
+
"""
|
|
21
21
|
|
|
22
22
|
df_results: df.DataFrame = (
|
|
23
23
|
df.groupby(
|
|
@@ -31,44 +31,4 @@ def run(df: pd.DataFrame):
|
|
|
31
31
|
.reset_index(name="number of occurences")
|
|
32
32
|
)
|
|
33
33
|
|
|
34
|
-
return df_results
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def main(df: pd.DataFrame, observations_list: list = [], parameters: dict = {}) -> pd.DataFrame:
|
|
38
|
-
"""
|
|
39
|
-
filter by selected observations.
|
|
40
|
-
filter by selected subjects.
|
|
41
|
-
filter by selected behaviors.
|
|
42
|
-
filter by time interval.
|
|
43
|
-
"""
|
|
44
|
-
|
|
45
|
-
# filter selected observations
|
|
46
|
-
if observations_list:
|
|
47
|
-
df = df[df["Observation id"].isin(observations_list)]
|
|
48
|
-
|
|
49
|
-
if parameters:
|
|
50
|
-
# filter selected subjects
|
|
51
|
-
df = df[df["Subject"].isin(parameters["selected subjects"])]
|
|
52
|
-
|
|
53
|
-
# filter selected behaviors
|
|
54
|
-
df = df[df["Behavior"].isin(parameters["selected behaviors"])]
|
|
55
|
-
|
|
56
|
-
# filter selected time interval
|
|
57
|
-
if parameters["start time"] is not None and parameters["end time"] is not None:
|
|
58
|
-
MIN_TIME = parameters["start time"]
|
|
59
|
-
MAX_TIME = parameters["end time"]
|
|
60
|
-
df_interval = df[
|
|
61
|
-
(
|
|
62
|
-
((df["Start (s)"] >= MIN_TIME) & (df["Start (s)"] <= MAX_TIME))
|
|
63
|
-
| ((df["Stop (s)"] >= MIN_TIME) & (df["Stop (s)"] <= MAX_TIME))
|
|
64
|
-
)
|
|
65
|
-
| ((df["Start (s)"] < MIN_TIME) & (df["Stop (s)"] > MAX_TIME))
|
|
66
|
-
]
|
|
67
|
-
df_interval.loc[df["Start (s)"] < MIN_TIME, "Start (s)"] = MIN_TIME
|
|
68
|
-
df_interval.loc[df["Stop (s)"] > MAX_TIME, "Stop (s)"] = MAX_TIME
|
|
69
|
-
|
|
70
|
-
df_interval.loc[:, "Duration (s)"] = df_interval["Stop (s)"] - df_interval["Start (s)"]
|
|
71
|
-
|
|
72
|
-
df = df_interval
|
|
73
|
-
|
|
74
|
-
return run(df)
|
|
34
|
+
return df_results
|
|
@@ -7,8 +7,8 @@ Time budget
|
|
|
7
7
|
import pandas as pd
|
|
8
8
|
import numpy as np
|
|
9
9
|
|
|
10
|
-
__version__ = "0.
|
|
11
|
-
__version_date__ = "2025-
|
|
10
|
+
__version__ = "0.3.0"
|
|
11
|
+
__version_date__ = "2025-03-17"
|
|
12
12
|
__plugin_name__ = "Time budget"
|
|
13
13
|
__author__ = "Olivier Friard - University of Torino - Italy"
|
|
14
14
|
|
|
@@ -18,7 +18,7 @@ def run(df: pd.DataFrame):
|
|
|
18
18
|
Calculate the following values:
|
|
19
19
|
|
|
20
20
|
- Total number of occurences of behavior
|
|
21
|
-
- Total duration of behavior (in seconds)
|
|
21
|
+
- Total duration of behavior (in seconds) (pandas.DataFrame.sum() ignore NaN values when computing the sum. Use min_count=1)
|
|
22
22
|
- Duration mean of behavior (in seconds)
|
|
23
23
|
- Standard deviation of behavior duration (in seconds)
|
|
24
24
|
- Inter-event intervals mean (in seconds)
|
|
@@ -26,11 +26,15 @@ def run(df: pd.DataFrame):
|
|
|
26
26
|
- % of total subject observation duration
|
|
27
27
|
"""
|
|
28
28
|
|
|
29
|
+
print("running time budget plugin")
|
|
30
|
+
|
|
31
|
+
print(df)
|
|
32
|
+
|
|
29
33
|
group_by = ["Subject", "Behavior"]
|
|
30
34
|
|
|
31
35
|
dfs = [
|
|
32
36
|
df.groupby(group_by)["Behavior"].count().reset_index(name="number of occurences"),
|
|
33
|
-
df.groupby(group_by)["Duration (s)"].sum().reset_index(name="total duration"),
|
|
37
|
+
df.groupby(group_by)["Duration (s)"].sum(min_count=1).reset_index(name="total duration"),
|
|
34
38
|
df.groupby(group_by)["Duration (s)"].mean().astype(float).round(3).reset_index(name="duration mean"),
|
|
35
39
|
df.groupby(group_by)["Duration (s)"].std().astype(float).round(3).reset_index(name="duration std dev"),
|
|
36
40
|
]
|
|
@@ -48,7 +52,7 @@ def run(df: pd.DataFrame):
|
|
|
48
52
|
interval = (df.groupby(["Subject"])["Stop (s)"].max() - df.groupby(["Subject"])["Start (s)"].min()).replace(0, np.nan)
|
|
49
53
|
|
|
50
54
|
dfs.append(
|
|
51
|
-
(100 * df.groupby(group_by)["Duration (s)"].sum() / interval)
|
|
55
|
+
(100 * df.groupby(group_by)["Duration (s)"].sum(min_count=1) / interval)
|
|
52
56
|
.astype(float)
|
|
53
57
|
.round(3)
|
|
54
58
|
.reset_index(name="% of total subject observation duration")
|
|
@@ -59,45 +63,3 @@ def run(df: pd.DataFrame):
|
|
|
59
63
|
merged_df = pd.merge(merged_df, df, on=group_by)
|
|
60
64
|
|
|
61
65
|
return merged_df
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def main(df: pd.DataFrame, observations_list: list = [], parameters: dict = {}) -> pd.DataFrame:
|
|
65
|
-
"""
|
|
66
|
-
filter by selected observations.
|
|
67
|
-
filter by selected subjects.
|
|
68
|
-
filter by selected behaviors.
|
|
69
|
-
filter by time interval.
|
|
70
|
-
"""
|
|
71
|
-
|
|
72
|
-
# filter selected observations
|
|
73
|
-
if observations_list:
|
|
74
|
-
df = df[df["Observation id"].isin(observations_list)]
|
|
75
|
-
|
|
76
|
-
if parameters:
|
|
77
|
-
# filter selected subjects
|
|
78
|
-
df = df[df["Subject"].isin(parameters["selected subjects"])]
|
|
79
|
-
|
|
80
|
-
# filter selected behaviors
|
|
81
|
-
df = df[df["Behavior"].isin(parameters["selected behaviors"])]
|
|
82
|
-
|
|
83
|
-
# filter selected time interval
|
|
84
|
-
if parameters["start time"] is not None and parameters["end time"] is not None:
|
|
85
|
-
MIN_TIME = parameters["start time"]
|
|
86
|
-
MAX_TIME = parameters["end time"]
|
|
87
|
-
|
|
88
|
-
df_interval = df[
|
|
89
|
-
(
|
|
90
|
-
((df["Start (s)"] >= MIN_TIME) & (df["Start (s)"] <= MAX_TIME))
|
|
91
|
-
| ((df["Stop (s)"] >= MIN_TIME) & (df["Stop (s)"] <= MAX_TIME))
|
|
92
|
-
)
|
|
93
|
-
| ((df["Start (s)"] < MIN_TIME) & (df["Stop (s)"] > MAX_TIME))
|
|
94
|
-
]
|
|
95
|
-
|
|
96
|
-
df_interval.loc[df["Start (s)"] < MIN_TIME, "Start (s)"] = MIN_TIME
|
|
97
|
-
df_interval.loc[df["Stop (s)"] > MAX_TIME, "Stop (s)"] = MAX_TIME
|
|
98
|
-
|
|
99
|
-
df_interval.loc[:, "Duration (s)"] = df_interval["Stop (s)"] - df_interval["Start (s)"]
|
|
100
|
-
|
|
101
|
-
df = df_interval
|
|
102
|
-
|
|
103
|
-
return run(df)
|
boris/behavior_binary_table.py
CHANGED
|
@@ -216,6 +216,8 @@ def behavior_binary_table(self):
|
|
|
216
216
|
selected_observations,
|
|
217
217
|
start_coding=start_coding,
|
|
218
218
|
end_coding=end_coding,
|
|
219
|
+
# start_interval=start_interval,
|
|
220
|
+
# end_interval=end_interval,
|
|
219
221
|
start_interval=start_interval,
|
|
220
222
|
end_interval=end_interval,
|
|
221
223
|
maxTime=max_media_duration_all_obs,
|
|
@@ -224,7 +226,7 @@ def behavior_binary_table(self):
|
|
|
224
226
|
by_category=False,
|
|
225
227
|
n_observations=len(selected_observations),
|
|
226
228
|
)
|
|
227
|
-
if parameters
|
|
229
|
+
if not parameters:
|
|
228
230
|
return
|
|
229
231
|
if not parameters[cfg.SELECTED_SUBJECTS] or not parameters[cfg.SELECTED_BEHAVIORS]:
|
|
230
232
|
QMessageBox.warning(None, cfg.programName, "Select subject(s) and behavior(s) to analyze")
|
boris/cooccurence.py
CHANGED
|
@@ -98,6 +98,7 @@ def get_cooccurence(self):
|
|
|
98
98
|
|
|
99
99
|
start_interval, end_interval = observation_operations.time_intervals_range(self.pj[cfg.OBSERVATIONS], selected_observations)
|
|
100
100
|
|
|
101
|
+
# loop on choose subjects /behaviors until parameters are OK
|
|
101
102
|
while True:
|
|
102
103
|
flag_ok: bool = True
|
|
103
104
|
parameters = select_subj_behav.choose_obs_subj_behav_category(
|
|
@@ -105,15 +106,17 @@ def get_cooccurence(self):
|
|
|
105
106
|
selected_observations,
|
|
106
107
|
start_coding=start_coding,
|
|
107
108
|
end_coding=end_coding,
|
|
108
|
-
start_interval=start_interval,
|
|
109
|
-
end_interval=end_interval,
|
|
109
|
+
# start_interval=start_interval,
|
|
110
|
+
# end_interval=end_interval,
|
|
111
|
+
start_interval=None,
|
|
112
|
+
end_interval=None,
|
|
110
113
|
maxTime=max_media_duration_all_obs,
|
|
111
114
|
n_observations=len(selected_observations),
|
|
112
115
|
show_include_modifiers=False,
|
|
113
116
|
show_exclude_non_coded_behaviors=True,
|
|
114
117
|
)
|
|
115
118
|
|
|
116
|
-
if parameters
|
|
119
|
+
if not parameters: # cancel button pressed
|
|
117
120
|
return
|
|
118
121
|
|
|
119
122
|
if not parameters[cfg.SELECTED_SUBJECTS]:
|
boris/core.py
CHANGED
|
@@ -34,7 +34,6 @@ import json
|
|
|
34
34
|
import logging
|
|
35
35
|
import pathlib as pl
|
|
36
36
|
import platform
|
|
37
|
-
import importlib
|
|
38
37
|
import re
|
|
39
38
|
import PIL.Image
|
|
40
39
|
import PIL.ImageEnhance
|
|
@@ -52,7 +51,6 @@ from decimal import Decimal as dec
|
|
|
52
51
|
from decimal import ROUND_DOWN
|
|
53
52
|
import gzip
|
|
54
53
|
from collections import deque
|
|
55
|
-
import pandas as pd
|
|
56
54
|
import matplotlib
|
|
57
55
|
import zipfile
|
|
58
56
|
import shutil
|
|
@@ -129,7 +127,6 @@ from . import config_file
|
|
|
129
127
|
from . import select_subj_behav
|
|
130
128
|
from . import observation_operations
|
|
131
129
|
from . import write_event
|
|
132
|
-
from . import view_df
|
|
133
130
|
|
|
134
131
|
|
|
135
132
|
# matplotlib.pyplot.switch_backend("Qt5Agg")
|
|
@@ -3634,6 +3631,18 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3634
3631
|
else:
|
|
3635
3632
|
current_time = self.getLaps()
|
|
3636
3633
|
|
|
3634
|
+
# check if observation time interval
|
|
3635
|
+
if self.pj[cfg.OBSERVATIONS][self.observationId].get(cfg.OBSERVATION_TIME_INTERVAL, [0, 0])[1]:
|
|
3636
|
+
# check if current time outside of interval
|
|
3637
|
+
if current_time >= self.pj[cfg.OBSERVATIONS][self.observationId].get(cfg.OBSERVATION_TIME_INTERVAL, [None, None])[1]:
|
|
3638
|
+
self.beep("beep")
|
|
3639
|
+
self.liveTimer.stop()
|
|
3640
|
+
self.liveObservationStarted = False
|
|
3641
|
+
# set current time to end of observation interval
|
|
3642
|
+
current_time = dec(self.pj[cfg.OBSERVATIONS][self.observationId].get(cfg.OBSERVATION_TIME_INTERVAL, [None, None])[1])
|
|
3643
|
+
self.pb_live_obs.setText("Live observation finished")
|
|
3644
|
+
|
|
3645
|
+
|
|
3637
3646
|
self.lb_current_media_time.setText(util.convertTime(self.timeFormat, current_time))
|
|
3638
3647
|
|
|
3639
3648
|
# extract State events
|
|
@@ -3663,13 +3672,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3663
3672
|
self.liveTimer.stop()
|
|
3664
3673
|
self.pb_live_obs.setText("Live observation stopped (scan sampling)")
|
|
3665
3674
|
|
|
3666
|
-
# observation time interval
|
|
3667
|
-
if self.pj[cfg.OBSERVATIONS][self.observationId].get(cfg.OBSERVATION_TIME_INTERVAL, [0, 0])[1]:
|
|
3668
|
-
if current_time >= self.pj[cfg.OBSERVATIONS][self.observationId].get(cfg.OBSERVATION_TIME_INTERVAL, [0, 0])[1]:
|
|
3669
|
-
self.beep("beep")
|
|
3670
|
-
self.liveTimer.stop()
|
|
3671
|
-
self.liveObservationStarted = False
|
|
3672
|
-
self.pb_live_obs.setText("Live observation finished")
|
|
3673
3675
|
|
|
3674
3676
|
def start_live_observation(self):
|
|
3675
3677
|
"""
|
|
@@ -3772,8 +3774,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3772
3774
|
selected_observations,
|
|
3773
3775
|
start_coding=start_coding,
|
|
3774
3776
|
end_coding=end_coding,
|
|
3775
|
-
start_interval=start_interval,
|
|
3776
|
-
end_interval=end_interval,
|
|
3777
|
+
# start_interval=start_interval,
|
|
3778
|
+
# end_interval=end_interval,
|
|
3779
|
+
start_interval=None,
|
|
3780
|
+
end_interval=None,
|
|
3777
3781
|
maxTime=max_media_duration_all_obs,
|
|
3778
3782
|
show_include_modifiers=False,
|
|
3779
3783
|
show_exclude_non_coded_behaviors=False,
|
|
@@ -5762,6 +5766,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
5762
5766
|
self.extract_frame(self.dw_player[0])
|
|
5763
5767
|
|
|
5764
5768
|
def obs_param(self):
|
|
5769
|
+
"""
|
|
5770
|
+
allow user to select observations and then subjects and behaviors
|
|
5771
|
+
"""
|
|
5765
5772
|
_, selected_observations = select_observations.select_observations2(self, mode=cfg.MULTIPLE, windows_title="")
|
|
5766
5773
|
|
|
5767
5774
|
if not selected_observations:
|
|
@@ -5786,8 +5793,14 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
5786
5793
|
|
|
5787
5794
|
start_coding, end_coding, _ = observation_operations.coding_time(self.pj[cfg.OBSERVATIONS], selected_observations)
|
|
5788
5795
|
|
|
5796
|
+
print(f"{start_coding=}")
|
|
5797
|
+
print(f"{end_coding=}")
|
|
5798
|
+
|
|
5789
5799
|
start_interval, end_interval = observation_operations.time_intervals_range(self.pj[cfg.OBSERVATIONS], selected_observations)
|
|
5790
5800
|
|
|
5801
|
+
print(f"{start_interval=}")
|
|
5802
|
+
print(f"{end_interval=}")
|
|
5803
|
+
|
|
5791
5804
|
parameters: dict = select_subj_behav.choose_obs_subj_behav_category(
|
|
5792
5805
|
self,
|
|
5793
5806
|
selected_observations,
|
|
@@ -5803,6 +5816,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
5803
5816
|
if parameters == {}:
|
|
5804
5817
|
return [], {}
|
|
5805
5818
|
|
|
5819
|
+
print(f"{parameters=}")
|
|
5820
|
+
|
|
5806
5821
|
if not parameters[cfg.SELECTED_SUBJECTS] or not parameters[cfg.SELECTED_BEHAVIORS]:
|
|
5807
5822
|
QMessageBox.warning(None, cfg.programName, "Select subject(s) and behavior(s) to analyze")
|
|
5808
5823
|
return [], {}
|
|
@@ -5810,94 +5825,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
5810
5825
|
logging.debug(f"{parameters=}")
|
|
5811
5826
|
return selected_observations, parameters
|
|
5812
5827
|
|
|
5813
|
-
def run_plugin(self):
|
|
5814
|
-
"""
|
|
5815
|
-
run plugin
|
|
5816
|
-
"""
|
|
5817
|
-
if not self.project:
|
|
5818
|
-
QMessageBox.warning(
|
|
5819
|
-
self,
|
|
5820
|
-
cfg.programName,
|
|
5821
|
-
"No observations found. Open a project first",
|
|
5822
|
-
QMessageBox.Ok | QMessageBox.Default,
|
|
5823
|
-
QMessageBox.NoButton,
|
|
5824
|
-
)
|
|
5825
|
-
return
|
|
5826
|
-
|
|
5827
|
-
logging.debug(f"{self.config_param.get(cfg.ANALYSIS_PLUGINS, {})=}")
|
|
5828
|
-
|
|
5829
|
-
plugin_name = self.sender().text()
|
|
5830
|
-
if plugin_name not in self.config_param.get(cfg.ANALYSIS_PLUGINS, {}):
|
|
5831
|
-
QMessageBox.critical(self, cfg.programName, f"Plugin '{plugin_name}' not found")
|
|
5832
|
-
return
|
|
5833
|
-
|
|
5834
|
-
plugin_path = self.config_param.get(cfg.ANALYSIS_PLUGINS, {})[plugin_name]
|
|
5835
|
-
|
|
5836
|
-
logging.debug(f"{plugin_path=}")
|
|
5837
|
-
|
|
5838
|
-
if not pl.Path(plugin_path).is_file():
|
|
5839
|
-
QMessageBox.critical(self, cfg.programName, f"The plugin {plugin_path} was not found.")
|
|
5840
|
-
return
|
|
5841
|
-
|
|
5842
|
-
logging.debug(f"run plugin from {plugin_path}")
|
|
5843
|
-
|
|
5844
|
-
module_name = pl.Path(plugin_path).stem
|
|
5845
|
-
|
|
5846
|
-
spec = importlib.util.spec_from_file_location(module_name, plugin_path)
|
|
5847
|
-
plugin_module = importlib.util.module_from_spec(spec)
|
|
5848
|
-
|
|
5849
|
-
logging.debug(f"{plugin_module=}")
|
|
5850
|
-
|
|
5851
|
-
spec.loader.exec_module(plugin_module)
|
|
5852
|
-
|
|
5853
|
-
logging.info(
|
|
5854
|
-
f"{plugin_module.__plugin_name__} loaded v.{getattr(plugin_module, '__version__')} v. {getattr(plugin_module, '__version_date__')}"
|
|
5855
|
-
)
|
|
5856
|
-
|
|
5857
|
-
selected_observations, parameters = self.obs_param()
|
|
5858
|
-
if not selected_observations:
|
|
5859
|
-
return
|
|
5860
|
-
|
|
5861
|
-
df = project_functions.project2dataframe(self.pj, selected_observations)
|
|
5862
|
-
|
|
5863
|
-
logging.debug("dataframe info")
|
|
5864
|
-
logging.debug(f"{df.info()}")
|
|
5865
|
-
logging.debug(f"{df.head()}")
|
|
5866
|
-
|
|
5867
|
-
# df_results, str_results = plugin_module.main(df, observations_list=selected_observations, parameters=parameters)
|
|
5868
|
-
|
|
5869
|
-
plugin_results = plugin_module.main(df, observations_list=selected_observations, parameters=parameters)
|
|
5870
|
-
# test if tuple: if not transform to tuple
|
|
5871
|
-
if not isinstance(plugin_results, tuple):
|
|
5872
|
-
plugin_results = tuple([plugin_results])
|
|
5873
|
-
|
|
5874
|
-
self.plugin_visu: list = []
|
|
5875
|
-
for result in plugin_results:
|
|
5876
|
-
if isinstance(result, str):
|
|
5877
|
-
self.plugin_visu.append(dialog.Results_dialog())
|
|
5878
|
-
self.plugin_visu[-1].setWindowTitle(self.sender().text())
|
|
5879
|
-
self.plugin_visu[-1].ptText.clear()
|
|
5880
|
-
self.plugin_visu[-1].ptText.appendPlainText(result)
|
|
5881
|
-
self.plugin_visu[-1].show()
|
|
5882
|
-
elif isinstance(result, pd.DataFrame):
|
|
5883
|
-
self.plugin_visu.append(
|
|
5884
|
-
view_df.View_df(self.sender().text(), f"{plugin_module.__version__} ({plugin_module.__version_date__})", result)
|
|
5885
|
-
)
|
|
5886
|
-
self.plugin_visu[-1].show()
|
|
5887
|
-
else:
|
|
5888
|
-
# result is not str nor dataframe
|
|
5889
|
-
QMessageBox.critical(
|
|
5890
|
-
None,
|
|
5891
|
-
cfg.programName,
|
|
5892
|
-
(
|
|
5893
|
-
f"Plugin returns an unknown object type: {type(result)}\n\n"
|
|
5894
|
-
"Plugins must return str and/or Pandas Dataframes.\n"
|
|
5895
|
-
"Check the plugin code."
|
|
5896
|
-
),
|
|
5897
|
-
QMessageBox.Ok | QMessageBox.Default,
|
|
5898
|
-
QMessageBox.NoButton,
|
|
5899
|
-
)
|
|
5900
|
-
|
|
5901
5828
|
|
|
5902
5829
|
def main():
|
|
5903
5830
|
# QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
|
boris/export_events.py
CHANGED
|
@@ -76,7 +76,7 @@ def export_events_as_behavioral_sequences(self, separated_subjects=False, timed=
|
|
|
76
76
|
else:
|
|
77
77
|
max_media_duration_all_obs = None
|
|
78
78
|
start_coding, end_coding = dec("NaN"), dec("NaN")
|
|
79
|
-
start_interval, end_interval =
|
|
79
|
+
start_interval, end_interval = None, None
|
|
80
80
|
|
|
81
81
|
parameters = select_subj_behav.choose_obs_subj_behav_category(
|
|
82
82
|
self,
|
|
@@ -169,7 +169,7 @@ def export_tabular_events(self, mode: str = "tabular") -> None:
|
|
|
169
169
|
else:
|
|
170
170
|
max_media_duration_all_obs = None
|
|
171
171
|
start_coding, end_coding = dec("NaN"), dec("NaN")
|
|
172
|
-
start_interval, end_interval =
|
|
172
|
+
start_interval, end_interval = None, None
|
|
173
173
|
|
|
174
174
|
parameters = select_subj_behav.choose_obs_subj_behav_category(
|
|
175
175
|
self,
|
|
@@ -373,7 +373,7 @@ def export_aggregated_events(self):
|
|
|
373
373
|
else:
|
|
374
374
|
max_media_duration_all_obs = None
|
|
375
375
|
start_coding, end_coding = dec("NaN"), dec("NaN")
|
|
376
|
-
start_interval, end_interval =
|
|
376
|
+
start_interval, end_interval = None, None
|
|
377
377
|
|
|
378
378
|
parameters = select_subj_behav.choose_obs_subj_behav_category(
|
|
379
379
|
self,
|
|
@@ -681,8 +681,10 @@ def export_events_as_textgrid(self) -> None:
|
|
|
681
681
|
selected_observations,
|
|
682
682
|
start_coding=start_coding,
|
|
683
683
|
end_coding=end_coding,
|
|
684
|
-
start_interval=start_interval,
|
|
685
|
-
end_interval=end_interval,
|
|
684
|
+
# start_interval=start_interval,
|
|
685
|
+
# end_interval=end_interval,
|
|
686
|
+
start_interval=None,
|
|
687
|
+
end_interval=None,
|
|
686
688
|
show_include_modifiers=False,
|
|
687
689
|
show_exclude_non_coded_behaviors=False,
|
|
688
690
|
maxTime=max_obs_length,
|
boris/gui_utilities.py
CHANGED
|
@@ -31,32 +31,40 @@ def save_geometry(widget: QWidget, widget_name: str):
|
|
|
31
31
|
save window geometry in ini file
|
|
32
32
|
"""
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
ini_file_path = pl.Path.home() / pl.Path(".boris")
|
|
35
|
+
if ini_file_path.is_file():
|
|
36
|
+
try:
|
|
37
37
|
settings = QSettings(str(ini_file_path), QSettings.IniFormat)
|
|
38
38
|
settings.setValue(f"{widget_name} geometry", widget.saveGeometry())
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
except Exception:
|
|
40
|
+
logging.warning(f"error during saving {widget_name} geometry")
|
|
41
41
|
|
|
42
42
|
|
|
43
|
-
def restore_geometry(widget: QWidget, widget_name: str,
|
|
43
|
+
def restore_geometry(widget: QWidget, widget_name: str, default_width_height):
|
|
44
44
|
"""
|
|
45
45
|
restore window geometry in ini file
|
|
46
46
|
"""
|
|
47
|
+
def default_resize(widget, default_width_height):
|
|
48
|
+
if default_width_height != (0, 0):
|
|
49
|
+
try:
|
|
50
|
+
widget.resize(default_width_height[0], default_width_height[1])
|
|
51
|
+
except Exception:
|
|
52
|
+
logging.warning("Error during restoring default")
|
|
53
|
+
|
|
47
54
|
|
|
55
|
+
logging.debug(f'restore geometry function for {widget_name}')
|
|
48
56
|
try:
|
|
49
57
|
ini_file_path = pl.Path.home() / pl.Path(".boris")
|
|
50
58
|
if ini_file_path.is_file():
|
|
51
59
|
settings = QSettings(str(ini_file_path), QSettings.IniFormat)
|
|
60
|
+
print(settings.value(f"{widget_name} geometry"))
|
|
52
61
|
widget.restoreGeometry(settings.value(f"{widget_name} geometry"))
|
|
62
|
+
logging.debug(f'geometry restored for {widget_name} {settings.value(f"{widget_name} geometry")}')
|
|
63
|
+
else:
|
|
64
|
+
default_resize(widget, default_width_height)
|
|
53
65
|
except Exception:
|
|
54
66
|
logging.warning(f"error during restoring {widget_name} geometry")
|
|
55
|
-
|
|
56
|
-
try:
|
|
57
|
-
widget.resize(default_geometry[0], default_geometry[1])
|
|
58
|
-
except Exception:
|
|
59
|
-
logging.warning("Error during restoring default")
|
|
67
|
+
default_resize(widget, default_width_height)
|
|
60
68
|
|
|
61
69
|
|
|
62
70
|
def set_icons(self, theme_mode: str) -> None:
|
boris/observation_operations.py
CHANGED
|
@@ -43,9 +43,8 @@ from PySide6.QtWidgets import (
|
|
|
43
43
|
QSlider,
|
|
44
44
|
QMainWindow,
|
|
45
45
|
QDockWidget,
|
|
46
|
-
QPushButton,
|
|
47
46
|
)
|
|
48
|
-
from PySide6.QtCore import Qt, QDateTime, QTimer
|
|
47
|
+
from PySide6.QtCore import Qt, QDateTime, QTimer
|
|
49
48
|
from PySide6.QtGui import QFont, QIcon, QTextCursor
|
|
50
49
|
|
|
51
50
|
from PySide6 import QtTest
|
|
@@ -365,8 +364,9 @@ def time_intervals_range(observations: dict, observations_list: list) -> Tuple[O
|
|
|
365
364
|
for obs_id in observations_list:
|
|
366
365
|
observation = observations[obs_id]
|
|
367
366
|
offset = observation[cfg.TIME_OFFSET]
|
|
368
|
-
|
|
369
|
-
|
|
367
|
+
if dec(observation[cfg.OBSERVATION_TIME_INTERVAL][0]) + offset and dec(observation[cfg.OBSERVATION_TIME_INTERVAL][1]) + offset:
|
|
368
|
+
start_interval_list.append(dec(observation[cfg.OBSERVATION_TIME_INTERVAL][0]) + offset)
|
|
369
|
+
end_interval_list.append(dec(observation[cfg.OBSERVATION_TIME_INTERVAL][1]) + offset)
|
|
370
370
|
|
|
371
371
|
if not start_interval_list:
|
|
372
372
|
earliest_start_interval = None
|
|
@@ -376,7 +376,7 @@ def time_intervals_range(observations: dict, observations_list: list) -> Tuple[O
|
|
|
376
376
|
if not end_interval_list:
|
|
377
377
|
latest_end_interval = None
|
|
378
378
|
else:
|
|
379
|
-
latest_end_interval =
|
|
379
|
+
latest_end_interval = max([x for x in end_interval_list])
|
|
380
380
|
|
|
381
381
|
return earliest_start_interval, latest_end_interval
|
|
382
382
|
|
boris/param_panel.py
CHANGED
|
@@ -95,7 +95,13 @@ class Param_panel(QDialog, Ui_Dialog):
|
|
|
95
95
|
if not ((self.start_interval is None) or self.start_interval.is_nan()):
|
|
96
96
|
# Set start_time and end_time widgets values even if it is not shown with
|
|
97
97
|
# more than 1 observation as some analyses might use it (eg: advanced event filtering)
|
|
98
|
+
|
|
99
|
+
print(f"{self.end_interval=}")
|
|
100
|
+
|
|
98
101
|
end_interval = self.end_interval if self.end_interval != 0 else self.media_duration
|
|
102
|
+
|
|
103
|
+
print(f"{end_interval=}")
|
|
104
|
+
|
|
99
105
|
self.start_time.set_time(self.start_interval)
|
|
100
106
|
self.end_time.set_time(end_interval)
|
|
101
107
|
self.frm_time_interval.setEnabled(False)
|
boris/plugins.py
CHANGED
|
@@ -19,10 +19,19 @@ Copyright 2012-2025 Olivier Friard
|
|
|
19
19
|
MA 02110-1301, USA.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
+
import importlib
|
|
22
23
|
import logging
|
|
24
|
+
import numpy as np
|
|
25
|
+
import pandas as pd
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
|
|
23
28
|
from PySide6.QtGui import QAction
|
|
29
|
+
from PySide6.QtWidgets import QMessageBox
|
|
30
|
+
|
|
24
31
|
from . import config as cfg
|
|
25
|
-
from
|
|
32
|
+
from . import project_functions
|
|
33
|
+
from . import dialog
|
|
34
|
+
from . import view_df
|
|
26
35
|
|
|
27
36
|
|
|
28
37
|
def add_plugins_to_menu(self):
|
|
@@ -32,7 +41,7 @@ def add_plugins_to_menu(self):
|
|
|
32
41
|
for plugin_name in self.config_param.get(cfg.ANALYSIS_PLUGINS, {}):
|
|
33
42
|
logging.debug(f"adding plugin '{plugin_name}' to menu")
|
|
34
43
|
# Create an action for each submenu option
|
|
35
|
-
action = QAction(self, triggered=self
|
|
44
|
+
action = QAction(self, triggered=lambda checked=False, name=plugin_name: run_plugin(self, name))
|
|
36
45
|
action.setText(plugin_name)
|
|
37
46
|
|
|
38
47
|
self.menu_plugins.addAction(action)
|
|
@@ -77,3 +86,162 @@ def load_plugins(self):
|
|
|
77
86
|
self.config_param[cfg.ANALYSIS_PLUGINS][plugin_name] = str(file_)
|
|
78
87
|
|
|
79
88
|
logging.debug(f"{self.config_param.get(cfg.ANALYSIS_PLUGINS, {})=}")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def plugin_df_filter(df: pd.DataFrame, observations_list: list = [], parameters: dict = {}) -> pd.DataFrame:
|
|
92
|
+
"""
|
|
93
|
+
filter the dataframe following parameters
|
|
94
|
+
|
|
95
|
+
filter by selected observations.
|
|
96
|
+
filter by selected subjects.
|
|
97
|
+
filter by selected behaviors.
|
|
98
|
+
filter by time interval.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
# filter selected observations
|
|
102
|
+
df = df[df["Observation id"].isin(observations_list)]
|
|
103
|
+
|
|
104
|
+
if parameters:
|
|
105
|
+
# filter selected subjects
|
|
106
|
+
df = df[df["Subject"].isin(parameters["selected subjects"])]
|
|
107
|
+
|
|
108
|
+
# filter selected behaviors
|
|
109
|
+
df = df[df["Behavior"].isin(parameters["selected behaviors"])]
|
|
110
|
+
|
|
111
|
+
if parameters["time"] == "interval of observation":
|
|
112
|
+
# filter each observation with observation interval start/stop
|
|
113
|
+
|
|
114
|
+
# keep events between observation interval start time and observation interval stop/end
|
|
115
|
+
df_interval = df[
|
|
116
|
+
(
|
|
117
|
+
((df["Start (s)"] >= df["Observation interval start"]) & (df["Start (s)"] <= df["Observation interval stop"]))
|
|
118
|
+
| ((df["Stop (s)"] >= df["Observation interval start"]) & (df["Stop (s)"] <= df["Observation interval stop"]))
|
|
119
|
+
)
|
|
120
|
+
| ((df["Start (s)"] < df["Observation interval start"]) & (df["Stop (s)"] > df["Observation interval stop"]))
|
|
121
|
+
]
|
|
122
|
+
|
|
123
|
+
df_interval.loc[df["Start (s)"] < df["Observation interval start"], "Start (s)"] = df["Observation interval start"]
|
|
124
|
+
df_interval.loc[df["Stop (s)"] > df["Observation interval stop"], "Stop (s)"] = df["Observation interval stop"]
|
|
125
|
+
|
|
126
|
+
df_interval.loc[:, "Duration (s)"] = (df_interval["Stop (s)"] - df_interval["Start (s)"]).replace(0, np.nan)
|
|
127
|
+
|
|
128
|
+
df = df_interval
|
|
129
|
+
|
|
130
|
+
else:
|
|
131
|
+
# filter selected time interval
|
|
132
|
+
if parameters["start time"] is not None and parameters["end time"] is not None:
|
|
133
|
+
MIN_TIME = parameters["start time"]
|
|
134
|
+
MAX_TIME = parameters["end time"]
|
|
135
|
+
|
|
136
|
+
# keep events between start time and end_time
|
|
137
|
+
df_interval = df[
|
|
138
|
+
(
|
|
139
|
+
((df["Start (s)"] >= MIN_TIME) & (df["Start (s)"] <= MAX_TIME))
|
|
140
|
+
| ((df["Stop (s)"] >= MIN_TIME) & (df["Stop (s)"] <= MAX_TIME))
|
|
141
|
+
)
|
|
142
|
+
| ((df["Start (s)"] < MIN_TIME) & (df["Stop (s)"] > MAX_TIME))
|
|
143
|
+
]
|
|
144
|
+
|
|
145
|
+
df_interval.loc[df["Start (s)"] < MIN_TIME, "Start (s)"] = MIN_TIME
|
|
146
|
+
df_interval.loc[df["Stop (s)"] > MAX_TIME, "Stop (s)"] = MAX_TIME
|
|
147
|
+
|
|
148
|
+
df_interval.loc[:, "Duration (s)"] = (df_interval["Stop (s)"] - df_interval["Start (s)"]).replace(0, np.nan)
|
|
149
|
+
|
|
150
|
+
df = df_interval
|
|
151
|
+
|
|
152
|
+
print("filtered")
|
|
153
|
+
print("=" * 50)
|
|
154
|
+
|
|
155
|
+
print(f"{df=}")
|
|
156
|
+
|
|
157
|
+
return df
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def run_plugin(self, plugin_name):
|
|
161
|
+
"""
|
|
162
|
+
run plugin
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
if not self.project:
|
|
166
|
+
QMessageBox.warning(
|
|
167
|
+
self,
|
|
168
|
+
cfg.programName,
|
|
169
|
+
"No observations found. Open a project first",
|
|
170
|
+
QMessageBox.Ok | QMessageBox.Default,
|
|
171
|
+
QMessageBox.NoButton,
|
|
172
|
+
)
|
|
173
|
+
return
|
|
174
|
+
|
|
175
|
+
logging.debug(f"{self.config_param.get(cfg.ANALYSIS_PLUGINS, {})=}")
|
|
176
|
+
|
|
177
|
+
if plugin_name not in self.config_param.get(cfg.ANALYSIS_PLUGINS, {}):
|
|
178
|
+
QMessageBox.critical(self, cfg.programName, f"Plugin '{plugin_name}' not found")
|
|
179
|
+
return
|
|
180
|
+
|
|
181
|
+
plugin_path = self.config_param.get(cfg.ANALYSIS_PLUGINS, {})[plugin_name]
|
|
182
|
+
|
|
183
|
+
logging.debug(f"{plugin_path=}")
|
|
184
|
+
|
|
185
|
+
if not Path(plugin_path).is_file():
|
|
186
|
+
QMessageBox.critical(self, cfg.programName, f"The plugin {plugin_path} was not found.")
|
|
187
|
+
return
|
|
188
|
+
|
|
189
|
+
logging.debug(f"run plugin from {plugin_path}")
|
|
190
|
+
|
|
191
|
+
module_name = Path(plugin_path).stem
|
|
192
|
+
|
|
193
|
+
spec = importlib.util.spec_from_file_location(module_name, plugin_path)
|
|
194
|
+
plugin_module = importlib.util.module_from_spec(spec)
|
|
195
|
+
|
|
196
|
+
logging.debug(f"{plugin_module=}")
|
|
197
|
+
|
|
198
|
+
spec.loader.exec_module(plugin_module)
|
|
199
|
+
|
|
200
|
+
logging.info(
|
|
201
|
+
f"{plugin_module.__plugin_name__} loaded v.{getattr(plugin_module, '__version__')} v. {getattr(plugin_module, '__version_date__')}"
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
selected_observations, parameters = self.obs_param()
|
|
205
|
+
if not selected_observations:
|
|
206
|
+
return
|
|
207
|
+
|
|
208
|
+
df = project_functions.project2dataframe(self.pj, selected_observations)
|
|
209
|
+
|
|
210
|
+
"""
|
|
211
|
+
logging.debug("dataframe info")
|
|
212
|
+
logging.debug(f"{df.info()}")
|
|
213
|
+
logging.debug(f"{df.head()}")
|
|
214
|
+
"""
|
|
215
|
+
|
|
216
|
+
# filter the dataframe with parameters
|
|
217
|
+
filtered_df = plugin_df_filter(df, observations_list=selected_observations, parameters=parameters)
|
|
218
|
+
|
|
219
|
+
plugin_results = plugin_module.run(filtered_df)
|
|
220
|
+
# test if plugin_tests is a tuple: if not transform to tuple
|
|
221
|
+
if not isinstance(plugin_results, tuple):
|
|
222
|
+
plugin_results = tuple([plugin_results])
|
|
223
|
+
|
|
224
|
+
self.plugin_visu: list = []
|
|
225
|
+
for result in plugin_results:
|
|
226
|
+
if isinstance(result, str):
|
|
227
|
+
self.plugin_visu.append(dialog.Results_dialog())
|
|
228
|
+
self.plugin_visu[-1].setWindowTitle(plugin_name)
|
|
229
|
+
self.plugin_visu[-1].ptText.clear()
|
|
230
|
+
self.plugin_visu[-1].ptText.appendPlainText(result)
|
|
231
|
+
self.plugin_visu[-1].show()
|
|
232
|
+
elif isinstance(result, pd.DataFrame):
|
|
233
|
+
self.plugin_visu.append(view_df.View_df(plugin_name, f"{plugin_module.__version__} ({plugin_module.__version_date__})", result))
|
|
234
|
+
self.plugin_visu[-1].show()
|
|
235
|
+
else:
|
|
236
|
+
# result is not str nor dataframe
|
|
237
|
+
QMessageBox.critical(
|
|
238
|
+
None,
|
|
239
|
+
cfg.programName,
|
|
240
|
+
(
|
|
241
|
+
f"Plugin returns an unknown object type: {type(result)}\n\n"
|
|
242
|
+
"Plugins must return str and/or Pandas Dataframes.\n"
|
|
243
|
+
"Check the plugin code."
|
|
244
|
+
),
|
|
245
|
+
QMessageBox.Ok | QMessageBox.Default,
|
|
246
|
+
QMessageBox.NoButton,
|
|
247
|
+
)
|
boris/project_functions.py
CHANGED
|
@@ -39,7 +39,6 @@ from . import db_functions
|
|
|
39
39
|
from . import dialog
|
|
40
40
|
from . import observation_operations
|
|
41
41
|
from . import portion as I
|
|
42
|
-
from . import project_functions
|
|
43
42
|
from . import utilities as util
|
|
44
43
|
from . import version
|
|
45
44
|
|
|
@@ -1806,9 +1805,11 @@ def project2dataframe(pj: dict, observations_list: list = []) -> pd.DataFrame:
|
|
|
1806
1805
|
|
|
1807
1806
|
data = {
|
|
1808
1807
|
"Observation id": [],
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1808
|
+
"Observation date": [],
|
|
1809
|
+
"Description": [],
|
|
1810
|
+
"Observation type": [],
|
|
1811
|
+
"Observation interval start": [],
|
|
1812
|
+
"Observation interval stop": [],
|
|
1812
1813
|
# "Source": [],
|
|
1813
1814
|
# "Time offset (s)": [],
|
|
1814
1815
|
# "Coding duration": [],
|
|
@@ -1847,9 +1848,11 @@ def project2dataframe(pj: dict, observations_list: list = []) -> pd.DataFrame:
|
|
|
1847
1848
|
|
|
1848
1849
|
type_ = {
|
|
1849
1850
|
"Observation id": "string",
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1851
|
+
"Observation date": "string",
|
|
1852
|
+
"Description": "string",
|
|
1853
|
+
"Observation type": "string",
|
|
1854
|
+
"Observation interval start": "float64",
|
|
1855
|
+
"Observation interval stop": "float64",
|
|
1853
1856
|
# "Source": "string",
|
|
1854
1857
|
# "Time offset (s)": "string",
|
|
1855
1858
|
# "Coding duration": "float64",
|
|
@@ -1885,14 +1888,6 @@ def project2dataframe(pj: dict, observations_list: list = []) -> pd.DataFrame:
|
|
|
1885
1888
|
"Comment stop": "string",
|
|
1886
1889
|
}
|
|
1887
1890
|
|
|
1888
|
-
"""
|
|
1889
|
-
state_behaviors = [
|
|
1890
|
-
pj[cfg.ETHOGRAM][x][cfg.BEHAVIOR_CODE]
|
|
1891
|
-
for x in pj[cfg.ETHOGRAM]
|
|
1892
|
-
if pj[cfg.ETHOGRAM][x]["type"] in (cfg.STATE_EVENT, cfg.STATE_EVENT_WITH_CODING_MAP)
|
|
1893
|
-
]
|
|
1894
|
-
"""
|
|
1895
|
-
|
|
1896
1891
|
state_behaviors = util.state_behavior_codes(pj[cfg.ETHOGRAM])
|
|
1897
1892
|
|
|
1898
1893
|
for obs_id in pj[cfg.OBSERVATIONS]:
|
|
@@ -1904,9 +1899,21 @@ def project2dataframe(pj: dict, observations_list: list = []) -> pd.DataFrame:
|
|
|
1904
1899
|
if idx_event in stop_event_idx:
|
|
1905
1900
|
continue
|
|
1906
1901
|
data["Observation id"].append(obs_id)
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1902
|
+
data["Observation date"].append(pj["observations"][obs_id]["date"])
|
|
1903
|
+
data["Description"].append(" ".join(pj["observations"][obs_id]["description"].splitlines()))
|
|
1904
|
+
data["Observation type"].append(pj["observations"][obs_id]["type"])
|
|
1905
|
+
|
|
1906
|
+
data["Observation interval start"].append(
|
|
1907
|
+
pj["observations"][obs_id]["observation time interval"][0]
|
|
1908
|
+
if pj["observations"][obs_id]["observation time interval"][0]
|
|
1909
|
+
else None
|
|
1910
|
+
)
|
|
1911
|
+
data["Observation interval stop"].append(
|
|
1912
|
+
pj["observations"][obs_id]["observation time interval"][1]
|
|
1913
|
+
if pj["observations"][obs_id]["observation time interval"][1]
|
|
1914
|
+
else None
|
|
1915
|
+
)
|
|
1916
|
+
|
|
1910
1917
|
# data["Source"].append("")
|
|
1911
1918
|
# data["Time offset (s)"].append(pj["observations"][obs_id]["time offset"])
|
|
1912
1919
|
# data["Coding duration"].append("")
|
|
@@ -1932,7 +1939,7 @@ def project2dataframe(pj: dict, observations_list: list = []) -> pd.DataFrame:
|
|
|
1932
1939
|
data[modifier_set].append(np.nan)
|
|
1933
1940
|
|
|
1934
1941
|
data["Behavior type"].append(cfg.STATE_EVENT if event[2] in state_behaviors else cfg.POINT_EVENT)
|
|
1935
|
-
data["Start (s)"].append(event[0])
|
|
1942
|
+
data["Start (s)"].append(float(event[0]))
|
|
1936
1943
|
if event[2] in state_behaviors:
|
|
1937
1944
|
# search stop
|
|
1938
1945
|
# print(f"==> {idx_event=} {event[1:4]=}")
|
|
@@ -1941,8 +1948,8 @@ def project2dataframe(pj: dict, observations_list: list = []) -> pd.DataFrame:
|
|
|
1941
1948
|
if event2[1:4] == event[1:4]:
|
|
1942
1949
|
# print("found")
|
|
1943
1950
|
stop_event_idx.add(idx_event2)
|
|
1944
|
-
data["Stop (s)"].append(event2[0])
|
|
1945
|
-
data["Duration (s)"].append(event2[0] - event[0])
|
|
1951
|
+
data["Stop (s)"].append(float(event2[0]))
|
|
1952
|
+
data["Duration (s)"].append(float(event2[0] - event[0]))
|
|
1946
1953
|
data["Comment start"].append(event[4])
|
|
1947
1954
|
data["Comment stop"].append(event2[4])
|
|
1948
1955
|
break
|
|
@@ -1950,9 +1957,17 @@ def project2dataframe(pj: dict, observations_list: list = []) -> pd.DataFrame:
|
|
|
1950
1957
|
raise ("not paired")
|
|
1951
1958
|
|
|
1952
1959
|
else: # point
|
|
1953
|
-
data["Stop (s)"].append(event[0])
|
|
1960
|
+
data["Stop (s)"].append(float(event[0]))
|
|
1954
1961
|
data["Duration (s)"].append(np.nan)
|
|
1955
1962
|
data["Comment start"].append(event[4])
|
|
1956
1963
|
data["Comment stop"].append(event[4])
|
|
1957
1964
|
|
|
1965
|
+
# Set the display option to show all rows and columns
|
|
1966
|
+
pd.set_option("display.max_rows", None)
|
|
1967
|
+
pd.set_option("display.max_columns", None)
|
|
1968
|
+
|
|
1969
|
+
pd.DataFrame(data).info()
|
|
1970
|
+
|
|
1971
|
+
print(pd.DataFrame(data))
|
|
1972
|
+
|
|
1958
1973
|
return pd.DataFrame(data)
|
boris/select_subj_behav.py
CHANGED
|
@@ -123,6 +123,10 @@ def choose_obs_subj_behav_category(
|
|
|
123
123
|
paramPanelWindow.start_time.set_time(start_coding)
|
|
124
124
|
paramPanelWindow.end_time.set_time(end_coding)
|
|
125
125
|
|
|
126
|
+
# check observation time interval
|
|
127
|
+
if start_interval is None or start_interval.is_nan() or end_interval is None or end_interval.is_nan():
|
|
128
|
+
paramPanelWindow.rb_obs_interval.setEnabled(False)
|
|
129
|
+
|
|
126
130
|
if selected_observations:
|
|
127
131
|
observedSubjects = project_functions.extract_observed_subjects(self.pj, selected_observations)
|
|
128
132
|
else:
|
boris/synthetic_time_budget.py
CHANGED
|
@@ -71,8 +71,10 @@ def synthetic_time_budget(self) -> None:
|
|
|
71
71
|
selected_observations,
|
|
72
72
|
start_coding=start_coding,
|
|
73
73
|
end_coding=end_coding,
|
|
74
|
-
start_interval=start_interval,
|
|
75
|
-
end_interval=end_interval,
|
|
74
|
+
# start_interval=start_interval,
|
|
75
|
+
# end_interval=end_interval,
|
|
76
|
+
start_interval=None,
|
|
77
|
+
end_interval=None,
|
|
76
78
|
maxTime=max_media_duration_all_obs,
|
|
77
79
|
show_exclude_non_coded_behaviors=False,
|
|
78
80
|
by_category=False,
|
|
@@ -201,8 +203,10 @@ def synthetic_binned_time_budget(self) -> None:
|
|
|
201
203
|
selected_observations,
|
|
202
204
|
start_coding=start_coding,
|
|
203
205
|
end_coding=end_coding,
|
|
204
|
-
start_interval=start_interval,
|
|
205
|
-
end_interval=end_interval,
|
|
206
|
+
# start_interval=start_interval,
|
|
207
|
+
# end_interval=end_interval,
|
|
208
|
+
start_interval=None,
|
|
209
|
+
end_interval=None,
|
|
206
210
|
maxTime=max_media_duration_all_obs,
|
|
207
211
|
show_exclude_non_coded_behaviors=False,
|
|
208
212
|
by_category=False,
|
|
@@ -221,7 +225,7 @@ def synthetic_binned_time_budget(self) -> None:
|
|
|
221
225
|
# ask for excluding behaviors durations from total time
|
|
222
226
|
cancel_pressed, synth_tb_param[cfg.EXCLUDED_BEHAVIORS] = self.filter_behaviors(
|
|
223
227
|
title="Select behaviors to exclude",
|
|
224
|
-
text=("The duration of the selected behaviors will
|
|
228
|
+
text=("The duration of the selected behaviors will be subtracted from the total time"),
|
|
225
229
|
table="",
|
|
226
230
|
behavior_type=[cfg.STATE_EVENT],
|
|
227
231
|
)
|
boris/time_budget_widget.py
CHANGED
|
@@ -436,8 +436,10 @@ def time_budget(self, mode: str, mode2: str = "list"):
|
|
|
436
436
|
selected_observations,
|
|
437
437
|
start_coding=start_coding,
|
|
438
438
|
end_coding=end_coding,
|
|
439
|
-
start_interval=start_interval,
|
|
440
|
-
end_interval=end_interval,
|
|
439
|
+
# start_interval=start_interval,
|
|
440
|
+
# end_interval=end_interval,
|
|
441
|
+
start_interval=None,
|
|
442
|
+
end_interval=None,
|
|
441
443
|
maxTime=max_media_duration_all_obs,
|
|
442
444
|
by_category=(mode == "by_category"),
|
|
443
445
|
n_observations=len(selected_observations),
|
|
@@ -744,7 +746,7 @@ def time_budget(self, mode: str, mode2: str = "list"):
|
|
|
744
746
|
|
|
745
747
|
self.tb.twTB.resizeColumnsToContents()
|
|
746
748
|
|
|
747
|
-
gui_utilities.restore_geometry(self.tb, "time budget", (
|
|
749
|
+
gui_utilities.restore_geometry(self.tb, "time budget", (800, 600))
|
|
748
750
|
|
|
749
751
|
self.tb.show()
|
|
750
752
|
|
boris/version.py
CHANGED
|
@@ -3,9 +3,9 @@ boris/__main__.py,sha256=ANjTbXgXDoz2nB1tCtOIllfIVotCa602iebACX7rXaE,764
|
|
|
3
3
|
boris/about.py,sha256=KEUz6nryrg8FceVyFsf8sMz-xWd2cGwIUfuVydHxqC4,5366
|
|
4
4
|
boris/add_modifier.py,sha256=DWqxkKDBm21QH_kPvhpnltwLtFvPxne0VmZ1SY26hj8,26340
|
|
5
5
|
boris/add_modifier_ui.py,sha256=Y7TLO5uS6zW7zpjXmjA4V_VIp_bFDNtjOTbJ9Q6m-mQ,11601
|
|
6
|
-
boris/advanced_event_filtering.py,sha256=
|
|
6
|
+
boris/advanced_event_filtering.py,sha256=VlvU12mL6xYacZOvJAi5uLpHMcmAw5Pvuvmka-PN29c,15469
|
|
7
7
|
boris/behav_coding_map_creator.py,sha256=PSEYMLvOwt0HR7H4kQZl6dli3q89wezWMv-Ri3EZWWc,37443
|
|
8
|
-
boris/behavior_binary_table.py,sha256=
|
|
8
|
+
boris/behavior_binary_table.py,sha256=sr2Wb7NFd-NjfXCL5fqsc_Uf7rvS0p9RxZwVbaFBeig,12502
|
|
9
9
|
boris/behaviors_coding_map.py,sha256=Pat6U2JHxH8epWH42ZlwzZJ0Rmgl-BKQ5KARjp3GbNg,7291
|
|
10
10
|
boris/boris_cli.py,sha256=n0OiVvZM1gM6E7yKaff9wlgmpAGK4TK052VRi8AabJo,13196
|
|
11
11
|
boris/cmd_arguments.py,sha256=oWb-FvhKLbKJhATlTHy9muWu8XnnUfOZ-3Fmz2M8Yzc,1848
|
|
@@ -15,8 +15,8 @@ boris/config_file.py,sha256=1-2ZmTvKET57rwrLR1dXblt0AxMpGB1LAiHxu-Sy8es,13543
|
|
|
15
15
|
boris/connections.py,sha256=y_KkIj3WQQEepJASATHBpZaqwT-ERyFNovy2Q8e7FAA,19321
|
|
16
16
|
boris/converters.py,sha256=c1Jps-URoglY5ILQHz-pCCf6-4DFUHZLtqr_ofsrFg0,11722
|
|
17
17
|
boris/converters_ui.py,sha256=uu7LOBV_fKv2DBdOqsqPwjGsjgONr5ODBoscAA-EP48,9900
|
|
18
|
-
boris/cooccurence.py,sha256=
|
|
19
|
-
boris/core.py,sha256=
|
|
18
|
+
boris/cooccurence.py,sha256=tVERC-V8MWjWHlGEfDuu08iS94qjt4do-38jwI62QaY,10367
|
|
19
|
+
boris/core.py,sha256=3NbJcsngnDTaLuXPWblgidKqjzZhJTxzL8N69pwgtkI,234818
|
|
20
20
|
boris/core_qrc.py,sha256=T3ki5e2Pj0I0QBGz63MPUgZzl8F_VHZwSq074mRNBDU,650669
|
|
21
21
|
boris/core_ui.py,sha256=SeC26uveDCjrCBLsRPuQ6FaapKfON_HIRcQStEDLhl4,76384
|
|
22
22
|
boris/db_functions.py,sha256=Uw9wWH_Pe-qNzpV1k21YG_jKsoOmfY_iiK_7ARZHGDc,13352
|
|
@@ -29,11 +29,11 @@ boris/event_operations.py,sha256=ys1DxZ6iooMvvq_hzpPVZSW0dF9Trbx921XV3jeKOxw,382
|
|
|
29
29
|
boris/events_cursor.py,sha256=VPY_ygD0fxE5lp25mcd2l00XQXurCR6hprffF4tKRbU,2078
|
|
30
30
|
boris/events_snapshots.py,sha256=PjWzQvUGQtIcEc_7FDsRphf7fAhhTccQgYc2eQSA65g,27621
|
|
31
31
|
boris/exclusion_matrix.py,sha256=ff88xD6aqc8bpIuj9ZCz9ju_HeqqgibQwoaJrIOJ6RI,5272
|
|
32
|
-
boris/export_events.py,sha256=
|
|
32
|
+
boris/export_events.py,sha256=8h6AenIuXJj-JWlkSS0UR38mhjUjmFv3_5QOyBSpYec,39744
|
|
33
33
|
boris/export_observation.py,sha256=uPJH_5MXqGm4JSeaSlTikh1i6OKSyLIaZFzS9wp-9qk,50729
|
|
34
34
|
boris/external_processes.py,sha256=vpmhA4Lj2GblBIrDD0YjesB8HPOgx4K9gSWVhTop4Cg,11927
|
|
35
35
|
boris/geometric_measurement.py,sha256=4pI-AYpBSFlJBqS-f8dnkgLtj_Z2E5kwwAdh6WwZ4kk,35049
|
|
36
|
-
boris/gui_utilities.py,sha256=
|
|
36
|
+
boris/gui_utilities.py,sha256=5vjIWbUOHFbqKSti-kT0GoteBBEQ5fUYdNGdMxcg_0A,4607
|
|
37
37
|
boris/image_overlay.py,sha256=zZAL8MTt2i2s58CuX81Nym3rJ5pKiTeP4AO8WbIUonM,2527
|
|
38
38
|
boris/import_observations.py,sha256=hwEPIag741AXTFIuxDdZLDvLrsmvaqTkjyTjQu5M_RA,8798
|
|
39
39
|
boris/irr.py,sha256=o5QN3B2b-02AUkrklMJCitFGsfiUDtmI0MxUbPv2cBg,22472
|
|
@@ -47,11 +47,11 @@ boris/mpv-1.0.3.py,sha256=EXRtzQqFjOn4wMC6482Ilq3fNQ9N1GRP1VxwLzdeaBY,88077
|
|
|
47
47
|
boris/mpv.py,sha256=EfzIHjPbgewG4w3smEtqEUPZoVwYmMQkL4Q8ZyW-a58,76410
|
|
48
48
|
boris/mpv2.py,sha256=IUI4t4r9GYX7G5OXTjd3RhMMOkDdfal_15buBgksLsk,92152
|
|
49
49
|
boris/observation.py,sha256=oop08nflDLZAgDbIB8GOiVdTgLhppJ_ODH0Z24cyqvE,57176
|
|
50
|
-
boris/observation_operations.py,sha256=
|
|
50
|
+
boris/observation_operations.py,sha256=8rVC_iWb0Y8zkd64_XvDxD2e7_jsKdGfDSdyi4eDRAs,105643
|
|
51
51
|
boris/observation_ui.py,sha256=DAnU94QBNvkLuHT6AxTwqSk_D_n6VUhSl8PexZv_dUk,33309
|
|
52
52
|
boris/observations_list.py,sha256=NqwECGHtHYmKhSe-qCfqPmJ24SSfzlXvIXS2i3op_zE,10591
|
|
53
53
|
boris/otx_parser.py,sha256=70QvilzFHXbjAHR88YH0aEXJ3xxheLS5fZGgHFHGpNE,16367
|
|
54
|
-
boris/param_panel.py,sha256=
|
|
54
|
+
boris/param_panel.py,sha256=G0XzNmJIX89-n2OQTDccuY_wWMhr3p7GB4ZorbU6EWc,8786
|
|
55
55
|
boris/param_panel_ui.py,sha256=4emQDFmuL4_R7bKxosLjdUb-VSPWkDm7suy38F5EKcA,13260
|
|
56
56
|
boris/player_dock_widget.py,sha256=VBuuGoAb2D027oFnMBlIQPiSQcEdedhoQltNFSJq8mw,5982
|
|
57
57
|
boris/plot_data_module.py,sha256=6QbLKfyGp4TYRyHnB9G45y5XrpeXLytcorltEAWfYak,16562
|
|
@@ -59,26 +59,26 @@ boris/plot_events.py,sha256=hA_Yt-ZaxbAOKjN7gYHiaEx5TPR-7HIWGJXXg4cq6lw,24048
|
|
|
59
59
|
boris/plot_events_rt.py,sha256=xig__Uea3mQqO5raMBVB3pm3vuQkjAbJpwSS7AwIob8,8327
|
|
60
60
|
boris/plot_spectrogram_rt.py,sha256=JV8N7T8133wGVhlPxmgOb426u1g1p21-LbTqgaeddkk,8361
|
|
61
61
|
boris/plot_waveform_rt.py,sha256=05JN_6HCq674ROore_6PNw93GQNZJQDlDxp2ODAFkkA,7474
|
|
62
|
-
boris/plugins.py,sha256=
|
|
62
|
+
boris/plugins.py,sha256=RtC_Ew6VxAwWQqRuKQj9FgpsSBGoZmZuCZ5gPj0EiwI,8963
|
|
63
63
|
boris/preferences.py,sha256=qPfd9Tyg7u30kXwVqMOgkdy2RXri9bItRa5U2-ZVQmg,16847
|
|
64
64
|
boris/preferences_ui.py,sha256=D2bFLb3E0m6IwSeqKoItRDiqvPmJGoeXLHF2K02n1Zo,26293
|
|
65
65
|
boris/project.py,sha256=hAeAb5pD0u_l0bezU9ePvbTOYQKfxrFGvYB2NAqSDHg,84377
|
|
66
|
-
boris/project_functions.py,sha256=
|
|
66
|
+
boris/project_functions.py,sha256=p_CC2UoFEbb0PpKt9c5MtJulSszz-fV1o1sgFRFVQEk,79920
|
|
67
67
|
boris/project_import_export.py,sha256=1FdsYFzZ_jrhPRaH7xEkcPnh-hQXN4HFz1PhsIsSoL8,38361
|
|
68
68
|
boris/project_ui.py,sha256=yB-ewhHt8S8DTTRIk-dNK2tPMNU24lNji9fDW_Xazu8,38805
|
|
69
69
|
boris/qrc_boris.py,sha256=aH-qUirYY1CGxmTK1SFCPvuZfazIHX4DdUKF1gxZeYM,675008
|
|
70
70
|
boris/qrc_boris5.py,sha256=prnOw7VGXWXRuVCYp_yIrmWhrlG1F9rx-3BQvkPenjY,161608
|
|
71
71
|
boris/select_modifiers.py,sha256=42uG9F75pfPoPJ-blp-vFgmpBpVJtL42FlIxpNpq9z4,13319
|
|
72
72
|
boris/select_observations.py,sha256=HM0suMes1YxVwQ-Xakw7ROaxbN0EyeSiZFZNrTQIHAA,7886
|
|
73
|
-
boris/select_subj_behav.py,sha256=
|
|
73
|
+
boris/select_subj_behav.py,sha256=ulXbsRY-AIyQRSwXhVlvkNRS_eqWaCvkDKTTyOLqvoE,11742
|
|
74
74
|
boris/state_events.py,sha256=R5CcT_cldnxqhQkvX_V1AMNxH0Nc6jLzMZYiWkeJwAE,7770
|
|
75
75
|
boris/subjects_pad.py,sha256=lSRRGfLfD10_YpGua8RGVdKhoXlsXawGhNibPkRhuzM,3541
|
|
76
|
-
boris/synthetic_time_budget.py,sha256=
|
|
76
|
+
boris/synthetic_time_budget.py,sha256=sj-5jq7MH-bxPUwKwpi7Xud-jkKTs6PUFlN_01vgimE,10481
|
|
77
77
|
boris/time_budget_functions.py,sha256=1-7_G84SDs7rp1EWr5zHInzRVDUkUdIfm_AX0516ceQ,52539
|
|
78
|
-
boris/time_budget_widget.py,sha256=
|
|
78
|
+
boris/time_budget_widget.py,sha256=H_HQHTuMq7U6PlGjJ-pZO4dDaOrYSsAKK697Gb6EQoI,43201
|
|
79
79
|
boris/transitions.py,sha256=_aZJfJWv3EBrtmQ7qsdTCayQo6uWU7BXqtQQgflEhr4,12250
|
|
80
80
|
boris/utilities.py,sha256=zwWpH-lozAUj_8K6Gf2Hl-BSW0aRdWo37HGXTWQ86qk,52782
|
|
81
|
-
boris/version.py,sha256=
|
|
81
|
+
boris/version.py,sha256=_3fXAvcL2OmwfUOC38JcxwXIb6rqJr_VIPrGA2HMk1k,787
|
|
82
82
|
boris/video_equalizer.py,sha256=FartoGghFK-T53zklP70rPKYqTuzL8qdvfGlsOF2wwc,5854
|
|
83
83
|
boris/video_equalizer_ui.py,sha256=1CG3s79eM4JAbaCx3i1ILZXLceb41_gGXlOLNfpBgnw,10142
|
|
84
84
|
boris/video_operations.py,sha256=mh3iR__Sm2KnV44L_sW2pOo3AgLwlM7wiTnnqQiAVs4,9381
|
|
@@ -86,18 +86,18 @@ boris/view_df.py,sha256=AKScLASX2Uatw7rqPbsnio83eVT4GZYCFhL091eMvlY,3370
|
|
|
86
86
|
boris/view_df_ui.py,sha256=CaMeRH_vQ00CTDDFQn73ZZaS-r8BSTWpL-dMCFqzJ_Q,2775
|
|
87
87
|
boris/write_event.py,sha256=jKZWzvDvQ-wwFvTLjA-zUjtXQCWwVC49Y5g-1UctpYw,23821
|
|
88
88
|
boris/analysis_plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
89
|
-
boris/analysis_plugins/number_of_occurences.py,sha256=
|
|
90
|
-
boris/analysis_plugins/number_of_occurences_by_independent_variable.py,sha256=
|
|
91
|
-
boris/analysis_plugins/time_budget.py,sha256=
|
|
89
|
+
boris/analysis_plugins/number_of_occurences.py,sha256=IDyDrdezqvSKT3BlD8QWpSYk8X9nnBBLI80OUnFJ3bY,509
|
|
90
|
+
boris/analysis_plugins/number_of_occurences_by_independent_variable.py,sha256=t39bmmmZIDCSbcDvVeiKAhKNNP2SdpHp417JczHEnP4,793
|
|
91
|
+
boris/analysis_plugins/time_budget.py,sha256=C1wNYwd5Jugr8h5z2aXRUBY8dF8pD4n953dPwNHY5VY,2244
|
|
92
92
|
boris/portion/__init__.py,sha256=ZBUG4I7YWhRkeWdP-JEpxhxldJlUYQkeaJseTjdhtJE,602
|
|
93
93
|
boris/portion/const.py,sha256=hEp26BKcEg1Js4DfZsBHmDtJJts83Tl1HWQ0CNJNwEc,1588
|
|
94
94
|
boris/portion/dict.py,sha256=SyHxc7PfDw2ufNLFQycwJtzmRfL48rDp4UrM2KN7IWc,11282
|
|
95
95
|
boris/portion/func.py,sha256=3TkQtFKLfsqntwd27HSGHceFhnXHmT-EbNMqktElC5Q,2174
|
|
96
96
|
boris/portion/interval.py,sha256=bAdUiJjGeUAPgsBAImwNeviiwfQq5odfhFZccAWzOTA,20299
|
|
97
97
|
boris/portion/io.py,sha256=ppNeRpiLNrocF1yzGeuEUIhYMf2LfsR-cji3d0nmvUs,6371
|
|
98
|
-
boris_behav_obs-9.
|
|
99
|
-
boris_behav_obs-9.
|
|
100
|
-
boris_behav_obs-9.
|
|
101
|
-
boris_behav_obs-9.
|
|
102
|
-
boris_behav_obs-9.
|
|
103
|
-
boris_behav_obs-9.
|
|
98
|
+
boris_behav_obs-9.2.1.dist-info/LICENSE.TXT,sha256=WJ7YI-moTFb-uVrFjnzzhGJrnL9P2iqQe8NuED3hutI,35141
|
|
99
|
+
boris_behav_obs-9.2.1.dist-info/METADATA,sha256=6dLb1vMMq5FHHeDTBpefrr6TIQjgg1pz_VoSMKqA_GE,42102
|
|
100
|
+
boris_behav_obs-9.2.1.dist-info/WHEEL,sha256=Kol19cahXavY536r5Aj6aAgK_6CmctrOu3bgNJMSNJA,109
|
|
101
|
+
boris_behav_obs-9.2.1.dist-info/entry_points.txt,sha256=-Vl37ZFjZYK5wTSDf5LAzd2cVLON1Pfy1xkx490Wxak,47
|
|
102
|
+
boris_behav_obs-9.2.1.dist-info/top_level.txt,sha256=fJSgm62S7WesiwTorGbOO4nNN0yzgZ3klgfGi3Px4qI,6
|
|
103
|
+
boris_behav_obs-9.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|