aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThéo de la Hogue2024-09-04 13:56:36 +0200
committerThéo de la Hogue2024-09-04 13:56:36 +0200
commitbe8a44033bd490ea7f4ddb1514a9cc2888affb88 (patch)
tree3274e4157e4618749d70c8cd1788ee3644b0aaca
parent08c48347a140becc5e4b60e03f2979305166a079 (diff)
downloadargaze-be8a44033bd490ea7f4ddb1514a9cc2888affb88.zip
argaze-be8a44033bd490ea7f4ddb1514a9cc2888affb88.tar.gz
argaze-be8a44033bd490ea7f4ddb1514a9cc2888affb88.tar.bz2
argaze-be8a44033bd490ea7f4ddb1514a9cc2888affb88.tar.xz
Improving CVS file parsing. Documenting CSV file support.
-rw-r--r--docs/user_guide/eye_tracking_context/configuration_and_execution.md1
-rw-r--r--docs/user_guide/eye_tracking_context/context_modules/file.md35
-rw-r--r--docs/user_guide/utils/demonstrations_scripts.md10
-rw-r--r--mkdocs.yml1
-rw-r--r--src/argaze/utils/contexts/File.py100
-rw-r--r--src/argaze/utils/contexts/__init__.py4
-rw-r--r--src/argaze/utils/demo/csv_file_context_xy_list.json9
-rw-r--r--src/argaze/utils/demo/csv_file_context_xy_splitted.json (renamed from src/argaze/utils/demo/csv_file_context.json)2
-rw-r--r--src/argaze/utils/demo/gaze_positions_xy_list.csv1052
-rw-r--r--src/argaze/utils/demo/gaze_positions_xy_splitted.csv (renamed from src/argaze/utils/demo/gaze_positions.csv)0
10 files changed, 1192 insertions, 22 deletions
diff --git a/docs/user_guide/eye_tracking_context/configuration_and_execution.md b/docs/user_guide/eye_tracking_context/configuration_and_execution.md
index 100ab5e..3deeb57 100644
--- a/docs/user_guide/eye_tracking_context/configuration_and_execution.md
+++ b/docs/user_guide/eye_tracking_context/configuration_and_execution.md
@@ -7,6 +7,7 @@ The [utils.contexts module](../../argaze.md/#argaze.utils.contexts) provides rea
* [Tobii Pro Glasses 3](context_modules/tobii_pro_glasses_3.md) data capture context,
* [Pupil Labs Invisible](context_modules/pupil_labs_invisible.md) data capture context,
* [Pupil Labs Neon](context_modules/pupil_labs_neon.md) data capture context,
+* [File](context_modules/file.md) data playback contexts,
* [OpenCV](context_modules/opencv.md) window cursor position capture and movie playback,
* [Random](context_modules/random.md) gaze position generator.
diff --git a/docs/user_guide/eye_tracking_context/context_modules/file.md b/docs/user_guide/eye_tracking_context/context_modules/file.md
new file mode 100644
index 0000000..8a66b83
--- /dev/null
+++ b/docs/user_guide/eye_tracking_context/context_modules/file.md
@@ -0,0 +1,35 @@
+File
+======
+
+ArGaze provides a ready-made contexts to read data from various file format.
+
+To select a desired context, the JSON samples have to be edited and saved inside an [ArContext configuration](../configuration_and_execution.md) file.
+Notice that the *pipeline* entry is mandatory.
+
+```json
+{
+ JSON sample
+ "pipeline": ...
+}
+```
+
+Read more about [ArContext base class in code reference](../../../argaze.md/#argaze.ArFeatures.ArContext).
+
+## CSV
+
+::: argaze.utils.contexts.File.CSV
+
+### JSON sample
+
+```json
+{
+ "argaze.utils.contexts.File.CSV": {
+ "name": "CSV file data playback",
+ "path": "./src/argaze/utils/demo/gaze_positions.csv",
+ "timestamp_column": "Timestamp (ms)",
+ "x_column": "Gaze Position X (px)",
+ "y_column": "Gaze Position Y (px)",
+ "pipeline": ...
+ }
+}
+```
diff --git a/docs/user_guide/utils/demonstrations_scripts.md b/docs/user_guide/utils/demonstrations_scripts.md
index e55e547..a2698b4 100644
--- a/docs/user_guide/utils/demonstrations_scripts.md
+++ b/docs/user_guide/utils/demonstrations_scripts.md
@@ -22,10 +22,16 @@ python -m argaze load ./src/argaze/utils/demo/random_context.json
## CSV file context
-Load **csv_file_context.json** file to analyze gaze positions from a CSV file:
+Load **csv_file_context_xy_splitted.json** file to analyze gaze positions from a CSV file where gaze position coordinates are splitted in two seperated column:
```shell
-python -m argaze load ./src/argaze/utils/demo/csv_file_context.json
+python -m argaze load ./src/argaze/utils/demo/csv_file_context_xy_splitted.json
+```
+
+Load **csv_file_context_xy_list.json** file to analyze gaze positions from a CSV file where gaze position coordinates are stored as a list in one single column:
+
+```shell
+python -m argaze load ./src/argaze/utils/demo/csv_file_context_xy_list.json
```
## OpenCV
diff --git a/mkdocs.yml b/mkdocs.yml
index 6384ae0..19ec21a 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -12,6 +12,7 @@ nav:
- user_guide/eye_tracking_context/context_modules/tobii_pro_glasses_3.md
- user_guide/eye_tracking_context/context_modules/pupil_labs_invisible.md
- user_guide/eye_tracking_context/context_modules/pupil_labs_neon.md
+ - user_guide/eye_tracking_context/context_modules/file.md
- user_guide/eye_tracking_context/context_modules/opencv.md
- user_guide/eye_tracking_context/context_modules/random.md
- Advanced Topics:
diff --git a/src/argaze/utils/contexts/File.py b/src/argaze/utils/contexts/File.py
index da12c5a..68854b8 100644
--- a/src/argaze/utils/contexts/File.py
+++ b/src/argaze/utils/contexts/File.py
@@ -21,6 +21,7 @@ import logging
import time
import math
import threading
+import ast
import pandas
import numpy
@@ -39,9 +40,12 @@ class CSV(ArFeatures.DataPlaybackContext):
# Init private attributes
self.__path = None
self.__separator = ','
+
self.__timestamp_column = None
self.__x_column = None
self.__y_column = None
+ self.__xy_column = None
+
self.__start = math.nan
self.__end = math.nan
self.__duration = 0.
@@ -69,7 +73,10 @@ class CSV(ArFeatures.DataPlaybackContext):
@property
def timestamp_column(self) -> str:
- """Select timestamp column."""
+ """Timestamp column name in file.
+ !!! warning
+ This column name is mandatory.
+ """
return self.__timestamp_column
@timestamp_column.setter
@@ -79,7 +86,10 @@ class CSV(ArFeatures.DataPlaybackContext):
@property
def x_column(self) -> str:
- """Select x column."""
+ """X coordinate column name.
+ !!! note
+ This column name is required in the case where gaze position coordinate is splitted in two columns.
+ """
return self.__x_column
@x_column.setter
@@ -89,13 +99,30 @@ class CSV(ArFeatures.DataPlaybackContext):
@property
def y_column(self) -> str:
- """Select y column."""
+ """Y coordinate column name.
+ !!! note
+ This column name is required in the case where gaze position coordinate is splitted in two columns.
+ """
return self.__y_column
@y_column.setter
def y_column(self, y_column: str):
self.__y_column = y_column
+
+ @property
+ def xy_column(self) -> str:
+ """X and Y coordinate column name.
+ !!! note
+ This column name is required in the case where gaze position coordinate is a list stored in one column.
+ """
+ return self.__xy_column
+
+ @xy_column.setter
+ def xy_column(self, xy_column: str):
+
+ self.__xy_column = xy_column
+
@property
def start(self) -> int|float:
"""Start reading timestamp."""
@@ -133,21 +160,40 @@ class CSV(ArFeatures.DataPlaybackContext):
logging.info('CSV file context starts...')
- # Load gaze positions from a CSV file into Panda Dataframe
- data_selector = {
- self.__timestamp_column: numpy.float64,
- self.__x_column: numpy.float64,
- self.__y_column: numpy.float64
- }
+ # Select data to load from CSV file
+ data_columns = []
+ data_types = {}
+ data_converters = {}
+
+ # Select timestamp column
+ if self.__timestamp_column:
+
+ data_columns.append(self.__timestamp_column)
+ data_types[self.__timestamp_column] = numpy.float64
+
+ else:
+
+ logging.error('Missing timestamp column name')
- dataframe = pandas.read_csv(self.__path, delimiter = self.__separator, low_memory = False, usecols=data_selector.keys(), dtype=data_selector)
+ # Case where gaze position coordinate is splitted in two columns
+ if self.__x_column and self.__y_column:
- # Rename columns with generic names
- dataframe.rename(columns={
- self.__timestamp_column: 'timestamp',
- self.__x_column: 'x',
- self.__y_column: 'y'
- }, inplace=True)
+ data_columns.append(self.__x_column)
+ data_types[self.__x_column] = numpy.float64
+
+ data_columns.append(self.__y_column)
+ data_types[self.__y_column] = numpy.float64
+
+ # Case where gaze position coordinate is a list stored in one column
+ elif self.__xy_column:
+
+ data_columns.append(self.__xy_column)
+ data_converters[self.__xy_column] = ast.literal_eval
+
+ dataframe = pandas.read_csv(self.__path, delimiter = self.__separator, low_memory = False, usecols=data_columns, dtype=data_types, converters=data_converters)
+
+ # DEBUG
+ print(dataframe)
# Optionnaly select a time range
if not math.isnan(self.start):
@@ -158,6 +204,26 @@ class CSV(ArFeatures.DataPlaybackContext):
dataframe = dataframe.loc[(dataframe['timestamp'] <= self.end)]
+ # Transform dataframe to a get only timestamp, x, y columns
+
+ # Case where gaze position coordinate is splitted in two columns
+ if self.__x_column and self.__y_column:
+
+ dataframe.rename(columns={
+ self.__timestamp_column: 'timestamp',
+ self.__x_column: 'x',
+ self.__y_column: 'y'
+ }, inplace=True)
+
+ # Case where gaze position coordinate is a list stored in one column
+ elif self.__xy_column:
+
+ dataframe.rename(columns={
+ self.__timestamp_column: 'timestamp',
+ }, inplace=True)
+
+ dataframe[['x','y']] = pandas.DataFrame(dataframe[self.__xy_column].to_list(), columns=['x','y'])
+
# Filter unvalid gaze positions
len_before = len(dataframe)
dataframe = dataframe[(dataframe['x'].notna() & dataframe['y']).notna()]
@@ -212,5 +278,5 @@ class CSV(ArFeatures.DataPlaybackContext):
self.__progression = row['timestamp'] / self.__duration
# TEST
- #time.sleep(0.01)
+ time.sleep(0.01)
\ No newline at end of file
diff --git a/src/argaze/utils/contexts/__init__.py b/src/argaze/utils/contexts/__init__.py
index 19b7533..c427de0 100644
--- a/src/argaze/utils/contexts/__init__.py
+++ b/src/argaze/utils/contexts/__init__.py
@@ -1,4 +1,4 @@
"""
-Collection of device interfaces.
+Collection of contexts.
"""
-__all__ = ['TobiiProGlasses2']
+__all__ = ['File','OpencCV','PupilLabsInvisible','PupilLabsNeon','Random','TobiiProGlasses2','TobiiProGlasses3']
diff --git a/src/argaze/utils/demo/csv_file_context_xy_list.json b/src/argaze/utils/demo/csv_file_context_xy_list.json
new file mode 100644
index 0000000..2030b8b
--- /dev/null
+++ b/src/argaze/utils/demo/csv_file_context_xy_list.json
@@ -0,0 +1,9 @@
+{
+ "argaze.utils.contexts.File.CSV" : {
+ "name": "CSV file data playback",
+ "path": "./src/argaze/utils/demo/gaze_positions_xy_list.csv",
+ "timestamp_column": "Timestamp (ms)",
+ "xy_column": "Gaze Position (px)",
+ "pipeline": "gaze_analysis_pipeline.json"
+ }
+} \ No newline at end of file
diff --git a/src/argaze/utils/demo/csv_file_context.json b/src/argaze/utils/demo/csv_file_context_xy_splitted.json
index a09914f..87fce4d 100644
--- a/src/argaze/utils/demo/csv_file_context.json
+++ b/src/argaze/utils/demo/csv_file_context_xy_splitted.json
@@ -1,7 +1,7 @@
{
"argaze.utils.contexts.File.CSV" : {
"name": "CSV file data playback",
- "path": "./src/argaze/utils/demo/gaze_positions.csv",
+ "path": "./src/argaze/utils/demo/gaze_positions_xy_splitted.csv",
"timestamp_column": "Timestamp (ms)",
"x_column": "Gaze Position X (px)",
"y_column": "Gaze Position Y (px)",
diff --git a/src/argaze/utils/demo/gaze_positions_xy_list.csv b/src/argaze/utils/demo/gaze_positions_xy_list.csv
new file mode 100644
index 0000000..759b897
--- /dev/null
+++ b/src/argaze/utils/demo/gaze_positions_xy_list.csv
@@ -0,0 +1,1052 @@
+"Timestamp (ms)","Gaze Position (px)"
+6016,"[400,443]"
+6056,"[400,443]"
+6106,"[401,443]"
+6128,"[401,443]"
+6168,"[401,442]"
+6367,"[401,442]"
+6409,"[401,442]"
+6486,"[401,442]"
+7310,"[408,433]"
+7334,"[415,427]"
+7375,"[435,412]"
+7397,"[441,409]"
+7438,"[445,405]"
+7472,"[446,405]"
+7509,"[446,404]"
+7532,"[446,404]"
+7570,"[449,392]"
+7593,"[450,384]"
+7631,"[450,378]"
+7653,"[450,377]"
+7705,"[432,371]"
+7730,"[415,365]"
+7766,"[390,353]"
+7788,"[376,345]"
+7828,"[334,318]"
+7847,"[318,306]"
+7890,"[296,288]"
+7912,"[286,277]"
+7950,"[278,263]"
+7978,"[275,256]"
+8018,"[268,246]"
+8039,"[266,245]"
+8074,"[265,244]"
+8092,"[264,243]"
+8128,"[262,243]"
+8185,"[263,242]"
+8205,"[264,241]"
+8241,"[265,231]"
+8261,"[265,228]"
+8305,"[267,227]"
+8337,"[267,226]"
+8392,"[267,228]"
+8427,"[269,232]"
+8445,"[270,232]"
+8481,"[272,231]"
+8501,"[273,228]"
+8537,"[273,219]"
+8558,"[272,217]"
+8592,"[272,217]"
+8613,"[271,218]"
+8650,"[271,222]"
+8671,"[271,225]"
+8703,"[272,227]"
+8724,"[272,227]"
+8755,"[274,227]"
+8776,"[274,226]"
+8813,"[275,224]"
+8834,"[275,223]"
+8866,"[275,223]"
+8886,"[279,225]"
+8922,"[292,228]"
+8944,"[312,227]"
+8981,"[351,222]"
+9000,"[382,218]"
+9033,"[424,214]"
+9053,"[447,213]"
+9087,"[510,216]"
+9104,"[538,216]"
+9137,"[591,218]"
+9156,"[620,220]"
+9192,"[691,219]"
+9212,"[719,216]"
+9246,"[788,214]"
+9267,"[812,215]"
+9300,"[855,216]"
+9319,"[878,215]"
+9352,"[900,215]"
+9371,"[907,216]"
+9403,"[915,217]"
+9420,"[915,217]"
+9464,"[915,217]"
+9484,"[915,218]"
+9519,"[913,219]"
+9538,"[912,219]"
+9573,"[904,222]"
+9592,"[893,224]"
+9626,"[875,225]"
+9645,"[871,226]"
+9677,"[869,226]"
+9738,"[869,227]"
+9760,"[870,229]"
+9798,"[872,231]"
+9818,"[872,231]"
+9851,"[875,232]"
+9871,"[879,232]"
+9904,"[883,230]"
+9925,"[884,229]"
+9963,"[886,228]"
+9984,"[886,227]"
+10073,"[887,229]"
+10125,"[892,234]"
+10146,"[894,234]"
+10181,"[895,233]"
+10202,"[896,231]"
+10232,"[896,229]"
+10252,"[896,229]"
+10341,"[896,229]"
+10363,"[896,232]"
+10399,"[894,247]"
+10420,"[894,254]"
+10454,"[890,274]"
+10472,"[887,284]"
+10519,"[866,316]"
+10540,"[858,328]"
+10573,"[842,352]"
+10590,"[830,370]"
+10621,"[816,386]"
+10641,"[801,399]"
+10671,"[780,415]"
+10690,"[770,422]"
+10723,"[749,435]"
+10742,"[734,442]"
+10772,"[717,449]"
+10790,"[699,458]"
+10823,"[673,468]"
+10839,"[659,471]"
+10868,"[639,477]"
+10885,"[625,481]"
+10921,"[597,492]"
+10941,"[587,496]"
+10975,"[566,508]"
+10991,"[558,513]"
+11025,"[545,523]"
+11044,"[542,527]"
+11078,"[537,536]"
+11095,"[536,540]"
+11126,"[535,548]"
+11142,"[535,551]"
+11177,"[538,556]"
+11196,"[538,557]"
+11230,"[541,559]"
+11247,"[542,559]"
+11288,"[542,559]"
+11331,"[542,559]"
+11349,"[541,559]"
+11383,"[540,558]"
+11441,"[542,558]"
+11462,"[544,559]"
+11497,"[552,562]"
+11518,"[558,566]"
+11549,"[561,569]"
+11571,"[562,569]"
+11605,"[562,570]"
+11657,"[565,564]"
+11676,"[565,561]"
+11711,"[564,557]"
+11766,"[564,558]"
+11787,"[565,560]"
+11822,"[569,569]"
+11841,"[569,570]"
+11877,"[571,570]"
+11898,"[572,568]"
+11933,"[573,564]"
+11954,"[574,561]"
+11988,"[575,559]"
+12009,"[575,559]"
+12078,"[575,560]"
+12115,"[578,564]"
+12137,"[583,565]"
+12171,"[599,560]"
+12192,"[607,549]"
+12229,"[612,537]"
+12254,"[613,535]"
+12288,"[613,536]"
+12305,"[613,537]"
+12334,"[613,539]"
+12354,"[613,539]"
+12388,"[617,541]"
+12406,"[624,540]"
+12438,"[638,534]"
+12458,"[647,530]"
+12495,"[685,512]"
+12515,"[706,502]"
+12547,"[752,474]"
+12567,"[779,449]"
+12602,"[811,405]"
+12622,"[830,380]"
+12653,"[848,359]"
+12671,"[864,341]"
+12706,"[881,316]"
+12726,"[887,308]"
+12760,"[890,305]"
+12776,"[892,305]"
+12812,"[896,301]"
+12831,"[898,300]"
+12868,"[901,299]"
+12888,"[911,296]"
+12926,"[928,284]"
+12947,"[936,280]"
+12983,"[957,266]"
+13000,"[963,262]"
+13034,"[969,257]"
+13053,"[969,257]"
+13087,"[969,258]"
+13108,"[969,260]"
+13142,"[970,266]"
+13159,"[971,267]"
+13189,"[971,267]"
+13216,"[972,266]"
+13249,"[972,261]"
+13271,"[970,256]"
+13310,"[964,252]"
+13331,"[963,252]"
+13367,"[962,253]"
+13388,"[962,255]"
+13422,"[962,257]"
+13443,"[963,257]"
+13480,"[964,256]"
+13500,"[964,255]"
+13536,"[964,253]"
+13556,"[964,253]"
+13590,"[964,254]"
+13611,"[964,255]"
+13647,"[965,257]"
+13668,"[965,257]"
+13705,"[966,256]"
+13725,"[967,253]"
+13762,"[959,243]"
+13782,"[944,238]"
+13816,"[914,234]"
+13837,"[893,233]"
+13870,"[830,223]"
+13890,"[806,216]"
+13922,"[751,204]"
+13941,"[718,201]"
+13974,"[655,192]"
+13993,"[629,188]"
+14030,"[565,184]"
+14051,"[539,184]"
+14082,"[491,186]"
+14100,"[467,186]"
+14132,"[420,189]"
+14150,"[393,189]"
+14182,"[363,190]"
+14198,"[349,189]"
+14232,"[324,188]"
+14252,"[315,188]"
+14286,"[306,190]"
+14305,"[303,190]"
+14338,"[295,191]"
+14358,"[295,191]"
+14394,"[295,190]"
+14414,"[296,190]"
+14448,"[299,188]"
+14468,"[302,186]"
+14501,"[311,178]"
+14521,"[317,174]"
+14556,"[319,174]"
+14614,"[318,177]"
+14634,"[318,181]"
+14666,"[318,182]"
+14686,"[319,182]"
+14721,"[320,181]"
+14741,"[320,180]"
+14776,"[319,179]"
+14795,"[318,179]"
+14835,"[313,181]"
+14856,"[312,185]"
+14896,"[312,186]"
+14917,"[312,186]"
+14950,"[315,185]"
+14971,"[316,184]"
+15007,"[316,182]"
+15027,"[315,182]"
+15069,"[309,182]"
+15094,"[302,187]"
+15127,"[285,199]"
+15144,"[276,205]"
+15178,"[261,219]"
+15204,"[256,223]"
+15238,"[250,229]"
+15256,"[243,239]"
+15290,"[235,263]"
+15309,"[229,274]"
+15344,"[217,294]"
+15363,"[212,302]"
+15400,"[205,314]"
+15419,"[204,314]"
+15453,"[204,314]"
+15482,"[203,313]"
+15517,"[204,307]"
+15537,"[204,305]"
+15569,"[203,304]"
+15586,"[203,303]"
+15621,"[202,303]"
+15641,"[203,302]"
+15673,"[208,296]"
+15694,"[209,294]"
+15732,"[210,291]"
+15753,"[210,291]"
+15790,"[210,290]"
+15808,"[210,291]"
+15842,"[211,292]"
+15861,"[211,292]"
+15899,"[212,292]"
+15924,"[212,291]"
+15955,"[209,290]"
+15973,"[209,290]"
+16010,"[208,291]"
+16032,"[208,291]"
+16070,"[208,287]"
+16091,"[210,279]"
+16122,"[210,258]"
+16140,"[208,244]"
+16174,"[205,213]"
+16193,"[204,203]"
+16223,"[203,195]"
+16239,"[203,192]"
+16273,"[203,190]"
+16291,"[203,190]"
+16325,"[203,192]"
+16345,"[205,202]"
+16377,"[210,210]"
+16397,"[211,210]"
+16433,"[213,208]"
+16454,"[213,205]"
+16488,"[211,202]"
+16507,"[211,202]"
+16543,"[211,202]"
+16565,"[211,203]"
+16600,"[212,205]"
+16621,"[213,206]"
+16654,"[214,206]"
+16674,"[214,206]"
+16713,"[214,203]"
+16734,"[213,203]"
+16768,"[212,203]"
+16788,"[213,206]"
+16823,"[223,224]"
+16843,"[227,229]"
+16876,"[241,236]"
+16894,"[252,242]"
+16930,"[263,252]"
+16950,"[269,258]"
+16987,"[273,262]"
+17006,"[278,267]"
+17037,"[284,272]"
+17054,"[288,275]"
+17089,"[290,275]"
+17106,"[291,276]"
+17139,"[299,282]"
+17162,"[303,285]"
+17197,"[305,286]"
+17217,"[306,287]"
+17256,"[307,287]"
+17277,"[307,285]"
+17315,"[302,279]"
+17337,"[302,279]"
+17373,"[304,281]"
+17394,"[306,282]"
+17427,"[308,281]"
+17448,"[308,281]"
+17484,"[308,280]"
+17505,"[307,280]"
+17544,"[308,281]"
+17567,"[309,282]"
+17603,"[316,285]"
+17624,"[326,291]"
+17662,"[350,319]"
+17683,"[361,336]"
+17719,"[389,378]"
+17738,"[403,396]"
+17768,"[435,430]"
+17788,"[451,444]"
+17822,"[486,473]"
+17842,"[499,482]"
+17875,"[523,500]"
+17894,"[538,510]"
+17928,"[552,519]"
+17947,"[557,522]"
+17981,"[565,528]"
+17998,"[566,529]"
+18033,"[568,527]"
+18051,"[569,527]"
+18085,"[572,527]"
+18102,"[573,526]"
+18136,"[574,522]"
+18153,"[575,520]"
+18185,"[578,518]"
+18206,"[579,517]"
+18242,"[580,517]"
+18300,"[581,517]"
+18321,"[582,517]"
+18359,"[585,513]"
+18379,"[586,509]"
+18411,"[590,498]"
+18432,"[592,491]"
+18467,"[593,487]"
+18489,"[594,487]"
+18527,"[594,486]"
+18582,"[595,490]"
+18601,"[596,490]"
+18638,"[597,491]"
+18660,"[598,490]"
+18696,"[599,483]"
+18717,"[599,481]"
+18750,"[599,480]"
+18771,"[600,483]"
+18810,"[603,496]"
+18830,"[604,500]"
+18866,"[609,508]"
+18888,"[613,513]"
+18924,"[614,513]"
+18945,"[615,514]"
+18983,"[621,530]"
+19001,"[622,538]"
+19035,"[624,548]"
+19060,"[625,554]"
+19093,"[626,567]"
+19110,"[626,570]"
+19145,"[626,571]"
+19164,"[626,572]"
+19199,"[628,576]"
+19218,"[628,576]"
+19249,"[631,576]"
+19266,"[632,575]"
+19304,"[633,573]"
+19325,"[633,573]"
+19405,"[633,574]"
+19428,"[637,576]"
+19467,"[642,578]"
+19488,"[642,578]"
+19546,"[643,578]"
+19583,"[644,577]"
+19604,"[645,576]"
+19636,"[649,572]"
+19654,"[651,569]"
+19686,"[654,567]"
+19707,"[657,565]"
+19745,"[666,559]"
+19764,"[672,555]"
+19801,"[691,535]"
+19822,"[704,514]"
+19853,"[720,489]"
+19872,"[740,462]"
+19907,"[771,419]"
+19926,"[791,382]"
+19960,"[814,335]"
+19977,"[825,315]"
+20010,"[846,289]"
+20030,"[859,275]"
+20063,"[877,258]"
+20080,"[885,249]"
+20115,"[897,240]"
+20134,"[901,238]"
+20170,"[902,239]"
+20190,"[903,246]"
+20224,"[905,252]"
+20242,"[906,253]"
+20277,"[908,258]"
+20296,"[910,266]"
+20330,"[911,275]"
+20350,"[910,276]"
+20384,"[910,279]"
+20404,"[909,282]"
+20443,"[908,289]"
+20464,"[908,290]"
+20560,"[907,290]"
+20597,"[907,290]"
+20630,"[907,289]"
+20665,"[907,286]"
+20686,"[907,285]"
+20745,"[907,286]"
+20777,"[908,288]"
+20798,"[911,288]"
+20835,"[923,283]"
+20854,"[937,272]"
+20891,"[955,247]"
+20913,"[964,231]"
+20947,"[973,211]"
+20968,"[980,196]"
+21004,"[986,175]"
+21021,"[989,166]"
+21054,"[990,142]"
+21071,"[989,135]"
+21100,"[988,129]"
+21120,"[987,129]"
+21156,"[983,131]"
+21177,"[980,134]"
+21213,"[978,137]"
+21232,"[977,142]"
+21270,"[974,158]"
+21292,"[974,162]"
+21326,"[969,169]"
+21348,"[969,172]"
+21381,"[967,177]"
+21402,"[965,180]"
+21436,"[965,181]"
+21494,"[965,179]"
+21516,"[964,179]"
+21554,"[959,178]"
+21572,"[957,178]"
+21607,"[949,181]"
+21629,"[948,182]"
+21666,"[947,183]"
+21686,"[947,184]"
+21723,"[942,185]"
+21745,"[936,185]"
+21778,"[920,183]"
+21797,"[910,181]"
+21833,"[892,180]"
+21854,"[890,181]"
+21889,"[889,181]"
+21918,"[889,181]"
+21954,"[895,186]"
+21973,"[903,189]"
+22008,"[922,198]"
+22029,"[928,200]"
+22069,"[930,200]"
+22091,"[928,200]"
+22128,"[909,192]"
+22149,"[902,191]"
+22182,"[895,191]"
+22205,"[894,191]"
+22251,"[893,191]"
+22278,"[894,193]"
+22317,"[894,194]"
+22338,"[894,194]"
+22375,"[895,194]"
+22396,"[896,193]"
+22433,"[900,188]"
+22454,"[902,187]"
+22492,"[915,187]"
+22513,"[920,188]"
+22550,"[924,190]"
+22571,"[930,195]"
+22609,"[949,212]"
+22631,"[962,219]"
+22667,"[979,225]"
+22686,"[991,226]"
+22717,"[1000,227]"
+22734,"[1004,228]"
+22770,"[1005,228]"
+22790,"[1005,230]"
+22821,"[1005,231]"
+22850,"[1005,231]"
+22886,"[1003,231]"
+22906,"[1001,231]"
+22943,"[985,232]"
+22964,"[975,231]"
+23003,"[959,230]"
+23025,"[956,231]"
+23063,"[954,233]"
+23084,"[954,233]"
+23116,"[954,235]"
+23135,"[956,236]"
+23174,"[956,239]"
+23195,"[956,241]"
+23231,"[954,244]"
+23250,"[953,244]"
+23288,"[948,242]"
+23309,"[941,239]"
+23347,"[918,228]"
+23366,"[906,226]"
+23404,"[898,224]"
+23424,"[894,223]"
+23460,"[892,221]"
+23480,"[890,221]"
+23513,"[890,222]"
+23530,"[891,224]"
+23568,"[893,229]"
+23589,"[894,232]"
+23625,"[905,245]"
+23646,"[912,248]"
+23682,"[930,248]"
+23704,"[932,248]"
+23742,"[931,247]"
+23760,"[930,247]"
+23793,"[928,248]"
+23814,"[927,249]"
+23854,"[926,251]"
+23876,"[926,252]"
+23908,"[926,252]"
+23927,"[926,252]"
+23967,"[926,254]"
+23989,"[926,255]"
+24027,"[928,258]"
+24049,"[930,259]"
+24081,"[932,258]"
+24102,"[933,252]"
+24141,"[929,240]"
+24163,"[929,239]"
+24213,"[929,239]"
+24235,"[930,239]"
+24269,"[940,247]"
+24290,"[951,258]"
+24327,"[958,264]"
+24345,"[958,264]"
+24385,"[958,265]"
+24404,"[959,266]"
+24440,"[959,268]"
+24463,"[959,272]"
+24504,"[962,283]"
+24525,"[963,285]"
+24559,"[961,285]"
+24579,"[961,285]"
+24616,"[955,282]"
+24638,"[953,282]"
+24673,"[948,279]"
+24691,"[944,276]"
+24724,"[939,272]"
+24744,"[938,272]"
+24781,"[937,272]"
+24802,"[937,272]"
+24837,"[940,272]"
+24858,"[943,270]"
+24898,"[944,260]"
+24920,"[941,257]"
+24956,"[933,256]"
+24978,"[931,257]"
+25011,"[929,262]"
+25030,"[929,263]"
+25072,"[931,266]"
+25093,"[931,266]"
+25129,"[924,267]"
+25150,"[909,266]"
+25188,"[879,261]"
+25210,"[847,260]"
+25245,"[797,265]"
+25263,"[759,274]"
+25298,"[682,286]"
+25318,"[629,288]"
+25353,"[472,278]"
+25373,"[412,270]"
+25407,"[273,250]"
+25427,"[239,243]"
+25461,"[187,227]"
+25481,"[158,210]"
+25518,"[147,198]"
+25538,"[147,198]"
+25568,"[147,198]"
+25589,"[149,198]"
+25629,"[174,201]"
+25649,"[194,206]"
+25686,"[235,222]"
+25704,"[252,229]"
+25738,"[281,236]"
+25758,"[291,237]"
+25794,"[296,238]"
+25824,"[296,238]"
+25860,"[296,242]"
+25880,"[296,243]"
+25934,"[296,243]"
+25972,"[297,243]"
+25991,"[297,243]"
+26026,"[297,244]"
+26046,"[298,247]"
+26078,"[301,249]"
+26098,"[302,249]"
+26137,"[303,246]"
+26158,"[303,244]"
+26195,"[302,243]"
+26213,"[302,243]"
+26251,"[300,250]"
+26271,"[300,251]"
+26302,"[300,251]"
+26321,"[303,248]"
+26358,"[305,243]"
+26376,"[303,240]"
+26409,"[302,239]"
+26431,"[301,239]"
+26470,"[295,240]"
+26492,"[293,241]"
+26529,"[291,242]"
+26550,"[291,242]"
+26588,"[287,238]"
+26609,"[284,237]"
+26642,"[279,235]"
+26663,"[277,237]"
+26702,"[272,246]"
+26723,"[267,254]"
+26761,"[262,268]"
+26782,"[259,272]"
+26821,"[258,273]"
+26840,"[257,272]"
+26877,"[246,268]"
+26902,"[242,268]"
+26937,"[242,268]"
+26955,"[245,266]"
+26993,"[267,263]"
+27013,"[274,262]"
+27046,"[278,258]"
+27066,"[280,251]"
+27102,"[279,246]"
+27149,"[279,247]"
+27171,"[280,250]"
+27205,"[289,252]"
+27224,"[294,249]"
+27259,"[298,239]"
+27280,"[298,223]"
+27315,"[296,208]"
+27334,"[297,202]"
+27370,"[303,192]"
+27391,"[304,190]"
+27428,"[304,189]"
+27459,"[304,190]"
+27494,"[303,197]"
+27513,"[303,197]"
+27550,"[302,198]"
+27567,"[301,198]"
+27603,"[294,200]"
+27624,"[284,207]"
+27662,"[272,224]"
+27684,"[268,233]"
+27719,"[270,241]"
+27740,"[273,244]"
+27774,"[275,248]"
+27795,"[274,250]"
+27831,"[273,251]"
+27853,"[273,251]"
+27888,"[284,255]"
+27907,"[292,255]"
+27945,"[304,256]"
+27966,"[305,257]"
+28003,"[308,265]"
+28022,"[311,272]"
+28056,"[327,294]"
+28077,"[337,304]"
+28117,"[374,334]"
+28138,"[400,351]"
+28173,"[432,372]"
+28193,"[456,389]"
+28224,"[480,408]"
+28241,"[488,416]"
+28276,"[505,439]"
+28295,"[514,455]"
+28329,"[519,469]"
+28349,"[521,475]"
+28385,"[528,491]"
+28405,"[529,495]"
+28438,"[530,497]"
+28455,"[533,501]"
+28492,"[548,516]"
+28510,"[554,522]"
+28543,"[566,534]"
+28563,"[577,545]"
+28599,"[604,575]"
+28619,"[610,581]"
+28654,"[612,585]"
+28674,"[613,588]"
+28707,"[615,593]"
+28727,"[615,594]"
+28774,"[613,589]"
+28795,"[608,584]"
+28828,"[602,578]"
+28845,"[602,578]"
+28880,"[599,578]"
+28900,"[598,579]"
+28931,"[595,579]"
+28951,"[593,579]"
+28982,"[593,580]"
+29040,"[592,579]"
+29059,"[587,577]"
+29094,"[575,577]"
+29115,"[567,578]"
+29147,"[558,579]"
+29167,"[555,579]"
+29207,"[555,579]"
+29251,"[555,578]"
+29271,"[555,577]"
+29309,"[554,575]"
+29330,"[550,573]"
+29369,"[549,573]"
+29420,"[552,574]"
+29446,"[571,577]"
+29494,"[615,569]"
+29517,"[627,561]"
+29554,"[635,547]"
+29578,"[635,545]"
+29634,"[635,545]"
+29672,"[629,540]"
+29692,"[623,535]"
+29728,"[608,523]"
+29746,"[606,522]"
+29778,"[600,518]"
+29799,"[597,514]"
+29840,"[597,514]"
+29859,"[598,516]"
+29896,"[600,524]"
+29917,"[600,527]"
+29953,"[600,529]"
+29974,"[600,529]"
+30011,"[605,517]"
+30033,"[606,509]"
+30068,"[606,508]"
+30089,"[606,509]"
+30121,"[605,517]"
+30142,"[604,522]"
+30181,"[603,527]"
+30200,"[604,529]"
+30244,"[606,530]"
+30269,"[608,529]"
+30310,"[609,528]"
+30331,"[609,528]"
+30368,"[605,533]"
+30389,"[602,535]"
+30428,"[591,536]"
+30447,"[580,532]"
+30484,"[558,515]"
+30505,"[540,498]"
+30540,"[513,471]"
+30559,"[491,451]"
+30591,"[460,424]"
+30609,"[442,408]"
+30647,"[402,372]"
+30667,"[387,359]"
+30702,"[348,332]"
+30722,"[333,321]"
+30758,"[306,303]"
+30779,"[289,292]"
+30812,"[273,282]"
+30829,"[267,278]"
+30864,"[254,275]"
+30888,"[243,274]"
+30933,"[224,272]"
+30953,"[217,270]"
+30984,"[214,269]"
+31002,"[214,269]"
+31047,"[215,269]"
+31078,"[216,267]"
+31096,"[216,267]"
+31143,"[215,267]"
+31162,"[214,268]"
+31196,"[213,271]"
+31213,"[213,273]"
+31250,"[216,274]"
+31272,"[217,272]"
+31311,"[219,261]"
+31332,"[218,257]"
+31366,"[217,256]"
+31398,"[218,257]"
+31436,"[220,263]"
+31457,"[221,264]"
+31492,"[224,262]"
+31513,"[229,258]"
+31552,"[230,247]"
+31574,"[229,242]"
+31612,"[228,237]"
+31633,"[227,232]"
+31670,"[230,229]"
+31689,"[237,224]"
+31729,"[254,212]"
+31756,"[267,207]"
+31791,"[289,208]"
+31812,"[292,209]"
+31845,"[291,211]"
+31865,"[286,221]"
+31902,"[280,236]"
+31924,"[279,244]"
+31962,"[280,248]"
+31984,"[289,248]"
+32021,"[305,242]"
+32043,"[312,237]"
+32083,"[313,236]"
+32139,"[313,238]"
+32158,"[312,238]"
+32192,"[312,239]"
+32224,"[312,239]"
+32264,"[316,235]"
+32285,"[317,232]"
+32323,"[317,224]"
+32344,"[317,223]"
+32392,"[317,225]"
+32430,"[318,235]"
+32451,"[318,238]"
+32586,"[317,239]"
+32609,"[313,244]"
+32644,"[301,254]"
+32665,"[295,257]"
+32707,"[290,257]"
+32728,"[288,256]"
+32764,"[285,255]"
+32784,"[284,255]"
+32823,"[287,261]"
+32845,"[290,264]"
+32883,"[314,264]"
+32904,"[338,257]"
+32940,"[372,245]"
+32961,"[398,238]"
+32999,"[454,238]"
+33020,"[478,240]"
+33054,"[524,239]"
+33074,"[558,236]"
+33112,"[620,231]"
+33132,"[645,229]"
+33168,"[707,224]"
+33189,"[733,225]"
+33223,"[784,222]"
+33243,"[800,221]"
+33279,"[840,223]"
+33296,"[851,225]"
+33332,"[867,227]"
+33353,"[873,226]"
+33394,"[891,226]"
+33416,"[898,227]"
+33452,"[899,227]"
+33480,"[899,228]"
+33512,"[900,233]"
+33530,"[901,236]"
+33569,"[901,237]"
+33629,"[900,237]"
+33647,"[898,237]"
+33680,"[896,238]"
+33697,"[896,239]"
+33737,"[894,240]"
+33758,"[893,240]"
+33798,"[890,243]"
+33819,"[887,247]"
+33856,"[882,254]"
+33877,"[882,256]"
+33911,"[882,257]"
+33929,"[882,257]"
+33969,"[883,257]"
+33990,"[883,258]"
+34027,"[884,261]"
+34049,"[884,263]"
+34089,"[884,265]"
+34111,"[886,265]"
+34147,"[893,263]"
+34169,"[902,258]"
+34207,"[923,233]"
+34229,"[929,223]"
+34265,"[944,203]"
+34290,"[951,189]"
+34325,"[955,170]"
+34346,"[955,159]"
+34382,"[955,155]"
+34413,"[954,155]"
+34449,"[952,165]"
+34471,"[951,175]"
+34506,"[949,189]"
+34527,"[950,195]"
+34564,"[951,197]"
+34586,"[952,198]"
+34627,"[954,199]"
+34649,"[955,202]"
+34685,"[955,214]"
+34704,"[955,221]"
+34737,"[956,223]"
+34758,"[958,223]"
+34798,"[959,223]"
+34817,"[959,222]"
+34854,"[957,222]"
+34874,"[955,223]"
+34914,"[953,228]"
+34938,"[954,231]"
+34973,"[959,238]"
+34994,"[964,244]"
+35030,"[968,249]"
+35049,"[967,250]"
+35091,"[965,252]"
+35113,"[962,258]"
+35149,"[958,267]"
+35171,"[956,270]"
+35209,"[956,271]"
+35265,"[956,271]"
+35299,"[949,266]"
+35319,"[943,264]"
+35353,"[940,263]"
+35373,"[937,263]"
+35414,"[932,263]"
+35438,"[928,263]"
+35469,"[921,260]"
+35490,"[914,248]"
+35530,"[905,223]"
+35552,"[904,207]"
+35585,"[908,198]"
+35604,"[910,196]"
+35638,"[915,192]"
+35658,"[918,191]"
+35696,"[920,190]"
+35750,"[920,193]"
+35768,"[921,195]"
+35802,"[925,201]"
+35821,"[928,202]"
+35864,"[941,208]"
+35886,"[945,211]"
+35924,"[946,219]"
+35945,"[944,228]"
+35983,"[942,244]"
+36005,"[942,248]"
+36044,"[942,250]"
+36062,"[942,250]"
+36100,"[939,248]"
+36122,"[926,243]"
+36163,"[914,243]"
+36185,"[907,243]"
+36223,"[893,243]"
+36243,"[891,243]"
+36282,"[890,243]"
+36304,"[889,244]"
+36341,"[887,246]"
+36360,"[886,248]"
+36403,"[885,253]"
+36425,"[882,259]"
+36459,"[878,268]"
+36481,"[874,272]"
+36515,"[854,275]"
+36535,"[818,275]"
+36569,"[756,275]"
+36589,"[728,279]"
+36625,"[660,296]"
+36643,"[635,302]"
+36673,"[589,309]"
+36690,"[573,311]"
+36731,"[555,313]"
+36757,"[554,313]"
+36843,"[555,313]"
+36863,"[559,316]"
+36897,"[566,322]"
+36917,"[573,325]"
+36957,"[597,329]"
+36981,"[615,326]"
+37030,"[633,316]"
+37054,"[633,314]"
+37095,"[634,314]"
+37117,"[634,315]"
+37153,"[633,316]"
+37174,"[633,317]"
+37212,"[635,319]"
+37233,"[637,319]"
+37274,"[639,318]"
+37295,"[639,315]"
+37334,"[633,311]"
+37355,"[628,310]"
+37389,"[623,311]"
+37407,"[621,313]"
+37443,"[620,315]"
+37461,"[620,316]"
+37497,"[621,317]"
+37515,"[623,318]"
+37555,"[626,317]"
+37576,"[626,317]"
+37610,"[627,320]"
+37630,"[628,324]"
+37667,"[629,325]"
+37687,"[630,326]"
+37722,"[633,326]"
+37742,"[634,325]"
+37779,"[634,324]"
+37801,"[634,323]"
diff --git a/src/argaze/utils/demo/gaze_positions.csv b/src/argaze/utils/demo/gaze_positions_xy_splitted.csv
index 558c995..558c995 100644
--- a/src/argaze/utils/demo/gaze_positions.csv
+++ b/src/argaze/utils/demo/gaze_positions_xy_splitted.csv