Skip to content

Commit

Permalink
improved synthetic time budget and plot events
Browse files Browse the repository at this point in the history
  • Loading branch information
olivierfriard committed Mar 26, 2018
1 parent 689e7c1 commit c8f71cb
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 92 deletions.
45 changes: 23 additions & 22 deletions boris.py
Expand Up @@ -735,17 +735,22 @@ def connections(self):
self.actionTime_budget.triggered.connect(lambda: self.time_budget("by_behavior"))
self.actionTime_budget_by_behaviors_category.triggered.connect(lambda: self.time_budget("by_category"))
#self.actionTime_budget_report.triggered.connect(lambda: self.time_budget("synthetic"))

self.actionTime_budget_report.triggered.connect(self.synthetic_time_budget)


#self.actionTest_stb2.triggered.connect(self.synthetic_time_budget)
self.actionTest_stb2.setVisible(False)

self.actionBehavior_bar_plot.triggered.connect(self.behaviors_bar_plot)
#self.actionBehavior_bar_plot.setVisible(False)
#self.actionBehavior_bar_plot.triggered.connect(self.behaviors_bar_plot)
self.actionBehavior_bar_plot.setVisible(False)

self.actionPlot_events1.triggered.connect(self.plot_events1_triggered)
self.actionPlot_events2.triggered.connect(self.plot_events2_triggered)
#self.actionPlot_events1.triggered.connect(self.plot_events1_triggered)
self.actionPlot_events1.setVisible(False)
self.actionPlot_events2.triggered.connect(self.plot_events2_new_triggered)

self.actionTest.triggered.connect(self.plot_events2_new_triggered)
#self.actionTest.triggered.connect(self.plot_events2_new_triggered)
self.actionTest.setVisible(False)


# menu Help
Expand Down Expand Up @@ -3643,7 +3648,7 @@ def selectObservations(self, mode):
mode: accepted values: OPEN, EDIT, SINGLE, MULTIPLE, SELECT1
"""
resultStr, selectedObs = select_observations.select_observations(self.pj, mode)

return resultStr, selectedObs


Expand Down Expand Up @@ -4753,7 +4758,8 @@ def choose_obs_subj_behav_category(self,
for behavior in [self.pj[ETHOGRAM][x]["code"] for x in sorted_keys(self.pj[ETHOGRAM])]:

if ((categories == ["###no category###"])
or (behavior in [self.pj[ETHOGRAM][x]["code"] for x in self.pj[ETHOGRAM] if "category" in self.pj[ETHOGRAM][x] and self.pj[ETHOGRAM][x]["category"] == category])):
or (behavior in [self.pj[ETHOGRAM][x][BEHAVIOR_CODE] for x in self.pj[ETHOGRAM]
if "category" in self.pj[ETHOGRAM][x] and self.pj[ETHOGRAM][x]["category"] == category])):

paramPanelWindow.item = QListWidgetItem(behavior)
if behavior in observedBehaviors:
Expand Down Expand Up @@ -4788,7 +4794,8 @@ def choose_obs_subj_behav_category(self,
startTime = Decimal(paramPanelWindow.dsbStartTime.value())
endTime = Decimal(paramPanelWindow.dsbEndTime.value())
if startTime > endTime:
QMessageBox.warning(None, programName, "The start time is after the end time", QMessageBox.Ok | QMessageBox.Default, QMessageBox.NoButton)
QMessageBox.warning(None, programName, "The start time is after the end time",
QMessageBox.Ok | QMessageBox.Default, QMessageBox.NoButton)
return {"selected subjects": [], "selected behaviors": []}

if paramPanelWindow.rb_full.isChecked():
Expand Down Expand Up @@ -4896,14 +4903,12 @@ def synthetic_time_budget(self):
if pathlib.Path(file_name).suffix != "." + output_format:
file_name = str(pathlib.Path(file_name)) + "." + output_format


'''synth_tb_param["group observations"] = True'''

ok, msg, data_report = time_budget_functions.synthetic_time_budget(self.pj,
selected_observations,
synth_tb_param["selected subjects"],
synth_tb_param["selected behaviors"],
synth_tb_param["include modifiers"],
synth_tb_param["time"],
synth_tb_param["start time"],
synth_tb_param["end time"]
synth_tb_param
)

if not ok:
Expand Down Expand Up @@ -5926,6 +5931,7 @@ def plot_events2_new_triggered(self):
plot events in time diagram
"""
result, selected_observations = self.selectObservations(MULTIPLE)

if not selected_observations:
return
# check if state events are paired
Expand Down Expand Up @@ -6011,7 +6017,7 @@ def plot_events2_new_triggered(self):

