Skip to content

Layer abstraction#12

Merged
kne42 merged 10 commits intonapari:masterfrom
kne42:layer-abstraction
Oct 23, 2018
Merged

Layer abstraction#12
kne42 merged 10 commits intonapari:masterfrom
kne42:layer-abstraction

Conversation

@kne42
Copy link
Copy Markdown
Member

@kne42 kne42 commented Oct 14, 2018

Introduces a standard for layers, a way to register them as convenience methods on Viewers, and a better programmatic management system.

  • layers must inherit from gui.layers.Layer and call super().__init__(visual_node) with their central/controlling visual node
  • layers must override methods _get_shape, _refresh, and property data
  • layers may override methods _set_view_slice, _after_set_viewer, and property _qt
  • add_* methods can be automatically added to Viewers by using the function/decorator gui.layers.add_to_viewer
  • gui.layers.LayerList provides a list-like interface to add and remove layers, as well as providing the swap and reorder methods to programmatically change the rendering order of layers

Note: ordering system used in this PR introduces an opacity-related bug: see vispy/vispy#1541

@pep8speaks
Copy link
Copy Markdown

pep8speaks commented Oct 14, 2018

Hello @kne42! Thanks for updating the PR.

Line 63:5: E301 expected 1 blank line, found 0
Line 64:5: E301 expected 1 blank line, found 0
Line 65:5: E301 expected 1 blank line, found 0
Line 66:5: E301 expected 1 blank line, found 0
Line 67:5: E301 expected 1 blank line, found 0

Line 76:17: E201 whitespace after '{'
Line 76:26: E203 whitespace before ':'
Line 76:32: E202 whitespace before '}'

Comment last updated on October 23, 2018 at 00:18 Hours UTC

@kne42 kne42 force-pushed the layer-abstraction branch from 1c1aea9 to dcbe887 Compare October 15, 2018 01:01
@royerloic
Copy link
Copy Markdown
Member

What if a layer does not define the notion of 'shape' -- that's very much an image-centric concept.
I would suggest that in that case, you simply ignore that layer for the purpose of computing the
max shape parameters... In general, pay attention to the generality of a layer's base properties,
an devise elegant strategies that address this. Luckily, many properties -- such as opacity -- exist for all layers...

@kne42
Copy link
Copy Markdown
Member Author

kne42 commented Oct 15, 2018

@royerloic Actually I would like to require some sort of required API that helps us determine the shape of the layer (perhaps even by slice but this may be costly in terms of memory) so that we can show a visual selection rectangle on the gui to allow users to move, scale, and rotate the visual.

@royerloic
Copy link
Copy Markdown
Member

Ok, makes sense. Maybe my question really is: what units do we have for 'shape' if the units is pixels of images that would work, assuming that we use the same units for the coordinates of other layers...
So, in fact if we think about a 'points' layer, you could set the shape to be (1000,1000) or (123,456), that would then help understand how to position the pints within a bounding box... But that also means that we need to know more that just with and height... We actually need (x, y, width, height) to be able to really make sense of the point coordinates -- note that (x,y) is a corner of the box.... Of course from that bounding box, the shape is trivially inferred. In most cases (x,y) will be (0,0), but it does not have to be (even in stacked mode! we want to keep the coordinates of the points relative to the box!). I am actually realising all this while I write.

Important: just as for image layers, other layers can have different shapes, but can be stacked together nevertheless, using the bounding box info...

@kne42
Copy link
Copy Markdown
Member Author

kne42 commented Oct 15, 2018

Ah, perhaps we should instead just require them to provide their ndims and some function that returns (x, y, width, height) given a set of indices (like in _set_view_slice)?

@royerloic
Copy link
Copy Markdown
Member

royerloic commented Oct 15, 2018 via email

@jni
Copy link
Copy Markdown
Member

jni commented Oct 15, 2018

why can't we infer the shape to be the min and max of the data? This should be super fast. If we want to allow offsets, we can add origin=(0,) * ndim as the default, but settable by new layers.

@royerloic
Copy link
Copy Markdown
Member

royerloic commented Oct 15, 2018 via email

@jni
Copy link
Copy Markdown
Member

jni commented Oct 15, 2018

Oh you mean because you are doing all this crazy resizing/moving around inside the canvas that I told you was a bad idea? =P

