Skip to content

Commit

Permalink
Merge branch 'main' into v2-3d
Browse files Browse the repository at this point in the history
  • Loading branch information
tlambert03 committed Jan 16, 2025
2 parents 954339d + dc59f7b commit 8214245
Show file tree
Hide file tree
Showing 33 changed files with 479 additions and 180 deletions.
16 changes: 14 additions & 2 deletions .github/workflows/deploy_docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,29 @@ jobs:
run: |
git config user.name github-actions[bot]
git config user.email github-actions[bot]@users.noreply.github.com
git fetch origin gh-pages --depth=1
- name: Deploy release docs
if: ${{ startsWith(github.ref, 'refs/tags/') }}
run: |
VERSION=$(git describe --abbrev=0 --tags)
echo "Deploy release docs to version $VERSION"
mike deploy --push --update-aliases $VERSION latest
# check if rc or beta release
if [[ $VERSION == *"rc"* ]] || [[ $VERSION == *"beta"* ]]; then
export DOCS_PRERELEASE=true
echo "Deploying pre-release docs"
mike deploy --push --update-aliases $VERSION rc
else
echo "Deploying release docs"
mike deploy --push --update-aliases $VERSION latest
fi
env:
DOCS_DEV: false

- name: Deploy dev docs
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
run: mike deploy --push --update-aliases dev
env:
DOCS_DEV: true

- name: Update default release docs
run: mike set-default --push latest
97 changes: 56 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,44 @@ Simple, fast-loading, asynchronous, n-dimensional array viewer, with minimal dep
```python
import ndv

data = ndv.data.cells3d() # or *any* arraylike object
data = ndv.data.cells3d() # or any arraylike object
ndv.imshow(data)
```

![Montage](https://github.com/pyapp-kit/ndv/assets/1609449/712861f7-ddcb-4ecd-9a4c-ba5f0cc1ee2c)

As an alternative to `ndv.imshow()`, you can instantiate the `ndv.NDViewer` (`QWidget` subclass) directly
[`ndv.imshow()`](https://pyapp-kit.github.io/ndv/dev/reference/ndv/#ndv.imshow)
creates an instance of
[`ndv.ArrayViewer`](https://pyapp-kit.github.io/ndv/dev/reference/ndv/controllers/#ndv.controllers.ArrayViewer),
which you can also use directly:

```python
from qtpy.QtWidgets import QApplication
from ndv import NDViewer
import ndv

app = QApplication([])
viewer = NDViewer(data)
viewer = ndv.ArrayViewer(data)
viewer.show()
app.exec()
ndv.run_app()
```

> [!TIP]
> To embed the viewer in a broader Qt or wxPython application, you can
> access the viewer's
> [`widget`](https://pyapp-kit.github.io/ndv/dev/reference/ndv/controllers/#ndv.controllers.ArrayViewer.widget)
> attribute and add it to your layout.
## Features

- ⚡️ fast import and time-to-show
- ♾️ supports arbitrary number of data dimensions
- 📦 2D/3D view canvas
<!-- - sliders support integer as well as slice (range)-based slicing -->
- 🎨 colormaps provided by [cmap](https://github.com/tlambert03/cmap)
- 🌠 supports [vispy](https://github.com/vispy/vispy) and [pygfx](https://github.com/pygfx/pygfx) backends
- 🦆 supports any numpy-like duck arrays, including (but not limited to):
- ⚡️ fast to import, fast to show
- 🪶 minimal dependencies
- 📦 supports arbitrary number of dimensions
- 🥉 2D/3D view canvas
- 🌠 supports [VisPy](https://github.com/vispy/vispy) or
[pygfx](https://github.com/pygfx/pygfx) backends
- 🛠️ support [Qt](https://doc.qt.io), [wx](https://www.wxpython.org), or
[Jupyter](https://jupyter.org) GUI frontends
- 🎨 colormaps provided by [cmap](https://cmap-docs.readthedocs.io/)
- 🏷️ supports named dimensions and categorical coordinate values (WIP)
- 🦆 supports most array types, including:
- `numpy.ndarray`
- `cupy.ndarray`
- `dask.array.Array`
Expand All @@ -49,48 +60,52 @@ app.exec()
- `xarray.DataArray` (supports named dimensions)
- `zarr` (supports named dimensions)

See examples for each of these array types in [examples](https://github.com/pyapp-kit/ndv/tree/main/examples)
See examples for each of these array types in
[examples](https://github.com/pyapp-kit/ndv/tree/main/examples)

> [!NOTE]
> *You can add support for any custom storage class by subclassing `ndv.DataWrapper`
> and implementing a couple methods.
> (This doesn't require modifying ndv, but contributions of new wrappers are welcome!)*
> *You can add support for any custom storage class by subclassing
> `ndv.DataWrapper` and [implementing a couple
> methods](https://github.com/pyapp-kit/ndv/blob/main/examples/custom_store.py).
> (This doesn't require modifying ndv, but contributions of new wrappers are
> welcome!)*
## Installation

To just get started using Qt and vispy:
Because ndv supports many combinations of GUI and graphics frameworks,
you must install it along with additional dependencies for your desired backend.

See the [installation guide](https://pyapp-kit.github.io/ndv/dev/install/) for
complete details.

To just get started quickly using Qt and vispy:

```python
pip install ndv[qt]
```

For Jupyter, without requiring Qt, you can use:
For Jupyter with vispy, (no Qt or wxPython):

```python
pip install ndv[jupyter]
pip install ndv[jup]
```

If you'd like more control over the backend, you can install the optional dependencies directly.

The only required dependencies are `numpy` and `superqt[cmap,iconify]`.
You will also need a Qt backend (PyQt or PySide) and one of either
[vispy](https://github.com/vispy/vispy) or [pygfx](https://github.com/pygfx/pygfx),
which can be installed through extras `ndv[<pyqt|pyside>,<vispy|pygfx>]`:
## Documentation

> [!TIP]
> If you have both vispy and pygfx installed, `ndv` will default to using vispy,
> but you can override this with the environment variable
> `NDV_CANVAS_BACKEND=pygfx` or `NDV_CANVAS_BACKEND=vispy`
For more information, and complete API reference, see the
[documentation](https://pyapp-kit.github.io/ndv/).

## Motivation

This package arose from the need for a way to *quickly* view multi-dimensional arrays with
zero tolerance for long import times and/or excessive dependency lists. I want something that I can
use to view any of the many multi-dimensional array types, out of the box, with no assumptions
about dimensionality. I want it to work reasonably well with remote, asynchronously loaded data.
I also want it to take advantage of things like named dimensions and categorical coordinate values
when available. For now, it's a Qt-only widget, since that's where the need arose, but I can
imagine a jupyter widget in the future (likely as a remote frame buffer for vispy/pygfx).

I do not intend for this to grow into full-fledged application, or wrap a complete scene graph,
though point and ROI selection would be welcome additions.
This package arose from the need for a way to *quickly* view multi-dimensional
arrays with zero tolerance for long import times and/or excessive dependency
lists. I want something that I can use to view any of the many multi-dimensional
array types, out of the box, with no assumptions about dimensionality. I want it
to work reasonably well with remote, asynchronously loaded data. I also want it
to take advantage of things like named dimensions and categorical coordinate
values when available. For now, it's a Qt-only widget, since that's where the
need arose, but I can imagine a jupyter widget in the future (likely as a remote
frame buffer for vispy/pygfx).

I do not intend for this to grow into full-fledged application, or wrap a
complete scene graph, though point and ROI selection would be welcome additions.
18 changes: 16 additions & 2 deletions docs/_overrides/main.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
{% extends "base.html" %}

{% set prebuild = 'pre-release' if config.extra.pre_release else 'dev' if config.extra.dev_build else '' %}

{% block announce %}
{%- if prebuild -%} <!-- See the dashes here -->
<!-- Need to reapply margin from base CSS, which is overridden in extra CSS (to fix empty banner) -->
<div style="margin: 0.6rem auto">
You are currently viewing documentation for a <strong>{{prebuild}}</strong> build.
This may reference unreleased features.
For latest release, see
<strong><a href="{{ '../' ~ base_url }}">stable release docs</a></strong>.
</div>
{%- endif -%}
{% endblock %}

{% block outdated %}
You're not viewing the latest version.
You're not viewing the latest stable version.
<a href="{{ '../' ~ base_url }}">
<strong>Click here to go to latest.</strong>
<strong>Click here to go to last release.</strong>
</a>
{% endblock %}
23 changes: 23 additions & 0 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,26 @@ and GUI libraries you want to use:

<!-- logic for this table in install-table.js -->
<div id="install-table"></div>

## Framework selection

If you have multiple GUI or graphics libraries installed, you can control which
ones `ndv` uses with environment variables. The following variables are
supported:

- `NDV_CANVAS_BACKEND`: Set to `"vispy"` or `"pygfx"` to choose the graphics library.
- `NDV_GUI_FRONTEND`: Set to `"qt"`, `"wx"`, or `"jupyter"` to choose the GUI library.

!!! info "Defaults"

**GUI:**

`ndv` tries to be aware of the GUI library you are using. So it will use
`jupyter` if you are in a Jupyter notebook, `qt` if a `QApplication` is
already running, and `wx` if a `wx.App` is already running. Finally, it
will check available libraries in the order of `qt`, `wx`, `jupyter`.

**Graphics:**

If you have both VisPy and pygfx installed, `ndv` will (currently) default
to using vispy.
65 changes: 65 additions & 0 deletions docs/motivation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Motivation and Scope

It can be informative to know what problems the developers were trying to solve
when creating a library, and under what constraints. `ndv` was created by a
former [napari](https://napari.org) core developer and collaborators out of a
desire to quickly view multi-dimensional arrays with minimal import times
minimal dependencies. The original need was for a component in a broader
(microscope control) application, where a fast and minimal viewer was needed to
display data.

## Goals

- [x] **N-dimensional viewer**: The current focus is on viewing multi-dimensional
arrays (and currently just a single array at a time), with sliders
controlling slicing from an arbitrary number of dimensions. 2D and 3D
volumetric views are supported.
- [x] **Minimal dependencies**: `ndv` should have as few dependencies as
possible (both direct and indirect). Installing `napari[all]==0.5.5` into a
clean environment brings a total of 126 dependencies. `ndv[qt]==0.2.0` has
29, and we aim to keep that low.
- [x] **Quick to import**: `ndv` should import and show a viewer in a reasonable
amount of time. "Reasonable" is of course relative and subjective, but we
aim for less than 1 second on a modern laptop (currently at <100ms).
- [x] **Broad GUI Compatibility**: A common feature request for `napari` is to support
Jupyter notebooks. `ndv` [can work with](./install.md#framework-selection) Qt,
wxPython, *and* Jupyter.
- [x] **Flexible Graphics Providers**: `ndv` works with VisPy in a classical OpenGL
context, but has an abstracting layer that allows for other graphics engines.
We currently also support `pygfx`, a WGPU-based graphics engine.
- [x] **Model/View architecture**: `ndv` should have a clear separation between the
data model and the view. The model should be serializable and easily
transferable between different views.
- [x] **Asynchronous first**: `ndv` should be asynchronous by default: meaning
that the data request/response process happens in the background, and the
GUI remains responsive. (Optimization of remote, multi-resolution data is on
the roadmap, but not currently implemented).

## Scope and Roadmap

We *do* want to support the following features:

- [ ] **Multiple data sources**: We want to allow for multiple data sources to be
displayed in the same viewer, with flexible coordinate transforms.
- [ ] **Non-image data**: We would like to support non-image data, such as points
segmentation masks, and meshes.
- [ ] **Multi-resolution (pyramid) data**: We would like to support multi-resolution
data, to allow for fast rendering of large datasets based on the current view.
- [ ] **Frustum culling**: We would like to support frustum culling to allow for
efficient rendering of large datasets.
- [ ] **Ortho-viewer**: `ndv`'s good model/view separation should allow for
easy creation of an orth viewer (e.g. synchronized `XY`, `XZ`, `YZ` views).

## Non-Goals

We *do not* plan to support the following features in the near future
(if ever):

- **Image Processing**: General image processing is out of scope. We aim to
provide a viewer, not a full image processing library.
- **Interactive segmentation and painting**: While extensible mouse event handling
*is* in scope, we don't intend to implement painting or interactive
segmentation tools.
- **Plugins**: We don't intend to support a plugin architecture. We aim to keep
the core library as small as possible, and encourage users to build on top
of it with their own tools.
20 changes: 20 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ validation:
nav:
- Home: index.md
- install.md
- motivation.md
# This is populated by scripts/gen_ref_nav.py
- API reference: reference/

Expand Down Expand Up @@ -68,6 +69,9 @@ extra_javascript:

markdown_extensions:
- admonition
- pymdownx.details
- pymdownx.keys
- pymdownx.tilde
- pymdownx.emoji:
emoji_index: !!python/name:material.extensions.emoji.twemoji
emoji_generator: !!python/name:material.extensions.emoji.to_svg
Expand All @@ -76,12 +80,21 @@ markdown_extensions:
- pymdownx.highlight:
pygments_lang_class: true
line_spans: __span
- pymdownx.tasklist:
custom_checkbox: true
- pymdownx.inlinehilite
- pymdownx.superfences
- toc:
permalink: "#"

plugins:
- autorefs
- search
- minify:
minify_html: true
minify_js: true
minify_css: true
cache_safe: true
- gen-files:
scripts:
- scripts/gen_ref_nav.py
Expand All @@ -96,6 +109,9 @@ plugins:
python:
import:
- https://docs.python.org/3/objects.inv
- https://docs.pydantic.dev/latest/objects.inv
- https://cmap-docs.readthedocs.io/objects.inv
- https://psygnal.readthedocs.io/en/latest/objects.inv
options:
docstring_section_style: list
docstring_style: "numpy"
Expand Down Expand Up @@ -126,6 +142,10 @@ hooks:
extra:
version:
provider: mike
# either of these tags will enable the "viewing pre" announcement banner
# see _overrides/main.html
pre_release: !ENV ["DOCS_PRERELEASE", false]
dev_build: !ENV ["DOCS_DEV", false]
social:
- icon: fontawesome/brands/github
link: https://github.com/pyapp-kit
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ docs = [
"mkdocstrings-python==1.13.0",
"mkdocs-spellcheck[codespell]==1.1.0",
"mike==2.1.3",
"ruff",
]
dev = [
"ndv[test,vispy,pygfx,pyqt,jupyter]",
Expand Down
Loading

0 comments on commit 8214245

Please sign in to comment.