Skip to main content

Koli Calling

In [2]:
%run prelude.ipy
The autoreload extension is already loaded. To reload it, use:
  %reload_ext autoreload

Data and Areas of Interest

Let's start by looking at the gaze data. We have fixations for two trials (subject 1 and subject 2). Each fixation has an x, y coordinate and a duration.

In [33]:
all_fixes = data.busjahn_2013.all_fixations()
subject1_fixes = all_fixes[all_fixes.trial_id == 8]
subject2_fixes = all_fixes[all_fixes.trial_id == 9]
print all_fixes
<class 'pandas.core.frame.DataFrame'>
Int64Index: 698 entries, 0 to 697
Data columns (total 17 columns):
trial_id           698  non-null values
start_ms           698  non-null values
duration_ms        698  non-null values
fix_x              698  non-null values
fix_y              698  non-null values
exp_id             698  non-null values
end_ms             698  non-null values
program            698  non-null values
offset_kind        698  non-null values
aoi_block          668  non-null values
aoi_interface      680  non-null values
aoi_line           626  non-null values
aoi_line chunks    626  non-null values
aoi_method-call    157  non-null values
aoi_signature      159  non-null values
aoi_sub-block      606  non-null values
aoi_sub-line       610  non-null values
dtypes: float64(2), int64(5), object(10)

Every fixation has been hit-tested against different layers of area-of-interest (AOI) rectangles. For example, here are the rectangles for each line:

In [18]:
aois = data.busjahn_2013.areas_of_interest("rectangle")
plot.draw_rectangles(aois[aois.kind == "line"], data.busjahn_2013.program_image("rectangle"))
Out[18]:

If we include only fixations that occurred inside one the above rectangles, we can assign a line number to each fixation.

In [10]:
all_line_fixes = data.busjahn_2013.line_fixations()
subject1_line_fixes = all_line_fixes[all_line_fixes.trial_id == 8]
subject2_line_fixes = all_line_fixes[all_line_fixes.trial_id == 9]
show_dataframe(subject1_line_fixes[:10])
Out[10]:
trial_id start_ms duration_ms fix_x fix_y exp_id end_ms program line
8 250 184 423.437500 378.083344 0 434 rectangle 8
8 1284 283 444.852936 159.117645 0 1567 rectangle 2
8 2034 867 366.030792 133.842896 0 2901 rectangle 1
8 2951 317 469.062500 143.449997 0 3268 rectangle 2
8 3352 233 397.500000 210.000000 0 3585 rectangle 4
8 3785 183 619.687500 221.500000 0 3968 rectangle 4
8 4102 383 782.343750 205.875000 0 4485 rectangle 4
8 4552 433 416.574066 275.481476 0 4985 rectangle 6
8 5953 466 424.913788 295.827576 0 6419 rectangle 6
8 6470 350 378.977264 496.909088 0 6820 rectangle 11

Plotting the timeline of fixated lines provides a great overview of a trial.

In [15]:
ax = plot.fixations.line_timeline_single(subject1_line_fixes, figsize=(17,5))
ax.xaxis.set_major_locator(pyplot.MultipleLocator(5000))
ax.set_title("Fixations by Line (Subject 1, Rectangle)")
fig = ax.figure
fig.tight_layout()
fig
Out[15]:
In [16]:
ax = plot.fixations.line_timeline_single(subject2_line_fixes, figsize=(17,5))
ax.xaxis.set_major_locator(pyplot.MultipleLocator(5000))
ax.set_title("Fixations by Line (Subject 2, Rectangle)")
fig = ax.figure
fig.tight_layout()
fig
Out[16]:

We can also calculate how much time was spent on each line during the trial.

In [45]:
code_image = data.busjahn_2013.code_image("rectangle")
print "Fixation Time by Line (Subject 1)"
plot.fixations.line_code_image(subject1_line_fixes, code_image, image_padding=5,
                               bar_height=0.75, bar_mult=1.015, num_lines=23)
Fixation Time by Line (Subject 1)

