コード例 #1
0
ファイル: plot_events.py プロジェクト: methfriz/BORIS
    def behav_color(behav):
        """
        return color corresponding to behavior
        if color not found returns "darkgray"

        see BEHAVIORS_PLOT_COLORS list in config.py
        """

        if behav in all_behaviors:
            return utilities.behavior_color(plot_colors, all_behaviors.index(behav))
        else:
            return "darkgray"
コード例 #2
0
def create_events_plot(pj,
                       selected_observations,
                       parameters,
                       plot_colors=BEHAVIORS_PLOT_COLORS,
                       plot_directory="",
                       file_format="png"):

    selected_subjects = parameters[SELECTED_SUBJECTS]
    selected_behaviors = parameters[SELECTED_BEHAVIORS]
    include_modifiers = parameters[INCLUDE_MODIFIERS]
    interval = parameters[TIME_INTERVAL]
    start_time = parameters[START_TIME]
    end_time = parameters[END_TIME]

    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 modifiers not to be included set modifiers to ""
    if not include_modifiers:
        cursor.execute("UPDATE aggregated_events SET modifiers = ''")

    cursor.execute(
        "SELECT distinct behavior, modifiers FROM aggregated_events")
    distinct_behav_modif = [[rows["behavior"], rows["modifiers"]]
                            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, "-"])

    distinct_behav_modif = sorted(distinct_behav_modif)
    max_len = len(distinct_behav_modif)

    all_behaviors = [
        pj[ETHOGRAM][x][BEHAVIOR_CODE]
        for x in utilities.sorted_keys(pj[ETHOGRAM])
    ]

    par1 = 1
    bar_height = 0.5
    init = dt.datetime(2017, 1, 1)

    for obs_id in selected_observations:

        if len(selected_subjects) > 1:
            fig, axs = plt.subplots(figsize=(20, 8),
                                    nrows=len(selected_subjects),
                                    ncols=1,
                                    sharex=True)
        else:
            fig, ax = plt.subplots(figsize=(20, 8),
                                   nrows=len(selected_subjects),
                                   ncols=1,
                                   sharex=True)
            axs = np.ndarray(shape=(1), dtype=type(ax))
            axs[0] = ax

        ok, msg, db_connector = db_functions.load_aggregated_events_in_db(
            pj, selected_subjects, [obs_id], selected_behaviors)

        cursor = db_connector.cursor()
        # if modifiers not to be included set modifiers to ""
        if not include_modifiers:
            cursor.execute("UPDATE aggregated_events SET modifiers = ''")
        cursor = db_connector.cursor()

        cursor.execute(
            "SELECT distinct behavior, modifiers FROM aggregated_events")
        distinct_behav_modif = [[rows["behavior"], rows["modifiers"]]
                                for rows in cursor.fetchall()]

        # add selected behaviors that are not observed
        if not parameters["exclude behaviors"]:
            for behav in selected_behaviors:
                if [x for x in distinct_behav_modif if x[0] == behav] == []:
                    distinct_behav_modif.append([behav, "-"])

        distinct_behav_modif = sorted(distinct_behav_modif)
        max_len = len(distinct_behav_modif)

        # time
        obs_length = project_functions.observation_total_length(
            pj[OBSERVATIONS][obs_id])
        if obs_length == -1:  # media length not available
            interval = TIME_EVENTS

        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,
            ))

        ylabels = [" ".join(x) for x in distinct_behav_modif]
        for ax_idx, subject in enumerate(selected_subjects):

            if parameters["exclude behaviors"]:
                cursor.execute(
                    "SELECT distinct behavior, modifiers FROM aggregated_events WHERE subject = ?",
                    (subject, ))
                distinct_behav_modif = [[rows["behavior"], rows["modifiers"]]
                                        for rows in cursor.fetchall()]

                # add selected behaviors that are not observed
                if not parameters["exclude behaviors"]:
                    for behav in selected_behaviors:
                        if [x for x in distinct_behav_modif
                                if x[0] == behav] == []:
                            distinct_behav_modif.append([behav, "-"])

                distinct_behav_modif = sorted(distinct_behav_modif)
                max_len = len(distinct_behav_modif)
                ylabels = [" ".join(x) for x in distinct_behav_modif]

            if not ax_idx:
                axs[ax_idx].set_title(f"Observation {obs_id}\n{subject}",
                                      fontsize=14)
            else:
                axs[ax_idx].set_title(subject, fontsize=14)
            bars = {}
            i = 0
            for behavior_modifiers in distinct_behav_modif:
                behavior, modifiers = behavior_modifiers
                behavior_modifiers_str = "|".join(
                    behavior_modifiers) if modifiers else behavior
                bars[behavior_modifiers_str] = []

                # total duration
                cursor.execute((
                    "SELECT start,stop FROM aggregated_events "
                    "WHERE observation = ? AND subject = ? AND behavior = ? AND modifiers = ?"
                ), (
                    obs_id,
                    subject,
                    behavior,
                    modifiers,
                ))
                for row in cursor.fetchall():
                    bars[behavior_modifiers_str].append(
                        (row["start"], row["stop"]))

                    start_date = matplotlib.dates.date2num(init + dt.timedelta(
                        seconds=row["start"]))
                    end_date = matplotlib.dates.date2num(init + dt.timedelta(
                        seconds=row["stop"] + POINT_EVENT_PLOT_DURATION *
                        (row["stop"] == row["start"])))
                    try:
                        bar_color = utilities.behavior_color(
                            plot_colors, all_behaviors.index(behavior))
                    except Exception:
                        bar_color = "darkgray"
                    bar_color = POINT_EVENT_PLOT_COLOR if row["stop"] == row[
                        "start"] else bar_color

                    # sage colors removed from matplotlib colors list
                    if bar_color in ["sage", "darksage", "lightsage"]:
                        bar_color = {
                            "darksage": "#598556",
                            "lightsage": "#bcecac",
                            "sage": "#87ae73"
                        }[bar_color]

                    try:
                        axs[ax_idx].barh((i * par1) + par1,
                                         end_date - start_date,
                                         left=start_date,
                                         height=bar_height,
                                         align="center",
                                         edgecolor=bar_color,
                                         color=bar_color,
                                         alpha=1)
                    except Exception:
                        axs[ax_idx].barh((i * par1) + par1,
                                         end_date - start_date,
                                         left=start_date,
                                         height=bar_height,
                                         align="center",
                                         edgecolor="darkgray",
                                         color="darkgray",
                                         alpha=1)

                i += 1

            axs[ax_idx].set_ylim(bottom=0, top=(max_len * par1) + par1)
            pos = np.arange(par1, max_len * par1 + par1 + 1, par1)
            axs[ax_idx].set_yticks(pos[:len(ylabels)])

            axs[ax_idx].set_yticklabels(ylabels, fontdict={"fontsize": 10})

            axs[ax_idx].set_ylabel("Behaviors" +
                                   " (modifiers)" * include_modifiers,
                                   fontdict={"fontsize": 10})

            axs[ax_idx].set_xlim(
                left=matplotlib.dates.date2num(init +
                                               dt.timedelta(seconds=min_time)),
                right=matplotlib.dates.date2num(init + dt.timedelta(
                    seconds=max_time + 1)))

            axs[ax_idx].grid(color="g", linestyle=":")
            axs[ax_idx].xaxis_date()
            axs[ax_idx].xaxis.set_major_formatter(DateFormatter("%H:%M:%S"))
            axs[ax_idx].set_xlabel("Time (HH:MM:SS)",
                                   fontdict={"fontsize": 12})
            axs[ax_idx].invert_yaxis()

        fig.autofmt_xdate()
        plt.tight_layout()

        if len(selected_observations) > 1:
            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()
