Skip to content

Commit b1a9b3e

Browse files
committed
Modified eyelink format bridge
1 parent e321366 commit b1a9b3e

File tree

6 files changed

+59
-16
lines changed

6 files changed

+59
-16
lines changed

PyTrack/Stimulus.py

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -762,8 +762,6 @@ def findMicrosaccades(self, sampling_freq=1000, plot_ms=False):
762762

763763
for fix_ind in range(len(fixation_indices["start"])):
764764

765-
766-
767765
all_MS = {"left" : None, "right" : None}
768766
ms_count = {"left" : None, "right" : None}
769767
ms_duration = {"left" : None, "right" : None}
@@ -805,9 +803,11 @@ def findMicrosaccades(self, sampling_freq=1000, plot_ms=False):
805803
a1.plot(smooth_gaze["left"]["x"][1:], smooth_gaze["left"]["y"][1:])
806804
a1.set_xlabel("x")
807805
a1.set_ylabel("y")
808-
a1.set_title("gaze plot")
806+
a1.set_title("Gaze Plot ")
809807
for i in range(MS["NB"]):
810808
a1.plot(smooth_gaze["left"]["x"][int(MS["bin"][i][0]) : int(MS["bin"][i][1]) + 1], smooth_gaze["left"]["y"][int(MS["bin"][i][0]) : int(MS["bin"][i][1]) + 1], color='r')
809+
# a1.set_xlim([-0.35, 0.25])
810+
# a1.set_ylim([-0.2, 1.25])
811811

812812
e = Ellipse((0, 0), 2*MS["bin"][0][7], 2*MS["bin"][0][8], linestyle='--', color='g', fill=False)
813813
a2.add_patch(e)
@@ -816,10 +816,11 @@ def findMicrosaccades(self, sampling_freq=1000, plot_ms=False):
816816
a2.plot(vel["left"]["x"], vel["left"]["y"], alpha=0.5)
817817
a2.set_xlabel("vel-x")
818818
a2.set_ylabel("vel-y")
819-
a2.set_title("gaze velocity plot")
819+
a2.set_title("Gaze Velocity Plot")
820820
for i in range(MS["NB"]):
821821
a2.plot(vel["left"]["x"][int(MS["bin"][i][0]) : int(MS["bin"][i][1]) + 1], vel["left"]["y"][int(MS["bin"][i][0]) : int(MS["bin"][i][1]) + 1], color='r')
822-
822+
# a2.set_xlim([-25, 40])
823+
# a2.set_ylim([-65, 70])
823824

824825
if not os.path.isdir(self.path + "/Subjects/" + self.subject_name + "/ms_gaze_vel/"):
825826
os.makedirs(self.path + "/Subjects/" + self.subject_name + "/ms_gaze_vel/")
@@ -1088,7 +1089,7 @@ def findBlinkParams(self):
10881089
return tuple(inside_aoi)
10891090

10901091

1091-
def gazePlot(self, save_fig=False, show_fig=True):
1092+
def gazePlot(self, save_fig=False, show_fig=True, save_data=False):
10921093
"""Function to plot eye gaze with numbered fixations.
10931094
10941095
Internal function of class that uses its `data` member variable. Can be invoked by an object of the class.
@@ -1099,6 +1100,8 @@ def gazePlot(self, save_fig=False, show_fig=True):
10991100
Save the gaze plot figure or not (Defaults to ``False``). If ``True``, will be saved in the Subjects folder of the experiment folder
11001101
show_fig : bool
11011102
Display the gaze plot figure or not (Defaults to ``True``).
1103+
save_data : bool
1104+
Save the data used for plotting as a csv file.
11021105
11031106
"""
11041107

@@ -1126,6 +1129,7 @@ def gazePlot(self, save_fig=False, show_fig=True):
11261129
(self.aoi_coords[3] - self.aoi_coords[1]),
11271130
color='r', fill=False, linestyle='--')
11281131
ax.add_patch(rect)
1132+
print(rect.get_verts())
11291133

11301134
# Circle AOI
11311135
elif len(self.aoi_coords) == 3:
@@ -1134,12 +1138,14 @@ def gazePlot(self, save_fig=False, show_fig=True):
11341138
self.aoi_coords[2],
11351139
color='r', fill=False, linestyle='--')
11361140
ax.add_patch(ellipse)
1141+
print(ellipse.get_verts())
11371142

