Exemple #1
0
def generate_all_output(
    experiments: List[Experiment],
    config: Configuration = Configuration()) -> str:
    """
    Generates a string in csv format of all measures specified in config file for a
    list of experiments.
    Args:
        experiments (List[Experiment]): List of experiments.
        config (Configuration): Configuration.
    """
    region_measures = config.measures.region
    trial_measures = config.measures.trial
    columns = config.output.columns

    output = ",".join([value.header for value in columns.values()]) + "\n"

    for experiment in experiments:
        for trial in experiment.trials.values():
            for (measure, value) in trial_measures.items():
                output += measure_output(measure, value.cutoff, columns,
                                         experiment, trial, None)
            for region in trial.item.regions:
                for (measure, value) in region_measures.items():
                    output += measure_output(measure, value.cutoff, columns,
                                             experiment, trial, region)
    return output
Exemple #2
0
def generate_all_output_wide_format(
    experiments: List[Experiment],
    config: Configuration = Configuration()) -> str:
    """
    Generates a string in csv format of all measures specified in config file for a
    list of experiments, with all measures as columns.

    Args:
        experiments (List[Experiment]): List of experiments.
        config (Configuration): Configuration.
    """
    columns: Dict[str, OutputColumnConfig] = {
        **config.output.columns,
        **config.measures.all,
    }
    output = ",".join([value.header for value in columns.values()]) + "\n"

    for experiment in experiments:
        for trial in experiment.trials.values():
            for region in trial.item.regions:
                output += (
                    ",".join(
                        map(
                            lambda col: write_column(
                                col[0],
                                experiment,
                                trial,
                                region,
                                col[0],
                                col[1].cutoff,  # pylint: disable=no-member
                            ),
                            columns.items(),
                        )) + "\n")
    return output
Exemple #3
0
def calculate_all_measures(
        experiments: List[Experiment],
        output_file: str = None,
        config: Configuration = Configuration(),
):
    """
    Given an array of experiments and config file, calculate all measures specified in the
    config file for the experiment, and optionally output the results as a csv.

    Args:
        experiments (List[Experiment]): List of experiments to calculate measures for.
        output_file (str): Name of output file. if `None`, no file is produced.
        config (Configuration): SideEye configuration.
    """
    wide_format = config.wide_format

    for measure in config.measures.names:
        calculate_measure(experiments, measure, config.terminal_output)

    output_text = (generate_all_output_wide_format(experiments, config) if
                   wide_format else generate_all_output(experiments, config))
    if output_file is not None:
        with open(output_file, "w") as output:
            output.write(output_text)

    return output_text
Exemple #4
0
def get_new_fixations(
    new_fixation: Fixation,
    fixations: List[Fixation],
    config: ASCParsingConfig = Configuration().asc_parsing,
) -> List[Fixation]:
    """Append a new fixation or merge with the previous fixation."""
    if fixations and new_fixation.duration() < config.fixation_min_cutoff:
        old_fix = fixations[-1]
        return fixations[:-1] + [
            Fixation(
                Point(old_fix.char, old_fix.line),
                old_fix.start,
                new_fixation.end,
                old_fix.index,
                old_fix.region,
            )
        ]
    if fixations and fixations[-1].duration() < config.fixation_min_cutoff:
        old_fix = fixations[-1]
        return fixations[:-1] + [
            Fixation(
                Point(new_fixation.char, new_fixation.line),
                old_fix.start,
                new_fixation.end,
                old_fix.index,
                new_fixation.region,
            )
        ]
    return fixations[:] + [new_fixation]
Exemple #5
0
def parse_files(
        experiment_files: List[str],
        region_file: str,
        config: Configuration = Configuration(),
) -> List[Experiment]:
    """
    Given a list of DA1 or ASC files, a region file, and config file, parse all files in
    the list into Experiments. If config is not provided, default config will be used.

    Args:
        experiment_files: List of DA1 or ASC files.
        region_file: Name of region file (.cnt, .reg, or .txt).
        config (Config): Configuration.
    """
    verbose = config.terminal_output

    if region_file[-4:].lower() == ".txt":
        items = region.textfile(region_file, verbose=verbose)
    else:
        items = region.file(region_file, config, verbose=verbose)
    experiments: List[Experiment] = []
    for experiment_file in experiment_files:
        if experiment_file[-4:].lower() == ".da1":
            experiments += [da1.parse(experiment_file, items, config)]
        elif experiment_file[-4:].lower() == ".asc":
            experiments += [
                asc.parse(experiment_file, items, config.asc_parsing)
            ]
        else:
            print("Skipping %s: not a DA1 or ASC file." % experiment_file)

    return experiments
