-
Notifications
You must be signed in to change notification settings - Fork 39
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
Add NAP for multicanvas #249
Conversation
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 took a first pass through this and left a few comments. Overall, I'm very excited to see something like this get approval and get implemented!
docs/naps/8-multiple-canvases.md
Outdated
* Specific UI implementations will be explored as part of this work, but I expect UX and UI will be formalized later (possibly in a separate NAP). | ||
* Supporting alternative frontend (Qt) and backend (Vispy) frameworks. While this work should not make such tasks more difficult in the future, explicit consideration is out-of-scope until further progress is made in these areas. | ||
* [Non-goals also in NAP-3](https://napari.org/dev/naps/3-spaces.html#non-goals) are related but also considered out-of-scope here | ||
* Separation of rendering information from the Layer(Data) model |
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.
Would this benefit the work here or do you think of it as mostly orthogonal? Would a simultaneous effort help or hinder progress here?
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 layergroups here could potentially provide a cleaner API, but overall the API is similar to current grid mode at least for multichannel view, thus could be an orthogonal effort.
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 don't think it's entirely orthogonal, but perhaps mostly. I think it depends on the scope of features we want. For example just below I propose for all canvases to share a common layer list, with independent slicing, camera, dimensionality, and layer visibility. I think this would be more relevant if supporting (for example) different colormaps for the same data in two canvases.
docs/naps/8-multiple-canvases.md
Outdated
* `ViewerModel` will own a *list* of `CanvasModel` objects | ||
* `QtViewer` will own a *list* of `VispyCanvas` objects | ||
* `VispyLayer` subclasses will hold references to their `Layer` (for rendering information) as well as a `LayerSlice` (for data) | ||
* The LayerSlicer will need to update the sync and async callbacks[^async-only] to pass a canvas parameter where the resulting sliced data will be stored, rather than storing it on the layer itself. Slice task cancellation logic will need to be revisited accordingly. |
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.
One alternative here that came to mind is that each canvas (or maybe vispy canvas) could own its own layer slicer - that way you don't need to pass in the extra canvas parameter and you can do cancellation per canvas (which I think is desirable).
With lots of canvas, you might introduce too much concurrency, but in most cases, maybe that won't be too bad. And we may be able to serialize it with a shared resource/controller if needed.
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.
Thanks - that's an interesting idea I hadn't considered. I was initially thinking the current LayerSlicer may expand to use a pool instead of a single thread.
I think you're right passing the full canvas is probably more than necessary, and trying to pass a canvas ID or something feels a bit hacky to me. One benefit of just passing the canvas object is that it would bring with it the camera, which might be useful for finding corner_pixels
without waiting for the draw.
docs/naps/8-multiple-canvases.md
Outdated
|
||
> Note: in both diagrams, the `on_draw()` method on the `VispyCanvas` breaks MVC convention (view layer talks directly to the model layer). This is a separate/known issue and I believe is mostly only true for multiscale image layers right now. Changing this is considered out of scope for this project at this time. | ||
|
||
Slice state for each layer is currently stored on the Layer model. Again, see [NAP-4 for previous discussion](https://napari.org/stable/naps/4-async-slicing.html#existing-slice-state). This NAP proposes to move this state off the Layer instance, into a specific Layer Slice instance. This is what will allow multiple slices of a single layer to be visualized simultaneously. *Table 1* lists the attributes related to slice state that will be moved in this work from each Layer class into corresponding Layer Slice classes. |
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.
Maybe I misread the out-of-scope section, but my impression was that moving slice state off the layer was a non-goal - is that wrong?
Or maybe this is the proposed approach that incidentally achieves that non-goal?
Anyway, I'm generally in favor of that move, but just wanted to clarify the proposal and intent here.
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.
Do you mean this non-goal?
Normalizing slice data for different layer types, though this may benefit in the course of this work.
That's not really what I meant there, but also I think it's ambiguous enough warrant changing or removing. I was trying to say it is a non-goal to create a uniform/generic concept (or Protocol) of a "slice" - it's okay for the slices to be quite specific for each layer type.
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.
No, I meant this one.
Separation of rendering information from the Layer(Data) model
But maybe you meant that only with respect to NAP-3.
Anyway, I also agree that a generic slice class/protocol should be a non-goal. Though we might consider during/after.
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 see - I will try to make this more clear. The goal here is indeed to move the slice state off the layer. The non-goal was meant to indicate that the remaining attributes of the layer will not be separated. So for example this work does not necessarily make it easier to share data between two layers with different colormaps.
docs/naps/8-multiple-canvases.md
Outdated
|
||
## Implementation | ||
|
||
1. Introduce minimally disruptive `_canvases` attribute on the ViewerModel |
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'm fully in support of this ordering where implementation of architecture changes happen first to support new functionality later.
One mistake on the async slicing project is that I didn't do enough to prioritize things that way, which meant that things didn't end up quite as I'd hoped.
docs/naps/8-multiple-canvases.md
Outdated
> [name=Ashley A] | ||
|
||
### UI Design and Architecture | ||
Specific UI design and architecture remains to be determined. This will be explored as part of step 4 in the [Implementation Plan](#Implementation). UI design needs additional refinement and exploration, and this is expected to continue after basic/core implementation propsed in this NAP is complete. UI changes may also be described in a separate NAP along with a discussion of convenience functions and affordances for common operations. Some placeholder or experimental code will be used in the meantime as a prototype implementation. |
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.
Is there any prototype code available to look at and play with? And/or some videos showing some of the proposals here at least kind-of in action?
Both could help to ground some of the proposals and discussion here.
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.
My prototype/experimentation code is pretty early, but is here:
aganders3/napari#13
docs/naps/8-multiple-canvases.md
Outdated
> Note: some layers include "seleciton" information (Points, Shapes, and Tracks). How selection is handled in multicanvas view is TBD at this point. | ||
|
||
***Table 1** - Layer attributes that hold slice data. These attributes will be moved from the Layer onto individual Layer Slice objects (one Layer Slice per Layer per Canvas).* | ||
> TODO: make this a list or figure out a way to center it [name=Ashley A] |
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 regretted adding something like this to the async slicing NAP, because it's just too much detail, so another option might be to remove it from the main NAP document and maybe link to it or shove it into an appendix.
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 found it helpful to write this out, but if it's too detailed I'm happy to move or remove it. It might just fit better in a PR with actual code changes.
Co-authored-by: Andy Sweet <[email protected]>
Thanks! I appreciate the support and feedback. |
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.
The number 8 is for telemetry (#226), also please add a new NAP to the table of contents.
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.
Generally, great work on the NAP! Other than comments and clarifications here and there, I have one main disagreement, and it seems it comes from a misunderstanding when we discussed before, because I thing this is quite important. You say:
* All canvases shall share a common layer list and (unsliced) layer data.
I think we need to ensure from the get-go that canvases can hold different layer lists, but can also share some layers. This is key for example for applications like highly multiplexed data (@melonora can add some more specifics here if needed). I fear that leaving this out will make it harder to support it afterwards.
Anyways, approving as draft as per normal NAP procedure :)
* The application shall natively display multiple canvases simultaneously. | ||
* There shall be a minimum of one canvas (current status) per viewer. | ||
* There shall be a maximum of 8 canvases (tentative) per viewer. | ||
* All canvases shall share a common layer list and (unsliced) layer data. |
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 is my only disagreement with the current form of the NAP, I wrote more details in the general review comment.
* What kind of cross-reference displays or tools should there be? | ||
* through-plane slice indicators | ||
* three-point slice definition |
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 is hard to do unless we assume a shared space between canvases, which I'm not sure we should do. Initially, I think we should leave this to the user.
Creating an orthoview example as part of this would would be a great way to test these ideas.
Thanks for the review and great comments @brisvag! I will try to respond to each and update accordingly, but generally your comments cleared up a few things for me. We're not too far apart on anything here :). |
Co-authored-by: Lorenzo Gaifas <[email protected]>
I updated a bit but not ready for your re-review @brisvag. I should be able to finish addressing your comments next week, but you can ignore GitHub notifications for now :) |
My way of addressing this use case was specifying layers would gain a per-canvas visibility setting. I think this is also where misalignment on #249 (comment) comes from; using a common layer list would also inherently share space between canvases. If you want a truly independent space, I don't see that much benefit over opening a separate viewer window. Changing to fully independent layer lists would definitely offer more flexibility, and may actually make this implementation simpler in some ways. My concern is that it will make for a more difficult UI design, and may make it more difficult to implement certain common use cases later (for example, where you do want a common space between canvases). That said, I am definitely still open to this approach. You (and @melonora) may have a better understanding of the use-cases that would benefit. |
Particular thanks to @brisvag and @melonora for previous work and discussions on this, and for agreeing to be co-authors. I am happy to absorb any criticism and direct praise their way 😄.
Thanks also to @andy-sweet and @Czaki, both of whom provided helpful discussion while I worked on this NAP.
Of course I expect many changes to this and look forward to feedback.