Skip to content

Commit

Permalink
bump version, merge pull request #27 from AMYPAD/devel
Browse files Browse the repository at this point in the history
  • Loading branch information
casperdcl authored Jan 16, 2022
2 parents f54cf4a + fe58d1c commit 1a9af92
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 61 deletions.
9 changes: 6 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ default_language_version:
python: python3
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1
rev: v4.1.0
hooks:
- id: check-added-large-files
- id: check-case-conflict
Expand Down Expand Up @@ -31,16 +31,19 @@ repos:
- id: flake8
args: [-j8]
additional_dependencies:
- flake8-broken-line
- flake8-bugbear
- flake8-comprehensions
- flake8-debugger
- flake8-isort
- flake8-string-format
- repo: https://github.com/google/yapf
rev: v0.31.0
rev: v0.32.0
hooks:
- id: yapf
args: [-i]
additional_dependencies: [toml]
- repo: https://github.com/PyCQA/isort
rev: 5.9.3
rev: 5.10.1
hooks:
- id: isort
1 change: 1 addition & 0 deletions miutil/fdio.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ def extractall(fzip, dest, desc="Extracting"):

def nsort(fnames):
"""Sort a file list, automatically detecting embedded numbers"""

def path2parts(fname):
parts = re.split(r"([0-9][0-9.]*e[-+][0-9]+|[0-9]+\.[0-9]+|[0-9]+)", fname)
parts[1::2] = map(float, parts[1::2])
Expand Down
68 changes: 32 additions & 36 deletions miutil/imio/nii.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def nii_gzip(imfile, outpath=""):
return fout


def getnii(fim, nan_replace=None, output="image"):
def getnii(fim, nan_replace=None, output='image'):
"""
Get PET image from NIfTI file.
Arguments:
Expand All @@ -71,10 +71,10 @@ def getnii(fim, nan_replace=None, output="image"):
"""
nim = nib.load(fspath(fim))

dim = nim.header.get("dim")
dim = nim.header.get('dim')
dimno = dim[0]

if output == "image" or output == "all":
if output == 'image' or output == 'all':
imr = np.asanyarray(nim.dataobj)
# replace NaNs if requested
if isinstance(nan_replace, numbers.Number):
Expand All @@ -86,38 +86,37 @@ def getnii(fim, nan_replace=None, output="image"):

# > get orientations from the affine
ornt = nib.io_orientation(nim.affine)
trnsp = tuple(2 - np.int8(ornt[:, 0]))
trnsp = tuple(np.int8([ornt[2, 0], ornt[1, 0], ornt[0, 0]]))
flip = tuple(np.int8(ornt[:, 1]))

# > voxel size
voxsize = nim.header.get("pixdim")[1:nim.header.get("dim")[0] + 1]
voxsize = nim.header.get('pixdim')[1:nim.header.get('dim')[0] + 1]
# > rearrange voxel size according to the orientation
voxsize = voxsize[np.array(trnsp)]

# > dimensions
dims = dim[1:nim.header.get("dim")[0] + 1]
dims = dim[1:nim.header.get('dim')[0] + 1]
dims = dims[np.array(trnsp)]

# > flip y-axis and z-axis and then transpose.
# Depends if dynamic (4 dimensions) or static (3 dimensions)
if dimno == 4:
# > flip y-axis and z-axis and then transpose
if dimno == 4: # dynamic
imr = np.transpose(imr[::-flip[0], ::-flip[1], ::-flip[2], :], (3,) + trnsp)
elif dimno == 3:
elif dimno == 3: # static
imr = np.transpose(imr[::-flip[0], ::-flip[1], ::-flip[2]], trnsp)

if output == "affine" or output == "all":
if output == 'affine' or output == 'all':
# A = nim.get_sform()
# if not A[:3,:3].any():
# A = nim.get_qform()
A = nim.affine

