%run prelude.ipy
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.
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
Every fixation has been hit-tested against different layers of area-of-interest (AOI) rectangles. For example, here are the rectangles for each line:
aois = data.busjahn_2013.areas_of_interest("rectangle")
plot.draw_rectangles(aois[aois.kind == "line"], data.busjahn_2013.program_image("rectangle"))
If we include only fixations that occurred inside one the above rectangles, we can assign a line number to each fixation.
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])
Plotting the timeline of fixated lines provides a great overview of a trial.
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
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
We can also calculate how much time was spent on each line during the trial.
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)
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)
With a little more effort, we can get how much time was spent on other kinds of AOIs.
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
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
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.
code_aoi = aois[aois.name == "code box"].iloc[0]
code_bbox = code_aoi[["x", "y", "width", "height"]].values
print code_aoi["program"], code_bbox
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.
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()
}
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.
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
Same for subject 2:
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
Basketball Program
aois = data.busjahn_2013.areas_of_interest("basketball")
plot.aoi.draw_rectangles(aois[aois.kind == "line"], data.busjahn_2013.program_image("basketball"))
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]
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
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)
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
code_aoi = aois[aois.name == "code box"].iloc[0]
code_bbox = code_aoi[["x", "y", "width", "height"]].values
print code_aoi["program"], code_bbox
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()
}
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
Other Plots
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
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