Exemplo n.º 1
0
def first_pass_fixation_count(trial: Trial,
                              region_number: int) -> RegionMeasure:
    """
    The number of fixations made in a region before leaving it during first pass.
    If the region was skipped this measure is None.

    ::

        fp_fixations = get_first_pass_fixations(trial, region_number)

        if length of fp_fixations is 0:
            return None
        else:
            return length of fp_fixations

    """
    region = region_exists(trial, region_number)
    fp_fixations = get_fp_fixations(trial, region_number)

    if not fp_fixations:
        return save_measure(trial, region, "first_pass_fixation_count", None,
                            None)

    return save_measure(trial, region, "first_pass_fixation_count",
                        len(fp_fixations), fp_fixations)
Exemplo n.º 2
0
def refixation_time(trial: Trial, region_number: int) -> RegionMeasure:
    """
    The sum of all first-pass fixations excluding the first
    fixation. If there was a single fixation in the region or it was skipped
    this measure is None.

    ::

        fp_fixations = get_first_pass_fixations(trial, region_number)

        if length of fp_fixations is 0 or 1:
            return None

        total = 0

        for fixation in fp_fixations[1:]:
            total += fixation.duration()

        return total

    """
    region = region_exists(trial, region_number)
    fp_fixations = get_fp_fixations(trial, region_number)

    if not fp_fixations or len(fp_fixations) == 1:
        return save_measure(trial, region, "refixation_time", None, None)

    total = 0
    for fixation in fp_fixations[1:]:
        total += fixation.duration()

    return save_measure(trial, region, "refixation_time", total,
                        fp_fixations[1:])
Exemplo n.º 3
0
def first_pass(trial: Trial, region_number: int) -> RegionMeasure:
    """
    The summed duration of all fixations in a region
    during first pass (i.e., before the reader fixates areas beyond the region).
    If this region is skipped during first pass, this measure is None.

    ::

        fp_fixations = get_first_pass_fixations(trial, region_number)

        if length of fp_fixations is 0:
            return None

        total = 0

        for fixation in fp_fixations:
            total += fixation.duration()

        return total

    """
    region = region_exists(trial, region_number)
    fp_fixations = get_fp_fixations(trial, region_number)

    if not fp_fixations:
        return save_measure(trial, region, "first_pass", None, None)

    total = 0
    for fixation in fp_fixations:
        total += fixation.duration()

    return save_measure(trial, region, "first_pass", total, fp_fixations)
Exemplo n.º 4
0
def total_time(trial: Trial, region_number: int) -> RegionMeasure:
    """
    The summed duration of all fixations in the region that
    occur at any time during the trial. If this region is never fixated this
    measure is 0.

    ::

        total = 0

        for fixation in trial:
            if fixation.region_number is region_number and fixation is not excluded:
                total += fixation.duration()

        return total

    """
    region = region_exists(trial, region_number)

    region_fixations: List[Fixation] = []
    total = 0
    for fixation in trial.fixations:
        if fixation.region.number is region_number and not fixation.excluded:
            region_fixations += [fixation]
            total += fixation.duration()

    return save_measure(trial, region, "total_time", total, region_fixations)
Exemplo n.º 5
0
def first_fixation_duration(trial: Trial, region_number: int) -> RegionMeasure:
    """
    The duration of the first fixation in a region during first pass reading
    (i.e., before the reader fixates areas beyond the region).
    If this region is skipped during first pass, this measure is None.

    ::

        fp_fixations = get_first_pass_fixations(trial, region_number)

        if length of fp_fixations is 0:
            return None
        else:
            return duration of first fixation in fp_fixations

    """
    region = region_exists(trial, region_number)
    fp_fixations = get_fp_fixations(trial, region_number)

    if not fp_fixations:
        return save_measure(trial, region, "first_fixation_duration", None,
                            None)
    return save_measure(
        trial,
        region,
        "first_fixation_duration",
        fp_fixations[0].duration(),
        [fp_fixations[0]],
    )
Exemplo n.º 6
0
def single_fixation_duration(trial: Trial,
                             region_number: int) -> RegionMeasure:
    """
    If there is only one fixation on the region during first pass reading, this
    measure is the duration of that fixation. If the region is skipped during
    first pass, the measure is None.

    ::

        fp_fixations = get_first_pass_fixations(trial, region_number)

        if length of fp_fixations is 1:
            return duration of fixation in fp_fixations
        else:
            return None

    """
    region = region_exists(trial, region_number)
    fp_fixations = get_fp_fixations(trial, region_number)

    if len(fp_fixations) == 1:
        return save_measure(
            trial,
            region,
            "single_fixation_duration",
            fp_fixations[0].duration(),
            [fp_fixations[0]],
        )
    return save_measure(trial, region, "single_fixation_duration", None, None)
