Git Product home page Git Product logo

Comments (12)

ericpre avatar ericpre commented on June 22, 2024 2

Regarding implementing it in hs.plot.plot_images, this could be done in a similar way as its Signal1D counterpart: hyperspy/hyperspy#2414

from lumispy.

ericpre avatar ericpre commented on June 22, 2024 1

Following the approach used in https://github.com/pyxem/pyxem/blob/996651e5c2ac22cbaf0e11fca1eed8cbd5a35616/pyxem/signals/common_diffraction.py#L76-L127, below is an example that works ignoring the part with hs.plot.plot_images that needs to be made interactive:

import hyperspy.api as hs
import numpy as np

# generate some appropriately shaped data
s = hs.signals.Signal1D(data=np.random.random((64, 64, 1024)), 
                        axes=[{'name': 'x', 'size': 64}, 
                              {'name': 'y', 'size': 64}, 
                              {'name': 'sig', 'size': 1024}])


peaks = [350, 750]
widths = [100, 50]

s.plot()

# Initialise the roi with the value from the step 1 and the corresponding/given width
roi1 = hs.roi.SpanROI(peaks[0]-widths[0]/2, peaks[0]+widths[0]/2)
roi2 = hs.roi.SpanROI(peaks[1]-widths[1]/2, peaks[1]+widths[1]/2)

roi1_signal = roi1.interactive(s, color="red", axes=s.axes_manager.signal_axes)
roi2_signal = roi2.interactive(s, color="green", axes=s.axes_manager.signal_axes)

# placehodler for the sum
roi1_sum = roi1_signal.sum(axis=roi1_signal.axes_manager.signal_axes).T
roi2_sum = roi2_signal.sum(axis=roi2_signal.axes_manager.signal_axes).T

hs.interactive(
    roi1_signal.nansum,
    axis=roi1_signal.axes_manager.signal_axes,
    event=roi1.events.changed,
    recompute_out_event=None,
    out=roi1_sum,
)
hs.interactive(
    roi2_signal.nansum,
    axis=roi2_signal.axes_manager.signal_axes,
    event=roi2.events.changed,
    recompute_out_event=None,
    out=roi2_sum,
)


# # Plot the result
roi1_sum.plot()
roi2_sum.plot()

# This part is the one that needs improvement to be interactive
# hs.plot.plot_images([roi1_sum, roi1_sum])

from lumispy.

0Hughman0 avatar 0Hughman0 commented on June 22, 2024 1

Thanks for the encouragement.

I will have a go at achieving the same thing with built-in hyperspy functionality. Although it sounds like from what you are saying, @ericpre, it will not be possible to overlay the maps and have them automatically update until there's a some tweaks to the hs.plot.plot_images function?

From briefly looking at the source, I think either hs.plot.plot_images needs to provide some sort of events argument, or if it were wrapped in some sort of object (akin to MPL_HyperExplorer), maybe users could hook into the internals to setup their own callbacks.

I don't know how people feel about having a navigation plot (where you select your wavelength ranges), but multiple maps of the integrated counts for each 'channel'? It's not quite a 1 to 1 replication of the Dorset functionality, but probably still useful.

from lumispy.

ericpre avatar ericpre commented on June 22, 2024

This makes sense to have such features; as an alternative of implementing new classes, I would suggest to use already existing functionalities using the following approach:

# Step 1: find peak, use hyperspy find_peaks_ohaver?
peaks =...
width = ...

# Step 2: add roi to figure
# Initialise the roi with the value from the step 1 and the corresponding/given width
roi1_signal = hs.roi.SpanROI(peaks[0]-width/2, peaks[0]+width/2).interactive(s, color="red")
roi2_signal = hs.roi.SpanROI(peaks[1]-width/2, peaks[1]+width/2).interactive(s, color="red")

# Step 3: generate map from signal
map1 = hs.interactive(roi1_signal.sum)
map2 = hs.interactive(roi2_signal.sum)

