Scan path ========= [GazeFeatures](/argaze/#argaze.GazeFeatures) defines classes to handle successive fixations/saccades and analyse their spatial or temporal properties. ## Fixation based scan path ### Definition The [ScanPath](/argaze/#argaze.GazeFeatures.ScanPath) class is defined as a list of [ScanSteps](/argaze/#argaze.GazeFeatures.ScanStep) which are defined as a fixation and a consecutive saccade. ![Fixation based scan path](../../img/scan_path.png) As fixations and saccades are identified, the scan path is built by calling respectively **append_fixation** and **append_saccade** methods. ### Analysis [GazeFeatures](/argaze/#argaze.GazeFeatures) defines abstract [ScanPathAnalyzer](/argaze/#argaze.GazeFeatures.ScanPathAnalyzer) classe to let add various analysis algorithms. Some scan path analysis are available thanks to [GazeAnalysis](/argaze/#argaze.GazeAnalysis) submodule: * [K-Coefficient](/argaze/#argaze.GazeAnalysis.KCoefficient) * [Nearest Neighbor Index](/argaze/#argaze.GazeAnalysis.NearestNeighborIndex) ### Example Here is a sample of code to illustrate how to built a scan path and analyze it: ``` python from argaze import GazeFeatures from argaze.GazeAnalysis import KCoefficient # Create a empty scan path scan_path = GazeFeatures.ScanPath() # Create a K coefficient analyzer kc_analyzer = KCoefficient.ScanPathAnalyzer() # Assuming a gaze movement is identified at ts time ...: # Fixation identified if GazeFeatures.is_fixation(gaze_movement): # Append fixation to scan path : no step is created scan_path.append_fixation(ts, gaze_movement) # Saccade identified elif GazeFeatures.is_saccade(gaze_movement): # Append saccade to scan path : a new step should be created new_step = scan_path.append_saccade(data_ts, gaze_movement) # Analyse scan path if new_step: K = kc_analyzer.analyze(scan_path) # Do something with K metric ... ``` ## AOI based scan path ### Definition The [AOIScanPath](/argaze/#argaze.GazeFeatures.AOIScanPath) class is defined as a list of [AOIScanSteps](/argaze/#argaze.GazeFeatures.AOIScanStep) which are defined as set of consecutives fixations looking at a same Area Of Interest (AOI) and a consecutive saccade. ![AOI based scan path](../../img/aoi_scan_path.png) As fixations and saccades are identified, the scan path is built by calling respectively **append_fixation** and **append_saccade** methods. ### Analysis [GazeFeatures](/argaze/#argaze.GazeFeatures) defines abstract [AOIScanPathAnalyzer](/argaze/#argaze.GazeFeatures.AOIScanPathAnalyzer) classe to let add various analysis algorithms. Some scan path analysis are available thanks to [GazeAnalysis](/argaze/#argaze.GazeAnalysis) submodule: * [Transition matrix](/argaze/#argaze.GazeAnalysis.TransitionMatrix) * [Entropy](/argaze/#argaze.GazeAnalysis.Entropy) * [Lempel-Ziv complexity](/argaze/#argaze.GazeAnalysis.LempelZivComplexity) * [N-Gram](/argaze/#argaze.GazeAnalysis.NGram) * [K-modified coefficient](/argaze/#argaze.GazeAnalysis.KCoefficient) ### Example Here is a sample of code to illustrate how to built a AOI scan path and analyze it: ``` python from argaze import GazeFeatures from argaze.GazeAnalysis import LempelZivComplexity # Assuming all AOI names are listed ... # Create a empty AOI scan path aoi_scan_path = GazeFeatures.AOIScanPath(aoi_names) # Create a Lempel-Ziv complexity analyzer lzc_analyzer = LempelZivComplexity.AOIScanPathAnalyzer() # Assuming a gaze movement is identified at ts time ...: # Fixation identified if GazeFeatures.is_fixation(gaze_movement): # Assuming fixation is detected as inside an AOI ... # Append fixation to AOI scan path : a new step should be created new_step = aoi_scan_path.append_fixation(ts, gaze_movement, looked_aoi_name) # Analyse AOI scan path if new_step: LZC = kc_analyzer.analyze(aoi_scan_path) # Do something with LZC metric ... # Saccade identified elif GazeFeatures.is_saccade(gaze_movement): # Append saccade to scan path : no step is created aoi_scan_path.append_saccade(data_ts, gaze_movement) ``` ### Advanced The [AOIScanPath](/argaze/#argaze.GazeFeatures.AOIScanPath) class provides some advanced features to analyse it. #### String representation When a new [AOIScanStep](/argaze/#argaze.GazeFeatures.AOIScanStep) is created, the [AOIScanPath](/argaze/#argaze.GazeFeatures.AOIScanPath) internally affects a unique letter index related to its AOI to ease pattern analysis. Then, the [AOIScanPath str](/argaze/#argaze.GazeFeatures.AOIScanPath.__str__) representation returns the concatenation of each [AOIScanStep](/argaze/#argaze.GazeFeatures.AOIScanStep) letter. The [AOIScanPath get_letter_aoi](/argaze/#argaze.GazeFeatures.AOIScanPath.get_letter_aoi) method helps to get back the AOI related to a letter index. ``` python # Assuming the following AOI scan path is built: Foo > Bar > Shu > Foo aoi_scan_path = ... # String representation should be: 'ABCA' print(str(aoi_scan_path)) # Output should be: 'Bar' print(aoi_scan_path.get_letter_aoi('B')) ``` #### Transition matrix When a new [AOIScanStep](/argaze/#argaze.GazeFeatures.AOIScanStep) is created, the [AOIScanPath](/argaze/#argaze.GazeFeatures.AOIScanPath) internally counts the number of transitions from an AOI to another AOI to ease Markov chain analysis. Then, the [AOIScanPath transition_matrix](/argaze/#argaze.GazeFeatures.AOIScanPath.transition_matrix) property returns a *Pandas DataFrame* where indexes are transition departures and columns are transition destinations. Here is an exemple of transition matrix for the following [AOIScanPath](/argaze/#argaze.GazeFeatures.AOIScanPath): Foo > Bar > Shu > Foo > Bar | |Foo|Bar|Shu| |:--|:--|:--|:--| |Foo|0 |2 |0 | |Bar|0 |0 |1 | |Shu|1 |0 |0 | #### Fixations count The [AOIScanPath fixations_count](/argaze/#argaze.GazeFeatures.AOIScanPath.fixations_count) method returns the total number of fixations in the whole scan path and a dictionary to get the fixations count per AOI.