Esempio n. 1
0
def test_empty():
    """Test that an empty dataframe is valid

    (As long as the required columns exist!)
    """
    empty = empty_events()
    check_event_specification(empty)
Esempio n. 2
0
def test_unknown_version(events):
    """Test only the current specification version

    If a new version of the events specification is implemented, this unit
    test should be updated to the next version.
    """
    with pytest.raises(ValueError):
        # This should fail because version='2' does not exist yet
        check_event_specification(events, version='2')
Esempio n. 3
0
    def preconditions(self, *, events, **inputs):
        """ Verify task preconditions

        Soft preconditions to this task are:

        * Input events follow the :ref:`event_specs`.

        """
        super().preconditions(events=events, **inputs)
        try:
            with pd.HDFStore(events.file, 'r') as store:
                events = pd.read_hdf(store, key=self.input_hdf5_key)
            check_event_specification(events)
        except EventSpecificationError as ex:
            logger.info('VR selection will not run: the input does not '
                        'adhere to standard event specification')
            raise SoftPreconditionFailed('Input did not adhere to standard '
                                         'event specification') from ex
Esempio n. 4
0
    def postconditions(self, results):
        """ Check standard event postconditions

        The postconditions of this task is that the result follows the event
        specification standard.
        """
        super().postconditions(results)

        if not isinstance(results, FileAdapter):
            raise PostconditionFailed('Output was not a file')

        # Postcondition: file is empty
        if results.empty:
            return

        key = self.output_hdf5_key
        with pd.HDFStore(results.file, 'r') as store:
            dataframe = pd.read_hdf(store, key)
            check_event_specification(dataframe)
Esempio n. 5
0
    def postconditions(self, results):
        """ Verify task postconditions

        Postconditions to this tasks are:

        * The results object is a :py:class:`~iguazu.helpers.files.FileAdapter`
        * One of:
          * Results are empty
          * Results contents adhere to :ref:`event_specs`.

        """
        super().postconditions(results)

        if not isinstance(results, FileAdapter):
            raise PostconditionFailed('Output was not a file')

        # Postcondition: file is empty
        if results.empty:
            return

        key = self.output_hdf5_key
        with pd.HDFStore(results.file, 'r') as store:
            dataframe = pd.read_hdf(store, key)
            check_event_specification(dataframe)
Esempio n. 6
0
def _check_and_assert_raises(obj, code):
    with pytest.raises(EventSpecificationError) as ex_info:
        check_event_specification(obj)
    exception = ex_info.value
    assert exception.code == code
Esempio n. 7
0
def test_datetime_contents(events, tz):
    """Test that datetime64 and datetime64 with utc are accepted"""
    # Note: tz=None gives a regular datetime64
    events['begin'] = events['begin'].dt.tz_localize(tz=tz)
    events['end'] = events['end'].dt.tz_localize(tz=tz)
    check_event_specification(events)
Esempio n. 8
0
def test_correct_event_dataframe(events):
    """Test a correct event dataframe"""
    # This should not raise anything
    check_event_specification(events)
Esempio n. 9
0
def extract_space_stress_spawns_stimulations(events):
    """ Extract information about spawns in space stress events
    This function extracts events with label "unity_space-stress_game_breach_spawns" and
    "unity_space-stress_game_enemy_spawns". It returns a dataframe with interesting features
    associated to these actions (spawn position, type, id ).

    Parameters
    ----------
    events: pd.DataFrame
        Dataframe with columns 'label' and 'data', containing events sent by
        unity during VR session.

    Returns
    -------
    A dataframe with each row corresponding to a stimulation from the game and
    columns are the following:
        - id: id of the breach or enemy
        - label: unity_space-stress_game_breach_spawns.
        - type: Type of spawner (enemy or breach).
        - x: Coordinate x of the spawn.
        - y: Coordinate y of the spawn.
        - z: Coordinate z of the spawn.
        - wave: Index of the wave.
        - difficulty: Difficulty of the wave.
        - trajectory_length: Euclidean distance between successive spawns in plan (X,Y).

    Notes
    ------
    Here is an example of how the outputshould look like:

    >>> data
                                             id                                 label   type      x      y      z    wave  difficulty  trajectory_length
        2019-04-03 08:36:07.464509437+00:00   0  unity_space-stress_game_enemy_spawns  enemy  1.989  2.766  5.480    1.         5.                NaN
        2019-04-03 08:36:07.691995137+00:00   1  unity_space-stress_game_enemy_spawns  enemy  1.989  2.766  5.480    1.         5.                NaN
        2019-04-03 08:36:07.890431837+00:00   2  unity_space-stress_game_enemy_spawns  enemy  0.278  1.919  5.673    1.         5.           1.955187
        2019-04-03 08:36:08.142808336+00:00   3  unity_space-stress_game_enemy_spawns  enemy  1.591  4.102  4.411    1.         5.           2.547441
        2019-04-03 08:36:08.324275836+00:00   4  unity_space-stress_game_enemy_spawns  enemy -1.140  1.840  5.230    1.         5.           3.546125
        ...

    """
    # check that the input meets the events standard specifications
    check_event_specification(events)

    if 'space-stress_sequence' not in extract_complete_sequences(
            events, label_column='name'):
        raise SequenceNotFound('Could not find "space-stress_sequence".')

    enemy_spawns = extract_metas(
        events,
        labels=['unity_space-stress_game_enemy_spawns'],
        meta_keys=['enemy_id', 'x', 'y', 'z'],
        label_column='name').rename(columns={'enemy_id': 'id'})
    enemy_spawns['type'] = 'enemy'

    breach_spawns = extract_metas(
        events,
        labels=['unity_space-stress_game_breach_spawns'],
        meta_keys=['breach_id', 'x', 'y', 'z'],
        label_column='name').rename(columns={'breach_id': 'id'})
    breach_spawns['type'] = 'breach'

    out = pd.concat([breach_spawns, enemy_spawns], sort=True).sort_index()
    out = estimate_trajectory_length(data=out, columns=['x', 'y'])

    return out.drop(['name', 'id'], axis=1)