Out[45]:
In [46]:
code_image = data.busjahn_2013.code_image("rectangle")
print "Fixation Time by Line (Subject 2)"
plot.fixations.line_code_image(subject2_line_fixes, code_image, image_padding=5,
                               bar_height=0.75, bar_mult=1.015, num_lines=23)
Fixation Time by Line (Subject 2)

Out[46]:

With a little more effort, we can get how much time was spent on other kinds of AOIs.

In [17]:
exclude_aois = [aoi.make_aoi_column(k)
                for k in ["interface", "line chunks", "sub-line", "line"]]

ax = plot.aoi.kind_bars(subject1_fixes.drop(exclude_aois, axis=1), figsize=(15,8))
ax.set_title("Fixation Time by AOI (Subject 1, Rectangle)")
fig = ax.figure
fig.tight_layout()
fig.subplots_adjust(right=0.90)
fig
Out[17]:
In [18]:
exclude_aois = [aoi.make_aoi_column(k)
                for k in ["interface", "line chunks", "sub-line", "line"]]

ax = plot.aoi.kind_bars(subject2_fixes.drop(exclude_aois, axis=1), figsize=(15,8))
ax.set_title("Fixation Time by AOI (Subject 2, Rectangle)")
fig = ax.figure
fig.tight_layout()
fig.subplots_adjust(right=0.90)
fig
Out[18]:

Rolling Metrics

Summary metrics are good, but we may be interested in things that unfold over time within a trial. We'll compute 3 different "rolling" metrics over fixations that fit within the area of the screen with code.

In [19]:
code_aoi = aois[aois.name == "code box"].iloc[0]
code_bbox = code_aoi[["x", "y", "width", "height"]].values
print code_aoi["program"], code_bbox
rectangle [326.0 90.0 636.0 847.0]

Our 3 functions will be Cowan's spatial density, fixation count, and mean fixation duration. We'll plot the rolling metrics as overlapping line graphs.

In [24]:
rolling_funs = {
    "density" : lambda fixes: metrics.spatial_density(fixes, grid_bbox=code_bbox,
                                                      num_rows=10, num_cols=1),
    "fcount" : lambda fixes: len(fixes),
    "duration" : lambda fixes: fixes["duration_ms"].mean()
}
In [9]:
def rolling_plot(df):
    from matplotlib.ticker import MultipleLocator, FormatStrFormatter, FuncFormatter
   
    fig = pyplot.figure(figsize=(15, 8))
    ax = pyplot.axes()
    axes = [ax, ax.twinx(), ax.twinx()]
    plots = [None] * len(axes)
    
    fig.subplots_adjust(left=0, right=0.75)
    axes[2].spines['right'].set_position(('axes', 1.1))
    axes[2].set_frame_on(True)
    axes[2].patch.set_visible(False)
    
    plots[0] = axes[0].plot(df.index, df.density, color="b", marker="o", markersize=10, label="Density")
    axes[0].set_ylabel("Spatial Density", color="b")
    axes[0].tick_params(axis="y", colors="b")
    
    axes[1].plot(df.index, df.duration, color="r", marker="*", markersize=10, label="Duration")
    axes[1].set_ylabel("Mean Fixation Duration (ms)", color="r")
    axes[1].tick_params(axis="y", colors="r")
    
    axes[2].plot(df.index, df.fcount, color="g", marker="^", markersize=10, label="Fix Count")
    axes[2].set_ylabel("Fixation Count", color="g")
    axes[2].tick_params(axis="y", colors="g")
    
    #ax.grid()
    ax.set_xlabel("Time (sec)")
    ax.xaxis.set_major_formatter(FuncFormatter(lambda x, pos: str(int(x) / 1000)))
    ax.xaxis.set_major_locator(MultipleLocator(5000))
    for label in ax.get_xticklabels():
        label.set_rotation(90)
    
    return ax

With our metrics and plotting function in hand, let's look at the rolling metrics for subject 1. Our rolling window will be 4 seconds in size, and will move foward 1 second at time.

