pymodaq_utils 5.3.0a0__tar.gz → 5.3.2__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.
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/PKG-INFO +12 -12
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/README.rst +11 -11
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/factory.py +6 -4
- pymodaq_utils-5.3.2/src/pymodaq_utils/help.py +47 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/math_utils.py +81 -46
- pymodaq_utils-5.3.2/src/pymodaq_utils/plugin_checks.py +635 -0
- pymodaq_utils-5.3.2/src/pymodaq_utils/plugin_rules.py +595 -0
- pymodaq_utils-5.3.2/src/pymodaq_utils/plugin_scaffold.py +361 -0
- pymodaq_utils-5.3.2/src/pymodaq_utils/plugin_testing.py +22 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/serialize/serializer_legacy.py +3 -4
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/utils.py +1 -1
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/.gitignore +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/LICENSE +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/pyproject.toml +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/__init__.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/abstract.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/array_manipulation.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/categorizing.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/config.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/enums.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/environment.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/icon.ico +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/logger.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/mysocket.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/packages.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/resources/__init__.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/resources/config_template.toml +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/resources/hatch_build_plugins.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/serialize/__init__.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/serialize/factory.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/serialize/mysocket.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/serialize/serializer.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/serialize/utils.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/singleton.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/splash.png +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/units.py +0 -0
- {pymodaq_utils-5.3.0a0 → pymodaq_utils-5.3.2}/src/pymodaq_utils/warnings.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pymodaq_utils
|
|
3
|
-
Version: 5.3.
|
|
3
|
+
Version: 5.3.2
|
|
4
4
|
Summary: Modular Data Acquisition with Python
|
|
5
5
|
Project-URL: Homepage, http://pymodaq.cnrs.fr
|
|
6
6
|
Project-URL: Source, https://github.com/PyMoDAQ/PyMoDAQ
|
|
@@ -76,11 +76,11 @@ PyMoDAQ Utils
|
|
|
76
76
|
:target: https://pypi.org/project/pymodaq_utils/
|
|
77
77
|
:alt: Latest Version
|
|
78
78
|
|
|
79
|
-
.. image:: https://readthedocs.org/projects/pymodaq/badge/?version=
|
|
80
|
-
:target: https://pymodaq.readthedocs.io/en/stable/?badge=
|
|
79
|
+
.. image:: https://readthedocs.org/projects/pymodaq/badge/?version=patch-3
|
|
80
|
+
:target: https://pymodaq.readthedocs.io/en/stable/?badge=patch-3
|
|
81
81
|
:alt: Documentation Status
|
|
82
82
|
|
|
83
|
-
.. image:: https://codecov.io/gh/PyMoDAQ/PyMoDAQ/branch/
|
|
83
|
+
.. image:: https://codecov.io/gh/PyMoDAQ/PyMoDAQ/branch/patch-3/graph/badge.svg?token=IQNJRCQDM2
|
|
84
84
|
:target: https://codecov.io/gh/PyMoDAQ/PyMoDAQ
|
|
85
85
|
|
|
86
86
|
+-------------+-------------+---------------+
|
|
@@ -99,28 +99,28 @@ PyMoDAQ Utils
|
|
|
99
99
|
|
|
100
100
|
|
|
101
101
|
|
|
102
|
-
.. |310-linux| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/
|
|
102
|
+
.. |310-linux| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/patch-3/tests_Linux_3.10.svg
|
|
103
103
|
:target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/tests-utils.yml
|
|
104
104
|
|
|
105
|
-
.. |311-linux| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/
|
|
105
|
+
.. |311-linux| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/patch-3/tests_Linux_3.11.svg
|
|
106
106
|
:target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/tests-utils.yml
|
|
107
107
|
|
|
108
|
-
.. |312-linux| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/
|
|
108
|
+
.. |312-linux| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/patch-3/tests_Linux_3.12.svg
|
|
109
109
|
:target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/tests-utils.yml
|
|
110
110
|
|
|
111
|
-
.. |313-linux| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/
|
|
111
|
+
.. |313-linux| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/patch-3/tests_Linux_3.13.svg
|
|
112
112
|
:target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/tests-utils.yml
|
|
113
113
|
|
|
114
|
-
.. |310-windows| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/
|
|
114
|
+
.. |310-windows| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/patch-3/tests_Windows_3.10.svg
|
|
115
115
|
:target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/tests-utils.yml
|
|
116
116
|
|
|
117
|
-
.. |311-windows| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/
|
|
117
|
+
.. |311-windows| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/patch-3/tests_Windows_3.11.svg
|
|
118
118
|
:target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/tests-utils.yml
|
|
119
119
|
|
|
120
|
-
.. |312-windows| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/
|
|
120
|
+
.. |312-windows| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/patch-3/tests_Windows_3.12.svg
|
|
121
121
|
:target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/tests-utils.yml
|
|
122
122
|
|
|
123
|
-
.. |313-windows| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/
|
|
123
|
+
.. |313-windows| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/patch-3/tests_Windows_3.13.svg
|
|
124
124
|
:target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/tests-utils.yml
|
|
125
125
|
|
|
126
126
|
|
|
@@ -11,11 +11,11 @@ PyMoDAQ Utils
|
|
|
11
11
|
:target: https://pypi.org/project/pymodaq_utils/
|
|
12
12
|
:alt: Latest Version
|
|
13
13
|
|
|
14
|
-
.. image:: https://readthedocs.org/projects/pymodaq/badge/?version=
|
|
15
|
-
:target: https://pymodaq.readthedocs.io/en/stable/?badge=
|
|
14
|
+
.. image:: https://readthedocs.org/projects/pymodaq/badge/?version=patch-3
|
|
15
|
+
:target: https://pymodaq.readthedocs.io/en/stable/?badge=patch-3
|
|
16
16
|
:alt: Documentation Status
|
|
17
17
|
|
|
18
|
-
.. image:: https://codecov.io/gh/PyMoDAQ/PyMoDAQ/branch/
|
|
18
|
+
.. image:: https://codecov.io/gh/PyMoDAQ/PyMoDAQ/branch/patch-3/graph/badge.svg?token=IQNJRCQDM2
|
|
19
19
|
:target: https://codecov.io/gh/PyMoDAQ/PyMoDAQ
|
|
20
20
|
|
|
21
21
|
+-------------+-------------+---------------+
|
|
@@ -34,28 +34,28 @@ PyMoDAQ Utils
|
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
.. |310-linux| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/
|
|
37
|
+
.. |310-linux| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/patch-3/tests_Linux_3.10.svg
|
|
38
38
|
:target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/tests-utils.yml
|
|
39
39
|
|
|
40
|
-
.. |311-linux| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/
|
|
40
|
+
.. |311-linux| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/patch-3/tests_Linux_3.11.svg
|
|
41
41
|
:target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/tests-utils.yml
|
|
42
42
|
|
|
43
|
-
.. |312-linux| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/
|
|
43
|
+
.. |312-linux| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/patch-3/tests_Linux_3.12.svg
|
|
44
44
|
:target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/tests-utils.yml
|
|
45
45
|
|
|
46
|
-
.. |313-linux| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/
|
|
46
|
+
.. |313-linux| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/patch-3/tests_Linux_3.13.svg
|
|
47
47
|
:target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/tests-utils.yml
|
|
48
48
|
|
|
49
|
-
.. |310-windows| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/
|
|
49
|
+
.. |310-windows| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/patch-3/tests_Windows_3.10.svg
|
|
50
50
|
:target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/tests-utils.yml
|
|
51
51
|
|
|
52
|
-
.. |311-windows| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/
|
|
52
|
+
.. |311-windows| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/patch-3/tests_Windows_3.11.svg
|
|
53
53
|
:target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/tests-utils.yml
|
|
54
54
|
|
|
55
|
-
.. |312-windows| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/
|
|
55
|
+
.. |312-windows| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/patch-3/tests_Windows_3.12.svg
|
|
56
56
|
:target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/tests-utils.yml
|
|
57
57
|
|
|
58
|
-
.. |313-windows| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/
|
|
58
|
+
.. |313-windows| image:: https://raw.githubusercontent.com/PyMoDAQ/PyMoDAQ/badges/pymodaq_utils/patch-3/tests_Windows_3.13.svg
|
|
59
59
|
:target: https://github.com/PyMoDAQ/PyMoDAQ/actions/workflows/tests-utils.yml
|
|
60
60
|
|
|
61
61
|
|
|
@@ -34,13 +34,15 @@ class ObjectFactory(metaclass=ABCMeta):
|
|
|
34
34
|
|
|
35
35
|
Examples
|
|
36
36
|
--------
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
::
|
|
38
|
+
|
|
39
|
+
@ObjectFactory.register('custom')
|
|
40
|
+
def my_custom_builder():
|
|
41
|
+
pass
|
|
40
42
|
|
|
41
43
|
See Also
|
|
42
44
|
--------
|
|
43
|
-
|
|
45
|
+
pymodaq_data.post_treatment.process_to_scalar.DataProcessorFactory
|
|
44
46
|
"""
|
|
45
47
|
_builders = {}
|
|
46
48
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Contextual help of the PyMoDAQ modules.
|
|
2
|
+
|
|
3
|
+
By convention, the help of a module (control module, manager, extension...) is a short markdown text stored in a file
|
|
4
|
+
named ``help.md`` in the same folder as the python file defining the module. The same text is used as the introduction
|
|
5
|
+
of the module documentation.
|
|
6
|
+
"""
|
|
7
|
+
import inspect
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from types import ModuleType
|
|
10
|
+
from typing import Optional, Union
|
|
11
|
+
|
|
12
|
+
from pymodaq_utils.logger import set_logger, get_module_name
|
|
13
|
+
|
|
14
|
+
logger = set_logger(get_module_name(__file__))
|
|
15
|
+
|
|
16
|
+
HELP_FILE_NAME = 'help.md'
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_help_text(obj: Union[type, object, ModuleType, str, Path]) -> Optional[str]:
|
|
20
|
+
"""Get the markdown help text associated with a module, a class or an object
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
obj: type, object, ModuleType, str or Path
|
|
25
|
+
A class, an instance, a python module, or the path of a file (or a folder) from which the help is looked for.
|
|
26
|
+
The help file is ``help.md`` in the folder of the file defining the object.
|
|
27
|
+
|
|
28
|
+
Returns
|
|
29
|
+
-------
|
|
30
|
+
str or None
|
|
31
|
+
The markdown text, None if no help file is found.
|
|
32
|
+
"""
|
|
33
|
+
if isinstance(obj, (str, Path)):
|
|
34
|
+
path = Path(obj)
|
|
35
|
+
else:
|
|
36
|
+
if not isinstance(obj, (type, ModuleType)):
|
|
37
|
+
obj = type(obj)
|
|
38
|
+
try:
|
|
39
|
+
path = Path(inspect.getfile(obj))
|
|
40
|
+
except (TypeError, OSError):
|
|
41
|
+
logger.warning(f'Could not find the source file of {obj}')
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
help_path = (path if path.is_dir() else path.parent) / HELP_FILE_NAME
|
|
45
|
+
if not help_path.is_file():
|
|
46
|
+
return None
|
|
47
|
+
return help_path.read_text(encoding='utf-8')
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import numbers
|
|
2
2
|
from typing import Union
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
import numpy as np
|
|
6
6
|
from numbers import Number
|
|
7
7
|
from typing import List, Union, Tuple
|
|
@@ -12,6 +12,31 @@ from pint import Quantity
|
|
|
12
12
|
logger = set_logger(get_module_name(__file__))
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
|
|
16
|
+
def get_si_prefix(number) -> tuple[Number, str]:
|
|
17
|
+
if number == 0:
|
|
18
|
+
return 0, ""
|
|
19
|
+
|
|
20
|
+
# Standard SI prefixes organized by their 10^(3*tier) powers
|
|
21
|
+
prefixes = {
|
|
22
|
+
24: 'Y', 21: 'Z', 18: 'E', 15: 'P', 12: 'T', 9: 'G', 6: 'M', 3: 'k',
|
|
23
|
+
0: '',
|
|
24
|
+
-3: 'm', -6: 'µ', -9: 'n', -12: 'p', -15: 'f', -18: 'a', -21: 'z', -24: 'y'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# Calculate the exponent tier (multiples of 3)
|
|
28
|
+
exponent = np.floor(np.log10(abs(number)) / 3) * 3
|
|
29
|
+
|
|
30
|
+
# Clip to maximum/minimum available prefixes
|
|
31
|
+
exponent = max(-24, min(24, exponent))
|
|
32
|
+
|
|
33
|
+
# Calculate the scaled number component
|
|
34
|
+
scaled_value = number / (10 ** exponent)
|
|
35
|
+
prefix_symbol = prefixes[exponent]
|
|
36
|
+
|
|
37
|
+
return scaled_value, prefix_symbol
|
|
38
|
+
|
|
39
|
+
|
|
15
40
|
def my_moment(x, y):
|
|
16
41
|
"""Returns the moments of a distribution y over an axe x
|
|
17
42
|
|
|
@@ -462,28 +487,29 @@ def flatten(xs):
|
|
|
462
487
|
class LSqEllipse:
|
|
463
488
|
|
|
464
489
|
def fit(self, data):
|
|
465
|
-
"""
|
|
490
|
+
"""Least Squares fitting algorithm
|
|
466
491
|
|
|
467
492
|
Theory taken from (*)
|
|
468
|
-
Solving equation Sa=lCa
|
|
469
|
-
a2 = |d f g>
|
|
493
|
+
Solving equation ``Sa=lCa``, with ``a = |a b c d f g>``, ``a1 = |a b c>`` and ``a2 = |d f g>``
|
|
470
494
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
data
|
|
474
|
-
|
|
495
|
+
Parameters
|
|
496
|
+
----------
|
|
497
|
+
data: list of list of float
|
|
498
|
+
list of two lists containing the x and y data of the ellipse, of the form
|
|
499
|
+
``[[x1, x2, ..., xi],[y1, y2, ..., yi]]``
|
|
475
500
|
|
|
476
501
|
Returns
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
502
|
+
-------
|
|
503
|
+
list
|
|
504
|
+
the coefficients ``[a,b,c,d,f,g]`` describing an ellipse corresponding to
|
|
505
|
+
``ax**2+2bxy+cy**2+2dx+2fy+g``
|
|
480
506
|
"""
|
|
481
|
-
x, y =
|
|
507
|
+
x, y = np.asarray(data, dtype=float)
|
|
482
508
|
|
|
483
509
|
# Quadratic part of design matrix [eqn. 15] from (*)
|
|
484
|
-
D1 =
|
|
510
|
+
D1 = np.mat(np.vstack([x ** 2, x * y, y ** 2])).T
|
|
485
511
|
# Linear part of design matrix [eqn. 16] from (*)
|
|
486
|
-
D2 =
|
|
512
|
+
D2 = np.mat(np.vstack([x, y, np.ones(len(x))])).T
|
|
487
513
|
|
|
488
514
|
# forming scatter matrix [eqn. 17] from (*)
|
|
489
515
|
S1 = D1.T * D1
|
|
@@ -491,23 +517,23 @@ class LSqEllipse:
|
|
|
491
517
|
S3 = D2.T * D2
|
|
492
518
|
|
|
493
519
|
# Constraint matrix [eqn. 18]
|
|
494
|
-
C1 =
|
|
520
|
+
C1 = np.mat('0. 0. 2.; 0. -1. 0.; 2. 0. 0.')
|
|
495
521
|
|
|
496
522
|
# Reduced scatter matrix [eqn. 29]
|
|
497
523
|
M = C1.I * (S1 - S2 * S3.I * S2.T)
|
|
498
524
|
|
|
499
525
|
# M*|a b c >=l|a b c >. Find eigenvalues and eigenvectors from this equation [eqn. 28]
|
|
500
|
-
eval, evec =
|
|
526
|
+
eval, evec = np.linalg.eig(M)
|
|
501
527
|
|
|
502
528
|
# eigenvector must meet constraint 4ac - b^2 to be valid.
|
|
503
|
-
cond = 4 *
|
|
504
|
-
a1 = evec[:,
|
|
529
|
+
cond = 4 * np.multiply(evec[0, :], evec[2, :]) - np.power(evec[1, :], 2)
|
|
530
|
+
a1 = evec[:, np.nonzero(cond.A > 0)[1]]
|
|
505
531
|
|
|
506
532
|
# |d f g> = -S3^(-1)*S2^(T)*|a b c> [eqn. 24]
|
|
507
533
|
a2 = -S3.I * S2.T * a1
|
|
508
534
|
|
|
509
535
|
# eigenvectors |a b c d f g>
|
|
510
|
-
self.coef =
|
|
536
|
+
self.coef = np.vstack([a1, a2])
|
|
511
537
|
self._save_parameters()
|
|
512
538
|
|
|
513
539
|
def _save_parameters(self):
|
|
@@ -515,17 +541,22 @@ class LSqEllipse:
|
|
|
515
541
|
|
|
516
542
|
Theory taken form http://mathworld.wolfram
|
|
517
543
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
coef
|
|
521
|
-
|
|
544
|
+
Parameters
|
|
545
|
+
----------
|
|
546
|
+
coef: list
|
|
547
|
+
list of the coefficients describing an ellipse ``[a,b,c,d,f,g]`` corresponding to
|
|
548
|
+
``ax**2+2bxy+cy**2+2dx+2fy+g``
|
|
522
549
|
|
|
523
550
|
Returns
|
|
524
|
-
|
|
525
|
-
center
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
551
|
+
-------
|
|
552
|
+
center: list
|
|
553
|
+
of the form [x0, y0]
|
|
554
|
+
width: float
|
|
555
|
+
major axis
|
|
556
|
+
height: float
|
|
557
|
+
minor axis
|
|
558
|
+
phi: float
|
|
559
|
+
rotation of major axis form the x-axis in radians
|
|
529
560
|
"""
|
|
530
561
|
|
|
531
562
|
# eigenvectors are the coefficients of an ellipse in general form
|
|
@@ -543,14 +574,14 @@ class LSqEllipse:
|
|
|
543
574
|
|
|
544
575
|
# Find the semi-axes lengths [eqn. 21 and 22] from (**)
|
|
545
576
|
numerator = 2 * (a * f * f + c * d * d + g * b * b - 2 * b * d * f - a * c * g)
|
|
546
|
-
denominator1 = (b * b - a * c) * ((c - a) *
|
|
547
|
-
denominator2 = (b * b - a * c) * ((a - c) *
|
|
548
|
-
width =
|
|
549
|
-
height =
|
|
577
|
+
denominator1 = (b * b - a * c) * ((c - a) * np.sqrt(1 + 4 * b * b / ((a - c) * (a - c))) - (c + a))
|
|
578
|
+
denominator2 = (b * b - a * c) * ((a - c) * np.sqrt(1 + 4 * b * b / ((a - c) * (a - c))) - (c + a))
|
|
579
|
+
width = np.sqrt(numerator / denominator1)
|
|
580
|
+
height = np.sqrt(numerator / denominator2)
|
|
550
581
|
|
|
551
582
|
# angle of counterclockwise rotation of major-axis of ellipse to x-axis [eqn. 23] from (**)
|
|
552
583
|
# or [eqn. 26] from (***).
|
|
553
|
-
phi = .5 *
|
|
584
|
+
phi = .5 * np.arctan((2. * b) / (a - c))
|
|
554
585
|
|
|
555
586
|
self._center = [x0, y0]
|
|
556
587
|
self._width = width
|
|
@@ -583,25 +614,29 @@ class LSqEllipse:
|
|
|
583
614
|
def make_test_ellipse(center=[1, 1], width=1, height=.6, phi=3.14 / 5):
|
|
584
615
|
"""Generate Elliptical data with noise
|
|
585
616
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
center
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
617
|
+
Parameters
|
|
618
|
+
----------
|
|
619
|
+
center: list of float
|
|
620
|
+
(<x_location>, <y_location>)
|
|
621
|
+
width: float
|
|
622
|
+
semimajor axis. Horizontal dimension of the ellipse
|
|
623
|
+
height: float
|
|
624
|
+
semiminor axis. Vertical dimension of the ellipse
|
|
625
|
+
phi: float
|
|
626
|
+
tilt of the ellipse in radians, the angle the semimajor axis makes with the x-axis
|
|
593
627
|
|
|
594
628
|
Returns
|
|
595
629
|
-------
|
|
596
|
-
|
|
597
|
-
|
|
630
|
+
list of list of float
|
|
631
|
+
list of two lists containing the x and y data of the ellipse, of the form
|
|
632
|
+
``[[x1, x2, ..., xi],[y1, y2, ..., yi]]``
|
|
598
633
|
"""
|
|
599
|
-
t =
|
|
600
|
-
x_noise, y_noise =
|
|
634
|
+
t = np.linspace(0, 2 * np.pi, 1000)
|
|
635
|
+
x_noise, y_noise = np.random.rand(2, len(t))
|
|
601
636
|
|
|
602
|
-
ellipse_x = center[0] + width *
|
|
637
|
+
ellipse_x = center[0] + width * np.cos(t) * np.cos(phi) - height * np.sin(t) * np.sin(
|
|
603
638
|
phi) + x_noise / 2.
|
|
604
|
-
ellipse_y = center[1] + width *
|
|
639
|
+
ellipse_y = center[1] + width * np.cos(t) * np.sin(phi) + height * np.sin(t) * np.cos(
|
|
605
640
|
phi) + y_noise / 2.
|
|
606
641
|
|
|
607
642
|
return [ellipse_x, ellipse_y]
|