コード例 #3
0
ファイル: plot_events.py プロジェクト: joey10086/BORIS
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()}
コード例 #4
0
ファイル: test_utilities.py プロジェクト: olivierfriard/BORIS
 def test_idx1000(self):
     assert utilities.behavior_color(config.BEHAVIORS_PLOT_COLORS, 1000) == "midnightblue"
コード例 #5
0
ファイル: test_utilities.py プロジェクト: olivierfriard/BORIS
 def test_idx0(self):
     assert utilities.behavior_color(config.BEHAVIORS_PLOT_COLORS, 0) == "tab:blue"
コード例 #6
0
ファイル: test_utilities.py プロジェクト: joey10086/BORIS
 def test_idx1000(self):
     assert utilities.behavior_color(config.BEHAVIORS_PLOT_COLORS, 1000) == "midnightblue"
コード例 #7
0
ファイル: test_utilities.py プロジェクト: joey10086/BORIS
 def test_idx0(self):
     assert utilities.behavior_color(config.BEHAVIORS_PLOT_COLORS, 0) == "tab:blue"
コード例 #8
0
def plot_time_ranges(pj, time_format, plot_colors, obs, obsId, minTime,
                     videoLength, excludeBehaviorsWithoutEvents, line_width):
    """
    create "hlines" matplotlib plot
    used by plot_event function (legacy)
    """
    def on_draw(event):
        # http://matplotlib.org/faq/howto_faq.html#move-the-edge-of-an-axes-to-make-room-for-tick-labels
        bboxes = []
        for label in labels:
            bbox = label.get_window_extent()
            bboxi = bbox.inverse_transformed(fig.transFigure)
            bboxes.append(bboxi)

        bbox = mtransforms.Bbox.union(bboxes)
        if fig.subplotpars.left < bbox.width:
            fig.subplots_adjust(left=1.1 * bbox.width)
            fig.canvas.draw()
        return False

    LINE_WIDTH = line_width
    all_behaviors, observedBehaviors = [], []
    maxTime = 0  # max time in all events of all subjects

    # all behaviors defined in project without modifiers
    all_project_behaviors = [
        pj[ETHOGRAM][idx]["code"]
        for idx in utilities.sorted_keys(pj[ETHOGRAM])
    ]
    all_project_subjects = [NO_FOCAL_SUBJECT] + [
        pj[SUBJECTS][idx]["name"]
        for idx in utilities.sorted_keys(pj[SUBJECTS])
    ]

    for subject in obs:

        for behavior_modifiers_json in obs[subject]:

            behavior_modifiers = json.loads(behavior_modifiers_json)

            if not excludeBehaviorsWithoutEvents:
                observedBehaviors.append(behavior_modifiers_json)
            else:
                if obs[subject][behavior_modifiers_json]:
                    observedBehaviors.append(behavior_modifiers_json)

            if not behavior_modifiers_json in all_behaviors:
                all_behaviors.append(behavior_modifiers_json)

            for t1, t2 in obs[subject][behavior_modifiers_json]:
                maxTime = max(maxTime, t1, t2)

        observedBehaviors.append("")

    lbl = []
    if excludeBehaviorsWithoutEvents:
        for behav_modif_json in observedBehaviors:

            if not behav_modif_json:
                lbl.append("")
                continue

            behav_modif = json.loads(behav_modif_json)
            if len(behav_modif) == 2:
                lbl.append("{0} ({1})".format(behav_modif[0], behav_modif[1]))
            else:
                lbl.append(behav_modif[0])

    else:
        all_behaviors.append('[""]')  # empty json list element
        for behav_modif_json in all_behaviors:

            behav_modif = json.loads(behav_modif_json)
            if len(behav_modif) == 2:
                lbl.append("{0} ({1})".format(behav_modif[0], behav_modif[1]))
            else:
                lbl.append(behav_modif[0])
        lbl = lbl[:] * len(obs)

    lbl = lbl[:-1]  # remove last empty line

    fig = plt.figure(figsize=(20, 10))
    fig.suptitle("Time diagram of observation {}".format(obsId), fontsize=14)
    ax = fig.add_subplot(111)
    labels = ax.set_yticklabels(lbl)

    ax.set_ylabel("Behaviors")

    if time_format == HHMMSS:
        fmtr = matplotlib.dates.DateFormatter("%H:%M:%S")  # %H:%M:%S:%f
        ax.xaxis.set_major_formatter(fmtr)
        ax.set_xlabel("Time (hh:mm:ss)")
    else:
        ax.set_xlabel("Time (s)")

    plt.ylim(len(lbl), -0.5)

    if not videoLength:
        videoLength = maxTime

    if pj[OBSERVATIONS][obsId]["time offset"]:
        t0 = round(pj[OBSERVATIONS][obsId]["time offset"] + minTime)
        t1 = round(pj[OBSERVATIONS][obsId]["time offset"] + videoLength + 2)
    else:
        t0 = round(minTime)
        t1 = round(videoLength)
    subjectPosition = t0 + (t1 - t0) * 0.05

    if time_format == HHMMSS:
        t0d = dt.datetime(1970, 1, 1, int(t0 / 3600),
                          int((t0 - int(t0 / 3600) * 3600) / 60), int(t0 % 60),
                          round(round(t0 % 1, 3) * 1000000))
        t1d = dt.datetime(1970, 1, 1, int(t1 / 3600),
                          int((t1 - int(t1 / 3600) * 3600) / 60), int(t1 % 60),
                          round(round(t1 % 1, 3) * 1000000))
        subjectPositiond = dt.datetime(
            1970, 1, 1, int(subjectPosition / 3600),
            int((subjectPosition - int(subjectPosition / 3600) * 3600) / 60),
            int(subjectPosition % 60),
            round(round(subjectPosition % 1, 3) * 1000000))

    if time_format == S:
        t0d, t1d = t0, t1
        subjectPositiond = subjectPosition

    plt.xlim(t0d, t1d)
    plt.yticks(range(len(lbl) + 1), np.array(lbl))

    count = 0
    flagFirstSubject = True

    for subject in all_project_subjects:
        if subject not in obs:
            continue

        if not flagFirstSubject:
            if excludeBehaviorsWithoutEvents:
                count += 1
            ax.axhline(y=(count - 1), linewidth=1, color="black")
            ax.hlines(np.array([count]),
                      np.array([0]),
                      np.array([0]),
                      lw=LINE_WIDTH,
                      color=col)
        else:
            flagFirstSubject = False

        ax.text(subjectPositiond, count - 0.5, subject)

        behaviors = obs[subject]

        x1, x2, y, col, pointsx, pointsy, guide = [], [], [], [], [], [], []
        col_count = 0

        for bm_json in all_behaviors:
            if bm_json in obs[subject]:
                if obs[subject][bm_json]:
                    for t1, t2 in obs[subject][bm_json]:
                        if t1 == t2:
                            pointsx.append(t1)
                            pointsy.append(count)
                            ax.axhline(y=count,
                                       linewidth=1,
                                       color="lightgray",
                                       zorder=-1)
                        else:
                            x1.append(t1)
                            x2.append(t2)
                            y.append(count)

                            col.append(
                                utilities.behavior_color(
                                    plot_colors,
                                    all_project_behaviors.index(
                                        json.loads(bm_json)[0])))
                            ax.axhline(y=count,
                                       linewidth=1,
                                       color="lightgray",
                                       zorder=-1)
                    count += 1
                else:
                    x1.append(0)
                    x2.append(0)
                    y.append(count)
                    col.append("white")
                    ax.axhline(y=count,
                               linewidth=1,
                               color="lightgray",
                               zorder=-1)
                    count += 1

            else:
                if not excludeBehaviorsWithoutEvents:
                    x1.append(0)
                    x2.append(0)
                    y.append(count)
                    col.append("white")
                    ax.axhline(y=count,
                               linewidth=1,
                               color="lightgray",
                               zorder=-1)
                    count += 1

            col_count += 1

        if time_format == HHMMSS:
            ax.hlines(np.array(y),
                      np.array([
                          dt.datetime(1970, 1, 1, int(p / 3600),
                                      int((p - int(p / 3600) * 3600) / 60),
                                      int(p % 60),
                                      round(round(p % 1, 3) * 1e6)) for p in x1
                      ]),
                      np.array([
                          dt.datetime(1970, 1, 1, int(p / 3600),
                                      int((p - int(p / 3600) * 3600) / 60),
                                      int(p % 60),
                                      round(round(p % 1, 3) * 1e6)) for p in x2
                      ]),
                      lw=LINE_WIDTH,
                      color=col)

        if time_format == S:
            ax.hlines(np.array(y),
                      np.array(x1),
                      np.array(x2),
                      lw=LINE_WIDTH,
                      color=col)

        if time_format == HHMMSS:

            ax.plot(
                np.array([
                    dt.datetime(1970, 1, 1, int(p / 3600),
                                int((p - int(p / 3600) * 3600) / 60),
                                int(p % 60), round(round(p % 1, 3) * 1e6))
                    for p in pointsx
                ]), pointsy, "r^")

        if time_format == S:
            ax.plot(pointsx, pointsy, "r^")

    fig.canvas.mpl_connect("draw_event", on_draw)
    plt.show()

    return True
