Пример #1
0
 def test_error1(self):
     try:
         1/0
     except:
         r = utilities.error_info(sys.exc_info())
         assert str(r[0]) == 'division by zero'
         assert r[1] == "test_utilities.py"
Пример #2
0
def error_message(task: str, exc_info: tuple) -> None:
    """
    show details about the error

    """
    error_type, error_file_name, error_lineno = utilities.error_info(exc_info)
    QMessageBox.critical(None, programName,
                         (f"An error occured during {task}.<br>"
                          f"BORIS version: {version.__version__}<br>"
                          f"Error: {error_type}<br>"
                          f"in {error_file_name} "
                          f"at line # {error_lineno}<br><br>"
                          "Please report this problem to improve the software at:<br>"
                          '<a href="https://github.com/olivierfriard/BORIS/issues">https://github.com/olivierfriard/BORIS/issues</a>'
                          ))
Пример #3
0
def behavior_binary_table(pj: dict):
    """
    ask user for parameters for behavior binary table
    call create_behavior_binary_table
    """

    result, selected_observations = select_observations.select_observations(
        pj, MULTIPLE, "Select observations for the behavior binary table")

    if not selected_observations:
        return
    # check if state events are paired
    out = ""
    not_paired_obs_list = []
    for obs_id in selected_observations:
        r, msg = project_functions.check_state_events_obs(
            obs_id, pj[ETHOGRAM], pj[OBSERVATIONS][obs_id])

        if not r:
            out += f"Observation: <strong>{obs_id}</strong><br>{msg}<br>"
            not_paired_obs_list.append(obs_id)

    if out:
        out = f"The observations with UNPAIRED state events will be removed from the analysis<br><br>{out}"
        results = dialog.Results_dialog()
        results.setWindowTitle(f"{programName} - Check selected observations")
        results.ptText.setReadOnly(True)
        results.ptText.appendHtml(out)
        results.pbSave.setVisible(False)
        results.pbCancel.setVisible(True)

        if not results.exec_():
            return
    selected_observations = [
        x for x in selected_observations if x not in not_paired_obs_list
    ]
    if not selected_observations:
        return

    max_obs_length, selectedObsTotalMediaLength = project_functions.observation_length(
        pj, selected_observations)
    if max_obs_length == -1:  # media length not available, user choose to not use events
        return

    parameters = dialog.choose_obs_subj_behav_category(
        pj,
        selected_observations,
        maxTime=max_obs_length,
        flagShowIncludeModifiers=True,
        flagShowExcludeBehaviorsWoEvents=True,
        by_category=False)

    if not parameters[SELECTED_SUBJECTS] or not parameters[SELECTED_BEHAVIORS]:
        QMessageBox.warning(None, programName,
                            "Select subject(s) and behavior(s) to analyze")
        return

    # ask for time interval
    i, ok = QInputDialog.getDouble(None, "Behavior binary table",
                                   "Time interval (in seconds):", 1.0, 0.001,
                                   86400, 3)
    if not ok:
        return
    time_interval = utilities.float2decimal(i)
    '''
    iw = dialog.Info_widget()
    iw.lwi.setVisible(False)
    iw.resize(350, 200)
    iw.setWindowFlags(Qt.WindowStaysOnTopHint)

    iw.setWindowTitle("Behavior binary table")
    iw.label.setText("Creating the behavior binary table...")
    iw.show()
    QApplication.processEvents()
    '''

    results_df = create_behavior_binary_table(pj, selected_observations,
                                              parameters, time_interval)
    '''
    iw.hide()
    '''

    if "error" in results_df:
        QMessageBox.warning(None, programName, results_df["msg"])
        return

    # save results
    if len(selected_observations) == 1:
        extended_file_formats = [
            "Tab Separated Values (*.tsv)", "Comma Separated Values (*.csv)",
            "Open Document Spreadsheet ODS (*.ods)",
            "Microsoft Excel Spreadsheet XLSX (*.xlsx)",
            "Legacy Microsoft Excel Spreadsheet XLS (*.xls)", "HTML (*.html)"
        ]
        file_formats = ["tsv", "csv", "ods", "xlsx", "xls", "html"]

        file_name, filter_ = QFileDialog().getSaveFileName(
            None, "Save results", "", ";;".join(extended_file_formats))
        if not file_name:
            return

        output_format = file_formats[extended_file_formats.index(filter_)]

        if pathlib.Path(file_name).suffix != "." + output_format:
            file_name = str(pathlib.Path(file_name)) + "." + output_format
            # check if file with new extension already exists
            if pathlib.Path(file_name).is_file():
                if dialog.MessageDialog(
                        programName, f"The file {file_name} already exists.",
                    [CANCEL, OVERWRITE]) == CANCEL:
                    return
    else:
        items = ("Tab Separated Values (*.tsv)",
                 "Comma separated values (*.csv)",
                 "Open Document Spreadsheet (*.ods)",
                 "Microsoft Excel Spreadsheet XLSX (*.xlsx)",
                 "Legacy Microsoft Excel Spreadsheet XLS (*.xls)",
                 "HTML (*.html)")

        item, ok = QInputDialog.getItem(None, "Save results",
                                        "Available formats", items, 0, False)
        if not ok:
            return
        output_format = re.sub(".* \(\*\.", "", item)[:-1]

        export_dir = QFileDialog().getExistingDirectory(
            None,
            "Choose a directory to save results",
            os.path.expanduser("~"),
            options=QFileDialog.ShowDirsOnly)
        if not export_dir:
            return

    mem_command = ""
    for obs_id in results_df:

        for subject in results_df[obs_id]:

            if len(selected_observations) > 1:
                file_name_with_subject = str(
                    pathlib.Path(export_dir) /
                    utilities.safeFileName(obs_id + "_" +
                                           subject)) + "." + output_format
            else:
                file_name_with_subject = str(
                    os.path.splitext(file_name)[0] +
                    utilities.safeFileName("_" +
                                           subject)) + "." + output_format

            # check if file with new extension already exists
            if mem_command != OVERWRITE_ALL and pathlib.Path(
                    file_name_with_subject).is_file():
                if mem_command == "Skip all":
                    continue
                mem_command = dialog.MessageDialog(
                    programName,
                    f"The file {file_name_with_subject} already exists.",
                    [OVERWRITE, OVERWRITE_ALL, "Skip", "Skip all", CANCEL])
                if mem_command == CANCEL:
                    return
                if mem_command in ["Skip", "Skip all"]:
                    continue

            try:
                if output_format in ["csv", "tsv", "html"]:
                    with open(file_name_with_subject, "wb") as f:
                        f.write(
                            str.encode(results_df[obs_id][subject].export(
                                output_format)))

                if output_format in ["ods", "xlsx", "xls"]:
                    with open(file_name_with_subject, "wb") as f:
                        f.write(
                            results_df[obs_id][subject].export(output_format))

            except Exception:

                error_type, error_file_name, error_lineno = utilities.error_info(
                    sys.exc_info())
                logging.critical(
                    f"Error in behavior binary table function: {error_type} {error_file_name} {error_lineno}"
                )

                QMessageBox.critical(None, programName,
                                     f"Error saving file: {error_type}")
                return
