aboutsummaryrefslogtreecommitdiff
path: root/docs/user_guide/gaze_analysis/gaze_movement.md
diff options
context:
space:
mode:
authorThéo de la Hogue2023-06-07 14:34:14 +0200
committerThéo de la Hogue2023-06-07 14:34:14 +0200
commitc4552e04e1271a9210a934233beae5be1943d034 (patch)
treea44041e544bc700976237bfea9058ec06f9a2904 /docs/user_guide/gaze_analysis/gaze_movement.md
parentbd9cd27c9d44c072164f564ffffeb22e37106b89 (diff)
downloadargaze-c4552e04e1271a9210a934233beae5be1943d034.zip
argaze-c4552e04e1271a9210a934233beae5be1943d034.tar.gz
argaze-c4552e04e1271a9210a934233beae5be1943d034.tar.bz2
argaze-c4552e04e1271a9210a934233beae5be1943d034.tar.xz
Writing User guide and use cases section.
Diffstat (limited to 'docs/user_guide/gaze_analysis/gaze_movement.md')
-rw-r--r--docs/user_guide/gaze_analysis/gaze_movement.md141
1 files changed, 141 insertions, 0 deletions
diff --git a/docs/user_guide/gaze_analysis/gaze_movement.md b/docs/user_guide/gaze_analysis/gaze_movement.md
new file mode 100644
index 0000000..6c7ab76
--- /dev/null
+++ b/docs/user_guide/gaze_analysis/gaze_movement.md
@@ -0,0 +1,141 @@
+Gaze movement
+=============
+
+## Definition
+
+!!! note
+
+ *"The act of classifying eye movements into distinct events is, on a general level, driven by a desire to isolate different intervals of the data stream strongly correlated with certain oculomotor or cognitive properties."*
+
+ Citation from ["One algorithm to rule them all? An evaluation and discussion of ten eye movement event-detection algorithms"](https://link.springer.com/article/10.3758/s13428-016-0738-9) article.
+
+[GazeFeatures](/argaze/#argaze.GazeFeatures) defines abstract [GazeMovement](/argaze/#argaze.GazeFeatures.GazeMovement) class, then abstract [Fixation](/argaze/#argaze.GazeFeatures.Fixation) and [Saccade](/argaze/#argaze.GazeFeatures.Saccade) classes which inherit from [GazeMovement](/argaze/#argaze.GazeFeatures.GazeMovement).
+
+The **positions** [GazeMovement](/argaze/#argaze.GazeFeatures.GazeMovement) attribute contain all [GazePositions](/argaze/#argaze.GazeFeatures.GazePosition) belonging to itself.
+
+![Fixation and Saccade](../../img/fixation_and_saccade.png)
+
+## Identification
+
+[GazeFeatures](/argaze/#argaze.GazeFeatures) defines abstract [GazeMovementIdentifier](/argaze/#argaze.GazeFeatures.GazeMovementIdentifier) classe to let add various identification algorithms.
+
+Some gaze movement identification algorithms are available thanks to [GazeAnalysis](/argaze/#argaze.GazeAnalysis) submodule:
+
+* [Dispersion threshold identification (I-DT)](/argaze/#argaze.GazeAnalysis.DispersionThresholdIdentification)
+* [Velocity threshold identification (I-VT)](/argaze/#argaze.GazeAnalysis.VelocityThresholdIdentification)
+
+### Identify method
+
+[GazeMovementIdentifier](/argaze/#argaze.GazeFeatures.GazeMovementIdentifier) **identify** method allows to fed its identification algorithm with successive gaze positions to output Fixation, Saccade or any kind of GazeMovement instances.
+
+Here is a sample of code based on I-DT algorithm to illustrate how to use it:
+
+``` python
+from argaze import GazeFeatures
+from argaze.GazeAnalysis import DispersionThresholdIdentification
+
+# Create a gaze movement identifier based on dispersion algorithm with 50px max deviation 200 ms max duration thresholds
+gaze_movement_identifier = DispersionThresholdIdentification.GazeMovementIdentifier(50, 200)
+
+# Assuming that timestamped gaze positions are provided through live stream or later data reading
+...:
+
+ gaze_movement = gaze_movement_identifier.identify(timestamp, gaze_position)
+
+ # Fixation identified
+ if GazeFeatures.is_fixation(gaze_movement):
+
+ # Access to first gaze position of identified fixation
+ start_ts, start_position = gaze_movement.positions.first
+
+ # Access to fixation duration
+ print('duration: {gaze_movement.duration}')
+
+ # Iterate over all gaze positions of identified fixation
+ for ts, position in gaze_movement.positions.items():
+
+ # Do something with each fixation position
+ ...
+
+ # Saccade identified
+ elif GazeFeatures.is_saccade(gaze_movement):
+
+ # Access to first gaze position of identified saccade
+ start_ts, start_position = gaze_movement.positions.first
+
+ # Access to saccade amplitude
+ print('amplitude: {gaze_movement.amplitude}')
+
+ # Iterate over all gaze positions of identified saccade
+ for ts, position in gaze_movement.positions.items():
+
+ # Do something with each saccade position
+ ...
+
+ # No gaze movement identified
+ else:
+
+ continue
+
+```
+
+### Browse method
+
+[GazeMovementIdentifier](/argaze/#argaze.GazeFeatures.GazeMovementIdentifier) **browse** method allows to pass a TimeStampedGazePositions buffer to apply identification algorithm on all gaze positions inside.
+
+Identified gaze movements are returned through:
+
+* [TimeStampedGazeMovements](/argaze/#argaze.GazeFeatures.TimeStampedGazeMovements) instance where all fixations are stored by starting gaze position timestamp.
+* [TimeStampedGazeMovements](/argaze/#argaze.GazeFeatures.TimeStampedGazeMovements) instance where all saccades are stored by starting gaze position timestamp.
+* [TimeStampedGazeStatus](/argaze/#argaze.GazeFeatures.TimeStampedGazeStatus) instance where all gaze positions are linked to a fixation or saccade index.
+
+``` python
+# Assuming that timestamped gaze positions are provided through data reading
+
+ts_fixations, ts_saccades, ts_status = gaze_movement_identifier.browse(ts_gaze_positions)
+
+```
+
+* ts_fixations would look like:
+
+|timestamp|positions |duration|dispersion|focus |
+|:--------|:-------------------------------------------------------------|:-------|:---------|:--------|
+|60034 |{"60034":[846,620], "60044":[837,641], "60054":[835,649], ...}|450 |40 |(840,660)|
+|60504 |{"60504":[838,667], "60514":[838,667], "60524":[837,669], ...}|100 |38 |(834,651)|
+|... |... |... |.. |... |
+
+* ts_saccades would look like:
+
+|timestamp|positions |duration|
+|:--------|:---------------------------------------|:-------|
+|60484 |{"60484":[836, 669], "60494":[837, 669]}|10 |
+|60594 |{"60594":[833, 613], "60614":[927, 601]}|20 |
+|... |... |... |
+
+* ts_status would look like:
+
+|timestamp|position |type |index|
+|:--------|:---------|:-------|:----|
+|60034 |(846, 620)|Fixation|1 |
+|60044 |(837, 641)|Fixation|1 |
+|... |... |... |. |
+|60464 |(836, 668)|Fixation|1 |
+|60474 |(836, 668)|Fixation|1 |
+|60484 |(836, 669)|Saccade |1 |
+|60494 |(837, 669)|Saccade |1 |
+|60504 |(838, 667)|Fixation|2 |
+|60514 |(838, 667)|Fixation|2 |
+|... |... |... |. |
+|60574 |(825, 629)|Fixation|2 |
+|60584 |(829, 615)|Fixation|2 |
+|60594 |(833, 613)|Saccade |2 |
+|60614 |(927, 601)|Saccade |2 |
+|60624 |(933, 599)|Fixation|3 |
+|60634 |(934, 603)|Fixation|3 |
+|... |... |... |. |
+
+
+!!! note
+ [TimeStampedGazeMovements](/argaze/#argaze.GazeFeatures.TimeStampedGazeMovements), [TimeStampedGazeMovements](/argaze/#argaze.GazeFeatures.TimeStampedGazeMovements) and [TimeStampedGazeStatus](/argaze/#argaze.GazeFeatures.TimeStampedGazeStatus) classes inherit from [TimeStampedBuffer](/argaze/#argaze.DataStructures.TimeStampedBuffer) class.
+
+ Read [timestamped data] page to understand all features it provides. \ No newline at end of file