-
Notifications
You must be signed in to change notification settings - Fork 5
feat: polygon inspector tool #518
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
base: main
Are you sure you want to change the base?
Conversation
1124b76 to
03d3745
Compare
| def _make_da() -> sc.DataArray: | ||
| data = sc.array( | ||
| dims=['y', 'x', 'z'], | ||
| values=np.arange(2 * 3 * 4, dtype=float).reshape(2, 3, 4), | ||
| ) | ||
| coords = { | ||
| 'x': sc.arange('x', 3), | ||
| 'y': sc.arange('y', 2), | ||
| 'z': sc.arange('z', 4), | ||
| } | ||
| return sc.DataArray(data=data, coords=coords) |
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.
[minor] Can we ask clauede to make it a pytest fixture instead?
05ca032 to
65b98fc
Compare
|
Hey! Nice to see this progressing so fast. Would it be possible to have some method to extract the pixels/indices/coordinates of the DataArray within each polygon? In EasyImaging I will create so-called ROI objects based on these, so I need to have some method of getting that information out. It can be a hacky solution, doesn't have to be a part of the user-facing API. |
src/plopp/__init__.py
Outdated
| ], | ||
| 'plotting': [ | ||
| 'inspector', | ||
| 'inspector_polygon', |
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.
Not sure about the interface? Should we have multiple tools, or just one with different modes (selected by a kwarg)?
We could/should fx generalize this to also use rectangles instead of polygons.
I would then probably vote for inspector(..., mode='points') or 'polygon' or 'rectangle'.
| def _to_bin_edges(da: sc.DataArray, dim: str) -> sc.DataArray: | ||
| """ | ||
| Convert dimension coords to bin edges. | ||
| """ | ||
| for d in set(da.dims) - {dim}: | ||
| da.coords[d] = coord_as_bin_edges(da, d) | ||
| return da | ||
|
|
||
|
|
||
| def _apply_op(da: sc.DataArray, op: str, dim: str) -> sc.DataArray: | ||
| out = getattr(sc, op)(da, dim=dim) | ||
| if out.name: | ||
| out.name = f'{op} of {out.name}' | ||
| return out |
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.
These functions already exist in inspector.py. We should avoid duplicating them.
| return sc.array(dims=[ydim, xdim], values=inside) | ||
|
|
||
|
|
||
| def _slice_polygon( |
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.
Use a better name for the function? We are not slicing but adding a mask and reducing?
src/plopp/widgets/drawing.py
Outdated
| self._tool.stop() | ||
|
|
||
|
|
||
| class PolygonTool(ToggleTool): |
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 should be implemented by looking at the Rectangle Selection example.
We shouldn't create a new tool from scratch, instead use the Polygons in mpltoolbox and create a tool using something like
PolygonTool = partial(
DrawingTool, tool=mpltoolbox.Polygons, get_artist_info=_get_polygon_info, icon='draw-polygon'
)|
There are some things to clean up here:
But besides that the functionality seems to be in place. We also gained the neat feature that the polygon edges can be dragged after they've been made, and the other figure updates continuously as we do so. |
Yeah I was thinking something similar. It would be good if users can access the data in the polygon regions to do other processing. I'll think about it. |
| vy = poly['y']['value'].to(unit=y.unit).values | ||
| verts = np.column_stack([vx, vy]) | ||
| path = Path(verts) | ||
| xx, yy = np.meshgrid(x.values, y.values, indexing='xy') |
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 this assumes that the x and y coords are 1d arrays, and would break down if one of the coords is 2d.
Instead, I think we can broacast the coord using scipp and then take the values of that?
e.g.
xx = sc.broadcast(x, sizes=da.sizes).values
yy = sc.broadcast(y, sizes=da.sizes).valuesand this would be a no-op if the coord is already 2d?
| ) | ||
|
|
||
|
|
||
| def _slice_dataarray_by_mask(da, mask): |
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 remember we discussed whether slicing would be a faster operation than adding a mask, but looking at this I feel the added complexity of having to loop through data, coords and masks might be making things less efficient that simply adding a 2d mask in the x and y dimensions? (or at least it's more complicated)
We already get the mask computed by the
inside = sc.array(
dims=[ydim, xdim], values=path.contains_points(points).reshape(yy.shape)
)below.
Can we just set the inverse of that as a mask and then do the reduction operation in the x and y dimensions?
I think that should give the same result?

There's been requests from time to time for a plopp tool that visualizes intensity inside a polygon region, similar to the
inspectortool, but with a polygon instead of a point.Be aware that it is mostly AI-written.