@royerloic
Copy link
Copy Markdown
Member

royerloic commented Oct 15, 2018 via email

@jni
Copy link
Copy Markdown
Member

jni commented Oct 15, 2018

Ok I'm gonna wait till our meeting to discuss since I feel some drawing is required. =)

@royerloic
Copy link
Copy Markdown
Member

royerloic commented Oct 15, 2018 via email

@kne42 kne42 force-pushed the layer-abstraction branch from 0a495ed to 4ee7754 Compare October 17, 2018 17:01
@kne42 kne42 changed the title WIP: Layer abstraction Layer abstraction Oct 18, 2018
@kne42 kne42 force-pushed the layer-abstraction branch 2 times, most recently from c9a8e3f to 0d455e6 Compare October 19, 2018 16:07
@kne42 kne42 force-pushed the layer-abstraction branch from 0d455e6 to dd4007a Compare October 19, 2018 16:15
@kne42 kne42 requested a review from a team October 19, 2018 21:49
@sofroniewn
Copy link
Copy Markdown
Contributor

I'm looking through the PR right now and ran into a problem not sure what I'm missing. When I run the following code the opacity and colormap changes work fine, but I get an error message when trying to change the clims. It's nice that when I change the opacity etc. the gui window automatically updates

window = gui.imshow(patch)
layer = window.layers[0]
layer.opacity = .5
layer.colormap = 'viridis'
layer.clim = (0,100)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-54-e8219f68bee2> in <module>()
      3 layer.opacity = .5
      4 layer.colormap = 'viridis'
----> 5 layer.clim = (0,100)

TypeError: clim() takes 1 positional argument but 2 were given

@kne42
Copy link
Copy Markdown
Member Author

kne42 commented Oct 20, 2018 via email

@sofroniewn
Copy link
Copy Markdown
Contributor

Thanks! No rush. I also think I've encountered the opacity bug you mentioned at the top of the thread, and saw your chats in vispy. Looks like it is being handled there

@sofroniewn
Copy link
Copy Markdown
Contributor

sofroniewn commented Oct 20, 2018

Is there a remove layer / delete layer function? Would be nice.

Also might be nice to be able to create an empty window, could be with something like window = gui.imshow()

Another thing that might be nice is if you pass a list of images window = gui.imshow([A, B]) then you get two layers with A and B inside them respectively

Also is it worth including the concept we talked about on thursday where if we call window=gui.imshow(A, layers=[2,3]) where dim(A)=5 say, then we'd get a collection of 3D images all as different layers. I guess an argument against this is that a simple reshape and list comprehension would generate a list of arrays that could then be passed to imshow if the behaviour in the above point is supported. A pro though is this is something people might want to do often for color-channel dimensions and it could be a convenience to do it inside imshow. I can really see it both ways.

Also unclear to me why window.add_image(image, meta) and gui.imshow(image, meta=None, multichannel=None, **kwargs) take different inputs, it would seem to me that they should take the same, and that we might as well have window.add_image(image, meta=None, multichannel=None, **kwargs)

@kne42
Copy link
Copy Markdown
Member Author

kne42 commented Oct 20, 2018 via email

@sofroniewn
Copy link
Copy Markdown
Contributor

sofroniewn commented Oct 20, 2018

Yes, right now this is implemented as Viewer.layers.remove(layer).

ok nice, i get it now, it's just like any list, i can use remove or maybe easier pop with a coordinate. thanks it works for me

Copy link
Copy Markdown
Member

@royerloic royerloic left a comment

Choose a reason for hiding this comment

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

Great work Kira!

@kne42 kne42 merged commit b622f57 into napari:master Oct 23, 2018
ttung pushed a commit to ttung/napari that referenced this pull request Dec 20, 2019
…visible

The visibilitychanged slot currently updates the title regardless of the visibility. We are seeing a crash when the viewer is shut down and a signal is sent to the visibilitychanged slot.  That executes some code which causes a segfault in the python process[1].  This PR changes the visibility changed slot to only update the title bar if the widget is visible.