Exemplo n.º 7
0
def skip(trial: Trial, region_number: int) -> RegionMeasure:
    """
    True if the reader fixates a region beyond the target region before
    fixating the target region or the target region is never fixated, False otherwise.

    ::

        if length of get_first_pass_fixations(trial, region_number) is 0:
            return True
        else return False

    """
    region = region_exists(trial, region_number)
    return save_measure(trial, region, "skip",
                        bool(not get_fp_fixations(trial, region_number)), None)
Exemplo n.º 8
0
def first_pass_regressions_out(trial: Trial,
                               region_number: int) -> RegionMeasure:
    """
    This measure is True if the reader made a regression out of the region on the
    first pass - that is, exited a region to the left after the first pass. The measure
    is False if they exited to the right, and None if the region was not fixated
    during first pass reading.

    ::

        fp_fixations = get_first_pass_fixations(trial, region_number)

        if length of fp_fixations is 0:
            return None

        next_fixation = next non-excluded fixation after last fixation in fp_fixations

        if next_fixation.region_number < region_number:
            return True
        else:
            return False

    """
    region = region_exists(trial, region_number)
    fp_fixations = get_fp_fixations(trial, region_number)

    if not fp_fixations:
        return save_measure(trial, region, "first_pass_regressions_out", None,
                            None)

    try:
        next_fix_idx = fp_fixations[-1].index + 1
        next_fix = trial.fixations[next_fix_idx]
        while next_fix.excluded and next_fix_idx < len(trial.fixations):
            next_fix_idx += 1
            next_fix = trial.fixations[next_fix_idx]
        if (next_fix.region.number is not None
                and next_fix.region.number < region_number):
            return save_measure(trial, region, "first_pass_regressions_out",
                                True, None)
    except IndexError:
        return save_measure(trial, region, "first_pass_regressions_out", False,
                            None)

    return save_measure(trial, region, "first_pass_regressions_out", False,
                        None)
Exemplo n.º 9
0
def spillover_time(trial: Trial, region_number: int) -> RegionMeasure:
    """
    The duration of fixations on the region immediately following
    the region of interest, where the previous fixation was on the region of interest.
    If there are no such fixations, the measure is None.

    ::

        total = 0
        visited_region = False

        for fixation in trial:
            if fixation is not excluded:
                if visited_region and fixation.region_number is not region_number + 1:
                    visited_region = False
                if fixation.region_number is region_number:
                    visited_region = True
                if visited_region and fixation.region_number is region_number + 1:
                    total += fixation.duration()

        if total is 0:
            return None

        return total

    """
    region = region_exists(trial, region_number)

    so_fixations: List[Fixation] = []
    total = 0
    visited_region = False
    for fixation in trial.fixations:
        if not fixation.excluded:
            if visited_region and fixation.region.number is not region_number + 1:
                visited_region = False
            if fixation.region.number is region_number:
                visited_region = True
            if visited_region and fixation.region.number is region_number + 1:
                so_fixations += [fixation]
                total += fixation.duration()

    if not total:
        return save_measure(trial, region, "spillover_time", None, None)
    return save_measure(trial, region, "spillover_time", total, so_fixations)
Exemplo n.º 10
0
def right_bounded_time(trial: Trial, region_number: int) -> RegionMeasure:
    """
    The summed duration of all fixations starting
    from the first fixation in the region, excluding any fixations in prior
    regions until the reader goes past the region (i.e., until the reader
    fixates areas beyond the region). If this region is skipped during first
    pass, this measure is None.

    ::

        if length of get_first_pass_fixations(trial, region_number) is 0:
            return None

        total = 0

        for fixation in trial:
            if fixation is not excluded:
                if fixation.region_number > region_number:
                    break
                if fixation.region_number is region_number:
                    total += fixation.duration()

        return total

    """
    region = region_exists(trial, region_number)

    if not get_fp_fixations(trial, region_number):
        return save_measure(trial, region, "right_bounded_time", None, None)

    rb_fixations: List[Fixation] = []
    total = 0
    for fixation in trial.fixations:
        if not fixation.excluded:
            if (fixation.region.number is not None
                    and fixation.region.number > region_number):
                break
            if fixation.region.number is region_number:
                rb_fixations += [fixation]
                total += fixation.duration()

    return save_measure(trial, region, "right_bounded_time", total,
                        rb_fixations)
