scanpath-studio 0.27.2__tar.gz → 0.28.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. {scanpath_studio-0.27.2/scanpath_studio.egg-info → scanpath_studio-0.28.0}/PKG-INFO +3 -2
  2. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/README.md +1 -0
  3. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/pyproject.toml +27 -1
  4. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/__init__.py +1 -1
  5. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/annotations.py +0 -12
  6. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/api.py +28 -5
  7. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/app.py +393 -134
  8. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/authoring.py +34 -6
  9. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/cli.py +42 -1
  10. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/constants.py +32 -44
  11. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/controls.py +625 -120
  12. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/data.py +76 -0
  13. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/export.py +34 -40
  14. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/measures.py +0 -13
  15. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/plots.py +140 -27
  16. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/preprocessing.py +65 -21
  17. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/session_keys.py +20 -0
  18. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/styles.py +119 -13
  19. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/tabs.py +941 -370
  20. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/tour.py +51 -22
  21. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/url_state.py +106 -2
  22. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/utils.py +28 -10
  23. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0/scanpath_studio.egg-info}/PKG-INFO +3 -2
  24. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio.egg-info/SOURCES.txt +3 -0
  25. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio.egg-info/requires.txt +1 -1
  26. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_apptest.py +412 -11
  27. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_apptest_flows.py +119 -18
  28. scanpath_studio-0.28.0/tests/test_authoring.py +73 -0
  29. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_cli.py +24 -0
  30. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_composite_selection.py +1 -1
  31. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_data.py +113 -2
  32. scanpath_studio-0.28.0/tests/test_debug_log.py +127 -0
  33. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_desktop_icon.py +2 -3
  34. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_disclosure.py +4 -2
  35. scanpath_studio-0.28.0/tests/test_experimental_setup.py +64 -0
  36. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_mode_parity.py +88 -2
  37. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_persistence.py +0 -1
  38. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_preprocessing.py +99 -0
  39. scanpath_studio-0.28.0/tests/test_saccade_class_filter.py +241 -0
  40. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_security_fixes.py +2 -2
  41. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_session_key_contract.py +16 -2
  42. scanpath_studio-0.28.0/tests/test_slider_number_callbacks.py +127 -0
  43. scanpath_studio-0.28.0/tests/test_stimulus_panel.py +396 -0
  44. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_tour.py +48 -0
  45. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_trial_sort.py +3 -3
  46. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_viz_palette.py +19 -14
  47. scanpath_studio-0.28.0/tests/test_widget_value_sync.py +294 -0
  48. scanpath_studio-0.27.2/tests/test_authoring.py +0 -26
  49. scanpath_studio-0.27.2/tests/test_experimental_setup.py +0 -22
  50. scanpath_studio-0.27.2/tests/test_stimulus_panel.py +0 -209
  51. scanpath_studio-0.27.2/tests/test_widget_value_sync.py +0 -191
  52. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/LICENSE +0 -0
  53. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/MANIFEST.in +0 -0
  54. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/NOTICE +0 -0
  55. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/__main__.py +0 -0
  56. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/aggregation.py +0 -0
  57. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/alignment.py +0 -0
  58. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/animation_export.py +0 -0
  59. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/datasets.py +0 -0
  60. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/debug_log.py +0 -0
  61. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/experimental_setup.py +0 -0
  62. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/html_embed.py +0 -0
  63. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/illustration.py +0 -0
  64. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/model_scanpaths.py +0 -0
  65. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/onestop_shard.py +0 -0
  66. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/persistence.py +0 -0
  67. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/fixations.csv +0 -0
  68. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/fixations.parquet +0 -0
  69. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/ia.csv +0 -0
  70. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/ia.parquet +0 -0
  71. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_1_Ele__answer_a.png +0 -0
  72. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_1_Ele__answer_b.png +0 -0
  73. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_1_Ele__answer_c.png +0 -0
  74. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_1_Ele__answer_d.png +0 -0
  75. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_1_Ele__paragraph.png +0 -0
  76. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_1_Ele__question.png +0 -0
  77. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_2_Ele__answer_a.png +0 -0
  78. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_2_Ele__answer_b.png +0 -0
  79. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_2_Ele__answer_c.png +0 -0
  80. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_2_Ele__answer_d.png +0 -0
  81. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_2_Ele__paragraph.png +0 -0
  82. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_2_Ele__question.png +0 -0
  83. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_3_Adv__answer_a.png +0 -0
  84. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_3_Adv__answer_b.png +0 -0
  85. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_3_Adv__answer_c.png +0 -0
  86. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_3_Adv__answer_d.png +0 -0
  87. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_3_Adv__paragraph.png +0 -0
  88. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_3_Adv__question.png +0 -0
  89. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_4_Adv__answer_a.png +0 -0
  90. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_4_Adv__answer_b.png +0 -0
  91. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_4_Adv__answer_c.png +0 -0
  92. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_4_Adv__answer_d.png +0 -0
  93. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_4_Adv__paragraph.png +0 -0
  94. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_4_Adv__question.png +0 -0
  95. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_5_Adv__answer_a.png +0 -0
  96. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_5_Adv__answer_b.png +0 -0
  97. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_5_Adv__answer_c.png +0 -0
  98. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_5_Adv__answer_d.png +0 -0
  99. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_5_Adv__paragraph.png +0 -0
  100. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_5_Adv__question.png +0 -0
  101. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_6_Ele__answer_a.png +0 -0
  102. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_6_Ele__answer_b.png +0 -0
  103. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_6_Ele__answer_c.png +0 -0
  104. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_6_Ele__answer_d.png +0 -0
  105. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_6_Ele__paragraph.png +0 -0
  106. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_1_6_Ele__question.png +0 -0
  107. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_1_Adv__answer_a.png +0 -0
  108. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_1_Adv__answer_b.png +0 -0
  109. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_1_Adv__answer_c.png +0 -0
  110. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_1_Adv__answer_d.png +0 -0
  111. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_1_Adv__paragraph.png +0 -0
  112. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_1_Adv__question.png +0 -0
  113. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_2_Adv__answer_a.png +0 -0
  114. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_2_Adv__answer_b.png +0 -0
  115. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_2_Adv__answer_c.png +0 -0
  116. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_2_Adv__answer_d.png +0 -0
  117. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_2_Adv__paragraph.png +0 -0
  118. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_2_Adv__question.png +0 -0
  119. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_3_Adv__answer_a.png +0 -0
  120. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_3_Adv__answer_b.png +0 -0
  121. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_3_Adv__answer_c.png +0 -0
  122. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_3_Adv__answer_d.png +0 -0
  123. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_3_Adv__paragraph.png +0 -0
  124. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_3_Adv__question.png +0 -0
  125. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_4_Ele__answer_a.png +0 -0
  126. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_4_Ele__answer_b.png +0 -0
  127. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_4_Ele__answer_c.png +0 -0
  128. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_4_Ele__answer_d.png +0 -0
  129. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_4_Ele__paragraph.png +0 -0
  130. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_4_Ele__question.png +0 -0
  131. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_5_Ele__answer_a.png +0 -0
  132. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_5_Ele__answer_b.png +0 -0
  133. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_5_Ele__answer_c.png +0 -0
  134. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_5_Ele__answer_d.png +0 -0
  135. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_5_Ele__paragraph.png +0 -0
  136. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_5_Ele__question.png +0 -0
  137. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_6_Ele__answer_a.png +0 -0
  138. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_6_Ele__answer_b.png +0 -0
  139. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_6_Ele__answer_c.png +0 -0
  140. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_6_Ele__answer_d.png +0 -0
  141. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_6_Ele__paragraph.png +0 -0
  142. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/2_2_6_Ele__question.png +0 -0
  143. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/images/manifest.csv +0 -0
  144. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/raw_gaze.csv +0 -0
  145. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/sample_data/raw_gaze.parquet +0 -0
  146. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/similarity.py +0 -0
  147. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/synthetic.py +0 -0
  148. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/update_sample_data.py +0 -0
  149. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio/wizard.py +0 -0
  150. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio.egg-info/dependency_links.txt +0 -0
  151. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio.egg-info/entry_points.txt +0 -0
  152. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/scanpath_studio.egg-info/top_level.txt +0 -0
  153. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/setup.cfg +0 -0
  154. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_aggregation.py +1 -1
  155. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_alignment.py +0 -0
  156. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_analysis_figures.py +0 -0
  157. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_animation_export.py +0 -0
  158. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_annotations.py +0 -0
  159. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_api.py +0 -0
  160. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_app.py +0 -0
  161. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_arc_saccades.py +0 -0
  162. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_builder_parity.py +0 -0
  163. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_citation.py +0 -0
  164. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_cli_drift.py +0 -0
  165. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_column_mapping.py +0 -0
  166. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_compare_ordering.py +0 -0
  167. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_dataset_support.py +0 -0
  168. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_deployment_gate.py +0 -0
  169. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_empty_states.py +0 -0
  170. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_export.py +0 -0
  171. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_export_naming.py +0 -0
  172. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_filters.py +0 -0
  173. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_fix_range_scope.py +0 -0
  174. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_illustration.py +0 -0
  175. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_measures.py +0 -0
  176. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_model_scanpaths.py +0 -0
  177. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_multiple_comparison_ui.py +0 -0
  178. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_multipleye_enrichment.py +0 -0
  179. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_numeric_sliders.py +0 -0
  180. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_onestop_shard.py +0 -0
  181. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_plot_config_restore.py +0 -0
  182. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_plots.py +0 -0
  183. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_raw_gaze_filters.py +0 -0
  184. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_raw_gaze_sample.py +0 -0
  185. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_remap.py +0 -0
  186. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_share_drift.py +0 -0
  187. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_similarity.py +0 -0
  188. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_smoke.py +0 -0
  189. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_synthetic.py +0 -0
  190. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_theme.py +0 -0
  191. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_tracker_server.py +0 -0
  192. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_upload_guard.py +0 -0
  193. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_wizard_helpers.py +0 -0
  194. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_word_box_geometry.py +0 -0
  195. {scanpath_studio-0.27.2 → scanpath_studio-0.28.0}/tests/test_word_id_offset.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scanpath-studio