if output == "all":
if output == 'all':
out = {
"im": imr, "affine": A, "fim": fim, "dtype": nim.get_data_dtype(), "shape": imr.shape,
"hdr": nim.header, "voxsize": voxsize, "dims": dims, "transpose": trnsp, "flip": flip}
elif output == "image":
'im': imr, 'affine': A, 'fim': fim, 'dtype': nim.get_data_dtype(), 'shape': imr.shape,
'hdr': nim.header, 'voxsize': voxsize, 'dims': dims, 'transpose': trnsp, 'flip': flip}
elif output == 'image':
out = imr
elif output == "affine":
elif output == 'affine':
out = A
else:
raise NameError("Unrecognised output request!")
Expand Down Expand Up @@ -154,15 +153,12 @@ def array2nii(im, A, fnii, descrip="", trnsp=None, flip=None, storage_as=None):
# >>as obtained from getnii(..., output='all')

# > permute the axis order in the image array
if (isinstance(storage_as, dict) and "transpose" in storage_as and "flip" in storage_as):
if (isinstance(storage_as, dict) and 'transpose' in storage_as and 'flip' in storage_as):

trnsp = (
storage_as["transpose"].index(0),
storage_as["transpose"].index(1),
storage_as["transpose"].index(2),
)
trnsp = (storage_as['transpose'].index(0), storage_as['transpose'].index(1),
storage_as['transpose'].index(2))

flip = storage_as["flip"]
flip = storage_as['flip']

if not trnsp:
im = im.transpose()
Expand All @@ -179,10 +175,10 @@ def array2nii(im, A, fnii, descrip="", trnsp=None, flip=None, storage_as=None):

res = nib.Nifti1Image(im, A)
hdr = res.header
hdr.set_sform(None, code="scanner")
hdr["cal_max"] = np.max(im) # np.percentile(im, 90) #
hdr["cal_min"] = np.min(im)
hdr["descrip"] = descrip
hdr.set_sform(None, code='scanner')
hdr['cal_max'] = np.max(im) # np.percentile(im, 90) #
hdr['cal_min'] = np.min(im)
hdr['descrip'] = descrip
nib.save(res, fspath(fnii))


Expand Down Expand Up @@ -255,23 +251,23 @@ def niisort(fims, memlim=True):
raise ValueError("Input image(s) must be 3D.")

out = {
"shape": _nii.shape[::-1], "files": _fims, "sortlist": sortlist,
"dtype": _nii.get_data_dtype(), "N": Nim}
'shape': _nii.shape[::-1], 'files': _fims, 'sortlist': sortlist,
'dtype': _nii.get_data_dtype(), 'N': Nim}

if memlim and Nfrm > 50:
imdic = getnii(_fims[0], output="all")
affine = imdic["affine"]
imdic = getnii(_fims[0], output='all')
affine = imdic['affine']
else:
# get the images into an array
_imin = np.zeros((Nfrm,) + _nii.shape[::-1], dtype=_nii.get_data_dtype())
for i in range(Nfrm):
if i in sortlist:
imdic = getnii(_fims[i], output="all")
_imin[i, :, :, :] = imdic["im"]
affine = imdic["affine"]
out["im"] = _imin[:Nfrm, :, :, :]
imdic = getnii(_fims[i], output='all')
_imin[i, :, :, :] = imdic['im']
affine = imdic['affine']
out['im'] = _imin[:Nfrm, :, :, :]

out["affine"] = affine
out['affine'] = affine

return out

Expand Down
49 changes: 28 additions & 21 deletions miutil/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@ class imscroll:
"""

_instances = []
_SUPPORTED_KEYS = ["control", "shift"]
_SUPPORTED_KEYS = ['control', 'shift']

def __init__(self, vol, view="t", fig=None, titles=None, order=0, **kwargs):
def __init__(self, vol, view='t', fig=None, titles=None, order=0, sharexy=None, show=False,
**kwargs):
"""
Scroll through 2D slices of 3D volume(s) using the mouse.
Args:
Expand All @@ -56,6 +57,8 @@ def __init__(self, vol, view="t", fig=None, titles=None, order=0, **kwargs):
titles (list): list of strings (overrides `vol.keys()`).
order (int): spline interpolation order for line profiles.
0: nearest, 1: bilinear, >2: probably avoid.
sharexy (bool): whether to link zoom across all axes.
show (bool): whether to run `matplotlib.pyplot.show()`.
**kwargs: passed to `matplotlib.pyplot.imshow()`.
"""
if isinstance(vol, str) and path.exists(vol):
Expand All @@ -79,19 +82,21 @@ def __init__(self, vol, view="t", fig=None, titles=None, order=0, **kwargs):
""".format(ndim)))

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

