Skip to content

Commit

Permalink
DOC+PL+TEST: Correct docstrings and change to property decorators.
Browse files Browse the repository at this point in the history
  • Loading branch information
thomastweets committed Feb 27, 2017
1 parent fdd34b5 commit 351ca44
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 135 deletions.
100 changes: 61 additions & 39 deletions nibabel/brainvoyager/bv.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ def calc_BV_header_size(hdr_dict_proto, hdr_dict, parent_hdr_dict=None):
# check the length of the array to expect
if def_or_name in hdr_dict:
n_values = hdr_dict[def_or_name]
# handle cases when n_values is resides outside of the
# current scope (e.g. nr_of_timepoints in VMP_HDR_DICT_PROTO)
else:
n_values = parent_hdr_dict[def_or_name]
for i in range(n_values):
Expand Down Expand Up @@ -306,7 +308,7 @@ def update_BV_header(hdr_dict_proto, hdr_dict_old, hdr_dict_new,
hdr_dict before any changes.
hdr_dict_new: OrderedDict
hdr_dict with changed fields in n_fields_name or c_fields_name fields.
parent_old: OrderedDict
parent_old: None or OrderedDict, optional
When update_BV_header() is called recursively the not yet updated
(parent) hdr_dict is passed to give access to n_fields_name fields
outside the current scope (see below).
Expand All @@ -325,28 +327,27 @@ def update_BV_header(hdr_dict_proto, hdr_dict_old, hdr_dict_new,
# handle only nested loop fields
if not isinstance(pack_format, tuple):
continue
# calculate the change of array length and the new array length
if def_or_name in hdr_dict_old:
delta_values = (hdr_dict_new[def_or_name] -
hdr_dict_old[def_or_name])
n_values = hdr_dict_new[def_or_name]
else:
# calculate the change of array length and the new array length
if def_or_name in hdr_dict_old:
delta_values = (hdr_dict_new[def_or_name] -
hdr_dict_old[def_or_name])
n_values = hdr_dict_new[def_or_name]
else:
delta_values = (parent_new[def_or_name] -
parent_old[def_or_name])
n_values = parent_new[def_or_name]
if delta_values > 0: # add nested loops
for i in range(delta_values):
hdr_dict_new[name].append(_proto2default(pack_format,
hdr_dict_new))
elif delta_values < 0: # remove nested loops
for i in range(abs(delta_values)):
hdr_dict_new[name].pop()
# loop over nested fields
for i in range(n_values):
update_BV_header(pack_format, hdr_dict_old[name][i],
hdr_dict_new[name][i], hdr_dict_old,
hdr_dict_new)
delta_values = (parent_new[def_or_name] -
parent_old[def_or_name])
n_values = parent_new[def_or_name]
if delta_values > 0: # add nested loops
for i in range(delta_values):
hdr_dict_new[name].append(_proto2default(pack_format,
hdr_dict_new))
elif delta_values < 0: # remove nested loops
for i in range(abs(delta_values)):
hdr_dict_new[name].pop()
# loop over nested fields
for i in range(n_values):
update_BV_header(pack_format, hdr_dict_old[name][i],
hdr_dict_new[name][i], hdr_dict_old,
hdr_dict_new)
return hdr_dict_new


Expand Down Expand Up @@ -453,7 +454,7 @@ class BvFileHeader(Header):
# format defaults
# BV files are radiological (left-is-right) by default
# (VTC files have a flag for that, however)
default_x_flip = True
default_xflip = True
default_endianness = '<' # BV files are always little-endian
allowed_dtypes = [1, 2, 3]
default_dtype = 2
Expand All @@ -470,9 +471,10 @@ def __init__(self,
Parameters
----------
binaryblock : {None, string} optional
binary block to set into header. By default, None, in
which case we insert the default empty header block
hdr_dict : None or OrderedDict, optional
An OrderedDict containing all header fields parsed from the file.
By default, None, in which case we create a default hdr_dict from
the corresponding _HDR_DICT_PROTO
endianness : {None, '<','>', other endian code} string, optional
endianness of the binaryblock. If None, guess endianness
from the data.
Expand Down Expand Up @@ -641,11 +643,12 @@ def set_data_dtype(self, datatype):
raise HeaderDataError(
'File format does not support setting of header!')

def get_xflip(self):
"""Get xflip for data."""
return self.default_x_flip
@property
def xflip(self):
return self.default_xflip

def set_xflip(self, xflip):
@xflip.setter
def xflip(self, xflip):
"""Set xflip for data."""
if xflip is True:
return
Expand All @@ -666,15 +669,15 @@ def get_base_affine(self):
Note that we get the translations from the center of the
(guessed) framing cube of the referenced VMR (anatomical) file.
Internal storage of the image is ZYXT, where (in patient coordiante/
Internal storage of the image is ZYXT, where (in patient coordinates/
real world orientations):
Z := axis increasing from right to left (R to L)
Y := axis increasing from superior to inferior (S to I)
X := axis increasing from anterior to posterior (A to P)
T := volumes (if present in file format)
"""
zooms = self.get_zooms()
if not self.get_xflip():
if not self.xflip:
# make the BV internal Z axis neurological (left-is-left);
# not default in BV files!
zooms = (-zooms[0], zooms[1], zooms[2])
Expand All @@ -689,7 +692,7 @@ def get_base_affine(self):
rot[:, 2] = [0, -zooms[1], 0]

# compute the translation
fcc = np.array(self.get_framing_cube()) / 2 # center of framing cube
fcc = np.array(self.framing_cube) / 2 # center of framing cube
bbc = np.array(self.get_bbox_center()) # center of bounding box
tra = np.dot((bbc - fcc), rot)

Expand All @@ -700,11 +703,14 @@ def get_base_affine(self):

return M

get_best_affine = get_base_affine
def get_best_affine(self):
return self.get_base_affine()

get_default_affine = get_base_affine
def get_default_affine(self):
return self.get_base_affine()

get_affine = get_base_affine
def get_affine(self):
return self.get_base_affine()

def _guess_framing_cube(self):
"""Guess the dimensions of the framing cube.
Expand All @@ -729,7 +735,8 @@ def _guess_framing_cube(self):
else:
return fc, fc, fc

def get_framing_cube(self):
@property
def framing_cube(self):
"""Get the dimensions of the framing cube.
Get the dimensions of the framing cube that constitutes the
Expand All @@ -739,7 +746,8 @@ def get_framing_cube(self):
"""
return self._framing_cube

def set_framing_cube(self, fc):
@framing_cube.setter
def framing_cube(self, fc):
"""Set the dimensions of the framing cube.
Set the dimensions of the framing cube that constitutes the
Expand Down Expand Up @@ -771,10 +779,24 @@ def get_zooms(self):
for d in shape[0:3])

def set_zooms(self, zooms):
"""Set the zooms for the image.
Voxel dimensions of functional data in BV file formats are
always in relationship to the voxel dimensions in a VMR file and
therefore need to be equal for all three spatial dimensions.
Parameters
----------
zooms : int or sequence
An integer or a sequence of integers specifying the relationship
between voxel dimensions and real-world dimensions. If a single
integer is used it is applied to all spatial dimensions. If a
sequence of integers is used all dimensions have to be equal.
"""
if type(zooms) == int:
self._hdr_dict['resolution'] = zooms
else:
if any([zooms[i] != zooms[i + 1] for i in range(len(zooms) - 1)]):
if np.any(np.diff(zooms)):
raise BvError('Zooms for all dimensions must be equal!')
else:
self._hdr_dict['resolution'] = int(zooms[0])
Expand Down
8 changes: 6 additions & 2 deletions nibabel/brainvoyager/bv_vmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ def get_data_shape(self):

def set_data_shape(self, shape=None, zyx=None, n=None):
''' Set shape of data
To conform with nibabel standards this implements shape.
However, to fill the BvVmpHeader with sensible information use the
zyx and the n parameter instead.
Expand Down Expand Up @@ -164,14 +165,16 @@ def set_data_shape(self, shape=None, zyx=None, n=None):
self._hdr_dict = update_BV_header(self.hdr_dict_proto,
hdr_dict_old, self._hdr_dict)

def get_framing_cube(self):
@property
def framing_cube(self):
''' Get the dimensions of the framing cube that constitutes
the coordinate system boundaries for the bounding box.
'''
hdr = self._hdr_dict
return hdr['dim_z'], hdr['dim_y'], hdr['dim_x']

def set_framing_cube(self, fc):
@framing_cube.setter
def framing_cube(self, fc):
''' Set the dimensions of the framing cube that constitutes
the coordinate system boundaries for the bounding box.
Expand All @@ -191,5 +194,6 @@ class BvVmpImage(BvFileImage):
files_types = (('image', '.vmp'),)
valid_exts = ('.vmp',)


load = BvVmpImage.load
save = BvVmpImage.instance_to_filename
43 changes: 19 additions & 24 deletions nibabel/brainvoyager/bv_vmr.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@
)


def computeOffsetPostHDR(hdr_dict, fileobj):
currentSeek = fileobj.tell()
return currentSeek + (hdr_dict['dim_x'] * hdr_dict['dim_y'] *
hdr_dict['dim_z'])
def compute_offset_post_hdr(hdr_dict, fileobj):
current_seek = fileobj.tell()
return current_seek + (hdr_dict['dim_x'] * hdr_dict['dim_y'] *
hdr_dict['dim_z'])


def concatePrePos(preDict, posDict):
def merge_pre_pos(preDict, posDict):
temp = preDict.copy()
temp.update(posDict)
return temp
Expand Down Expand Up @@ -175,7 +175,7 @@ def get_base_affine(self):
rot[:, 2] = [0, -zooms[1], 0]

# compute the translation
fcc = np.array(self.get_framing_cube()) / 2 # center of framing cube
fcc = np.array(self.framing_cube) / 2 # center of framing cube
bbc = np.array(self.get_bbox_center()) # center of bounding box
tra = np.dot((bbc - fcc), rot)

Expand All @@ -187,30 +187,24 @@ def get_base_affine(self):
# look for additional transformations in past_spatial_trans and combine
# with M
if self._hdr_dict['past_spatial_trans']:
STarray = np.zeros((len(self._hdr_dict['past_spatial_trans']),
4, 4))
st_array = np.zeros((len(self._hdr_dict['past_spatial_trans']),
4, 4))
for st in range(len(self._hdr_dict['past_spatial_trans'])):
STarray[st, :, :] = \
st_array[st, :, :] = \
parse_st(self._hdr_dict['past_spatial_trans'][st])
combinedST = combine_st(STarray, inv=True)
M = np.dot(M, combinedST)
combined_st = combine_st(st_array, inv=True)
M = np.dot(M, combined_st)
return M

get_best_affine = get_base_affine

get_default_affine = get_base_affine

get_affine = get_base_affine

@classmethod
def from_fileobj(klass, fileobj, endianness=default_endianness,
check=True):
hdr_dictPre = parse_BV_header(VMR_PRHDR_DICT_PROTO, fileobj)
hdr_dict_pre = parse_BV_header(VMR_PRHDR_DICT_PROTO, fileobj)
# calculate new seek for the post data header
newSeek = computeOffsetPostHDR(hdr_dictPre, fileobj)
fileobj.seek(newSeek)
hdr_dictPos = parse_BV_header(VMR_PSHDR_DICT_PROTO, fileobj)
hdr_dict = concatePrePos(hdr_dictPre, hdr_dictPos)
new_seek = compute_offset_post_hdr(hdr_dict_pre, fileobj)
fileobj.seek(new_seek)
hdr_dict_pos = parse_BV_header(VMR_PSHDR_DICT_PROTO, fileobj)
hdr_dict = merge_pre_pos(hdr_dict_pre, hdr_dict_pos)
# The offset is always 8 for VMR files.
offset = 8
return klass(hdr_dict, endianness, check, offset)
Expand All @@ -219,7 +213,7 @@ def get_bbox_center(self):
"""Get the center coordinate of the bounding box.
Not required for VMR files
"""
return np.array([self.get_framing_cube() / 2 for d in range(3)])
return np.array([self.framing_cube / 2 for d in range(3)])

def get_zooms(self):
return (self._hdr_dict['vox_res_z'], self._hdr_dict['vox_res_y'],
Expand All @@ -236,7 +230,7 @@ def write_to(self, fileobj):
sizePrH = calc_BV_header_size(VMR_PRHDR_DICT_PROTO, self._hdr_dict)
# write the preHeader
fileobj.write(binaryblock[0:sizePrH])
fileobj.seek(computeOffsetPostHDR(self._hdr_dict, fileobj))
fileobj.seek(compute_offset_post_hdr(self._hdr_dict, fileobj))
fileobj.write(binaryblock[sizePrH:])


Expand All @@ -250,5 +244,6 @@ class BvVmrImage(BvFileImage):
files_types = (('image', '.vmr'),)
valid_exts = ('.vmr',)


load = BvVmrImage.load
save = BvVmrImage.instance_to_filename
Loading

0 comments on commit 351ca44

Please sign in to comment.