mesofield 0.3.2b0__py3-none-any.whl

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 (111) hide show
  1. docs/_static/custom.css +40 -0
  2. docs/_static/favicon.png +0 -0
  3. docs/_static/logo.png +0 -0
  4. docs/api/index.md +70 -0
  5. docs/conf.py +200 -0
  6. docs/developer_guide.md +303 -0
  7. docs/index.md +25 -0
  8. docs/tutorial.md +4 -0
  9. docs/user_guide.md +172 -0
  10. examples/teensy_pulse_generator.py +320 -0
  11. experiments/pipeline_demo/experiment.json +24 -0
  12. experiments/pipeline_demo/hardware.yaml +23 -0
  13. experiments/pipeline_demo/procedure.py +50 -0
  14. experiments/two_cam_demo/experiment.json +24 -0
  15. experiments/two_cam_demo/hardware.yaml +58 -0
  16. experiments/two_cam_demo/load_dataset.py +213 -0
  17. experiments/two_cam_demo/procedure.py +87 -0
  18. external/video-codecs/openh264-1.8.0-win64.dll +0 -0
  19. mesofield/__init__.py +45 -0
  20. mesofield/__main__.py +11 -0
  21. mesofield/_version.py +24 -0
  22. mesofield/base.py +750 -0
  23. mesofield/cli/__init__.py +57 -0
  24. mesofield/cli/_richhelp.py +100 -0
  25. mesofield/cli/acquire.py +254 -0
  26. mesofield/cli/datakit.py +165 -0
  27. mesofield/cli/process.py +376 -0
  28. mesofield/cli/rig.py +108 -0
  29. mesofield/cli/tools.py +347 -0
  30. mesofield/config.py +751 -0
  31. mesofield/data/__init__.py +23 -0
  32. mesofield/data/batch.py +633 -0
  33. mesofield/data/manager.py +388 -0
  34. mesofield/data/writer.py +289 -0
  35. mesofield/datakit/__init__.py +44 -0
  36. mesofield/datakit/__main__.py +35 -0
  37. mesofield/datakit/_utils/_logger.py +5 -0
  38. mesofield/datakit/_version.py +141 -0
  39. mesofield/datakit/config.py +50 -0
  40. mesofield/datakit/core.py +783 -0
  41. mesofield/datakit/datamodel.py +200 -0
  42. mesofield/datakit/discover.py +124 -0
  43. mesofield/datakit/explore.py +651 -0
  44. mesofield/datakit/notebooks/pupil_dlc.ipynb +2445 -0
  45. mesofield/datakit/profile.py +535 -0
  46. mesofield/datakit/shell.py +83 -0
  47. mesofield/datakit/sources/__init__.py +65 -0
  48. mesofield/datakit/sources/analysis/mesomap.py +194 -0
  49. mesofield/datakit/sources/analysis/mesoscope.py +77 -0
  50. mesofield/datakit/sources/analysis/pupil.py +246 -0
  51. mesofield/datakit/sources/behavior/__init__.py +0 -0
  52. mesofield/datakit/sources/behavior/dataqueue.py +281 -0
  53. mesofield/datakit/sources/behavior/psychopy.py +364 -0
  54. mesofield/datakit/sources/behavior/treadmill.py +323 -0
  55. mesofield/datakit/sources/behavior/wheel.py +277 -0
  56. mesofield/datakit/sources/camera/mesoscope.py +32 -0
  57. mesofield/datakit/sources/camera/metadata_json.py +130 -0
  58. mesofield/datakit/sources/camera/pupil.py +28 -0
  59. mesofield/datakit/sources/camera/suite2p.py +547 -0
  60. mesofield/datakit/sources/register.py +204 -0
  61. mesofield/datakit/sources/session/config.py +130 -0
  62. mesofield/datakit/sources/session/notes.py +63 -0
  63. mesofield/datakit/sources/session/timestamps.py +58 -0
  64. mesofield/datakit/timeline.py +306 -0
  65. mesofield/devices/__init__.py +42 -0
  66. mesofield/devices/base.py +498 -0
  67. mesofield/devices/base_camera.py +295 -0
  68. mesofield/devices/cameras.py +740 -0
  69. mesofield/devices/daq.py +151 -0
  70. mesofield/devices/encoder.py +384 -0
  71. mesofield/devices/mocks.py +275 -0
  72. mesofield/devices/psychopy_device.py +455 -0
  73. mesofield/devices/subprocesses/__init__.py +0 -0
  74. mesofield/devices/subprocesses/psychopy.py +133 -0
  75. mesofield/devices/treadmill.py +318 -0
  76. mesofield/engines.py +380 -0
  77. mesofield/gui/Mesofield_icon.png +0 -0
  78. mesofield/gui/__init__.py +76 -0
  79. mesofield/gui/config_wizard.py +724 -0
  80. mesofield/gui/controller.py +535 -0
  81. mesofield/gui/dynamic_controller.py +78 -0
  82. mesofield/gui/maingui.py +427 -0
  83. mesofield/gui/mdagui.py +285 -0
  84. mesofield/gui/qt_device_adapter.py +109 -0
  85. mesofield/gui/speedplotter.py +152 -0
  86. mesofield/gui/theme.py +445 -0
  87. mesofield/gui/tiff_viewer.py +1050 -0
  88. mesofield/gui/viewer.py +691 -0
  89. mesofield/hardware.py +549 -0
  90. mesofield/playback.py +1298 -0
  91. mesofield/processing/__init__.py +12 -0
  92. mesofield/processing/runner.py +237 -0
  93. mesofield/processors/__init__.py +13 -0
  94. mesofield/processors/base.py +287 -0
  95. mesofield/processors/frame_mean.py +19 -0
  96. mesofield/protocols.py +378 -0
  97. mesofield/scaffold/__init__.py +34 -0
  98. mesofield/scaffold/experiment.py +400 -0
  99. mesofield/scaffold/rigs.py +121 -0
  100. mesofield/signals.py +85 -0
  101. mesofield/utils/__init__.py +0 -0
  102. mesofield/utils/_logger.py +156 -0
  103. mesofield/utils/retrofit.py +309 -0
  104. mesofield/utils/utils.py +217 -0
  105. mesofield-0.3.2b0.dist-info/METADATA +178 -0
  106. mesofield-0.3.2b0.dist-info/RECORD +111 -0
  107. mesofield-0.3.2b0.dist-info/WHEEL +5 -0
  108. mesofield-0.3.2b0.dist-info/entry_points.txt +2 -0
  109. mesofield-0.3.2b0.dist-info/licenses/LICENSE +21 -0
  110. mesofield-0.3.2b0.dist-info/top_level.txt +6 -0
  111. scripts/bench_frame_processor.py +103 -0