# Step 4: generate overlay maps figure
hs.plot.plot_images([map1, map2], overlay=True)

In the first two steps need the correct argument to be efficient (avoid redundant computation) and are very similar to: https://github.com/pyxem/pyxem/blob/996651e5c2ac22cbaf0e11fca1eed8cbd5a35616/pyxem/signals/common_diffraction.py#L76-L127

The last step is the overlay of the two (or more) maps and I am not sure if it would be interactive, if not, this should be fixed in hyperspy.

This could be nicely wrapped up in a signal method, which could possibly go in hyperspy as this is a generic functionality and other spectroscopy technique could benefit from it.

from lumispy.

0Hughman0 avatar 0Hughman0 commented on June 22, 2024

Great thanks so much for the feedback.

Indeed the functionality I want to add looks very similar to the one you linked in pyxem.

I do think the ability to have multiple 'channels' would be quite beneficial, and I think interactivity is a must for this to be useful for people to quickly use this tool.

I do think such a thing could be widely useful, but I don't know what the philosophy is hyperspy is in terms of stacking more functionality into the signal classes.

I'm super impressed it looks like this can be accomplished with hs's interactive features. Not sure why, but I sometimes find them a bit bewildering and frequently run into errors, which puts me off using it a bit.

Sadly I have tried to get the snippet you have suggested working, I'm not sure where I'm going wrong:

import hyperspy.api as hs

# generate some appropriately shaped data
s = hs.signals.Signal1D(data=np.random.random((64, 64, 1024)), 
                        axes=[{'name': 'x', 'size': 64}, 
                              {'name': 'y', 'size': 64}, 
                              {'name': 'sig', 'size': 1024}])


peaks = [350, 750]
widths = [100, 50]

# I guess maybe issue is I'm not plotting the appropriate thing here?
s.plot()

# Step 2: add roi to figure
# Initialise the roi with the value from the step 1 and the corresponding/given width
roi1_signal = hs.roi.SpanROI(peaks[0]-widths[0]/2, peaks[0]+widths[0]/2).interactive(s, color="red")
roi2_signal = hs.roi.SpanROI(peaks[1]-widths[1]/2, peaks[1]+widths[1]/2).interactive(s, color="green")

# Step 3: generate map from signal
map1 = hs.interactive(roi1_signal.sum)
map2 = hs.interactive(roi2_signal.sum)

# Step 4: generate overlay maps figure
hs.plot.plot_images([map1, map2], overlay=True)

From that I get:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_20276/994102482.py in <module>
     12 # Step 2: add roi to figure
     13 # Initialise the roi with the value from the step 1 and the corresponding/given width
---> 14 roi1_signal = hs.roi.SpanROI(peaks[0]-widths[0]/2, peaks[0]+widths[0]/2).interactive(s, color="red")
     15 roi2_signal = hs.roi.SpanROI(peaks[1]-widths[1]/2, peaks[1]+widths[1]/2).interactive(s, color="green")
     16 

C:\ProgramData\Anaconda3\envs\PhD\lib\site-packages\hyperspy\roi.py in interactive(self, signal, navigation_signal, out, color, snap, **kwargs)
    429                 [])
    430         if out is None:
