def default_value(ethogram, behav, param): """ return value for duration in case of point event """ default_value_ = 0 if (project_functions.event_type(behav, ethogram) == "POINT EVENT" and param in ["duration"]): default_value_ = "-" return default_value_
def behaviors_bar_plot(pj, selected_observations, selected_subjects, selected_behaviors, include_modifiers, interval, start_time, end_time, plot_directory, output_format): """ scatter plot """ parameters = [ ["duration", "Total duration"], ] ok, msg, db_connector = db_functions.load_aggregated_events_in_db( pj, selected_subjects, selected_observations, selected_behaviors) if not ok: return False, msg, None cursor = db_connector.cursor() if include_modifiers: cursor.execute( "SELECT distinct behavior, modifiers FROM aggregated_events") distinct_behav_modif = [[rows["behavior"], rows["modifiers"]] for rows in cursor.fetchall()] else: cursor.execute("SELECT distinct behavior FROM aggregated_events") distinct_behav_modif = [[rows["behavior"], ""] for rows in cursor.fetchall()] # add selected behaviors that are not observed for behav in selected_behaviors: if [x for x in distinct_behav_modif if x[0] == behav] == []: distinct_behav_modif.append([behav, "-"]) behaviors = init_behav_modif(pj[ETHOGRAM], selected_subjects, distinct_behav_modif, include_modifiers, parameters) # select time interval for obs_id in selected_observations: if len(selected_subjects) > 1: fig, axs = plt.subplots(nrows=1, ncols=len(selected_subjects), sharey=True) else: fig, ax = plt.subplots(nrows=1, ncols=len(selected_subjects), sharey=True) axs = np.ndarray(shape=(1), dtype=type(ax)) axs[0] = ax # if modifiers not to be included set modifiers to "" if not include_modifiers: cursor.execute("UPDATE aggregated_events SET modifiers = ''") # time obs_length = project_functions.observation_total_length( pj[OBSERVATIONS][obs_id]) if obs_length == -1: obs_length = 0 if interval == TIME_FULL_OBS: min_time = float(0) max_time = float(obs_length) if interval == TIME_EVENTS: try: min_time = float(pj[OBSERVATIONS][obs_id][EVENTS][0][0]) except Exception: min_time = float(0) try: max_time = float(pj[OBSERVATIONS][obs_id][EVENTS][-1][0]) except Exception: max_time = float(obs_length) if interval == TIME_ARBITRARY_INTERVAL: min_time = float(start_time) max_time = float(end_time) cursor.execute( "UPDATE aggregated_events SET start = ? WHERE observation = ? AND start < ? AND stop BETWEEN ? AND ?", ( min_time, obs_id, min_time, min_time, max_time, )) cursor.execute( "UPDATE aggregated_events SET stop = ? WHERE observation = ? AND stop > ? AND start BETWEEN ? AND ?", ( max_time, obs_id, max_time, min_time, max_time, )) cursor.execute( "UPDATE aggregated_events SET start = ?, stop = ? WHERE observation = ? AND start < ? AND stop > ?", ( min_time, max_time, obs_id, min_time, max_time, )) for subject in selected_subjects: for behavior_modifiers in distinct_behav_modif: behavior, modifiers = behavior_modifiers # skip if behavior defined as POINT if POINT in project_functions.event_type( behavior, pj[ETHOGRAM]): continue behavior_modifiers_str = "|".join( behavior_modifiers) if modifiers else behavior # total duration cursor.execute(( "SELECT SUM(stop-start) FROM aggregated_events " "WHERE observation = ? AND subject = ? AND behavior = ? AND modifiers = ?" ), ( obs_id, subject, behavior, modifiers, )) for row in cursor.fetchall(): behaviors[subject][behavior_modifiers_str][ "duration"] = 0 if row[0] is None else row[0] print("behaviors") print(behaviors) print() print("sorted(distinct_behav_modif)", sorted(distinct_behav_modif)) max_length = 0 behaviors_duration = {} mb = {} for ax_idx, subj in enumerate(selected_subjects): behaviors_duration[subj] = {} behavior_ticks = [] for behavior_modifiers in sorted(distinct_behav_modif): behavior, modifiers = behavior_modifiers # skip if behavior defined as POINT if POINT in project_functions.event_type( behavior, pj[ETHOGRAM]): continue if behavior not in behaviors_duration[subj]: behaviors_duration[subj][behavior] = [[], []] behavior_modifiers_str = "|".join( behavior_modifiers) if modifiers else behavior if behavior not in behavior_ticks: behavior_ticks.append(behavior) for param in parameters: behaviors_duration[subj][behavior][0].append( behaviors[subj][behavior_modifiers_str][param[0]]) behaviors_duration[subj][behavior][1].append(modifiers) max_length = max( max_length, len(behaviors_duration[subj][behavior][1])) print() print("behaviors_duration", behaviors_duration) print() print("behavior_ticks", behavior_ticks) print() behavior_mod_ticks = behavior_ticks[:] for ax_idx, subj in enumerate(selected_subjects): print("subject", subj) md_lgd = [] b = {} for i in range(max_length): b[i] = [] for behavior in sorted(behaviors_duration[subj].keys()): try: b[i].append(behaviors_duration[subj][behavior][0][i]) if include_modifiers: if behaviors_duration[subj][behavior][1][i]: md_lgd.append( behavior + " " + behaviors_duration[subj][behavior][1][i]) else: md_lgd.append(behavior) except Exception: b[i].append(0) print() print("behavior_mod_ticks", behavior_mod_ticks) print() print("b") print(b) print() print("md_lgd") print(md_lgd) ind = np.arange(len(behavior_ticks)) width = 0.35 # the width of the bars: can also be len(x) sequence pp = [] max_obs = 0 bottom_ = [] idx_color = 0 for i in sorted(b.keys()): if i == 0: pp.append(axs[ax_idx].bar( ind, b[i], width, color=BEHAVIORS_PLOT_COLORS[idx_color:idx_color + len(b[i])])) else: pp.append(axs[ax_idx].bar( ind, b[i], width, color=BEHAVIORS_PLOT_COLORS[idx_color:idx_color + len(b[i])], bottom=bottom_)) idx_color += len(b[i]) if not bottom_: bottom_ = b[i] else: bottom_ = [x + bottom_[idx] for idx, x in enumerate(b[i])] max_obs = max(max_obs, sum(b[i])) if ax_idx == 0: axs[ax_idx].set_ylabel("Duration (s)") axs[ax_idx].set_xlabel("Behaviors") axs[ax_idx].set_title(f"{subj}") axs[ax_idx].set_xticks(ind) axs[ax_idx].set_xticklabels(behavior_mod_ticks, rotation=90) axs[ax_idx].set_yticks(np.arange(0, max(bottom_), 50)) lgd_col = [] for p in pp: for r in p: if r.get_height(): lgd_col.append(r) plt.legend(lgd_col, md_lgd) if plot_directory: output_file_name = str( pathlib.Path( pathlib.Path(plot_directory) / utilities.safeFileName(obs_id)).with_suffix("." + file_format)) plt.savefig(output_file_name) else: plt.show()
def create_behaviors_bar_plot(pj: dict, selected_observations: list, param: dict, plot_directory: str, output_format: str, plot_colors:list=BEHAVIORS_PLOT_COLORS): """ time budget bar plot Args: pj (dict): project param (dict): parameters plot_directory (str): path of directory output_format (str): image format Returns: dict: """ selected_subjects = param[SELECTED_SUBJECTS] selected_behaviors = param[SELECTED_BEHAVIORS] time_interval = param["time"] start_time = param[START_TIME] end_time = param[END_TIME] parameters = ["duration", "number of occurences"] ok, msg, db_connector = db_functions.load_aggregated_events_in_db(pj, selected_subjects, selected_observations, selected_behaviors) if not ok: return {"error": True, "message": msg} try: # extract all behaviors from ethogram for colors in plot all_behaviors = [pj[ETHOGRAM][x][BEHAVIOR_CODE] for x in utilities.sorted_keys(pj[ETHOGRAM])] for obs_id in selected_observations: cursor = db_connector.cursor() # distinct behaviors cursor.execute("SELECT distinct behavior FROM aggregated_events WHERE observation = ?", (obs_id,)) distinct_behav = [rows["behavior"] for rows in cursor.fetchall()] # add selected behaviors that are not observed ''' if not param[EXCLUDE_BEHAVIORS]: for behavior in selected_behaviors: if [x for x in distinct_behav if x == behavior] == []: distinct_behav.append(behavior) ''' # distinct subjects cursor.execute("SELECT distinct subject FROM aggregated_events WHERE observation = ?", (obs_id,)) distinct_subjects = [rows["subject"] for rows in cursor.fetchall()] behaviors = init_behav(pj[ETHOGRAM], distinct_subjects, distinct_behav, parameters) # plot creation if len(distinct_subjects) > 1: fig, axs = plt.subplots(nrows=1, ncols=len(distinct_subjects), sharey=True) fig2, axs2 = plt.subplots(nrows=1, ncols=len(distinct_subjects), sharey=True) else: fig, ax = plt.subplots(nrows=1, ncols=len(distinct_subjects), sharey=True) axs = np.ndarray(shape=(1), dtype=type(ax)) axs[0] = ax fig2, ax2 = plt.subplots(nrows=1, ncols=len(distinct_subjects), sharey=True) axs2 = np.ndarray(shape=(1), dtype=type(ax2)) axs2[0] = ax2 fig.suptitle("Durations of behaviors") fig2.suptitle("Number of occurences of behaviors") # if modifiers not to be included set modifiers to "" cursor.execute("UPDATE aggregated_events SET modifiers = ''") # time obs_length = project_functions.observation_total_length(pj[OBSERVATIONS][obs_id]) if obs_length == -1: obs_length = 0 if param["time"] == TIME_FULL_OBS: min_time = float(0) max_time = float(obs_length) if param["time"] == TIME_EVENTS: try: min_time = float(pj[OBSERVATIONS][obs_id][EVENTS][0][0]) except Exception: min_time = float(0) try: max_time = float(pj[OBSERVATIONS][obs_id][EVENTS][-1][0]) except Exception: max_time = float(obs_length) if param["time"] == TIME_ARBITRARY_INTERVAL: min_time = float(start_time) max_time = float(end_time) cursor.execute("UPDATE aggregated_events SET start = ? WHERE observation = ? AND start < ? AND stop BETWEEN ? AND ?", (min_time, obs_id, min_time, min_time, max_time, )) cursor.execute("UPDATE aggregated_events SET stop = ? WHERE observation = ? AND stop > ? AND start BETWEEN ? AND ?", (max_time, obs_id, max_time, min_time, max_time, )) cursor.execute("UPDATE aggregated_events SET start = ?, stop = ? WHERE observation = ? AND start < ? AND stop > ?", (min_time, max_time, obs_id, min_time, max_time, )) for ax_idx, subject in enumerate(sorted(distinct_subjects)): for behavior in distinct_behav: # number of occurences cursor.execute(("SELECT COUNT(*) AS count FROM aggregated_events " "WHERE observation = ? AND subject = ? AND behavior = ?"), (obs_id, subject, behavior, )) for row in cursor.fetchall(): behaviors[subject][behavior]["number of occurences"] = 0 if row["count"] is None else row["count"] # total duration if STATE in project_functions.event_type(behavior, pj[ETHOGRAM]): cursor.execute(("SELECT SUM(stop - start) AS duration FROM aggregated_events " "WHERE observation = ? AND subject = ? AND behavior = ?"), (obs_id, subject, behavior, )) for row in cursor.fetchall(): behaviors[subject][behavior]["duration"] = 0 if row["duration"] is None else row["duration"] durations, n_occurences, colors, x_labels, colors_duration, x_labels_duration = [], [], [], [], [], [] for behavior in sorted(distinct_behav): if param[EXCLUDE_BEHAVIORS] and behaviors[subject][behavior]["number of occurences"] == 0: continue n_occurences.append(behaviors[subject][behavior]["number of occurences"]) x_labels.append(behavior) try: colors.append(utilities.behavior_color(plot_colors, all_behaviors.index(behavior))) except Exception: colors.append("darkgray") if STATE in project_functions.event_type(behavior, pj[ETHOGRAM]): durations.append(behaviors[subject][behavior]["duration"]) x_labels_duration.append(behavior) try: colors_duration.append(utilities.behavior_color(plot_colors, all_behaviors.index(behavior))) except Exception: colors_duration.append("darkgray") #width = 0.35 # the width of the bars: can also be len(x) sequence axs2[ax_idx].bar(np.arange(len(n_occurences)), n_occurences, #width, color=colors ) axs[ax_idx].bar(np.arange(len(durations)), durations, #width, color=colors_duration ) if ax_idx == 0: axs[ax_idx].set_ylabel("Duration (s)") axs[ax_idx].set_xlabel("Behaviors") axs[ax_idx].set_title(f"{subject}") axs[ax_idx].set_xticks(np.arange(len(durations))) axs[ax_idx].set_xticklabels(x_labels_duration, rotation='vertical', fontsize=8) if ax_idx == 0: axs2[ax_idx].set_ylabel("Number of occurences") axs2[ax_idx].set_xlabel("Behaviors") axs2[ax_idx].set_title(f"{subject}") axs2[ax_idx].set_xticks(np.arange(len(n_occurences))) axs2[ax_idx].set_xticklabels(x_labels, rotation='vertical', fontsize=8) fig.align_labels() fig.tight_layout(rect=[0, 0.03, 1, 0.95]) fig2.align_labels() fig2.tight_layout(rect=[0, 0.03, 1, 0.95]) if plot_directory: # output_file_name = f"{pathlib.Path(plot_directory) / utilities.safeFileName(obs_id)}.{output_format}" fig.savefig(f"{pathlib.Path(plot_directory) / utilities.safeFileName(obs_id)}.duration.{output_format}") fig2.savefig(f"{pathlib.Path(plot_directory) / utilities.safeFileName(obs_id)}.number_of_occurences.{output_format}") plt.close() else: fig.show() fig2.show() return {} except Exception: error_type, error_file_name, error_lineno = utilities.error_info(sys.exc_info()) logging.critical(f"Error in time budget bar plot: {error_type} {error_file_name} {error_lineno}") return {"error": True, "exception": sys.exc_info()}
def time_budget_analysis(ethogram: dict, cursor, selected_observations: list, parameters: dict, by_category: bool = False): """ extract number of occurrences, total duration, mean ... if start_time = 0 and end_time = 0 all events are extracted Args: ethogram (dict): project ethogram cursor: cursor on temporary database selected_observations (list): selected observations parameters (dict): parameters for analysis by_category (bool): True for grouping in category else False Returns: list: results dict: """ categories, out = {}, [] for subject in parameters[SELECTED_SUBJECTS]: out_cat, categories[subject] = [], {} for behavior in parameters[SELECTED_BEHAVIORS]: if parameters[INCLUDE_MODIFIERS]: cursor.execute( "SELECT DISTINCT modifiers FROM events WHERE subject = ? AND code = ?", (subject, behavior)) distinct_modifiers = list(cursor.fetchall()) if not distinct_modifiers: if not parameters[EXCLUDE_BEHAVIORS]: if STATE in project_functions.event_type( behavior, ethogram): out.append({ "subject": subject, "behavior": behavior, "modifiers": "", "duration": 0, "duration_mean": 0, "duration_stdev": "NA", "number": "0", "inter_duration_mean": "NA", "inter_duration_stdev": "NA" }) else: # point out.append({ "subject": subject, "behavior": behavior, "modifiers": "", "duration": 0, "duration_mean": 0, "duration_stdev": "NA", "number": "0", "inter_duration_mean": "NA", "inter_duration_stdev": "NA" }) continue if POINT in project_functions.event_type(behavior, ethogram): for modifier in distinct_modifiers: cursor.execute( ("SELECT occurence, observation FROM events " "WHERE subject = ? " "AND code = ? " "AND modifiers = ? " "ORDER BY observation, occurence"), (subject, behavior, modifier[0])) rows = cursor.fetchall() # inter events duration all_event_interdurations = [] for idx, row in enumerate(rows): if idx and row[1] == rows[idx - 1][1]: all_event_interdurations.append( float(row[0]) - float(rows[idx - 1][0])) out_cat.append({ "subject": subject, "behavior": behavior, "modifiers": modifier[0], "duration": NA, "duration_mean": NA, "duration_stdev": NA, "number": len(rows), "inter_duration_mean": round(statistics.mean(all_event_interdurations), 3) if len(all_event_interdurations) else NA, "inter_duration_stdev": round(statistics.stdev(all_event_interdurations), 3) if len(all_event_interdurations) > 1 else NA }) if STATE in project_functions.event_type(behavior, ethogram): for modifier in distinct_modifiers: cursor.execute( ("SELECT occurence, observation FROM events " "WHERE subject = ? " "AND code = ? " "AND modifiers = ? " "ORDER BY observation, occurence"), (subject, behavior, modifier[0])) rows = list(cursor.fetchall()) if len(rows) % 2: out.append({ "subject": subject, "behavior": behavior, "modifiers": modifier[0], "duration": UNPAIRED, "duration_mean": UNPAIRED, "duration_stdev": UNPAIRED, "number": UNPAIRED, "inter_duration_mean": UNPAIRED, "inter_duration_stdev": UNPAIRED }) else: all_event_durations, all_event_interdurations = [], [] for idx, row in enumerate(rows): # event if idx % 2 == 0: new_init, new_end = float(row[0]), float( rows[idx + 1][0]) all_event_durations.append(new_end - new_init) # inter event if same observation if idx % 2 and idx != len(rows) - 1 and row[ 1] == rows[idx + 1][1]: if (parameters["start time"] <= row[0] <= parameters["end time"] and parameters["start time"] <= rows[idx + 1][0] <= parameters["end time"]): all_event_interdurations.append( float(rows[idx + 1][0]) - float(row[0])) out_cat.append({ "subject": subject, "behavior": behavior, "modifiers": modifier[0], "duration": round(sum(all_event_durations), 3), "duration_mean": round(statistics.mean(all_event_durations), 3) if len(all_event_durations) else "NA", "duration_stdev": round(statistics.stdev(all_event_durations), 3) if len(all_event_durations) > 1 else "NA", "number": len(all_event_durations), "inter_duration_mean": round( statistics.mean(all_event_interdurations), 3) if len(all_event_interdurations) else "NA", "inter_duration_stdev": round( statistics.stdev(all_event_interdurations), 3) if len(all_event_interdurations) > 1 else "NA" }) else: # no modifiers if POINT in project_functions.event_type(behavior, ethogram): cursor.execute(( "SELECT occurence,observation FROM events " "WHERE subject = ? AND code = ? ORDER BY observation, occurence" ), (subject, behavior)) rows = list(cursor.fetchall()) if len(selected_observations) == 1: new_rows = [] for occurence, observation in rows: new_occurence = max( float(parameters["start time"]), occurence) new_occurence = min(new_occurence, float(parameters["end time"])) new_rows.append([new_occurence, observation]) rows = list(new_rows) # include behaviors without events if not len(rows): if not parameters[EXCLUDE_BEHAVIORS]: out.append({ "subject": subject, "behavior": behavior, "modifiers": "", "duration": NA, "duration_mean": NA, "duration_stdev": NA, "number": "0", "inter_duration_mean": NA, "inter_duration_stdev": NA }) continue # inter events duration all_event_interdurations = [] for idx, row in enumerate(rows): if idx and row[1] == rows[idx - 1][1]: all_event_interdurations.append( float(row[0]) - float(rows[idx - 1][0])) out_cat.append({ "subject": subject, "behavior": behavior, "modifiers": "", "duration": NA, "duration_mean": NA, "duration_stdev": NA, "number": len(rows), "inter_duration_mean": round(statistics.mean(all_event_interdurations), 3) if len(all_event_interdurations) else NA, "inter_duration_stdev": round(statistics.stdev(all_event_interdurations), 3) if len(all_event_interdurations) > 1 else NA }) if STATE in project_functions.event_type(behavior, ethogram): cursor.execute(( "SELECT occurence, observation FROM events " "WHERE subject = ? AND code = ? ORDER BY observation, occurence" ), (subject, behavior)) rows = list(cursor.fetchall()) if not len(rows): if not parameters[ EXCLUDE_BEHAVIORS]: # include behaviors without events out.append({ "subject": subject, "behavior": behavior, "modifiers": "", "duration": 0, "duration_mean": 0, "duration_stdev": "NA", "number": 0, "inter_duration_mean": "-", "inter_duration_stdev": "-" }) continue if len(rows) % 2: out.append({ "subject": subject, "behavior": behavior, "modifiers": "", "duration": UNPAIRED, "duration_mean": UNPAIRED, "duration_stdev": UNPAIRED, "number": UNPAIRED, "inter_duration_mean": UNPAIRED, "inter_duration_stdev": UNPAIRED }) else: all_event_durations, all_event_interdurations = [], [] for idx, row in enumerate(rows): # event if idx % 2 == 0: new_init, new_end = float(row[0]), float( rows[idx + 1][0]) all_event_durations.append(new_end - new_init) # inter event if same observation if idx % 2 and idx != len(rows) - 1 and row[ 1] == rows[idx + 1][1]: if (parameters["start time"] <= row[0] <= parameters["end time"] and parameters["start time"] <= rows[idx + 1][0] <= parameters["end time"]): all_event_interdurations.append( float(rows[idx + 1][0]) - float(row[0])) out_cat.append({ "subject": subject, "behavior": behavior, "modifiers": "", "duration": round(sum(all_event_durations), 3), "duration_mean": round(statistics.mean(all_event_durations), 3) if len(all_event_durations) else NA, "duration_stdev": round(statistics.stdev(all_event_durations), 3) if len(all_event_durations) > 1 else NA, "number": len(all_event_durations), "inter_duration_mean": round(statistics.mean(all_event_interdurations), 3) if len(all_event_interdurations) else NA, "inter_duration_stdev": round(statistics.stdev(all_event_interdurations), 3) if len(all_event_interdurations) > 1 else NA }) out += out_cat if by_category: # and flagCategories: for behav in out_cat: try: category = [ ethogram[x]["category"] for x in ethogram if "category" in ethogram[x] and ethogram[x]["code"] == behav['behavior'] ][0] except Exception: category = "" if category in categories[subject]: if behav["duration"] not in [ "-", "NA" ] and categories[subject][category]["duration"] not in [ "-", "NA" ]: categories[subject][category]["duration"] += behav[ "duration"] else: categories[subject][category]["duration"] = "-" categories[subject][category]["number"] += behav["number"] else: categories[subject][category] = { "duration": behav["duration"], "number": behav["number"] } out_sorted = [] for subject in parameters[SELECTED_SUBJECTS]: for behavior in parameters[SELECTED_BEHAVIORS]: for row in out: if row["subject"] == subject and row["behavior"] == behavior: out_sorted.append(row) # http://stackoverflow.com/questions/673867/python-arbitrary-order-by return out_sorted, categories
def export_aggregated_events(pj, parameters, obsId): """ export aggregated events Args: pj (dict): BORIS project parameters (dict): subjects, behaviors obsId (str): observation id Returns: tablib.Dataset: """ data = tablib.Dataset() observation = pj[OBSERVATIONS][obsId] duration1 = [] # in seconds if observation[TYPE] in [MEDIA]: try: for mediaFile in observation[FILE][PLAYER1]: if "media_info" in observation: duration1.append( observation["media_info"]["length"][mediaFile]) except: duration1 = [] total_length = "{0:.3f}".format( project_functions.observation_total_length(observation)) cursor = db_functions.load_events_in_db(pj, parameters["selected subjects"], [obsId], parameters["selected behaviors"]) for subject in parameters["selected subjects"]: for behavior in 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()) for idx, row in enumerate(rows): if observation[TYPE] in [MEDIA]: if duration1: mediaFileIdx = [ idx1 for idx1, x in enumerate(duration1) if row["occurence"] >= sum(duration1[0:idx1]) ][-1] mediaFileString = observation[FILE][PLAYER1][ mediaFileIdx] fpsString = observation["media_info"]["fps"][ observation[FILE][PLAYER1][mediaFileIdx]] else: mediaFileString = "-" fpsString = "NA" if observation[TYPE] in [LIVE]: mediaFileString = "LIVE" fpsString = "NA" if POINT in project_functions.event_type( behavior, pj[ETHOGRAM]): row_data = [] row_data.extend([ obsId, observation["date"].replace("T", " "), mediaFileString, total_length, fpsString ]) # independent variables if INDEPENDENT_VARIABLES in pj: for idx_var in utilities.sorted_keys( pj[INDEPENDENT_VARIABLES]): if pj[INDEPENDENT_VARIABLES][idx_var][ "label"] in observation[ INDEPENDENT_VARIABLES]: row_data.append( observation[INDEPENDENT_VARIABLES][ 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 project_functions.event_type( behavior, pj[ETHOGRAM]): if idx % 2 == 0: row_data = [] row_data.extend([ obsId, observation["date"].replace("T", " "), mediaFileString, total_length, fpsString ]) # independent variables if INDEPENDENT_VARIABLES in pj: for idx_var in utilities.sorted_keys( pj[INDEPENDENT_VARIABLES]): if pj[INDEPENDENT_VARIABLES][idx_var][ "label"] in observation[ INDEPENDENT_VARIABLES]: row_data.append( observation[INDEPENDENT_VARIABLES][ 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) return data
def behaviors_bar_plot(pj, selected_observations, selected_subjects, selected_behaviors, include_modifiers, interval, start_time, end_time, plot_directory, output_format): """ scatter plot """ parameters = [["duration", "Total duration"], ] ok, msg, db_connector = db_functions.load_aggregated_events_in_db(pj, selected_subjects, selected_observations, selected_behaviors) if not ok: return False, msg, None cursor = db_connector.cursor() if include_modifiers: cursor.execute("SELECT distinct behavior, modifiers FROM aggregated_events") distinct_behav_modif = [[rows["behavior"], rows["modifiers"]] for rows in cursor.fetchall()] else: cursor.execute("SELECT distinct behavior FROM aggregated_events") distinct_behav_modif = [[rows["behavior"], ""] for rows in cursor.fetchall()] # add selected behaviors that are not observed for behav in selected_behaviors: if [x for x in distinct_behav_modif if x[0] == behav] == []: distinct_behav_modif.append([behav, "-"]) behaviors = init_behav_modif(pj[ETHOGRAM], selected_subjects, distinct_behav_modif, include_modifiers, parameters) # select time interval for obs_id in selected_observations: if len(selected_subjects) > 1: fig, axs = plt.subplots(nrows=1, ncols=len(selected_subjects), sharey=True) else: fig, ax = plt.subplots(nrows=1, ncols=len(selected_subjects), sharey=True) axs = np.ndarray(shape=(1), dtype=type(ax)) axs[0] = ax # if modifiers not to be included set modifiers to "" if not include_modifiers: cursor.execute("UPDATE aggregated_events SET modifiers = ''") # time obs_length = project_functions.observation_total_length(pj[OBSERVATIONS][obs_id]) if obs_length == -1: obs_length = 0 if interval == TIME_FULL_OBS: min_time = float(0) max_time = float(obs_length) if interval == TIME_EVENTS: try: min_time = float(pj[OBSERVATIONS][obs_id][EVENTS][0][0]) except Exception: min_time = float(0) try: max_time = float(pj[OBSERVATIONS][obs_id][EVENTS][-1][0]) except Exception: max_time = float(obs_length) if interval == TIME_ARBITRARY_INTERVAL: min_time = float(start_time) max_time = float(end_time) cursor.execute("UPDATE aggregated_events SET start = ? WHERE observation = ? AND start < ? AND stop BETWEEN ? AND ?", (min_time, obs_id, min_time, min_time, max_time, )) cursor.execute("UPDATE aggregated_events SET stop = ? WHERE observation = ? AND stop > ? AND start BETWEEN ? AND ?", (max_time, obs_id, max_time, min_time, max_time, )) cursor.execute("UPDATE aggregated_events SET start = ?, stop = ? WHERE observation = ? AND start < ? AND stop > ?", (min_time, max_time, obs_id, min_time, max_time, )) for subject in selected_subjects: for behavior_modifiers in distinct_behav_modif: behavior, modifiers = behavior_modifiers # skip if behavior defined as POINT if POINT in project_functions.event_type(behavior, pj[ETHOGRAM]): continue behavior_modifiers_str = "|".join(behavior_modifiers) if modifiers else behavior # total duration cursor.execute(("SELECT SUM(stop-start) FROM aggregated_events " "WHERE observation = ? AND subject = ? AND behavior = ? AND modifiers = ?"), (obs_id, subject, behavior, modifiers,)) for row in cursor.fetchall(): behaviors[subject][behavior_modifiers_str]["duration"] = 0 if row[0] is None else row[0] print("behaviors") print(behaviors) print() print("sorted(distinct_behav_modif)", sorted(distinct_behav_modif)) max_length = 0 behaviors_duration = {} mb = {} for ax_idx, subj in enumerate(selected_subjects): behaviors_duration[subj] = {} behavior_ticks = [] for behavior_modifiers in sorted(distinct_behav_modif): behavior, modifiers = behavior_modifiers # skip if behavior defined as POINT if POINT in project_functions.event_type(behavior, pj[ETHOGRAM]): continue if behavior not in behaviors_duration[subj]: behaviors_duration[subj][behavior] = [[],[]] behavior_modifiers_str = "|".join(behavior_modifiers) if modifiers else behavior #print(subj, behavior, modifiers) if behavior not in behavior_ticks: behavior_ticks.append(behavior) for param in parameters: behaviors_duration[subj][behavior][0].append(behaviors[subj][behavior_modifiers_str][param[0]]) behaviors_duration[subj][behavior][1].append(modifiers) max_length = max(max_length, len(behaviors_duration[subj][behavior][1])) print() print("behaviors_duration", behaviors_duration) print() print("behavior_ticks", behavior_ticks) print() #b = {} behavior_mod_ticks = behavior_ticks[:] for ax_idx, subj in enumerate(selected_subjects): print("subject", subj) md_lgd = [] b = {} for i in range(max_length): b[i] = [] for behavior in sorted(behaviors_duration[subj].keys()): try: b[i].append(behaviors_duration[subj][behavior][0][i]) if include_modifiers: ''' if behaviors_duration[subj][behavior][1][i]: behavior_mod_ticks[behavior_ticks.index(behavior)] = behavior_mod_ticks[behavior_ticks.index(behavior)] + "\n" + \ behaviors_duration[subj][behavior][1][i] ''' if behaviors_duration[subj][behavior][1][i]: md_lgd.append(behavior + " " + behaviors_duration[subj][behavior][1][i]) else: md_lgd.append(behavior) except: b[i].append(0) print() print("behavior_mod_ticks", behavior_mod_ticks) print() print("b") print(b) print() print("md_lgd") print(md_lgd) #ind = np.arange(len(behavior_ticks)) # the x locations for the groups ind = np.arange(len(behavior_ticks)) width = 0.35 # the width of the bars: can also be len(x) sequence pp = [] max_obs = 0 bottom_ = [] idx_color = 0 for i in sorted(b.keys()): print(i, b[i]) if i == 0: pp.append(axs[ax_idx].bar(ind, b[i], width, color=BEHAVIORS_PLOT_COLORS[idx_color:idx_color + len(b[i])])) else: pp.append(axs[ax_idx].bar(ind, b[i], width, color=BEHAVIORS_PLOT_COLORS[idx_color:idx_color + len(b[i])], bottom=bottom_)) idx_color += len(b[i]) if not bottom_: bottom_ = b[i] else: bottom_ = [x + bottom_[idx] for idx,x in enumerate(b[i])] max_obs = max(max_obs, sum(b[i])) if ax_idx == 0: axs[ax_idx].set_ylabel('Duration (s)') axs[ax_idx].set_xlabel('Behaviors') axs[ax_idx].set_title('{}'.format(subj)) axs[ax_idx].set_xticks(ind) axs[ax_idx].set_xticklabels(behavior_mod_ticks,rotation=90) axs[ax_idx].set_yticks(np.arange(0, max(bottom_), 50)) lgd_col = [] for p in pp: for r in p: if r.get_height(): lgd_col.append(r) plt.legend(lgd_col, md_lgd) if plot_directory: output_file_name = str(pathlib.Path(pathlib.Path(plot_directory) / utilities.safeFileName(obs_id)).with_suffix("." + file_format)) plt.savefig(output_file_name) else: plt.show()