brainglobe / napari-experimental

BSD 3-Clause "New" or "Revised" License
3 stars 1 forks source link

napari-experimental

License BSD-3 PyPI Python Version tests codecov napari hub

Overview

Features

This plugin allows napari layers to be organised into 'layer groups'. Groups can hold any number of layers, in addition to further sub-groups. This follows suggestions from the corresponding issue on the main napari repository.

Main features:

Ethos

The aim of this plugin is to provide an entirely separate way to interact with layers in napari. While using it, the main layer list should only be used to add/remove layers, with all re-ordering, re-naming etc done directly within the plugin itself.

To aid this, the plugin contains its own independent layer controls, as well as right click menus and other features.

Outlook

Ultimately, the goal of this plugin is to provide a way to experiment with group layers independent from the main napari codebase. Hopefully, parts of this plugin widget will be incorporated back into napari, replacing the existing LayerList.

Implementation Details

This section is a halfway point between full developer documentation and throwing docstrings in a contributor's face. We have been diligent in adding docstrings to our methods, however we recommend you first read about model/view programming and in particular tree models and views. We also recommend you read the docstrings for Groups and Nodes in the napari codebase, for context on how napari currently handles such structures. You may also want to review this article on composite design patterns.

The docstrings, plus the explanations in this section, should then afford you enough information into how the plugin is operating.

Additionally, the "enter debugger" button has been left within the plugin. This is intended for developer use and should be removed when the plugin is ready for release! Adding a breakpoint within the GroupLayerWidget._enter_debug method allows a developer to enter a debug context with the plugin's widget as self, whilst running napari.

Key Classes

The key classes implemented in this plugin are

Groups and Nodes

GroupLayerNode (GLN) and GroupLayer (GL) inherit from the base napari classes Node and Group (respectively). The GLNs act as wrappers for Layers - each one tracks (a pointer to) one particular Layer through the .layer attribute and uses its information when rendering in the GUI. GLs allow us to organise GLNs into groups, but they themselves must also be instances of GLN. For this reason, the convention we have adopted is that GLs have the .layer attribute set to None (since they do not track an individual layer that is associated to them specifically). Furthermore, the is_group method is explicitly defined on both GLNs and GLs, which provides a way to distinguish between the two classes when traversing the tree structure.

It should also be noted that we have made the decision not to make GLNs inherit from Layer, nor make the existing Layer class subclass from Node.

Differences in Indexing Conventions

A key difference between a flat LayerList and our GL structure is how they are indexed, and how the structures are rendered in the napari viewer based on this indexing. LayerList is indexed from 0 ascending, and renders in the napari viewer with the layer at index 0 at the bottom of the LayerList. Layers with higher indices are rendered on top of those with a lower index, with the item assigned the highest index appearing at the top of the layer viewer window.

By contrast, GL uses NestedIndexes to track the position of GLNs; these are tuples of integers that can be of arbitrary length (so long as the GL has the structure to match), and should be interpreted as subsequent accesses of objects in the tree:

Note that an "item" can be a GLN or a GL (use the is_group method to distinguish if necessary)! Again, items are added to a GL using the lowest available index. GLs can also assign a flat index order to their elements by starting from the root tree and counting upwards from 0, descending into sub-GLs and exhausting their items when they are encountered (see GroupLayer.flat_index_order).

However GLs render with index 0 at the top of the view, and higher indices below them. In order to preserve the user's intuitive understanding of "layers higher up in the display appear on top of lower layers", it is thus necessary to pass the reversed order of layers back to the viewer after a rearrangement event in the GL viewer.

Todo

Desirable features

Known bugs and issues (non-breaking, but poor UX)

Known bugs and issues (breaking)

Development Tasks

Installation

You can install napari-experimental via pip:

pip install napari-experimental

To install the latest development version:

pip install git+https://github.com/brainglobe/napari-experimental.git

You can also install a version of the package that uses the latest version of napari (fetched from https://github.com/napari/napari):

pip install napari-experimental[napari-latest]

Contributing

Contributions are very welcome. Tests can be run with tox, please ensure the coverage at least stays the same before you submit a pull request.

License

Distributed under the terms of the [BSD-3] license, "napari-experimental" is free and open source software

Issues

If you encounter any problems, please file an issue along with a detailed description.