8000 Merge pull request #104 from hyperspy/integrate_in_range · magnunor/matplotlib@83eebdf · GitHub
[go: up one dir, main page]

Skip to content

Commit 83eebdf

Browse files
committed
Merge pull request matplotlib#104 from hyperspy/integrate_in_range
Integrate in range
2 parents 3ed2b54 + 7f17724 commit 83eebdf

File tree

6 files changed

+134
-14
lines changed

6 files changed

+134
-14
lines changed

CHANGES.txt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ We only cover here the main highlights, for a detailed list of all the changes s
99
v0.7
1010
====
1111

12-
New features
13-
------------
12+
New features ------------
1413
* Hyperspy is now fully compatible with the Qt toolkit in addition to the WX
15-
toolkit. The Qt toolkit is now the default.
14+
toolkit. Qt toolkit is now the default toolkit, but this can be changed
15+
in preferences.
1616
* Hyperspy can now use the GTK and TK toolkits, although without the GUI
1717
features.
18-
* The default toolkit can now be saved in the preferences.
19-
* It is now possible to run hyperspy in :ref:`a headless system <headless-label>`.
18+
* It is now possible to run hyperspy in :ref:`a headless system
19+
<headless-label>`.
20+
* New method for 1D signal intregration. See :ref:`integrate_1D-label`.
2021

2122
.. _changes_0.6:
2223

doc/api/hyperspy.misc.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ misc Package
3333
:undoc-members:
3434
:show-inheritance:
3535

36-
:mod:`interactive_ns` Module
37-
----------------------------
36+
:mod:`ipython_tools` Module
37+
---------------------------
3838

39-
.. automodule:: hyperspy.misc.interactive_ns
39+
.. automodule:: hyperspy.misc.ipython_tools
4040
:members:
4141
:undoc-members:
4242
:show-inheritance:

doc/user_guide/tools.rst

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,7 @@ Simple operations over one axis
504504
* :py:meth:`~.signal.Signal.std`
505505
* :py:meth:`~.signal.Signal.var`
506506
* :py:meth:`~.signal.Signal.diff`
507+
* :py:meth:`~.signal.Signal.integrate_simpson`
507508

508509
Changing the data type
509510
^^^^^^^^^^^^^^^^^^^^^^
@@ -542,7 +543,6 @@ equal to one.
542543

543544
Cropping
544545
^^^^^^^^
545-
546546
In addition to cropping using the powerful and compact
547547
:ref:`Signal indexing <signal.indexing>` syntax
548548
the following method is available to crop spectra using a GUI:
@@ -573,10 +573,17 @@ files.
573573
* :py:meth:`~.signal.Signal1DTools.align1D`
574574
* :py:meth:`~.signal.Signal1DTools.shift1D`
575575

576+
.. _integrate_1D-label:
577+
578+
Integration
579+
-----------
580+
The :py:meth:`~.signal.Signal1DTools.integrate_in_range` method provides a GUI
581+
and a CLI to integrate the 1D signal dimension in a given range using the
582+
Simpson's rule. The GUI operates in-place while the CLI opearation is
583+
not-in-place.
576584

577585
Data smoothing
578586
^^^^^^^^^^^^^^
579-
580587
The following methods (that include user interfaces when no arguments are
581588
passed) can perform data smoothing with different algorithms:
582589

hyperspy/gui/tools.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
from hyperspy.drawing.widgets import DraggableVerticalLine
3535
from hyperspy.misc import spectrum_tools
3636

37-
3837
import sys
3938

