Configure and execute ArFrame ============================= The [ArFrame](../../../argaze/#argaze.ArFeatures.ArFrame) class defines a rectangular area where timestamped gaze positions are projected in and inside which they need to be analyzed. ![Empty frame area](../../img/ar_frame_empty.png) ## Load JSON configuration file The [ArFrame](../../../argaze/#argaze.ArFeatures.ArFrame) internal pipeline is entirely customizable from a JSON configuration file thanks to [ArFrame.from_json](../../../argaze/#argaze.ArFeatures.ArFrame.from_json) class method. Here is a simple JSON ArFrame configuration file example: ```json { "name": "My FullHD screen", "size": [1920, 1080], "gaze_movement_identifier": { "DispersionThresholdIdentification": { "deviation_max_threshold": 50, "duration_min_threshold": 200 } }, "scan_path": { "duration_max": 30000 }, "scan_path_analyzers": { "Basic": {}, "ExploitExploreRatio": { "short_fixation_duration_threshold": 0 } }, "heatmap": { "size": [320, 180], "sigma": 0.025, "buffer": 0 } } ``` Then, here is how to load the JSON file: ```python from argaze import ArFeatures # Load ArFrame ar_frame = ArFeatures.ArFrame.from_json('./configuration.json') # Print ArFrame attributes print("name:", ar_frame.name) print("size:", ar_frame.size) print("gaze movement identifier type:", type(ar_frame.gaze_movement_identifier)) print("scan path:", ar_frame.scan_path) for module, analyzer in ar_frame.scan_path_analyzers.items(): print('scan path analyzer module:', module) print("heatmap:", ar_frame.heatmap) ``` Finally, here is what the program writes in console: ```txt name: My FullHD screen size: [1920, 1080] gaze movement identifier type: scan path: [] scan path analyzer module: argaze.GazeAnalysis.Basic scan path analyzer module: argaze.GazeAnalysis.ExploitExploreRatio heatmap: Heatmap(size=[320, 180], buffer=0, sigma=0.025) ``` Now, let's understand the meaning of each JSON entry. ### Name The name of the [ArFrame](../../../argaze/#argaze.ArFeatures.ArFrame). Basically useful for visualisation purpose. ### Size The size of the [ArFrame](../../../argaze/#argaze.ArFeatures.ArFrame) defines the dimension of the rectangular area where gaze positions are projected. Be aware that gaze positions have to be in the same range of value. ### Gaze Movement Identifier The first [ArFrame](../../../argaze/#argaze.ArFeatures.ArFrame) pipeline step is to identify fixations or saccades from consecutive timestamped gaze positions. ![Gaze Movement Identifier](../../img/ar_frame_gaze_movement_identifier.png) The identification method can be selected by instantiating a particular [GazeMovementIdentifier](../../../argaze/#argaze.GazeFeatures.GazeMovementIdentifier) from the [argaze.GazeAnalysis](../../../argaze/#argaze.GazeAnalysis) submodule or [another python package](../advanced_topics/plugin_loading). In the example file, the choosen identification method is the [Dispersion Threshold Identification (I-DT)](../../../argaze/#argaze.GazeAnalysis.DispersionThresholdIdentification) which has two specific *deviation_max_threshold* and *duration_min_threshold* attributes. !!! note In ArGaze, [Fixation](../../../argaze/#argaze.GazeFeatures.Fixation) and [Saccade](../../../argaze/#argaze.GazeFeatures.Saccade) are considered as particular [GazeMovements](../../../argaze/#argaze.GazeFeatures.GazeMovement). !!! warning JSON *gaze_movement_identifier* entry is mandatory. Otherwise, the ScanPath and ScanPathAnalyzers steps are disabled. ### Scan Path The second [ArFrame](../../../argaze/#argaze.ArFeatures.ArFrame) pipeline step aims to build a [ScanPath](../../../argaze/#argaze.GazeFeatures.ScanPath) defined as a list of [ScanSteps](../../../argaze/#argaze.GazeFeatures.ScanStep) made by a fixation and a consecutive saccade. ![Scan Path](../../img/ar_frame_scan_path.png) Once fixations and saccades are identified, they are automatically appended to the ScanPath if required. The [ScanPath.duration_max](../../../argaze/#argaze.GazeFeatures.ScanPath.duration_max) attribute is the duration from which older scan steps are removed each time new scan steps are added. ### Scan Path Analyzers Finally, the last [ArFrame](../../../argaze/#argaze.ArFeatures.ArFrame) pipeline step consists in passing the previously built [ScanPath](../../../argaze/#argaze.GazeFeatures.ScanPath) to each loaded [ScanPathAnalyzer](../../../argaze/#argaze.GazeFeatures.ScanPathAnalyzer). Each analysis algorithm can be selected by instantiating a particular [ScanPathAnalyzer](../../../argaze/#argaze.GazeFeatures.ScanPathAnalyzer) from the [argaze.GazeAnalysis](../../../argaze/#argaze.GazeAnalysis) submodule or [another python package](../advanced_topics/plugin_loading). !!! note JSON *scan_path* entry is not mandatory. If scan_path_analyzers entry is not empty, the ScanPath step is automatically enabled. ### Heatmap This is an optional [ArFrame](../../../argaze/#argaze.ArFeatures.ArFrame) pipeline step. It is executed at each new gaze position to update Heatmap image. ![Heatmap](../../img/ar_frame_heatmap.png) The Heatmap object have tree attributes to set its size, the sigma point spreading and optional buffer size (0 means no buffering). ## Pipeline execution Timestamped gaze positions have to be passed one by one to [ArFrame.look](../../../argaze/#argaze.ArFeatures.ArFrame.look) method to execute the whole intanciated pipeline. ```python # Assuming that timestamped gaze positions are available ... # Look ArFrame at a timestamped gaze position movement, scan_path_analysis, _, execution_times, exception = ar_frame.look(timestamp, gaze_position) # Check if a movement has been identified if movement.valid and movement.finished: # Do something with identified fixation if GazeFeatures.is_fixation(movement): ... # Do something with identified saccade elif GazeFeatures.is_saccade(movement): ... # Do something with scan path analysis for module, analysis in scan_path_analysis.items(): for data, value in analysis.items(): ... # Do something with pipeline execution times ... # Do something with pipeline exception if exception: ... ```