Log gaze analysis ================= [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) analysis can be logged by registering observers to their **look** method. ## Export gaze analysis to CSV file [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) have an observers attribute to enable pipeline execution logging. Here is an extract from the JSON ArFrame configuration file where logging is enabled for the [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and for one [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) by pointing to dedicated Python files: ```json { "name": "My FullHD screen", "size": [1920, 1080], "observers": "my_frame_logger.py", ... "layers": { "MyLayer": { "observers": "my_layer_logger.py", ... } } } ``` !!! note [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and its [ArLayers](../../argaze.md/#argaze.ArFeatures.ArLayer) automatically notify **look** method observers after each call. Here is *my_frame_logger.py* file: ```python from argaze import DataFeatures from argaze.utils import UtilsFeatures class ScanPathAnalysisLogger(DataFeatures.PipelineStepObserver, UtilsFeatures.FileWriter): def on_look(self, timestamp, ar_frame, exception): """Log scan path metrics""" if ar_frame.analysis_available: log = ( timestamp, ar_frame.scan_path_analyzers['argaze.GazeAnalysis.Basic'].path_duration, ar_frame.scan_path_analyzers['argaze.GazeAnalysis.Basic'].steps_number ) # Write to file self.write(log) # Export logger as observer __observers__ = { "Scan path analysis logger": ScanPathAnalysisLogger(path="./scan_path_metrics.csv", header=("Timestamp (ms)", "Duration (ms)", "Steps number")) } ``` Assuming that [ArGaze.GazeAnalysis.Basic](../../argaze.md/#argaze.GazeAnalysis.Basic) scan path analysis module is enabled for 'My FullHD screen' ArFrame, a ***scan_path_metrics.csv*** file would be created: |Timestamp (ms)|Duration (ms)|Steps number| |:-------------|:------------|:-----------| |3460 |1750 |2 | |4291 |2623 |3 | |4769 |3107 |4 | |6077 |4411 |5 | |6433 |4760 |6 | |7719 |6050 |7 | |... |... |... | Here is *my_layer_logger.py* file: ```python from argaze import DataFeatures from argaze.utils import UtilsFeatures class AOIScanPathAnalysisLogger(DataFeatures.PipelineStepObserver, UtilsFeatures.FileWriter): def on_look(self, timestamp, ar_layer, exception): """Log aoi scan path metrics.""" if ar_layer.analysis_available: log = ( timestamp, ar_layer.aoi_scan_path_analyzers['argaze.GazeAnalysis.NGram'].ngrams_count ) # Write to file self.write(log) # Export logger as observer __observers__ = { "AOI Scan path analysis logger": AOIScanPathAnalysisLogger(path="./aoi_scan_path_metrics.csv", header=("Timestamp (ms)", "NGram counts")) } ``` Assuming that [ArGaze.GazeAnalysis.NGram](../../argaze.md/#argaze.GazeAnalysis.NGram) AOI scan path analysis module is enabled for 'MyLayer' ArLayer, a ***aoi_scan_path_metrics.csv*** file would be created: |Timestamp (ms)|NGram counts| |:-------------|:-----------| |5687 |"{3: {}, 4: {}, 5: {}}"| |6208 |"{3: {('LeftPanel', 'GeoSector', 'CircularWidget'): 1}, 4: {}, 5: {}}"| |... |... | !!! note "" Learn to [script the pipeline](./advanced_topics/scripting.md) to know more about [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and [ArLayers](../../argaze.md/#argaze.ArFeatures.ArLayer) attributes. ### Export gaze analysis to video file As explained in [pipeline steps visualisation chapter](visualisation.md), it is possible to get [ArFrame.image](../../argaze.md/#argaze.ArFeatures.ArFrame.image) once timestamped gaze positions have been processed by [ArFrame.look](../../argaze.md/#argaze.ArFeatures.ArFrame.look) method. ```python from argaze import DataFeatures from argaze.utils import UtilsFeatures class VideoRecorder(DataFeatures.PipelineStepObserver, UtilsFeatures.VideoWriter): def on_look(self, timestamp, ar_frame, exception): """Record frame image into video file.""" self.write(ar_frame.image()) # Export recorder as observer __observers__ = { "Video recorder": VideoRecorder(path="./video.mp4", width=1920, height=1080, fps=15) } ``` Assuming that [ArFrame.image_parameters](../../argaze.md/#argaze.ArFeatures.ArFrame.image_parameters) are provided, ***video.mp4*** file would be created.