# volumes
self.titles = titles or [None] * len(vol)
self.index_max = min(map(len, vol))
self.index = self.index_max // 2
if sharexy is None:
sharexy = len({i.shape for i in vol}) == 1
if fig is not None:
self.fig, axs = fig, fig.subplots(1, len(vol))
self.fig, axs = fig, fig.subplots(1, len(vol), sharex=sharexy, sharey=sharexy)
else:
self.fig, axs = plt.subplots(1, len(vol))
self.fig, axs = plt.subplots(1, len(vol), sharex=sharexy, sharey=sharexy)
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)
Expand All @@ -103,28 +108,30 @@ def __init__(self, vol, view="t", fig=None, titles=None, order=0, **kwargs):
self._annotes = []
# event callbacks
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)
self.fig.canvas.mpl_connect("button_press_event", self._on_click)
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)
self.fig.canvas.mpl_connect('button_press_event', self._on_click)
imscroll._instances.append(self) # prevents gc
if show:
plt.show()

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

def _on_key(self, event):
key = {"ctrl": "control"}.get(event.key, event.key)
key = {'ctrl': 'control'}.get(event.key, event.key)
if key in self._SUPPORTED_KEYS:
self.key[key] = True

def _off_key(self, event):
key = {"ctrl": "control"}.get(event.key, event.key)
key = {'ctrl': 'control'}.get(event.key, event.key)
if key in self._SUPPORTED_KEYS:
self.key[key] = False

def _scroll(self, event):
self.set_index(self.index + event.step * (10 if self.key["shift"] else 1))
self.set_index(self.index + event.step * (10 if self.key['shift'] else 1))

def set_index(self, index):
self.index = int(index) % self.index_max
Expand All @@ -137,7 +144,7 @@ def set_index(self, index):
self.fig.canvas.draw()

def _on_click(self, event):
if not self.key["control"] or None in (event.xdata, event.ydata):
if not self.key['control'] or None in (event.xdata, event.ydata):
return
self.picked.append((event.xdata, event.ydata))
if len(self.picked) < 2:
Expand All @@ -156,20 +163,20 @@ def _on_click(self, event):
arr,
np.vstack((x, y, np.ones_like(x) * i)),
order=self.order,
mode="nearest",
mode='nearest',
) for i in range(event.inaxes.images[0].get_array().shape[-1])]
else:
z = ndi.map_coordinates(arr, np.vstack((x, y)), order=self.order, mode="nearest")
z = ndi.map_coordinates(arr, np.vstack((x, y)), order=self.order, mode='nearest')
self.picked = []
self.key["control"] = False
self.key['control'] = False

self._annotes.append(event.inaxes.plot([x0, x1], [y0, y1], "r-")[0])
self._annotes.append(event.inaxes.plot([x0, x1], [y0, y1], 'r-')[0])
plt.figure()
if arr.ndim == 3:
for channel, colour in zip(z, "rgbcmyk"):
plt.plot(x, channel, colour + "-")
for channel, colour in zip(z, 'rgbcmyk'):
plt.plot(x, channel, colour + '-')
else:
plt.plot(x, z, "r-")
plt.plot(x, z, 'r-')
plt.xlabel("x")
plt.ylabel("Intensity")
plt.show()
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[build-system]
requires = ["setuptools>=42", "wheel", "setuptools_scm[toml]>=3.4"]
build-backend = "setuptools.build_meta"

[tool.setuptools_scm]
write_to = "miutil/_dist_ver.py"
Expand Down

0 comments on commit 1a9af92

Please sign in to comment.