aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/argaze.test/GazeAnalysis/ExploitExploreRatio.py40
-rw-r--r--src/argaze/GazeAnalysis/ExploitExploreRatio.py63
-rw-r--r--src/argaze/GazeAnalysis/__init__.py2
3 files changed, 104 insertions, 1 deletions
diff --git a/src/argaze.test/GazeAnalysis/ExploitExploreRatio.py b/src/argaze.test/GazeAnalysis/ExploitExploreRatio.py
new file mode 100644
index 0000000..febfec7
--- /dev/null
+++ b/src/argaze.test/GazeAnalysis/ExploitExploreRatio.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+""" """
+
+__author__ = "Théo de la Hogue"
+__credits__ = []
+__copyright__ = "Copyright 2023, Ecole Nationale de l'Aviation Civile (ENAC)"
+__license__ = "BSD"
+
+import unittest
+
+from argaze import GazeFeatures
+from argaze.GazeAnalysis import ExploitExploreRatio
+from argaze.utils import MiscFeatures
+
+GazeFeaturesTest = MiscFeatures.importFromTestPackage('GazeFeatures')
+
+class TestScanPathAnalyzer(unittest.TestCase):
+ """Test ScanPathAnalyzer class."""
+
+ def test_analyze(self):
+ """Test analyze method."""
+
+ xxr_analyzer = ExploitExploreRatio.ScanPathAnalyzer()
+
+ scan_path = GazeFeaturesTest.build_scan_path(10)
+
+ # Check scan path
+ self.assertEqual(len(scan_path), 10)
+
+ xxr = xxr_analyzer.analyze(scan_path)
+
+ print(xxr)
+
+ # Check exploit explore ratio
+ self.assertGreaterEqual(xxr, 0)
+
+if __name__ == '__main__':
+
+ unittest.main() \ No newline at end of file
diff --git a/src/argaze/GazeAnalysis/ExploitExploreRatio.py b/src/argaze/GazeAnalysis/ExploitExploreRatio.py
new file mode 100644
index 0000000..eba8ec2
--- /dev/null
+++ b/src/argaze/GazeAnalysis/ExploitExploreRatio.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+
+"""Implementation of exploit vs explore ratio algorithm as described in:
+
+ **Goldberg J. H., Kotval X. P. (1999).**
+ *Computer interface evaluation using eye movements: methods and constructs.*
+ International Journal of Industrial Ergonomics (631–645).
+ [https://doi.org/10.1016/S0169-8141(98)00068-7](https://doi.org/10.1016/S0169-8141\\(98\\)00068-7)
+
+ **Dehais F., Peysakhovich V., Scannella S., Fongue J., Gateau T. (2015).**
+ *Automation surprise in aviation: Real-time solutions.*
+ Proceedings of the 33rd annual ACM conference on Human Factors in Computing Systems (2525–2534).
+ [https://doi.org/10.1145/2702123.2702521](https://doi.org/10.1145/2702123.2702521)
+"""
+
+__author__ = "Théo de la Hogue"
+__credits__ = []
+__copyright__ = "Copyright 2023, Ecole Nationale de l'Aviation Civile (ENAC)"
+__license__ = "BSD"
+
+from dataclasses import dataclass
+
+from argaze import GazeFeatures
+
+import numpy
+
+@dataclass
+class ScanPathAnalyzer(GazeFeatures.ScanPathAnalyzer):
+
+ def __post_init__(self):
+
+ pass
+
+ def analyze(self, scan_path: GazeFeatures.ScanPathType, long_fixation_duration_threshold: float = 0.) -> float:
+ """Analyze scan path."""
+
+ assert(len(scan_path) > 1)
+
+ short_fixations_durations = []
+ long_fixations_durations = []
+ saccades_durations = []
+
+ for scan_step in scan_path:
+
+ if scan_step.first_fixation.duration > long_fixation_duration_threshold:
+
+ long_fixations_durations.append(scan_step.first_fixation.duration)
+
+ else:
+
+ short_fixations_durations.append(scan_step.first_fixation.duration)
+
+ saccades_durations.append(scan_step.last_saccade.duration)
+
+ short_fixations_duration = numpy.array(short_fixations_durations).sum()
+ long_fixations_duration = numpy.array(long_fixations_durations).sum()
+ saccades_duration = numpy.array(saccades_durations).sum()
+
+ print(short_fixations_duration, long_fixations_duration, saccades_duration)
+
+ assert(saccades_duration + short_fixations_duration > 0)
+
+ return long_fixations_duration / (saccades_duration + short_fixations_duration)
diff --git a/src/argaze/GazeAnalysis/__init__.py b/src/argaze/GazeAnalysis/__init__.py
index 21753c1..5f8b102 100644
--- a/src/argaze/GazeAnalysis/__init__.py
+++ b/src/argaze/GazeAnalysis/__init__.py
@@ -2,4 +2,4 @@
.. include:: README.md
"""
__docformat__ = "restructuredtext"
-__all__ = ['DispersionThresholdIdentification', 'VelocityThresholdIdentification', 'TransitionMatrix', 'KCoefficient', 'LempelZivComplexity', 'NGram', 'Entropy', 'NearestNeighborIndex'] \ No newline at end of file
+__all__ = ['DispersionThresholdIdentification', 'VelocityThresholdIdentification', 'TransitionMatrix', 'KCoefficient', 'LempelZivComplexity', 'NGram', 'Entropy', 'NearestNeighborIndex', 'ExploitExploreRatio'] \ No newline at end of file