Esempio n. 10
0
def extract_space_stress_participant_actions(events):
    """ Extract information about participant controller actions from space stress events

    This function extracts events with label "unity_space-stress_game_participant_pushes_button" and construct a table
    with interesting features associated to the action (cursor position, context, results .. ).

    Parameters
    ----------
    events: pd.DataFrame
        Dataframe with columns 'label' and 'data', containing events sent by
        unity during VR session.

    Returns
    -------
    A dataframe with each row corresponding to one action from the participant
    and columns are the following:
        - label: "unity_space-stress_game_participant_pushes_button"
        - button: Button pressed by the participant (trigger or pad).
        - x: Coordinate x of the cursor position.
        - y: Coordinate y of the cursor position.
        - z: Coordinate z of the cursor position.
        - action_succeed: Boolean giving action output (True if success, False if fail).
        - failure_reason: string ("finger_confusion"|"bad_precision"|"bad_planification") or None if there is no failure.
        - wave: Index of the wave.
        - difficulty: Difficulty of the wave
        - trajectory_length: Euclidean distance between successive actions in plan (X,Y).

    Notes
    ------
    Here is an example of how the output should look like.

    >>> data
                                                                                         label   button         x         y         z  action_succeed failure_reason  wave  difficulty trajectory_length
        2019-04-03 08:35:21.521755333+00:00  unity_space-stress_game_participant_pushes_button  trigger -1.428315  2.280506  5.309360  False          bad_precision   1.          5.            NaN
        2019-04-03 08:35:21.775456032+00:00  unity_space-stress_game_participant_pushes_button  trigger -1.428315  2.280506  5.309360  False          bad_precision   1.          5.            0.000000
        2019-04-03 08:35:22.500084331+00:00  unity_space-stress_game_participant_pushes_button  trigger -1.428408  2.402699  5.282661  False          bad_precision   1.          5.            0.122193
        2019-04-03 08:35:22.753246430+00:00  unity_space-stress_game_participant_pushes_button  trigger -1.428408  2.402699  5.282661  False          bad_precision   1.          5.            0.000000
        2019-04-03 08:35:22.986076530+00:00  unity_space-stress_game_participant_pushes_button  trigger -1.448533  2.439976  5.272884  False          bad_precision   1.          5.            0.042363
        ...

    See the documentation of :py:func:dsu.space_stress.classify_failures

    """
    # check that the input meets the events standard specifications
    check_event_specification(events)

    if 'space-stress_sequence' not in extract_complete_sequences(
            events, label_column='name'):
        raise SequenceNotFound('Could not find "space-stress_sequence".')

    space_stress_times = extract_complete_sequence_times(
        events, 'space-stress_sequence', pedantic='warn', label_column='name')
    begins, ends = space_stress_times[0]

    out = truncate(extract_metas(
        events,
        labels=['unity_space-stress_game_participant_pushes_button'],
        meta_keys=['button', 'x', 'y', 'z', 'result'],
        label_column='name'),
                   begins=begins,
                   ends=ends)
    out.loc[:, 'action_succeed'] = out.result.apply(
        lambda x: 'succeed' in x['action'])
    out = out.drop(out.loc[(out.button == 'pad') & (out.result == {
        'action': 'action_failed'
    })].index)

    for button in ['pad', 'trigger']:
        # classify failure reason depending on button type
        idx_button = (out.button == button)
        func_button = functools.partial(categorize_failure, button=button)
        out.loc[idx_button,
                'failure_reason'] = out.loc[idx_button,
                                            'result'].apply(func_button)

    # estimate trajectory length of participant actions in X,Y plan.
    out = estimate_trajectory_length(data=out, columns=['x', 'y'])
    return out.drop(['result', 'name'], axis=1)