parameters = self.choose_obs_subj_behav_category(selected_observations,
maxTime=max_obs_length,
flagShowExcludeBehaviorsWoEvents=False,
flagShowExcludeBehaviorsWoEvents=True,
by_category=False)

if not parameters["selected subjects"] or not parameters["selected behaviors"]:
Expand All @@ -6020,12 +6026,7 @@ def plot_events2_new_triggered(self):

plot_events.create_events_plot2_new(self.pj,
selected_observations,
parameters["selected subjects"],
parameters["selected behaviors"],
parameters["include modifiers"],
parameters["time"],
parameters["start time"],
parameters["end time"],
parameters,
plot_colors=self.plot_colors,
plot_directory=plot_directory,
file_format=file_format)
Expand Down
6 changes: 6 additions & 0 deletions boris.ui
Expand Up @@ -211,6 +211,7 @@
<addaction name="actionTime_budget_by_behaviors_category"/>
<addaction name="menuPlot_events"/>
<addaction name="menuInter_rater_reliability"/>
<addaction name="actionTest_stb2"/>
</widget>
<widget class="QMenu" name="menuPlayback">
<property name="title">
Expand Down Expand Up @@ -1198,6 +1199,11 @@
<string>test</string>
</property>
</action>
<action name="actionTest_stb2">
<property name="text">
<string>test stb2</string>
</property>
</action>
</widget>
<resources/>
<connections/>
Expand Down
31 changes: 20 additions & 11 deletions boris_cli.py
Expand Up @@ -43,6 +43,9 @@ def cleanhtml(raw_html):
cleantext = re.sub(cleanr, "", raw_html)
return cleantext

def all_observations(pj):
return [idx for idx in sorted(pj[OBSERVATIONS])]

