Input:
To do:
In [58]:
## set to full width if not using theme
#from IPython.core.display import display, HTML
#display(HTML("<style>.container { width:100% !important; }</style>"))
In [59]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import string
import matplotlib.patches as mpatches
import seaborn as sns
#sns.set(style="whitegrid", color_codes=True)
plt.ioff() # Turn interactive plotting off
#url = "https://raw.githubusercontent.com/jamcro/shootGaze/master/data/shootingNoviceGaze.csv"
#gaze_df = pd.read_csv(url, sep=',', skipinitialspace=True)
#url = "https://raw.githubusercontent.com/jamcro/shootGaze/master/data/shootingNoviceKinematics.csv"
#kin_df = pd.read_csv(url, sep=',', skipinitialspace=True)
gaze_df = pd.read_csv('/Users/jc/Documents/GitHub/shootGaze/data/shootingNoviceGaze.csv', sep=',', skipinitialspace=True)
kin_df = pd.read_csv('/Users/jc/Documents/GitHub/shootGaze/data/shootingNoviceKinematics.csv', sep=',', skipinitialspace=True)
shot_df = pd.read_csv('/Users/jc/Documents/GitHub/shootGaze/data/shootingNoviceShots.csv', sep=',', skipinitialspace=True)
In [60]:
# remove trailing nans
first_idx = gaze_df.first_valid_index()
last_idx = gaze_df.last_valid_index()
print(first_idx, last_idx)
gaze_df = gaze_df.loc[first_idx:last_idx]
#gaze_df['fixOn'] = (gaze_df.startTime - gaze_df.Timer)
#gaze_df['fixOff'] = (gaze_df.finishTime - gaze_df.Timer)
#gaze_df['fixLen'] = (gaze_df.fixOff - gaze_df.fixOn)
# put them in order to make table easier to view
gaze_df.insert(7, 'tFixOn', (gaze_df.startTime - gaze_df.Timer))
gaze_df.insert(8, 'tFixOff', (gaze_df.finishTime - gaze_df.Timer))
gaze_df.insert(9, 'fixDur', (gaze_df.tFixOff - gaze_df.tFixOn))
gaze_df['shotFired'] = gaze_df['shotFired'].astype('int64')
gaze_df['fixID'] = pd.Categorical(gaze_df['fixID'], categories=['A','B','C','D'], ordered=True)
gaze_df['fixIDcode'] = gaze_df['fixID'].cat.codes + 1
#gaze_df['fixID'].value_counts()
gaze_df.head(10)
Out[60]:
In [61]:
shot_df['threat1'] = pd.Categorical(shot_df['threat1'], categories=['A','B','C','D'], ordered=True)
shot_df['threat2'] = pd.Categorical(shot_df['threat2'], categories=['A','B','C','D'], ordered=True)
shot_df['targetShot1'] = pd.Categorical(shot_df['targetShot1'], categories=['A','B','C','D'], ordered=True)
shot_df['targetShot2'] = pd.Categorical(shot_df['targetShot2'], categories=['A','B','C','D'], ordered=True)
shot_df['outcomeShot1'] = pd.Categorical(shot_df['outcomeShot1'])
shot_df['outcomeShot2'] = pd.Categorical(shot_df['outcomeShot2'])
In [62]:
# remove trailing nans
first_idx = kin_df.first_valid_index()
last_idx = kin_df.last_valid_index()
print(first_idx, last_idx)
kin_df = kin_df.loc[first_idx:last_idx]
# convert dtypes
kin_df['Subject'] = kin_df['Subject'].astype('int64')
kin_df['Intervention'] = kin_df['Intervention'].astype('int64')
kin_df['Day'] = kin_df['Day'].astype('int64')
kin_df['Trial'] = kin_df['Trial'].astype('int64')
#subtract Timer (start of trial) from all time values
kin_df.loc[:, 'Timer':'tShot2'] = kin_df.loc[:, 'Timer':'tShot2'].sub(kin_df['Timer'], axis=0)
kin_df.head(3)
Out[62]:
In [63]:
#kin_df[(kin_df.Subject == 1) & (kin_df.Day == 1) & (kin_df.Trial == 5)]
#gaze_df[(gaze_df.Subject == 1) & (gaze_df.Day == 1) & (gaze_df.Trial == 5)]
In [64]:
# combine data that has one row per trial
events_df = pd.merge(kin_df, shot_df, on=['Subject', 'Intervention', 'Day', 'Trial'])
# combine with gaze data (i.e. repeat trial based data for each fixation)
dat_df = pd.merge(gaze_df,events_df, on=['Subject', 'Intervention', 'Day', 'Trial'])
#dat_df.columns.values
dat_df.head()
Out[64]:
In [65]:
dat_df['idGazeShot'] = ((dat_df['tShot1'] < dat_df['tFixOff']) & (dat_df['tShot1'] > dat_df['tFixOn'])) | ((dat_df['tShot2'] < dat_df['tFixOff']) & (dat_df['tShot2'] > dat_df['tFixOn']))
In [66]:
onthreat_df = dat_df.loc[((dat_df['fixID']==dat_df['threat1']) | (dat_df['fixID']==dat_df['threat2'])),
['Subject', 'Intervention', 'Day', 'Trial',
'idGazeShot','tFixOn','fixID', 'threat1', 'threat2',
'fixDur', 'Position','fixIDcode','tOnTrigger',
'tShot1', 'tShot2', 'targetShot1', 'targetShot2', 'outcomeShot1', 'outcomeShot2']]
onthreat_df.head(10)
#['Subject', 'Intervention', 'Day', 'Trial', 'shotFired','tFixOn', 'fixID', 'threat1', 'threat2',
# 'tOnTrigger', 'tShot1', 'tShot2', 'targetShot1', 'targetShot2', 'outcomeShot1', 'outcomeShot2']]
fired_df = onthreat_df.loc[(onthreat_df['idGazeShot']==True),
['Subject', 'Intervention', 'Day', 'Trial',
'idGazeShot','tFixOn','fixID', 'threat1', 'threat2',
'fixDur', 'Position','fixIDcode','tOnTrigger',
'tShot1', 'tShot2', 'targetShot1', 'targetShot2', 'outcomeShot1', 'outcomeShot2']]
fired_df.head(10)
#fired_df['tShot1'].dtypes
Out[66]:
In [67]:
def plotGazeTimeline(df, subj, day, tr, axId):
# identify this trial
x = df.loc[(df.Subject == subj) & (df.Day == day) & (df.Trial == tr)].tFixOn
width = df.loc[(df.Subject == subj) & (df.Day == day) & (df.Trial == tr)].fixDur
bottom = df.loc[(df.Subject == subj) & (df.Day == day) & (df.Trial == tr)].Position
height = [0.5] * len(x)
catColor = df.loc[(df.Subject == subj) & (df.Day == day) & (df.Trial == tr)].fixIDcode
mycolors = ['#d7191c','#fdae61','#abdda4','#2b83ba']
colorlist = [mycolors[x] for x in catColor-1]
if axId.ndim == 1:
axId[tr-1].bar(x, height, width, bottom, align='edge', color=colorlist, label=catColor)
else:
axId[tr-1, day-1].bar(x, height, width, bottom, align='edge', color=colorlist, label=catColor)
In [68]:
def plotThreat(df, subj, day, tr, axId):
# identify this trial
x = df.loc[(df.Subject == subj) & (df.Day == day) & (df.Trial == tr)].tFixOn
width = df.loc[(df.Subject == subj) & (df.Day == day) & (df.Trial == tr)].fixDur
bottom = df.loc[(df.Subject == subj) & (df.Day == day) & (df.Trial == tr)].Position
height = [0.5] * len(x)
edgecol = 'k' * len(x)
if axId.ndim == 1:
axId[tr-1].bar(x, 0.5, width, bottom, align='edge', color='none', edgecolor = edgecol, lw=1.5)
else:
axId[tr-1, day-1].bar(x, height, width, bottom, align='edge', color='none', edgecolor = edgecol, lw=1.5)
In [69]:
def plotKinEvents(df, subj, day, tr, axId):
# identify this trial
thisTr = df.loc[(df.Subject == subj) & (df.Day == day) & (df.Trial == tr)]
from itertools import cycle
lines = ["-","--","-.",":"]
linecycler = cycle(lines)
#labels=df.loc[:,'handGun':'shot2'].columns.tolist()
if thisTr.size > 0:
xcoords = thisTr.loc[:,'tHandGun':'tShot2'].values
for xc in xcoords[0]:
if axId.ndim == 1:
axId[tr-1].axvline(x=xc, linestyle=next(linecycler), color='k', lw=1)
axId[tr-1].grid(b=False)
else:
axId[tr-1, day-1].axvline(x=xc, linestyle=next(linecycler), color='k', lw=1)
In [70]:
# plotGazeTimeline(gaze_df, 1, 1, 2, 1)
width = 8
height = 12
nsubj = gaze_df.Subject.unique().size
for sbj in range(1,nsubj+1):
for dy in range(1,4):
fig, ax = plt.subplots(nrows=10, ncols=1, sharex=True, sharey=True, figsize=(width, height))
figName = '/Users/jc/Documents/GitHub/shootGaze/figs/s' + str(sbj) + 'day' + str(dy) + 'gaze.png'
for tr in range(1,11):
plotGazeTimeline(gaze_df, sbj, dy, tr, ax)
plotThreat(onthreat_df, sbj, dy, tr, ax)
plotKinEvents(kin_df, sbj, dy, tr, ax)
ax[0].set_title('Day ' + str(dy))
ax[9].set_xlabel('Time (s)')
axc=plt.gca() # get the axis
axc.set_ylim([0.75,4.75])
axc.set_ylim(axc.get_ylim()[::-1]) # invert the axis
axc.yaxis.set_ticks([1.25,2.25,3.25,4.25]) # set y-ticks
axc.yaxis.tick_left() # remove right y-Ticks
labels = ['Far Left','Left','Right','Far Right']
axc.set_yticklabels(labels, fontdict=None, minor=False)
xlims = axc.get_xlim()
axc.set_xlim([0,xlims[1]])
plt.tick_params(top='off', right='off', labelbottom='on') # remove all the ticks
#for spine in plt.gca().spines.values():
# spine.set_visible(False)
patch1 = mpatches.Patch(color='#d7191c', label='A')
patch2 = mpatches.Patch(color='#fdae61', label='B')
patch3 = mpatches.Patch(color='#abdda4', label='C')
patch4 = mpatches.Patch(color='#2b83ba', label='D')
plt.legend(handles=[patch1,patch2,patch3,patch4],
bbox_to_anchor=(0.95, 0.95),
loc=1, ncol=4,
bbox_transform=plt.gcf().transFigure,
fontsize=8,
title='Target ID')
# # Fine-tune figure; hide x ticks for top plots and y ticks for right plots
#plt.setp([a.get_xticklabels() for a in ax[0, :]], visible=False)
#plt.setp([a.get_yticklabels() for a in ax[:, 1]], visible=False)
# Tight layout often produces nice results but requires the title to be spaced accordingly
fig.tight_layout()
fig.subplots_adjust(top=0.88)
plt.savefig(figName)
#plt.show()
plt.close(fig)
Average fixation duration
Number of fixations
Number of fixations on same target
Number of hits by body location
Time to ID target from trial onset (tOnTrigger)
Time to ID target after fixation (tFixOn - tOnTrigger)
Time to shoot after fixation (tFixOn - tOnTrigger)
Time to shoot (tOnTrigger - tShot)
Trial
Day
Group
Group*Day
In [71]:
fired_df['tShot1-tFixOn'] = fired_df['tShot1'] - fired_df['tFixOn']
fired_df.loc[fired_df['tShot1-tFixOn']<0,'tShot1-tFixOn'] = np.nan
fired_df['tShot2-tFixOn'] = fired_df['tShot2'] - fired_df['tFixOn']
mask = fired_df['tShot1-tFixOn'].isnull()
fired_df['tShot2-tFixOn'] = fired_df[mask]['tShot2-tFixOn']
fired_df['tFixOn-tOnTrigger'] = fired_df['tOnTrigger'] - fired_df['tFixOn']
fired_df.loc[fired_df['tFixOn-tOnTrigger']<0,'tFixOn-tOnTrigger'] = np.nan #ignore trials where finger on trigger before fixation - mostly shot2
fired_df.head(10)
Out[71]:
In [54]:
sns.set(style="white", palette="muted", color_codes=True)
f, axes = plt.subplots(1, 2, figsize=(8, 4), sharex=True)
sns.distplot(fired_df['tShot1-tFixOn'].dropna(axis=0), hist=False, rug=True, color="r", ax=axes[0])
sns.distplot(fired_df['tShot1-tFixOn'].dropna(axis=0), color="m", ax=axes[1])
sns.despine(left=True)
sns.set_context("talk")
plt.setp(axes, yticks=[])
plt.tight_layout()
plt.show()
# vertical 'bar' plot with data and median by group
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [53]:
df = onthreat_df
df.loc[(df.Subject == subj) & (df.Day == day) & (df.Trial == tr)]
In [ ]:
df = gaze_df
df.loc[(df.Subject == subj) & (df.Day == day) & (df.Trial == tr)]