Skip to content

Commit

Permalink
Merge pull request #150 from TimMonko/main_container
Browse files Browse the repository at this point in the history
Add nDev app
  • Loading branch information
TimMonko authored Jan 2, 2025
2 parents a052f94 + aae6374 commit 07fed7c
Show file tree
Hide file tree
Showing 18 changed files with 410 additions and 59 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test_and_deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install setuptools tox tox-gh-actions
python -m pip install setuptools tox tox-gh-actions codecov
# this runs the platform-specific tests declared in tox.ini
- name: Test with tox
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[![codecov](https://codecov.io/gh/TimMonko/napari-ndev/branch/main/graph/badge.svg)](https://codecov.io/gh/TimMonko/napari-ndev)
[![napari hub](https://img.shields.io/endpoint?url=https://api.napari-hub.org/shields/napari-ndev)](https://napari-hub.org/plugins/napari-ndev)

<img src="docs/resources/images/neuralDev-logo.svg" alt="logo" width="300">
<img src="resources/nDev-logo-large.png" alt="logo" width="400" style="display: block; margin: auto;">

A collection of widgets intended to serve any person seeking to process microscopy images from start to finish, *with no coding necessary*. `napari-ndev` was designed to address the **gap between the napari viewer and batch python scripting**.

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[![codecov](https://codecov.io/gh/TimMonko/napari-ndev/branch/main/graph/badge.svg)](https://codecov.io/gh/TimMonko/napari-ndev)
[![napari hub](https://img.shields.io/endpoint?url=https://api.napari-hub.org/shields/napari-ndev)](https://napari-hub.org/plugins/napari-ndev)

<img src="resources/images/neuralDev-logo.svg" alt="neuralDev logo" width="300">
<img src="resources/images/nDev-logo-large.png" alt="nDev logo" width="400" style="display: block; margin: auto;">

A collection of widgets intended to serve any person seeking to process microscopy images from start to finish, *with no coding necessary*. `napari-ndev` was designed to address the **gap between the napari viewer and batch python scripting**.

Expand Down
18 changes: 13 additions & 5 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,26 @@ If you are unfamiliar with python or the command line, instead use the bundled a

## Install with uv

uv is the newest and fastest way to manage python libraries. It is very easy to install, and simplifies environment manage, but requires minimal input to the command line. [Install uv from here](https://docs.astral.sh/uv/getting-started/installation/#__tabbed_1_1). Then, the simplest way to install `napari-ndev`:
uv is the newest and fastest way to manage python libraries. It is very easy to install, and simplifies environment manage, but requires some minimal input to the command line. [Install uv from here](https://docs.astral.sh/uv/getting-started/installation/#__tabbed_1_1). Then, the simplest way to install `napari-ndev`:

```bash
uv tool install napari-ndev
napari-ndev
```

With this method, plugins installed via the plugin menu persist between each call to `napari-ndev`
Alternatively, download the full opinionated package, which includes non-BSD3 licensed libraries with:

```bash
uv tool install napari-ndev[all]
```

Then, you can easily open napari with the command line every time by just typing:

```bash
napari-ndev
```

The tool version of `napari-ndev` effectively runs as an alias for `napari -w napari-ndev` and opens the `nDev App` upon launch. With this method, additional plugins installed via the plugin menu persist between each call to `napari-ndev`

To update a tool with uv:

```bash
Expand All @@ -26,7 +32,7 @@ uv tool upgrade napari-ndev

## Install with pip

**napari-ndev** is a pure Python package, and can be installed with [pip]:
**napari-ndev** is a pure Python package, and can be installed with [pip] (and it is recommended to do so in a [managed environment](https://biapol.github.io/blog/mara_lampert/getting_started_with_mambaforge_and_python/readme.html)):

```bash
pip install napari-ndev
Expand All @@ -38,6 +44,8 @@ The easiest way to get started with **napari-ndev** is to install all the option
pip install napari-ndev[all]
```

Afterwards, you can call from the command line (in the same environment) `napari-ndev` to open napari with the `nDev App` open on launch.

### Optional Libraries

**napari-ndev** is most useful when interacting with some other napari plugins (e.g. napari-assistant) and can read additional filetypes. A few extra BSD3 compatible napari-plugins may be installed with [pip]:
Expand Down Expand Up @@ -85,7 +93,7 @@ You may also test the tool version of uv during development with:
uv install tool .
```

You may also test with tox in parallel ([via tox-uv](https://github.com/tox-dev/tox-uv)) with:
You can also test with tox in parallel ([via tox-uv](https://github.com/tox-dev/tox-uv)) with:

```bash
tox - p auto
Expand Down
Binary file added docs/resources/images/nDev-logo-large.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed docs/resources/images/ndev-logo.png
Binary file not shown.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ dynamic = ["version"]
napari-ndev = "napari_ndev:napari.yaml"

[project.scripts]
napari-ndev = "napari.__main__:main"
napari-ndev = "napari_ndev.__main__:main"

[project.optional-dependencies]
testing = [
Expand Down
Binary file added resources/nDev-logo-large.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/nDev-logo-small.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
114 changes: 114 additions & 0 deletions resources/nDev-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/napari_ndev/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
MeasureContainer,
UtilitiesContainer,
WorkflowContainer,
nDevContainer,
)

__all__ = [
Expand All @@ -28,5 +29,6 @@
'image_overview',
'measure',
'morphology',
'nDevContainer',
'nImage',
]
8 changes: 8 additions & 0 deletions src/napari_ndev/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Open napari with the napari_ndev plugin using command line."""

import subprocess


def main():
"""Run napari with the napari_ndev plugin."""
subprocess.run(["napari", "-w", "napari-ndev"])
12 changes: 12 additions & 0 deletions src/napari_ndev/_tests/test_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from unittest.mock import patch

from napari_ndev import __main__


@patch('subprocess.run')
def test_main(mock_run):
__main__.main()
# Check if subprocess.run was called, indicating an attempt to open napari
assert mock_run.called
# Optionally, you can check the arguments to ensure it was called correctly
mock_run.assert_called_with(["napari", "-w", "napari-ndev"])
58 changes: 58 additions & 0 deletions src/napari_ndev/_tests/widgets/test_ndev_container.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from pathlib import Path
from unittest.mock import patch

import pytest

from napari_ndev import nImage
from napari_ndev.widgets._ndev_container import nDevContainer


def test_ndev_container_init_no_viewer():
ndev = nDevContainer()

assert ndev._viewer is None
assert ndev._apoc_container is not None
assert ndev._measure_container is not None
assert ndev._utilities_container is not None
assert ndev._workflow_container is not None

with patch('webbrowser.open') as mock_open:
ndev._open_docs_link()
mock_open.assert_called_once_with('https://timmonko.github.io/napari-ndev')

with patch('webbrowser.open') as mock_open:
ndev._open_bug_report_link()
mock_open.assert_called_once_with('https://github.com/TimMonko/napari-ndev/issues')

@pytest.fixture
def test_cells3d2ch_image(resources_dir: Path):
path = resources_dir / 'cells3d2ch.tiff'
img = nImage(path)
return path, img

def test_ndev_container_viewer(make_napari_viewer, test_cells3d2ch_image, tmp_path: Path):
viewer = make_napari_viewer()

ndev = nDevContainer(viewer=viewer)
assert ndev._viewer is viewer

path, img = test_cells3d2ch_image
ndev._utilities_container._files.value = path
ndev._utilities_container.open_images()

# make sure images opened and there are callbacks to the widgets
assert viewer.layers[0] is not None

# check interacting with alyers in utilities container works
ndev._utilities_container._save_directory.value = tmp_path
ndev._utilities_container._save_name.value = 'test'
layer_data = ndev._utilities_container.save_layers_as_ome_tiff()

expected_save_loc = tmp_path / 'Image' / 'test.tiff'
assert layer_data.shape.__len__() == 5
assert expected_save_loc.exists()

# check interacting with apoc container works
assert ndev._apoc_container._image_layers.choices == (
viewer.layers[0], viewer.layers[1]
)
5 changes: 5 additions & 0 deletions src/napari_ndev/napari.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ contributions:
- id: napari-ndev.get_reader
python_name: napari_ndev._napari_reader:napari_get_reader
title: Get BioIO Reader
- id: napari-ndev.make_ndev_container
python_name: napari_ndev.widgets._ndev_container:nDevContainer
title: Make nDev App
- id: napari-ndev.make_utilities_container
python_name: napari_ndev.widgets._utilities_container:UtilitiesContainer
title: Make Image Utilities
Expand All @@ -23,6 +26,8 @@ contributions:
title: Make Measure Container

widgets:
- command: napari-ndev.make_ndev_container
display_name: nDev App
- command: napari-ndev.make_utilities_container
display_name: Image Utilities
- command: napari-ndev.make_workflow_container
Expand Down
2 changes: 2 additions & 0 deletions src/napari_ndev/widgets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from napari_ndev.widgets._apoc_container import ApocContainer
from napari_ndev.widgets._apoc_feature_stack import ApocFeatureStack
from napari_ndev.widgets._measure_container import MeasureContainer
from napari_ndev.widgets._ndev_container import nDevContainer
from napari_ndev.widgets._utilities_container import UtilitiesContainer
from napari_ndev.widgets._workflow_container import WorkflowContainer

Expand All @@ -21,4 +22,5 @@
'MeasureContainer',
'UtilitiesContainer',
'WorkflowContainer',
'nDevContainer',
]
121 changes: 121 additions & 0 deletions src/napari_ndev/widgets/_ndev_container.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from magicclass.widgets import (
ScrollableContainer,
TabbedContainer,
)
from magicgui.widgets import (
Container,
Label,
PushButton,
)

if TYPE_CHECKING:
import napari

class nDevContainer(ScrollableContainer):
"""
A widget container to container the primary ndev widgets.
Parameters
----------
viewer: napari.viewer.Viewer, optional
The napari viewer instance.
"""

def __init__(self, viewer: napari.viewer.Viewer = None):
"""
Initialize the MainContainer.
Parameters
----------
viewer: napari.viewer.Viewer, optional
The napari viewer instance.
"""
super().__init__(labels=False)

self.min_width = 700 # TODO: remove this hardcoded value
self._viewer = viewer if viewer is not None else None

_logo_path = r'resources\nDev-logo-small.png'
self._logo_label = Label(
value='<h1 style="text-align: center;">'
f'<img src="{_logo_path}"/>'
'</h1>'
)


self._docs_link_button = PushButton(
text='Docs',
icon='ic:round-menu-book'
)
self._bug_report_link_button = PushButton(
text='Bug Report',
icon='ic:outline-bug-report',
)
self._link_container = Container(
widgets=[self._docs_link_button, self._bug_report_link_button],
layout='vertical',
)
self._header_container = Container(
widgets=[self._logo_label, self._link_container],
layout='horizontal',
)

self._init_widget_containers()
self._init_layout()
self._init_callbacks()

def _init_widget_containers(self):
from napari_ndev import (
ApocContainer,
MeasureContainer,
UtilitiesContainer,
WorkflowContainer,
)
"""Initialize the widget containers."""
self._apoc_container = ApocContainer(viewer=self._viewer)
self._apoc_container.label = "APOC"
self._measure_container = MeasureContainer(viewer=self._viewer)
self._measure_container.label = "Measure"
self._utilities_container = UtilitiesContainer(viewer=self._viewer)
self._utilities_container.label = "Utilities"
self._workflow_container = WorkflowContainer(viewer=self._viewer)
self._workflow_container.label = "Workflow"

self._tabbed_container = TabbedContainer(
# labels=["Apoc", "Measure", "Utilities", "Workflow"],
labels = False,
layout="horizontal",
widgets=[
self._utilities_container,
self._apoc_container,
self._workflow_container,
self._measure_container,
],
)

def _init_layout(self):
"""Initialize the layout."""
self.append(self._header_container)
self.append(self._tabbed_container)
# self.stretch(self._tabbed_container)

def _init_callbacks(self):
"""Initialize the widget callbacks."""
self._docs_link_button.clicked.connect(self._open_docs_link)
self._bug_report_link_button.clicked.connect(self._open_bug_report_link)

def _open_docs_link(self):
"""Open the documentation link."""
import webbrowser
webbrowser.open('https://timmonko.github.io/napari-ndev')

def _open_bug_report_link(self):
"""Open the bug report link."""
import webbrowser
webbrowser.open('https://github.com/TimMonko/napari-ndev/issues')

0 comments on commit 07fed7c

Please sign in to comment.