Skip to content

Commit

Permalink
bulid: initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
tlambert03 committed Jun 7, 2024
1 parent cadf550 commit ed8f547
Show file tree
Hide file tree
Showing 23 changed files with 2,343 additions and 67 deletions.
58 changes: 16 additions & 42 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ name: CI

on:
push:
branches:
- main
branches: [main]
tags:
- "v*"
pull_request:
Expand All @@ -24,48 +23,23 @@ jobs:
- run: pipx run check-manifest

test:
name: ${{ matrix.platform }} (${{ matrix.python-version }})
runs-on: ${{ matrix.platform }}
uses: pyapp-kit/workflows/.github/workflows/test-pyrepo.yml@v2
with:
os: ${{ matrix.os }}
python-version: ${{ matrix.python-version }}
coverage-upload: artifact
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
platform: [ubuntu-latest, macos-latest, windows-latest]
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ["3.9", "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v4

- name: 🐍 Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache-dependency-path: "pyproject.toml"
cache: "pip"

- name: Install Dependencies
run: |
python -m pip install -U pip
# if running a cron job, we add the --pre flag to test against pre-releases
python -m pip install .[test] ${{ github.event_name == 'schedule' && '--pre' || '' }}
- name: 🧪 Run Tests
run: pytest --color=yes --cov --cov-report=xml --cov-report=term-missing

- name: 📝 Report --pre Failures
if: failure() && github.event_name == 'schedule'
uses: JasonEtco/create-an-issue@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PLATFORM: ${{ matrix.platform }}
PYTHON: ${{ matrix.python-version }}
RUN_ID: ${{ github.run_id }}
TITLE: "[test-bot] pip install --pre is failing"
with:
filename: .github/TEST_FAIL_TEMPLATE.md
update_existing: true

- name: Coverage
uses: codecov/codecov-action@v3
upload_coverage:
if: always()
needs: [test]
uses: pyapp-kit/workflows/.github/workflows/upload-coverage.yml@v2
secrets:
codecov_token: ${{ secrets.CODECOV_TOKEN }}

deploy:
name: Deploy
Expand All @@ -83,7 +57,7 @@ jobs:
fetch-depth: 0

- name: 🐍 Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: "3.x"

Expand All @@ -98,4 +72,4 @@ jobs:
- uses: softprops/action-gh-release@v1
with:
generate_release_notes: true
files: './dist/*'
files: "./dist/*"
13 changes: 4 additions & 9 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
# enable pre-commit.ci at https://pre-commit.ci/
# it adds:
# 1. auto fixing pull requests
# 2. auto updating the pre-commit configuration
ci:
autoupdate_schedule: monthly
autofix_commit_msg: "style(pre-commit.ci): auto fixes [...]"
Expand All @@ -17,20 +13,19 @@ repos:
rev: typos-dict-v0.11.20
hooks:
- id: typos
args: [--force-exclude] # omitting --write-changes
args: [--force-exclude] # omitting --write-changes

- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.4.8
hooks:
- id: ruff
args: [--fix] # may also add '--unsafe-fixes'
args: [--fix, --unsafe-fixes]
- id: ruff-format

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
hooks:
- id: mypy
files: "^src/"
# # you have to add the things you want to type check against here
# additional_dependencies:
# - numpy
additional_dependencies:
- numpy
32 changes: 32 additions & 0 deletions examples/dask_arr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from __future__ import annotations

import numpy as np

try:
from dask.array.core import map_blocks
except ImportError:
raise ImportError("Please `pip install dask[array]` to run this example.")

frame_size = (1024, 1024)


def _dask_block(block_id: tuple[int, int, int, int, int]) -> np.ndarray | None:
if isinstance(block_id, np.ndarray):
return None
data = np.random.randint(0, 255, size=frame_size, dtype=np.uint8)
return data[(None,) * 3]


chunks = [(1,) * x for x in (1000, 64, 3)]
chunks += [(x,) for x in frame_size]
dask_arr = map_blocks(_dask_block, chunks=chunks, dtype=np.uint8)

if __name__ == "__main__":
from qtpy import QtWidgets

from ndv import NDViewer

qapp = QtWidgets.QApplication([])
v = NDViewer(dask_arr)
v.show()
qapp.exec()
20 changes: 20 additions & 0 deletions examples/jax_arr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from __future__ import annotations

try:
import jax.numpy as jnp
except ImportError:
raise ImportError("Please install jax to run this example")
from numpy_arr import generate_5d_sine_wave
from qtpy import QtWidgets

from ndv import NDViewer

# Example usage
array_shape = (10, 3, 5, 512, 512) # Specify the desired dimensions
sine_wave_5d = jnp.asarray(generate_5d_sine_wave(array_shape))

if __name__ == "__main__":
qapp = QtWidgets.QApplication([])
v = NDViewer(sine_wave_5d, channel_axis=1)
v.show()
qapp.exec()
64 changes: 64 additions & 0 deletions examples/numpy_arr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from __future__ import annotations

import numpy as np


def generate_5d_sine_wave(
shape: tuple[int, int, int, int, int],
amplitude: float = 240,
base_frequency: float = 5,
) -> np.ndarray:
"""5D dataset."""
# Unpack the dimensions
angle_dim, freq_dim, phase_dim, ny, nx = shape

# Create an empty array to hold the data
output = np.zeros(shape)

# Define spatial coordinates for the last two dimensions
half_per = base_frequency * np.pi
x = np.linspace(-half_per, half_per, nx)
y = np.linspace(-half_per, half_per, ny)
y, x = np.meshgrid(y, x)

# Iterate through each parameter in the higher dimensions
for phase_idx in range(phase_dim):
for freq_idx in range(freq_dim):
for angle_idx in range(angle_dim):
# Calculate phase and frequency
phase = np.pi / phase_dim * phase_idx
frequency = 1 + (freq_idx * 0.1) # Increasing frequency with each step

# Calculate angle
angle = np.pi / angle_dim * angle_idx
# Rotate x and y coordinates
xr = np.cos(angle) * x - np.sin(angle) * y
np.sin(angle) * x + np.cos(angle) * y

# Compute the sine wave
sine_wave = (amplitude * 0.5) * np.sin(frequency * xr + phase)
sine_wave += amplitude * 0.5

# Assign to the output array
output[angle_idx, freq_idx, phase_idx] = sine_wave

return output


try:
from skimage import data

img = data.cells3d()
except Exception:
img = generate_5d_sine_wave((10, 3, 8, 512, 512))


if __name__ == "__main__":
from qtpy import QtWidgets

from ndv import NDViewer

qapp = QtWidgets.QApplication([])
v = NDViewer(img)
v.show()
qapp.exec()
23 changes: 23 additions & 0 deletions examples/tensorstore_arr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from __future__ import annotations

import numpy as np
import tensorstore as ts
from qtpy import QtWidgets

from ndv import NDViewer

shape = (10, 4, 3, 512, 512)
ts_array = ts.open(
{"driver": "zarr", "kvstore": {"driver": "memory"}},
create=True,
shape=shape,
dtype=ts.uint8,
).result()
ts_array[:] = np.random.randint(0, 255, size=shape, dtype=np.uint8)
ts_array = ts_array[ts.d[:].label["t", "c", "z", "y", "x"]]

if __name__ == "__main__":
qapp = QtWidgets.QApplication([])
v = NDViewer(ts_array)
v.show()
qapp.exec()
14 changes: 14 additions & 0 deletions examples/xarray_arr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from __future__ import annotations

import xarray as xr
from qtpy import QtWidgets

from ndv import NDViewer

da = xr.tutorial.open_dataset("air_temperature").air

if __name__ == "__main__":
qapp = QtWidgets.QApplication([])
v = NDViewer(da, colormaps=["thermal"], channel_mode="composite")
v.show()
qapp.exec()
16 changes: 16 additions & 0 deletions examples/zarr_arr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from __future__ import annotations

import zarr
import zarr.storage
from qtpy import QtWidgets

from ndv import NDViewer

URL = "https://s3.embl.de/i2k-2020/ngff-example-data/v0.4/tczyx.ome.zarr"
zarr_arr = zarr.open(URL, mode="r")

if __name__ == "__main__":
qapp = QtWidgets.QApplication([])
v = NDViewer(zarr_arr["s0"])
v.show()
qapp.exec()
31 changes: 17 additions & 14 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,35 @@ sources = ["src"]
[project]
name = "ndv"
dynamic = ["version"]
description = "simple ndviewer"
description = "simple nd image viewer"
readme = "README.md"
requires-python = ">=3.8"
requires-python = ">=3.9"
license = { text = "BSD-3-Clause" }
authors = [{ name = "Talley Lambert", email = "talley.lambert@example.com" }]
authors = [{ name = "Talley Lambert", email = "talley.lambert@gmail.com" }]
classifiers = [
"Development Status :: 3 - Alpha",
"License :: OSI Approved :: BSD License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Typing :: Typed",
]
dependencies = []
dependencies = ["qtpy", "numpy", "superqt[cmap,iconify]"]

# https://peps.python.org/pep-0621/#dependencies-optional-dependencies
[project.optional-dependencies]
test = ["pytest", "pytest-cov"]
pyqt = ["pyqt6"]
vispy = ["vispy", "pyopengl"]
pyside = ["pyside6"]
test = ["pytest", "pytest-cov", "pytest-qt", "dask"]
dev = [
"ipython",
"mypy",
"pdbpp", # https://github.com/pdbpp/pdbpp
"pdbpp", # https://github.com/pdbpp/pdbpp
"pre-commit",
"rich", # https://github.com/Textualize/rich
"rich", # https://github.com/Textualize/rich
"ruff",
]

Expand Down Expand Up @@ -81,11 +83,13 @@ ignore = [

[tool.ruff.lint.per-file-ignores]
"tests/*.py" = ["D", "S"]
"examples/*.py" = ["D", "B9"]


# https://docs.astral.sh/ruff/formatter/
[tool.ruff.format]
docstring-code-format = true
skip-magic-trailing-comma = false # default is false
skip-magic-trailing-comma = false # default is false

# https://mypy.readthedocs.io/en/stable/config_file.html
[tool.mypy]
Expand Down Expand Up @@ -119,8 +123,7 @@ exclude_lines = [
source = ["ndv"]

[tool.check-manifest]
ignore = [
".pre-commit-config.yaml",
".ruff_cache/**/*",
"tests/**/*",
]
ignore = [".pre-commit-config.yaml", ".ruff_cache/**/*", "tests/**/*"]

[tool.typos.default]
extend-ignore-identifiers-re = ["(?i)nd2?.*", "(?i)ome", ".*ser_schema"]
5 changes: 5 additions & 0 deletions src/ndv/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@
__version__ = "uninstalled"
__author__ = "Talley Lambert"
__email__ = "[email protected]"

from .viewer._indexing import DataWrapper
from .viewer._stack_viewer import NDViewer

__all__ = ["NDViewer", "DataWrapper"]
1 change: 1 addition & 0 deletions src/ndv/viewer/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""viewer source."""
Loading

0 comments on commit ed8f547

Please sign in to comment.