magscope 0.1.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.
@@ -0,0 +1,484 @@
1
+ Metadata-Version: 2.4
2
+ Name: magscope
3
+ Version: 0.1.0
4
+ Summary: Live data acquisition and analysis for magnetic tweezers microscopy with only Python
5
+ Author-email: James London <7jameslondon@gmail.com>
6
+ License-Expression: GPL-3.0
7
+ Project-URL: Homepage, https://github.com/7jameslondon/MagScope
8
+ Project-URL: Issues, https://github.com/7jameslondon/MagScope/issues
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Operating System :: Microsoft :: Windows
11
+ Requires-Python: ==3.11
12
+ Description-Content-Type: text/markdown
13
+ License-File: license
14
+ Requires-Dist: numpy
15
+ Requires-Dist: scipy
16
+ Requires-Dist: matplotlib
17
+ Requires-Dist: tifffile
18
+ Requires-Dist: PyYAML
19
+ Requires-Dist: magtrack
20
+ Requires-Dist: PyQt6
21
+ Provides-Extra: cpu
22
+ Provides-Extra: gpu
23
+ Requires-Dist: cupy-cuda12x>=13.0; sys_platform != "darwin" and extra == "gpu"
24
+ Dynamic: license-file
25
+
26
+ <h1 align="center">
27
+ MagScope
28
+ <img src="https://raw.githubusercontent.com/7jameslondon/MagScope/refs/heads/master/logo.png" width="300">
29
+ </h1><br>
30
+
31
+ [![PyPi](https://img.shields.io/pypi/v/magscope.svg)](https://pypi.org/project/magscope/)
32
+ [![Docs](https://img.shields.io/readthedocs/magscope/latest.svg)](https://magscope.readthedocs.io/en/latest/)
33
+ [![Paper](https://img.shields.io/badge/DOI-INSERTDOI-blue)](
34
+ https://doi.org/DOI-INSERTDOI)
35
+ [![Python package](https://github.com/7jameslondon/MagScope/actions/workflows/python-package.yml/badge.svg)](https://github.com/7jameslondon/MagScope/actions/workflows/python-package.yml)
36
+
37
+ MagScope is a Python framework for live data acquisition and analysis in magnetic tweezers microscopy.
38
+
39
+ * GUI (Graphical User Interface)
40
+ * No setup required to give it a try
41
+ * Easily extended to your setup
42
+ * Fast, high-throughput, and high-resolution
43
+ * Create simple scripts to automate data-collection and motor movment for long/complex experiments
44
+ * CPU or GPU tracking of beads via [MagTrack](https://github.com/7jameslondon/MagTrack)
45
+
46
+ ## ⏳ Install
47
+ ### Pre-requisites
48
+ * Python >=3.9
49
+ * PyQt6
50
+ * matplotlib
51
+ * tifffile
52
+ * PyYAML
53
+ * NumPy >=1.26
54
+ * SciPy >=1.11.1
55
+ * MagTrack
56
+ * (Optional, but needed for GPU acceleration) CuPy-CUDA12x >=13.0
57
+
58
+ ### Instructions
59
+ ```
60
+ pip install magscope[gpu]
61
+ ```
62
+ Or without CuPy
63
+ ```
64
+ pip install magscope
65
+ ```
66
+ Optional: For GPU acceleration on a computer with an NVIDIA CUDA GPU, you may need to install the CUDA Toolkit for CuPy. See details at https://docs.cupy.dev/en/stable/install.html
67
+
68
+ ## ⚒ Usage
69
+ Start with the demo verions which include a simulated camera.
70
+ ```
71
+ import magscope
72
+
73
+ scope = magscope.MagScope()
74
+ scope.start()
75
+ ```
76
+ ### More Examples
77
+ Coming soon
78
+
79
+ ## 📖 Documentation
80
+ View the full documentation at [magscope.readthedocs.io](https://magscope.readthedocs.io/en/latest/)
81
+
82
+ ## 💬 Support
83
+ Report issues, make requests, and ask questions on the [GitHub issue tracker](https://github.com/7jameslondon/MagScope/issues)
84
+
85
+
86
+
87
+
88
+
89
+
90
+
91
+ # OLD
92
+
93
+
94
+
95
+ ## Project Overview
96
+
97
+ MagScope is a modular control and analysis environment for magnetic tweezer
98
+ and microscopy experiments. It coordinates camera acquisition, bead tracking,
99
+ and hardware automation so researchers can run reproducible experiments from a
100
+ single desktop application. The toolkit is built to be extended – new cameras,
101
+ actuators, and analysis routines can plug into the same orchestration layer
102
+ without rewriting the core system.
103
+
104
+ **Key features**
105
+
106
+ * Multi-process managers for the camera, bead locking, video processing, GUI,
107
+ and scripting keep latency low while sharing data through high-performance
108
+ buffers.
109
+ * Shared-memory `VideoBuffer` and `MatrixBuffer` structures make it easy to
110
+ stream image stacks and time-series telemetry between producers and
111
+ consumers.
112
+ * A lightweight scripting runtime allows repeatable experiment protocols and
113
+ automated GUI interactions.
114
+ * Extensible hardware and control panel base classes simplify adding custom
115
+ instruments or user interface panels.
116
+
117
+ **High-level architecture**
118
+
119
+ At runtime `MagScope` instantiates manager processes for each subsystem,
120
+ including the `CameraManager`, `BeadLockManager`, `VideoProcessorManager`,
121
+ `ScriptManager`, and `WindowManager`. The core `MagScope` orchestrator loads
122
+ settings, allocates shared locks and buffers, and wires up inter-process pipes
123
+ before launching the managers. Managers exchange work and status updates via a
124
+ message-passing API and shared memory, while the GUI presents controls built on
125
+ `ControlPanelBase` widgets and time-series plots. Hardware integrations derive
126
+ from `HardwareManagerBase`, letting custom devices participate in the same
127
+ event loop and scripting hooks.
128
+
129
+ ## Documentation
130
+
131
+ In-depth guides, diagrams, and usage examples now live in the
132
+ [`docs/`](docs/) directory. Start with the
133
+ [MagScope orchestrator overview](docs/scope.md) to learn how `MagScope.start()`
134
+ wires together managers, shared memory, and inter-process communication. The
135
+ documentation site is powered by MkDocs; see [`docs/index.md`](docs/index.md)
136
+ for instructions on building the site locally and contributing new pages.
137
+
138
+ ## Quick Start Guide
139
+
140
+ Use the following condensed checklist when you simply want to get the simulated
141
+ scope running end-to-end:
142
+
143
+ 1. **Install prerequisites** – Python 3.10+, git, and a terminal for your
144
+ operating system.
145
+ 2. **Clone the repository**:
146
+
147
+ ```bash
148
+ git clone https://github.com/your-org/MagScope.git
149
+ cd MagScope
150
+ ```
151
+
152
+ 3. **Create and activate a virtual environment**:
153
+
154
+ ```bash
155
+ python3 -m venv .venv
156
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
157
+ ```
158
+
159
+ 4. **Install dependencies**:
160
+
161
+ ```bash
162
+ pip install --upgrade pip
163
+ pip install -r requirements.txt
164
+ ```
165
+
166
+ 5. **Run the simulated scope**:
167
+
168
+ ```bash
169
+ python simulated_scope.py
170
+ ```
171
+
172
+ When the GUI appears you should see the dummy camera streaming frames. Close the
173
+ window or press `Ctrl+C` in the terminal when you are finished.
174
+
175
+ ## Detailed Setup Guide
176
+
177
+ The sections below expand each quick start step with more background
178
+ information, helpful links, and troubleshooting tips for developers who are new
179
+ to Python tooling.
180
+
181
+ ### 0. Install the core tooling (Python, git, and a terminal)
182
+
183
+ If you are brand new to Python development, start by installing the latest
184
+ Python 3.10+ release from the
185
+ [official downloads page](https://www.python.org/downloads/). During the Windows
186
+ installer flow make sure the "Add python.exe to PATH" option is selected so that
187
+ the `python` command is available in Command Prompt and PowerShell. You will
188
+ also need a terminal (macOS Terminal, Windows Terminal, or any Linux shell) and
189
+ [git](https://git-scm.com/downloads) to clone the project repository. The
190
+ [Python beginner's guide to software engineering](https://docs.python.org/3/faq/programming.html)
191
+ explains how these pieces fit together if you need more background.
192
+
193
+ Once Python and git are installed, clone the repository and change into the
194
+ project directory:
195
+
196
+ ```bash
197
+ git clone https://github.com/your-org/MagScope.git
198
+ cd MagScope
199
+ ```
200
+
201
+ If you prefer a graphical interface, GitHub Desktop and GitKraken both provide
202
+ point-and-click workflows that accomplish the same clone and checkout steps.
203
+
204
+ ### 1. Create an isolated Python environment
205
+
206
+ MagScope targets Python 3.10 or newer. From the project root create and activate
207
+ a virtual environment so the project's dependencies stay separate from other
208
+ Python work. If you are new to the concept, the
209
+ [official venv tutorial](https://docs.python.org/3/tutorial/venv.html) provides a
210
+ gentle walkthrough.
211
+
212
+ ```bash
213
+ python3 -m venv .venv
214
+ source .venv/bin/activate
215
+ ```
216
+
217
+ On Windows use `python -m venv .venv` followed by `.venv\Scripts\activate`. You
218
+ can confirm activation by checking that your shell prompt is prefixed with
219
+ `(.venv)` and that `which python` (macOS/Linux) or `where python` (Windows)
220
+ points to the `.venv` directory.
221
+
222
+ ### 2. Install the dependencies
223
+
224
+ With the virtual environment activated, install the project requirements using
225
+ `pip`, Python's package installer. If you have never used `pip` before, the
226
+ [official user guide](https://pip.pypa.io/en/stable/user_guide/) explains the
227
+ basics and common troubleshooting steps.
228
+
229
+ Install the core requirements with pip:
230
+
231
+ ```bash
232
+ pip install --upgrade pip
233
+ pip install -r requirements.txt
234
+ ```
235
+
236
+ The list includes optional GPU-accelerated packages such as CuPy. If you do not
237
+ have a compatible CUDA toolkit available, comment out or remove the CuPy line
238
+ and install the remainder of the requirements. The
239
+ [Python Packaging User Guide](https://packaging.python.org/en/latest/tutorials/installing-packages/)
240
+ has additional background if you want to learn more about how Python packages
241
+ are managed.
242
+
243
+ ### 3. Run the simulated scope end-to-end
244
+
245
+ When everything looks correct, start the simulated scope. The repository ships
246
+ with a dummy camera so you can exercise the full user interface without
247
+ connecting lab hardware. Launch it with:
248
+
249
+ ```bash
250
+ python simulated_scope.py
251
+ ```
252
+
253
+ This command starts `MagScope`, wires the `DummyBeadCamera` into the
254
+ `CameraManager`, and opens the Qt-based GUI. You should see the interface begin
255
+ streaming mock camera frames within a few seconds. If the window does not
256
+ appear, double-check that the virtual environment is active and that the
257
+ required Qt libraries were installed during the dependency step. When you are
258
+ ready to connect real instruments you can instead run `python main.py` and
259
+ configure the hardware classes described later in this document.
260
+
261
+ ```mermaid
262
+ flowchart TD
263
+ subgraph Core Orchestrator
264
+ A[MagScope Main Process]
265
+ end
266
+
267
+ subgraph Shared Memory Buffers
268
+ VB[VideoBuffer]
269
+ MB[MatrixBuffer]
270
+ end
271
+
272
+ subgraph Manager Processes
273
+ CM[CameraManager]
274
+ BLM[BeadLockManager]
275
+ VPM[VideoProcessorManager]
276
+ SM[ScriptManager]
277
+ WM[WindowManager]
278
+ end
279
+
280
+ A -- spawn & configure --> CM
281
+ A -- spawn & configure --> BLM
282
+ A -- spawn & configure --> VPM
283
+ A -- spawn & configure --> SM
284
+ A -- spawn & configure --> WM
285
+
286
+ CM -- frames --> VB
287
+ VPM -- processed frames --> VB
288
+ BLM -- bead positions --> MB
289
+ SM -- experiment data --> MB
290
+
291
+ VB -. read/update .-> VPM
292
+ VB -. display frames .-> WM
293
+ MB -. analysis results .-> WM
294
+
295
+ WM -- GUI commands --> SM
296
+ SM -- IPC messages --> CM
297
+ SM -- IPC messages --> BLM
298
+ SM -- IPC messages --> VPM
299
+ ```
300
+
301
+ ## Settings
302
+
303
+ The `settings.py` module provides a convenient location for storing key user
304
+ preferences. Two notable parameters are `OBJECTIVE_MAG`, which determines how
305
+ pixels are converted to nanometers, and `ROI_WIDTH`, which defines the width of
306
+ the region of interest.
307
+
308
+ ## Configuring a Camera
309
+
310
+ Verify your camera integration by running `test_camera.py` in the `tests`
311
+ directory. To add a camera, create a subclass of `CameraABC` (see
312
+ `camera.py`) and implement the required attributes and methods. Finally, set
313
+ the `ImplementedCamera` variable in `camera.py` to reference your new class.
314
+
315
+ ## Shared-memory data buffers
316
+
317
+ The ``magscope.datatypes`` module defines the shared-memory-backed buffers that
318
+ processes use to exchange data efficiently.
319
+
320
+ * ``VideoBuffer`` stores image stacks and their capture timestamps. Create it in
321
+ the producer process with the desired shape information and share the
322
+ resulting metadata with consumer processes that instantiate the class with
323
+ ``create=False``.
324
+ * ``MatrixBuffer`` stores 2D numeric data such as bead positions or motor
325
+ telemetry. The number of columns is fixed when the buffer is created, while
326
+ the number of rows written at a time can vary up to the buffer capacity.
327
+
328
+ Both buffers expect locks from ``multiprocessing`` so reads and writes can be
329
+ coordinated safely. See ``magscope/datatypes.py`` for detailed docstrings
330
+ covering their parameters and usage patterns.
331
+
332
+ ## Force Calibrants (optional)
333
+
334
+ Provide force calibrants as plain-text files (for example, `force cal.txt`). You
335
+ may comment out the header line with `#`. Each subsequent line should map the
336
+ motor position in millimeters to the force in piconewtons. Include as many
337
+ interpolated data points as possible for the most accurate fit, e.g.:
338
+
339
+ ```
340
+ # Motor Position (mm) Force (pN)
341
+ 1.000 5.000
342
+ 1.010 5.053
343
+ 1.020 5.098
344
+ 1.030 5.156
345
+ ...
346
+ ```
347
+
348
+ ## Adding custom hardware
349
+
350
+ To add hardware, create a subclass of `HardwareManagerBase`.
351
+
352
+ * Set `buffer_shape` in `__init__`. Each row represents a time point. For
353
+ example, a shape of `(100000, 3)` stores 100,000 time points with three values
354
+ per sample (for example, time, position, and speed).
355
+ * Implement `connect`, which should set `self._is_connected` to `True` when the
356
+ connection succeeds.
357
+ * Implement `disconnect`.
358
+ * Implement `fetch`, which appends an entry to the buffer whenever the
359
+ program automatically polls the device.
360
+
361
+ ## Scripting
362
+
363
+ MagScope ships with a lightweight scripting runtime that allows you to queue up
364
+ GUI interactions and hardware commands for repeatable experiments. A script is
365
+ an instance of `magscope.Script` where each call records a step to be executed
366
+ by the `ScriptManager` process:
367
+
368
+ ```python
369
+ import magscope
370
+
371
+ script = magscope.Script()
372
+ script('set_acquisition_mode', magscope.AcquisitionMode.CROP_VIDEO)
373
+ script('sleep', 2.0) # wait for 2 seconds before running the next command
374
+ script('print', 'Ready for capture!')
375
+ ```
376
+
377
+ Save the script to a `.py` file and load it from the GUI to run it. The manager
378
+ validates each step to ensure the referenced method exists and that the
379
+ provided arguments match the registered callable.
380
+
381
+ Built-in scriptable functions include:
382
+
383
+ * `print` – display a message in the GUI log
384
+ * `sleep` – pause script execution for a fixed number of seconds
385
+ * `set_acquisition_on` – toggle processing of incoming frames
386
+ * `set_acquisition_dir` – choose the directory used to save acquisitions
387
+ * `set_acquisition_dir_on` – enable or disable saving data to disk
388
+ * `set_acquisition_mode` – switch between modes such as tracking or video
389
+ recording
390
+
391
+ See `example_script.py` for a minimal working example.
392
+
393
+ Expose additional methods to scripts by decorating a manager method with
394
+ `@registerwithscript('my_method_name')`. The string you provide becomes the
395
+ first argument when adding the step to a script, for example
396
+ `script('my_method_name', ...)`.
397
+
398
+ ## Adding a custom process
399
+
400
+ You can extend `ManagerProcessBase` to create a separate process that manages
401
+ logic more complex than a single hardware device. Implement the following
402
+ abstract methods:
403
+
404
+ * `setup` – called when the process starts on its dedicated worker. Initialize
405
+ long-lived resources such as timers or hardware connections here. If no setup
406
+ work is required, use `pass`.
407
+ * `do_main_loop` – invoked repeatedly for the lifetime of the process. Place
408
+ autonomous process logic here. If no actions are needed, use `pass`.
409
+
410
+ ## Adding a control panel
411
+
412
+ Subclass `ControlPanelBase` and implement an `__init__` method to construct the
413
+ PyQt6 widgets. The initializer must accept a `manager` argument and pass it to
414
+ `super().__init__`. Later, access `self.manager` to invoke `WindowManager`
415
+ functions. `ControlPanelBase` derives from `QWidget` and provides a default
416
+ `QVBoxLayout`. Replace the layout with `setLayout` if needed, or add elements
417
+ via `self.layout().addWidget()` and `self.layout().addLayout()`.
418
+
419
+ Example:
420
+
421
+ ```
422
+ import magscope
423
+
424
+ class MyNewControlPanel(magscope.ControlPanelBase):
425
+ def __init__(self, manager: 'WindowManager'):
426
+ super().__init__(manager=manager, title='New Panel')
427
+ self.layout().addWidget(QLabel('This is my new panel'))
428
+
429
+ row = QHBoxLayout()
430
+ self.layout().addLayout(row)
431
+
432
+ row.addWidget(QLabel('A Button'))
433
+ button = QPushButton('Press Me')
434
+ button.clicked.connect(self.button_callback)
435
+ row.addWidget(button)
436
+
437
+ def button_callback(self):
438
+ print('The button was pressed')
439
+ ```
440
+
441
+ ## Sending interprocess calls (IPC)
442
+
443
+ Start by creating a `magscope.Message`. Provide at least two arguments: `to`,
444
+ which specifies the destination process (for example `CameraManager` or the
445
+ base `ManagerProcessBase` to broadcast to all managers), and `meth`, which is
446
+ the uninvoked method object that should be executed (for example
447
+ `CameraManager.set_camera_setting`). Do not call the method when constructing
448
+ the message. Supply positional or keyword arguments as additional parameters, or
449
+ explicitly pass tuples and dictionaries through the `args` and `kwargs`
450
+ keywords.
451
+
452
+ Send the message with `send_ipc()`. To avoid circular imports, perform local
453
+ imports of the destination process class immediately before use.
454
+
455
+ Example:
456
+
457
+ ```
458
+ import magscope
459
+
460
+ class MyProcesses(magscope.ManagerProcessBase):
461
+ def send_camera_setting(self, setting_name, setting_value):
462
+ message = magscope.Message(
463
+ to=magscope.CameraManager,
464
+ meth=magscope.CameraManager.set_camera_setting,
465
+ args=(setting_name, setting_value),
466
+ )
467
+ self.send_ipc(message)
468
+ ```
469
+
470
+ ## Development
471
+
472
+ To format the Python files, run the following commands:
473
+
474
+ ```bash
475
+ yapf main.py -i
476
+ yapf .\magscope\ -i -r
477
+ yapf .\tests\ -i -r
478
+ ```
479
+
480
+ To install MagTrack during development, run:
481
+
482
+ ```bash
483
+ pip install --force-reinstall --no-deps --no-cache-dir '..\MagTrack\magtrack-0.3.2-py3-none-any.whl'
484
+ ```