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

Shape selector #91

Merged
merged 17 commits into from
Nov 17, 2024
Merged

Conversation

multimeric
Copy link
Collaborator

Closes #90.

@pr4deepr
Copy link
Collaborator

When launching the plugin, I get this error:

RuntimeError: Failed to import command at 'napari_lattice.dock_widget:LLSZWidget': No module named 'plugin'

I installed into an existing environment.

@multimeric
Copy link
Collaborator Author

Oops, fixed

@pr4deepr
Copy link
Collaborator

With cropping:

  • If I use the New Crop button to create a Shapes Layer and then draw ROIs. The cropping works, even if the ROI is outside the bounds of the image. It just returns the cropped image for latter.
  • If I create a Shapes layer in napari using the New Shapes tool, and then draw an ROI; I get the following error:

image

@multimeric
Copy link
Collaborator Author

I realised why this happens. It's because the Shape has 3 dimensions but the ROI class I created only expects 2 dimensions. We don't support ROIs in 3D or higher do we? If not, I'll just drop the other dimensions.

shape.get_array()
array([[  27.83333333,  540.61463643,  420.71545234],
       [  27.83333333,  540.61463643, 1006.41766134],
       [  27.83333333,  992.6239499 , 1006.41766134],
       [  27.83333333,  992.6239499 ,  420.71545234]])

@pr4deepr
Copy link
Collaborator

Yes, the ROI will be in 2D for now (X,Y). We can crop in 3D by specifying z range. But I think z range is disabled for now.

@multimeric multimeric requested a review from pr4deepr October 18, 2024 03:56
@multimeric multimeric marked this pull request as ready for review October 18, 2024 06:08
@pr4deepr
Copy link
Collaborator

Thanks

If I use the New Crop button under Crop tab, cropping works fine when I draw ROIs. But, when selecting ROIs, the corresponding cell doesn't get selected or updated though.

If I create a Shapes layer manually and click mouse button to draw an ROI, I get an error with the following traceback


ValueError                                Traceback (most recent call last)
File ~\.conda\envs\napari_lattice\lib\site-packages\vispy\app\backends\_qt.py:496, in QtBaseCanvasBackend.mousePressEvent(self=<vispy.app.backends._qt.CanvasBackendDesktop object>, ev=<PyQt5.QtGui.QMouseEvent object>)
    494 if self._vispy_canvas is None:
    495     return
--> 496 self._vispy_mouse_press(
        self = <vispy.app.backends._qt.CanvasBackendDesktop object at 0x0000020FA2BF8CA0>
        ev = <PyQt5.QtGui.QMouseEvent object at 0x0000020FA2BE5A20>
        BUTTONMAP = {0: 0, 1: 1, 2: 2, 4: 3, 8: 4, 16: 5}
    497     native=ev,
    498     pos=_get_event_xy(ev),
    499     button=BUTTONMAP.get(ev.button(), 0),
    500     modifiers=self._modifiers(ev),
    501 )

File ~\.conda\envs\napari_lattice\lib\site-packages\vispy\app\base.py:184, in BaseCanvasBackend._vispy_mouse_press(self=<vispy.app.backends._qt.CanvasBackendDesktop object>, **kwargs={'button': 1, 'buttons': [], 'last_event': <MouseEvent blocked=False button=None buttons=[]...urces=[] time=1729845941.0053525 type=mouse_move>, 'last_mouse_press': None, 'modifiers': (), 'native': <PyQt5.QtGui.QMouseEvent object>, 'pos': (337, 244), 'press_event': None})
    181 def _vispy_mouse_press(self, **kwargs):
    182     # default method for delivering mouse press events to the canvas
    183     kwargs.update(self._vispy_mouse_data)
--> 184     ev = self._vispy_canvas.events.mouse_press(**kwargs)
        self._vispy_canvas.events.mouse_press = <vispy.util.event.EventEmitter object at 0x0000020FA2BEF010>
        kwargs = {'native': <PyQt5.QtGui.QMouseEvent object at 0x0000020FA2BE5A20>, 'pos': (337, 244), 'button': 1, 'modifiers': (), 'buttons': [], 'press_event': None, 'last_event': <MouseEvent blocked=False button=None buttons=[] delta=[0. 0.] handled=False is_dragging=False last_event=MouseEvent modifiers=() native=<PyQt5.QtGui.QMouseEvent object at 0x0000020FA2BE5A20> pos=[337 244] press_event=None source=None sources=[] time=1729845941.0053525 type=mouse_move>, 'last_mouse_press': None}
        self = <vispy.app.backends._qt.CanvasBackendDesktop object at 0x0000020FA2BF8CA0>
        self._vispy_canvas.events = <vispy.util.event.EmitterGroup object at 0x0000020FA2BEEF20>
        self._vispy_canvas = <VispyCanvas (PyQt5) at 0x20fa2bea230>
    185     if self._vispy_mouse_data['press_event'] is None:
    186         self._vispy_mouse_data['press_event'] = ev

