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

Add inspector tool #29

Merged
merged 17 commits into from
Sep 23, 2022
Merged

Add inspector tool #29

merged 17 commits into from
Sep 23, 2022

Conversation

nvaytet
Copy link
Member

@nvaytet nvaytet commented Sep 22, 2022

This is a tool for inspecting the 3rd dimension of 3d data by placing dots on a 2d image.
The dots indicate where to slice out the displayed dimensions, only to leave the 3rd dim.
The resulting 1d plot is shown on a new figure.
Points can be moved around, and removed.

Example:

%matplotlib widget
import plopp as pp

da = pp.data.dense_data_array(ndim=3)
pp.inspector(da)

Fixes #28

@nvaytet nvaytet marked this pull request as draft September 22, 2022 15:26
@nvaytet nvaytet marked this pull request as ready for review September 22, 2022 17:21
"source": [
"# Inspector plot\n",
"\n",
"The `inspector` plot is for three-dimensional data.\n",
Copy link
Member

Choose a reason for hiding this comment

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

Good name, I think.

For the future: I could imagine using this for 2-D data, in two ways:

  • 1-D plot with 1-D profile.
  • 2-D plot with inspected values displayed in a table.

Copy link
Member Author

@nvaytet nvaytet Sep 23, 2022

Choose a reason for hiding this comment

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

I think "1-D plot with 1-D profile." as we had it in the old plotting, with adding vertical line markers was pretty useless.
For that, I am thinking more of having a superplot (like Lamp's superplot), which is like the slicer plot: you slice 2d data to get a 1d plot with a slider. In addition, you have buttons to save the current line. I think it's better than clicking on the figure to see a cut in the other dimension.

"2-D plot with inspected values displayed in a table.": good idea 👍

Copy link
Member

Choose a reason for hiding this comment

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

I think "1-D plot with 1-D profile." as we had it in the old plotting, with adding vertical line markers was pretty useless.

Not necessarily: Consider {'spectrum':1_000_000, 'tof':1000}. We cannot make a 2-D plot anymore, but someone might want to make a 1-D plot of the counts per spectrum and then inspect and compare TOF-spectra from different pixels.

Copy link
Member Author

Choose a reason for hiding this comment

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

What you suggest is a little different, because the inspector plot does no summing along the third dimension.
So in your example, the first plot wouldn't be the counts per spectrum, it would be the counts per spectrum in the first tof bin.

I guess you could easily make this by adding a summing node in the graph.

Copy link
Member

Choose a reason for hiding this comment

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

What you suggest is a little different, because the inspector plot does no summing along the third dimension.

Without sum this does not seem very useful? In many cases a single slice does not contain useful values to display?

Copy link
Member Author

Choose a reason for hiding this comment

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

So are you saying that inspector should also sum along the third dimension?

Copy link
Member Author

Choose a reason for hiding this comment

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

Should we allow different operations, such as sum, mean, min, max ?

Copy link
Member

Choose a reason for hiding this comment

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

👍

Copy link
Member

Choose a reason for hiding this comment

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

So are you saying that inspector should also sum along the third dimension?

Yes.

Comment on lines 50 to 51
"- Left-click to make new point\n",
"- Left-click and hold on point to move point\n",
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"- Left-click to make new point\n",
"- Left-click and hold on point to move point\n",
"- Click to make new point\n",
"- Drag existing point to move it\n",

or something like that?

@@ -14,7 +14,7 @@
plt.ioff()

from .core import Node, node, input_node, widget_node, show_graph, View
from .functions import figure, plot, slicer
from .functions import figure, plot, slicer, inspector
Copy link
Member

Choose a reason for hiding this comment

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

We should consider our import strategy: I feel some things should stay optional dependencies. I do not know if mpltoolbox is one of them, but pythreejs (for 3D scatter plots) should be.

Copy link
Member Author

Choose a reason for hiding this comment

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

currently mpltoolbox is optional. It only gets imported when inspector is called.

Copy link
Member Author

Choose a reason for hiding this comment

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

And we should probably think about reviewing the code in mpltoolbox, and also making it available on conda.

Comment on lines 10 to 11
from scipp import Variable, scalar
from scipp.typing import VariableLike
Copy link
Member

Choose a reason for hiding this comment

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

I importing without namespace good style? As this is not part of scipp anymore we should maybe just import scipp as sc?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't know, i'm also importing things from ipywidgets like that. e.g. from ipywidgets import VBox.
I thought it is cheaper than importing the whole of ipywidgets, but maybe it makes no difference in practise because it still has to run through the whole __init__.py?

Copy link
Member

Choose a reason for hiding this comment

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

I guess it is a question of style, and we have never made a clear decision on that.


event_nodes = {}

def make_node(change):
Copy link
Member

Choose a reason for hiding this comment

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

What is the reason for the design choice of nested functions?

Copy link
Member Author

Choose a reason for hiding this comment

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

No particular reason. It was the easiest. I can refactor.

@@ -81,23 +81,23 @@ def home(self):
self.crop(**self._crop)
self.draw()

def pan(self):
def pan(self, *_):
Copy link
Member

Choose a reason for hiding this comment

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

Silently ignoring other args? Why and where is this required?

Copy link
Member Author

Choose a reason for hiding this comment

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

I wanted the ToggleButton tool to send its current value when it is pressed, so that the PointsTool can decide whether to start or stop.

In this particular case, we use the tool state from the matplotlib figure to determine which zoom or pan tool should be active. So we don't actually care about the value of the tool for pan and zoom (we could care for logx, logy but not necessarily, cf the current implementation).

That said, in the current implementation the PointsTool is actually a ToggleTool and it knows its current value, so I could just do

    def start_stop(self):
        if self.value:
            self.points.start()
        else:
            self.points.stop()

and no need to send the value when the button is toggled.

I guess I was thinking of future toggle tools, that might call a method that is not part of the class, and that might need the value in the callback message.

But that could be in the future. I am happy to just remove the value from the call, and remove the *_ from the fig.py.

Copy link
Member

Choose a reason for hiding this comment

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

That, or at least add some documentation about what is going on.

@nvaytet nvaytet merged commit 0072c11 into main Sep 23, 2022
@nvaytet nvaytet deleted the add_profiler branch September 23, 2022 10:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement profiler plot
2 participants