Skip to content

Commit 0ce347f

Browse files
author
Ben Cipollini
committed
Merge remote-tracking branch 'upstream/master' into gifti-loadsave
2 parents 54c3019 + 63f9ef2 commit 0ce347f

File tree

7 files changed

+481
-110
lines changed

7 files changed

+481
-110
lines changed

nibabel/fileslice.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -767,9 +767,15 @@ def strided_scalar(shape, scalar=0.):
767767
strided_arr : array
768768
Array of shape `shape` for which all values == `scalar`, built by
769769
setting all strides of `strided_arr` to 0, so the scalar is broadcast
770-
out to the full array `shape`.
770+
out to the full array `shape`. `strided_arr` is flagged as not
771+
`writeable`.
772+
773+
The array is set read-only to avoid a numpy error when broadcasting -
774+
see https://github.com/numpy/numpy/issues/6491
771775
"""
772776
shape = tuple(shape)
773777
scalar = np.array(scalar)
774778
strides = [0] * len(shape)
775-
return np.lib.stride_tricks.as_strided(scalar, shape, strides)
779+
strided_scalar = np.lib.stride_tricks.as_strided(scalar, shape, strides)
780+
strided_scalar.flags.writeable = False
781+
return strided_scalar

nibabel/gifti/gifti.py

+117-39
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212

1313
import numpy as np
1414

15+
from .util import (array_index_order_codes, gifti_encoding_codes,
16+
gifti_endian_codes, KIND2FMT)
1517
from .. import xmlutils as xml
1618
from ..filebasedimages import FileBasedHeader, FileBasedImage
1719
from ..nifti1 import data_type_codes, xform_codes, intent_codes
18-
from .util import (array_index_order_codes, gifti_encoding_codes,
19-
gifti_endian_codes, KIND2FMT)
2020

2121
# {en,de}codestring in deprecated in Python3, but
2222
# {en,de}codebytes not available in Python2.
@@ -40,7 +40,12 @@ def from_dict(klass, data_dict):
4040
meda.data.append(nv)
4141
return meda
4242

43+
@np.deprecate_with_doc("Use the metadata property instead.")
4344
def get_metadata(self):
45+
return self.metadata
46+
47+
@property
48+
def metadata(self):
4449
""" Returns metadata as dictionary """
4550
self.data_as_dict = {}
4651
for ele in self.data:
@@ -58,7 +63,7 @@ def _to_xml_element(self):
5863
return metadata
5964

6065
def print_summary(self):
61-
print(self.get_metadata())
66+
print(self.metadata)
6267

6368

6469
class GiftiNVPairs(object):
@@ -118,10 +123,28 @@ def __init__(self, key=0, label='', red=None, green=None, blue=None,
118123
self.blue = blue
119124
self.alpha = alpha
120125

126+
@np.deprecate_with_doc("Use the rgba property instead.")
121127
def get_rgba(self):
128+
return self.rgba
129+
130+
@property
131+
def rgba(self):
122132
""" Returns RGBA as tuple """
123133
return (self.red, self.green, self.blue, self.alpha)
124134

135+
@rgba.setter
136+
def rgba(self, rgba):
137+
""" Set RGBA via tuple
138+
139+
Parameters
140+
----------
141+
rgba : tuple (red, green, blue, alpha)
142+
143+
"""
144+
if len(rgba) != 4:
145+
raise ValueError('rgba must be length 4.')
146+
self.red, self.green, self.blue, self.alpha = rgba
147+
125148

126149
def _arr2txt(arr, elem_fmt):
127150
arr = np.asarray(arr)
@@ -163,6 +186,17 @@ def print_summary(self):
163186
print('Affine Transformation Matrix: \n', self.xform)
164187

165188

189+
@np.deprecate_with_doc("This is an internal API that will be discontinued.")
190+
def data_tag(dataarray, encoding, datatype, ordering):
191+
class DataTag(xml.XmlSerializable):
192+
def __init__(self, *args):
193+
self.args = args
194+
def _to_xml_element(self):
195+
return _data_tag_element(*self.args)
196+
197+
return DataTag(dataarray, encoding, datatype, ordering).to_xml()
198+
199+
166200
def _data_tag_element(dataarray, encoding, datatype, ordering):
167201
""" Creates the data tag depending on the required encoding,
168202
returns as XML element"""
@@ -297,6 +331,34 @@ def _to_xml_element(self):
297331

298332
return data_array
299333

334+
@np.deprecate_with_doc("Use the to_xml() function instead.")
335+
def to_xml_open(self):
336+
out = """<DataArray Intent="%s"
337+
\tDataType="%s"
338+
\tArrayIndexingOrder="%s"
339+
\tDimensionality="%s"
340+
%s\tEncoding="%s"
341+
\tEndian="%s"
342+
\tExternalFileName="%s"
343+
\tExternalFileOffset="%s">\n"""
344+
di = ""
345+
for i, n in enumerate(self.dims):
346+
di = di + '\tDim%s=\"%s\"\n' % (str(i), str(n))
347+
return out % (intent_codes.niistring[self.intent],
348+
data_type_codes.niistring[self.datatype],
349+
array_index_order_codes.label[self.ind_ord],
350+
str(self.num_dim),
351+
str(di),
352+
gifti_encoding_codes.specs[self.encoding],
353+
gifti_endian_codes.specs[self.endian],
354+
self.ext_fname,
355+
self.ext_offset,
356+
)
357+
358+
@np.deprecate_with_doc("Use the to_xml() function instead.")
359+
def to_xml_close(self):
360+
return "</DataArray>\n"
361+
300362
def print_summary(self):
301363
print('Intent: ', intent_codes.niistring[self.intent])
302364
print('DataType: ', data_type_codes.niistring[self.datatype])
@@ -313,13 +375,15 @@ def print_summary(self):
313375
print('Coordinate System:')
314376
print(self.coordsys.print_summary())
315377

378+
@np.deprecate_with_doc("Use the metadata property instead.")
316379
def get_metadata(self):
317-
""" Returns metadata as dictionary """
318-
return self.meta.get_metadata()
380+
return self.meta.metadata
319381

382+
@property
383+
def metadata(self):
384+
""" Returns metadata as dictionary """
385+
return self.meta.metadata
320386

321-
class GiftiHeader(FileBasedHeader):
322-
pass
323387

324388
class GiftiImage(FileBasedImage, xml.XmlSerializable):
325389
valid_exts = ('.gii',)
@@ -332,38 +396,52 @@ def __init__(self, header=None, extra=None, file_map=None, meta=None,
332396

333397
if darrays is None:
334398
darrays = []
335-
self.darrays = darrays
336399
if meta is None:
337-
self.meta = GiftiMetaData()
338-
else:
339-
self.meta = meta
400+
meta = GiftiMetaData()
340401
if labeltable is None:
341-
self.labeltable = GiftiLabelTable()
342-
else:
343-
self.labeltable = labeltable
344-
self.numDA = len(self.darrays)
402+
labeltable = GiftiLabelTable()
403+
404+
self._labeltable = labeltable
405+
self._meta = meta
406+
407+
self.darrays = darrays
345408
self.version = version
346409

347-
def get_labeltable(self):
348-
return self.labeltable
410+
@property
411+
def numDA(self):
412+
return len(self.darrays)
349413

350-
def set_labeltable(self, labeltable):
414+
@property
415+
def labeltable(self):
416+
return self._labeltable
417+
418+
@labeltable.setter
419+
def labeltable(self, labeltable):
351420
""" Set the labeltable for this GiftiImage
352421
353422
Parameters
354423
----------
355424
labeltable : GiftiLabelTable
356425
357426
"""
358-
if isinstance(labeltable, GiftiLabelTable):
359-
self.labeltable = labeltable
360-
else:
361-
print("Not a valid GiftiLabelTable instance")
427+
if not isinstance(labeltable, GiftiLabelTable):
428+
raise TypeError("Not a valid GiftiLabelTable instance")
429+
self._labeltable = labeltable
362430

363-
def get_metadata(self):
364-
return self.meta
431+
@np.deprecate_with_doc("Use the gifti_img.labeltable property instead.")
432+
def set_labeltable(self, labeltable):
433+
self.labeltable = labeltable
365434

366-
def set_metadata(self, meta):
435+
@np.deprecate_with_doc("Use the gifti_img.labeltable property instead.")
436+
def get_labeltable(self):
437+
return self.labeltable
438+
439+
@property
440+
def meta(self):
441+
return self._meta
442+
443+
@meta.setter
444+
def meta(self, meta):
367445
""" Set the metadata for this GiftiImage
368446
369447
Parameters
@@ -374,12 +452,17 @@ def set_metadata(self, meta):
374452
-------
375453
None
376454
"""
377-
if isinstance(meta, GiftiMetaData):
378-
self.meta = meta
379-
print("New Metadata set. Be aware of changing "
380-
"coordinate transformation!")
381-
else:
382-
print("Not a valid GiftiMetaData instance")
455+
if not isinstance(meta, GiftiMetaData):
456+
raise TypeError("Not a valid GiftiMetaData instance")
457+
self._meta = meta
458+
459+
@np.deprecate_with_doc("Use the gifti_img.labeltable property instead.")
460+
def set_metadata(self, meta):
461+
self.meta = meta
462+
463+
@np.deprecate_with_doc("Use the gifti_img.labeltable property instead.")
464+
def get_meta(self):
465+
return self.meta
383466

384467
def add_gifti_data_array(self, dataarr):
385468
""" Adds a data array to the GiftiImage
@@ -388,24 +471,20 @@ def add_gifti_data_array(self, dataarr):
388471
----------
389472
dataarr : GiftiDataArray
390473
"""
391-
if isinstance(dataarr, GiftiDataArray):
392-
self.darrays.append(dataarr)
393-
self.numDA += 1
394-
else:
395-
print("dataarr paramater must be of tzpe GiftiDataArray")
474+
if not isinstance(dataarr, GiftiDataArray):
475+
raise TypeError("Not a valid GiftiDataArray instance")
476+
self.darrays.append(dataarr)
396477

397478
def remove_gifti_data_array(self, ith):
398479
""" Removes the ith data array element from the GiftiImage """
399480
self.darrays.pop(ith)
400-
self.numDA -= 1
401481

402482
def remove_gifti_data_array_by_intent(self, intent):
403483
""" Removes all the data arrays with the given intent type """
404484
intent2remove = intent_codes.code[intent]
405485
for dele in self.darrays:
406486
if dele.intent == intent2remove:
407487
self.darrays.remove(dele)
408-
self.numDA -= 1
409488

410489
def get_arrays_from_intent(self, intent):
411490
""" Returns a a list of GiftiDataArray elements matching
@@ -438,7 +517,6 @@ def print_summary(self):
438517
print(da.print_summary())
439518
print('----end----')
440519