File ~\.conda\envs\napari_lattice\lib\site-packages\vispy\util\event.py:453, in EventEmitter.__call__(self=<vispy.util.event.EventEmitter object>, *args=(), **kwargs={'button': 1, 'buttons': [], 'last_event': <MouseEvent blocked=False button=None buttons=[]...urces=[] time=1729845941.0053525 type=mouse_move>, 'last_mouse_press': None, 'modifiers': (), 'native': <PyQt5.QtGui.QMouseEvent object>, 'pos': (337, 244), 'press_event': None})
    450 if self._emitting > 1:
    451     raise RuntimeError('EventEmitter loop detected!')
--> 453 self._invoke_callback(cb, event)
        event = <MouseEvent blocked=False button=1 buttons=[1] delta=[0. 0.] handled=False is_dragging=False last_event=MouseEvent modifiers=() native=<PyQt5.QtGui.QMouseEvent object at 0x0000020FA2BE5A20> pos=[337 244] press_event=None source=None sources=[] time=1729845941.1405299 type=mouse_press>
        self = <vispy.util.event.EventEmitter object at 0x0000020FA2BEF010>
        cb = <bound method QtViewer.on_mouse_press of <napari._qt.qt_viewer.QtViewer object at 0x0000020FA2BE56C0>>
    454 if event.blocked:
    455     break

File ~\.conda\envs\napari_lattice\lib\site-packages\vispy\util\event.py:471, in EventEmitter._invoke_callback(self=<vispy.util.event.EventEmitter object>, cb=<bound method QtViewer.on_mouse_press of <napari._qt.qt_viewer.QtViewer object>>, event=<MouseEvent blocked=False button=1 buttons=[1] d...rces=[] time=1729845941.1405299 type=mouse_press>)
    469     cb(event)
    470 except Exception:
--> 471     _handle_exception(self.ignore_callback_errors,
        self = <vispy.util.event.EventEmitter object at 0x0000020FA2BEF010>
        cb = <bound method QtViewer.on_mouse_press of <napari._qt.qt_viewer.QtViewer object at 0x0000020FA2BE56C0>>
        event = <MouseEvent blocked=False button=1 buttons=[1] delta=[0. 0.] handled=False is_dragging=False last_event=MouseEvent modifiers=() native=<PyQt5.QtGui.QMouseEvent object at 0x0000020FA2BE5A20> pos=[337 244] press_event=None source=None sources=[] time=1729845941.1405299 type=mouse_press>
        (cb, event) = (<bound method QtViewer.on_mouse_press of <napari._qt.qt_viewer.QtViewer object at 0x0000020FA2BE56C0>>, <MouseEvent blocked=False button=1 buttons=[1] delta=[0. 0.] handled=False is_dragging=False last_event=MouseEvent modifiers=() native=<PyQt5.QtGui.QMouseEvent object at 0x0000020FA2BE5A20> pos=[337 244] press_event=None source=None sources=[] time=1729845941.1405299 type=mouse_press>)
    472                       self.print_callback_errors,
    473                       self, cb_event=(cb, event))

File ~\.conda\envs\napari_lattice\lib\site-packages\vispy\util\event.py:469, in EventEmitter._invoke_callback(self=<vispy.util.event.EventEmitter object>, cb=<bound method QtViewer.on_mouse_press of <napari._qt.qt_viewer.QtViewer object>>, event=<MouseEvent blocked=False button=1 buttons=[1] d...rces=[] time=1729845941.1405299 type=mouse_press>)
    467 def _invoke_callback(self, cb, event):
    468     try:
--> 469         cb(event)
        cb = <bound method QtViewer.on_mouse_press of <napari._qt.qt_viewer.QtViewer object at 0x0000020FA2BE56C0>>
        event = <MouseEvent blocked=False button=1 buttons=[1] delta=[0. 0.] handled=False is_dragging=False last_event=MouseEvent modifiers=() native=<PyQt5.QtGui.QMouseEvent object at 0x0000020FA2BE5A20> pos=[337 244] press_event=None source=None sources=[] time=1729845941.1405299 type=mouse_press>
    470     except Exception:
    471         _handle_exception(self.ignore_callback_errors,
    472                           self.print_callback_errors,
    473                           self, cb_event=(cb, event))