4039
OurApplyButton = tu.Action(name = "Apply",
@@ -785,5 +784,44 @@ def _fit_fired(self):
785784
def apply(self):
786785
self._fit_fired()
787786

788-
787+
class IntegrateArea(SpanSelectorInSpectrum):
788+
integrate = t.Button()
789+
790+
view = tu.View(
791+
buttons = [OKButton, CancelButton],
792+
title = 'Integrate in range',
793+
handler = SpanSelectorInSpectrumHandler,
794+
)
795+
796+
def __init__(self, signal, signal_range=None):
797+
if signal.axes_manager.signal_dimension != 1:
798+
raise SignalOutputDimensionError(
799+
signal.axes.signal_dimension, 1)
800+
801+
self.signal = signal
802+
self.span_selector = None
803+
if not hasattr(self.signal, '_plot'):
804+
self.signal.plot()
805+
elif self.signal._plot is None:
806+
self.signal.plot()
807+
elif self.signal._plot.is_active() is False:
808+
self.signal.plot()
809+
self.span_selector_switch(on=True)
810+
811+
def apply(self):
812+
integrated_spectrum = self.signal._integrate_in_range_commandline(
813+
signal_range=(
814+
self.ss_left_value,
815+
self.ss_right_value)
816+
)
817+
#Replaces the original signal inplace with the new integrated spectrum
818+
plot = False
819+
if self.signal._plot:
820+
self.signal._plot.close()
821+
plot = True
822+
self.signal.__init__(**integrated_spectrum._to_dictionary())
823+
self.signal._assign_subclass()
824+
self.signal.axes_manager.set_signal_dimension(0)
825+
if plot is True:
826+
self.signal.plot()
789827

hyperspy/signal.py

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
from hyperspy.exceptions import SignalDimensionError, DataDimensionError
5656
from hyperspy.misc import array_tools
5757
from hyperspy.misc import spectrum_tools
58+
from hyperspy.gui.tools import IntegrateArea
5859
from hyperspy import components
5960

6061
class Signal2DTools(object):
@@ -593,8 +594,8 @@ def align1D(self,
593594
as this one and that will be aligned using the shift map
594595
estimated using the this signal.
595596
596-
Return
597-
------
597+
Returns
598+
-------
598599
An array with the result of the estimation. The shift will be
599600
600601
Raises
@@ -624,6 +625,58 @@ def align1D(self,
624625
crop=crop,
625626
fill_value=fill_value)
626627

628+
def integrate_in_range(self, signal_range='interactive'):
629+
""" Sums the spectrum over an energy range, giving the integrated
630+
area.
631+
632+
The energy range can either be selected through a GUI or the command
633+
line. When `signal_range` is "interactive" the operation is performed
634+
in-place, i.e. the original spectrum is replaced. Otherwise the
635+
operation is performed not-in-place, i.e. a new object is returned with
636+
the result of the integration.
637+
638+
Parameters
639+
----------
640+
signal_range : {a tuple of this form (l, r), "interactive"}
641+
l and r are the left and right limits of the range. They can be numbers or None,
642+
where None indicates the extremes of the interval. When `signal_range` is
643+
"interactive" (default) the range is selected using a GUI.
644+
645+
Returns
646+
-------
647+
integrated_spectrum : {Signal subclass, None}
648+
649+
See Also
650+
--------
651+
integrate_simpson
652+
653+
Examples
654+
--------
655+
656+
Using the GUI (in-place operation).
657+
658+
>>> s.integrate_in_range()
659+
660+
Using the CLI (not-in-place operation).
661+
662+
>>> s_int = s.integrate_in_range(signal_range=(560,None))
663+
664+
"""
665+
666+
if signal_range == 'interactive':
667+
ia = IntegrateArea(self, signal_range)
668+
ia.edit_traits()
669+
integrated_spectrum = None
670+
else:
671+
integrated_spectrum = self._integrate_in_range_commandline(signal_range)
672+
return(integrated_spectrum)
673+
674+
def _integrate_in_range_commandline(self, signal_range):
675+
e1 = signal_range[0]
676+
e2 = signal_range[1]
677+
integrated_spectrum = self[..., e1:e2].integrate_simpson(-1)
678+
return(integrated_spectrum)
679+
627680
@only_interactive
628681
def calibrate(self):
629682
"""Calibrate the spectral dimension using a gui.
@@ -3659,6 +3712,8 @@ def as_image(self, image_axes):
36593712
im._assign_subclass()
36603713
return im
36613714

3715+
3716+
36623717
def _assign_subclass(self):
36633718
mp = self.mapped_parameters
36643719
current_class = self.__class__
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from nose.tools import assert_true, assert_equal, raises
2+
import numpy as np
3+
4+
from hyperspy.signals import Signal
5+
from hyperspy.components import Gaussian
6+
7+
class Test1D():
8+
def setUp(self):
9+
gaussian = Gaussian()
10+
gaussian.A.value = 20
11+
gaussian.sigma.value = 10
12+
gaussian.centre.value = 50
13+
self.signal = Signal(gaussian.function(np.arange(0,100,0.01)))
14+
self.signal.axes_manager[0].scale = 0.01
15+
16+
def test_integrate_in_range(self):
17+
integrated_signal = self.signal.integrate_in_range(signal_range=(None,None))
18+
assert_true(np.allclose(integrated_signal.data, 20,))
19+

0 commit comments

Comments
 (0)
0