--> 431             return interactive(self.__call__,
    432                                event=self.events.changed,
    433                                signal=signal,

C:\ProgramData\Anaconda3\envs\PhD\lib\site-packages\hyperspy\interactive.py in interactive(f, event, recompute_out_event, *args, **kwargs)
    128 
    129 def interactive(f, event="auto", recompute_out_event="auto", *args, **kwargs):
--> 130     cls = Interactive(f, event, recompute_out_event, *args, **kwargs)
    131     return cls.out
    132 

C:\ProgramData\Anaconda3\envs\PhD\lib\site-packages\hyperspy\interactive.py in __init__(self, f, event, recompute_out_event, *args, **kwargs)
     79             self.out = self.kwargs.pop('out')
     80         else:
---> 81             self.out = self.f(*self.args, **self.kwargs)
     82         # Reuse the `_plot_kwargs` for the roi if available
     83         if _plot_kwargs and 'signal' in self.kwargs:

C:\ProgramData\Anaconda3\envs\PhD\lib\site-packages\hyperspy\roi.py in __call__(self, signal, out, axes)
    213 
    214         natax = signal.axes_manager._get_axes_in_natural_order()
--> 215         slices = self._make_slices(natax, axes)
    216         nav_axes = [ax.navigate for ax in axes]
    217         nav_dim = signal.axes_manager.navigation_dimension

C:\ProgramData\Anaconda3\envs\PhD\lib\site-packages\hyperspy\roi.py in _make_slices(self, axes_collection, axes, ranges)
    170                 i = axes.index(ax)
    171                 try:
--> 172                     ilow = ax.value2index(ranges[i][0])
    173                 except ValueError:
    174                     if ranges[i][0] < ax.low_value:

C:\ProgramData\Anaconda3\envs\PhD\lib\site-packages\hyperspy\axes.py in value2index(self, value, rounding)
   1231                 return index
   1232             else:
-> 1233                 raise ValueError("The value is out of the axis limits")
   1234 
   1235     def update_axis(self):

ValueError: The value is out of the axis limits

Using the latest '1.7.1' version of hyperspy.

What's worse, I just updated from a dev version of 1.7.0dev0, and now my own snippet is broken 😅 - serves me right I guess!

from lumispy.

0Hughman0 avatar 0Hughman0 commented on June 22, 2024

Ok, I've kept going with the branch here:

https://github.com/0Hughman0/lumispy/blob/auto_peak_map/lumispy/utils/analysis.py

I am trying to make a bit more use of the roi functionality. I did try chaining together events using hs.interactive, but I couldn't get the plots to update, even if the callbacks called sig._plot.navigator_plot.update(), not sure what I was doing wrong.

from lumispy.

jordiferrero avatar jordiferrero commented on June 22, 2024

@0Hughman0 thanks for the contribution! Let us know if you managed to make it work using hyperspy interactive method with 2d images. I have also tried in the past and got very confused with the interactivity of 2 rois in parallel.
If it does not work, I believe lumispy could benefit from such functionality.

from lumispy.

jlaehne avatar jlaehne commented on June 22, 2024

Indeed, where possible to use existing HyperSpy functions that makes sense. As brought up by @jordiferrero in #55 we can consider to still have a set of dedicated plot functions in LumiSpy amending those of HyperSpy - just because it is easier for some types of plots to have a dedicated function and not to have to work with a complicated set of options to a more generic function.

from lumispy.

0Hughman0 avatar 0Hughman0 commented on June 22, 2024

ok please see #148, I haven't gone as far as writing tests and docstrings (excited to try pytest-mpl!)

from lumispy.

ericpre avatar ericpre commented on June 22, 2024

I will have a go at achieving the same thing with built-in hyperspy functionality. Although it sounds like from what you are saying, @ericpre, it will not be possible to overlay the maps and have them automatically update until there's a some tweaks to the hs.plot.plot_images function?

From briefly looking at the source, I think either hs.plot.plot_images needs to provide some sort of events argument, or if it were wrapped in some sort of object (akin to MPL_HyperExplorer), maybe users could hook into the internals to setup their own callbacks.

As it has been done for hs.plot.plot_spectra (see hyperspy/hyperspy#2414), it should be implemented in a way that the plot update automatically when the data changed. This changed is needed in the hs.plot.plot_images and the user doesn't need to do anything with events.

from lumispy.

jlaehne avatar jlaehne commented on June 22, 2024

Upstreamed to hyperspy/hyperspy#3224

from lumispy.

jlaehne avatar jlaehne commented on June 22, 2024

Closing as hyperspy/hyperspy#3224 was merged and is included in HyperSpy 2.0

from lumispy.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.