In [22]:
rolling_df = util.rolling_func(subject1_fixes, rolling_funs, 4000, 1000).dropna()
ax = rolling_plot(rolling_df)
ax.set_title("Rolling Metrics (Subject 1, Rectangle)")
fig = ax.figure
fig.tight_layout()
fig
Out[22]:

Same for subject 2:

In [23]:
rolling_df = util.rolling_func(subject2_fixes, rolling_funs, 4000, 1000).dropna()
ax = rolling_plot(rolling_df)
ax.set_title("Rolling Metrics (Subject 2, Rectangle)")
fig = ax.figure
fig.tight_layout()
fig
Out[23]:

Basketball Program

In [16]:
aois = data.busjahn_2013.areas_of_interest("basketball")
plot.aoi.draw_rectangles(aois[aois.kind == "line"], data.busjahn_2013.program_image("basketball"))
Out[16]:
In [9]:
subject1_fixes = all_fixes[all_fixes.trial_id == 10]
all_line_fixes = data.busjahn_2013.line_fixations()
subject1_line_fixes = all_line_fixes[all_line_fixes.trial_id == 10]
In [5]:
ax = plot.fixations.line_timeline_single(subject1_line_fixes, figsize=(17,7))
ax.xaxis.set_major_locator(pyplot.MultipleLocator(5000))
ax.set_title("Fixations by Line (Subject 1, Basketball)")
fig = ax.figure
fig.tight_layout()
fig
Out[5]:
In [6]:
code_image = data.busjahn_2013.code_image("basketball")
print "Fixation Time by Line (Subject 1)"
plot.fixations.line_code_image(subject1_line_fixes, code_image, image_padding=4,
                               bar_height=0.7, bar_mult=0.9425, num_lines=27)
Fixation Time by Line (Subject 1)

Out[6]:
In [7]:
exclude_aois = [aoi.make_aoi_column(k)
                for k in ["interface", "line chunks", "sub-line", "line"]]

ax = plot.aoi.kind_bars(subject1_fixes.drop(exclude_aois, axis=1), figsize=(15,8))
ax.set_title("Fixation Time by AOI (Subject 1, Basketball)")
fig = ax.figure
fig.tight_layout()
fig.subplots_adjust(right=0.90)
fig
Out[7]:
In [17]:
code_aoi = aois[aois.name == "code box"].iloc[0]
code_bbox = code_aoi[["x", "y", "width", "height"]].values
print code_aoi["program"], code_bbox
basketball [326.0 25.0 626.0 981.0]

In [18]:
rolling_funs = {
    "density" : lambda fixes: metrics.spatial_density(fixes, grid_bbox=code_bbox,
                                                      num_rows=10, num_cols=1),
    "fcount" : lambda fixes: len(fixes),
    "duration" : lambda fixes: fixes["duration_ms"].mean()
}
In [19]:
rolling_df = util.rolling_func(subject1_fixes, rolling_funs, 4000, 1000).dropna()
ax = rolling_plot(rolling_df)
ax.set_title("Rolling Metrics (Subject 1, Basketball)")
fig = ax.figure
fig.tight_layout()
fig
Out[19]:

Other Plots

In [15]:
pyplot.rc("font", size=20)
ax = plot.fix_timeline(subject1_line_fixes, 21, figsize=(15,7))
ax.xaxis.set_major_locator(pyplot.MultipleLocator(5000))
ax.set_title("Fixations by Line (Subject 1, Rectangle)")
fig = ax.figure
fig.tight_layout()
fig
Out[15]:
In [38]:
rolling_df = util.rolling_func(subject1_fixes, rolling_funs, 4000, 1000).dropna()
ax = plot.rolling_metrics(rolling_df, columns=rolling_df.columns,
                          names=["Spatial Density", "Mean Fixation Duration (ms)", "Fixation Count"],
                          figsize=(15, 7))
ax.set_title("Rolling Metrics (Subject 1, Rectangle)")
#ax.set_ylim((0, 0.8))
fig = ax.figure
fig.tight_layout()
fig
Out[38]: