Metadata-Version: 2.4
Name: ndv
Version: 0.2.0rc0
Summary: simple nd image viewer
Project-URL: homepage, https://github.com/pyapp-kit/ndv
Project-URL: repository, https://github.com/pyapp-kit/ndv
Author-email: Talley Lambert <talley.lambert@gmail.com>, Gabriel Selzer <gjselzer@wisc.edu>
License: BSD-3-Clause
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: numpy
Requires-Dist: psygnal
Requires-Dist: pydantic
Requires-Dist: qtpy
Requires-Dist: superqt[cmap,iconify]
Requires-Dist: typing-extensions
Provides-Extra: dev
Requires-Dist: glfw; extra == 'dev'
Requires-Dist: imageio[tifffile]; extra == 'dev'
Requires-Dist: ipykernel; extra == 'dev'
Requires-Dist: ipython; extra == 'dev'
Requires-Dist: ipywidgets; extra == 'dev'
Requires-Dist: jupyter; extra == 'dev'
Requires-Dist: jupyter-rfb; extra == 'dev'
Requires-Dist: mypy; extra == 'dev'
Requires-Dist: pdbpp; extra == 'dev'
Requires-Dist: pre-commit; extra == 'dev'
Requires-Dist: pygfx>=0.6.0; extra == 'dev'
Requires-Dist: pyopengl; extra == 'dev'
Requires-Dist: pyqt6; extra == 'dev'
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: pytest-cov; extra == 'dev'
Requires-Dist: pytest-qt; extra == 'dev'
Requires-Dist: rich; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Requires-Dist: vispy>=0.14.3; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mike==2.1.3; extra == 'docs'
Requires-Dist: mkdocs-gen-files==0.5.0; extra == 'docs'
Requires-Dist: mkdocs-literate-nav==0.6.1; extra == 'docs'
Requires-Dist: mkdocs-material==9.5.49; extra == 'docs'
Requires-Dist: mkdocs-minify-plugin==0.8.0; extra == 'docs'
Requires-Dist: mkdocs-spellcheck[codespell]==1.1.0; extra == 'docs'
Requires-Dist: mkdocs==1.6.1; extra == 'docs'
Requires-Dist: mkdocstrings-python==1.13.0; extra == 'docs'
Provides-Extra: jup
Requires-Dist: glfw; extra == 'jup'
Requires-Dist: imageio[tifffile]; extra == 'jup'
Requires-Dist: ipywidgets; extra == 'jup'
Requires-Dist: jupyter; extra == 'jup'
Requires-Dist: jupyter-rfb; extra == 'jup'
Requires-Dist: pyopengl; extra == 'jup'
Requires-Dist: vispy>=0.14.3; extra == 'jup'
Provides-Extra: jupyter
Requires-Dist: glfw; extra == 'jupyter'
Requires-Dist: ipywidgets; extra == 'jupyter'
Requires-Dist: jupyter; extra == 'jupyter'
Requires-Dist: jupyter-rfb; extra == 'jupyter'
Provides-Extra: pygfx
Requires-Dist: pygfx>=0.6.0; extra == 'pygfx'
Provides-Extra: pyqt
Requires-Dist: pyqt6; extra == 'pyqt'
Provides-Extra: pyside
Requires-Dist: pyside6<6.8; extra == 'pyside'
Provides-Extra: qt
Requires-Dist: imageio[tifffile]; extra == 'qt'
Requires-Dist: pyopengl; extra == 'qt'
Requires-Dist: pyqt6; extra == 'qt'
Requires-Dist: vispy>=0.14.3; extra == 'qt'
Provides-Extra: test
Requires-Dist: imageio[tifffile]; extra == 'test'
Requires-Dist: pytest; extra == 'test'
Requires-Dist: pytest-cov; extra == 'test'
Provides-Extra: third-party-arrays
Requires-Dist: aiohttp; extra == 'third-party-arrays'
Requires-Dist: dask[array]; extra == 'third-party-arrays'
Requires-Dist: jax[cpu]; extra == 'third-party-arrays'
Requires-Dist: numpy<2.0; extra == 'third-party-arrays'
Requires-Dist: pooch; extra == 'third-party-arrays'
Requires-Dist: pyopencl[pocl]; (sys_platform == 'linux') and extra == 'third-party-arrays'
Requires-Dist: sparse; extra == 'third-party-arrays'
Requires-Dist: tensorstore; extra == 'third-party-arrays'
Requires-Dist: torch; extra == 'third-party-arrays'
Requires-Dist: xarray; extra == 'third-party-arrays'
Requires-Dist: zarr<3; extra == 'third-party-arrays'
Provides-Extra: vispy
Requires-Dist: pyopengl; extra == 'vispy'
Requires-Dist: vispy>=0.14.3; extra == 'vispy'
Provides-Extra: wx
Requires-Dist: imageio[tifffile]; extra == 'wx'
Requires-Dist: pyopengl; extra == 'wx'
Requires-Dist: vispy>=0.14.3; extra == 'wx'
Requires-Dist: wxpython; extra == 'wx'
Provides-Extra: wxpython
Requires-Dist: wxpython; extra == 'wxpython'
Description-Content-Type: text/markdown

# ndv

[![License](https://img.shields.io/pypi/l/ndv.svg?color=green)](https://github.com/pyapp-kit/ndv/raw/main/LICENSE)
[![PyPI](https://img.shields.io/pypi/v/ndv.svg?color=green)](https://pypi.org/project/ndv)
[![Python Version](https://img.shields.io/pypi/pyversions/ndv.svg?color=green)](https://python.org)
[![CI](https://github.com/pyapp-kit/ndv/actions/workflows/ci.yml/badge.svg)](https://github.com/pyapp-kit/ndv/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/pyapp-kit/ndv/branch/main/graph/badge.svg)](https://codecov.io/gh/pyapp-kit/ndv)

Simple, fast-loading, asynchronous, n-dimensional array viewer, with minimal dependencies.

```python
import ndv

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

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

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

## 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):
    - `numpy.ndarray`
    - `cupy.ndarray`
    - `dask.array.Array`
    - `jax.Array`
    - `pyopencl.array.Array`
    - `sparse.COO`
    - `tensorstore.TensorStore` (supports named dimensions)
    - `torch.Tensor` (supports named dimensions)
    - `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)

> [!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!)*

## Installation

To just get started using Qt and vispy:
  
```python
pip install ndv[qt]
```

For Jupyter, without requiring Qt, you can use:

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

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>]`:

> [!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`

## 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.