Exemple #6
0
def parse(
    experiment_file: str,
    region_file: str,
    config: Configuration = Configuration()) -> Experiment:
    """
    Given a DA1 file and region file, and config file, parse an Experiment. If
    config is not provided, default config will be used.

    Args:
        experiment_file (str): Name of DA1 or ASC file.
        region_file: Name of region file (.cnt, .reg, or .txt).
        config (Configuration): Configuration.
    """
    verbose = config.terminal_output

    if region_file[-4:].lower() == ".txt":
        items = region.textfile(region_file, verbose=verbose)
    else:
        items = region.file(region_file, config, verbose=verbose)

    if experiment_file[-4:].lower() == ".da1":
        experiment = da1.parse(experiment_file, items, config)
    if experiment_file[-4:].lower() == ".asc":
        experiment = asc.parse(experiment_file, items, config.asc_parsing)
    return experiment
Exemple #7
0
def file(
    filename: str, config: Configuration = Configuration(), verbose: int = 0
) -> Dict[ItemNum, Dict[Condition, Item]]:
    """
    Parses a .reg or .cnt file into a dictionary of sideeye Item objects.

    Args:
        filename (str): Region filename.
        config (Configuration): Configuration.
    """
    if verbose > 0:
        print("\nParsing region file: %s" % filename)

    number_location = config.region_fields.number
    condition_location = config.region_fields.condition
    boundaries_start = config.region_fields.boundaries_start
    includes_y = config.region_fields.includes_y

    validate_region_file(filename)

    def line_to_regions(line):
        """Helper function to convert a list of region boundaries into an item."""
        regions = []
        if includes_y:
            for boundary in range(0, len(line) - 3, 2):
                x_start = line[boundary]
                y_start = line[boundary + 1]
                x_end = line[boundary + 2]
                y_end = line[boundary + 3]
                regions += [Region(Point(x_start, y_start), Point(x_end, y_end))]
        else:
            for boundary in range(0, len(line) - 1):
                x_start = line[boundary]
                x_end = line[boundary + 1]
                regions += [Region(Point(x_start, 0), Point(x_end, 0))]
        return regions

    with open(filename, "r") as region_file:
        items: DefaultDict[ItemNum, Dict[Condition, Item]] = defaultdict(dict)
        for region_line in region_file:
            split_line = region_line.split()
            condition = split_line[condition_location]
            number = split_line[number_location]
            line = [int(x) for x in split_line]
            if verbose == 2 or verbose >= 5:
                print("\tParsing item: %s, condition: %s" % (number, condition))
            items[number][condition] = Item(
                number, condition, line_to_regions(line[boundaries_start:])
            )
        return items
Exemple #8
0
def generate_trial_output(
    experiments: List[Experiment],
    config: Configuration = Configuration()) -> str:
    """
    Generates a string in csv format of list of experiments' trial measures using columns and
    measures specified in config file.

    Args:
        experiments (List[Experiment]): List of experiments.
        config (Configuration): Configuration.
    """
    measures = config.measures.trial
    columns = config.output.trial
    output = ",".join([value.header for value in columns.values()]) + "\n"

    for experiment in experiments:
        for trial in experiment.trials.values():
            for (measure, value) in measures.items():
                measure_output(measure, value.cutoff, columns, experiment,
                               trial, None)
    return output
Exemple #9
0
def parse(
    asc_file: str,
    items: Dict[Condition, Dict[ItemNum, Item]],
    config: ASCParsingConfig = Configuration().asc_parsing,
):
    """
    Parses a .ASC file into an Experiment object.

    Args:
        asc_file (string): Path to .ASC file.
        items (Dict[str, Dict[str, Item]]): List of items in experiments.
        config (ASCParsingConfig): Configuration for .ASC parsing.
    """
    with open(asc_file) as file:
        trials = get_trials(file.read(), items, config)
        return Experiment(
            "".join(os.path.split(asc_file)[1].split(".")[:-1]),
            trials,
            asc_file,
            datetime.fromtimestamp(os.path.getmtime(asc_file)),
        )