Exemplo n.º 11
0
def go_past(trial: Trial, region_number: int) -> RegionMeasure:
    """
    Also known as regression path duration. The summed duration of all fixations
    starting from the first fixation in the region, including any fixations in
    prior regions until the reader goes past the region (i.e., before the reader
    fixates areas beyond the region). If this region is skipped during first pass,
    this measure is None.

    ::

        if length of get_first_pass_fixations(trial, region_number) is 0:
            return None

        total = 0

        for fixation in trial:
            if fixation is not excluded:
                if fixation.region_number > region_number:
                    break
                if total is not 0 or fixation.region_number is region_number:
                    total += fixation.duration()

        return total

    """
    region = region_exists(trial, region_number)

    if not get_fp_fixations(trial, region_number):
        return save_measure(trial, region, "go_past", None, None)

    gp_fixations: List[Fixation] = []
    total = 0
    for fixation in trial.fixations:
        if not fixation.excluded:
            if fixation.region.number and fixation.region.number > region_number:
                break
            if total or fixation.region.number is region_number:
                gp_fixations += [fixation]
                total += fixation.duration()

    return save_measure(trial, region, "go_past", total, gp_fixations)
Exemplo n.º 12
0
def second_pass(trial: Trial, region_number: int) -> RegionMeasure:
    """
    The summed duration of all fixations in the region that occur on a region
    after that region has been exited in either direction for the first time.
    If this region is never fixated this measure is 0.

    ::

        total = 0
        first_pass = False
        exited = False

        for fixation in trial:
            if fixation is not excluded:
                if fixation.region_number is region_number:
                    first_pass = True
                if first_pass and fixation.region_number is not region_number:
                    exited = True
                if first_pass and exited and fixation.region_number is region_number:
                    total += fixation.duration()

        return total

    """
    region = region_exists(trial, region_number)

    sp_fixations: List[Fixation] = []
    total = 0
    f_pass = False
    exited = False
    for fixation in trial.fixations:
        if not fixation.excluded:
            if fixation.region.number is region_number:
                f_pass = True
            if f_pass and fixation.region.number is not region_number:
                exited = True
            if f_pass and exited and fixation.region.number is region_number:
                sp_fixations += [fixation]
                total += fixation.duration()

    return save_measure(trial, region, "second_pass", total, sp_fixations)
Exemplo n.º 13
0
def first_pass_regressions_in(trial: Trial,
                              region_number: int) -> RegionMeasure:
    """
    This measure is True if the reader made a fixation in the region
    after fixating on any region to the right of it, False if they only fixated
    on the region after fixating on regions to the left, and None if the region
    was never fixated.

    ::

        region_fixations = [all non-excluded fixations in region]

        if length of region_fixations is 0:
            return None

        for fixation in region_fixations:
            if previous_fixation.region_number > region_number:
                return True

        return False

    """
    region = region_exists(trial, region_number)
    trial_fixations = [fix for fix in trial.fixations if not fix.excluded]
    region_fixations = [
        key for key, fixation in enumerate(trial_fixations)
        if fixation.region.number is region_number
    ]

    if not region_fixations:
        return save_measure(trial, region, "first_pass_regressions_in", None,
                            None)
    for fixation in region_fixations:
        prev_fix_region = trial_fixations[fixation - 1].region
        if (fixation and prev_fix_region.number is not None
                and prev_fix_region.number > region_number):
            return save_measure(trial, region, "first_pass_regressions_in",
                                True, None)
    return save_measure(trial, region, "first_pass_regressions_in", False,
                        None)
Exemplo n.º 14
0
def landing_position(trial: Trial, region_number: int) -> RegionMeasure:
    """
    The location relative to the beginning of the region (in
    number of characters) of the first fixation during the first pass, where the
    first character in the region is at position (0, 0). If the region was skipped,
    this measure is None.

    ::

        fp_fixations = get_first_pass_fixations(trial, region_number)

        if (length of fp_fixations is not 0
                and fp_fixations[0].char is not None
                and fp_fixations[0].line is not None):
            return (fp_fixations[0].char - region.start.char,
                    fp_fixations[0].line - region.start.line)

        else:
            return None

    """
    region = region_exists(trial, region_number)
    landing_pos = None
    fixation = None
    fp_fixations = get_fp_fixations(trial, region_number)

    if (fp_fixations and fp_fixations[0].char is not None
            and fp_fixations[0].line is not None):
        landing_pos = '"(%s, %s)"' % (
            fp_fixations[0].char - region.start.x,
            fp_fixations[0].line - region.start.y,
        )
        fixation = fp_fixations[0]

    return save_measure(trial, region, "landing_position", landing_pos,
                        [fixation] if fixation else None)
Exemplo n.º 15
0
def reread_time(trial: Trial, region_number: int) -> RegionMeasure:
    """
    The summed duration of all fixations in the region that occur after a region
    to the right has been fixated. If this region is never fixated this measure is 0.

    ::

        total = 0
        reread = False

        for fixation in trial:
            if fixation is not excluded:
                if fixation.region_number > region_number:
                    reread = True
                if reread and fixation.region_number is region_number:
                    total += fixation.duration()

        return total

    """
    region = region_exists(trial, region_number)

    rr_fixations: List[Fixation] = []
    total = 0
    reread = False
    for fixation in trial.fixations:
        if not fixation.excluded:
            if (fixation.region.number is not None
                    and fixation.region.number > region_number):
                reread = True
            if (reread and fixation.region.number is not None
                    and fixation.region.number is region_number):
                rr_fixations += [fixation]
                total += fixation.duration()

    return save_measure(trial, region, "reread_time", total, rr_fixations)
