Source code for dispel.providers.bdh.tasks.ft
"""Processing functionality for Finger Tapping (FT) task."""
from typing import List, Union
import pandas as pd
from dispel.data.raw import RawDataValueDefinition
from dispel.processing.core import ProcessingStep
from dispel.processing.data_set import transformation
from dispel.processing.level import ProcessingStepGroup
from dispel.processing.transform import TransformStep
from dispel.providers.bdh.data import BDHReading
from dispel.providers.generic.sensor import SetTimestampIndex
from dispel.providers.generic.tasks.ft.const import TOUCH_ATTRIBUTES
from dispel.providers.generic.tasks.ft.steps import TASK_NAME, GenericFingerTappingSteps
from dispel.providers.generic.touch import TOUCH_COLUMNS, Gesture, split_touches
from dispel.providers.registry import process_factory
[docs]
class TransformRawTouchEvents(TransformStep):
"""Preprocess the io raw touch events.
The touch path ids that we receive with the io format are not increasing
over time, this is just a counter of the number of fingers on the screen.
In order to use the :class: `~dispel.providers.generic.touch.Gesture`
module we need to transform those ids into an increasing sequence with one
touch path id per tap.
"""
data_set_ids = "screen"
new_data_set_id = "processed_screen"
definitions = [RawDataValueDefinition(column, column) for column in TOUCH_COLUMNS]
[docs]
@staticmethod
@transformation
def preprocess_raw_touch_events(data):
"""Pre-process the raw touch events."""
return split_touches(
data, begin=data["tsTouch"].min(), end=data["tsTouch"].max()
)
[docs]
class SetTimestampIndexBDHonly(SetTimestampIndex):
"""BDH specific set timestamp processing step."""
[docs]
class TransformGesture(TransformStep):
"""Generate a gesture dataset from the preprocessed raw touch events."""
data_set_ids = "processed_screen"
new_data_set_id = "gestures"
definitions = [RawDataValueDefinition("gestures", "gestures")]
@staticmethod
@transformation
def _generate_gesture(data):
return pd.Series(Gesture.from_data_frame(data))
[docs]
class TransformTapsFromRaw(TransformStep):
"""Retrieve the tap events from the gesture dataset."""
data_set_ids = "gestures"
new_data_set_id = "taps_from_raw"
definitions = [
RawDataValueDefinition(column, column)
for column in TOUCH_ATTRIBUTES + ["tap_duration"]
]
@staticmethod
@transformation
def _generate_taps_from_raw(data):
new_data = {}
# Explode the gesture dataset to have individual taps
exploded_touch = (
data["gestures"].apply(lambda x: x.touches).explode().reset_index(drop=True)
)
# Extract the touch attributes
for attribute in TOUCH_ATTRIBUTES:
new_data[attribute] = exploded_touch.apply(lambda x: getattr(x, attribute))
df = pd.DataFrame(new_data).sort_values(by="begin")
df["tap_duration"] = (df["end"] - df["begin"]).dt.total_seconds() * 1e3
return df
[docs]
class TransformTapEvents(TransformStep):
"""Generate a gesture dataset from the preprocessed raw touch events."""
data_set_ids = ["taps_from_raw", "tap_events_ts"]
new_data_set_id = "enriched_tap_events"
definitions = [
RawDataValueDefinition(column, column)
for column in TOUCH_ATTRIBUTES + ["tap_duration", "location"]
]
[docs]
@staticmethod
@transformation
def enrich(raw_ts, taps):
"""Enrich the tap events with the information provided by the raw events."""
raw_ts_copy = raw_ts.copy().sort_values(by="begin")
taps_copy = taps.copy().sort_index()
if len(raw_ts) == len(taps):
return pd.concat([taps_copy.reset_index(), raw_ts_copy], axis=1).drop(
columns="timestamp"
)
return pd.merge_asof(
raw_ts_copy,
taps_copy,
left_on="begin",
right_index=True,
direction="nearest",
)
[docs]
class BDHPreprocessingStepGroup(ProcessingStepGroup):
"""BDH preprocessing step group for finger tapping."""
steps: List[Union[ProcessingStep, ProcessingStepGroup]] = [
TransformRawTouchEvents(),
# Generate gesture from the raw touch events
TransformGesture(),
# Generate the tap events from the gesture dataset
TransformTapsFromRaw(),
SetTimestampIndexBDHonly(
data_set_id="tap_events",
columns=["location"],
time_stamp_column="timestamp",
duplicates="first",
),
TransformTapEvents(),
SetTimestampIndexBDHonly(
data_set_id="enriched_tap_events",
columns=["location", "end", "tap_duration", "first_position"],
time_stamp_column="begin",
duplicates="first",
),
]
[docs]
class BDHSteps(ProcessingStepGroup):
"""BDH steps used to process finger tapping records."""
steps: List[ProcessingStep] = [
BDHPreprocessingStepGroup(),
GenericFingerTappingSteps(),
]
process_ft = process_factory(
task_name=TASK_NAME,
steps=BDHSteps(),
codes="fingertap-activity",
supported_type=BDHReading,
)