Exemple #10
0
def parse(
    filename: str,
    items: Dict[ItemNum, Dict[Condition, Item]],
    config: Configuration = Configuration(),
    da1_type: str = None,
) -> Experiment:
    """
    Parses DA1-like files into sideeye Experiment objects, given column positions.

    Args:
        filename (str): DA1 file.
        items (Dict[ItemNum, Dict[Condition, Item]]): List of items in the experiment.
        da1_type (str): Type of DA1 file - `timdrop`, `robodoc`, or `None` for any other type.
    """
    if config.terminal_output > 0:
        print("\nParsing DA1 file: %s" % filename)

    validate(filename, config.da1_fields.fixation_start, da1_type)

    def parse_fixations(line, item):
        """Parses a list of (x, y, start time, end time) numbers into a list of Fixations."""
        fixations = []
        for pos in range(0, len(line), 4):
            x_pos = line[pos]
            y_pos = line[pos + 1]
            start = line[pos + 2]
            end = line[pos + 3]
            if (end - start) > config.cutoffs.min and (
                    config.cutoffs.max < 0 or
                (end - start) < config.cutoffs.max):
                fixations += [
                    Fixation(
                        Point(x_pos, y_pos),
                        start,
                        end,
                        len(fixations),
                        item.find_region(x_pos, y_pos),
                    )
                ]
            else:
                fixations += [
                    Fixation(
                        Point(x_pos, y_pos),
                        start,
                        end,
                        len(fixations),
                        item.find_region(x_pos, y_pos),
                        excluded=True,
                    )
                ]

        return fixations

    with open(filename) as da1_file:
        trials: List[Trial] = []
        for da1_line in da1_file:
            split_line = da1_line.split()
            number = split_line[config.da1_fields.number]
            condition = split_line[config.da1_fields.condition]
            line: List[int] = [int(x) for x in split_line]
            if config.terminal_output == 2 or config.terminal_output >= 5:
                print("\tParsing trial: %s" % line[config.da1_fields.index])
            if items[number][condition]:
                fixations = parse_fixations(
                    line[config.da1_fields.fixation_start:],
                    items[number][condition])
                trials += [
                    Trial(
                        line[config.da1_fields.index],
                        line[config.da1_fields.time],
                        items[number][condition],
                        fixations,
                        config.cutoffs.include_fixation,
                        config.cutoffs.include_saccades,
                    )
                ]
            else:
                print(
                    "Item number",
                    number,
                    ", condition",
                    condition,
                    "does not exist. It was not added to the Experiment object.",
                )

        return Experiment("".join(os.path.split(filename)[1].split(".")[:-1]),
                          trials, filename)
Exemple #11
0
def get_trials(
    asc: str,
    items: Dict[Condition, Dict[ItemNum, Item]],
    config: ASCParsingConfig = Configuration().asc_parsing,
) -> List[Trial]:
    """
    Parses .ASC text into a list of Trial objects.

    Args:
        asc (string): Text of .ASC file.
        items (Dict[str, Dict[str, Item]]): List of items in experiments.
        config (ASCParsingConfig): Configuration for .ASC parsing.
    """
    characters: List[CharPosition] = []
    fixations: List[Fixation] = []
    fixation_start_time = 0
    trials: List[Trial] = []
    exclude = False
    blinks = 0
    start_time = 0
    condition: Optional[str] = None
    item: Optional[str] = None
    for line in asc.split("\n"):
        if line.split() and line.split()[0] in LINE_TYPES:
            start_time = get_start(line) or start_time
            condition = get_condition(line) or condition
            item = get_item(line) or item
            char = get_char(line)
            characters = characters + [char] if char else characters
            new_fixation, fixation_start_time = (
                get_fixation(
                    line,
                    characters,
                    items[item][condition],
                    len(fixations),
                    fixation_start_time,
                )
                if start_time
                and item
                and condition
                and item in items
                and condition in items[item]
                else (None, fixation_start_time)
            )
            fixations = (
                get_new_fixations(new_fixation, fixations, config)
                if new_fixation
                else fixations
            )
            if (
                config.max_saccade_dur
                and len(fixations) > 1
                and fixations[-1].start - fixations[-2].end > config.max_saccade_dur
            ):
                exclude = True
            blink_dur = get_blink_dur(line)
            if blink_dur:
                blinks += 1
                if config.blink_max_dur and blink_dur > config.blink_max_dur:
                    exclude = True
                if config.blink_max_count and blinks > config.blink_max_count:
                    exclude = True
            end_time = get_end(line)
            if end_time:
                if (
                    item
                    and condition
                    and item in items
                    and condition in items[item]
                    and not exclude
                ):
                    trials += [
                        Trial(
                            len(trials),
                            end_time - start_time,
                            items[item][condition],
                            fixations,
                        )
                    ]
                start_time = 0
                fixations = []
                fixation_start_time = 0
                characters = []
                exclude = False
                blinks = 0
                item = None
                condition = None
    return trials