napari: Error when returning named shapes/surface layer multiple times (Dock widget)
Running a dock widget multiple times (i.e. pressing the call_button
) will cause an error with named shapes
(and also surface
, not shown) output layers.
Code
Minimal dock widget to reproduce the issue.
@magic_factory(call_button=True)
def widget() -> List[napari.types.LayerDataTuple]:
polygons = [np.array([[11, 13], [111, 113], [22, 246]])]
# return [(polygons, dict(shape_type='polygon'), 'shapes')] # this works
return [(polygons, dict(name='Test', shape_type='polygon'), 'shapes')]
@napari_hook_implementation
def napari_experimental_provide_dock_widget():
return widget
Expected behavior
Not to throw an error. Would have expected that the layer is either replaced (as happens for image
and labels
layers) or a new layer is added with a name suffix (e.g. Test [1]
) as happens if the layer is not named.
Environment
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 23 (21 by maintainers)
I like this, I think it makes the most sense.
I think this is a reasonable approach to fix the use case and provide more flexibility overall, and I think the
List[Tuple(Array, str)]
is quite readable as well. @jni ?I think i’d probably keep it, and inside the data setter split out the shape type so that
layer.shape_type
is always returnsList[str]
andlayer.data
always returnsList[Array]
. If something is passed tolayer.data
then it overwrites anything inlayer.shape_type
.Note in the motivating example above you’d need to now do
which doesn’t look too bad to me …
Another thought is that we should swap the order of line 180 and the for loop lines (181, 182) here https://github.com/napari/napari/blob/102a7e8f845893c874d2b86f9371d41130100b89/napari/utils/_magicgui.py#L180
and then if we additionally go with the approach I propose above
and the optional tuple, then
return [(polygons, dict(name='Test', shape_type='polygon'), 'shapes')]
will just work without extra thought, and all the special cases can be handled.I know this discussion has gotten quite involved now, but I do see a way forward that will fix this use case, allow for additional flexibility, and be mostly backwards compatible
@sofroniewn on it now
Yes I think so, combined with #2507
all clear from me! 😊
We do have an internal shape object already (right now is also contains the dims to be displayed, which we’ll want to change) https://github.com/napari/napari/blob/master/napari/layers/shapes/_shapes_models/shape.py
I was imagining
Array | Tuple(Array, str) | List[Array | Tuple(Array, str)] | Tuple(List[Array], str)
as the full set of allowed inputs. I think this would be the most minimal and backwards compatible change we could make. Currently we supportArray | List[Array]
and I don’t think we’d want to loose that.I also think most users will have a single shape type per layer most of the time, and we don’t want to make things unnecessarily hard for them
Looks like something funky is definitely happening, the error message “three vertices to a rectangle” is relatively deep in the code, not quite sure what would have caused that. We’ll look into it.