コード例 #9
0
ファイル: plot_events.py プロジェクト: olivierfriard/BORIS
def create_events_plot(pj,
                       selected_observations,
                       parameters,
                       plot_colors=BEHAVIORS_PLOT_COLORS,
                       plot_directory="",
                       file_format="png"):


    selected_subjects = parameters["selected subjects"]
    selected_behaviors = parameters["selected behaviors"]
    include_modifiers = parameters["include modifiers"]
    interval = parameters[TIME_INTERVAL]
    start_time = parameters[START_TIME]
    end_time = parameters[END_TIME]

    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 modifiers not to be included set modifiers to ""
    if not include_modifiers:
        cursor.execute("UPDATE aggregated_events SET modifiers = ''")

    cursor.execute("SELECT distinct behavior, modifiers FROM aggregated_events")
    distinct_behav_modif = [[rows["behavior"], rows["modifiers"]] 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, "-"])

    distinct_behav_modif = sorted(distinct_behav_modif)
    max_len = len(distinct_behav_modif)

    all_behaviors = [pj[ETHOGRAM][x][BEHAVIOR_CODE] for x in utilities.sorted_keys(pj[ETHOGRAM])]

    par1 = 1
    bar_height = 0.5
    init = dt.datetime(2017, 1, 1)

    for obs_id in selected_observations:

        if len(selected_subjects) > 1:
            fig, axs = plt.subplots(figsize=(20, 8), nrows=len(selected_subjects), ncols=1, sharex=True)
        else:
            fig, ax = plt.subplots(figsize=(20, 8), nrows=len(selected_subjects), ncols=1, sharex=True)
            axs = np.ndarray(shape=(1), dtype=type(ax))
            axs[0] = ax


        ok, msg, db_connector = db_functions.load_aggregated_events_in_db(
            pj,
            selected_subjects,
            [obs_id],
            selected_behaviors)

        cursor = db_connector.cursor()
        # if modifiers not to be included set modifiers to ""
        if not include_modifiers:
            cursor.execute("UPDATE aggregated_events SET modifiers = ''")
        cursor = db_connector.cursor()

        cursor.execute("SELECT distinct behavior, modifiers FROM aggregated_events")
        distinct_behav_modif = [[rows["behavior"], rows["modifiers"]] for rows in cursor.fetchall()]

        # add selected behaviors that are not observed
        if not parameters["exclude behaviors"]:
            for behav in selected_behaviors:
                if [x for x in distinct_behav_modif if x[0] == behav] == []:
                    distinct_behav_modif.append([behav, "-"])

        distinct_behav_modif = sorted(distinct_behav_modif)
        max_len = len(distinct_behav_modif)


        # time
        obs_length = project_functions.observation_total_length(pj[OBSERVATIONS][obs_id])
        if obs_length == -1: # media length not available
            interval = TIME_EVENTS

        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, ))

        ylabels = [" ".join(x) for x in distinct_behav_modif]
        for ax_idx, subject in enumerate(selected_subjects):

            if parameters["exclude behaviors"]:
                cursor.execute("SELECT distinct behavior, modifiers FROM aggregated_events WHERE subject = ?", (subject, ))
                distinct_behav_modif = [[rows["behavior"], rows["modifiers"]] for rows in cursor.fetchall()]

                # add selected behaviors that are not observed
                if not parameters["exclude behaviors"]:
                    for behav in selected_behaviors:
                        if [x for x in distinct_behav_modif if x[0] == behav] == []:
                            distinct_behav_modif.append([behav, "-"])

                distinct_behav_modif = sorted(distinct_behav_modif)
                max_len = len(distinct_behav_modif)
                ylabels = [" ".join(x) for x in distinct_behav_modif]

            if not ax_idx:
                axs[ax_idx].set_title("Observation {}\n{}".format(obs_id, subject), fontsize=14)
            else:
                axs[ax_idx].set_title(subject, fontsize=14)
            bars = {}
            i = 0
            for behavior_modifiers in distinct_behav_modif:
                behavior, modifiers = behavior_modifiers
                behavior_modifiers_str = "|".join(behavior_modifiers) if modifiers else behavior
                bars[behavior_modifiers_str] = []

                # total duration
                cursor.execute(("SELECT start,stop FROM aggregated_events "
                                "WHERE observation = ? AND subject = ? AND behavior = ? AND modifiers = ?"),
                               (obs_id, subject, behavior, modifiers,))
                for row in cursor.fetchall():
                    bars[behavior_modifiers_str].append((row["start"], row["stop"]))

                    start_date = matplotlib.dates.date2num(init + dt.timedelta(seconds=row["start"]))
                    end_date = matplotlib.dates.date2num(
                        init + dt.timedelta(seconds=row["stop"] + POINT_EVENT_PLOT_DURATION * (row["stop"] == row["start"])))
                    try:
                        bar_color = utilities.behavior_color(plot_colors, all_behaviors.index(behavior))
                    except Exception:
                        bar_color = "darkgray"
                    bar_color = POINT_EVENT_PLOT_COLOR if row["stop"] == row["start"] else bar_color

                    # sage colors removed from matplotlib colors list
                    if bar_color in ["sage", "darksage", "lightsage"]:
                        bar_color = {"darksage": "#598556", "lightsage": "#bcecac", "sage": "#87ae73"}[bar_color]

                    try:
                        axs[ax_idx].barh((i * par1) + par1, end_date - start_date, left=start_date, height=bar_height,
                                         align="center", edgecolor=bar_color, color=bar_color, alpha=1)
                    except Exception:
                        axs[ax_idx].barh((i * par1) + par1, end_date - start_date, left=start_date, height=bar_height,
                                         align="center", edgecolor="darkgray", color="darkgray", alpha=1)

                i += 1

            axs[ax_idx].set_ylim(bottom=0, top=(max_len * par1) + par1)
            pos = np.arange(par1, max_len * par1 + par1 + 1, par1)
            axs[ax_idx].set_yticks(pos[:len(ylabels)])

            axs[ax_idx].set_yticklabels(ylabels, fontdict={"fontsize": 10})

            axs[ax_idx].set_ylabel("Behaviors" + " (modifiers)" * include_modifiers, fontdict={"fontsize": 10})

            axs[ax_idx].set_xlim(left=matplotlib.dates.date2num(init + dt.timedelta(seconds=min_time)),
                                 right=matplotlib.dates.date2num(init + dt.timedelta(seconds=max_time + 1)))

            axs[ax_idx].grid(color="g", linestyle=":")
            axs[ax_idx].xaxis_date()
            axs[ax_idx].xaxis.set_major_formatter(DateFormatter("%H:%M:%S"))
            axs[ax_idx].set_xlabel("Time (HH:MM:SS)", fontdict={"fontsize": 12})
            axs[ax_idx].invert_yaxis()

        fig.autofmt_xdate()
        plt.tight_layout()

        if len(selected_observations) > 1:
            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()
