From a963da0948b22ae2eb284e13cd77400c893a653b Mon Sep 17 00:00:00 2001 From: Olivier Friard Date: Thu, 25 Jan 2018 16:23:09 +0100 Subject: [PATCH] added db_functions --- README.TXT | 2 +- boris.py | 65 +++++++++++++++------- db_functions.py | 119 ++++++++++++++++++++++++++++++++++++++++ dialog.py | 2 +- edit_event.py | 8 ++- edit_event.ui | 3 + edit_event_ui.py | 4 +- edit_event_ui5.py | 3 +- irr.py | 97 ++++++++++++++++++++++---------- map_creator.py | 2 +- modifiers_coding_map.py | 2 +- observations_list.py | 2 +- param_panel.py | 2 +- plot_events.py | 2 +- preferences.py | 2 +- project_functions.py | 2 +- recode_widget.py | 2 +- select_modifiers.py | 2 +- subjects_pad.py | 2 +- time_budget_widget.py | 2 +- transitions.py | 2 +- utilities.py | 57 +++++++++++++------ 22 files changed, 298 insertions(+), 86 deletions(-) create mode 100644 db_functions.py diff --git a/README.TXT b/README.TXT index fcbb6443..02f6f231 100644 --- a/README.TXT +++ b/README.TXT @@ -1,7 +1,7 @@ BORIS Behavioral Observation Research Interactive Software -Copyright 2012-2017 Olivier Friard +Copyright 2012-2018 Olivier Friard BORIS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/boris.py b/boris.py index d111f3f7..06479a0f 100644 --- a/boris.py +++ b/boris.py @@ -969,6 +969,7 @@ def irr_cohen_kappa(self): #paramPanelWindow.item.setCheckState(Qt.Unchecked) #paramPanelWindow.lwSubjects.addItem(paramPanelWindow.item) + paramPanelWindow.resize(500, 400) if paramPanelWindow.exec_(): selected_subjects = paramPanelWindow.selectedSubjects include_modifiers = paramPanelWindow.cbIncludeModifiers.isChecked() @@ -1000,6 +1001,11 @@ def irr_cohen_kappa(self): if "STATE" in self.pj[ETHOGRAM][x][TYPE].upper() and self.pj[ETHOGRAM][x]["code"] in observed_codes] + point_behaviors_codes = [self.pj[ETHOGRAM][x]["code"] for x in self.pj[ETHOGRAM] + if "POINT" in self.pj[ETHOGRAM][x][TYPE].upper() + and self.pj[ETHOGRAM][x]["code"] in observed_codes] + + if not state_behaviors_codes: QMessageBox.warning(self, programName, "No state event behaviors") return @@ -1023,6 +1029,7 @@ def irr_cohen_kappa(self): self.pj[OBSERVATIONS][obsid2][EVENTS], interval, state_behaviors_codes, + point_behaviors_codes, selected_subjects, include_modifiers) @@ -1962,7 +1969,18 @@ def edit_observation(self): def check_state_events_obs(self, obsId): - + """ + check state events + if no current observation check all observations + check if number is odd + + Args: + obsId (str): id of observation to check + + Returns: + set (bool, str): True/False, message + """ + # check if behaviors are defined as "state event" event_types = {self.pj[ETHOGRAM][idx]["type"] for idx in self.pj[ETHOGRAM]} @@ -1981,15 +1999,17 @@ def check_state_events_obs(self, obsId): for behavior in sorted(set(behaviors)): if behavior not in ethogram_behaviors: - return (False, "The behaviour {} does not exist more in the ethogram.
".format(behavior)) + return (False, "The behaviour {} not found in the ethogram.
".format(behavior)) else: - if "STATE" in self.eventType(behavior).upper(): + if STATE in self.eventType(behavior).upper(): flagStateEvent = True lst, memTime = [], {} for event in [event for event in self.pj[OBSERVATIONS][obsId][EVENTS] if event[EVENT_BEHAVIOR_FIELD_IDX] == behavior and event[EVENT_SUBJECT_FIELD_IDX] == subject]: + behav_modif = [event[EVENT_BEHAVIOR_FIELD_IDX], event[EVENT_MODIFIER_FIELD_IDX]] + if behav_modif in lst: lst.remove(behav_modif) del memTime[str(behav_modif)] @@ -1998,7 +2018,7 @@ def check_state_events_obs(self, obsId): memTime[str(behav_modif)] = event[EVENT_TIME_FIELD_IDX] for event in lst: - out += ("""The behavior {behavior} {modifier}is not PAIRED for subject""" + out += ("""The behavior {behavior} {modifier} is not PAIRED for subject""" """ "{subject}" at {time}
""").format( behavior=behavior, modifier=("(modifier "+ event[1] + ") ") if event[1] else "", @@ -2010,9 +2030,11 @@ def check_state_events_obs(self, obsId): def check_state_events(self, mode="all"): """ - check state events for each subject in current observation - if no current observation check all observations - check if number is odd + check state events for each subject + use check_state_events_obs function + + Args: + mode (str): current: check current observation / all: ask user to select observations """ tot_out = "" @@ -4633,19 +4655,25 @@ def eventType(self, code): def loadEventsInDB(self, selectedSubjects, selectedObservations, selectedBehaviors): """ - populate the db databse with events from selectedObservations, selectedSubjects and selectedBehaviors - selectedObservations: list - selectedSubjects: list - selectedBehaviors: list + populate an memory sqlite database with events from selectedObservations, selectedSubjects and selectedBehaviors + + Args: + selectedObservations (list): + selectedSubjects (list): + selectedBehaviors (list): + + Returns: + database cursor: + """ db = sqlite3.connect(":memory:") - + ''' if os.path.isfile("/tmp/boris_debug.sqlite"): os.system("rm /tmp/boris_debug.sqlite") db = sqlite3.connect("/tmp/boris_debug.sqlite") ''' - + db.row_factory = sqlite3.Row cursor = db.cursor() cursor.execute("""CREATE TABLE events (observation TEXT, @@ -7546,12 +7574,10 @@ def export_aggregated_events(self): if "media_info" in self.pj[OBSERVATIONS][obsId]: duration1.append(self.pj[OBSERVATIONS][obsId]["media_info"]["length"][mediaFile]) else: - #if "media_file_info" in - print("no media_info tag") + logging.info("no media_info tag for {} in observation {}" .format(mediaFile, obsId)) except: - print("error") - pass - + logging.critical(sys.exc_info()[1]) + QMessageBox.critical(None, programName, str(sys.exc_info()[1]), QMessageBox.Ok | QMessageBox.Default, QMessageBox.NoButton) total_length = "{0:.3f}".format(self.observationTotalMediaLength(obsId)) logging.debug("media length for {0}: {1}".format(obsId, total_length)) @@ -8685,7 +8711,7 @@ def actionAbout_activated(self): about_dialog.setEscapeButton(QMessageBox.Ok) about_dialog.setInformativeText(("{prog_name} {ver} - {date}" - "

Copyright © 2012-2017 Olivier Friard - Marco Gamba
" + "

Copyright © 2012-2018 Olivier Friard - Marco Gamba
" "Department of Life Sciences and Systems Biology
" "University of Torino - Italy
" "
" @@ -11050,6 +11076,7 @@ def changedFocusSlot(self, old, now): print(window.check_state_events_obs(observation_to_open)[1]) sys.exit() + if observation_to_open: r = window.load_observation(observation_to_open) if r: diff --git a/db_functions.py b/db_functions.py new file mode 100644 index 00000000..44b3a855 --- /dev/null +++ b/db_functions.py @@ -0,0 +1,119 @@ + +def loadEventsInDB(self, selectedSubjects, selectedObservations, selectedBehaviors): + + cursor = self.loadEventsInDB(plot_parameters["selected subjects"], selectedObservations, plot_parameters["selected behaviors"]) + + for subject in plot_parameters["selected subjects"]: + + for behavior in plot_parameters["selected behaviors"]: + + cursor.execute("SELECT occurence, modifiers, comment FROM events WHERE observation = ? AND subject = ? AND code = ? ORDER by occurence", (obsId, subject, behavior)) + rows = list(cursor.fetchall()) + + if STATE in self.eventType(behavior).upper() and len(rows) % 2: # unpaired events + flagUnpairedEventFound = True + continue + + for idx, row in enumerate(rows): + + if self.pj[OBSERVATIONS][obsId]["type"] in [MEDIA]: + + mediaFileIdx = [idx1 for idx1, x in enumerate(duration1) if row["occurence"] >= sum(duration1[0:idx1])][-1] + mediaFileString = self.pj[OBSERVATIONS][obsId][FILE][PLAYER1][mediaFileIdx] + fpsString = self.pj[OBSERVATIONS][obsId]["media_info"]["fps"][self.pj[OBSERVATIONS][obsId][FILE][PLAYER1][mediaFileIdx]] + + if self.pj[OBSERVATIONS][obsId]["type"] in [LIVE]: + mediaFileString = "LIVE" + fpsString = "NA" + + if POINT in self.eventType(behavior).upper(): + + if outputFormat == "sql": + out += template.format(observation=obsId, + date=self.pj[OBSERVATIONS][obsId]["date"].replace("T", " "), + media_file=mediaFileString, + total_length=total_length, + fps=fpsString, + subject=subject, + behavior=behavior, + modifiers=row["modifiers"].strip(), + event_type=POINT, + start="{0:.3f}".format(row["occurence"]), + stop=0, + comment_start=row["comment"], + comment_stop="") + else: + row_data = [] + row_data.extend([obsId, + self.pj[OBSERVATIONS][obsId]["date"].replace("T", " "), + mediaFileString, + total_length, + fpsString]) + + # independent variables + if "independent_variables" in self.pj: + for idx_var in sorted_keys(self.pj["independent_variables"]): + if self.pj["independent_variables"][idx_var]["label"] in self.pj[OBSERVATIONS][obsId]["independent_variables"]: + row_data.append(self.pj[OBSERVATIONS][obsId]["independent_variables"][self.pj["independent_variables"][idx_var]["label"]]) + else: + row_data.append("") + + row_data.extend([subject, + behavior, + row["modifiers"].strip(), + POINT, + "{0:.3f}".format(row["occurence"]), # start + "NA", # stop + "NA", # duration + row["comment"], + "" + ]) + data.append(row_data) + + + if STATE in self.eventType(behavior).upper(): + if idx % 2 == 0: + if outputFormat == "sql": + out += template.format(observation=obsId, + date=self.pj[OBSERVATIONS][obsId]["date"].replace("T", " "), + media_file=mediaFileString, + total_length=total_length, + fps=fpsString, + subject=subject, + behavior=behavior, + modifiers=row["modifiers"].strip(), + event_type=STATE, + start="{0:.3f}".format(row["occurence"]), + stop="{0:.3f}".format(rows[idx + 1]["occurence"]), + comment_start=row["comment"], + comment_stop=rows[idx + 1]["comment"]) + + else: + row_data = [] + + row_data.extend([obsId, + self.pj[OBSERVATIONS][obsId]["date"].replace("T", " "), + mediaFileString, + total_length, + fpsString]) + + # independent variables + if "independent_variables" in self.pj: + for idx_var in sorted_keys(self.pj["independent_variables"]): + if self.pj["independent_variables"][idx_var]["label"] in self.pj[OBSERVATIONS][obsId]["independent_variables"]: + row_data.append(self.pj[OBSERVATIONS][obsId]["independent_variables"][self.pj["independent_variables"][idx_var]["label"]]) + else: + row_data.append("") + + row_data.extend([subject, + behavior, + row["modifiers"].strip(), + STATE, + "{0:.3f}".format(row["occurence"]), + "{0:.3f}".format(rows[idx + 1]["occurence"]), + "{0:.3f}".format(rows[idx + 1]["occurence"] - row["occurence"]), + row["comment"], + rows[idx + 1]["comment"] + ]) + + data.append(row_data) diff --git a/dialog.py b/dialog.py index 628cca07..47365fd7 100644 --- a/dialog.py +++ b/dialog.py @@ -3,7 +3,7 @@ """ BORIS Behavioral Observation Research Interactive Software -Copyright 2012-2017 Olivier Friard +Copyright 2012-2018 Olivier Friard This file is part of BORIS. diff --git a/edit_event.py b/edit_event.py index 40250815..9ca2a49b 100644 --- a/edit_event.py +++ b/edit_event.py @@ -3,7 +3,7 @@ """ BORIS Behavioral Observation Research Interactive Software -Copyright 2012-2017 Olivier Friard +Copyright 2012-2018 Olivier Friard This file is part of BORIS. @@ -35,16 +35,18 @@ from config import * + if QT_VERSION_STR[0] == "4": from edit_event_ui import Ui_Form -else: +if QT_VERSION_STR[0] == "5": from edit_event_ui5 import Ui_Form + class DlgEditEvent(QDialog, Ui_Form): def __init__(self, log_level, parent=None): - super(DlgEditEvent, self).__init__(parent) + super().__init__(parent) logging.basicConfig(level=log_level) self.setupUi(self) diff --git a/edit_event.ui b/edit_event.ui index 5827dbca..88ac5d90 100644 --- a/edit_event.ui +++ b/edit_event.ui @@ -139,6 +139,9 @@ OK + + true + diff --git a/edit_event_ui.py b/edit_event_ui.py index 36b457d2..06a17764 100644 --- a/edit_event_ui.py +++ b/edit_event_ui.py @@ -2,8 +2,7 @@ # Form implementation generated from reading ui file 'edit_event.ui' # -# Created: Tue Dec 15 12:51:27 2015 -# by: PyQt4 UI code generator 4.11.2 +# Created by: PyQt4 UI code generator 4.11.4 # # WARNING! All changes made in this file will be lost! @@ -84,6 +83,7 @@ def setupUi(self, Form): self.pbCancel.setObjectName(_fromUtf8("pbCancel")) self.horizontalLayout.addWidget(self.pbCancel) self.pbOK = QtGui.QPushButton(Form) + self.pbOK.setDefault(True) self.pbOK.setObjectName(_fromUtf8("pbOK")) self.horizontalLayout.addWidget(self.pbOK) self.verticalLayout.addLayout(self.horizontalLayout) diff --git a/edit_event_ui5.py b/edit_event_ui5.py index 2901a11f..5adcfa6f 100644 --- a/edit_event_ui5.py +++ b/edit_event_ui5.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'edit_event.ui' # -# Created by: PyQt5 UI code generator 5.6 +# Created by: PyQt5 UI code generator 5.9 # # WARNING! All changes made in this file will be lost! @@ -69,6 +69,7 @@ def setupUi(self, Form): self.pbCancel.setObjectName("pbCancel") self.horizontalLayout.addWidget(self.pbCancel) self.pbOK = QtWidgets.QPushButton(Form) + self.pbOK.setDefault(True) self.pbOK.setObjectName("pbOK") self.horizontalLayout.addWidget(self.pbOK) self.verticalLayout.addLayout(self.horizontalLayout) diff --git a/irr.py b/irr.py index 6de48be0..42a694b3 100644 --- a/irr.py +++ b/irr.py @@ -33,18 +33,20 @@ def cohen_kappa(obsid1, obsid2, events1, events2, interval, state_behaviors_codes, + point_behaviors_codes, selected_subjects, include_modifiers): """ Args: obsid1 (str): id of observation #1 - obsid2 (str): id of observation #1 + obsid2 (str): id of observation #2 events1 (list): events of obs #1 events2 (list): events of obs #2 state_behaviors_codes (list): list of behavior codes defined as state event + point_behaviors_codes (list): list of behavior codes defined as point event selected_subjects (list): subjects selected for analysis - include_modifiers (bool): true: include modifiers false: do not + include_modifiers (bool): True: include modifiers False: do not Return: str: result of analysis @@ -60,23 +62,22 @@ def cohen_kappa(obsid1, obsid2, while currentTime <= last_event: for events in [events1, events2]: + for subject in selected_subjects: - + if subject == NO_FOCAL_SUBJECT: subject = "" - #logging.debug("subject: {}".format(subject)) - + current_states = utilities.get_current_states_by_subject(state_behaviors_codes, events, {subject: {"name": subject}}, currentTime) - - #print("subject", subject, "current_states", current_states) - + + #print(currentTime, "subject", subject, "current_states", current_states) + s = [] if include_modifiers: - cm = {} for behavior in current_states[subject]: for ev in events: @@ -90,22 +91,46 @@ def cohen_kappa(obsid1, obsid2, if cm: for behavior in cm: - s.append([subject, behavior, cm[behavior]]) + s.append([subject, [[behavior, cm[behavior]]]]) else: s.append([subject]) - else: s.append([subject, current_states[subject]]) + + print(currentTime, "state", s) + + # point events + current_points = utilities.get_current_points_by_subject(point_behaviors_codes, + events, + {subject: {"name": subject}}, + currentTime, + Decimal(str(round(interval/2, 3)))) + + + #print(currentTime, current_points) + + if current_points[subject]: + if include_modifiers: + if s == [['']]: + s = [[subject, current_points[subject]]] + else: + s.append([subject, current_points[subject]]) + else: + s.append([subject, current_points[subject]]) + + print(currentTime, "point", s) + if s not in total_states: total_states.append(s) currentTime += interval - total_states = sorted(total_states) logging.debug("total_states: {}".format(total_states)) + + print(total_states) contingency_table = np.zeros((len(total_states), len(total_states))) @@ -187,8 +212,7 @@ def cohen_kappa(obsid1, obsid2, print(tot1) print(tot2) ''' - - + ''' taskdata=[[0,str(i),str(tot1[i])] for i in range(0,len(tot1))]+[[1,str(i),str(tot2[i])] for i in range(0,len(tot2))] ratingtask = agreement.AnnotationTask(data=taskdata) @@ -253,6 +277,10 @@ def cohen_kappa(obsid1, obsid2, from nltk import agreement + + logging.basicConfig(level=logging.INFO) + + obsid1, obsid2 = "obs #1", "obs #2" interval = 1 @@ -264,34 +292,43 @@ def cohen_kappa(obsid1, obsid2, include_modifiers = True - events1 = [[Decimal('1.0'), '', 's', 'xx', ''], [Decimal('10.0'), '', 's', '', ''], [Decimal('20.0'), '', 's', '', ''], [Decimal('30.0'), '', 's', '', '']] - events2 = [[Decimal('1.0'), '', 's', 'xxx', ''], [Decimal('10.0'), '', 's', '', ''], [Decimal('20.0'), '', 's', '', ''], [Decimal('30.0'), '', 's', '', '']] + + events1 = [[ Decimal(2.1), "", "p", "", "" ], + [ Decimal(3.743), "", "s", "", "" ], - events1 = [ [ 3.743, "", "s", "", "" ], - [ 9.719, "", "s", "", "" ], - [ 11.135, "", "a", "bbb|None", "" ], - [ 22.87, "", "a", "bbb|None", "" ], - [ 22.871, "", "a", "None|None", "" ], - [ 35.759, "", "a", "None|None", "" ] + [ Decimal(5.5), "", "p", "", "" ], + [ Decimal(5.6), "", "p", "", "" ], + + [ Decimal(9.719), "", "s", "", "" ], + + [ Decimal(10), "", "ss", "x", "" ], + [ Decimal(11.135), "", "s", "bbb|None", "" ], + [ Decimal(15), "", "ss", "x", "" ], + [ Decimal(22.87), "", "s", "bbb|None", "" ], + [ Decimal(22.871), "", "s", "None|None", "" ], + [ Decimal(35.759), "", "s", "None|None", "" ] ] - events2 = [ [ 3.743, "", "s", "", "" ], - [ 9.719, "", "s", "", "" ], - [ 11.135, "", "a", "aaa|None", "" ], - [ 22.87, "", "a", "aaa|None", "" ], - [ 22.871, "", "a", "None|None", "" ], - [ 35.759, "", "a", "None|None", "" ] + events2 = [ [ Decimal( 3.743), "", "s", "", "" ], + [ Decimal(9.719), "", "s", "", "" ], + [ Decimal(11.135), "", "s", "aaa|None", "" ], + [ Decimal(22.87), "", "s", "aaa|None", "" ], + [ Decimal(22.871), "", "s", "None|None", "" ], + [ Decimal(35.759), "", "s", "None|None", "" ] ] - state_behaviors_codes = list(set([x[2] for x in events1] + [x[2] for x in events2])) + state_behaviors_codes = ['s','ss'] + point_behaviors_codes = ['p'] print(cohen_kappa(obsid1, obsid2, events1, events2, interval, state_behaviors_codes, + point_behaviors_codes, selected_subjects, - include_modifiers)) + True #include_modifiers + )) diff --git a/map_creator.py b/map_creator.py index 940a8009..4108e536 100644 --- a/map_creator.py +++ b/map_creator.py @@ -3,7 +3,7 @@ """ BORIS Behavioral Observation Research Interactive Software -Copyright 2012-2017 Olivier Friard +Copyright 2012-2018 Olivier Friard This file is part of BORIS. diff --git a/modifiers_coding_map.py b/modifiers_coding_map.py index 5bbf9a24..5e4dfd59 100644 --- a/modifiers_coding_map.py +++ b/modifiers_coding_map.py @@ -3,7 +3,7 @@ """ BORIS Behavioral Observation Research Interactive Software -Copyright 2012-2017 Olivier Friard +Copyright 2012-2018 Olivier Friard This file is part of BORIS. diff --git a/observations_list.py b/observations_list.py index f03cff5f..bf9ac382 100644 --- a/observations_list.py +++ b/observations_list.py @@ -3,7 +3,7 @@ """ BORIS Behavioral Observation Research Interactive Software -Copyright 2012-2017 Olivier Friard +Copyright 2012-2018 Olivier Friard This program is free software; you can redistribute it and/or modify diff --git a/param_panel.py b/param_panel.py index adc7b20a..2c9486e7 100644 --- a/param_panel.py +++ b/param_panel.py @@ -3,7 +3,7 @@ """ BORIS Behavioral Observation Research Interactive Software -Copyright 2012-2017 Olivier Friard +Copyright 2012-2018 Olivier Friard This file is part of BORIS. diff --git a/plot_events.py b/plot_events.py index c2a3a6e5..19b1b6e7 100644 --- a/plot_events.py +++ b/plot_events.py @@ -3,7 +3,7 @@ """ BORIS Behavioral Observation Research Interactive Software -Copyright 2012-2017 Olivier Friard +Copyright 2012-2018 Olivier Friard This file is part of BORIS. diff --git a/preferences.py b/preferences.py index 16813474..9b7c51a8 100644 --- a/preferences.py +++ b/preferences.py @@ -3,7 +3,7 @@ """ BORIS Behavioral Observation Research Interactive Software -Copyright 2012-2017 Olivier Friard +Copyright 2012-2018 Olivier Friard This file is part of BORIS. diff --git a/project_functions.py b/project_functions.py index bb945ec7..4348931f 100644 --- a/project_functions.py +++ b/project_functions.py @@ -1,7 +1,7 @@ """ BORIS Behavioral Observation Research Interactive Software -Copyright 2012-2017 Olivier Friard +Copyright 2012-2018 Olivier Friard This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/recode_widget.py b/recode_widget.py index 24c6e6b1..f7e8fc5d 100644 --- a/recode_widget.py +++ b/recode_widget.py @@ -3,7 +3,7 @@ """ BORIS Behavioral Observation Research Interactive Software -Copyright 2012-2017 Olivier Friard +Copyright 2012-2018 Olivier Friard This program is free software; you can redistribute it and/or modify diff --git a/select_modifiers.py b/select_modifiers.py index d0a6dbbb..cc93a0fd 100644 --- a/select_modifiers.py +++ b/select_modifiers.py @@ -3,7 +3,7 @@ """ BORIS Behavioral Observation Research Interactive Software -Copyright 2012-2017 Olivier Friard +Copyright 2012-2018 Olivier Friard This file is part of BORIS. diff --git a/subjects_pad.py b/subjects_pad.py index d1a389b7..bd46cf8c 100644 --- a/subjects_pad.py +++ b/subjects_pad.py @@ -3,7 +3,7 @@ """ BORIS Behavioral Observation Research Interactive Software -Copyright 2012-2017 Olivier Friard +Copyright 2012-2018 Olivier Friard This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/time_budget_widget.py b/time_budget_widget.py index 646a9da5..66b48179 100644 --- a/time_budget_widget.py +++ b/time_budget_widget.py @@ -3,7 +3,7 @@ """ BORIS Behavioral Observation Research Interactive Software -Copyright 2012-2017 Olivier Friard +Copyright 2012-2018 Olivier Friard This file is part of BORIS. diff --git a/transitions.py b/transitions.py index a6bc0485..2886c4ba 100644 --- a/transitions.py +++ b/transitions.py @@ -3,7 +3,7 @@ """ BORIS Behavioral Observation Research Interactive Software -Copyright 2012-2017 Olivier Friard +Copyright 2012-2018 Olivier Friard This file is part of BORIS. diff --git a/utilities.py b/utilities.py index 9f18eb42..12baccd8 100644 --- a/utilities.py +++ b/utilities.py @@ -178,37 +178,60 @@ def get_current_states_by_subject(state_behaviors_codes, events, subjects, time) return current_states - -def get_current_states_modifiers_by_subject(state_behaviors_codes, events, subjects, time): +def get_current_points_by_subject(point_behaviors_codes, events, subjects, time, distance): """ - get current states for subjects at given time + get near point events for subjects at given time Args: - state_behaviors_codes (list): list of behavior codes defined as STATE event + point_behaviors_codes (list): list of behavior codes defined as POINT event events (list): list of events subjects (dict): dictionary of subjects time (Decimal): time + distance (Decimal): distance from time Returns: - dict: current state(s) and modifier(s) by subject. dict of list + dict: current states by subject. dict of list """ - current_states = {} + current_points = {} for idx in subjects: - current_states[idx] = [] - for sbc in state_behaviors_codes: - - event_list = [x[EVENT_BEHAVIOR_FIELD_IDX] for x in events + current_points[idx] = [] + for sbc in point_behaviors_codes: + events = [[x[EVENT_BEHAVIOR_FIELD_IDX], x[EVENT_MODIFIER_FIELD_IDX]] for x in events if x[EVENT_SUBJECT_FIELD_IDX] == subjects[idx]["name"] and x[EVENT_BEHAVIOR_FIELD_IDX] == sbc - and x[EVENT_TIME_FIELD_IDX] <= time] + and abs(x[EVENT_TIME_FIELD_IDX] - time) <= distance] - if len([x[EVENT_BEHAVIOR_FIELD_IDX] for x in events - if x[EVENT_SUBJECT_FIELD_IDX] == subjects[idx]["name"] - and x[EVENT_BEHAVIOR_FIELD_IDX] == sbc - and x[EVENT_TIME_FIELD_IDX] <= time]) % 2: # test if odd - current_states[idx].append(sbc) + for event in events: + current_points[idx].append(event) - return current_states + return current_points + +''' +def get_current_states_modifiers_by_subject(state_behaviors_codes, events, subjects, time): + """ + get current states and modifiers for subjects at given time + Args: + state_behaviors_codes (list): list of behavior codes defined as STATE event + events (list): list of events + subjects (dict): dictionary of subjects + time (Decimal): time + Returns: + dict: current state(s) and modifier(s) by subject. dict of list + """ + + current_states = get_current_states_by_subject(state_behaviors_codes, events, subjects, time) + cm = {} + for behavior in current_states[subject]: + for event in events: + if event[EVENT_TIME_FIELD_IDX] > currentTime: + break + if event[EVENT_SUBJECT_FIELD_IDX] == subject: + if event[EVENT_BEHAVIOR_FIELD_IDX] == behavior: + cm[behavior] = event[EVENT_MODIFIER_FIELD_IDX] + + + return current_states +''' def get_ip_address():