11381143
# Polygon AOI
11391144
else:
11401145
xy = np.asarray(self.aoi_coords)
11411146
poly = Polygon(xy, color='r', fill=False, linestyle='--')
11421147
ax.add_patch(poly)
1148+
print(poly.get_verts())
11431149

11441150

11451151
fixation_dict = self.findFixations()
@@ -1161,11 +1167,16 @@ def gazePlot(self, save_fig=False, show_fig=True):
11611167
ax.plot(self.data["InterpGaze"]["left"]["x"], self.data["InterpGaze"]["left"]["y"], 'r-')
11621168

11631169
i = 0
1170+
exp_data = {"ind":[], "x":[], "y":[], "gaze_x":self.data["InterpGaze"]["left"]["x"], "gaze_y":self.data["InterpGaze"]["left"]["y"]}
11641171
for x, y in zip(fixation_gaze_x, fixation_gaze_y):
11651172
ax.plot(np.mean(x), np.mean(y), 'go', markersize=15, alpha=0.7)
1173+
exp_data["ind"].append(i)
1174+
exp_data["x"].append(np.mean(x))
1175+
exp_data["y"].append(np.mean(y))
11661176
ax.text(np.mean(x), np.mean(y), str(i), fontsize=10, color='w')
11671177
i += 1
11681178

1179+
11691180
ax.set_xlim(0, int(self.width))
11701181
ax.set_ylim(int(self.height), 0)
11711182

@@ -1175,10 +1186,16 @@ def gazePlot(self, save_fig=False, show_fig=True):
11751186
if save_fig:
11761187
fig.savefig(self.path + "/Subjects/" + self.subject_name + "/gaze_plot_" + self.name + ".png", dpi=300)
11771188

1189+
if save_data:
1190+
max_len = max([len(exp_data[x]) for x in exp_data])
1191+
for key in exp_data:
1192+
exp_data[key] = np.pad(exp_data[key], (0, max_len - len(exp_data[key])), 'constant', constant_values=float('nan'))
1193+
pd.DataFrame().from_dict(exp_data).to_csv(self.path + "/Subjects/" + self.subject_name + "/gaze_plot_data_" + self.name + ".csv")
1194+
11781195
plt.close(fig)
11791196

11801197

1181-
def gazeHeatMap(self, save_fig=False, show_fig=True):
1198+
def gazeHeatMap(self, save_fig=False, show_fig=True, save_data=False):
11821199
"""Function to plot heat map of gaze.
11831200
11841201
Internal function of class that uses its `data` member variable. Can be invoked by an object of the class.
@@ -1189,6 +1206,8 @@ def gazeHeatMap(self, save_fig=False, show_fig=True):
11891206
Save the heat map figure or not (Defaults to ``False``). If ``True``, will be saved in the Subjects folder of the experiment folder
11901207
show_fig : bool
11911208
Display the heat map figure or not (Defaults to ``True``).
1209+
save_data : bool
1210+
Save the data used for plotting as a csv file.
11921211
11931212
"""
11941213

@@ -1267,11 +1286,18 @@ def gazeHeatMap(self, save_fig=False, show_fig=True):
12671286
plt.close(fig)
12681287

12691288

1270-
def visualize(self, show=True):
1289+
def visualize(self, show=True, save_data=False):
12711290
"""Function to create dynamic plot of gaze and pupil size.
12721291
12731292
Internal function of class that uses its `data` member variable. Does not take any input and can be invoked by an object of the class.
12741293
1294+
Paramaters
1295+
----------
1296+
show : bool
1297+
Open figure after plotting the data or not.
1298+
save_data : bool
1299+
Save the data used for plotting as a csv file.
1300+
12751301
"""
12761302
if self.data == None:
12771303
return

PyTrack/etDataReader.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,8 @@ def message(msg):
590590
fixation_flag = 0
591591
saccade_flag = 0
592592
blink_flag = 0
593+
cont_flag = -1
594+
last_time = 0
593595

594596
which_eye = ''
595597
if eye == 'B':
@@ -599,14 +601,23 @@ def message(msg):
599601

600602
# loop through all lines
601603
for line in raw:
602-
604+
# print(line)
603605
# check if trial has already started
604606
if started:
605607
# only check for stop if there is one
606608
if stop != None:
607-
if stop in line:
608-
started = False
609-
trialend = True
609+
if stop in line or last_time == cont_flag:
610+
t = -1
611+
if line[0:3] == "MSG":
612+
ms = line.find(" ")
613+
t = int(line[4:ms])
614+
615+
if trackertime[-1] < t:
616+
cont_flag = t
617+
else:
618+
cont_flag = -1
619+
started = False
620+
trialend = True
610621
# check for new start otherwise
611622
else:
612623
if (start in line) or (line == finalline):
@@ -795,6 +806,7 @@ def message(msg):
795806

