Utility functions for analyze-like formats
BinOpener(fileish, *args, **kwargs) | Class to accept, maybe open, and context-manage file-likes / filenames |
DtypeMapper() | Specialized mapper for numpy dtypes |
Recoder(codes[, fields, map_maker]) | class to return canonical code(s) from code or aliases |
allopen(fileish, *args, **kwargs) | Compatibility wrapper for old allopen function |
apply_read_scaling(arr[, slope, inter]) | Apply scaling in slope and inter to array arr |
array_from_file(shape, in_dtype, infile[, ...]) | Get array from file with specified shape, dtype and file offset |
array_to_file(data, fileobj[, out_dtype, ...]) | Helper function for writing arrays to file objects |
best_write_scale_ftype(arr[, slope, inter, ...]) | Smallest float type to contain range of arr after scaling |
better_float_of(first, second[, default]) | Return more capable float type of first and second |
finite_range(arr[, check_nan]) | Return range (min, max) or range and flag (min, max, has_nan) from arr |
fname_ext_ul_case(fname) | fname with ext changed to upper / lower case if file exists |
int_scinter_ftype(ifmt[, slope, inter, default]) | float type containing int type ifmt * slope + inter |
make_dt_codes(codes_seqs) | Create full dt codes Recoder instance from datatype codes |
pretty_mapping(mapping[, getterfunc]) | Make pretty string from mapping |
rec2dict(rec) | Convert recarray to dictionary |
seek_tell(fileobj, offset[, write0]) | Seek in fileobj or check we’re in the right place already |
shape_zoom_affine(shape, zooms[, x_flip]) | Get affine implied by given shape and zooms |
working_type(in_type[, slope, inter]) | Return array type from applying slope, inter to array of in_type |
write_zeros(fileobj, count[, block_size]) | Write count zero bytes to fileobj |
Bases: nibabel.openers.Opener
Class to accept, maybe open, and context-manage file-likes / filenames
Provides context manager to close files that the constructor opened for you.
Parameters: | fileish : str or file-like
*args : positional arguments
**kwargs : keyword arguments
|
---|
Bases: object
Specialized mapper for numpy dtypes
We pass this mapper into the Recoder class to deal with numpy dtype hashing.
The hashing problem is that dtypes that compare equal may not have the same hash. This is true for numpys up to the current at time of writing (1.6.0). For numpy 1.2.1 at least, even dtypes that look exactly the same in terms of fields don’t always have the same hash. This makes dtypes difficult to use as keys in a dictionary.
This class wraps a dictionary in order to implement a __getitem__ to deal with dtype hashing. If the key doesn’t appear to be in the mapping, and it is a dtype, we compare (using ==) all known dtype keys to the input key, and return any matching values for the matching key.
Bases: object
class to return canonical code(s) from code or aliases
The concept is a lot easier to read in the implementation and tests than it is to explain, so...
>>> # If you have some codes, and several aliases, like this:
>>> code1 = 1; aliases1=['one', 'first']
>>> code2 = 2; aliases2=['two', 'second']
>>> # You might want to do this:
>>> codes = [[code1]+aliases1,[code2]+aliases2]
>>> recodes = Recoder(codes)
>>> recodes.code['one']
1
>>> recodes.code['second']
2
>>> recodes.code[2]
2
>>> # Or maybe you have a code, a label and some aliases
>>> codes=((1,'label1','one', 'first'),(2,'label2','two'))
>>> # you might want to get back the code or the label
>>> recodes = Recoder(codes, fields=('code','label'))
>>> recodes.code['first']
1
>>> recodes.code['label1']
1
>>> recodes.label[2]
'label2'
>>> # For convenience, you can get the first entered name by
>>> # indexing the object directly
>>> recodes[2]
2
Create recoder object
codes give a sequence of code, alias sequences fields are names by which the entries in these sequences can be accessed.
By default fields gives the first column the name “code”. The first column is the vector of first entries in each of the sequences found in codes. Thence you can get the equivalent first column value with ob.code[value], where value can be a first column value, or a value in any of the other columns in that sequence.
You can give other columns names too, and access them in the same way - see the examples in the class docstring.
Parameters: | codes : seqence of sequences
fields : {(‘code’,) string sequence}, optional
map_maker: callable, optional :
|
---|
Create recoder object
codes give a sequence of code, alias sequences fields are names by which the entries in these sequences can be accessed.
By default fields gives the first column the name “code”. The first column is the vector of first entries in each of the sequences found in codes. Thence you can get the equivalent first column value with ob.code[value], where value can be a first column value, or a value in any of the other columns in that sequence.
You can give other columns names too, and access them in the same way - see the examples in the class docstring.
Parameters: | codes : seqence of sequences
fields : {(‘code’,) string sequence}, optional
map_maker: callable, optional :
|
---|
Add codes to object
Parameters: | code_syn_seqs : sequence
|
---|
Examples
>>> code_syn_seqs = ((1, 'one'), (2, 'two'))
>>> rc = Recoder(code_syn_seqs)
>>> rc.value_set() == set((1,2))
True
>>> rc.add_codes(((3, 'three'), (1, 'first')))
>>> rc.value_set() == set((1,2,3))
True
Return all available code and alias values
Returns same value as obj.field1.keys() and, with the default initializing fields argument of fields=(‘code’,), this will return the same as obj.code.keys()
>>> codes = ((1, 'one'), (2, 'two'), (1, 'repeat value'))
>>> k = Recoder(codes).keys()
>>> set(k) == set([1, 2, 'one', 'repeat value', 'two'])
True
Return set of possible returned values for column
By default, the column is the first column.
Returns same values as set(obj.field1.values()) and, with the default initializing``fields`` argument of fields=(‘code’,), this will return the same as set(obj.code.values())
Parameters: | name : {None, string}
>>> codes = ((1, ‘one’), (2, ‘two’), (1, ‘repeat value’)) : >>> vs = Recoder(codes).value_set() : >>> vs == set([1, 2]) # Sets are not ordered, hence this test : True : >>> rc = Recoder(codes, fields=(‘code’, ‘label’)) : >>> rc.value_set(‘label’) == set((‘one’, ‘two’, ‘repeat value’)) : True : |
---|
Compatibility wrapper for old allopen function
Wraps creation of BinOpener instance, while picking up module global default_compresslevel.
Please see docstring for BinOpener and Opener for details.
Apply scaling in slope and inter to array arr
This is for loading the array from a file (as opposed to the reverse scaling when saving an array to file)
Return data will be arr * slope + inter. The trick is that we have to find a good precision to use for applying the scaling. The heuristic is that the data is always upcast to the higher of the types from arr, `slope, inter if slope and / or inter are not default values. If the dtype of arr is an integer, then we assume the data more or less fills the integer range, and upcast to a type such that the min, max of arr.dtype * scale + inter, will be finite.
Parameters: | arr : array-like slope : None or float, optional
inter : None or float, optional
|
---|---|
Returns: | ret : array
|
Get array from file with specified shape, dtype and file offset
Parameters: | shape : sequence
in_dtype : numpy dtype
infile : file-like
offset : int, optional
order : {‘F’, ‘C’} string
mmap : {True, False, ‘c’, ‘r’, ‘r+’}
|
---|---|
Returns: | arr : array-like
|
Examples
>>> from io import BytesIO
>>> bio = BytesIO()
>>> arr = np.arange(6).reshape(1,2,3)
>>> _ = bio.write(arr.tostring('F')) # outputs int in python3
>>> arr2 = array_from_file((1,2,3), arr.dtype, bio)
>>> np.all(arr == arr2)
True
>>> bio = BytesIO()
>>> _ = bio.write(b' ' * 10)
>>> _ = bio.write(arr.tostring('F'))
>>> arr2 = array_from_file((1,2,3), arr.dtype, bio, 10)
>>> np.all(arr == arr2)
True
Helper function for writing arrays to file objects
Writes arrays as scaled by intercept and divslope, and clipped at (prescaling) mn minimum, and mx maximum.
Parameters: | data : array-like
fileobj : file-like
out_dtype : None or dtype, optional
offset : None or int, optional
intercept : scalar, optional
divslope : None or scalar, optional
mn : scalar, optional
mx : scalar, optional
order : {‘F’, ‘C’}, optional
nan2zero : {True, False}, optional
|
---|
Examples
>>> from io import BytesIO
>>> sio = BytesIO()
>>> data = np.arange(10, dtype=np.float)
>>> array_to_file(data, sio, np.float)
>>> sio.getvalue() == data.tostring('F')
True
>>> _ = sio.truncate(0); _ = sio.seek(0) # outputs 0 in python 3
>>> array_to_file(data, sio, np.int16)
>>> sio.getvalue() == data.astype(np.int16).tostring()
True
>>> _ = sio.truncate(0); _ = sio.seek(0)
>>> array_to_file(data.byteswap(), sio, np.float)
>>> sio.getvalue() == data.byteswap().tostring('F')
True
>>> _ = sio.truncate(0); _ = sio.seek(0)
>>> array_to_file(data, sio, np.float, order='C')
>>> sio.getvalue() == data.tostring('C')
True
Smallest float type to contain range of arr after scaling
Scaling that will be applied to arr is (arr - inter) / slope.
Note that slope and inter get promoted to 1D arrays for this purpose to avoid the numpy scalar casting rules, which prevent scalars upcasting the array.
Parameters: | arr : array-like
slope : array-like, optional
inter : array-like, optional
default : numpy type, optional
|
---|---|
Returns: | ftype : numpy type
|
Examples
>>> arr = np.array([0, 1, 2], dtype=np.int16)
>>> best_write_scale_ftype(arr, 1, 0) is np.float32
True
Specify higher default return value
>>> best_write_scale_ftype(arr, 1, 0, default=np.float64) is np.float64
True
Even large values that don’t overflow don’t change output
>>> arr = np.array([0, np.finfo(np.float32).max], dtype=np.float32)
>>> best_write_scale_ftype(arr, 1, 0) is np.float32
True
Scaling > 1 reduces output values, so no upcast needed
>>> best_write_scale_ftype(arr, np.float32(2), 0) is np.float32
True
Scaling < 1 increases values, so upcast may be needed (and is here)
>>> best_write_scale_ftype(arr, np.float32(0.5), 0) is np.float64
True
Return more capable float type of first and second
Return default if neither of first or second is a float
Parameters: | first : numpy type specifier
second : numpy type specifier
default : numpy type specifier, optional
|
---|---|
Returns: | better_type : numpy type
|
Examples
>>> better_float_of(np.float32, np.float64) is np.float64
True
>>> better_float_of(np.float32, 'i4') is np.float32
True
>>> better_float_of('i2', 'u4') is np.float32
True
>>> better_float_of('i2', 'u4', np.float64) is np.float64
True
Return range (min, max) or range and flag (min, max, has_nan) from arr
Parameters: | arr : array-like check_nan : {False, True}, optional
|
---|---|
Returns: | mn : scalar
mx : scalar
has_nan : bool
|
Examples
>>> a = np.array([[-1, 0, 1],[np.inf, np.nan, -np.inf]])
>>> finite_range(a)
(-1.0, 1.0)
>>> a = np.array([[-1, 0, 1],[np.inf, np.nan, -np.inf]])
>>> finite_range(a, check_nan=True)
(-1.0, 1.0, True)
>>> a = np.array([[np.nan],[np.nan]])
>>> finite_range(a) == (np.inf, -np.inf)
True
>>> a = np.array([[-3, 0, 1],[2,-1,4]], dtype=np.int)
>>> finite_range(a)
(-3, 4)
>>> a = np.array([[1, 0, 1],[2,3,4]], dtype=np.uint)
>>> finite_range(a)
(0, 4)
>>> a = a + 1j
>>> finite_range(a)
(1j, (4+1j))
>>> a = np.zeros((2,), dtype=[('f1', 'i2')])
>>> finite_range(a)
Traceback (most recent call last):
...
TypeError: Can only handle numeric types
Traceback (most recent call last):
...
TypeError: Can only handle numeric types
fname with ext changed to upper / lower case if file exists
Check for existence of fname. If it does exist, return unmodified. If it doesn’t, check for existence of fname with case changed from lower to upper, or upper to lower. Return this modified fname if it exists. Otherwise return fname unmodified
Parameters: | fname : str
|
---|---|
Returns: | mod_fname : str
|
float type containing int type ifmt * slope + inter
Return float type that can represent the max and the min of the ifmt type after multiplication with slope and addition of inter with something like np.array([imin, imax], dtype=ifmt) * slope + inter.
Note that slope and inter get promoted to 1D arrays for this purpose to avoid the numpy scalar casting rules, which prevent scalars upcasting the array.
Parameters: | ifmt : object
slope : float, optional
inter : float, optional
default_out : object, optional
|
---|---|
Returns: | ftype : object
|
Notes
It is difficult to make floats overflow with just addition because the deltas are so large at the extremes of floating point. For example:
>>> arr = np.array([np.finfo(np.float32).max], dtype=np.float32)
>>> res = arr + np.iinfo(np.int16).max
>>> arr == res
array([ True], dtype=bool)
Examples
>>> int_scinter_ftype(np.int8, 1.0, 0.0) == np.float32
True
>>> int_scinter_ftype(np.int8, 1e38, 0.0) == np.float64
True
Create full dt codes Recoder instance from datatype codes
Include created numpy dtype (from numpy type) and opposite endian numpy dtype
Parameters: | codes_seqs : sequence of sequences
|
---|---|
Returns: | rec : Recoder instance
|
Make pretty string from mapping
Adjusts text column to print values on basis of longest key. Probably only sensible if keys are mainly strings.
You can pass in a callable that does clever things to get the values out of the mapping, given the names. By default, we just use __getitem__
Parameters: | mapping : mapping
getterfunc : None or callable
|
---|---|
Returns: | str : string |
Examples
>>> d = {'a key': 'a value'}
>>> print(pretty_mapping(d))
a key : a value
>>> class C(object): # to control ordering, show get_ method
... def __iter__(self):
... return iter(('short_field','longer_field'))
... def __getitem__(self, key):
... if key == 'short_field':
... return 0
... if key == 'longer_field':
... return 'str'
... def get_longer_field(self):
... return 'method string'
>>> def getter(obj, key):
... # Look for any 'get_<name>' methods
... try:
... return obj.__getattribute__('get_' + key)()
... except AttributeError:
... return obj[key]
>>> print(pretty_mapping(C(), getter))
short_field : 0
longer_field : method string
Convert recarray to dictionary
Also converts scalar values to scalars
Parameters: | rec : ndarray
|
---|---|
Returns: | dct : dict
|
Examples
>>> r = np.zeros((), dtype = [('x', 'i4'), ('s', 'S10')])
>>> d = rec2dict(r)
>>> d == {'x': 0, 's': b''}
True
Seek in fileobj or check we’re in the right place already
Parameters: | fileobj : file-like
offset : int
write0 : {False, True}, optional
|
---|
Get affine implied by given shape and zooms
We get the translations from the center of the image (implied by shape).
Parameters: | shape : (N,) array-like
zooms : (N,) array-like
x_flip : {True, False}
|
---|---|
Returns: | aff : (4,4) array
|
Examples
>>> shape = (3, 5, 7)
>>> zooms = (3, 2, 1)
>>> shape_zoom_affine((3, 5, 7), (3, 2, 1))
array([[-3., 0., 0., 3.],
[ 0., 2., 0., -4.],
[ 0., 0., 1., -3.],
[ 0., 0., 0., 1.]])
>>> shape_zoom_affine((3, 5, 7), (3, 2, 1), False)
array([[ 3., 0., 0., -3.],
[ 0., 2., 0., -4.],
[ 0., 0., 1., -3.],
[ 0., 0., 0., 1.]])
Return array type from applying slope, inter to array of in_type
Numpy type that results from an array of type in_type being combined with slope and inter. It returns something like the dtype type of ((np.zeros((2,), dtype=in_type) - inter) / slope), but ignoring the actual values of slope and inter.
Note that you would not necessarily get the same type by applying slope and inter the other way round. Also, you’ll see that the order in which slope and inter are applied is the opposite of the order in which they are passed.
Parameters: | in_type : numpy type specifier
slope : scalar, optional
inter : scalar, optional
|
---|---|
Returns: | wtype: numpy type :
|