Exemplo n.º 16
0
def launch_site(trial: Trial, region_number: int) -> RegionMeasure:
    """
    The location of the last fixation prior to the first fixation
    in the region. This measure returns an (x, y) tuple, where x is either the
    number of characters from the the beginning of the target region and y is the
    number of lines from the beginning of the region. -1 indicates the last character
    of the region preceding the target region, or the preceding line, and increasing
    negative numbers indicate further launch sites. If the region was skipped this
    measure is None.

    ::

        fixations = [fixation for fixation in trial if fixation is not excluded]

        for (index, fixation) in enumerate(fixations):
            if fixation.region_number > region_number:
                break
            if fixation.region_number == region_number:
                if index == 0:
                    break

                if fixations[index - 1].char is None:
                    launch_char = fixations[index - 1].char
                else:
                    launch_char = fixations[index - 1].char - fixation.region.start.char

                if fixations[index - 1].line is None:
                    launch_line = fixations[index - 1].line
                else:
                    launch_line = fixations[index - 1].line - fixation.region.start.line

                return (launch_char, launch_line)

        return None

    """
    region = region_exists(trial, region_number)
    launch = None
    fixation = None
    trial_fixations = [fix for fix in trial.fixations if not fix.excluded]

    for (idx, fixation) in enumerate(trial_fixations):
        if (fixation.region.number is not None
                and fixation.region.number > region_number):
            break
        if (fixation.region.number is not None
                and fixation.region.number == region_number):
            if idx == 0:
                break
            if trial_fixations[idx - 1].char is None:
                launch_char = trial_fixations[idx - 1].char
            else:
                launch_char = trial_fixations[idx -
                                              1].char - fixation.region.start.x
            if trial_fixations[idx - 1].line is None:
                launch_line = trial_fixations[idx - 1].line
            else:
                launch_line = trial_fixations[idx -
                                              1].line - fixation.region.start.y
            launch = '"(%s, %s)"' % (launch_char, launch_line)
            fixation = trial_fixations[idx - 1]
            break

    return save_measure(trial, region, "launch_site", launch,
                        [fixation] if fixation else None)
Exemplo n.º 17
0
def go_back_time_region(trial: Trial, region_number: int) -> RegionMeasure:
    """
    Go-back time is the time (in ms) until the first regression is made after encountering a region.
    For the purposes of go-back time, any fixation which lands to the left of the preceding fixation
    is considered a regression; the landing site regression does not need to precede
    the critical region.
    If a region was fixated, it is measured from the onset of the first fixation in that regreion.
    If a region was skipped, it is measured from the offset of the preceding fixation.
    The end point is the end of the fixation that precedes the regression.
    If no regression is made after the critical region, this measure is 'None.'

    go_back_time_region defines a regression region by region: any fixation which
    lands on a region to the left of the preceding fixation counts as a regression.
    """
    region = region_exists(trial, region_number)
    fp_fixations = get_fp_fixations(trial, region_number)
    go_back_start = 0
    go_back_end = None

    if fp_fixations:
        go_back_start = fp_fixations[0].start
        start_fix = fp_fixations[0]

    if not fp_fixations:
        try:
            start_fix = [
                fix for fix in trial.fixations
                if not fix.excluded and fix.region.number is not None
                and fix.region.number < region_number
            ][0]
            for idx in range(1, len(trial.fixations) - 1):
                curr_fix = trial.fixations[idx]
                if not curr_fix.excluded:
                    if (curr_fix.region.number is not None
                            and curr_fix.region.number > region_number):
                        break
                    start_fix = curr_fix
            go_back_start = start_fix.end
        except IndexError:
            return save_measure(trial, region, "go_back_time_region", None,
                                None)

    try:
        prev_fix = start_fix
        curr_fix = trial.fixations[start_fix.index + 1]
        for idx in range(start_fix.index + 1, len(trial.fixations) - 1):
            curr_fix = trial.fixations[idx]
            if not curr_fix.excluded:
                if (curr_fix.region.number is not None
                        and prev_fix.region.number is not None
                        and curr_fix.region.number < prev_fix.region.number):
                    go_back_end = prev_fix.end
                    break
                prev_fix = curr_fix
    except IndexError:
        pass

    if go_back_end is not None:
        return save_measure(trial, region, "go_back_time_region",
                            go_back_end - go_back_start, None)

    return save_measure(trial, region, "go_back_time_region", None, None)