Skip to content

Commit

Permalink
Merge pull request #1058 from CodeMonkeyJan/master
Browse files Browse the repository at this point in the history
Added support for complex data
  • Loading branch information
francisco-dlp committed Jul 11, 2016
2 parents e0fdf66 + 5d4b721 commit 3c78998
Show file tree
Hide file tree
Showing 29 changed files with 1,054 additions and 275 deletions.
15 changes: 15 additions & 0 deletions doc/user_guide/dielectric_function.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,21 @@ Dielectric function tools

.. versionadded:: 0.7

The :py:class:`~.signals.dielectric_function.DielectricFunction` class inherits from
:py:class:`~.signals.complex_signal.ComplexSignal` and can thus access complex properties.
To convert a :py:class:`~.signals.complex_signal.ComplexSignal` to a
:py:class:`~.signals.dielectric_function.DielectricFunction`, make sure that the signal dimension
and signal type are properly set:

.. code-block:: python
>>> self.metadata.Signal.record_by = 'spectrum'
>>> s.set_signal_type('DielectricFunction')
Note that :py:class:`~._signals.dielectric_function.DielectricFunction` is complex and therefore
is a subclass of :py:class:`~._signals.complex_signal1d.ComplexSignal1D`.


Number of effective electrons
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
2 changes: 1 addition & 1 deletion doc/user_guide/eds.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ downloaded using:
>>> urlretrieve(url + 'Ni_superalloy_010.raw', 'Ni_superalloy_010.raw')
Loading data
^^^^^^^^
^^^^^^^^^^^^

All data are loaded with the :py:func:`~.io.load` function, as described in detail in
:ref:`Loading files<loading_files>`. HyperSpy is able to import different formats,
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/user_guide/images/HyperSpySignalOverview.pptx
Binary file not shown.
2 changes: 1 addition & 1 deletion doc/user_guide/mva.rst
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ the decomposition model. You can easily calculate and display the residuals:
the model constructed using the chosen components.

Non-negative matrix factorization
----------------------------
---------------------------------

Another popular decomposition method is non-negative matrix factorization (NMF), which
can be accessed in HyperSpy with:
Expand Down
10 changes: 10 additions & 0 deletions doc/user_guide/signal2d.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,13 @@ the following method is available to crop spectra the familiar top, bottom,
left, right syntax.

* :py:meth:`~._signals.signal2d.Signal2DTools.crop_image`


Add a linear ramp
-----------------

A linear ramp can be added to the signal via the :py:func:`~._signals.signal2d.Signal2D.add_ramp`
method. The parameters `ramp_x` and `ramp_y` dictate the slope of the ramp in `x`- and `y` direction,
while the offset is determined by the `offset` parameter. The fulcrum of the linear ramp is at the origin
and the slopes are given in units of the axis with the according scale taken into account.
Both are available via the :py:class:`~.axes.AxesManager` of the signal.
132 changes: 108 additions & 24 deletions doc/user_guide/tools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,16 @@ Currently the following signal subclasses are available:

* :py:class:`~._signals.signal1d.Signal1D`
* :py:class:`~._signals.signal2d.Signal2D`
* :py:class:`~._signals.complex_signal.ComplexSignal`
* :py:class:`~._signals.complex_signal1d.ComplexSignal1D`
* :py:class:`~._signals.complex_signal2d.ComplexSignal2D`
* :py:class:`~._signals.eels.EELSSpectrum`
* :py:class:`~._signals.eds_tem.EDSTEMSpectrum`
* :py:class:`~._signals.eds_sem.EDSSEMSpectrum`

Note that in HyperSpy 1.0.0 the :py:class:`~._signals.signal1D.Signal1D` and
:py:class:`~._signals.image.Signal2D` classes were deprecated.
:py:class:`~._signals.image.Signal2D` classes deprecated the old `Spectrum`
and `Image` classes.


The :py:mod:`~.signals` module, which contains all available signal subclasses,
Expand All @@ -61,7 +65,7 @@ Transforming between signal subclasses
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The different subclasses are characterized by three
:py:attr:`~.signal.BaseSignal.metadata` attributes (see the table below):
:py:attr:`~.signal.BaseSignal.metadata` attributes (see the table and diagram below):

`record_by`
Can be "spectrum", "image" or "", the latter meaning undefined and describes
Expand All @@ -87,27 +91,38 @@ The different subclasses are characterized by three
may result in a :py:class:`~.signal.BaseSignal` subclass transformation.


Furthermore, the `dtype` of the signal data also affects the subclass assignment. There are
e.g. specialised signal subclasses to handle complex data (see the following diagram).