@@ -0,0 +1,178 @@
1
+ Metadata-Version: 2.4
2
+ Name: mesofield
3
+ Version: 0.3.2b0
4
+ Summary: Mesofield is an open-source image acquisition Python software package build for the Sipe Laboratory at Pennsylvania State University.
5
+ Author: Jacob Gronemeyer
6
+ License: MIT License
7
+
8
+ Copyright (c) 2024 Gronemeyer
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/Gronemeyer/mesofield/
29
+ Project-URL: Repository, https://github.com/Gronemeyer/mesofield/
30
+ Project-URL: Issues, https://github.com/Gronemeyer/mesofield/issues
31
+ Project-URL: Documentation, https://gronemeyer.github.io/mesofield/
32
+ Keywords: imaging,microscopy,acquisition,neuroscience
33
+ Classifier: Development Status :: 4 - Beta
34
+ Classifier: Intended Audience :: Science/Research
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Operating System :: OS Independent
37
+ Classifier: Programming Language :: Python :: 3.10
38
+ Classifier: Programming Language :: Python :: 3.11
39
+ Classifier: Programming Language :: Python :: 3.12
40
+ Classifier: Topic :: Scientific/Engineering
41
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
42
+ Requires-Python: >=3.10
43
+ Description-Content-Type: text/markdown
44
+ License-File: LICENSE
45
+ Requires-Dist: annotated-types
46
+ Requires-Dist: click
47
+ Requires-Dist: ipykernel
48
+ Requires-Dist: ipython
49
+ Requires-Dist: jupyter_client
50
+ Requires-Dist: jupyter_core
51
+ Requires-Dist: loguru
52
+ Requires-Dist: markdown-it-py
53
+ Requires-Dist: matplotlib
54
+ Requires-Dist: mesokit-schema
55
+ Requires-Dist: nidaqmx
56
+ Requires-Dist: numpy
57
+ Requires-Dist: packaging
58
+ Requires-Dist: pandas
59
+ Requires-Dist: parso
60
+ Requires-Dist: pillow
61
+ Requires-Dist: platformdirs
62
+ Requires-Dist: psygnal
63
+ Requires-Dist: pyaml
64
+ Requires-Dist: opencv-python
65
+ Requires-Dist: pymmcore
66
+ Requires-Dist: pymmcore-plus
67
+ Requires-Dist: pymmcore-widgets
68
+ Requires-Dist: PyQt6
69
+ Requires-Dist: PyQt6-Qt6
70
+ Requires-Dist: PyQt6_sip
71
+ Requires-Dist: pyqtgraph
72
+ Requires-Dist: pyserial
73
+ Requires-Dist: python-dateutil
74
+ Requires-Dist: pytz
75
+ Requires-Dist: pywin32; sys_platform == "win32"
76
+ Requires-Dist: pyzmq
77
+ Requires-Dist: qtconsole
78
+ Requires-Dist: rich
79
+ Requires-Dist: setuptools
80
+ Requires-Dist: tifffile
81
+ Requires-Dist: typer
82
+ Requires-Dist: typer-slim
83
+ Requires-Dist: typing_extensions
84
+ Requires-Dist: useq-schema
85
+ Requires-Dist: wheel
86
+ Provides-Extra: test
87
+ Requires-Dist: pytest; extra == "test"
88
+ Requires-Dist: coverage; extra == "test"
89
+ Requires-Dist: flake8; extra == "test"
90
+ Requires-Dist: black; extra == "test"
91
+ Requires-Dist: isort; extra == "test"
92
+ Requires-Dist: pytest-cov; extra == "test"
93
+ Requires-Dist: mypy; extra == "test"
94
+ Requires-Dist: gitchangelog; extra == "test"
95
+ Provides-Extra: docs
96
+ Requires-Dist: sphinx>=7; extra == "docs"
97
+ Requires-Dist: pydata-sphinx-theme; extra == "docs"
98
+ Requires-Dist: myst-parser; extra == "docs"
99
+ Requires-Dist: sphinx-copybutton; extra == "docs"
100
+ Requires-Dist: sphinx-design; extra == "docs"
101
+ Dynamic: license-file
102
+
103
+ ```
104
+ __ __ ______ ______ ______ ______ __ ______ __ _____
105
+ /\ "-./ \ /\ ___\ /\ ___\ /\ __ \ /\ ___\ /\ \ /\ ___\ /\ \ /\ __-.
106
+ \ \ \-./\ \ \ \ __\ \ \___ \ \ \ \/\ \ \ \ __\ \ \ \ \ \ __\ \ \ \____ \ \ \/\ \
107
+ \ \_\ \ \_\ \ \_____\ \/\_____\ \ \_____\ \ \_\ \ \_\ \ \_____\ \ \_____\ \ \____-
108
+ \/_/ \/_/ \/_____/ \/_____/ \/_____/ \/_/ \/_/ \/_____/ \/_____/ \/____/
109
+ ```
110
+
111
+ Mesofield is a PyQt6-based framework for running real-time, multi-camera
112
+ neuroscience experiments. It coordinates hardware via serial connections
113
+ and MicroManager (through [pymmcore-plus](https://pymmcore-plus.github.io/pymmcore-plus/)
114
+ custom `MDAEngine`s and multi-`CMMCorePlus` instancing) and manages
115
+ experiment configuration, acquisition orchestration, and data logging.
116
+ The project is aimed at laboratory use and is not a full production
117
+ package; some specialised knowledge of device hardware and
118
+ MicroManager device configuration is necessary to get started.
119
+
120
+ <img width="2454" height="1592" alt="Mesofield acquisition window" src="https://github.com/user-attachments/assets/151196ab-2d74-4644-85b7-c4facf3b779a" />
121
+
122
+ ---
123
+
124
+ ## Documentation
125
+
126
+ Documentation lives at **[gronemeyer.github.io/mesofield](https://gronemeyer.github.io/mesofield/)**
127
+ and is split by audience:
128
+
129
+ - **[Tutorial](https://gronemeyer.github.io/mesofield/tutorial.html)** —
130
+ the fastest path from a fresh conda env to a working acquisition on
131
+ your hardware.
132
+ - **[User Guide](https://gronemeyer.github.io/mesofield/user_guide.html)** —
133
+ for experimenters running acquisitions: launching the GUI, writing
134
+ `experiment.json`, interpreting the on-disk output.
135
+ - **[Developer Guide](https://gronemeyer.github.io/mesofield/developer_guide.html)** —
136
+ for developers extending mesofield: custom devices, `Procedure`
137
+ subclasses, frame processors, threading models.
138
+ - **[API Reference](https://gronemeyer.github.io/mesofield/api/index.html)** —
139
+ auto-generated from docstrings.
140
+
141
+ ---
142
+
143
+ ## Quick start
144
+
145
+ ```bash
146
+ conda create -n mesofield python=3.12 -y
147
+ conda activate mesofield
148
+ pip install -e .
149
+ ```
150
+
151
+ Launch an acquisition:
152
+
153
+ ```bash
154
+ mesofield launch path/to/experiment.json
155
+ ```
156
+
157
+ Scaffold a new experiment:
158
+
159
+ ```bash
160
+ mesofield new my-experiment
161
+ ```
162
+
163
+ For end-to-end setup, follow the
164
+ [Tutorial](https://gronemeyer.github.io/mesofield/tutorial.html).
165
+
166
+ ---
167
+
168
+ ## System requirements
169
+
170
+ Tested on Windows 10/11. For multi-camera acquisition with large files
171
+ we recommend ≥ 32 GB RAM, a 12th-gen Intel i7 or equivalent, and fast
172
+ local NVMe storage for the experiment directory.
173
+
174
+ ---
175
+
176
+ ## License
177
+
178
+ MIT — see `LICENSE`.
@@ -0,0 +1,111 @@
1
+ docs/conf.py,sha256=28qzRsFqHtGuxwMMnO61Z3342QWuAFf-Lot3Ce-4ccw,5797
2
+ docs/developer_guide.md,sha256=VwL0-VwSGDlJqn8WtfFNKkKIdWDJpbR-rCnMm8sDWmM,10092
3
+ docs/index.md,sha256=MZmUXpcVBVRzekQ16L8ptgbD-2c8MxhFGk9pX0rYK7k,231
4
+ docs/tutorial.md,sha256=O02adi_EwtThPnGZPm5PFq8SfkJItsyvFsKum68CX7s,44
5
+ docs/user_guide.md,sha256=fkkPPO2B91ptc8FU2YEN9ne-06kin_3WQHAxToivkkU,5456
6
+ docs/_static/custom.css,sha256=GghYxBc-OUBS2ZlzRbpFdlWpoJmwdRgv6IqOAx4abPM,1143
7
+ docs/_static/favicon.png,sha256=wID6OeeUAaa9Z3nRDViMwodadPUyut6P1PY_ZqrnO-M,5521
8
+ docs/_static/logo.png,sha256=v-vcal3qIT7UQ-fFoVKZxmqoSnSx9gm3fUBOvjDOa5c,3307179
9
+ docs/api/index.md,sha256=M6ei1sQoAD5vV7F7YdSkTprJIerEch2cOIpqMKXslDY,1419
10
+ examples/teensy_pulse_generator.py,sha256=N_pCd-zy-58dvV_bd0gduzrbSEkNPp5dcmAUq4w820o,11809
11
+ experiments/pipeline_demo/experiment.json,sha256=i0TxmPDbQMUKzA1HSQZLPedwJ5p4peprCuxAfeou9GM,510
12
+ experiments/pipeline_demo/hardware.yaml,sha256=RZwkcwUNtxDNDkNZdYBiqjNodBEEQz9yc2RAZp1A9qU,766
13
+ experiments/pipeline_demo/procedure.py,sha256=Jf6NQKDMzDmbafPUZ6HvZJWy-v0IcecHWp-JePoIfKk,1794
14
+ experiments/two_cam_demo/experiment.json,sha256=d_6sJQO0tamUtFcD_96arwUu6jlawzzp7RuF9dHuHks,500
15
+ experiments/two_cam_demo/hardware.yaml,sha256=RueqtivtSLNErUbZZFkFv_Eu_SxTt7TJf07REjVe8Nw,1670
16
+ experiments/two_cam_demo/load_dataset.py,sha256=xUfIbLKLxOhYWxE0gkzDz5ueVIQztpinW4M95qflkAM,7833
17
+ experiments/two_cam_demo/procedure.py,sha256=_aCodNaMV38K1-TQdwEpSKOBmsrTSkhdrhpaOmgNohI,2811
18
+ external/video-codecs/openh264-1.8.0-win64.dll,sha256=46XPBbZzoX6_6VrGtHlgfPTfIon-Sm1fPT_wmqj1YZI,825160
19
+ mesofield/__init__.py,sha256=PNApkSEBeOKDn8H36K82ypujeE_z3RJqwqUdO9BcynU,1598
20
+ mesofield/__main__.py,sha256=LQd6RQOjvkGRKNjYt0axPM8K1lpIy7e09HXFDeCDtAQ,322
21
+ mesofield/_version.py,sha256=8vQ-PW_RN5R5Sm30qpmcKIOz6bUBKcwPZ4KWfmHoUhA,528
22
+ mesofield/base.py,sha256=eZDZ2CSE-gYkhd5qFqtNyoYNpbcvI0t8Xaz1uOh-hzk,30882
23
+ mesofield/config.py,sha256=uVxGvOf9_c20fq7J71SAQz_jkNws6n5LCKdEJqIhiP0,29665
24
+ mesofield/engines.py,sha256=LH5Jv-9rpQAV3xGxzZeB2hSYEVQ0QJM3TEnLbUIoQ5M,17385
25
+ mesofield/hardware.py,sha256=1BvZGrN5Xkl550C5cOA45OiwbwcmxEVhzHrjfIhVW6w,23056
26
+ mesofield/playback.py,sha256=_kmb7hqodXlvl5ZhJYWq6UpiIsQltpOQrzRB54DRzkY,48359
27
+ mesofield/protocols.py,sha256=fWtBRBDcj6GRDGUJH8b2fTLvVfFbyRT_2oONrjQzs4w,11173
28
+ mesofield/signals.py,sha256=FnL-cXwTJDp9kbO5shqrWPewKk3njlqGWJyRJ6ODZz4,3191
29
+ mesofield/cli/__init__.py,sha256=W0_C7bRJMuBCBLU7lzvjfs_MJDXZqVxK4P-wdVID9U8,1521
30
+ mesofield/cli/_richhelp.py,sha256=nGs_dUnanY4O7Chyw-iw6ajOdA1K-D86CE1xl4oCw6Q,3455
31
+ mesofield/cli/acquire.py,sha256=omtRtH2n3TKNthdmWtCgUVUvpy8YWBvstQQr1IAar3I,9796
32
+ mesofield/cli/datakit.py,sha256=fS-tGBJIpuSQPgNtINYQiKVFJY6PSeTl2OspVinP79Q,6668
33
+ mesofield/cli/process.py,sha256=sjlRHNfSr0SdrbYy1h-MANN8jr5vtsE-AUxQQLUDMk4,14798
34
+ mesofield/cli/rig.py,sha256=nsRYQTYFhqjFr5pazEnXAjoywkhUobxyo94f63vV1kE,3400
35
+ mesofield/cli/tools.py,sha256=st3YE4LmAMxRxalSIj9Pb0FJPNO2U0d_F3S7dXaFX9o,12446
36
+ mesofield/data/__init__.py,sha256=n2IWLLEAltoYNHturPUqpXG581oOZ4ViJZwzn7efnu0,850
37
+ mesofield/data/batch.py,sha256=6BwlCdq_rnIg19p4glZ2bMLdyaAPQmgDYXuhpDhMAK0,23543
38
+ mesofield/data/manager.py,sha256=OL-LZfx7oosQtDJaxiZK2H7Z1Zu1BcpsZWY8_ga0zbI,15029
39
+ mesofield/data/writer.py,sha256=B3W5CloTmoeqGsLCnHFHWLkppDRsGyviJvxCt2_RDxw,12084
40
+ mesofield/datakit/__init__.py,sha256=q_NUyMwNpRPB1ETlrKKydTGjVI0I0_cc5FOB1a5lvxw,1229
41
+ mesofield/datakit/__main__.py,sha256=J7oYsPGBJDL99U2CSx4lt7zi-5pChmTsegsXCJzDhoM,953
42
+ mesofield/datakit/_version.py,sha256=P1-D0rmwXjXyZsIU_ebUw3WdyW_d3Ni8pkBY5yQGziU,4445
43
+ mesofield/datakit/config.py,sha256=LzD0WttrIb44LM9tlcnK3cqvaiWinudKYRUFTt37y2w,1359
44
+ mesofield/datakit/core.py,sha256=YDNMxgwZDtXso4SvYrZzVfe5F-QKH7lH9BG8IsXrkjM,29420
45
+ mesofield/datakit/datamodel.py,sha256=NpdoAh2tscDNeTRfO0s2Wzx1CoQjY7AGymamFUrfd24,6909
46
+ mesofield/datakit/discover.py,sha256=0iGwnwnKthw2lmSQ_y6aDwhK1Z_3kG5AtWqtYHoWz_Y,4317
47
+ mesofield/datakit/explore.py,sha256=nGJ5OVMnU-uGlH0ZCQt1Opjlt9LI4T8Qf7SCh-w8Xu0,22348
48
+ mesofield/datakit/profile.py,sha256=sVppbHBiIu4H8ybnKmxggfpZCt2wHryklx56CNekanM,20147
49
+ mesofield/datakit/shell.py,sha256=BivWC-tPEAKnnPPlcl6nA-Jbn1QRopezSOJMQJuPrk0,2736
50
+ mesofield/datakit/timeline.py,sha256=VIm0_vmk2SvYqk9JZt9gcFTb5RDMr_as3NF_nYLTHKM,10472
51
+ mesofield/datakit/_utils/_logger.py,sha256=G5zHT8QlDCWZgdRZLD290WY1QdskJLy0BLEPBeU8m80,232
52
+ mesofield/datakit/notebooks/pupil_dlc.ipynb,sha256=ujk_XZe3aJQFHIXx3VtuQuV3huZPgndZS_-eZbJxviw,174264
53
+ mesofield/datakit/sources/__init__.py,sha256=hoNoMtyPTSnkSkxDHeilXrp-Zcfp9pvAbr_VZp8yVyc,2005
54
+ mesofield/datakit/sources/register.py,sha256=uqpOrXeFWKl5Pdvlhkwp-YC6ya82IDo_-bAFtH0xYSg,7572
55
+ mesofield/datakit/sources/analysis/mesomap.py,sha256=6VRonqRHB-JgoNujeBz_H5HXRiW9UiIp9In0bLxbWXE,5818
56
+ mesofield/datakit/sources/analysis/mesoscope.py,sha256=dLn_0G-63qzy7o8X-hNsyTTbXdNnOFHA6iVT_8e9P10,2499
57
+ mesofield/datakit/sources/analysis/pupil.py,sha256=Vltfu2Lzpj0HSPr2CbrVcNz5CMtQoIZYMvFDdETlehU,10136
58
+ mesofield/datakit/sources/behavior/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
+ mesofield/datakit/sources/behavior/dataqueue.py,sha256=hayM6CPNVPmTO6BHSAWHPEgl6fS5REYiHaVwpUjO3i0,11394
60
+ mesofield/datakit/sources/behavior/psychopy.py,sha256=r5CiETEfnGzpzK27tDwK6sg-8ecumtC2jMOiSTkHzlg,17554
61
+ mesofield/datakit/sources/behavior/treadmill.py,sha256=LM2xjiWdUdDDK42LVR6jTxRR6OteWFQU-hE3UrJtXzY,13100
62
+ mesofield/datakit/sources/behavior/wheel.py,sha256=ix25Dk4C8zFVsMEmAxLUsdvQGFaX8LyWMkBwJz6R74E,11379
63
+ mesofield/datakit/sources/camera/mesoscope.py,sha256=2epNdmHuDaU1mojLW4Oy0byG40iKJRmhJ7CSAs_89bM,975
64
+ mesofield/datakit/sources/camera/metadata_json.py,sha256=vcwPSuEAFQSDc0PGhiL-XZLq4aZBL3wjDN-M9FOg2yY,4953
65
+ mesofield/datakit/sources/camera/pupil.py,sha256=Z0BfXaI0ih4psD0eMtqVVAqVicnQ2in5WnuTBRO06AM,895
66
+ mesofield/datakit/sources/camera/suite2p.py,sha256=74-VUCyB-agb3E94ASi3ri8oL5j_v8FmS4aISm77h64,21374
67
+ mesofield/datakit/sources/session/config.py,sha256=yMUX4ev2ZJczn6baD0F7cMcmz3cPTfQC7rheLrnqbTM,4070
68
+ mesofield/datakit/sources/session/notes.py,sha256=AQTcQpQiGdVCjULJUnrjieYi3zonCg-6QagZqnn5ZK8,2202
69
+ mesofield/datakit/sources/session/timestamps.py,sha256=48Vimmg9NHHTf4pn7k1hkF9YdYm8gbbkHRr5uVHzgLM,1760
70
+ mesofield/devices/__init__.py,sha256=i3S6vfo-vs3nfilVA-t8zEoqr92JEx4GV7I-I1k9yb8,1139
71
+ mesofield/devices/base.py,sha256=Ammh4GyIgIEcW4EhHOf_dzKIN8q2SimL8kDcyOWCxQE,18883
72
+ mesofield/devices/base_camera.py,sha256=g3q9rWXB9l8TWmkk131YTG_4-deB-sj4OX9nyPuYxIs,13336
73
+ mesofield/devices/cameras.py,sha256=gQKkGyv8iiOl3bcJcpGik7bRnhXUytokdbnUqntMxnc,30938
74
+ mesofield/devices/daq.py,sha256=s9HZjP6WgQSwxhom3rUQ2DTJn3yqqcWrctEieXNP3Pw,5087
75
+ mesofield/devices/encoder.py,sha256=bfLefLJiw5TYHQ9T8aLrO9X_xaA1hDA_JDcfCQEexlQ,15721
76
+ mesofield/devices/mocks.py,sha256=DiZAuDnXyteQbdbM71WX30EGVa4vg7Xl1Hqjr2sWH9k,9676
77
+ mesofield/devices/psychopy_device.py,sha256=C-iXt5k_3fD0n97MowySAiXwvf6I1RCg8l6JGlp0_Zg,20127
78
+ mesofield/devices/treadmill.py,sha256=C8Bd5PTPdl-kWrrwo0zm3FyLSb805qQ62CPjXq_zzcc,12505
79
+ mesofield/devices/subprocesses/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
+ mesofield/devices/subprocesses/psychopy.py,sha256=ogjlV3Z8SCt1UUpgUnHnzbtII3T4oklkxYELt6w3UO8,4779
81
+ mesofield/gui/Mesofield_icon.png,sha256=v-vcal3qIT7UQ-fFoVKZxmqoSnSx9gm3fUBOvjDOa5c,3307179
82
+ mesofield/gui/__init__.py,sha256=JaN3ucCS9oljWyMgDvSBEIIjLmm-Gqan63fFziFmJdM,2972
83
+ mesofield/gui/config_wizard.py,sha256=Xtg0FGRkS_XkIWjA15OyaRskKL8CurO0u60cio5BXzs,26306
84
+ mesofield/gui/controller.py,sha256=d59eBrKzm79ecWzzwPYNvqUXBRQTNt6QdOSkLSxBlLE,22956
85
+ mesofield/gui/dynamic_controller.py,sha256=-TW0hgzTz8JWck7BPkgTpFh3dd3ifd3PWH2esj-a0K0,3067
86
+ mesofield/gui/maingui.py,sha256=zmWDPxV9HyGJuu9ZnIzrCBIYhrhSr03J-GCP7P9UyeQ,18399
87
+ mesofield/gui/mdagui.py,sha256=8SWPiCfj7WeXnc614093m5sQ1lAFs0S7YKPWxZW3zRw,12333
88
+ mesofield/gui/qt_device_adapter.py,sha256=ArdQY4ViY4MdgEkTAO8cjNz7TOe-QvJx-RB87w8O4ec,3873
89
+ mesofield/gui/speedplotter.py,sha256=HInnc9-U9B9l184r2YeA2GO5C-d8Uspx3G2rGGf0xV0,5331
90
+ mesofield/gui/theme.py,sha256=AfGPpXW-UXjJ1yRFTWxvPJOF2K6VCrcYyklmmuBUf50,12575
91
+ mesofield/gui/tiff_viewer.py,sha256=jKJBYCXfdaamo3iMsHDUMwG2y-YHHkcIjbamGU4jj48,39855
92
+ mesofield/gui/viewer.py,sha256=1AO73-HsvWDePoOJdXg6TDJCShzsYDn_ONZNGhNFdTc,27919
93
+ mesofield/processing/__init__.py,sha256=NB8sq44fSHokcHCZHtfbmcTXXemDCnSjcqdklF0A0AI,493
94
+ mesofield/processing/runner.py,sha256=0F3k7tHwC9fhzwnr5lrTrHBIOFNwp9RJKD-a6Nhcbu8,8777
95
+ mesofield/processors/__init__.py,sha256=2kWdxGH3n9ujnkDKbzKZjkRt0TTnxnutMVr8Dp0bYRE,519
96
+ mesofield/processors/base.py,sha256=2JbE5PDAW7v1b624mb73d0J_5zMXVGpBAFCG5LNmHWM,10121
97
+ mesofield/processors/frame_mean.py,sha256=jDwLprmRuv60ZfZxnuaikWg4ZosS12m_81a8ViU11kY,465
98
+ mesofield/scaffold/__init__.py,sha256=kYmq5PQg0LEIsO2yIs2bIgoE0hi0Rs6FT7mOOwoe5F8,799
99
+ mesofield/scaffold/experiment.py,sha256=dcjjqfN0NZ1h1NduV2BcTxR2wJ1157eC-SGB5db-aFw,16078
100
+ mesofield/scaffold/rigs.py,sha256=TD6JVB_7i8-dYwo-F8kTtssR6YC5H66opfSRRd0arQY,4235
101
+ mesofield/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
102
+ mesofield/utils/_logger.py,sha256=U6Zcn-MPG7GrY3pS1THDt59mVx0Ql3Ky-27wgIePwCw,4423
103
+ mesofield/utils/retrofit.py,sha256=hr4yWWRxfHiUeLiq55cYZOJIKp1b9hzMowlCaKFMxQQ,11037
104
+ mesofield/utils/utils.py,sha256=mfrsHMob1-A8rMXN2qZ9XrdmTpIQiyL9HOuTkWRsxbQ,7516
105
+ mesofield-0.3.2b0.dist-info/licenses/LICENSE,sha256=K-JfzMZ1QmIaDcdcEHXi2Oq4K4AT092cqbQoy5LeR0o,1067
106
+ scripts/bench_frame_processor.py,sha256=m8rnBoBPUp_L5O0lZr3AP0MYUq-nfmC-5uFUVdgMcgQ,3317
107
+ mesofield-0.3.2b0.dist-info/METADATA,sha256=Uy99aQ_JFvWN32rkaLlU46uEXTJODicxFSa0xEgeFKQ,6653
108
+ mesofield-0.3.2b0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
109
+ mesofield-0.3.2b0.dist-info/entry_points.txt,sha256=nDsPDlUztjAGQC1awrNrSC4tnrxbpNYd4uL2lrfTc0s,48
110
+ mesofield-0.3.2b0.dist-info/top_level.txt,sha256=t_c9i9mTQRzaM345eXWVMqlGjyKXZgG23RYVPhZg0oU,53
111
+ mesofield-0.3.2b0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ mesofield = mesofield.cli:cli
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Gronemeyer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ docs
2
+ examples
3
+ experiments
4
+ external
5
+ mesofield
6
+ scripts
@@ -0,0 +1,103 @@
1
+ """Stress harness for :class:`mesofield.processors.FrameProcessor`.
2
+
3
+ Emits synthetic frames through ``DeviceSignals.frame`` at a target rate
4
+ with a configurable image size and (optional) artificial compute load,
5
+ then prints throughput, drop %, and EWMA / max compute time.
6
+
7
+ No real camera or Qt is required. Example::
8
+
9
+ python scripts/bench_frame_processor.py --size 512 --fps 60 --seconds 3
10
+ python scripts/bench_frame_processor.py --size 2048 --fps 120 \\
11
+ --extra-compute-ms 5 --seconds 5
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import argparse
17
+ import time
18
+ from typing import Any, Optional
19
+
20
+ import numpy as np
21
+
22
+ from mesofield.processors import FrameMean
23
+ from mesofield.signals import DeviceSignals
24
+
25
+
26
+ class _FakeCamera:
27
+ def __init__(self, fps: float) -> None:
28
+ self.signals = DeviceSignals()
29
+ self.sampling_rate = fps
30
+
31
+
32
+ class _BenchMean(FrameMean):
33
+ """FrameMean with an optional artificial compute delay."""
34
+
35
+ def __init__(self, *args: Any, extra_compute_ms: float = 0.0, **kw: Any) -> None:
36
+ super().__init__(*args, **kw)
37
+ self._extra_s = extra_compute_ms / 1000.0
38
+
39
+ def compute(self, img: Any, idx: Any, ts: Any) -> Optional[float]:
40
+ v = super().compute(img, idx, ts)
41
+ if self._extra_s > 0:
42
+ time.sleep(self._extra_s)
43
+ return v
44
+
45
+
46
+ def run(size: int, fps: float, seconds: float, extra_compute_ms: float) -> dict:
47
+ cam = _FakeCamera(fps=fps)
48
+ proc = _BenchMean(name="bench", camera=cam, extra_compute_ms=extra_compute_ms)
49
+ proc.attach(cam)
50
+
51
+ period = 1.0 / fps if fps > 0 else 0.0
52
+ n_target = int(seconds * fps)
53
+ img_buf = np.random.default_rng(0).integers(
54
+ 0, 255, size=(size, size), dtype=np.uint16
55
+ )
56
+
57
+ emit_t0 = time.perf_counter()
58
+ next_t = emit_t0
59
+ for i in range(n_target):
60
+ # Mutate a couple of pixels so the mean changes each frame.
61
+ img_buf[i % size, 0] = (i * 13) & 0xFF
62
+ cam.signals.frame.emit(img_buf, i, time.perf_counter() - emit_t0)
63
+ if period:
64
+ next_t += period
65
+ sleep_for = next_t - time.perf_counter()
66
+ if sleep_for > 0:
67
+ time.sleep(sleep_for)
68
+ emit_elapsed = time.perf_counter() - emit_t0
69
+
70
+ # Let the worker drain the last frame.
71
+ time.sleep(max(0.1, (proc.compute_ms_ewma * 3) / 1000.0))
72
+ proc.detach()
73
+
74
+ s = proc.status()
75
+ s["emit_elapsed_s"] = round(emit_elapsed, 3)
76
+ s["target_fps"] = fps
77
+ s["actual_emit_fps"] = round(n_target / emit_elapsed, 1) if emit_elapsed else 0.0
78
+ s["frame_size"] = f"{size}x{size}"
79
+ s["extra_compute_ms"] = extra_compute_ms
80
+ return s
81
+
82
+
83
+ def main() -> None:
84
+ p = argparse.ArgumentParser()
85
+ p.add_argument("--size", type=int, default=512, help="square frame edge (px)")
86
+ p.add_argument("--fps", type=float, default=60.0, help="target emission rate")
87
+ p.add_argument("--seconds", type=float, default=3.0, help="run duration")
88
+ p.add_argument(
89
+ "--extra-compute-ms",
90
+ type=float,
91
+ default=0.0,
92
+ help="extra artificial compute load per frame (ms)",
93
+ )
94
+ args = p.parse_args()
95
+
96
+ s = run(args.size, args.fps, args.seconds, args.extra_compute_ms)
97
+ width = max(len(k) for k in s)
98
+ for k, v in s.items():
99
+ print(f" {k:<{width}} : {v}")
100
+
101
+
102
+ if __name__ == "__main__":
103
+ main()