Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for complex data #1058

Merged
merged 54 commits into from
Jul 11, 2016
Merged
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
e0d73ff
New Signal subclasses for electron holography added.
jan-car Apr 22, 2016
fc892fc
Merge with new_signals
jan-car May 11, 2016
70839c2
Merge pull request #2 from hyperspy/master
jan-car May 19, 2016
94f9bac
Merge pull request #3 from hyperspy/master
jan-car May 25, 2016
d5e84be
Merge
jan-car May 25, 2016
fbc5997
Merge pull request #4 from hyperspy/master
jan-car Jun 3, 2016
657f48d
Added barebone classes for holograms and wave images and tests!
jan-car Jun 3, 2016
fea7d37
Merge
jan-car Jun 3, 2016
3728afa
Added documentation (user guide and docstrings).
jan-car Jun 8, 2016
ae60991
Fixed error: import skimage but install scikit-image...
jan-car Jun 8, 2016
2becaf6
Fixed problem with ambiguity of the get_unwrapped_phase function in t…
jan-car Jun 9, 2016
5086820
Fixed a small import detail which could lead to errors.
jan-car Jun 14, 2016
1d19b4d
Merge pull request #5 from hyperspy/master
jan-car Jun 14, 2016
e90cbb7
Corrected premature (stupid) commit...
jan-car Jun 14, 2016
cf78763
Merge pull request #7 from hyperspy/master
jan-car Jun 15, 2016
b6c28c7
Merge
jan-car Jun 15, 2016
499925b
Corrected a small documentation error.
jan-car Jun 16, 2016
39957d7
Merge
jan-car Jun 16, 2016
d911cbe
Fixed to merge with new Signal1D/2D structure.
jan-car Jun 16, 2016
7d81608
Forgot fixes in the tests...
jan-car Jun 16, 2016
1e3ca5d
Streamlined WaveImage.
jan-car Jun 16, 2016
a54f4f3
Fixed transition to Signal1D/2D in documentation.
jan-car Jun 16, 2016
5c00684
Removed hologram_image and tests from this branch / PR
jan-car Jun 18, 2016
6e6f55f
Merge
jan-car Jun 18, 2016
d27479c
Removed scikit-image from setup.py again.
jan-car Jun 18, 2016
f8b4971
Found more appearances of hologram_image which belong in a later PR.
jan-car Jun 18, 2016
d82d7fe
Pulled remaining properties amplitude and phase from WaveImage to Bas…
jan-car Jun 18, 2016
5cf77ac
Restructured complex properties of BaseSignal.
jan-car Jun 20, 2016
36f7176
Small correction in properties.
jan-car Jun 21, 2016
d6c24b8
Renamed get_unwrapped_phase and get_angle (got rid of get_)
jan-car Jun 21, 2016
55ca8a3
Pulled up unwrapped_phase to BaseSignal and add_phase_ramp to Signal2D
jan-car Jun 22, 2016
e0e82df
Merge
jan-car Jun 22, 2016
d7b465f
New structure with ComplexSignal and ElectronWaveImage.
jan-car Jun 23, 2016
3951cfa
Added support for complex plotting.
jan-car Jun 23, 2016
2e22145
Fixed spelling error.
jan-car Jun 23, 2016
c7d0b12
Introduced new _dtype keyword for signal classes.
jan-car Jun 24, 2016
bc190ae
Merge
jan-car Jun 24, 2016
59ee0b3
Removed ComplexSignal1D/2D, changed assign_signal_subclass behaviour …
jan-car Jun 24, 2016
b9cac04
Removed complex class inheritance from Signal1D/2D.
jan-car Jun 25, 2016
8d37c2c
Trying to fix __init__.
jan-car Jun 26, 2016
3313e6f
Fixed stupid copy/paste mistake (DielectricFunction has signal dimens…
jan-car Jun 26, 2016
867c5b9
assign_signal_subclass should finally be fixed.
jan-car Jun 26, 2016
7be3646
Make sure ComplexSignal data is complex.
jan-car Jun 26, 2016
3f5ce02
ComplexSignal now has complex128 as standard. Added documentation.
jan-car Jun 26, 2016
e6a9d42
Added HyperSpy Signal Overview.
jan-car Jun 27, 2016
719ad06
Rename
jan-car Jun 27, 2016
8bf2d3c
Fixed typo
jan-car Jun 27, 2016
3f62e73
Lots of tests for Signal subclass conversion.
jan-car Jun 27, 2016
8dbe4c3
Fixed conceptual error.
jan-car Jun 27, 2016
07438d2
Merge
jan-car Jul 8, 2016
2fd4bda
Removed ElectronWaveImage and added ComplexSignal1D/2D
jan-car Jul 8, 2016
018261c
Merge
jan-car Jul 10, 2016
f7276e7
Added CommonSignal classes and fixed a few more instances of signal_o…
jan-car Jul 10, 2016
5d4b721
Correction in tool.rst and usage of np.issubdtype(...).
jan-car Jul 11, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 17 additions & 0 deletions doc/user_guide/dielectric_function.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@ 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 signyl type are properly set:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo signyl


.. code-block:: python

>>> self.metadata.Signal.record_by = 'spectrum'
>>> s.set_signal_type('DielectricFunction')

Note that a :py:class:`~._signals.dielectric_function.DielectricFunction` does not inherit from
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a simpler "Note that DielectricFunction is complex and therefore it is a subclass of ComplexSignal" would contain the same information in a more compact form?

:py:class:`~._signals.signal1d.Signal1D`, because most functionality can not operate on complex
data.



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
42 changes: 42 additions & 0 deletions doc/user_guide/electron_holography.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Electron Holography
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this new section of the documentation should probably be added in #1079 instead and this one document the new methods in BaseSignal, Signal2D and the new wave signal?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think we should do this. This section is now gone (@woozey, keep this in mind when we come to #1079 later).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't seem to be gone.

*******************

HyperSpy provides the user with a class which can be used to process electron holography data and
electron wave data in general:

* :py:class:`~._signals.electron_wave_image.ElectronWaveImage`

The usage of the class is explained in the following sections.



The ElectronWaveImage class
===========================

The :py:class:`~._signals.electron_wave_image.ElectronWaveImage` class can hold information about
the complex electron wave. It inherits from :py:class:`~._signals.complex_signal.ComplexSignal`
and as such relevant properties like the `amplitude`, `phase` and the `real` and `imag` part of
the complex data can be directly accessed and return appropriate
:py:class:`~._signals.signal2d.Signal2D` signals.

To transform a complex signal into a :py:class:`~._signals.electron_wave_image.ElectronWaveImage`
use:

.. code-block:: python

>>> s.metadata.Signal.record_by = 'image'
>>> s.set_signal_type('electron wave')

Note that a :py:class:`~._signals.electron_wave_image.ElectronWaveImage` does not inherit from
:py:class:`~._signals.signal2d.Signal2D`, because most functionality can not operate on complex
data.


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

A linear phase ramp can be added to the signal via the :py:func:`~._signals.signal2d.Signal2D.add_phase_ramp`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a typo ~._signals.signal2d.Signal2D.add_phase_ramp -> ~._signals.signal2d.ComplexSignal2D.add_phase_ramp?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that there is no ComplexSignal2D yet, but, maybe add_phase_ramp could be moved to a new ComplexSignal2D?

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.
Binary file added doc/user_guide/images/HyperSpySignalOverview.png
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.
1 change: 1 addition & 0 deletions doc/user_guide/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ HyperSpy User Guide (DRAFT)
eels.rst
eds.rst
dielectric_function.rst
electron_holography.rst
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

electron_holography is still here too.

io.rst
events.rst
metadata_structure.rst
Expand Down
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.
97 changes: 76 additions & 21 deletions doc/user_guide/tools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@ spectroscopy data analysis.

Currently the following signal subclasses are available:

* :py:class:`~._signals.complex_signal.ComplexSignal`
* :py:class:`~._signals.signal1d.Signal1D`
* :py:class:`~._signals.signal2d.Signal2D`
* :py:class:`~._signals.eels.EELSSpectrum`
* :py:class:`~._signals.eds_tem.EDSTEMSpectrum`
* :py:class:`~._signals.eds_sem.EDSSEMSpectrum`
* :py:class:`~._signals.electron_wave_image.ElectronWaveImage`
* :py:class:`~._signals.spectrum_simulation.SpectrumSimulation`
* :py:class:`~._signals.image_simulation.ImageSimulation`

Expand Down Expand Up @@ -62,12 +64,12 @@ information (including calibration) can be accessed (and modified) in the
Transforming between signal subclasses
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

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

`record_by`
Can be "spectrum", "image" or "", the latter meaning undefined and describes
the way the data is arranged in memory. It is possible to transform any
the way the data is arranged in memory. It is possible to transform any non-complex
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Why not providing a to_signal1D method for ComplexSignal2D. A to_signal2D method would probably justify adding a ComplexSignal1D class. The current to_signal1D and to_signal2D should operate well on complex data. Maybe the could be place in new CommonSignal1D and CommonSignal2D classes?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is "non-complex" in "It is possible to transform any non-complex" necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was left over from before we had distinct classes for ComplexSignal1D/2D...
It's removed now.

:py:class:`~.signal.BaseSignal` subclass to a :py:class:`~._signals.signal1d.Signal1D`
or :py:class:`~._signals.signal2d.Signal2D` subclass using the following
:py:class:`~.signal.BaseSignal` methods: :py:meth:`~.signal.BaseSignal.as_signal2D`
Expand Down Expand Up @@ -95,27 +97,36 @@ The different subclasses are characterized by three
:py:meth:`~.signal.BaseSignal.set_signal_origin` changes the signal_origin in place,
which may result in a :py:class:`~.signal.BaseSignal` subclass transformation.

`dtype`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we shouldn't document this in this way here. The _dtype attribute is private and the users shouldn't need to know about it. What about simply explaining (using your diagram) that the data dtype affects the subclass assignment and that the preferred way to change the dtype is using the change_dtype method?

Describes the underlying data type of the signal data and is determined automatically.
Can be "real" or "complex". It is important to note that `data` passed to the constructor of a
:py:class:`~._signals.complex_signal.ComplexSignal`, 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.

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

+---------------------------------------------------------------+-----------+-------------+---------------+
| BaseSignal subclass | record_by | signal_type | signal_origin |
+===============================================================+===========+=============+===============+
| :py:class:`~.signal.BaseSignal` | - | - | - |
+---------------------------------------------------------------+-----------+-------------+---------------+
| :py:class:`~._signals.signal1d.Signal1D` | spectrum | - | - |
+---------------------------------------------------------------+-----------+-------------+---------------+
| :py:class:`~._signals.spectrum_simulation.SpectrumSimulation` | spectrum | - | simulation |
+---------------------------------------------------------------+-----------+-------------+---------------+
| :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 | - | simulation |
+---------------------------------------------------------------+-----------+-------------+---------------+
+---------------------------------------------------------------+-----------+---------------+---------------+---------+
| BaseSignal subclass | record_by | signal_type | signal_origin | dtype |
+===============================================================+===========+===============+===============+=========+
| :py:class:`~.signal.BaseSignal` | - | - | - | real |
+---------------------------------------------------------------+-----------+---------------+---------------+---------+
| :py:class:`~._signals.complex_signal.ComplexSignal` | - | - | - | complex |
+---------------------------------------------------------------+-----------+---------------+---------------+---------+
| :py:class:`~._signals.signal1d.Signal1D` | spectrum | - | - | real |
+---------------------------------------------------------------+-----------+---------------+---------------+---------+
| :py:class:`~._signals.spectrum_simulation.SpectrumSimulation` | spectrum | - | simulation | 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.electron_wave_image.ElectronWaveImage` | image | electron_wave | - | complex |
+---------------------------------------------------------------+-----------+---------------+---------------+---------+
| :py:class:`~._signals.image_simulation.ImageSimulation` | image | - | simulation | real |
+---------------------------------------------------------------+-----------+---------------+---------------+---------+


The following example shows how to transform between different subclasses.
Expand Down Expand Up @@ -198,6 +209,8 @@ following table:
+===============================================================+========+
| :py:class:`~.signal.BaseSignal` | False |
+---------------------------------------------------------------+--------+
| :py:class:`~._signals.complex_signal.ComplexSignal` | False |
+---------------------------------------------------------------+--------+
| :py:class:`~._signals.signal1d.Signal1D` | False |
+---------------------------------------------------------------+--------+
| :py:class:`~._signals.spectrum_simulation.SpectrumSimulation` | False |
Expand All @@ -210,6 +223,8 @@ following table:
+---------------------------------------------------------------+--------+
| :py:class:`~._signals.signal2d.Signal2D` | False |
+---------------------------------------------------------------+--------+
| :py:class:`~._signals.electron_wave_image.ElectronWaveImage` | False |
+---------------------------------------------------------------+--------+
| :py:class:`~._signals.image_simulation.ImageSimulation` | False |
+---------------------------------------------------------------+--------+

Expand Down Expand Up @@ -993,3 +1008,43 @@ for example:
├── record_by = spectrum
├── signal_origin = simulation
└── signal_type =



Handling complex data
^^^^^^^^^^^^^^^^^^^^^

The HyperSpy :py:class:`~.hyperspy.signals.ComplexSignal` signal class allows 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


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).