.. figure:: images/HyperSpySignalOverview.png
:align: center
:width: 500

Diagram showing the inheritance structure of the different subclasses


.. table:: BaseSignal subclass :py:attr:`~.signal.BaseSignal.metadata` attributes.

+---------------------------------------------------------------+-----------+-------------+
| BaseSignal subclass | record_by | signal_type |
+===============================================================+===========+=============+
| :py:class:`~.signal.BaseSignal` | - | - |
+---------------------------------------------------------------+-----------+-------------+
| :py:class:`~._signals.signal1d.Signal1D` | spectrum | - |
+---------------------------------------------------------------+-----------+-------------+
| :py:class:`~._signals.spectrum_simulation.SpectrumSimulation` | spectrum | - |
+---------------------------------------------------------------+-----------+-------------+
| :py:class:`~._signals.eels.EELSSpectrum` | spectrum | EELS |
+---------------------------------------------------------------+-----------+-------------+
| :py:class:`~._signals.eds_sem.EDSSEMSpectrum` | spectrum | EDS_SEM |
+---------------------------------------------------------------+-----------+-------------+
| :py:class:`~._signals.eds_tem.EDSTEMSpectrum` | spectrum | EDS_TEM |
+---------------------------------------------------------------+-----------+-------------+
| :py:class:`~._signals.signal2d.Signal2D` | image | - |
+---------------------------------------------------------------+-----------+-------------+
| :py:class:`~._signals.image_simulation.ImageSimulation` | image | - |
+---------------------------------------------------------------+-----------+-------------+
+---------------------------------------------------------------+-----------+---------------+---------+
| BaseSignal subclass | record_by | signal_type | dtype |
+===============================================================+===========+===============+=========+
| :py:class:`~.signal.BaseSignal` | - | - | real |
+---------------------------------------------------------------+-----------+---------------+---------+
| :py:class:`~._signals.signal1d.Signal1D` | spectrum | - | real |
+---------------------------------------------------------------+-----------+---------------+---------+
| :py:class:`~._signals.eels.EELSSpectrum` | spectrum | EELS | real |
+---------------------------------------------------------------+-----------+---------------+---------+
| :py:class:`~._signals.eds_sem.EDSSEMSpectrum` | spectrum | EDS_SEM | real |
+---------------------------------------------------------------+-----------+---------------+---------+
| :py:class:`~._signals.signal2d.Signal2D` | image | - | real |
+---------------------------------------------------------------+-----------+---------------+---------+
| :py:class:`~._signals.complex_signal.ComplexSignal` | - | - | complex |
+---------------------------------------------------------------+-----------+---------------+---------+
| :py:class:`~._signals.complex_signal1d.ComplexSignal1D` | spectrum | - | complex |
+---------------------------------------------------------------+-----------+---------------+---------+
| :py:class:`~._signals.complex_signal2d.ComplexSignal2D` | image | - | complex |
+---------------------------------------------------------------+-----------+---------------+---------+


The following example shows how to transform between different subclasses.
Expand Down Expand Up @@ -187,8 +202,6 @@ following table:
+---------------------------------------------------------------+--------+
| :py:class:`~._signals.signal1d.Signal1D` | False |
+---------------------------------------------------------------+--------+
| :py:class:`~._signals.spectrum_simulation.SpectrumSimulation` | False |
+---------------------------------------------------------------+--------+
| :py:class:`~._signals.eels.EELSSpectrum` | True |
+---------------------------------------------------------------+--------+
| :py:class:`~._signals.eds_sem.EDSSEMSpectrum` | True |
Expand All @@ -197,7 +210,11 @@ following table:
+---------------------------------------------------------------+--------+
| :py:class:`~._signals.signal2d.Signal2D` | False |
+---------------------------------------------------------------+--------+
| :py:class:`~._signals.image_simulation.ImageSimulation` | False |
| :py:class:`~._signals.complex_signal.ComplexSignal` | False |
+---------------------------------------------------------------+--------+
| :py:class:`~._signals.complex_signal1d.ComplexSignal1D` | False |
+---------------------------------------------------------------+--------+
| :py:class:`~._signals.complex_signal2d.ComplexSignal2D` | False |
+---------------------------------------------------------------+--------+


Expand Down Expand Up @@ -978,3 +995,70 @@ for example:
├── binned = False
├── record_by = spectrum
└── signal_type =
Handling complex data
^^^^^^^^^^^^^^^^^^^^^