commands_list = ["check_state_events", "export_events", "irr", "subtitles", "check_project_integrity", "plot_events"]
commands_usage = {

Expand All @@ -69,10 +72,11 @@ def cleanhtml(raw_html):

"check_project_integrity": "usage:\nboris_cli -p PROJECT_FILE --command check_project_integrity",

"plot_events": ("usage:\nboris_cli - p PROJECT_FILE -o OBSERVATION_ID --command plot_events [OUTPUT_DIRECTORY] [INCLUDE_MODIFIERS] [PLOT_FORMAT]\n"
"plot_events": ("usage:\nboris_cli - p PROJECT_FILE -o OBSERVATION_ID --command plot_events [OUTPUT_DIRECTORY] [INCLUDE_MODIFIERS] [EXCLUDE_BEHAVIORS] [PLOT_FORMAT]\n"
"where\n"
"OUTPUT_DIRECTORY is the directory where the plots will be saved\n"
"INCLUDE_MODIFIERS must be true or false (default is true)\n"
"EXCLUDE_BEHAVIORS: True: behaviors without events are not plotted (default is true)\n"
"PLOT_FORMAT can be png, svg, pdf, ps")
}

Expand Down Expand Up @@ -190,7 +194,7 @@ def cleanhtml(raw_html):

if not observations_id_list:
print("No observation selected. Command applied on all observations found in project\n")
observations_id_list = [idx for idx in pj[OBSERVATIONS]]
observations_id_list = all_observations(pj)

for observation_id in observations_id_list:
ret, msg = project_functions.check_state_events_obs(observation_id, pj[ETHOGRAM], pj[OBSERVATIONS][observation_id], HHMMSS)
Expand Down Expand Up @@ -268,7 +272,7 @@ def cleanhtml(raw_html):

if not observations_id_list:
print("No observation selected. Command applied on all observations found in project\n")
observations_id_list = [idx for idx in pj[OBSERVATIONS]]
observations_id_list = all_observations(pj)

behaviors = [pj[ETHOGRAM][k]["code"] for k in utilities.sorted_keys(pj[ETHOGRAM])]
subjects = [pj[SUBJECTS][k]["name"] for k in utilities.sorted_keys(pj[SUBJECTS])] + [NO_FOCAL_SUBJECT]
Expand Down Expand Up @@ -303,7 +307,7 @@ def cleanhtml(raw_html):

if not observations_id_list:
print("No observation selected. Command applied on all observations found in project\n")
observations_id_list = [idx for idx in pj[OBSERVATIONS]]
observations_id_list = all_observations(pj)

behaviors = [pj[ETHOGRAM][k]["code"] for k in utilities.sorted_keys(pj[ETHOGRAM])]
subjects = [pj[SUBJECTS][k]["name"] for k in utilities.sorted_keys(pj[SUBJECTS])] + [NO_FOCAL_SUBJECT]
Expand All @@ -319,18 +323,23 @@ def cleanhtml(raw_html):
if len(args.command) > 2:
include_modifiers = "TRUE" in args.command[2].upper()

plot_format = "png"
exclude_behaviors = True
if len(args.command) > 3:
plot_format = args.command[3].lower()
exclude_behaviors = False if "FALSE" in args.command[3].upper() else True

plot_format = "png"
if len(args.command) > 4:
plot_format = args.command[4].lower()


plot_events.create_events_plot2_new(pj,
observations_id_list,
subjects,
behaviors,
True,
TIME_FULL_OBS,
0, 0,
{"selected subjects": subjects,
"selected behaviors": behaviors,
"include modifiers": include_modifiers,
"exclude behaviors": exclude_behaviors,
"time": TIME_FULL_OBS,
"start time": 0, "end time": 0},
plot_colors=BEHAVIORS_PLOT_COLORS,
plot_directory=export_dir,
file_format=plot_format)
Expand Down
4 changes: 4 additions & 0 deletions boris_ui.py
Expand Up @@ -449,6 +449,8 @@ def setupUi(self, MainWindow):
self.action_obs_list.setObjectName(_fromUtf8("action_obs_list"))
self.actionTest = QtGui.QAction(MainWindow)
self.actionTest.setObjectName(_fromUtf8("actionTest"))
self.actionTest_stb2 = QtGui.QAction(MainWindow)
self.actionTest_stb2.setObjectName(_fromUtf8("actionTest_stb2"))
self.menuHelp.addAction(self.actionUser_guide)
self.menuHelp.addAction(self.actionCheckUpdate)
self.menuHelp.addSeparator()
Expand Down Expand Up @@ -514,6 +516,7 @@ def setupUi(self, MainWindow):
self.menuAnalyze.addAction(self.actionTime_budget_by_behaviors_category)
self.menuAnalyze.addAction(self.menuPlot_events.menuAction())
self.menuAnalyze.addAction(self.menuInter_rater_reliability.menuAction())
self.menuAnalyze.addAction(self.actionTest_stb2)
self.menuZoom1.addAction(self.actionZoom1_fitwindow)
self.menuZoom1.addAction(self.actionZoom1_1_4)
self.menuZoom1.addAction(self.actionZoom1_1_2)
Expand Down Expand Up @@ -755,4 +758,5 @@ def retranslateUi(self, MainWindow):
self.action_obs_list.setText(_translate("MainWindow", "Obs list", None))
self.action_obs_list.setToolTip(_translate("MainWindow", "Observations list", None))
self.actionTest.setText(_translate("MainWindow", "test", None))
self.actionTest_stb2.setText(_translate("MainWindow", "test stb2", None))

4 changes: 4 additions & 0 deletions boris_ui5.py
Expand Up @@ -435,6 +435,8 @@ def setupUi(self, MainWindow):
self.action_obs_list.setObjectName("action_obs_list")
self.actionTest = QtWidgets.QAction(MainWindow)
self.actionTest.setObjectName("actionTest")
self.actionTest_stb2 = QtWidgets.QAction(MainWindow)
self.actionTest_stb2.setObjectName("actionTest_stb2")
self.menuHelp.addAction(self.actionUser_guide)
self.menuHelp.addAction(self.actionCheckUpdate)
self.menuHelp.addSeparator()
Expand Down Expand Up @@ -500,6 +502,7 @@ def setupUi(self, MainWindow):
self.menuAnalyze.addAction(self.actionTime_budget_by_behaviors_category)
self.menuAnalyze.addAction(self.menuPlot_events.menuAction())
self.menuAnalyze.addAction(self.menuInter_rater_reliability.menuAction())
self.menuAnalyze.addAction(self.actionTest_stb2)
self.menuZoom1.addAction(self.actionZoom1_fitwindow)
self.menuZoom1.addAction(self.actionZoom1_1_4)
self.menuZoom1.addAction(self.actionZoom1_1_2)
Expand Down Expand Up @@ -742,4 +745,5 @@ def retranslateUi(self, MainWindow):
self.action_obs_list.setText(_translate("MainWindow", "Obs list"))
self.action_obs_list.setToolTip(_translate("MainWindow", "Observations list"))
self.actionTest.setText(_translate("MainWindow", "test"))
self.actionTest_stb2.setText(_translate("MainWindow", "test stb2"))

37 changes: 26 additions & 11 deletions db_functions.py
Expand Up @@ -26,6 +26,8 @@
from config import *
import project_functions

import time


def load_events_in_db(pj, selectedSubjects, selectedObservations, selectedBehaviors):
"""
Expand Down Expand Up @@ -65,6 +67,10 @@ def load_events_in_db(pj, selectedSubjects, selectedObservations, selectedBehavi
modifiers TEXT,
occurence FLOAT,
comment TEXT)""")
cursor.execute("CREATE INDEX observation_idx ON events(observation)")
cursor.execute("CREATE INDEX subject_idx ON events(subject)")
cursor.execute("CREATE INDEX code_idx ON events(code)")
cursor.execute("CREATE INDEX modifiers_idx ON events(modifiers)")

