1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
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.
## Enable ArFrame and ArLayer analysis logging
[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, frame):
"""Log scan path metrics"""
if frame.analysis_available:
log = (
timestamp,
frame.scan_path_analyzers['argaze.GazeAnalysis.Basic'].path_duration,
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, layer):
"""Log aoi scan path metrics"""
if layer.analysis_available:
log = (
timestamp,
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: {}}"|
|... |... |
|