-
Notifications
You must be signed in to change notification settings - Fork 206
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
Intensity log scale plot #1727
Intensity log scale plot #1727
Conversation
… the data. Add tests.
Fix #543. |
…sity_log_scale_plot # Conflicts: # hyperspy/drawing/image.py
@woozey, in case you fancy having a look! ;) |
I've been playing around with the log plotting. Works nicely! One minor error: My (EELS) spectrum image has some negative values in it, but certainly not all of the values are negative: >>> eels
<EELSSpectrum, title: EELS Spectrum Image, dimensions: (24, 56|2048)>
>>> eels.T.plot(intensity_scale='log')
ValueError: Data has no positive values, and therefore can not be log-scaled. |
Does the |
Based on a quick google search I think you are correct. I can double check tomorrow. Any thought on the |
… is plotted shifted. For convenience set the same options to the roi plot as the original signal plot.
I haven't got time right now to look for the file with negative counts. I'm pretty sure that this was matplotlib, not you. |
…sity_log_scale_plot # Conflicts: # hyperspy/drawing/image.py # hyperspy/drawing/signal1d.py
Thanks for the feedback! There are indeed quite a few things which need to be discussed here. I did look at using the "shifted" node of the metadata, but I ended up not being happy about it. This PR implements the |
What is the reason? Is there anything that should be improved there?
I wouldn't say my worry are defaults, as I'm happy to have it shifted by default. My real worry is that it is confusing for a user getting the plots shifted although the actual data is not. So I still would strongly advice to put a warning or something in order to inform a user.
Indeed! I have overseen that for no reason! It works excellent! Thanks! |
I don't remember exactly, but I don't think there was any particular reason, I just wanted to keep it simple and also hear what other people would expect as default behaviour before going forward. The problem with warning is that people doesn't like it... maybe we could log this at the "info" level. Normally, they should be a shortcut "l" (as L) to toggle from linear to log scale. |
This sounds reasonable to me. The name does not really matter but that certainly will help avoiding confusion! Another option could be doing similar to
Perhaps... I don't know what is the best practice in such cases.
This one works too! |
Yes, indeed, "origin" got its drawback too... I did as you suggested and did two versions for the name of the parameter:
I prefer the second one because it is clear what it does regardless if the FFT is shifted or not. Moreover, I find it is more convenient to use with ROI: import hyperspy.api as hs
holo = hs.datasets.example_signals.object_hologram()
fft = holo.fft(True)
fft.plot(True) # True is for the power spectrum With the version with "shifted": import hyperspy.api as hs
holo = hs.datasets.example_signals.object_hologram()
fft = holo.fft(True)
fft.plot(True, shifted=True) # True is for the power spectrum, but we also need to specify `shifted=True` if not the FFT is shifted back... |
Now I see the point for shift and shifted! Yes, I think shift would be better than. I'll test the latest version in a while. |
Just gave it a try. Looks good to me! |
…sity_log_scale_plot # Conflicts: # hyperspy/drawing/image.py
0ec0de2
to
ae55bad
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In addition to the small comments I wonder if it wouldn't be better to replace the fft
shift
kwarg with a shift_fft
or maybe better (for discovery) fft_shift
method. The main advantage is that it'll enable going from unshifted to shifted and back to unshifted. It'll also make be more explicit that the operation doubles the size in memory of the data temporarily.
hyperspy/drawing/image.py
Outdated
'not supported, falling back to the default ' | ||
'(linear).') | ||
# if the `norm` kwargs is passed to matplotlib, we use it | ||
norm = kwargs.pop('norm', None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be good to add an example to the docstring and the user guide of how to use mpl's norm
to e.g. display images with negative numbers using SymLogNorm
doc/user_guide/tools.rst
Outdated
|
||
By default both methods calculate FFT and IFFT with origin at (0, 0) (not in the centre of FFT). Use `shifted=True` option to | ||
By default, both methods calculate FFT and IFFT with origin at (0, 0) (not in the centre of FFT). Use ``shifted=True`` option to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that it would be good to mention here that ROIs don't work on "unshifted" FFTs shifted to plot.
hyperspy/docstrings/plot.py
Outdated
@@ -53,6 +53,10 @@ | |||
plot_markers : bool, default True | |||
Plot markers added using s.add_marker(marker, permanent=True). | |||
Note, a large number of markers might lead to very slow plotting. | |||
intensity_scale : {None, 'linear', 'log'}, default is None. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about using "auto"
instead of None
. The advantage is that it's more explicit. I know that in HyperSpy None
often means "auto"
, maybe something else to fix?
hyperspy/drawing/image.py
Outdated
# set the image normalisation | ||
if self.intensity_scale == 'log': | ||
from matplotlib.colors import LogNorm | ||
norm = LogNorm(vmin=self.vmin, vmax=self.vmax) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if norm
is in kwargs
and intensity_scale == "log"
?
Wouldn't it be clearer if we use norm
instead of intensity_scale
as the name for this kwarg. If it is a mpl norm, we use it directly, if "linear" or "log" or "auto"
we do as it currently does for intensity_scale
.
hyperspy/drawing/image.py
Outdated
'not supported, falling back to the default ' | ||
'(linear).') | ||
# if the `norm` kwargs is passed to matplotlib, we use it | ||
norm = kwargs.pop('norm', None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the norm is an mpl norm it could be an instance or a class (currently it assumes that it is an instance). If it is a class, it could create the instance passing vmin
and max
to the constructor.
@@ -57,6 +57,9 @@ def add_phase_ramp(self, ramp_x, ramp_y, offset=0): | |||
self.phase = phase | |||
|
|||
def plot(self, | |||
power_spectrum=False, | |||
intensity_scale=None, | |||
shift=False, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about calling this shift_fft
instead?
hyperspy/signal.py
Outdated
self._plot.signal_title = self.metadata.General.title | ||
title = self.metadata.General.title | ||
if kwargs.get('power_spectrum', False): | ||
title = title.replace('FFT', 'Power spectrum') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assumes that FFT is contained in the title. It may not be the case because the user has changed it or the data comes from an external source.
hyperspy/signal.py
Outdated
title = self.metadata.General.title | ||
if kwargs.get('power_spectrum', False): | ||
title = title.replace('FFT', 'Power spectrum') | ||
self._plot.quantity_label = 'Power spectral density' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about the units?
hyperspy/signal.py
Outdated
@@ -3256,7 +3268,7 @@ def fft(self, shifted=False, **kwargs): | |||
|
|||
Parameters | |||
---------- | |||
shifted : bool, optional | |||
shift : bool, optional | |||
If True, the origin of FFT will be shifted in the centre (Default: False). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to the centre?
im_fft.metadata.set_item('Signal.FFT.shifted', shifted) | ||
im_fft.metadata.set_item('Signal.FFT.shifted', shift) | ||
if hasattr(self.metadata.Signal, 'quantity'): | ||
self.metadata.Signal.__delattr__('quantity') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why removing the quantity? Couldn't we compute the right one with pint? Same for units.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if pint can do it properly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In addition to the comments above I think that it would be better to replace the shift
kwarg of fft
with a fft_shift
method. In this way:
- It'll be possible to "unshift" a "shifted" fft
- It'll be more explicit that the operations requires temporarily doubling the size in memory.
This is already the possible, isn't
I don't see what is doubling the memory? |
I may be wrong, but I think that |
@ericpre, is this ready for review? |
Even if it's return a copy (I haven't checked), for plotting it is computed only using the current index, so this is possibly not a big deal in term of memory issue? Other than that, yes, it is ready for review. |
Sorry my point wasn't fully clear: I meant the |
Yes, let's do this in another PR. |
Following #1725, this PR add support for plotting signal on a log scale with the
intensity_scale
argument of theplot
, which can be set to 'linear', 'log' or None.:intensity_scale
to theplot
method of theBaseSignal
class,power_spectrum
andshifted
parameters to theplot
method of complex signals,By default if the signal to plot has the
Signal.FFT
node in the metadata, the power spectrum will be plotted on a log scale (the complex FFT can still be plotted by settingpower_spectrum=False
).