[1]
```
  * frame #0: 0x0000000115cc96e4 QtWidgets`QWidgetPrivate::reparentFocusWidgets(QWidget*) + 356
    frame napari#1: 0x0000000115cb99cf QtWidgets`QWidget::setParent(QWidget*, QFlags<Qt::WindowType>) + 911
    frame napari#2: 0x0000000115cb82c0 QtWidgets`QWidgetPrivate::init(QWidget*, QFlags<Qt::WindowType>) + 688
    frame napari#3: 0x0000000115d73e5e QtWidgets`QFrame::QFrame(QFramePrivate&, QWidget*, QFlags<Qt::WindowType>) + 14
    frame napari#4: 0x0000000115dc3705 QtWidgets`QLabel::QLabel(QWidget*, QFlags<Qt::WindowType>) + 277
    frame napari#5: 0x0000000116503189 QtWidgets.abi3.so`Sbk_QLabel_Init(_object*, _object*, _object*) + 1497
    frame napari#6: 0x000000010015f84d Python`wrap_init + 12
    frame napari#7: 0x0000000100113e64 Python`_PyObject_FastCallDict + 143
    frame napari#8: 0x00000001001b17a2 Python`call_function + 439
    frame napari#9: 0x00000001001aa46b Python`_PyEval_EvalFrameDefault + 3078
    frame napari#10: 0x00000001001b1ee2 Python`_PyEval_EvalCodeWithName + 1638
    frame napari#11: 0x00000001001b281b Python`_PyFunction_FastCallDict + 447
    frame napari#12: 0x0000000100113e99 Python`_PyObject_FastCallDict + 196
    frame napari#13: 0x0000000100113fa3 Python`_PyObject_Call_Prepend + 131
    frame napari#14: 0x0000000100113d1e Python`PyObject_Call + 101
    frame napari#15: 0x000000010015f7d1 Python`slot_tp_init + 57
    frame napari#16: 0x000000010015c782 Python`type_call + 178
    frame napari#17: 0x0000000100113e64 Python`_PyObject_FastCallDict + 143
    frame napari#18: 0x00000001001141fa Python`_PyObject_FastCallKeywords + 97
    frame napari#19: 0x00000001001b17a2 Python`call_function + 439
    frame napari#20: 0x00000001001aa4fb Python`_PyEval_EvalFrameDefault + 3222
    frame napari#21: 0x00000001001b28e0 Python`_PyFunction_FastCall + 110
    frame napari#22: 0x0000000100113e99 Python`_PyObject_FastCallDict + 196
    frame napari#23: 0x0000000100113fa3 Python`_PyObject_Call_Prepend + 131
    frame napari#24: 0x0000000100113d1e Python`PyObject_Call + 101
    frame napari#25: 0x000000011126f146 libpyside2.abi3.5.14.dylib`PySide::SignalManager::callPythonMetaMethod(QMetaMethod const&, void**, _object*, bool) + 534
    frame napari#26: 0x000000011126eb77 libpyside2.abi3.5.14.dylib`PySide::SignalManager::qt_metacall(QObject*, QMetaObject::Call, int, void**) + 519
```
melonora added a commit to melonora/napari that referenced this pull request May 8, 2023
Added tests and adjusted events in shapes_mouse_bindings tests in order for event.pos to be supported
Czaki pushed a commit that referenced this pull request Jun 23, 2023
* Add white space for images diff

* Add missing images to diff

* Apply event alt text!

Co-authored-by: Draga Doncila Pop <17995243+DragaDoncila@users.noreply.github.com>
Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com>
Co-authored-by: Kandarp Khandwala <kandarpksk@users.noreply.github.com>

* Copy edits and clean up

* Remove white space placeholders

* Remove typos and white space

* Update docs/howtos/layers/shapes.md

Co-authored-by: Melissa Weber Mendonça <melissawm@gmail.com>

Co-authored-by: isabela-pf <irpf.design@gmail.com>
Co-authored-by: Isabela Presedo-Floyd <50221806+isabela-pf@users.noreply.github.com>
Co-authored-by: Draga Doncila Pop <17995243+DragaDoncila@users.noreply.github.com>
Co-authored-by: Andy Sweet <andrew.d.sweet@gmail.com>
Co-authored-by: Kandarp Khandwala <kandarpksk@users.noreply.github.com>
Co-authored-by: Melissa Weber Mendonça <melissawm@gmail.com>
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.

5 participants