From a73847df9e17daf1bdf59281c722658ba15b8161 Mon Sep 17 00:00:00 2001 From: Eric Prestat Date: Sat, 13 Apr 2024 09:08:27 +0100 Subject: [PATCH 1/5] Use pint default global registry --- hyperspy/api.py | 4 ++-- hyperspy/tests/test_import.py | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/hyperspy/api.py b/hyperspy/api.py index 778edfd3c2..4ca9923b8d 100644 --- a/hyperspy/api.py +++ b/hyperspy/api.py @@ -149,9 +149,9 @@ def __getattr__(name): # Special case _ureg to use it as a singleton elif name == "_ureg": if "_ureg" not in globals(): - from pint import UnitRegistry + import pint - setattr(sys.modules[__name__], "_ureg", UnitRegistry()) + setattr(sys.modules[__name__], "_ureg", pint.get_application_registry()) return getattr(sys.modules[__name__], "_ureg") raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/hyperspy/tests/test_import.py b/hyperspy/tests/test_import.py index 30e5bbc9fc..cfc9f4245d 100644 --- a/hyperspy/tests/test_import.py +++ b/hyperspy/tests/test_import.py @@ -247,3 +247,15 @@ def test_dir_utils_samfire4(): "LocalStrategy", "ReducedChiSquaredStrategy", ] + + +def test_pint_default_unit_registry(): + import pint + + import hyperspy.api as hs + + # the pint unit registry used by hyperspy must be the + # same as pint default for interoperability reason + # See https://github.com/hgrecco/pint/issues/108 + # and https://github.com/hgrecco/pint/issues/623 + assert id(hs._ureg) == id(pint.get_application_registry()) From 7da27393ccda8b2c0c9c667dcd3fe5fadaa05fe2 Mon Sep 17 00:00:00 2001 From: Eric Prestat Date: Sat, 13 Apr 2024 10:15:56 +0100 Subject: [PATCH 2/5] Add documentation on operating with pint quantity --- doc/conf.py | 1 + doc/user_guide/index.rst | 1 + doc/user_guide/pint_unit_registry.rst | 32 +++++++++++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 doc/user_guide/pint_unit_registry.rst diff --git a/doc/conf.py b/doc/conf.py index 762c00c846..9c560f8a0b 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -329,6 +329,7 @@ "mdp": ("https://mdp-toolkit.github.io/", None), "matplotlib": ("https://matplotlib.org/stable", None), "numpy": ("https://numpy.org/doc/stable", None), + "pint": ("https://pint.readthedocs.io/en/stable", None), "python": ("https://docs.python.org/3", None), "rsciio": ("https://hyperspy.org/rosettasciio/", None), "scipy": ("https://docs.scipy.org/doc/scipy", None), diff --git a/doc/user_guide/index.rst b/doc/user_guide/index.rst index a203cc26da..f46139f630 100644 --- a/doc/user_guide/index.rst +++ b/doc/user_guide/index.rst @@ -32,6 +32,7 @@ User guide region_of_interest.rst events.rst interactive_operations.rst + pint_unit_registry.rst .. toctree:: :caption: Bibliography diff --git a/doc/user_guide/pint_unit_registry.rst b/doc/user_guide/pint_unit_registry.rst new file mode 100644 index 0000000000..36d8bfede0 --- /dev/null +++ b/doc/user_guide/pint_unit_registry.rst @@ -0,0 +1,32 @@ +.. _pint_unit_registry: + +Operation with Pint Quantity +**************************** + +HyperSpy uses the `pint `_ library to handle unit conversion. +To be interoperatable with other modules, hyperspy uses the default pint :class:`pint.UnitRegistry` +provided by the :func:`pint.get_application_registry` function as described in the sections +`having a shared registry `_ +and the `serialization `_ +of the pint user guide. + +For example, to use pint quantity object from :class:`~.axes.UniformDataAxis`, the same +unit registry needs to be used: + +.. code-block:: python + + >>> s = hs.signals.Signal1D(np.arange(10)) + >>> s.axes_manager[0].scale_as_quantity + + >>> s.axes_manager[0].scale_as_quantity = '2.5 µm' + >>> s.axes_manager[0].scale_as_quantity + + +Use :func:`pint.get_application_registry` to get pint default unit registry: + + >>> import pint + >>> ureg = pint.get_application_registry() + >>> scale = 2E-6 * ureg.meter + >>> s.axes_manager[0].scale_as_quantity += scale + >>> s.axes_manager[0].scale_as_quantity + From b934f33253822b46a2ed9eb70f1a436d5ee9c33d Mon Sep 17 00:00:00 2001 From: Eric Prestat Date: Sat, 13 Apr 2024 10:44:49 +0100 Subject: [PATCH 3/5] Add changelog entry --- upcoming_changes/3357.enhancements.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 upcoming_changes/3357.enhancements.rst diff --git a/upcoming_changes/3357.enhancements.rst b/upcoming_changes/3357.enhancements.rst new file mode 100644 index 0000000000..c06aae2a34 --- /dev/null +++ b/upcoming_changes/3357.enhancements.rst @@ -0,0 +1 @@ +Use :func:`pint.get_application_registry` to get :class:`pint.UnitRegistry` and facilitate interoperability of pint quantity operation with other modules . \ No newline at end of file From 33bb083d821d4046af555ac2423ac1e35bfbcef9 Mon Sep 17 00:00:00 2001 From: Eric Prestat Date: Mon, 15 Apr 2024 09:46:59 +0100 Subject: [PATCH 4/5] Improve user guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jonas Lähnemann --- doc/user_guide/pint_unit_registry.rst | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/doc/user_guide/pint_unit_registry.rst b/doc/user_guide/pint_unit_registry.rst index 36d8bfede0..4cb8d537cb 100644 --- a/doc/user_guide/pint_unit_registry.rst +++ b/doc/user_guide/pint_unit_registry.rst @@ -1,17 +1,17 @@ .. _pint_unit_registry: -Operation with Pint Quantity -**************************** +Unit Handling with Pint Quantity +******************************** HyperSpy uses the `pint `_ library to handle unit conversion. -To be interoperatable with other modules, hyperspy uses the default pint :class:`pint.UnitRegistry` +To be interoperatable with other modules, HyperSpy uses the default pint :class:`pint.UnitRegistry` provided by the :func:`pint.get_application_registry` function as described in the sections `having a shared registry `_ -and the `serialization `_ +and `serialization `_ of the pint user guide. -For example, to use pint quantity object from :class:`~.axes.UniformDataAxis`, the same -unit registry needs to be used: +For example, in the case of the ``scale_as_quantify`` pint quantity object from :class:`~.axes.UniformDataAxis`, +the default pint :class:`pint.UnitRegistry` is used: .. code-block:: python @@ -22,7 +22,8 @@ unit registry needs to be used: >>> s.axes_manager[0].scale_as_quantity -Use :func:`pint.get_application_registry` to get pint default unit registry: +Then, using :func:`pint.get_application_registry` get the handle of the same instance of :class:`pint.UnitRegistry` +used by HyperSpy and used it to operate on this pint quantity: >>> import pint >>> ureg = pint.get_application_registry() From 5f61ce939a60e22de3e16cce868b72db57b53444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20L=C3=A4hnemann?= Date: Mon, 15 Apr 2024 21:58:52 +0200 Subject: [PATCH 5/5] Update doc/user_guide/pint_unit_registry.rst --- doc/user_guide/pint_unit_registry.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user_guide/pint_unit_registry.rst b/doc/user_guide/pint_unit_registry.rst index 4cb8d537cb..c078902c27 100644 --- a/doc/user_guide/pint_unit_registry.rst +++ b/doc/user_guide/pint_unit_registry.rst @@ -23,7 +23,7 @@ the default pint :class:`pint.UnitRegistry` is used: Then, using :func:`pint.get_application_registry` get the handle of the same instance of :class:`pint.UnitRegistry` -used by HyperSpy and used it to operate on this pint quantity: +used by HyperSpy and use it to operate on this pint quantity: >>> import pint >>> ureg = pint.get_application_registry()