QuLab 2.0.1__cp311-cp311-macosx_10_9_universal2.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.
- QuLab-2.0.1.dist-info/LICENSE +21 -0
- QuLab-2.0.1.dist-info/METADATA +95 -0
- QuLab-2.0.1.dist-info/RECORD +82 -0
- QuLab-2.0.1.dist-info/WHEEL +5 -0
- QuLab-2.0.1.dist-info/entry_points.txt +2 -0
- QuLab-2.0.1.dist-info/top_level.txt +1 -0
- qulab/__init__.py +1 -0
- qulab/__main__.py +24 -0
- qulab/fun.cpython-311-darwin.so +0 -0
- qulab/monitor/__init__.py +1 -0
- qulab/monitor/__main__.py +8 -0
- qulab/monitor/config.py +41 -0
- qulab/monitor/dataset.py +77 -0
- qulab/monitor/event_queue.py +54 -0
- qulab/monitor/mainwindow.py +234 -0
- qulab/monitor/monitor.py +93 -0
- qulab/monitor/ploter.py +123 -0
- qulab/monitor/qt_compat.py +16 -0
- qulab/monitor/toolbar.py +265 -0
- qulab/scan/__init__.py +4 -0
- qulab/scan/base.py +548 -0
- qulab/scan/dataset.py +0 -0
- qulab/scan/expression.py +472 -0
- qulab/scan/optimize.py +0 -0
- qulab/scan/scanner.py +270 -0
- qulab/scan/transforms.py +16 -0
- qulab/scan/utils.py +37 -0
- qulab/storage/__init__.py +0 -0
- qulab/storage/__main__.py +51 -0
- qulab/storage/backend/__init__.py +0 -0
- qulab/storage/backend/redis.py +204 -0
- qulab/storage/base_dataset.py +352 -0
- qulab/storage/chunk.py +60 -0
- qulab/storage/dataset.py +127 -0
- qulab/storage/file.py +273 -0
- qulab/storage/models/__init__.py +22 -0
- qulab/storage/models/base.py +4 -0
- qulab/storage/models/config.py +28 -0
- qulab/storage/models/file.py +89 -0
- qulab/storage/models/ipy.py +58 -0
- qulab/storage/models/models.py +88 -0
- qulab/storage/models/record.py +161 -0
- qulab/storage/models/report.py +22 -0
- qulab/storage/models/tag.py +93 -0
- qulab/storage/storage.py +95 -0
- qulab/sys/__init__.py +0 -0
- qulab/sys/chat.py +688 -0
- qulab/sys/device/__init__.py +3 -0
- qulab/sys/device/basedevice.py +221 -0
- qulab/sys/device/loader.py +86 -0
- qulab/sys/device/utils.py +46 -0
- qulab/sys/drivers/FakeInstrument.py +52 -0
- qulab/sys/drivers/__init__.py +0 -0
- qulab/sys/ipy_events.py +125 -0
- qulab/sys/net/__init__.py +0 -0
- qulab/sys/net/bencoder.py +205 -0
- qulab/sys/net/cli.py +169 -0
- qulab/sys/net/dhcp.py +543 -0
- qulab/sys/net/dhcpd.py +176 -0
- qulab/sys/net/kad.py +1142 -0
- qulab/sys/net/kcp.py +192 -0
- qulab/sys/net/nginx.py +192 -0
- qulab/sys/progress.py +190 -0
- qulab/sys/rpc/__init__.py +0 -0
- qulab/sys/rpc/client.py +0 -0
- qulab/sys/rpc/exceptions.py +96 -0
- qulab/sys/rpc/msgpack.py +1052 -0
- qulab/sys/rpc/msgpack.pyi +41 -0
- qulab/sys/rpc/rpc.py +412 -0
- qulab/sys/rpc/serialize.py +139 -0
- qulab/sys/rpc/server.py +29 -0
- qulab/sys/rpc/socket.py +29 -0
- qulab/sys/rpc/utils.py +25 -0
- qulab/sys/rpc/worker.py +0 -0
- qulab/version.py +1 -0
- qulab/visualization/__init__.py +188 -0
- qulab/visualization/__main__.py +71 -0
- qulab/visualization/_autoplot.py +457 -0
- qulab/visualization/plot_layout.py +408 -0
- qulab/visualization/plot_seq.py +90 -0
- qulab/visualization/qdat.py +152 -0
- qulab/visualization/widgets.py +86 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 feihoo87
|
|
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,95 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: QuLab
|
|
3
|
+
Version: 2.0.1
|
|
4
|
+
Summary: contral instruments and manage data
|
|
5
|
+
Author-email: feihoo87 <feihoo87@gmail.com>
|
|
6
|
+
Maintainer-email: feihoo87 <feihoo87@gmail.com>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/feihoo87/QuLab
|
|
9
|
+
Project-URL: Bug Reports, https://github.com/feihoo87/QuLab/issues
|
|
10
|
+
Project-URL: Source, https://github.com/feihoo87/QuLab/
|
|
11
|
+
Keywords: experiment,laboratory
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator
|
|
20
|
+
Classifier: Programming Language :: Python
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: blinker >=1.4
|
|
28
|
+
Requires-Dist: click >=7.1.2
|
|
29
|
+
Requires-Dist: dill >=0.3.6
|
|
30
|
+
Requires-Dist: GitPython >=3.1.14
|
|
31
|
+
Requires-Dist: ipython >=7.4.0
|
|
32
|
+
Requires-Dist: ipywidgets >=7.4.2
|
|
33
|
+
Requires-Dist: matplotlib >=3.7.2
|
|
34
|
+
Requires-Dist: numpy >=1.13.3
|
|
35
|
+
Requires-Dist: ply >=3.11
|
|
36
|
+
Requires-Dist: scipy >=1.0.0
|
|
37
|
+
|
|
38
|
+
# QuLab
|
|
39
|
+
[](https://travis-ci.org/feihoo87/QuLab)
|
|
40
|
+
[](https://coveralls.io/github/feihoo87/QuLab)
|
|
41
|
+
[](https://pyup.io/repos/github/feihoo87/QuLab/)
|
|
42
|
+
[](http://qulab.readthedocs.org)
|
|
43
|
+
[](https://badge.fury.io/py/QuLab)
|
|
44
|
+
[]()
|
|
45
|
+
[](https://doi.org/10.5281/zenodo.3352232)
|
|
46
|
+
|
|
47
|
+
**Documentation can be found at [qulab.readthedocs.org](https://qulab.readthedocs.org/).**
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
We encourage installing QuLab via the pip tool (a python package manager):
|
|
51
|
+
```bash
|
|
52
|
+
python -m pip install QuLab
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
To install from the latest source, you need to clone the GitHub repository on your machine.
|
|
56
|
+
```bash
|
|
57
|
+
git clone https://github.com/feihoo87/QuLab.git
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Then dependencies and QuLab can be installed in this way:
|
|
61
|
+
```bash
|
|
62
|
+
cd QuLab
|
|
63
|
+
python -m pip install -e .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Usage
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
## Running Tests
|
|
70
|
+
To run tests:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
python -m pip install -r requirements-dev.txt
|
|
74
|
+
python -m pytest
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Attribution
|
|
78
|
+
If you make use of this code, please consider citing the Zenodo DOI [](https://doi.org/10.5281/zenodo.3352232) as a software citation:
|
|
79
|
+
```
|
|
80
|
+
@misc{xu_huikai_2019_3352232,
|
|
81
|
+
author = {Xu, Huikai},
|
|
82
|
+
title = {QuLab},
|
|
83
|
+
month = aug,
|
|
84
|
+
year = 2019,
|
|
85
|
+
doi = {10.5281/zenodo.3352232},
|
|
86
|
+
url = {https://doi.org/10.5281/zenodo.3352232}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Reporting Issues
|
|
91
|
+
Please report all issues [on github](https://github.com/feihoo87/QuLab/issues).
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
[MIT](https://opensource.org/licenses/MIT)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
qulab/__init__.py,sha256=8zLGg-DfQhnDl2Ky0n-zXpN-8e-g7iR0AcaI4l4Vvpk,32
|
|
2
|
+
qulab/__main__.py,sha256=HnWr_0eErzaJUkjeTpeR7-l5FASfYK-h0VtqQI-eVoc,371
|
|
3
|
+
qulab/fun.cpython-311-darwin.so,sha256=yZONlFl41M9Z37UygNHeMFNtyeHskCbAPtrJuxncif0,160422
|
|
4
|
+
qulab/version.py,sha256=pMl7p0vBanIg04EfboBE80RyG_KP7M0m9V3-qTl0YLQ,21
|
|
5
|
+
qulab/monitor/__init__.py,sha256=nTHelnDpxRS_fl_B38TsN0njgq8eVTEz9IAnN3NbDlM,42
|
|
6
|
+
qulab/monitor/__main__.py,sha256=w3yUcqq195LzSnXTkQcuC1RSFRhy4oQ_PEBmucXguME,97
|
|
7
|
+
qulab/monitor/config.py,sha256=fQ5JcsMApKc1UwANEnIvbDQZl8uYW0tle92SaYtX9lI,744
|
|
8
|
+
qulab/monitor/dataset.py,sha256=C4wZU-XqYHY1ysvUGSF5958M_GANrXW-f1SHnruHJno,2455
|
|
9
|
+
qulab/monitor/event_queue.py,sha256=o66jOTKJmJibt-bhYFjk5p_rExxu-hdoR_BfR8PMN3I,1823
|
|
10
|
+
qulab/monitor/mainwindow.py,sha256=Bme7YKg2LQSpRH6cg8rcFhdnxUU_d_F4b6TIvPVAbx4,7799
|
|
11
|
+
qulab/monitor/monitor.py,sha256=7E4bnTsO6qC85fs2ONrccGHfaYKv7SW74mtXzv6QjVc,2305
|
|
12
|
+
qulab/monitor/ploter.py,sha256=CbiIjmohgtwDDTVeGzhXEGVo3XjytMdhLwU9VUkg9vo,3601
|
|
13
|
+
qulab/monitor/qt_compat.py,sha256=OK71_JSO_iyXjRIKHANmaK4Lx4bILUzmXI-mwKg3QeI,788
|
|
14
|
+
qulab/monitor/toolbar.py,sha256=WEag6cxAtEsOLL14XvM7pSE56EA3MO188_JuprNjdBs,7948
|
|
15
|
+
qulab/scan/__init__.py,sha256=yT_L9Rdr9lwxds-uq-sC_lhnTQxJgIkSzQkiX9PYmug,216
|
|
16
|
+
qulab/scan/base.py,sha256=SAmv-QRPHcN_FlfKeMykbBatm5Qo5DS76PFt5h2xtWY,17143
|
|
17
|
+
qulab/scan/dataset.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
|
+
qulab/scan/expression.py,sha256=J0F7jFyCkMKcHieT5ok6alivjrnHXPqQ0Xil5czGDuI,14781
|
|
19
|
+
qulab/scan/optimize.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
+
qulab/scan/scanner.py,sha256=H5wXarVeJab6pNVfLEWB6jCmpeIdpUu6igR9vlaQ-wc,7802
|
|
21
|
+
qulab/scan/transforms.py,sha256=ReUuG57B_1GEgOwZZaxYbOTappG7yY9ERvagc2v48Pg,252
|
|
22
|
+
qulab/scan/utils.py,sha256=2bj7ggTNTK5LXwBDi8w7IzFqFjchoE6EhgSASC0fpDQ,1024
|
|
23
|
+
qulab/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
+
qulab/storage/__main__.py,sha256=3emxxRry8BB0m8hUZvJ_oBqkPy7ksV7flHB_KEDXZuI,1692
|
|
25
|
+
qulab/storage/base_dataset.py,sha256=4aKhqBNdZfdlm_z1Qy5dv0HrvgpvMdy8pbyfua8uE-4,11865
|
|
26
|
+
qulab/storage/chunk.py,sha256=dtck2Pem7OYYX3TYlnWwfqrgXSmkLhi0nN_ElbuS-c8,1701
|
|
27
|
+
qulab/storage/dataset.py,sha256=Q9asJxNwYNcmu7sSqsAdAntYIre9b4dGIiFnt1O-KI4,4655
|
|
28
|
+
qulab/storage/file.py,sha256=KAaXFI1SKdcCVWjopVqYaWU4WZgZU9Oh2epdqH1ADPw,8343
|
|
29
|
+
qulab/storage/storage.py,sha256=qRyR-5zRRx84DfsifozlYKMRj8bykwRyF7TW8oyFmwk,2561
|
|
30
|
+
qulab/storage/backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
+
qulab/storage/backend/redis.py,sha256=hNaPP0V1BSWbUcx4AxOhEXiR83c_BZqeVzeOYkb8-zM,5202
|
|
32
|
+
qulab/storage/models/__init__.py,sha256=DkKzQF7tYd1WL1gGPuCThBcGfpnCuZ_PTLrqV3M_EJ0,586
|
|
33
|
+
qulab/storage/models/base.py,sha256=QLXiTRCPcg28BCFxBHexAxdNLjh2ONkzgNavoFOBW9s,114
|
|
34
|
+
qulab/storage/models/config.py,sha256=Mxk0-YcK0WgA-7-2oIuDMAeBaUECzj-3_oPvgF7gYtE,689
|
|
35
|
+
qulab/storage/models/file.py,sha256=1Rypz1QSco6drBCiR_BS6Oy0ifOapBIeNEm0uDqqxBk,2716
|
|
36
|
+
qulab/storage/models/ipy.py,sha256=uYBeqWsOxxCWUsDpnwhxugh6C9OuH92OrChlLj0gddk,1574
|
|
37
|
+
qulab/storage/models/models.py,sha256=JUqtvk8ywulkcFL38WfTviuVOcdvSGakZYJS7jAPNig,2879
|
|
38
|
+
qulab/storage/models/record.py,sha256=L0k531bGF9JN-GLv3hG87tB7k0kuSBkEeC9vi6_qywE,4970
|
|
39
|
+
qulab/storage/models/report.py,sha256=j9ByrVoue-rwaXcnfTzVOSf1xDJdlZJq666agF0AZRY,798
|
|
40
|
+
qulab/storage/models/tag.py,sha256=c3cTxpJUoG9L6xyDvVuagYVhB32amzbkBOmVeRIZ5Zo,2339
|
|
41
|
+
qulab/sys/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
|
+
qulab/sys/chat.py,sha256=DlFLP_gbVyL8fDUyad6Xu8sjQCZJauLIvF31mj5BtMs,22449
|
|
43
|
+
qulab/sys/ipy_events.py,sha256=qvsqs7-CYQ-P4WtSe9UUZZ0tC88XxPMd9DM4LJALgEk,2889
|
|
44
|
+
qulab/sys/progress.py,sha256=Tk1B96_1QrlI4yU0cyZlf2wVsF238DjQGqXJVG2j4t0,5350
|
|
45
|
+
qulab/sys/device/__init__.py,sha256=bDqJrYQJx8YR4u_CYvJPpIBr6whP7pVnxnROTHk_yhA,149
|
|
46
|
+
qulab/sys/device/basedevice.py,sha256=iqyX2SQLb7aRWNE5Uj2yHkFOLqVrX2I1N-xubTDB5tQ,6423
|
|
47
|
+
qulab/sys/device/loader.py,sha256=AL0rNF4UZ-CUHoF8FNtT_ZGLwySvz7SDPsKALaJS8po,2501
|
|
48
|
+
qulab/sys/device/utils.py,sha256=H9TvMqHZABhFdIah4uT0x9FvQ6ZPwbvw-wCnWTy4rfo,1564
|
|
49
|
+
qulab/sys/drivers/FakeInstrument.py,sha256=kwIXN-dHmvGYBinmcCLxUQKm0ENiJpsMwgQIYNLDS2k,1867
|
|
50
|
+
qulab/sys/drivers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
51
|
+
qulab/sys/net/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
52
|
+
qulab/sys/net/bencoder.py,sha256=p85DtmVy3cna3Da07boau77el2Cnym5-mKGF4xCJSy4,4959
|
|
53
|
+
qulab/sys/net/cli.py,sha256=dm-JxbgZgFH2P_5Zu3kSrLzy2U_VRLswkvE1d3xGp0w,5690
|
|
54
|
+
qulab/sys/net/dhcp.py,sha256=gT5ehyvwW3y8E5u_DnYRd5I0KaddonmQJFVhlIS2yxM,23509
|
|
55
|
+
qulab/sys/net/dhcpd.py,sha256=pNC47i-hu8HTzCrKU0PatL3AbgEqe1ovmpLPwNoZLa8,5322
|
|
56
|
+
qulab/sys/net/kad.py,sha256=gGYb9cXbAdbYhubQdCRqOGigllBy0kSUp4z3_f3AWz0,38981
|
|
57
|
+
qulab/sys/net/kcp.py,sha256=oFyiosQ1o0qeVA9hODIYEZtJj4HN1aNLGVP6vbxouMs,5761
|
|
58
|
+
qulab/sys/net/nginx.py,sha256=QAQthr_Dux7xRpgqeY6BVxxre4dg0WJITztSk8Fn-jU,4964
|
|
59
|
+
qulab/sys/rpc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
60
|
+
qulab/sys/rpc/client.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
61
|
+
qulab/sys/rpc/exceptions.py,sha256=djK44hYVMixF2Y-lAXDGHlyyCmYGw7EJjB3I0ttejok,2567
|
|
62
|
+
qulab/sys/rpc/msgpack.py,sha256=s9mbPIkQktO1FiSAuE6ymM_1w8rIERA0gMm5GQkT7z8,35327
|
|
63
|
+
qulab/sys/rpc/msgpack.pyi,sha256=3dJgISPCTEBo65VaoGjcFkdLijPx6zJtKqcZiS9bcaE,1274
|
|
64
|
+
qulab/sys/rpc/rpc.py,sha256=9ZwzC79FgmbHXbO1Gjg4z0wZgHLDziTwVuS2aZpLJAk,11979
|
|
65
|
+
qulab/sys/rpc/serialize.py,sha256=0SR1me02mao2JwWR3rdjUIcOzh1m1JFb7fLEaw_q-pE,3355
|
|
66
|
+
qulab/sys/rpc/server.py,sha256=e3R0gwOHpLEkSp7Tb43FMSDvqSG-pjrkskdISKQRseE,713
|
|
67
|
+
qulab/sys/rpc/socket.py,sha256=e3R0gwOHpLEkSp7Tb43FMSDvqSG-pjrkskdISKQRseE,713
|
|
68
|
+
qulab/sys/rpc/utils.py,sha256=6YGFOkY7o09lkA_I1FIP9_1Up3k2F1KOkftvu0_8lxo,594
|
|
69
|
+
qulab/sys/rpc/worker.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
70
|
+
qulab/visualization/__init__.py,sha256=26cuHt3QIJXUb3VaMxlJx3IQTOUVJFKlYBZr7WMP53M,6129
|
|
71
|
+
qulab/visualization/__main__.py,sha256=9zKK3yZFy0leU40ou6BpRC1Fsetfc1gjjFzIZYIwP6Y,1639
|
|
72
|
+
qulab/visualization/_autoplot.py,sha256=p4jzsJFgtOhnU0iuZJvjTT2ar6fvGd9VmxBr5dx1JC8,13777
|
|
73
|
+
qulab/visualization/plot_layout.py,sha256=clNw9QjE_kVNpIIx2Ob4YhAz2fucPGMuzkoIrOJo_Y8,13533
|
|
74
|
+
qulab/visualization/plot_seq.py,sha256=lphYF4VhkEdc_wWr1kFBwrx2yujkyFPFaJ3pjr61awI,2693
|
|
75
|
+
qulab/visualization/qdat.py,sha256=ZeevBYWkzbww4xZnsjHhw7wRorJCBzbG0iEu-XQB4EA,5735
|
|
76
|
+
qulab/visualization/widgets.py,sha256=6KkiTyQ8J-ei70LbPQZAK35wjktY47w2IveOa682ftA,3180
|
|
77
|
+
QuLab-2.0.1.dist-info/LICENSE,sha256=PRzIKxZtpQcH7whTG6Egvzl1A0BvnSf30tmR2X2KrpA,1065
|
|
78
|
+
QuLab-2.0.1.dist-info/METADATA,sha256=9lh5a31NtQa3tADAUrr94sSw38Mzza_1BSzEkHJVtPY,3385
|
|
79
|
+
QuLab-2.0.1.dist-info/WHEEL,sha256=eupBwbXGAhwNAPJSvj5BiShZwdZO8jnQ5yHfv-9aUGw,115
|
|
80
|
+
QuLab-2.0.1.dist-info/entry_points.txt,sha256=ohBzutEnQimP_BZWiuXdSliu4QAYSHHcN0PZD8c7ZCY,46
|
|
81
|
+
QuLab-2.0.1.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
|
|
82
|
+
QuLab-2.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
qulab
|
qulab/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .version import __version__
|
qulab/__main__.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from .monitor.__main__ import main as monitor
|
|
4
|
+
from .sys.net.cli import dht
|
|
5
|
+
from .visualization.__main__ import plot
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@click.group()
|
|
9
|
+
def main():
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@main.command()
|
|
14
|
+
def hello():
|
|
15
|
+
"""Print hello world."""
|
|
16
|
+
click.echo('hello, world')
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
main.add_command(monitor)
|
|
20
|
+
main.add_command(plot)
|
|
21
|
+
main.add_command(dht)
|
|
22
|
+
|
|
23
|
+
if __name__ == '__main__':
|
|
24
|
+
main()
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .monitor import Monitor, get_monitor
|
qulab/monitor/config.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
style = '''
|
|
4
|
+
QWidget {
|
|
5
|
+
font: medium Ubuntu;
|
|
6
|
+
background-color: #011F2F;
|
|
7
|
+
font-size: 16px;
|
|
8
|
+
font-size: 16px;
|
|
9
|
+
color:#FFFFFF;
|
|
10
|
+
}
|
|
11
|
+
'''
|
|
12
|
+
#
|
|
13
|
+
Nroll = 6
|
|
14
|
+
|
|
15
|
+
# Format of the data.
|
|
16
|
+
forms = {
|
|
17
|
+
"mag": lambda w, ang: np.abs(w),
|
|
18
|
+
"phase": lambda w, ang: np.angle(w),
|
|
19
|
+
"real": lambda w, ang: np.real(w),
|
|
20
|
+
"imag": lambda w, ang: np.imag(w),
|
|
21
|
+
"rot": lambda w, ang: np.real(np.exp(1j * ang) * np.array(w))
|
|
22
|
+
}
|
|
23
|
+
form_keys = list(forms.keys())
|
|
24
|
+
#
|
|
25
|
+
COL_SEL = (0, 0, 0)
|
|
26
|
+
COL_UNSEL = (6, 6, 8)
|
|
27
|
+
#
|
|
28
|
+
|
|
29
|
+
defualt_colors = [
|
|
30
|
+
(200, 0, 0),
|
|
31
|
+
(55, 100, 180),
|
|
32
|
+
(40, 80, 150),
|
|
33
|
+
(30, 50, 110),
|
|
34
|
+
(25, 40, 70),
|
|
35
|
+
(25, 30, 50),
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
widths = [3, 2, 2, 2, 1, 1]
|
|
39
|
+
SymSize = [5, 0, 0, 0, 0, 0]
|
|
40
|
+
ridx = list(range(Nroll))
|
|
41
|
+
ridx.reverse()
|
qulab/monitor/dataset.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from collections import defaultdict, deque
|
|
2
|
+
|
|
3
|
+
from .config import Nroll
|
|
4
|
+
|
|
5
|
+
PAUSE_TIME = 1
|
|
6
|
+
|
|
7
|
+
Number = int | float | complex
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def remove_duplicates(input_list: list[str]) -> list[str]:
|
|
11
|
+
"""
|
|
12
|
+
Remove duplicates from a list of strings, keeping the order of the elements.
|
|
13
|
+
"""
|
|
14
|
+
return list(dict.fromkeys(input_list))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Dataset():
|
|
18
|
+
|
|
19
|
+
def __init__(self):
|
|
20
|
+
self.column_names = []
|
|
21
|
+
self.box = deque(maxlen=Nroll)
|
|
22
|
+
self.dirty = True
|
|
23
|
+
|
|
24
|
+
def clear(self):
|
|
25
|
+
self.box.clear()
|
|
26
|
+
|
|
27
|
+
def clear_history(self):
|
|
28
|
+
o = self.box.popleft()
|
|
29
|
+
self.box.clear()
|
|
30
|
+
self.box.appendleft(o)
|
|
31
|
+
|
|
32
|
+
def set_column_names(self, column_names: list[str]):
|
|
33
|
+
column_names = remove_duplicates(column_names)
|
|
34
|
+
if column_names != self.column_names:
|
|
35
|
+
self.clear()
|
|
36
|
+
self.column_names = column_names
|
|
37
|
+
|
|
38
|
+
def get_data(self, step: int, xname: str,
|
|
39
|
+
yname: str) -> tuple[list[Number], list[Number]]:
|
|
40
|
+
try:
|
|
41
|
+
b = self.box[step]
|
|
42
|
+
except IndexError:
|
|
43
|
+
return [], []
|
|
44
|
+
return b[xname], b[yname]
|
|
45
|
+
|
|
46
|
+
def append(self, dataframe: list[Number] | list[list[Number]]):
|
|
47
|
+
if not dataframe:
|
|
48
|
+
return
|
|
49
|
+
try:
|
|
50
|
+
iter(dataframe[0]) # test if dataframe is a list of list
|
|
51
|
+
self._append_traces(dataframe)
|
|
52
|
+
except TypeError:
|
|
53
|
+
self._append_points(dataframe)
|
|
54
|
+
|
|
55
|
+
def roll(self):
|
|
56
|
+
self.box.appendleft(defaultdict(list))
|
|
57
|
+
|
|
58
|
+
def _append_points(self, points: list[Number]):
|
|
59
|
+
self.dirty = True
|
|
60
|
+
assert (len(points) == len(
|
|
61
|
+
self.column_names)), (f"-PointDataBox\n"
|
|
62
|
+
f"-ap\n"
|
|
63
|
+
f"-Length Must be same\n"
|
|
64
|
+
f"the column_names : {self.column_names}\n"
|
|
65
|
+
f"given data : {points}")
|
|
66
|
+
for name, p in zip(self.column_names, points):
|
|
67
|
+
self.box[0][name].append(p)
|
|
68
|
+
|
|
69
|
+
def _append_traces(self, traces: list[list[Number]]):
|
|
70
|
+
self.dirty = True
|
|
71
|
+
assert (len(traces) == len(
|
|
72
|
+
self.column_names)), (f"-TraceDataBox\n"
|
|
73
|
+
f"-at\n"
|
|
74
|
+
f"-Length Must be same\n"
|
|
75
|
+
f"the column_names : {self.column_names}\n"
|
|
76
|
+
f"given data : {traces}")
|
|
77
|
+
self.box.appendleft(dict(zip(self.column_names, traces)))
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
from multiprocessing import Queue
|
|
3
|
+
|
|
4
|
+
from .dataset import Dataset
|
|
5
|
+
from .toolbar import ToolBar
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class EventQueue():
|
|
9
|
+
|
|
10
|
+
def __init__(self, queue: Queue, toolbar: ToolBar, point_dataset: Dataset,
|
|
11
|
+
trace_dataset: Dataset):
|
|
12
|
+
self.toolbar = toolbar
|
|
13
|
+
self.queue = queue
|
|
14
|
+
self.point_dataset = point_dataset
|
|
15
|
+
self.trace_dataset = trace_dataset
|
|
16
|
+
|
|
17
|
+
def flush(self):
|
|
18
|
+
while (not self.queue.empty()):
|
|
19
|
+
words = self.queue.get()
|
|
20
|
+
try:
|
|
21
|
+
assert (isinstance(
|
|
22
|
+
words, tuple)), "QueueHandler - fifo Content must be tuple"
|
|
23
|
+
assert (
|
|
24
|
+
len(words) == 2
|
|
25
|
+
), "QueueHandler -the tuple must be like (\"command_type\" , \"DATA\")"
|
|
26
|
+
cmd, data = words
|
|
27
|
+
assert (isinstance(
|
|
28
|
+
cmd, str)), "QueueHandler - the command should be a string"
|
|
29
|
+
except AssertionError as e:
|
|
30
|
+
warnings.warn(e.args[0])
|
|
31
|
+
continue
|
|
32
|
+
|
|
33
|
+
self.handle(cmd, data)
|
|
34
|
+
|
|
35
|
+
def handle(self, cmd, data):
|
|
36
|
+
match cmd:
|
|
37
|
+
case "PN":
|
|
38
|
+
self.point_dataset.set_column_names(data)
|
|
39
|
+
self.toolbar.refresh_comb()
|
|
40
|
+
case "TN":
|
|
41
|
+
self.trace_dataset.set_column_names(data)
|
|
42
|
+
self.toolbar.refresh_comb()
|
|
43
|
+
case "PD":
|
|
44
|
+
self.point_dataset.append(data)
|
|
45
|
+
case "TD":
|
|
46
|
+
self.trace_dataset.append(data)
|
|
47
|
+
case "ROLL":
|
|
48
|
+
self.point_dataset.roll()
|
|
49
|
+
case "PXY":
|
|
50
|
+
self.toolbar.set_point_text(data)
|
|
51
|
+
case "TXY":
|
|
52
|
+
self.toolbar.set_trace_text(data)
|
|
53
|
+
case _:
|
|
54
|
+
warnings.warn(f"QueueHandler - unknown command : {cmd}")
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
from multiprocessing import Queue
|
|
2
|
+
from typing import Literal
|
|
3
|
+
|
|
4
|
+
from .config import forms, ridx, style
|
|
5
|
+
from .dataset import Dataset
|
|
6
|
+
from .event_queue import EventQueue
|
|
7
|
+
from .ploter import PlotWidget
|
|
8
|
+
from .qt_compat import (BottomDockWidgetArea, QtCore, QtWidgets,
|
|
9
|
+
ScrollBarAlwaysOff, ScrollBarAlwaysOn,
|
|
10
|
+
TopDockWidgetArea)
|
|
11
|
+
from .toolbar import ToolBar
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MainWindow(QtWidgets.QMainWindow):
|
|
15
|
+
|
|
16
|
+
def __init__(self,
|
|
17
|
+
queue: Queue,
|
|
18
|
+
ncols=3,
|
|
19
|
+
plot_minimum_height=350,
|
|
20
|
+
plot_colors: list[tuple[int, int, int]] | None = None):
|
|
21
|
+
super().__init__()
|
|
22
|
+
self.ncols = ncols
|
|
23
|
+
self.need_reshuffled = False
|
|
24
|
+
self.plot_minimum_height = plot_minimum_height
|
|
25
|
+
self.plot_widgets: list[PlotWidget] = []
|
|
26
|
+
self.plot_colors = plot_colors
|
|
27
|
+
self.toolbar = ToolBar()
|
|
28
|
+
self.trace_data_box = Dataset()
|
|
29
|
+
self.point_data_box = Dataset()
|
|
30
|
+
self.queue = EventQueue(queue, self.toolbar, self.point_data_box,
|
|
31
|
+
self.trace_data_box)
|
|
32
|
+
|
|
33
|
+
self.init_ui()
|
|
34
|
+
|
|
35
|
+
self.timer = QtCore.QTimer()
|
|
36
|
+
self.timer.timeout.connect(self.update)
|
|
37
|
+
self.timer.start(250)
|
|
38
|
+
|
|
39
|
+
def init_ui(self):
|
|
40
|
+
self.setStyleSheet(style)
|
|
41
|
+
self.setMinimumHeight(500)
|
|
42
|
+
self.setMinimumWidth(700)
|
|
43
|
+
self.scroll = QtWidgets.QScrollArea(
|
|
44
|
+
) # Scroll Area which contains the widgets, set as the centralWidget
|
|
45
|
+
self.widget = QtWidgets.QWidget(
|
|
46
|
+
) # Widget that contains the collection of Vertical Box
|
|
47
|
+
self.layout = QtWidgets.QGridLayout()
|
|
48
|
+
self.widget.setLayout(self.layout)
|
|
49
|
+
|
|
50
|
+
#Scroll Area Properties
|
|
51
|
+
#self.setCorner(Qt.TopSection, Qt.TopDockWidgetArea);
|
|
52
|
+
self.scroll.setVerticalScrollBarPolicy(ScrollBarAlwaysOn)
|
|
53
|
+
self.scroll.setHorizontalScrollBarPolicy(ScrollBarAlwaysOff)
|
|
54
|
+
self.scroll.setWidgetResizable(True)
|
|
55
|
+
self.scroll.setWidget(self.widget)
|
|
56
|
+
self.setCentralWidget(self.scroll)
|
|
57
|
+
|
|
58
|
+
self.dock = QtWidgets.QDockWidget(self)
|
|
59
|
+
self.dock.setAllowedAreas(TopDockWidgetArea | BottomDockWidgetArea)
|
|
60
|
+
self.addDockWidget(TopDockWidgetArea, self.dock)
|
|
61
|
+
self.dock.setFloating(False)
|
|
62
|
+
self.dock.setWidget(self.toolbar)
|
|
63
|
+
self.dock.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable)
|
|
64
|
+
#self.tabifyDockWidget(self.dock,None);
|
|
65
|
+
#self.addDockWidget(self.dock);
|
|
66
|
+
#self.setStatusBar(self.toolbar);
|
|
67
|
+
#self.layout.addWidget(self.toolbar , 0 , 0 , 1, self.ncol);
|
|
68
|
+
|
|
69
|
+
self.setWindowTitle('Scroll multi view')
|
|
70
|
+
self.show()
|
|
71
|
+
self.toolbar.set_mainwindow(self)
|
|
72
|
+
self.toolbar.pb.setChecked(True)
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def mode(self) -> Literal["P", "T"]:
|
|
76
|
+
return self.toolbar.mode
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def dataset(self) -> Dataset:
|
|
80
|
+
return {"P": self.point_data_box, "T": self.trace_data_box}[self.mode]
|
|
81
|
+
|
|
82
|
+
def set_ncols(self, x: int):
|
|
83
|
+
x = max(1, min(10, int(x)))
|
|
84
|
+
if (x != self.ncols):
|
|
85
|
+
self.need_reshuffled = True
|
|
86
|
+
self.ncols = x
|
|
87
|
+
|
|
88
|
+
def add_subplot(self):
|
|
89
|
+
n = len(self.plot_widgets)
|
|
90
|
+
pw = PlotWidget(self.plot_minimum_height, self.plot_colors)
|
|
91
|
+
self.plot_widgets.append(pw)
|
|
92
|
+
grid_row = n // self.ncols
|
|
93
|
+
grid_col = n % self.ncols
|
|
94
|
+
self.layout.addWidget(pw, grid_row + 1, grid_col)
|
|
95
|
+
return pw
|
|
96
|
+
|
|
97
|
+
def create_subplots(self, xy_pairs):
|
|
98
|
+
for xn, yn in xy_pairs:
|
|
99
|
+
pw = self.add_subplot()
|
|
100
|
+
pw.set_X_label(xn)
|
|
101
|
+
pw.set_Y_label(yn)
|
|
102
|
+
self.do_link()
|
|
103
|
+
self.all_enable_auto_range()
|
|
104
|
+
|
|
105
|
+
def clear_subplots(self):
|
|
106
|
+
for i in range(len(self.plot_widgets)):
|
|
107
|
+
self.layout.removeWidget(self.plot_widgets[i])
|
|
108
|
+
self.plot_widgets[i].setParent(None)
|
|
109
|
+
self.plot_widgets.clear()
|
|
110
|
+
|
|
111
|
+
def remove_plot(self, w: PlotWidget):
|
|
112
|
+
w.setParent(None)
|
|
113
|
+
self.plot_widgets.remove(w)
|
|
114
|
+
self.reshuffle()
|
|
115
|
+
|
|
116
|
+
def drop_last_plot(self, i_=-1):
|
|
117
|
+
# delete the one
|
|
118
|
+
i = int(i_)
|
|
119
|
+
if (i < len(self.plot_widgets)):
|
|
120
|
+
w = self.plot_widgets[i]
|
|
121
|
+
w.setParent(None)
|
|
122
|
+
del w
|
|
123
|
+
del self.plot_widgets[i]
|
|
124
|
+
self.reshuffle()
|
|
125
|
+
|
|
126
|
+
def reshuffle(self):
|
|
127
|
+
for idx, widget in enumerate(self.plot_widgets):
|
|
128
|
+
widget.setParent(None)
|
|
129
|
+
grid_row = idx // self.ncols
|
|
130
|
+
grid_col = idx % self.ncols
|
|
131
|
+
self.layout.addWidget(widget, grid_row + 1, grid_col)
|
|
132
|
+
|
|
133
|
+
def keyPressEvent(self, ev):
|
|
134
|
+
#print(ev.text());
|
|
135
|
+
tx = ev.text()
|
|
136
|
+
if (tx in ['_', '-']):
|
|
137
|
+
self.set_ncols(self.ncols - 1)
|
|
138
|
+
elif (tx in ['=', '+']):
|
|
139
|
+
self.set_ncols(self.ncols + 1)
|
|
140
|
+
|
|
141
|
+
def mouse_click(self):
|
|
142
|
+
pass
|
|
143
|
+
|
|
144
|
+
def do_link(self):
|
|
145
|
+
"""
|
|
146
|
+
link the plot
|
|
147
|
+
|
|
148
|
+
share the same x or y axis
|
|
149
|
+
"""
|
|
150
|
+
same_X = {}
|
|
151
|
+
xy_pairs = self.toolbar.xypairs
|
|
152
|
+
for idx, xyn in enumerate(xy_pairs):
|
|
153
|
+
xn, yn = xyn
|
|
154
|
+
if xn not in same_X:
|
|
155
|
+
same_X[xn] = []
|
|
156
|
+
same_X[xn].append(idx)
|
|
157
|
+
|
|
158
|
+
sharex, sharey = self.toolbar.sharexy()
|
|
159
|
+
|
|
160
|
+
s_A = not (sharex and sharey)
|
|
161
|
+
for x, yidxs in same_X.items():
|
|
162
|
+
pre_yidx = -1
|
|
163
|
+
for yidx in yidxs:
|
|
164
|
+
if (-1 != pre_yidx):
|
|
165
|
+
if (s_A):
|
|
166
|
+
self.plot_widgets[pre_yidx].plotItem.vb.setXLink(None)
|
|
167
|
+
self.plot_widgets[pre_yidx].plotItem.vb.setYLink(None)
|
|
168
|
+
|
|
169
|
+
if sharex:
|
|
170
|
+
self.plot_widgets[pre_yidx].plotItem.vb.setXLink(
|
|
171
|
+
self.plot_widgets[yidx].plotItem.vb)
|
|
172
|
+
|
|
173
|
+
if sharey:
|
|
174
|
+
self.plot_widgets[pre_yidx].plotItem.vb.setYLink(
|
|
175
|
+
self.plot_widgets[yidx].plotItem.vb)
|
|
176
|
+
pre_yidx = yidx
|
|
177
|
+
|
|
178
|
+
def all_auto_range(self):
|
|
179
|
+
for pw in self.plot_widgets:
|
|
180
|
+
pw.auto_range()
|
|
181
|
+
|
|
182
|
+
def all_enable_auto_range(self):
|
|
183
|
+
for pw in self.plot_widgets:
|
|
184
|
+
pw.enable_auto_range()
|
|
185
|
+
|
|
186
|
+
def update(self):
|
|
187
|
+
# update the queue
|
|
188
|
+
self.queue.flush()
|
|
189
|
+
|
|
190
|
+
rescale = False
|
|
191
|
+
|
|
192
|
+
# setup the xyfm
|
|
193
|
+
if (self.toolbar.xypairs_dirty):
|
|
194
|
+
self.clear_subplots()
|
|
195
|
+
self.create_subplots(self.toolbar.xypairs)
|
|
196
|
+
self.toolbar.xypairs_dirty = False
|
|
197
|
+
rescale = True
|
|
198
|
+
|
|
199
|
+
if (self.toolbar.link_dirty):
|
|
200
|
+
self.do_link()
|
|
201
|
+
self.toolbar.link_dirty = False
|
|
202
|
+
|
|
203
|
+
if (self.need_reshuffled):
|
|
204
|
+
self.need_reshuffled = False
|
|
205
|
+
self.reshuffle()
|
|
206
|
+
|
|
207
|
+
# checking the log space
|
|
208
|
+
if (self.toolbar.xyfm_dirty):
|
|
209
|
+
for pw in self.plot_widgets:
|
|
210
|
+
pw.plotItem.ctrl.logXCheck.setChecked(self.toolbar.lx)
|
|
211
|
+
pw.plotItem.ctrl.logYCheck.setChecked(self.toolbar.ly)
|
|
212
|
+
|
|
213
|
+
#update the plot
|
|
214
|
+
# if clear is set then do the clear :
|
|
215
|
+
if (self.toolbar.CR_flag):
|
|
216
|
+
self.toolbar.CR_flag = False
|
|
217
|
+
self.dataset.clear_history()
|
|
218
|
+
self.dataset.dirty = True
|
|
219
|
+
|
|
220
|
+
if (self.dataset.dirty or self.toolbar.xyfm_dirty or rescale):
|
|
221
|
+
self.dataset.dirty = False
|
|
222
|
+
self.xyfm_dirty = False
|
|
223
|
+
for pw in self.plot_widgets:
|
|
224
|
+
|
|
225
|
+
fx = forms[self.toolbar.fx]
|
|
226
|
+
fy = forms[self.toolbar.fy]
|
|
227
|
+
for i in ridx:
|
|
228
|
+
x, y = self.dataset.get_data(i, pw.xname, pw.yname)
|
|
229
|
+
l = min(len(x), len(y))
|
|
230
|
+
x, y = fx(x[:l], 0), fy(y[:l], 0)
|
|
231
|
+
pw.set_data(i, x, y)
|
|
232
|
+
pw.update()
|
|
233
|
+
if rescale:
|
|
234
|
+
pw.auto_range()
|