for subject_to_analyze in selectedSubjects:

Expand Down Expand Up @@ -121,7 +127,7 @@ def load_aggregated_events_in_db(pj, selectedSubjects, selectedObservations, sel

# if no behavior selected select all
if not selectedBehaviors:
selectedBehaviors = sorted([pj[ETHOGRAM][x]["code"] for x in pj[ETHOGRAM]])
selectedBehaviors = sorted([pj[ETHOGRAM][x][BEHAVIOR_CODE] for x in pj[ETHOGRAM]])

# check if state events are paired
out = ""
Expand All @@ -135,16 +141,14 @@ def load_aggregated_events_in_db(pj, selectedSubjects, selectedObservations, sel
return False, out, None

# selected behaviors defined as state event
state_behaviors_codes = [pj[ETHOGRAM][x]["code"] for x in pj[ETHOGRAM]
state_behaviors_codes = [pj[ETHOGRAM][x][BEHAVIOR_CODE] for x in pj[ETHOGRAM]
if STATE in pj[ETHOGRAM][x][TYPE].upper()
and pj[ETHOGRAM][x]["code"] in selectedBehaviors]
and pj[ETHOGRAM][x][BEHAVIOR_CODE] in selectedBehaviors]

# selected behaviors defined as point event
point_behaviors_codes = [pj[ETHOGRAM][x]["code"] for x in pj[ETHOGRAM]
point_behaviors_codes = [pj[ETHOGRAM][x][BEHAVIOR_CODE] for x in pj[ETHOGRAM]
if POINT in pj[ETHOGRAM][x][TYPE].upper()
and pj[ETHOGRAM][x]["code"] in selectedBehaviors]

cursor1 = load_events_in_db(pj, selectedSubjects, selectedObservations, selectedBehaviors)
and pj[ETHOGRAM][x][BEHAVIOR_CODE] in selectedBehaviors]

db = sqlite3.connect(":memory:")
db.row_factory = sqlite3.Row
Expand All @@ -161,25 +165,34 @@ def load_aggregated_events_in_db(pj, selectedSubjects, selectedObservations, sel
comment TEXT,
comment_stop TEXT)""")


cursor2.execute("CREATE INDEX observation_idx ON aggregated_events(observation)")
cursor2.execute("CREATE INDEX subject_idx ON aggregated_events(subject)")
cursor2.execute("CREATE INDEX behavior_idx ON aggregated_events(behavior)")
cursor2.execute("CREATE INDEX modifiers_idx ON aggregated_events(modifiers)")


for obsId in selectedObservations:

cursor1 = load_events_in_db(pj, selectedSubjects, [obsId], selectedBehaviors)

for subject in selectedSubjects:
for behavior in selectedBehaviors:

cursor1.execute("select distinct modifiers from events where observation=? AND subject=? AND code=? order by modifiers",
cursor1.execute("SELECT DISTINCT modifiers FROM events WHERE observation=? AND subject=? AND code=? ORDER BY modifiers",
(obsId, subject, behavior,))
rows_distinct_modifiers = list(x[0].strip() for x in cursor1.fetchall())

for distinct_modifiers in rows_distinct_modifiers:

cursor1.execute(("SELECT occurence, comment FROM events "
"WHERE observation = ? AND subject = ? AND code = ? AND modifiers = ? ORDER by occurence"),
(obsId, subject, behavior, distinct_modifiers))
rows = list(cursor1.fetchall())

for idx, row in enumerate(rows):

if behavior in point_behaviors_codes:

cursor2.execute(("INSERT INTO aggregated_events (observation, subject, behavior, type, modifiers, "
" start, stop, comment, comment_stop) "
"VALUES (?,?,?,?,?,?,?,?,?)"),
Expand All @@ -194,7 +207,9 @@ def load_aggregated_events_in_db(pj, selectedSubjects, selectedObservations, sel
(obsId, subject, behavior, STATE, distinct_modifiers,
row["occurence"], rows[idx + 1]["occurence"], row["comment"], rows[idx + 1]["comment"]))


db.commit()

return True, "", db


Expand Down

0 comments on commit c8f71cb

Please sign in to comment.