napari-spatialdata
napari-spatialdata copied to clipboard
Issues reproducing annotation notebooks
I've been trying to reproduce the two annotation notebooks from the spatialdata tutorials, and am running into different issues with both of them:
I tried reproducing this one as described and shown in the gif, but when I add a new points layer and press SHIFT+E nothing happens. When I afterwards inspect the SpatialData object, it appears unchanged. Any guidance on how to further debug this would be appreciated.
When I instead annotate a shapes layer as shown in the second notebook and press SHIFT+E, I get an error with a long traceback, the last four entries of which are:
File ~/src/napari-3.10/venv/lib/python3.10/site-packages/napari/utils/key_bindings.py:545, in KeymapHandler.on_key_press(self=<napari.utils.key_bindings.KeymapHandler object>, event=<KeyEvent blocked=False handled=False key=<Key '...c0> source=None sources=[] text=E type=key_press>)
535 if (
536 event.native is not None
537 and event.native.isAutoRepeat()
(...)
541 # unless the combo being held down is one of the autorepeatables or
542 # one of the navigation keys (helps with scrolling).
543 return
--> 545 self.press_key(combo)
combo = 'Shift-E'
self = <napari.utils.key_bindings.KeymapHandler object at 0x2a324d300>
File ~/src/napari-3.10/venv/lib/python3.10/site-packages/napari/utils/key_bindings.py:470, in KeymapHandler.press_key(self=<napari.utils.key_bindings.KeymapHandler object>, key_combo='Shift-E')
461 if not callable(func):
462 raise TypeError(
463 trans._(
464 "expected {func} to be callable",
(...)
467 )
468 )
--> 470 generator_or_callback = func()
func = <bound method QtAdataViewWidget.export of Viewer(camera=Camera(center=(0.0, 10785.0, 9752.0), zoom=0.046125222806246056, angles=(0.0, 0.0, 90.0), perspective=0.0, mouse_pan=False, mouse_zoom=True), cursor=Cursor(position=(20519.370711726915, 18857.64737205759), scaled=True, size=1, style=<CursorStyle.CROSS: 'cross'>), dims=Dims(ndim=2, ndisplay=2, last_used=0, range=((0.0, 21571.0, 1.0), (0.0, 19505.0, 1.0)), current_step=(10785, 9752), order=(0, 1), axis_labels=('0', '1')), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[<Image layer 'CytAssist_FFPE_Human_Breast_Cancer_full_image' at 0x3129f5060>, <Shapes layer 'Shapes' at 0x311fe9210>], help='use <6> for pan/zoom, use <2> for transform, use <R> for add rectangles, 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={'layer_base': 'Shapes', 'source_type': '', 'plugin': '', 'coordinates': ' [20519 18858]: [, ]'}, tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_over_canvas=True, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[], mouse_wheel_callbacks=[<function dims_scroll at 0x2a13311b0>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, keymap={'Shift-L': <bound method SpatialDataViewer._inherit_metadata of <napari_spatialdata._viewer.SpatialDataViewer object at 0x2c7e44a30>>, 'Shift-E': <bound method QtAdataViewWidget.export of <napari_spatialdata._view.QtAdataViewWidget object at 0x2c7b86c20>>})>
472 if inspect.isgeneratorfunction(func):
473 try:
File ~/src/napari-3.10/venv/lib/python3.10/site-packages/napari_spatialdata/_view.py:292, in QtAdataViewWidget.export(self=<napari_spatialdata._view.QtAdataViewWidget object>, _=Viewer(camera=Camera(center=(0.0, 10785.0, 9752...._view.QtAdataViewWidget object at 0x2c7b86c20>>}))
289 key = f"{layer.name}_{self.model.layer.name}" # type:ignore[union-attr]
291 logger.info(f"Adding `adata.obs[{key!r}]`\n `adata.uns[{key!r}]['mesh']`.")
--> 292 self._save_shapes(layer, key=key)
layer = <Shapes layer 'Shapes' at 0x311fe9210>
key = 'Shapes_Shapes'
self = <napari_spatialdata._view.QtAdataViewWidget object at 0x2c7b86c20>
293 self._update_obs_items(key)
File ~/src/napari-3.10/venv/lib/python3.10/site-packages/napari_spatialdata/_view.py:300, in QtAdataViewWidget._save_shapes(self=<napari_spatialdata._view.QtAdataViewWidget object>, layer=<Shapes layer 'Shapes'>, key='Shapes_Shapes')
297 triangles = shape_list._mesh.vertices[shape_list._mesh.displayed_triangles]
299 # TODO(giovp): check if view and save accordingly
--> 300 points_mask: NDArrayA = _points_inside_triangles(self.model.coordinates[:, 1:], triangles)
triangles = <class 'numpy.ndarray'> (894, 3, 2) float64
NDArrayA = numpy.ndarray[typing.Any, numpy.dtype[typing.Any]]
_points_inside_triangles = CPUDispatcher(<function _points_inside_triangles at 0x2a23de290>)
self = <napari_spatialdata._view.QtAdataViewWidget object at 0x2c7b86c20>
302 if self._model._adata is not None:
303 logger.info("Saving layer shapes.")
TypeError: 'NoneType' object is not subscriptable
I've tried both examples on various different python versions (3.9, 3.10, 3.11) and with different versions of the spatialdata and napari-spatialdata packages, including the latest pypi releases and github HEADs, and haven't been able to get it to work.
I'd greatly appreciate any help.
We are aware of the issue and this is the result of an old implementation which most likely within a week will be changed. I am opening a PR today. I'll keep you posted. We are ultimately looking to combine this with partial writes to disk.
I opened #168 as a draft. It does have a dependency on a PR currently being worked on in SpatialData.