File ~\.conda\envs\napari_lattice\lib\site-packages\napari\_qt\qt_viewer.py:1201, in QtViewer.on_mouse_press(self=<napari._qt.qt_viewer.QtViewer object>, event=<MouseEvent blocked=False button=1 buttons=[1] d...rces=[] time=1729845941.1405299 type=mouse_press>)
   1193 def on_mouse_press(self, event):
   1194     """Called whenever mouse pressed in canvas.
   1195
   1196     Parameters
   (...)
   1199         The vispy event that triggered this method.
   1200     """
-> 1201     self._process_mouse_event(mouse_press_callbacks, event)
        event = <MouseEvent blocked=False button=1 buttons=[1] delta=[0. 0.] handled=False is_dragging=False last_event=MouseEvent modifiers=() native=<PyQt5.QtGui.QMouseEvent object at 0x0000020FA2BE5A20> pos=[337 244] press_event=None source=None sources=[] time=1729845941.1405299 type=mouse_press>
        self = <napari._qt.qt_viewer.QtViewer object at 0x0000020FA2BE56C0>

File ~\.conda\envs\napari_lattice\lib\site-packages\napari\_qt\qt_viewer.py:1160, in QtViewer._process_mouse_event(self=<napari._qt.qt_viewer.QtViewer object>, mouse_callbacks=<function mouse_press_callbacks>, event=<ReadOnlyWrapper at 0x0000020FB4395BC0 for MouseEvent>)
   1158 layer = self.viewer.layers.selection.active
   1159 if layer is not None:
-> 1160     mouse_callbacks(layer, event)
        event = <ReadOnlyWrapper at 0x0000020FB4395BC0 for MouseEvent at 0x0000020FB41D5C60>
        layer = <Shapes layer 'Shapes' at 0x20fa3290f10>
        mouse_callbacks = <function mouse_press_callbacks at 0x0000020FA044DC60>

File ~\.conda\envs\napari_lattice\lib\site-packages\napari\utils\interactions.py:125, in mouse_press_callbacks(obj=<Shapes layer 'Shapes'>, event=<ReadOnlyWrapper at 0x0000020FB4395BC0 for MouseEvent>)
    123 if inspect.isgenerator(gen):
    124     try:
--> 125         next(gen)
        gen = <generator object add_rectangle at 0x0000020FA317E3B0>
    126         # now store iterated genenerator
    127         obj._mouse_drag_gen[mouse_drag_func] = gen

File ~\.conda\envs\napari_lattice\lib\site-packages\napari\layers\shapes\_shapes_mouse_bindings.py:233, in add_rectangle(layer=<Shapes layer 'Shapes'>, event=<ReadOnlyWrapper at 0x0000020FB4395BC0 for MouseEvent>)
    228 corner = np.array(coordinates)
    229 data = np.array(
    230     [corner, corner + size_v, corner + size_h + size_v, corner + size_h]
    231 )
--> 233 yield from _add_line_rectangle_ellipse(
        data = <class 'numpy.ndarray'> (4, 4) float64
        layer = <Shapes layer 'Shapes' at 0x20fa3290f10>
        event = <ReadOnlyWrapper at 0x0000020FB4395BC0 for MouseEvent at 0x0000020FB41D5C60>
    234     layer, event, data=data, shape_type='rectangle'
    235 )

File ~\.conda\envs\napari_lattice\lib\site-packages\napari\layers\shapes\_shapes_mouse_bindings.py:260, in _add_line_rectangle_ellipse(layer=<Shapes layer 'Shapes'>, event=<ReadOnlyWrapper at 0x0000020FB4395BC0 for MouseEvent>, data=<class 'numpy.ndarray'> (4, 4) float64, shape_type='rectangle')
    258 layer._value = (layer.nshapes - 1, 4)
    259 layer._moving_value = copy(layer._value)
--> 260 layer.refresh()
        layer = <Shapes layer 'Shapes' at 0x20fa3290f10>
    261 yield
    263 # on move

File ~\.conda\envs\napari_lattice\lib\site-packages\napari\layers\base\base.py:1300, in Layer.refresh(self=<Shapes layer 'Shapes'>, event=None)
   1298 self.events.set_data()
   1299 self._update_thumbnail()
-> 1300 self._set_highlight(force=True)
        self = <Shapes layer 'Shapes' at 0x20fa3290f10>

File ~\.conda\envs\napari_lattice\lib\site-packages\napari\layers\shapes\shapes.py:2542, in Shapes._set_highlight(self=<Shapes layer 'Shapes'>, force=True)
   2540 self._value_stored = copy(self._value)
   2541 self._drag_box_stored = copy(self._drag_box)
