Source code for ibllib.qc.task_extractors
import logging
import numpy as np
from one.alf.spec import is_session_path
import one.alf.io as alfio
_logger = logging.getLogger('ibllib')
REQUIRED_FIELDS = [
'choice',
'contrastLeft',
'contrastRight',
'correct',
'errorCueTrigger_times',
'errorCue_times',
'feedbackType',
'feedback_times',
'firstMovement_times',
'goCueTrigger_times',
'goCue_times',
'intervals',
'itiIn_times',
'phase',
'position',
'probabilityLeft',
'quiescence',
'response_times',
'rewardVolume',
'stimFreezeTrigger_times',
'stimFreeze_times',
'stimOffTrigger_times',
'stimOff_times',
'stimOnTrigger_times',
'stimOn_times',
'valveOpen_times',
'wheelMoves_intervals',
'wheelMoves_peakAmplitude',
'wheelMoves_peakVelocity_times',
'wheel_position',
'wheel_timestamps',
]
[docs]
class TaskQCExtractor:
def __init__(self, session_path):
"""
A class for holding the task data required to perform task quality control.
:param session_path: a valid session path
"""
if not is_session_path(session_path):
raise ValueError('Invalid session path')
self.session_path = session_path
self.log = _logger
self.data = None
self.settings = None
self.raw_data = None
self.frame_ttls = self.audio_ttls = self.bpod_ttls = None
self.wheel_encoding = None
[docs]
@staticmethod
def rename_data(data):
"""Rename the extracted data dict for use with TaskQC
Splits 'feedback_times' to 'errorCue_times' and 'valveOpen_times'.
NB: The data is not copied before making changes
:param data: A dict of task data returned by the task extractors
:return: the same dict after modifying the keys
"""
# Expand trials dataframe into key value pairs
trials_table = data.pop('table', None)
if trials_table is not None:
data = {**data, **alfio.AlfBunch.from_df(trials_table)}
correct = data['feedbackType'] > 0
# get valve_time and errorCue_times from feedback_times
if 'errorCue_times' not in data:
data['errorCue_times'] = data['feedback_times'].copy()
data['errorCue_times'][correct] = np.nan
if 'valveOpen_times' not in data:
data['valveOpen_times'] = data['feedback_times'].copy()
data['valveOpen_times'][~correct] = np.nan
data['correct'] = correct
diff_fields = list(set(REQUIRED_FIELDS).difference(set(data.keys())))
for miss_field in diff_fields:
data[miss_field] = None if miss_field.startswith('wheel') else data['feedback_times'] * np.nan
if len(diff_fields):
_logger.warning(f'QC extractor, missing fields filled with NaNs: {diff_fields}')
return data