Пример #4
0
def observation_to_behavioral_sequences(pj, selected_observations, parameters,
                                        behaviors_separator,
                                        separated_subjects, timed, file_name):

    try:
        with open(file_name, "w", encoding="utf-8") as out_file:
            for obs_id in selected_observations:
                # observation id
                out_file.write("\n" + f"# observation id: {obs_id}" + "\n")
                # observation description
                descr = pj[OBSERVATIONS][obs_id]["description"]
                if "\r\n" in descr:
                    descr = descr.replace("\r\n", "\n# ")
                elif "\r" in descr:
                    descr = descr.replace("\r", "\n# ")
                out_file.write(f"# observation description: {descr}\n\n")
                # media file name
                if pj[OBSERVATIONS][obs_id][TYPE] in [MEDIA]:
                    out_file.write(
                        f"# Media file name: {', '.join([os.path.basename(x) for x in pj[OBSERVATIONS][obs_id][FILE][PLAYER1]])}\n\n"
                    )
                if pj[OBSERVATIONS][obs_id][TYPE] in [LIVE]:
                    out_file.write(
                        f"# Live observation{os.linesep}{os.linesep}")

                # independent variables
                if INDEPENDENT_VARIABLES in pj[OBSERVATIONS][obs_id]:
                    out_file.write("# Independent variables\n")

                    for variable in pj[OBSERVATIONS][obs_id][
                            INDEPENDENT_VARIABLES]:
                        out_file.write(
                            f"# {variable}: {pj[OBSERVATIONS][obs_id][INDEPENDENT_VARIABLES][variable]}\n"
                        )
                out_file.write("\n")

                # one sequence for all subjects
                if not separated_subjects:
                    out = events_to_behavioral_sequences_all_subj(
                        pj, obs_id, parameters[SELECTED_SUBJECTS], parameters,
                        behaviors_separator)
                    if out:
                        out_file.write(out + "\n")

                # one sequence by subject
                if separated_subjects:
                    # selected subjects
                    for subject in parameters[SELECTED_SUBJECTS]:
                        out_file.write(
                            f"\n# {subject if subject else NO_FOCAL_SUBJECT}:\n"
                        )

                        if not timed:
                            out = events_to_behavioral_sequences(
                                pj, obs_id, subject, parameters,
                                behaviors_separator)
                        if timed:
                            out = events_to_timed_behavioral_sequences(
                                pj, obs_id, subject, parameters, 0.001,
                                behaviors_separator)

                        if out:
                            out_file.write(out + "\n")

            return True, ""

    except Exception:
        raise
        error_type, error_file_name, error_lineno = utilities.error_info(
            sys.exc_info())
        return False, f"{error_type} {error_file_name} {error_lineno}"