-> 2542 self.events.highlight()
        self = <Shapes layer 'Shapes' at 0x20fa3290f10>
        self.events.highlight = <napari.utils.events.event.EventEmitter object at 0x0000020FB3F72CE0>
        self.events = <napari.utils.events.event.EmitterGroup object at 0x0000020FA338DF30>

File ~\.conda\envs\napari_lattice\lib\site-packages\napari\utils\events\event.py:763, in EventEmitter.__call__(self=<napari.utils.events.event.EventEmitter object>, *args=(), **kwargs={})
    760     self._block_counter.update([cb])
    761     continue
--> 763 self._invoke_callback(cb, event if pass_event else None)
        event = <Event blocked=False handled=False native=None source=None sources=[] type='highlight'>
        self = <napari.utils.events.event.EventEmitter object at 0x0000020FB3F72CE0>
        cb = <bound method ShapeSelector._on_selection_change of <napari_lattice.shape_selector.ShapeSelector object at 0x0000020FB05A08E0>>
        pass_event = True
    764 if event.blocked:
    765     break

File ~\.conda\envs\napari_lattice\lib\site-packages\napari\utils\events\event.py:801, in EventEmitter._invoke_callback(self=<napari.utils.events.event.EventEmitter object>, cb=<bound method ShapeSelector._on_selection_change...ari_lattice.shape_selector.ShapeSelector object>>, event=<Event blocked=False handled=False native=None source=None sources=[] type='highlight'>)
    799     self.disconnect(cb)
    800     return
--> 801 _handle_exception(
        self = <napari.utils.events.event.EventEmitter object at 0x0000020FB3F72CE0>
        event = <Event blocked=False handled=False native=None source=None sources=[] type='highlight'>
        cb = <bound method ShapeSelector._on_selection_change of <napari_lattice.shape_selector.ShapeSelector object at 0x0000020FB05A08E0>>
        (cb, event) = (<bound method ShapeSelector._on_selection_change of <napari_lattice.shape_selector.ShapeSelector object at 0x0000020FB05A08E0>>, <Event blocked=False handled=False native=None source=None sources=[] type='highlight'>)
    802     self.ignore_callback_errors,
    803     self.print_callback_errors,
    804     self,
    805     cb_event=(cb, event),
    806 )

File ~\.conda\envs\napari_lattice\lib\site-packages\napari\utils\events\event.py:788, in EventEmitter._invoke_callback(self=<napari.utils.events.event.EventEmitter object>, cb=<bound method ShapeSelector._on_selection_change...ari_lattice.shape_selector.ShapeSelector object>>, event=<Event blocked=False handled=False native=None source=None sources=[] type='highlight'>)
    786 try:
    787     if event is not None:
--> 788         cb(event)
        event = <Event blocked=False handled=False native=None source=None sources=[] type='highlight'>
        cb = <bound method ShapeSelector._on_selection_change of <napari_lattice.shape_selector.ShapeSelector object at 0x0000020FB05A08E0>>
    789     else:
    790         cb()

File ~\multimeric\napari_lattice\plugin\napari_lattice\shape_selector.py:88, in ShapeSelector._on_selection_change(self=<napari_lattice.shape_selector.ShapeSelector object>, event=<Event blocked=False handled=False native=None source=None sources=[] type='highlight'>)
     86 for index in source.selected_data:
     87     selection.append(Shape(layer=source, index=index))
---> 88 self.shapes.value = selection
        selection = [Shape(layer=<Shapes layer 'Shapes' at 0x20fa3290f10>, index=0)]
        self = <napari_lattice.shape_selector.ShapeSelector object at 0x0000020FB05A08E0>

File ~\.conda\envs\napari_lattice\lib\site-packages\magicgui\widgets\bases\_categorical_widget.py:71, in CategoricalWidget.value(self=Select(value=[], annotation=None, name='shapes'), value=[Shape(layer=<Shapes layer 'Shapes' at 0x20fa3290f10>, index=0)])
     69 if isinstance(value, (list, tuple)) and self._allow_multiple:
     70     if any(v not in self.choices for v in value):
---> 71         raise ValueError(
        value = [Shape(layer=<Shapes layer 'Shapes' at 0x20fa3290f10>, index=0)]
        self = Select(value=[], annotation=None, name='shapes')
     72             f"{value!r} is not a valid choice. must be in {self.choices}"
     73         )
     74 elif value not in self.choices:
     75     raise ValueError(
     76         f"{value!r} is not a valid choice. must be in {self.choices}"
     77     )

