Skip to content

Commit

Permalink
bump verison, merge branch 'devel'
Browse files Browse the repository at this point in the history
  • Loading branch information
casperdcl committed Nov 12, 2020
2 parents 965710d + 7afa9ba commit ac87bda
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Intended for inclusion in requirements for other packages.
The package name is ``miutil``. Options include:

- nii
- plot

To install options and their dependencies,
use the package name ``miutil[option1,option2]``.
Expand Down
20 changes: 20 additions & 0 deletions miutil/imio/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import re

RE_NII_GZ = re.compile(r"^(.+)(\.nii(?:\.gz)?)$", flags=re.I)
RE_NPYZ = re.compile(r"^(.+)(\.np[yz])$", flags=re.I)


def imread(fname):
"""Read any supported filename"""
if RE_NII_GZ.search(fname):
from .nii import getnii

return getnii(fname)
elif RE_NPYZ.search(fname):
import numpy as np

res = np.load(fname)
if hasattr(res, "keys") and len(res.keys()) == 1:
res = res[list(res.keys())[0]]
return res
raise ValueError("Unknown image type: " + fname)
2 changes: 1 addition & 1 deletion miutil/imio/nii.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
import nibabel as nib
import numpy as np

from . import RE_NII_GZ
from ..fdio import create_dir

RE_NII_GZ = re.compile(r"^(.+)(\.nii(?:\.gz)?)$", flags=re.I)
RE_GZ = re.compile(r"^(.+)(\.gz)$", flags=re.I)
log = logging.getLogger(__name__)

Expand Down
87 changes: 87 additions & 0 deletions miutil/plot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from os import path
import matplotlib.pyplot as plt

from .imio import imread


class imscroll:
"""
Slice through volumes by scrolling.
Hold SHIFT to scroll faster.
"""

instances = []
SUPPORTED_KEYS = ["shift"]

def __init__(self, vol, view="t", fig=None, titles=None, **kwargs):
"""
Scroll through 2D slices of 3D volume(s) using the mouse.
Args:
vol (str or numpy.ndarray or list or dict): path to file or
a (list/dict of) array(s).
view (str): z, t, transverse/y, c, coronal/x, s, sagittal.
fig (matplotlib.pyplot.Figure): will be created if unspecified.
titles (list): list of strings (overrides `vol.keys()`).
**kwargs: passed to `matplotlib.pyplot.imshow()`.
"""
if isinstance(vol, str) and path.exists(vol):
vol = imread(vol)
if hasattr(vol, "keys"):
keys = list(vol.keys())
vol = [vol[i] for i in keys]
if titles is None:
titles = keys
if vol[0].ndim == 2:
vol = [vol]
elif vol[0].ndim != 3:
raise IndexError("Expected vol.ndim in [3, 4] but got {}".format(vol.ndim))

self.titles = titles or [None] * len(vol)

view = view.lower()
if view in ["c", "coronal", "y"]:
vol = [i.transpose(1, 0, 2) for i in vol]
elif view in ["s", "saggital", "x"]:
vol = [i.transpose(2, 0, 1) for i in vol]

self.index_max = min(map(len, vol))
self.index = self.index_max // 2
if fig is not None:
self.fig, axs = fig, fig.subplots(1, len(vol))
else:
self.fig, axs = plt.subplots(1, len(vol))
self.axs = [axs] if len(vol) == 1 else list(axs.flat)
for ax, i, t in zip(self.axs, vol, self.titles):
ax.imshow(i[self.index], **kwargs)
ax.set_title(t or "slice #{}".format(self.index))
self.vols = vol
self.key = {i: False for i in self.SUPPORTED_KEYS}
self.fig.canvas.mpl_connect("scroll_event", self.scroll)
self.fig.canvas.mpl_connect("key_press_event", self.on_key)
self.fig.canvas.mpl_connect("key_release_event", self.off_key)
imscroll.instances.append(self) # prevents gc

@classmethod
def clear(cls, self):
cls.instances.clear()

def on_key(self, event):
if event.key in self.SUPPORTED_KEYS:
self.key[event.key] = True

def off_key(self, event):
if event.key in self.SUPPORTED_KEYS:
self.key[event.key] = False

def scroll(self, event):
self.set_index(
self.index
+ (1 if event.button == "up" else -1) * (10 if self.key["shift"] else 1)
)

def set_index(self, index):
self.index = index % self.index_max
for ax, vol, t in zip(self.axs, self.vols, self.titles):
ax.images[0].set_array(vol[self.index])
ax.set_title(t or "slice #{}".format(self.index))
self.fig.canvas.draw()
4 changes: 3 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = miutil
version = 0.1.0
version = 0.2.0
description = Medical imaging utilities for the AMYPAD and NiftyPET projects
long_description = file: README.rst
license = Apache 2.0
Expand Down Expand Up @@ -48,6 +48,8 @@ dev =
nii =
nibabel
numpy
plot =
matplotlib

[flake8]
max_line_length = 88
Expand Down
19 changes: 19 additions & 0 deletions tests/test_imio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from pytest import importorskip

from miutil.imio import imread


def test_imread(tmp_path):
np = importorskip("numpy")

x = np.random.randint(10, size=(9, 9))
fname = tmp_path / "test_imread.npy"
np.save(fname, x)
assert (imread(str(fname)) == x).all()

fname = tmp_path / "test_imread.npz"
np.savez(fname, x)
assert (imread(str(fname)) == x).all()

np.savez(fname, x, x)
assert (imread(str(fname))["arr_0"] == x).all()
File renamed without changes.

0 comments on commit ac87bda

Please sign in to comment.