コード例 #10
0
ファイル: plot_events.py プロジェクト: olivierfriard/BORIS
def plot_time_ranges(pj, time_format, plot_colors, obs, obsId, minTime, videoLength, excludeBehaviorsWithoutEvents, line_width):
    """
    create "hlines" matplotlib plot
    used by plot_event function (legacy)
    """

    def on_draw(event):
        # http://matplotlib.org/faq/howto_faq.html#move-the-edge-of-an-axes-to-make-room-for-tick-labels
        bboxes = []
        for label in labels:
            bbox = label.get_window_extent()
            bboxi = bbox.inverse_transformed(fig.transFigure)
            bboxes.append(bboxi)

        bbox = mtransforms.Bbox.union(bboxes)
        if fig.subplotpars.left < bbox.width:
            fig.subplots_adjust(left=1.1*bbox.width)
            fig.canvas.draw()
        return False

    LINE_WIDTH = line_width
    all_behaviors, observedBehaviors = [], []
    maxTime = 0  # max time in all events of all subjects

    # all behaviors defined in project without modifiers
    all_project_behaviors = [pj[ETHOGRAM][idx]["code"] for idx in utilities.sorted_keys(pj[ETHOGRAM])]
    all_project_subjects = [NO_FOCAL_SUBJECT] + [pj[SUBJECTS][idx]["name"] for idx in utilities.sorted_keys(pj[SUBJECTS])]

    for subject in obs:

        for behavior_modifiers_json in obs[subject]:

            behavior_modifiers = json.loads(behavior_modifiers_json)

            if not excludeBehaviorsWithoutEvents:
                observedBehaviors.append(behavior_modifiers_json)
            else:
                if obs[subject][behavior_modifiers_json]:
                    observedBehaviors.append(behavior_modifiers_json)

            if not behavior_modifiers_json in all_behaviors:
                all_behaviors.append(behavior_modifiers_json)

            for t1, t2 in obs[subject][behavior_modifiers_json]:
                maxTime = max(maxTime, t1, t2)

        observedBehaviors.append("")

    lbl = []
    if excludeBehaviorsWithoutEvents:
        for behav_modif_json in observedBehaviors:

            if not behav_modif_json:
                lbl.append("")
                continue

            behav_modif = json.loads(behav_modif_json)
            if len(behav_modif) == 2:
                lbl.append("{0} ({1})".format(behav_modif[0], behav_modif[1]))
            else:
                lbl.append(behav_modif[0])

    else:
        all_behaviors.append('[""]') # empty json list element
        for behav_modif_json in all_behaviors:

            behav_modif = json.loads(behav_modif_json)
            if len(behav_modif) == 2:
                lbl.append("{0} ({1})".format(behav_modif[0], behav_modif[1]))
            else:
                lbl.append(behav_modif[0])
        lbl = lbl[:] * len(obs)


    lbl = lbl[:-1]  # remove last empty line

    fig = plt.figure(figsize=(20, 10))
    fig.suptitle("Time diagram of observation {}".format(obsId), fontsize=14)
    ax = fig.add_subplot(111)
    labels = ax.set_yticklabels(lbl)

    ax.set_ylabel("Behaviors")

    if time_format == HHMMSS:
        fmtr = matplotlib.dates.DateFormatter("%H:%M:%S") # %H:%M:%S:%f
        ax.xaxis.set_major_formatter(fmtr)
        ax.set_xlabel("Time (hh:mm:ss)")
    else:
        ax.set_xlabel("Time (s)")

    plt.ylim(len(lbl), -0.5)

    if not videoLength:
        videoLength = maxTime

    if pj[OBSERVATIONS][obsId]["time offset"]:
        t0 = round(pj[OBSERVATIONS][obsId]["time offset"] + minTime)
        t1 = round(pj[OBSERVATIONS][obsId]["time offset"] + videoLength + 2)
    else:
        t0 = round(minTime)
        t1 = round(videoLength)
    subjectPosition = t0 + (t1 - t0) * 0.05

    if time_format == HHMMSS:
        t0d = dt.datetime(1970, 1, 1, int(t0 / 3600), int((t0 - int(t0 / 3600) * 3600) / 60), int(t0 % 60), round(round(t0 % 1, 3) * 1000000))
        t1d = dt.datetime(1970, 1, 1, int(t1 / 3600), int((t1 - int(t1 / 3600) * 3600) / 60), int(t1 % 60), round(round(t1 % 1, 3) * 1000000))
        subjectPositiond = dt.datetime(1970, 1, 1, int(subjectPosition / 3600), int((subjectPosition - int(subjectPosition / 3600) * 3600) / 60), int(subjectPosition % 60), round(round(subjectPosition % 1, 3) * 1000000))

    if time_format == S:
        t0d, t1d = t0, t1
        subjectPositiond = subjectPosition

    plt.xlim(t0d, t1d)
    plt.yticks(range(len(lbl) + 1), np.array(lbl))

    count = 0
    flagFirstSubject = True

    for subject in all_project_subjects:
        if subject not in obs:
            continue

        if not flagFirstSubject:
            if excludeBehaviorsWithoutEvents:
                count += 1
            ax.axhline(y=(count-1), linewidth=1, color="black")
            ax.hlines(np.array([count]), np.array([0]), np.array([0]), lw=LINE_WIDTH, color=col)
        else:
            flagFirstSubject = False

        ax.text(subjectPositiond, count - 0.5, subject)

        behaviors = obs[subject]

        x1, x2, y, col, pointsx, pointsy, guide = [], [], [], [], [], [], []
        col_count = 0

        for bm_json in all_behaviors:
            if bm_json in obs[subject]:
                if obs[subject][bm_json]:
                    for t1, t2 in obs[subject][bm_json]:
                        if t1 == t2:
                            pointsx.append(t1)
                            pointsy.append(count)
                            ax.axhline(y=count, linewidth=1, color="lightgray", zorder=-1)
                        else:
                            x1.append(t1)
                            x2.append(t2)
                            y.append(count)

                            col.append(utilities.behavior_color(plot_colors, all_project_behaviors.index(json.loads(bm_json)[0])))
                            ax.axhline(y=count, linewidth=1, color="lightgray", zorder=-1)
                    count += 1
                else:
                    x1.append(0)
                    x2.append(0)
                    y.append(count)
                    col.append("white")
                    ax.axhline(y=count, linewidth=1, color="lightgray", zorder=-1)
                    count += 1

            else:
                if not excludeBehaviorsWithoutEvents:
                    x1.append(0)
                    x2.append(0)
                    y.append(count)
                    col.append("white")
                    ax.axhline(y=count, linewidth=1, color="lightgray", zorder=-1)
                    count += 1

            col_count += 1

        if time_format == HHMMSS:
            ax.hlines(np.array(y), np.array([dt.datetime(1970, 1, 1, int(p / 3600),
                                                               int((p - int(p / 3600) * 3600) / 60),
                                                               int(p % 60), round(round(p % 1, 3) * 1e6))
                                            for p in x1]),
            np.array([dt.datetime(1970, 1, 1, int(p / 3600), int((p - int(p / 3600) * 3600) / 60), int(p % 60), round(round(p % 1, 3) * 1e6)) for p in x2]),
            lw=LINE_WIDTH, color=col)

        if time_format == S:
            ax.hlines(np.array(y), np.array(x1), np.array(x2), lw=LINE_WIDTH, color=col)

        if time_format == HHMMSS:

            ax.plot(
                np.array([
                    dt.datetime(1970, 1, 1, int(p / 3600),
                                int((p - int(p / 3600) * 3600) / 60), int(p % 60),
                                round(round(p % 1, 3) * 1e6)) for p in pointsx
                ]), pointsy, "r^")

        if time_format == S:
            ax.plot(pointsx, pointsy, "r^")

    fig.canvas.mpl_connect("draw_event", on_draw)
    plt.show()

    return True