3
- Version: 0.27.2
3
+ Version: 0.28.0
4
4
  Summary: Interactive Streamlit workbench for visualizing eye-tracking-while-reading scanpaths, computing reading measures, and exporting figures and tabular data.
5
5
  Author-email: "Omer Shubi (LACC Lab, Technion)" <lacclab.technion@gmail.com>
6
6
  License: MIT License
@@ -44,7 +44,7 @@ Requires-Python: >=3.11
44
44
  Description-Content-Type: text/markdown
45
45
  License-File: LICENSE
46
46
  License-File: NOTICE
47
- Requires-Dist: streamlit>=1.58.0
47
+ Requires-Dist: streamlit>=1.61.1
48
48
  Requires-Dist: pandas>=2.3.3
49
49
  Requires-Dist: plotly>=6.5.2
50
50
  Requires-Dist: numpy>=2.4.1
@@ -72,6 +72,7 @@ Dynamic: license-file
72
72
  [![Live demo](https://img.shields.io/badge/Live_demo-Streamlit-FF4B4B?logo=streamlit&logoColor=white)](https://scanpath-studio.streamlit.app)
73
73
  [![Docs](https://img.shields.io/badge/docs-mkdocs-blue)](https://lacclab.github.io/scanpath-studio/)
74
74
  [![CI](https://github.com/lacclab/scanpath-studio/actions/workflows/ci.yml/badge.svg)](https://github.com/lacclab/scanpath-studio/actions/workflows/ci.yml)
75
+ [![Coverage](https://img.shields.io/endpoint?url=https%3A%2F%2Flacclab.github.io%2Fscanpath-studio%2Fcoverage%2Fbadge.json)](https://lacclab.github.io/scanpath-studio/coverage/)
75
76
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
76
77
 
77
78
  An interactive workbench for visualizing **eye-tracking-while-reading** data.
@@ -5,6 +5,7 @@
5
5
  [![Live demo](https://img.shields.io/badge/Live_demo-Streamlit-FF4B4B?logo=streamlit&logoColor=white)](https://scanpath-studio.streamlit.app)
6
6
  [![Docs](https://img.shields.io/badge/docs-mkdocs-blue)](https://lacclab.github.io/scanpath-studio/)
7
7
  [![CI](https://github.com/lacclab/scanpath-studio/actions/workflows/ci.yml/badge.svg)](https://github.com/lacclab/scanpath-studio/actions/workflows/ci.yml)
8
+ [![Coverage](https://img.shields.io/endpoint?url=https%3A%2F%2Flacclab.github.io%2Fscanpath-studio%2Fcoverage%2Fbadge.json)](https://lacclab.github.io/scanpath-studio/coverage/)
8
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
9
10
 
10
11
  An interactive workbench for visualizing **eye-tracking-while-reading** data.
@@ -25,7 +25,7 @@ classifiers = [
25
25
  "Topic :: Scientific/Engineering :: Visualization",
26
26
  ]
27
27
  dependencies = [
28
- "streamlit>=1.58.0",
28
+ "streamlit>=1.61.1",
29
29
  "pandas>=2.3.3",
30
30
  "plotly>=6.5.2",
31
31
  "numpy>=2.4.1",
@@ -92,3 +92,29 @@ include = ["scanpath_studio"]
92
92
  "sample_data/images/*.png",
93
93
  "sample_data/images/*.csv",
94
94
  ]
95
+
96
+ [tool.coverage.run]
97
+ source = ["scanpath_studio"]
98
+ # Two one-shot data-prep scripts, deliberately untested and deliberately not
99
+ # counted. Both are run by hand, once per data refresh, against corpora that are
100
+ # not in the repo and cannot be in CI: `onestop_shard` needs the ~15 GB OneStop
101
+ # lacclab CSVs, `update_sample_data` needs the full OneStop release to
102
+ # regenerate the bundled demo. Testing them would mean mocking the file layout
103
+ # they exist to walk, which pins the mock rather than the script (ENG-37).
104
+ omit = [
105
+ "scanpath_studio/onestop_shard.py",
106
+ "scanpath_studio/update_sample_data.py",
107
+ ]
108
+
109
+ [tool.coverage.report]
110
+ # A floor, not a target: it fails the build when a change drops coverage
111
+ # meaningfully, without turning every PR into a coverage negotiation. Raise it
112
+ # when the real number has been comfortably above for a while.
113
+ fail_under = 89
114
+ show_missing = true
115
+ exclude_also = [
116
+ "if TYPE_CHECKING:",
117
+ "raise NotImplementedError",
118
+ "if __name__ == .__main__.:",
119
+ "@(abc\\.)?abstractmethod",
120
+ ]
@@ -27,7 +27,7 @@ __all__ = [
27
27
  "load_multipleye",
28
28
  "load_onestop",
29
29
  ]
30
- __version__ = "0.27.2"
30
+ __version__ = "0.28.0"
31
31
 
32
32
  # Public headless API (see api.py / datasets.py). Resolved lazily so
33
33
  # `import scanpath_studio` stays cheap and doesn't pull in pandas/plotly/
@@ -141,18 +141,6 @@ def known_tags() -> List[str]:
141
141
  return sorted(tags)
142
142
 
143
143
 
144
- def starred_keys() -> Set[Key]:
145
- return {k for k, v in _store().items() if v.get("star")}
146
-
147
-
148
- def keys_with_tag(tag: str) -> Set[Key]:
149
- return {k for k, v in _store().items() if tag in v.get("tags", [])}
150
-
151
-
152
- def annotated_count() -> int:
153
- return len(_store())
154
-
155
-
156
144
  def current_records() -> List[dict]:
157
145
  """All annotations as a flat record list — for embedding in a saved config."""
158
146
  return store_to_records(_store())
@@ -63,17 +63,19 @@ from .constants import ( # noqa: E402
63
63
  DEFAULT_SACCADE_WIDTH,
64
64
  FONT_FAMILY,
65
65
  PALETTES,
66
+ SACCADE_CLASS_ORDER,
66
67
  SACCADE_COLOR,
67
68
  UNIFORM_COLOR_FIELD,
68
69
  palette_settings,
69
70
  )
71
+ from .export import annotate_figure # noqa: E402
70
72
  from .plots import ( # noqa: E402
71
73
  animation_autoplay_frame_duration,
72
74
  animation_autoplay_post_script,
73
- make_scanpath_animation,
74
- make_scanpath_figure,
75
75
  make_difference_profile_figure,
76
76
  make_distribution_figure,
77
+ make_scanpath_animation,
78
+ make_scanpath_figure,
77
79
  make_word_profile_figure,
78
80
  split_scanpath_layers,
79
81
  )
@@ -161,6 +163,12 @@ CANONICAL_FIGURE_DEFAULTS: dict = dict(
161
163
  saccade_color_mode="Uniform",
162
164
  saccade_class_colors=None,
163
165
  saccade_type_legend=True,
166
+ # VIZ-31: the reading-class filter — which classes are drawn at all, as
167
+ # opposed to what colour they are drawn in. Spelled out as the full list
168
+ # rather than the equivalent `None` so this matches what the app's
169
+ # all-selected multiselect resolves to key-for-key; the builder treats a
170
+ # complete list as "no filter" and skips the classification pass.
171
+ saccade_classes=list(SACCADE_CLASS_ORDER),
164
172
  saccade_render_mode="Straight",
165
173
  fixation_snap_to_word=False,
166
174
  # VIZ-17 uniform fixation colour · VIZ-15 marker shape — the flat colour and
@@ -923,7 +931,7 @@ def _expand_palette(overrides: dict) -> dict:
923
931
  any colour the caller also passes explicitly wins over it::
924
932
 
925
933
  sps.plot_scanpath(w, f, palette="Print / greyscale")
926
- sps.plot_scanpath(w, f, palette="Colourblind-safe", saccade_color="#000")
934
+ sps.plot_scanpath(w, f, palette="Default (colourblind-safe)", saccade_color="#000")
927
935
 
928
936
  The palette itself isn't a figure kwarg, so it's consumed here rather than
929
937
  forwarded. Raises on an unknown name — a silent fallback to the default
@@ -1082,6 +1090,8 @@ def plot_scanpath(
1082
1090
  fix_index_range: Optional[Tuple[int, int]] = None,
1083
1091
  illustration: bool = False,
1084
1092
  illustration_label: str = "auto",
1093
+ title: str = "",
1094
+ caption: str = "",
1085
1095
  **figure_overrides,
1086
1096
  ) -> go.Figure:
1087
1097
  """Build the canonical scanpath figure for one trial.
@@ -1106,6 +1116,11 @@ def plot_scanpath(
1106
1116
  the app's fixation-index window. It is applied before the drift correction,
1107
1117
  like the app.
1108
1118
 
1119
+ ``title`` / ``caption`` (EXP-5) stamp a title/caption band onto the figure
1120
+ without shrinking the plot area, exactly like the rail's *Title & caption on
1121
+ the figure* control — literal text here, not the rail's ``{trial_id}``-style
1122
+ pattern, since the caller already knows which trial this is.
1123
+
1109
1124
  Remaining keywords override the app's defaults and are forwarded to
1110
1125
  :func:`plots.make_scanpath_figure` (e.g. ``show_heatmap=False``,
1111
1126
  ``color_by="pass_index"``, ``x_field="order_in_trial"``); an unknown keyword
@@ -1177,7 +1192,7 @@ def plot_scanpath(
1177
1192
  _require_normalized(raw_gaze, "raw_gaze")
1178
1193
  raw_gaze = _data.filter_raw_gaze(raw_gaze, [pid], [tid])
1179
1194
  settings.setdefault("show_raw_gaze", True)
1180
- return make_scanpath_figure(
1195
+ fig = make_scanpath_figure(
1181
1196
  trial_words,
1182
1197
  trial_fixations,
1183
1198
  canvas_width=int(canvas_size[0]),
@@ -1189,6 +1204,8 @@ def plot_scanpath(
1189
1204
  raw_gaze=raw_gaze,
1190
1205
  **settings,
1191
1206
  )
1207
+ annotate_figure(fig, title=title, caption=caption)
1208
+ return fig
1192
1209
 
1193
1210
 
1194
1211
  def animate_scanpath(
@@ -1203,6 +1220,8 @@ def animate_scanpath(
1203
1220
  playback_speed: float = 1.0,
1204
1221
  autoplay: bool = True,
1205
1222
  fix_index_range: Optional[Tuple[int, int]] = None,
1223
+ title: str = "",
1224
+ caption: str = "",
1206
1225
  **animation_overrides,
1207
1226
  ) -> go.Figure:
1208
1227
  """Build the animated scanpath replay for one trial.
@@ -1230,6 +1249,8 @@ def animate_scanpath(
1230
1249
  matches the static figure. ``palette=`` (VIZ-18) works here too; the colours
1231
1250
  it implies that the animation doesn't support are dropped rather than
1232
1251
  raising, since the caller named a look, not those individual keys.
1252
+
1253
+ ``title`` / ``caption`` (EXP-5) — same as :func:`plot_scanpath`.
1233
1254
  """
1234
1255
  valid = set(_ANIMATION_FIGURE_PARAMS)
1235
1256
  explicit = set(animation_overrides) - {"palette"}
@@ -1256,7 +1277,7 @@ def animate_scanpath(
1256
1277
  trial_fixations = _apply_fix_index_range(trial_fixations, fix_index_range, pid, tid)
1257
1278
  if canvas_size is None:
1258
1279
  canvas_size = _data.compute_canvas_size(trial_words, trial_fixations)
1259
- return make_scanpath_animation(
1280
+ fig = make_scanpath_animation(
1260
1281
  trial_words,
1261
1282
  trial_fixations,
1262
1283
  canvas_width=int(canvas_size[0]),
@@ -1267,6 +1288,8 @@ def animate_scanpath(
1267
1288
  autoplay=autoplay,
1268
1289
  **animation_overrides,
1269
1290
  )
1291
+ annotate_figure(fig, title=title, caption=caption)
1292
+ return fig
1270
1293
 
1271
1294
 
1272
1295
  def save_figure(