ValueError: [Shape(layer=<Shapes layer 'Shapes' at 0x20fa3290f10>, index=0)] is not a valid choice. must be in ()


I can draw ROIs after this without any issues, but I have 2 errors:

  • the roi selection in the gui does not update as I click the rois.
  • when I click Preview, I get:
    image

with traceback:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
File ~\.conda\envs\nap_lat_test\lib\site-packages\napari_lattice\dock_widget.py:162, in LLSZWidget.preview(self=<napari_lattice.dock_widget.LLSZWidget object>, header='', time=0, channel=0)
    159     previews = lattice.process_workflow().roi_previews()
    161 for preview in previews:
--> 162     self.parent_viewer.add_image(preview, scale=scale, name="Napari Lattice Preview")
        scale = (0.14999999999999997, 0.14499219272808386, 0.14499219272808386)
        preview = <class 'numpy.ndarray'> (70, 0, 0) float32
        self = <napari_lattice.dock_widget.LLSZWidget object at 0x00000244684DF280>
    163     max_z = np.argmax(np.sum(preview, axis=(1, 2)))
    164     self.parent_viewer.dims.set_current_step(0, max_z)

File ~\.conda\envs\nap_lat_test\lib\site-packages\napari\utils\migrations.py:101, in rename_argument.<locals>._wrapper.<locals>._update_from_dict(*args=(Viewer(camera=Camera(center=(0.0, 83.87798349319...use_drag_gen={}, _mouse_wheel_gen={}, _keymap={}), <class 'numpy.ndarray'> (70, 0, 0) float32), **kwargs={'name': 'Napari Lattice Preview', 'scale': (0.14999999999999997, 0.14499219272808386, 0.14499219272808386)})
     99     kwargs = kwargs.copy()
    100     kwargs[to_name] = kwargs.pop(from_name)
--> 101 return func(*args, **kwargs)
        func = <function ViewerModel.add_image at 0x000002445BFC3520>
        kwargs = {'scale': (0.14999999999999997, 0.14499219272808386, 0.14499219272808386), 'name': 'Napari Lattice Preview'}
        args = (Viewer(camera=Camera(center=(0.0, 83.87798349319651, 107.80169529333034), zoom=3.4521695616211745, angles=(0.0, 0.0, 90.0), perspective=0.0, mouse_pan=False, mouse_zoom=True), cursor=Cursor(position=(34.0, 6.149999999999999, 70.84270016075888, 208.8975347059132), scaled=True, style=<CursorStyle.CROSS: 'cross'>, size=1.0), dims=Dims(ndim=4, ndisplay=2, order=(0, 1, 2, 3), axis_labels=('0', '1', '2', '3'), rollable=(True, True, True, True), range=(RangeTuple(start=0.0, stop=99.0, step=1.0), RangeTuple(start=0.0, stop=150.0, step=0.14999999999999997), RangeTuple(start=0.0, stop=167.75596698639302, step=0.14499219272808386), RangeTuple(start=0.0, stop=215.6033905866607, step=0.14499219272808386)), margin_left=(0.0, 0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0, 0.0), point=(34.0, 6.149999999999999, 10.004461298237787, 107.7291991969663), last_used=1), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[<Image layer 'RAPA_treated-01_resaved_c02_t_100' at 0x2446a06d9f0>, <Image layer 'Napari Lattice Preview' at 0x2446962d030>, <Shapes layer 'Shapes' at 0x2445da50850>], help='use <6> for pan/zoom, use <7> for transform, use <E> for add ellipses, use <L> for add lines, use <T> for add path, use <P> for add polygons, use <Shift+P> for add polygons lasso, use <4> for select vertices, use <5> for select shapes, use <2> for insert vertex, use <1> for remove vertex', status='', tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_over_canvas=False, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[], mouse_wheel_callbacks=[<function dims_scroll at 0x000002445BF555A0>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={}), <class 'numpy.ndarray'> (70, 0, 0) float32)

File ~\.conda\envs\nap_lat_test\lib\site-packages\napari\components\viewer_model.py:995, in ViewerModel.add_image(self=Viewer(camera=Camera(center=(0.0, 83.87798349319...use_drag_gen={}, _mouse_wheel_gen={}, _keymap={}), data=<class 'numpy.ndarray'> (70, 0, 0) float32, channel_axis=None, affine=None, axis_labels=None, attenuation=0.05, blending=None, cache=True, colormap=None, contrast_limits=None, custom_interpolation_kernel_2d=None, depiction='volume', experimental_clipping_planes=None, gamma=1.0, interpolation2d='nearest', interpolation3d='linear', iso_threshold=None, metadata=None, multiscale=None, name='Napari Lattice Preview', opacity=1.0, plane=None, projection_mode='none', rendering='mip', rgb=None, rotate=None, scale=(0.14999999999999997, 0.14499219272808386, 0.14499219272808386), shear=None, translate=None, units=None, visible=True)
    987     if k not in iterable_kwargs and is_sequence(v):
    988         raise TypeError(
    989             trans._(
    990                 "Received sequence for argument '{argument}', did you mean to specify a 'channel_axis'? ",
   (...)
    993             )
    994         )
--> 995 layer = Image(data, **kwargs)
        kwargs = {'rgb': None, 'axis_labels': None, 'colormap': 'gray', 'contrast_limits': None, 'gamma': 1.0, 'interpolation2d': 'nearest', 'interpolation3d': 'linear', 'rendering': 'mip', 'depiction': 'volume', 'iso_threshold': None, 'attenuation': 0.05, 'name': 'Napari Lattice Preview', 'metadata': None, 'scale': (0.14999999999999997, 0.14499219272808386, 0.14499219272808386), 'translate': None, 'rotate': None, 'shear': None, 'affine': None, 'opacity': 1.0, 'blending': 'translucent_no_depth', 'visible': True, 'multiscale': None, 'cache': True, 'plane': None, 'experimental_clipping_planes': None, 'custom_interpolation_kernel_2d': None, 'projection_mode': 'none', 'units': None}
        data = <class 'numpy.ndarray'> (70, 0, 0) float32
        Image = <class 'napari.layers.image.image.Image'>
    996 self.layers.append(layer)
    998 return layer

File ~\.conda\envs\nap_lat_test\lib\site-packages\napari\layers\base\base.py:114, in PostInit.__call__(self=<class 'napari.layers.image.image.Image'>, *args=(<class 'numpy.ndarray'> (70, 0, 0) float32,), **kwargs={'affine': None, 'attenuation': 0.05, 'axis_labels': None, 'blending': 'translucent_no_depth', 'cache': True, 'colormap': 'gray', 'contrast_limits': None, 'custom_interpolation_kernel_2d': None, 'depiction': 'volume', 'experimental_clipping_planes': None, ...})
    113 def __call__(self, *args, **kwargs):
--> 114     obj = super().__call__(*args, **kwargs)
        args = (<class 'numpy.ndarray'> (70, 0, 0) float32,)
        kwargs = {'rgb': None, 'axis_labels': None, 'colormap': 'gray', 'contrast_limits': None, 'gamma': 1.0, 'interpolation2d': 'nearest', 'interpolation3d': 'linear', 'rendering': 'mip', 'depiction': 'volume', 'iso_threshold': None, 'attenuation': 0.05, 'name': 'Napari Lattice Preview', 'metadata': None, 'scale': (0.14999999999999997, 0.14499219272808386, 0.14499219272808386), 'translate': None, 'rotate': None, 'shear': None, 'affine': None, 'opacity': 1.0, 'blending': 'translucent_no_depth', 'visible': True, 'multiscale': None, 'cache': True, 'plane': None, 'experimental_clipping_planes': None, 'custom_interpolation_kernel_2d': None, 'projection_mode': 'none', 'units': None}
    115     obj._post_init()
    116     return obj

File ~\.conda\envs\nap_lat_test\lib\site-packages\napari\utils\migrations.py:101, in rename_argument.<locals>._wrapper.<locals>._update_from_dict(*args=(<Image layer 'Napari Lattice Preview'>, <class 'numpy.ndarray'> (70, 0, 0) float32), **kwargs={'affine': None, 'attenuation': 0.05, 'axis_labels': None, 'blending': 'translucent_no_depth', 'cache': True, 'colormap': 'gray', 'contrast_limits': None, 'custom_interpolation_kernel_2d': None, 'depiction': 'volume', 'experimental_clipping_planes': None, ...})
     99     kwargs = kwargs.copy()
    100     kwargs[to_name] = kwargs.pop(from_name)
--> 101 return func(*args, **kwargs)
        func = <function Image.__init__ at 0x000002445AAD8040>
        kwargs = {'rgb': None, 'axis_labels': None, 'colormap': 'gray', 'contrast_limits': None, 'gamma': 1.0, 'interpolation2d': 'nearest', 'interpolation3d': 'linear', 'rendering': 'mip', 'depiction': 'volume', 'iso_threshold': None, 'attenuation': 0.05, 'name': 'Napari Lattice Preview', 'metadata': None, 'scale': (0.14999999999999997, 0.14499219272808386, 0.14499219272808386), 'translate': None, 'rotate': None, 'shear': None, 'affine': None, 'opacity': 1.0, 'blending': 'translucent_no_depth', 'visible': True, 'multiscale': None, 'cache': True, 'plane': None, 'experimental_clipping_planes': None, 'custom_interpolation_kernel_2d': None, 'projection_mode': 'none', 'units': None}
        args = (<Image layer 'Napari Lattice Preview' at 0x244c243c490>, <class 'numpy.ndarray'> (70, 0, 0) float32)

File ~\.conda\envs\nap_lat_test\lib\site-packages\napari\layers\image\image.py:320, in Image.__init__(self=<Image layer 'Napari Lattice Preview'>, data=<class 'numpy.ndarray'> (70, 0, 0) float32, affine=None, attenuation=0.05, axis_labels=None, blending='translucent_no_depth', cache=True, colormap='gray', contrast_limits=None, custom_interpolation_kernel_2d=None, depiction='volume', experimental_clipping_planes=None, gamma=1.0, interpolation2d='nearest', interpolation3d='linear', iso_threshold=None, metadata=None, multiscale=None, name='Napari Lattice Preview', opacity=1.0, plane=None, projection_mode='none', rendering='mip', rgb=False, rotate=None, scale=(0.14999999999999997, 0.14499219272808386, 0.14499219272808386), shear=None, translate=None, units=None, visible=True)
    318         self._should_calc_clims = dtype != np.uint8
    319     else:
--> 320         self.contrast_limits_range = self._calc_data_range()
        self = <Image layer 'Napari Lattice Preview' at 0x244c243c490>
    321 else:
    322     self.contrast_limits_range = contrast_limits

File ~\.conda\envs\nap_lat_test\lib\site-packages\napari\layers\image\image.py:647, in Image._calc_data_range(self=<Image layer 'Napari Lattice Preview'>, mode='data')
    639 else:
    640     raise ValueError(
    641         trans._(
    642             "mode must be either 'data' or 'slice', got {mode!r}",
   (...)
    645         )
    646     )
--> 647 return calc_data_range(
        input_data = <class 'numpy.ndarray'> (70, 0, 0) float32
        LayerDataProtocol = <class 'napari.layers._data_protocols.LayerDataProtocol'>
        self.rgb = False
        self = <Image layer 'Napari Lattice Preview' at 0x244c243c490>
    648     cast(LayerDataProtocol, input_data), rgb=self.rgb
    649 )

File ~\.conda\envs\nap_lat_test\lib\site-packages\napari\layers\utils\layer_utils.py:285, in calc_data_range(data=<class 'numpy.ndarray'> (70, 0, 0) float32, rgb=False)
    282 else:
    283     reduced_data = data
--> 285 min_val = _nanmin(reduced_data)
        reduced_data = <class 'numpy.ndarray'> (70, 0, 0) float32
    286 max_val = _nanmax(reduced_data)
    288 if min_val == max_val:

File ~\.conda\envs\nap_lat_test\lib\site-packages\napari\layers\utils\layer_utils.py:185, in _nanmin(array=<class 'numpy.ndarray'> (70, 0, 0) float32)
    181 def _nanmin(array):
    182     """
    183     call np.min but fall back to avoid nan and inf if necessary
    184     """
--> 185     min_value = np.min(array)
        np.min = <function amin at 0x000002447EFFE7A0>
        array = <class 'numpy.ndarray'> (70, 0, 0) float32
        np = <module 'numpy' from 'C:\\Users\\Pradeep\\.conda\\envs\\nap_lat_test\\lib\\site-packages\\numpy\\__init__.py'>
    186     if not np.isfinite(min_value):
    187         masked = array[np.isfinite(array)]

File <__array_function__ internals>:200, in amin(*args=(<class 'numpy.ndarray'> (70, 0, 0) float32,), **kwargs={})

File ~\.conda\envs\nap_lat_test\lib\site-packages\numpy\core\fromnumeric.py:2946, in amin(a=<class 'numpy.ndarray'> (70, 0, 0) float32, axis=None, out=None, keepdims=<no value>, initial=<no value>, where=<no value>)
   2829 @array_function_dispatch(_amin_dispatcher)
   2830 def amin(a, axis=None, out=None, keepdims=np._NoValue, initial=np._NoValue,
   2831          where=np._NoValue):
   2832     """
   2833     Return the minimum of an array or minimum along an axis.
   2834 
   (...)
   2944     6
   2945     """
-> 2946     return _wrapreduction(a, np.minimum, 'min', axis, None, out,
        np = <module 'numpy' from 'C:\\Users\\Pradeep\\.conda\\envs\\nap_lat_test\\lib\\site-packages\\numpy\\__init__.py'>
        a = <class 'numpy.ndarray'> (70, 0, 0) float32
        np.minimum = <ufunc 'minimum'>
        axis = None
        out = None
        keepdims = <no value>
        initial = <no value>
        where = <no value>
   2947                           keepdims=keepdims, initial=initial, where=where)

File ~\.conda\envs\nap_lat_test\lib\site-packages\numpy\core\fromnumeric.py:86, in _wrapreduction(obj=<class 'numpy.ndarray'> (70, 0, 0) float32, ufunc=<ufunc 'minimum'>, method='min', axis=None, dtype=None, out=None, **kwargs={'initial': <no value>, 'keepdims': <no value>, 'where': <no value>})
     83         else:
     84             return reduction(axis=axis, out=out, **passkwargs)
---> 86 return ufunc.reduce(obj, axis, dtype, out, **passkwargs)
        passkwargs = {}
        obj = <class 'numpy.ndarray'> (70, 0, 0) float32
        axis = None
        dtype = None
        out = None
        ufunc = <ufunc 'minimum'>

ValueError: zero-size array to reduction operation minimum which has no identity

@multimeric
Copy link
Collaborator Author

If I create a Shapes layer manually and click mouse button to draw an ROI, I get an error with the following traceback

Hmm, I'm struggling to reproduce this. Can you maybe take a screenshot when it happens, and also list the minimal actions you have to take beforehand to trigger this issue?

@pr4deepr
Copy link
Collaborator

shape_selector.mp4

@pr4deepr
Copy link
Collaborator

  • Open file
  • Select file in Deskew tab
  • Preview Deskew and perform a maximum projection to get a 2D image to use for drawing rois

--
First part of the video

  • Enable Crop
  • Create Shapes Layer manually and attempt to draw regions
  • Get error when drawing first roi

--
Second part of the video

-Create SHapes layer via New Crop

  • Draw ROIs

The ROI selection doesn't work, but cropping works based on selection

@pr4deepr
Copy link
Collaborator

If I import an ImageJ/Fiji ROIManager file, it works fine. The selected ROI is highlighted and cropping works..

shape_selector_import_roimanager.mp4

@multimeric
Copy link
Collaborator Author

Hmm, I still can't reproduce this even with the same steps. Does the image have any unique properties?

@pr4deepr
Copy link
Collaborator

I tried with different images actually.
Maybe I'll reinstall and try again

@pr4deepr
Copy link
Collaborator

pr4deepr commented Nov 2, 2024

Btw, did you try it on a Windows PC?

@pr4deepr
Copy link
Collaborator

pr4deepr commented Nov 4, 2024

So, I'm still getting the error.
The manually drawing shapes layer error only happens after I start the plugin

Also, I didn't open any images either

test.mp4

napari info:


napari: 0.4.19.post1
Platform: Windows-10-10.0.27729-SP0
Python: 3.10.15 | packaged by conda-forge | (main, Oct 16 2024, 01:15:49) [MSC v.1941 64 bit (AMD64)]
Qt: 5.15.8
PyQt5: 5.15.9
NumPy: 1.24.0
SciPy: 1.14.1
Dask: 2023.5.0
VisPy: 0.14.3
magicgui: 0.7.3
superqt: 0.6.7
in-n-out: 0.2.1
app-model: 0.2.8
npe2: 0.7.7

OpenGL:
- GL version: 4.6.0 NVIDIA 560.94
- MAX_TEXTURE_SIZE: 32768

Screens:
- screen 1: resolution 3840x1600, scale 1.0

Settings path:
- C:\Users\Pradeep\AppData\Local\napari\nap_latt_test1_ac39642951bb6a9d189528a809ab5d9219680290\settings.yaml

@multimeric
Copy link
Collaborator Author

Okay, I think I've fixed this issue on Windows. I've tested it on the VM as well.

@multimeric
Copy link
Collaborator Author

ValueError: zero-size array to reduction operation minimum which has no identity

I can't replicate this on the latest commit. Let me know if it's still there when you next test this.

@pr4deepr
Copy link
Collaborator

I can confirm its working now and the cropping works perfectly as well.
Happy for this to be merged!

@multimeric multimeric merged commit baaec71 into BioimageAnalysisCoreWEHI:master Nov 17, 2024
5 checks passed
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.

Better ROI selection UI
2 participants