796807
time.append(int(l[0])-starttime)
797808
trackertime.append(int(l[0]))
809+
last_time = int(l[0])
798810

799811

800812
# # # # #

PyTrack/formatBridge.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,9 @@ def toBase(et_type, filename, stim_list=None, start='START', stop=None, eye='B')
124124
del(temp_dict)
125125

126126
i += 1
127+
print("Progress: %.2f %" % ((i*100)/len(data)), end="\r")
127128

129+
print()
128130
return df
129131

130132

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[![Build Status](https://travis-ci.org/titoghose/PyTrack.svg?branch=master)](https://travis-ci.org/titoghose/PyTrack)
22
[![codecov](https://codecov.io/gh/titoghose/PyTrack/branch/master/graph/badge.svg)](https://codecov.io/gh/titoghose/PyTrack)
3-
[![Documentation Status](https://readthedocs.org/projects/pytrack-ntu/badge/)](https://pytrack-ntu.readthedocs.io/en/latest/)
3+
[![Documentation Status](https://readthedocs.org/projects/pytrack-ntu/badge/?style=flat-square)](https://pytrack-ntu.readthedocs.io/en/latest/?badge=latest)
44

55
# PyTrack
66

@@ -63,7 +63,7 @@ Please make sure that pip is for Python3 and not Python2. Python3 can be found
6363
**NOTE:** Python3 can be installed alongside Python2
6464

6565
# Sample Data
66-
In order to test the toolkit some sample data in SMI, EyeLink and Tobii formats can be found [here](https://drive.google.com/open?id=1tWD69hurELVuVRFzizCbukWnr22RZrnp). The .txt file in the folder describes the data found. The SMI and Tobii files have been taken from [here](http://www2.hu-berlin.de/eyetracking-eeg/testdata.html).
66+
In order to test the toolkit some sample data in SMI, EyeLink and Tobii formats can be found [here](https://osf.io/f9mey/files/). The .txt file in the folder describes the data found. The SMI and Tobii files have been taken from [here](http://www2.hu-berlin.de/eyetracking-eeg/testdata.html).
6767

6868
# Using PyTrack
6969

@@ -370,8 +370,11 @@ This project is licensed under the GPL3 License - see the [LICENSE.txt](LICENSE.
370370

371371
# Acknowledgments
372372

373+
* We would like to thank [Dr. Dominique Makowski](https://dominiquemakowski.github.io/) for helping us develop this toolkit.
374+
373375
* The formatsBridge module was adapted from the work done by [Edwin Dalmaijer](https://github.com/esdalmaijer) in [PyGazeAnalyser](https://github.com/esdalmaijer/PyGazeAnalyser/).
374376

375377
* This work was done under the supervision of [Dr. Chng Eng Siong](http://www.ntu.edu.sg/home/aseschng/) - School of Computer Science and Engineering NTU and in collaboration with [Dr. Xu Hong](http://www.ntu.edu.sg/home/xuhong/) - School of Humanitites and Social Sciences NTU.
378+
376379
* We extend our thanks to the **Department of Computer Science and Engineering Manipal Isntitute of Technology**[[link]](https://manipal.edu/mit/department-faculty/department-list/computer-science-and-engineering.html) and the **Department of Computer Science and Information Systems BITS Pilani, Hyderabad Campus** [[link]](https://www.bits-pilani.ac.in/hyderabad/computerscience/ComputerScience).
377380

docs/Introduction.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ Sample Data
8585

8686
In order to test the toolkit some sample data in SMI, EyeLink and Tobii
8787
formats can be found
88-
`here <https://drive.google.com/open?id=1tWD69hurELVuVRFzizCbukWnr22RZrnp>`__.
88+
`here <https://osf.io/f9mey/files/>`__.
8989
The .txt file in the folder describes the data found. The SMI and Tobii
9090
files have been taken from
9191
`here <http://www2.hu-berlin.de/eyetracking-eeg/testdata.html>`__.

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name="PyTrack-NTU",
8-
version="0.0.12",
8+
version="0.0.13",
99
author="Upamanyu Ghose, Arvind Srinivasan",
1010
1111
description="An end-to-end python analysis toolkit for eye tracking",

0 commit comments

Comments
 (0)