def set_to_current_time(self): """ set time to current media time """ self.teTime.setTime( QTime.fromString(seconds2time(self.current_time), HHMMSSZZZ)) self.dsbTime.setValue(float(self.current_time))
def choose_obs_subj_behav_category(pj: dict, selected_observations: list, maxTime=0, flagShowIncludeModifiers: bool = True, flagShowExcludeBehaviorsWoEvents: bool = True, by_category: bool = False, show_time: bool = False, timeFormat: str = HHMMSS): """ show window for: - selection of subjects - selection of behaviors (based on selected subjects) - selection of time interval - inclusion/exclusion of modifiers - inclusion/exclusion of behaviors without events (flagShowExcludeBehaviorsWoEvents == True) Returns: dict: {"selected subjects": selectedSubjects, "selected behaviors": selectedBehaviors, "include modifiers": True/False, "exclude behaviors": True/False, "time": TIME_FULL_OBS / TIME_EVENTS / TIME_ARBITRARY_INTERVAL "start time": startTime, "end time": endTime } """ paramPanelWindow = param_panel.Param_panel() paramPanelWindow.resize(600, 500) paramPanelWindow.setWindowTitle("Select subjects and behaviors") paramPanelWindow.selectedObservations = selected_observations paramPanelWindow.pj = pj if not flagShowIncludeModifiers: paramPanelWindow.cbIncludeModifiers.setVisible(False) if not flagShowExcludeBehaviorsWoEvents: paramPanelWindow.cbExcludeBehaviors.setVisible(False) if by_category: paramPanelWindow.cbIncludeModifiers.setVisible(False) paramPanelWindow.cbExcludeBehaviors.setVisible(False) paramPanelWindow.frm_time_interval.setEnabled(False) if timeFormat == HHMMSS: paramPanelWindow.teStartTime.setTime(QTime.fromString("00:00:00.000", "hh:mm:ss.zzz")) paramPanelWindow.teEndTime.setTime(QTime.fromString(utilities.seconds2time(maxTime), "hh:mm:ss.zzz")) paramPanelWindow.dsbStartTime.setVisible(False) paramPanelWindow.dsbEndTime.setVisible(False) if timeFormat == S: paramPanelWindow.dsbStartTime.setValue(0.0) paramPanelWindow.dsbEndTime.setValue(maxTime) paramPanelWindow.teStartTime.setVisible(False) paramPanelWindow.teEndTime.setVisible(False) # hide max time if not maxTime: paramPanelWindow.frm_time.setVisible(False) if selected_observations: observedSubjects = project_functions.extract_observed_subjects(pj, selected_observations) else: # load all subjects and "No focal subject" observedSubjects = [pj[SUBJECTS][x][SUBJECT_NAME] for x in pj[SUBJECTS]] + [""] selectedSubjects = [] # add 'No focal subject' if "" in observedSubjects: selectedSubjects.append(NO_FOCAL_SUBJECT) paramPanelWindow.item = QListWidgetItem(paramPanelWindow.lwSubjects) paramPanelWindow.ch = QCheckBox() paramPanelWindow.ch.setText(NO_FOCAL_SUBJECT) paramPanelWindow.ch.stateChanged.connect(paramPanelWindow.cb_changed) paramPanelWindow.ch.setChecked(True) paramPanelWindow.lwSubjects.setItemWidget(paramPanelWindow.item, paramPanelWindow.ch) all_subjects = [pj[SUBJECTS][x][SUBJECT_NAME] for x in utilities.sorted_keys(pj[SUBJECTS])] for subject in all_subjects: paramPanelWindow.item = QListWidgetItem(paramPanelWindow.lwSubjects) paramPanelWindow.ch = QCheckBox() paramPanelWindow.ch.setText(subject) paramPanelWindow.ch.stateChanged.connect(paramPanelWindow.cb_changed) if subject in observedSubjects: selectedSubjects.append(subject) paramPanelWindow.ch.setChecked(True) paramPanelWindow.lwSubjects.setItemWidget(paramPanelWindow.item, paramPanelWindow.ch) logging.debug(f'selectedSubjects: {selectedSubjects}') if selected_observations: observedBehaviors = paramPanelWindow.extract_observed_behaviors(selected_observations, selectedSubjects) # not sorted else: # load all behaviors observedBehaviors = [pj[ETHOGRAM][x][BEHAVIOR_CODE] for x in pj[ETHOGRAM]] logging.debug(f'observed behaviors: {observedBehaviors}') if BEHAVIORAL_CATEGORIES in pj: categories = pj[BEHAVIORAL_CATEGORIES][:] # check if behavior not included in a category try: if "" in [pj[ETHOGRAM][idx][BEHAVIOR_CATEGORY] for idx in pj[ETHOGRAM] if BEHAVIOR_CATEGORY in pj[ETHOGRAM][idx]]: categories += [""] except Exception: categories = ["###no category###"] else: categories = ["###no category###"] for category in categories: if category != "###no category###": if category == "": paramPanelWindow.item = QListWidgetItem("No category") paramPanelWindow.item.setData(34, "No category") else: paramPanelWindow.item = QListWidgetItem(category) paramPanelWindow.item.setData(34, category) font = QFont() font.setBold(True) paramPanelWindow.item.setFont(font) paramPanelWindow.item.setData(33, "category") paramPanelWindow.item.setData(35, False) paramPanelWindow.lwBehaviors.addItem(paramPanelWindow.item) for behavior in [pj[ETHOGRAM][x][BEHAVIOR_CODE] for x in utilities.sorted_keys(pj[ETHOGRAM])]: if ((categories == ["###no category###"]) or (behavior in [pj[ETHOGRAM][x][BEHAVIOR_CODE] for x in pj[ETHOGRAM] if BEHAVIOR_CATEGORY in pj[ETHOGRAM][x] and pj[ETHOGRAM][x][BEHAVIOR_CATEGORY] == category])): paramPanelWindow.item = QListWidgetItem(behavior) if behavior in observedBehaviors: paramPanelWindow.item.setCheckState(Qt.Checked) else: paramPanelWindow.item.setCheckState(Qt.Unchecked) if category != "###no category###": paramPanelWindow.item.setData(33, "behavior") if category == "": paramPanelWindow.item.setData(34, "No category") else: paramPanelWindow.item.setData(34, category) paramPanelWindow.lwBehaviors.addItem(paramPanelWindow.item) if not paramPanelWindow.exec_(): return {SELECTED_SUBJECTS: [], SELECTED_BEHAVIORS: []} selectedSubjects = paramPanelWindow.selectedSubjects selectedBehaviors = paramPanelWindow.selectedBehaviors logging.debug(f"selected subjects: {selectedSubjects}") logging.debug(f"selected behaviors: {selectedBehaviors}") if timeFormat == HHMMSS: startTime = utilities.time2seconds(paramPanelWindow.teStartTime.time().toString(HHMMSSZZZ)) endTime = utilities.time2seconds(paramPanelWindow.teEndTime.time().toString(HHMMSSZZZ)) if timeFormat == S: 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) return {SELECTED_SUBJECTS: [], SELECTED_BEHAVIORS: []} if paramPanelWindow.rb_full.isChecked(): time_param = TIME_FULL_OBS if paramPanelWindow.rb_limit.isChecked(): time_param = TIME_EVENTS if paramPanelWindow.rb_interval.isChecked(): time_param = TIME_ARBITRARY_INTERVAL return {SELECTED_SUBJECTS: selectedSubjects, SELECTED_BEHAVIORS: selectedBehaviors, INCLUDE_MODIFIERS: paramPanelWindow.cbIncludeModifiers.isChecked(), EXCLUDE_BEHAVIORS: paramPanelWindow.cbExcludeBehaviors.isChecked(), "time": time_param, START_TIME: startTime, END_TIME: endTime }
def create_subtitles(pj: dict, selected_observations: list, parameters: dict, export_dir: str) -> tuple: """ create subtitles for selected observations, subjects and behaviors Args: pj (dict): project selected_observations (list): list of observations parameters (dict): export_dir (str): directory to save subtitles Returns: bool: True if OK else False str: error message """ def subject_color(subject): """ subject color Args: subject (str): subject name Returns: str: HTML tag for color font (beginning) str: HTML tag for color font (closing) """ if subject == NO_FOCAL_SUBJECT: return "", "" else: return ( """<font color="{}">""".format( subtitlesColors[parameters["selected subjects"].index( row["subject"]) % len(subtitlesColors)]), "</font>", ) try: ok, msg, db_connector = db_functions.load_aggregated_events_in_db( pj, parameters["selected subjects"], selected_observations, parameters["selected behaviors"]) if not ok: return False, msg cursor = db_connector.cursor() flag_ok = True msg = "" for obsId in selected_observations: if pj[OBSERVATIONS][obsId][TYPE] in [LIVE]: out = "" cursor.execute( ("SELECT subject, behavior, start, stop, type, modifiers FROM aggregated_events " "WHERE observation = ? AND subject in ({}) " "AND behavior in ({}) " "ORDER BY start").format( ",".join(["?"] * len(parameters["selected subjects"])), ",".join(["?"] * len(parameters["selected behaviors"]))), [obsId] + parameters["selected subjects"] + parameters["selected behaviors"], ) for idx, row in enumerate(cursor.fetchall()): col1, col2 = subject_color(row["subject"]) if parameters["include modifiers"]: modifiers_str = "\n{}".format(row["modifiers"].replace( "|", ", ")) else: modifiers_str = "" out += ("{idx}\n" "{start} --> {stop}\n" "{col1}{subject}: {behavior}" "{modifiers}" "{col2}\n\n").format( idx=idx + 1, start=utilities.seconds2time( row["start"]).replace(".", ","), stop=utilities.seconds2time( row["stop"] if row["type"] == STATE else row["stop"] + POINT_EVENT_ST_DURATION).replace(".", ","), col1=col1, col2=col2, subject=row["subject"], behavior=row["behavior"], modifiers=modifiers_str, ) file_name = str( pathlib.Path( pathlib.Path(export_dir) / utilities.safeFileName(obsId)).with_suffix(".srt")) try: with open(file_name, "w") as f: f.write(out) except Exception: flag_ok = False msg += "observation: {}\ngave the following error:\n{}\n".format( obsId, str(sys.exc_info()[1])) elif pj[OBSERVATIONS][obsId][TYPE] in [MEDIA]: for nplayer in ALL_PLAYERS: if not pj[OBSERVATIONS][obsId][FILE][nplayer]: continue init = 0 for mediaFile in pj[OBSERVATIONS][obsId][FILE][nplayer]: try: end = init + pj[OBSERVATIONS][obsId][MEDIA_INFO][ LENGTH][mediaFile] except KeyError: return False, f"The length for media file {mediaFile} is not available" out = "" print(",".join(["?"] * len(parameters["selected subjects"]))) print(",".join(["?"] * len(parameters["selected behaviors"]))) print([obsId, init, end] + parameters["selected subjects"] + parameters["selected behaviors"]) cursor.execute( ("SELECT subject, behavior, type, start, stop, modifiers FROM aggregated_events " "WHERE observation = ? AND start BETWEEN ? and ? " "AND subject in ({}) " "AND behavior in ({}) " "ORDER BY start").format( ",".join( ["?"] * len(parameters["selected subjects"])), ",".join( ["?"] * len(parameters["selected behaviors"])), ), [obsId, init, end] + parameters["selected subjects"] + parameters["selected behaviors"], ) for idx, row in enumerate(cursor.fetchall()): col1, col2 = subject_color(row["subject"]) if parameters["include modifiers"]: modifiers_str = "\n{}".format( row["modifiers"].replace("|", ", ")) else: modifiers_str = "" out += ( "{idx}\n" "{start} --> {stop}\n" "{col1}{subject}: {behavior}" "{modifiers}" "{col2}\n\n").format( idx=idx + 1, start=utilities.seconds2time(row["start"] - init).replace( ".", ","), stop=utilities.seconds2time( (row["stop"] if row["type"] == STATE else row["stop"] + POINT_EVENT_ST_DURATION) - init).replace(".", ","), col1=col1, col2=col2, subject=row["subject"], behavior=row["behavior"], modifiers=modifiers_str, ) file_name = str( pathlib.Path( pathlib.Path(export_dir) / pathlib.Path(mediaFile).name).with_suffix( ".srt")) try: with open(file_name, "w") as f: f.write(out) except Exception: flag_ok = False msg += "observation: {}\ngave the following error:\n{}\n".format( obsId, str(sys.exc_info()[1])) init = end return flag_ok, msg except Exception: return False, str(sys.exc_info()[1])
def check_state_events_obs(obsId: str, ethogram: dict, observation: dict, time_format: str = HHMMSS) -> tuple: """ check state events for the observation obsId check if behaviors in observation are defined in ethogram check if number is odd Args: obsId (str): id of observation to check ethogram (dict): ethogram of project observation (dict): observation to be checked time_format (str): time format Returns: tuple (bool, str): if OK True else False , message """ out = "" # check if behaviors are defined as "state event" event_types = {ethogram[idx]["type"] for idx in ethogram} if not event_types or event_types == {"Point event"}: return (True, "No behavior is defined as `State event`") flagStateEvent = False subjects = [ event[EVENT_SUBJECT_FIELD_IDX] for event in observation[EVENTS] ] ethogram_behaviors = {ethogram[idx][BEHAVIOR_CODE] for idx in ethogram} for subject in sorted(set(subjects)): behaviors = [ event[EVENT_BEHAVIOR_FIELD_IDX] for event in observation[EVENTS] if event[EVENT_SUBJECT_FIELD_IDX] == subject ] for behavior in sorted(set(behaviors)): if behavior not in ethogram_behaviors: # return (False, "The behaviour <b>{}</b> is not defined in the ethogram.<br>".format(behavior)) continue else: if STATE in event_type(behavior, ethogram).upper(): flagStateEvent = True lst, memTime = [], {} for event in [ event for event in observation[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)] else: lst.append(behav_modif) memTime[str( behav_modif)] = event[EVENT_TIME_FIELD_IDX] for event in lst: out += ( """The behavior <b>{behavior}</b> {modifier} is not PAIRED for subject""" """ "<b>{subject}</b>" at <b>{time}</b><br>""" ).format( behavior=behavior, modifier=("(modifier " + event[1] + ") ") if event[1] else "", subject=subject if subject else NO_FOCAL_SUBJECT, time=memTime[str(event)] if time_format == S else utilities.seconds2time(memTime[str(event)]), ) return (False, out) if out else (True, "No problem detected")
def test_10(self): assert utilities.seconds2time(Decimal(10.0)) == "00:00:10.000"
def test_gt_86400(self): assert utilities.seconds2time( Decimal(86400.999)) == "24:00:00.999"
def test_negative(self): assert utilities.seconds2time( Decimal(-2.123)) == "-00:00:02.123"
def create_subtitles(pj: dict, selected_observations: list, parameters: dict, export_dir: str) -> tuple: """ create subtitles for selected observations, subjects and behaviors Args: pj (dict): project selected_observations (list): list of observations parameters (dict): export_dir (str): directory to save subtitles Returns: bool: True if OK else False str: error message """ def subject_color(subject): """ subject color Args: subject (str): subject name Returns: str: HTML tag for color font (beginning) str: HTML tag for color font (closing) """ if subject == NO_FOCAL_SUBJECT: return "", "" else: return ( """<font color="{}">""".format( subtitlesColors[parameters["selected subjects"].index(row["subject"]) % len(subtitlesColors)] ), "</font>", ) try: ok, msg, db_connector = db_functions.load_aggregated_events_in_db( pj, parameters["selected subjects"], selected_observations, parameters["selected behaviors"] ) if not ok: return False, msg cursor = db_connector.cursor() flag_ok = True msg = "" for obsId in selected_observations: if pj[OBSERVATIONS][obsId][TYPE] in [LIVE]: out = "" cursor.execute( ( "SELECT subject, behavior, start, stop, type, modifiers FROM aggregated_events " "WHERE observation = ? AND subject in ({}) " "AND behavior in ({}) " "ORDER BY start" ).format(",".join(["?"] * len(parameters["selected subjects"])), ",".join(["?"] * len(parameters["selected behaviors"]))), [obsId] + parameters["selected subjects"] + parameters["selected behaviors"], ) for idx, row in enumerate(cursor.fetchall()): col1, col2 = subject_color(row["subject"]) if parameters["include modifiers"]: modifiers_str = "\n{}".format(row["modifiers"].replace("|", ", ")) else: modifiers_str = "" out += ("{idx}\n" "{start} --> {stop}\n" "{col1}{subject}: {behavior}" "{modifiers}" "{col2}\n\n").format( idx=idx + 1, start=utilities.seconds2time(row["start"]).replace(".", ","), stop=utilities.seconds2time(row["stop"] if row["type"] == STATE else row["stop"] + POINT_EVENT_ST_DURATION).replace( ".", "," ), col1=col1, col2=col2, subject=row["subject"], behavior=row["behavior"], modifiers=modifiers_str, ) file_name = str(pathlib.Path(pathlib.Path(export_dir) / utilities.safeFileName(obsId)).with_suffix(".srt")) try: with open(file_name, "w") as f: f.write(out) except Exception: flag_ok = False msg += "observation: {}\ngave the following error:\n{}\n".format(obsId, str(sys.exc_info()[1])) elif pj[OBSERVATIONS][obsId][TYPE] in [MEDIA]: for nplayer in ALL_PLAYERS: if not pj[OBSERVATIONS][obsId][FILE][nplayer]: continue init = 0 for mediaFile in pj[OBSERVATIONS][obsId][FILE][nplayer]: try: end = init + pj[OBSERVATIONS][obsId][MEDIA_INFO][LENGTH][mediaFile] except KeyError: return False, f"The length for media file {mediaFile} is not available" out = "" print(",".join(["?"] * len(parameters["selected subjects"]))) print(",".join(["?"] * len(parameters["selected behaviors"]))) print([obsId, init, end] + parameters["selected subjects"] + parameters["selected behaviors"]) cursor.execute( ( "SELECT subject, behavior, type, start, stop, modifiers FROM aggregated_events " "WHERE observation = ? AND start BETWEEN ? and ? " "AND subject in ({}) " "AND behavior in ({}) " "ORDER BY start" ).format( ",".join(["?"] * len(parameters["selected subjects"])), ",".join(["?"] * len(parameters["selected behaviors"])), ), [obsId, init, end] + parameters["selected subjects"] + parameters["selected behaviors"], ) for idx, row in enumerate(cursor.fetchall()): col1, col2 = subject_color(row["subject"]) if parameters["include modifiers"]: modifiers_str = "\n{}".format(row["modifiers"].replace("|", ", ")) else: modifiers_str = "" out += ("{idx}\n" "{start} --> {stop}\n" "{col1}{subject}: {behavior}" "{modifiers}" "{col2}\n\n").format( idx=idx + 1, start=utilities.seconds2time(row["start"] - init).replace(".", ","), stop=utilities.seconds2time( (row["stop"] if row["type"] == STATE else row["stop"] + POINT_EVENT_ST_DURATION) - init ).replace(".", ","), col1=col1, col2=col2, subject=row["subject"], behavior=row["behavior"], modifiers=modifiers_str, ) file_name = str(pathlib.Path(pathlib.Path(export_dir) / pathlib.Path(mediaFile).name).with_suffix(".srt")) try: with open(file_name, "w") as f: f.write(out) except Exception: flag_ok = False msg += "observation: {}\ngave the following error:\n{}\n".format(obsId, str(sys.exc_info()[1])) init = end return flag_ok, msg except Exception: return False, str(sys.exc_info()[1])
def check_state_events_obs(obsId: str, ethogram: dict, observation: dict, time_format: str = HHMMSS) -> tuple: """ check state events for the observation obsId check if behaviors in observation are defined in ethogram check if number is odd Args: obsId (str): id of observation to check ethogram (dict): ethogram of project observation (dict): observation to be checked time_format (str): time format Returns: tuple (bool, str): if OK True else False , message """ out = "" # check if behaviors are defined as "state event" event_types = {ethogram[idx]["type"] for idx in ethogram} if not event_types or event_types == {"Point event"}: return (True, "No behavior is defined as `State event`") flagStateEvent = False subjects = [event[EVENT_SUBJECT_FIELD_IDX] for event in observation[EVENTS]] ethogram_behaviors = {ethogram[idx][BEHAVIOR_CODE] for idx in ethogram} for subject in sorted(set(subjects)): behaviors = [event[EVENT_BEHAVIOR_FIELD_IDX] for event in observation[EVENTS] if event[EVENT_SUBJECT_FIELD_IDX] == subject] for behavior in sorted(set(behaviors)): if behavior not in ethogram_behaviors: # return (False, "The behaviour <b>{}</b> is not defined in the ethogram.<br>".format(behavior)) continue else: if STATE in event_type(behavior, ethogram).upper(): flagStateEvent = True lst, memTime = [], {} for event in [ event for event in observation[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)] else: lst.append(behav_modif) memTime[str(behav_modif)] = event[EVENT_TIME_FIELD_IDX] for event in lst: out += ( """The behavior <b>{behavior}</b> {modifier} is not PAIRED for subject""" """ "<b>{subject}</b>" at <b>{time}</b><br>""" ).format( behavior=behavior, modifier=("(modifier " + event[1] + ") ") if event[1] else "", subject=subject if subject else NO_FOCAL_SUBJECT, time=memTime[str(event)] if time_format == S else utilities.seconds2time(memTime[str(event)]), ) return (False, out) if out else (True, "No problem detected")