Пример #5
0
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()}
Пример #6
0
def synthetic_time_budget(pj: dict, selected_observations: list,
                          parameters_obs: dict):
    """
    create a synthetic time budget

    Args:
        pj (dict): project dictionary
        selected_observations (list): list of observations to include in time budget
        parameters_obs (dict):

    Returns:
        bool: True if everything OK
        str: message
        tablib.Dataset: dataset containing synthetic time budget data
    """
    try:
        selected_subjects = parameters_obs[SELECTED_SUBJECTS]
        selected_behaviors = parameters_obs[SELECTED_BEHAVIORS]
        include_modifiers = parameters_obs[INCLUDE_MODIFIERS]
        interval = parameters_obs["time"]
        start_time = parameters_obs["start time"]
        end_time = parameters_obs["end time"]

        parameters = [
            ["duration", "Total duration"],
            ["number", "Number of occurrences"],
            ["duration mean", "Duration mean"],
            ["duration stdev", "Duration std dev"],
            ["proportion of time", "Proportion of time"],
        ]

        data_report = tablib.Dataset()
        data_report.title = "Synthetic time budget"

        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

        db_connector.create_aggregate("stdev", 1, StdevFunc)
        cursor = db_connector.cursor()

        # modifiers
        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)

        param_header = ["", "Total length (s)"]
        subj_header, behav_header, modif_header = [""] * len(param_header), [
            ""
        ] * len(param_header), [""] * len(param_header)

        for subj in selected_subjects:
            for behavior_modifiers in distinct_behav_modif:
                behavior, modifiers = behavior_modifiers
                behavior_modifiers_str = "|".join(
                    behavior_modifiers) if modifiers else behavior
                for param in parameters:
                    subj_header.append(subj)
                    behav_header.append(behavior)
                    modif_header.append(modifiers)
                    param_header.append(param[1])
        '''
        if parameters_obs["group observations"]:
            cursor.execute("UPDATE aggregated_events SET observation = 'all' " )
            #selected_observations = ["all"]
        '''

        data_report.append(subj_header)
        data_report.append(behav_header)
        if include_modifiers:
            data_report.append(modif_header)
        data_report.append(param_header)

        # select time interval
        for obs_id in selected_observations:

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

            if not ok:
                return False, msg, None

            db_connector.create_aggregate("stdev", 1, StdevFunc)
            cursor = db_connector.cursor()

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

            # adapt start and stop to the selected time interval
            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,
                ))

            cursor.execute(
                "DELETE FROM aggregated_events WHERE observation = ? AND (start < ? AND stop < ?) OR (start > ? AND stop > ?)",
                (
                    obs_id,
                    min_time,
                    min_time,
                    max_time,
                    max_time,
                ))

            for subject in selected_subjects:

                # check if behaviors are to exclude from total time
                time_to_subtract = 0
                if EXCLUDED_BEHAVIORS in parameters_obs:
                    for excluded_behav in parameters_obs[EXCLUDED_BEHAVIORS]:
                        cursor.execute((
                            "SELECT SUM(stop-start) "
                            "FROM aggregated_events "
                            "WHERE observation = ? AND subject = ? AND behavior = ? "
                        ), (
                            obs_id,
                            subject,
                            excluded_behav,
                        ))
                        for row in cursor.fetchall():
                            if row[0] is not None:
                                time_to_subtract += row[0]

                for behavior_modifiers in distinct_behav_modif:
                    behavior, modifiers = behavior_modifiers
                    behavior_modifiers_str = "|".join(
                        behavior_modifiers) if modifiers else behavior

                    cursor.execute((
                        "SELECT SUM(stop-start), COUNT(*), AVG(stop-start), stdev(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
                                           f"{row[0]:.3f}")

                        behaviors[subject][behavior_modifiers_str][
                            "number"] = 0 if row[1] is None else row[1]
                        behaviors[subject][behavior_modifiers_str][
                            "duration mean"] = (0 if row[2] is None else
                                                f"{row[2]:.3f}")
                        behaviors[subject][behavior_modifiers_str][
                            "duration stdev"] = (0 if row[3] is None else
                                                 f"{row[3]:.3f}")

                        if behavior not in parameters_obs[EXCLUDED_BEHAVIORS]:
                            try:
                                behaviors[subject][behavior_modifiers_str][
                                    "proportion of time"] = (
                                        0 if row[0] is None else
                                        f"{row[0] / ((max_time - min_time) - time_to_subtract):.3f}"
                                    )
                            except ZeroDivisionError:
                                behaviors[subject][behavior_modifiers_str][
                                    "proportion of time"] = "-"
                        else:
                            # behavior subtracted
                            behaviors[subject][behavior_modifiers_str][
                                "proportion of time"] = (
                                    0 if row[0] is None else
                                    f"{row[0] / (max_time - min_time):.3f}")

            columns = [obs_id, f"{max_time - min_time:0.3f}"]
            for subj in selected_subjects:
                for behavior_modifiers in distinct_behav_modif:
                    behavior, modifiers = behavior_modifiers
                    behavior_modifiers_str = "|".join(
                        behavior_modifiers) if modifiers else behavior

                    for param in parameters:
                        columns.append(
                            behaviors[subj][behavior_modifiers_str][param[0]])

            data_report.append(columns)
    except Exception:

        error_type, error_file_name, error_lineno = utilities.error_info(
            sys.exc_info())
        logging.critical(
            f"Error in edit_event function: {error_type} {error_file_name} {error_lineno}"
        )

        msg = f"Error type: {error_type}\nError file name: {error_file_name}\nError line number: {error_lineno}"

        logging.critical(msg)

        return (False, msg, tablib.Dataset())

    return True, msg, data_report
Пример #7
0
    def filter(self):
        """
        filter events
        """
        if not self.logic.text():
            return
        if self.logic.text().count('"') % 2:
            QMessageBox.warning(self, programName,
                                f'Wrong number of double quotes (")')
            return

        sb_list = re.findall('"([^"]*)"', self.logic.text())

        self.out = []
        flag_error = False
        for obs_id in self.events:
            logic = self.logic.text()
            for sb in set(sb_list):
                logic = logic.replace(f'"{sb}"',
                                      f'self.events[obs_id]["{sb}"]')
                if sb not in self.events[obs_id]:
                    self.events[obs_id][sb] = io([0, 0])

            try:
                eval_result = eval(logic)
                for i in eval_result:
                    if not i.is_empty():
                        self.out.append([
                            obs_id, "", f"{i.lower}", f"{i.upper}",
                            f"{i.upper - i.lower:.3f}"
                        ])
            except KeyError:
                self.out.append(
                    [obs_id, "subject / behavior not found", "NA", "NA", "NA"])
            except Exception:
                # out += f"Error in {self.logic.text()}" + "\n"
                error_type, error_file_name, error_lineno = utilities.error_info(
                    sys.exc_info())
                self.out.append([
                    obs_id, f"Error in {self.logic.text()}: {error_type} ",
                    "NA", "NA", "NA"
                ])
                flag_error = True

        self.tw.clear()

        if flag_error or self.rb_details.isChecked():

            self.lb_results.setText(
                f"Results ({len(self.out)} event{'s'*(len(self.out) > 1)})")

            self.tw.setRowCount(len(self.out))
            self.tw.setColumnCount(len(
                self.details_header))  # obs_id, comment, start, stop, duration
            self.tw.setHorizontalHeaderLabels(self.details_header)

        if not flag_error and self.rb_summary.isChecked():

            summary = {}
            for row in self.out:
                obs_id, _, start, stop, duration = row
                if obs_id not in summary:
                    summary[obs_id] = []
                summary[obs_id].append(float(duration))

            self.out = []
            for obs_id in summary:

                self.out.append([
                    obs_id,
                    str(len(summary[obs_id])),
                    str(round(sum(summary[obs_id]), 3)),
                    str(round(statistics.mean(summary[obs_id]), 3)),
                    str(round(statistics.stdev(summary[obs_id]), 3))
                    if len(summary[obs_id]) > 1 else "NA"
                ])

            self.lb_results.setText(
                f"Results ({len(summary)} observation{'s'*(len(summary) > 1)})"
            )
            self.tw.setRowCount(len(summary))
            self.tw.setColumnCount(len(
                self.summary_header))  # obs_id, mean, stdev
            self.tw.setHorizontalHeaderLabels(self.summary_header)

        for r in range(len(self.out)):
            for c in range(self.tw.columnCount()):
                item = QTableWidgetItem()
                item.setText(self.out[r][c])
                item.setFlags(Qt.ItemIsEnabled)
                self.tw.setItem(r, c, item)