The HyperSpy :py:class:`~.hyperspy.signals.ComplexSignal` signal class and its subclasses
for 1-dimensional and 2-dimensional data allow the user to access complex properties like the
`real` and `imag` parts of the data or the `amplitude` (also known as the modulus) and `phase`
(also known as angle or argument) directly. Getting and setting those properties can be done
as follows:

..code-block:: python

>>> real = s.real # real is a new HyperSpy signal accessing the same data
>>> s.real = new_real # new_real can be an array or signal
>>> imag = s.imag # imag is a new HyperSpy signal accessing the same data
>>> s.imag = new_imag # new_imag can be an array or signal

It is important to note that `data` passed to the constructor of a
:py:class:`~._signals.complex_signal.ComplexSignal` (or to a subclass), which is not already
complex, will be converted to the numpy standard of `np.complex`/`np.complex128`. `data` which
is already complex will be passed as is.

To transform a real signal into a complex one use:

.. code-block:: python
>>> s.change_dtype(complex)
Changing the `dtype` of a complex signal to something real is not clearly defined and thus not
directly possible. Use the `real`, `imag`, `amplitude` or `phase` properties instead to extract
the real data that is desired.


Calculate the angle / phase / argument
--------------------------------------

The :py:func:`~hyperspy.signals.ComplexSignal.angle` function can be used to calculate the
angle, which is equivalent to using the `phase` property if no argument is used. If the data is
real, the angle will be 0 for positive values and 2$\pi$ for negative values. If the `deg`
parameter is set to `True`, the result will be given in degrees, otherwise in rad (default).
The underlying function is the :py:func:`~numpy.angle` function.
:py:func:`~hyperspy.signals.ComplexSignal.angle` will return an appropriate HyperSpy signal.


Phase unwrapping
----------------

With the :py:func:`~hyperspy.signals.ComplexSignal.unwrapped_phase` method the complex phase
of a signal can be unwrapped and returned as a new signal. The underlying method is
:py:func:`~skimage.restoration.unwrap`, which uses the algorithm described in:
Miguel Arevallilo Herraez, David R. Burton, Michael J. Lalor, and Munther A. Gdeisat,
“Fast two-dimensional phase-unwrapping algorithm based on sorting by reliability following
a noncontinuous path”, Journal Applied Optics, Vol. 41, No. 35, pp. 7437, 2002.
(doi: 10.1364/AO.41.007437).


Add a linear phase ramp
-----------------------

For 2-dimensional complex images, a linear phase ramp can be added to the signal via the
:py:func:`~._signals.complex_signal2d.ComplexSignal2D.add_phase_ramp` method. The parameters
`ramp_x` and `ramp_y` dictate the slope of the ramp in `x`- and `y` direction, while the offset
is determined by the `offset` parameter. The fulcrum of the linear ramp is at the origin
and the slopes are given in units of the axis with the according scale taken into account.
Both are available via the :py:class:`~.axes.AxesManager` of the signal.
46 changes: 46 additions & 0 deletions hyperspy/_signals/common_signal1d.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
# Copyright 2007-2016 The HyperSpy developers
#
# This file is part of HyperSpy.
#
# HyperSpy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# HyperSpy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with HyperSpy. If not, see <http://www.gnu.org/licenses/>.


from hyperspy.signal import BaseSignal
from hyperspy.exceptions import DataDimensionError


class CommonSignal1D(object):
"""Common functions for 1-dimensional signals."""

def to_signal2D(self):
"""Returns the one dimensional signal as a two dimensional signal.
See Also
--------
as_signal2D : a method for the same purpose with more options.
signals.Signal1D.to_signal2D : performs the inverse operation on images.
Raises
------
DataDimensionError: when data.ndim < 2
"""
if self.data.ndim < 2:
raise DataDimensionError(
"A Signal dimension must be >= 2 to be converted to Signal2D")
im = self.rollaxis(-1 + 3j, 0 + 3j)
im.metadata.Signal.record_by = "image"
im._assign_subclass()
return im
36 changes: 36 additions & 0 deletions hyperspy/_signals/common_signal2d.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
# Copyright 2007-2016 The HyperSpy developers
#
# This file is part of HyperSpy.
#
# HyperSpy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# HyperSpy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with HyperSpy. If not, see <http://www.gnu.org/licenses/>.


from hyperspy.signal import BaseSignal


class CommonSignal2D(object):
"""Common functions for 2-dimensional signals."""

def to_signal1D(self):
"""Returns the image as a spectrum.
See Also
--------
as_signal1D : a method for the same purpose with more options.
signals.Signal1D.to_signal1D : performs the inverse operation on one
dimensional signals.
"""
return self.as_signal1D(0 + 3j)

0 comments on commit 3c78998

Please sign in to comment.