Skip to content

Commit 903bb3d

Browse files
committed
RF - clean up analyze using arraywriters
Plug in the new fancy arraywriters classes. This allows me to remove some ugly lumps of code.
1 parent 82ad6c8 commit 903bb3d

File tree

2 files changed

+30
-129
lines changed

2 files changed

+30
-129
lines changed

nibabel/analyze.py

Lines changed: 30 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,13 @@
8080
can be loaded with and without a default flip, so the saved zoom will not
8181
constrain the affine.
8282
'''
83+
import sys
84+
8385
import numpy as np
8486

85-
from .volumeutils import (native_code, swapped_code, make_dt_codes,
86-
calculate_scale, allopen, shape_zoom_affine,
87-
array_to_file, array_from_file, can_cast)
87+
from .volumeutils import (native_code, swapped_code, make_dt_codes, allopen,
88+
shape_zoom_affine, array_from_file, seek_tell)
89+
from .arraywriters import make_array_writer, get_slope_inter, WriterError
8890
from .wrapstruct import WrapStruct
8991
from .spatialimages import (HeaderDataError, HeaderTypeError,
9092
SpatialImage)
@@ -530,23 +532,23 @@ def data_to_fileobj(self, data, fileobj):
530532
>>> data.astype(np.float64).tostring('F') == str_io.getvalue()
531533
True
532534
'''
533-
data = np.asarray(data)
534-
slope, inter, mn, mx = self.scaling_from_data(data)
535+
data = np.asanyarray(data)
535536
shape = self.get_data_shape()
536537
if data.shape != shape:
537538
raise HeaderDataError('Data should be shape (%s)' %
538539
', '.join(str(s) for s in shape))
539-
offset = self.get_data_offset()
540540
out_dtype = self.get_data_dtype()
541-
array_to_file(data,
542-
fileobj,
543-
out_dtype,
544-
offset,
545-
inter,
546-
slope,
547-
mn,
548-
mx)
549-
self.set_slope_inter(slope, inter)
541+
try:
542+
arr_writer = make_array_writer(data,
543+
out_dtype,
544+
self.has_data_intercept,
545+
self.has_data_slope)
546+
except WriterError:
547+
msg = sys.exc_info()[1] # python 2 / 3 compatibility
548+
raise HeaderTypeError(msg)
549+
seek_tell(fileobj, self.get_data_offset())
550+
arr_writer.to_fileobj(fileobj)
551+
self.set_slope_inter(*get_slope_inter(arr_writer))
550552

551553
def get_data_dtype(self):
552554
''' Get numpy dtype for data
@@ -756,45 +758,6 @@ def set_slope_inter(self, slope, inter=None):
756758
raise HeaderTypeError('Cannot set slope != 1 or intercept != 0 '
757759
'for Analyze headers')
758760

759-
def scaling_from_data(self, data):
760-
''' Calculate slope, intercept, min, max from data given header
761-
762-
Check that the data can be sensibly adapted to this header data
763-
dtype. If the header type does support useful scaling to allow
764-
this, raise a HeaderTypeError.
765-
766-
Parameters
767-
----------
768-
data : array-like
769-
array of data for which to calculate scaling etc
770-
771-
Returns
772-
-------
773-
divslope : None or scalar
774-
divisor for data, after subtracting intercept. If None, then
775-
there are no valid data
776-
intercept : None or scalar
777-
number to subtract from data before writing.
778-
mn : None or scalar
779-
data minimum to write, None means use data minimum
780-
mx : None or scalar
781-
data maximum to write, None means use data maximum
782-
'''
783-
data = np.asarray(data)
784-
out_dtype = self.get_data_dtype()
785-
if not can_cast(data.dtype.type,
786-
out_dtype.type,
787-
self.has_data_intercept,
788-
self.has_data_slope):
789-
raise HeaderTypeError('Cannot cast data to header dtype without'
790-
' large potential loss in precision')
791-
if not self.has_data_slope:
792-
return 1.0, 0.0, None, None
793-
return calculate_scale(
794-
data,
795-
out_dtype,
796-
self.has_data_intercept)
797-
798761
@classmethod
799762
def _get_checks(klass):
800763
''' Return sequence of check functions for this class '''
@@ -967,41 +930,6 @@ def _write_header(self, header_file, header, slope, inter):
967930
header.set_slope_inter(slope, inter)
968931
header.write_to(header_file)
969932

970-
def _write_image(self, image_file, data, header, slope, inter, mn, mx):
971-
''' Utility routine to write image
972-
973-
Parameters
974-
----------
975-
image_file : file-like
976-
file-like object implementing ``seek`` or ``tell``, and
977-
``write``
978-
data : array-like
979-
array to write
980-
header : analyze-type header object
981-
header
982-
slope : None or float
983-
scale factor for `data` so that written data is ``data /
984-
slope + inter``. None means no valid data
985-
inter : float
986-
intercept (see above)
987-
mn : None or float
988-
minimum to scale data to. None means use data minimum
989-
max : None or float
990-
maximum to scale data to. None means use data maximum
991-
992-
Returns
993-
-------
994-
None
995-
'''
996-
shape = header.get_data_shape()
997-
if data.shape != shape:
998-
raise HeaderDataError('Data should be shape (%s)' %
999-
', '.join(str(s) for s in shape))
1000-
offset = header.get_data_offset()
1001-
out_dtype = header.get_data_dtype()
1002-
array_to_file(data, image_file, out_dtype, offset,
1003-
inter, slope, mn, mx)
1004-
1005933
def to_file_map(self, file_map=None):
1006934
''' Write image to `file_map` or contained ``self.file_map``
1007935
@@ -1016,7 +944,11 @@ def to_file_map(self, file_map=None):
1016944
data = self.get_data()
1017945
self.update_header()
1018946
hdr = self.get_header()
1019-
slope, inter, mn, mx = hdr.scaling_from_data(data)
947+
out_dtype = self.get_data_dtype()
948+
arr_writer = make_array_writer(data,
949+
out_dtype,
950+
hdr.has_data_intercept,
951+
hdr.has_data_slope)
1020952
hdr_fh, img_fh = self._get_fileholders(file_map)
1021953
# Check if hdr and img refer to same file; this can happen with odd
1022954
# analyze images but most often this is because it's a single nifti file
@@ -1026,8 +958,15 @@ def to_file_map(self, file_map=None):
1026958
imgf = hdrf
1027959
else:
1028960
imgf = img_fh.get_prepare_fileobj(mode='wb')
961+
slope, inter = get_slope_inter(arr_writer)
1029962
self._write_header(hdrf, hdr, slope, inter)
1030-
self._write_image(imgf, data, hdr, slope, inter, mn, mx)
963+
# Write image
964+
shape = hdr.get_data_shape()
965+
if data.shape != shape:
966+
raise HeaderDataError('Data should be shape (%s)' %
967+
', '.join(str(s) for s in shape))
968+
seek_tell(imgf, hdr.get_data_offset())
969+
arr_writer.to_fileobj(imgf)
1031970
if hdr_fh.fileobj is None: # was filename
1032971
hdrf.close()
1033972
if not hdr_img_same:

nibabel/tests/test_header_scaling.py

Lines changed: 0 additions & 38 deletions
This file was deleted.

0 commit comments

Comments
 (0)