441-
442520
def _to_xml_element(self):
443521
GIFTI = xml.Element('GIFTI', attrib={
444522
'Version': self.version,

nibabel/gifti/giftiio.py

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*-
2+
# vi: set ft=python sts=4 ts=4 sw=4 et:
3+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
4+
#
5+
# See COPYING file distributed along with the NiBabel package for the
6+
# copyright and license terms.
7+
#
8+
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
9+
# General Gifti Input - Output to and from the filesystem
10+
# Stephan Gerhard, Oktober 2010
11+
##############
12+
13+
import os
14+
import codecs
15+
16+
from .parse_gifti_fast import parse_gifti_file
17+
18+
19+
def read(filename):
20+
""" Load a Gifti image from a file
21+
22+
Parameters
23+
----------
24+
filename : string
25+
The Gifti file to open, it has usually ending .gii
26+
27+
Returns
28+
-------
29+
img : GiftiImage
30+
Returns a GiftiImage
31+
"""
32+
if not os.path.isfile(filename):
33+
raise IOError("No such file or directory: '%s'" % filename)
34+
return parse_gifti_file(filename)
35+
36+
37+
def write(image, filename):
38+
""" Save the current image to a new file
39+
40+
Parameters
41+
----------
42+
image : GiftiImage
43+
A GiftiImage instance to store
44+
filename : string
45+
Filename to store the Gifti file to
46+
47+
Returns
48+
-------
49+
None
50+
51+
Notes
52+
-----
53+
We write all files with utf-8 encoding, and specify this at the top of the
54+
XML file with the ``encoding`` attribute.
55+
56+
The Gifti spec suggests using the following suffixes to your
57+
filename when saving each specific type of data:
58+
59+
.gii
60+
Generic GIFTI File
61+
.coord.gii
62+
Coordinates
63+
.func.gii
64+
Functional
65+
.label.gii
66+
Labels
67+
.rgba.gii
68+
RGB or RGBA
69+
.shape.gii
70+
Shape
71+
.surf.gii
72+
Surface
73+
.tensor.gii
74+
Tensors
75+
.time.gii
76+
Time Series
77+
.topo.gii
78+
Topology
79+
80+
The Gifti file is stored in endian convention of the current machine.
81+
"""
82+
# Our giftis are always utf-8 encoded - see GiftiImage.to_xml
83+
with open(filename, 'wb') as f:
84+
f.write(image.to_xml())

0 commit comments

Comments
 (0)