Skip to content

Commit fcb7fd2

Browse files
committed
Add loadtxt and savetxt adapted from matplotlib.
1 parent 41861b5 commit fcb7fd2

File tree

2 files changed

+175
-4
lines changed

2 files changed

+175
-4
lines changed

COMPATIBILITY

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ but always 1-d) --- only has .copy and .__array__ attributes of an array!!!
1515

1616
If you used typecode characters:
1717

18-
'c' -> 'S1'
18+
'c' -> 'S1' or 'c'
1919
'b' -> 'B'
2020
'1' -> 'b'
2121
's' -> 'h'
@@ -35,12 +35,12 @@ using PyMemData_FREE(ptr);
3535
a->descr->zero --> PyArray_Zero(a)
3636
a->descr->one --> PyArray_One(a)
3737

38-
Numeric/arrayobject.h --> numpy/arrayobject.h
38+
Numeric/arrayobject.h --> numpy/oldnumeric.h
3939

4040

4141
# These will actually work and are defines for PyArray_BYTE,
4242
# but you really should change it in your code
43-
PyArray_CHAR --> PyArray_BYTE
43+
PyArray_CHAR --> PyArray_CHAR
4444
(or PyArray_STRING which is more flexible)
4545
PyArray_SBYTE --> PyArray_BYTE
4646

numpy/core/numeric.py

+172-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
'array_repr', 'array_str', 'set_string_function',
1313
'little_endian', 'require',
1414
'fromiter', 'array_equal', 'array_equiv',
15-
'indices', 'fromfunction',
15+
'indices', 'fromfunction', 'loadtxt', 'savetxt',
1616
'load', 'loads', 'isscalar', 'binary_repr', 'base_repr',
1717
'ones', 'identity', 'allclose', 'compare_chararrays', 'putmask',
1818
'seterr', 'geterr', 'setbufsize', 'getbufsize',
@@ -610,6 +610,177 @@ def load(file):
610610
file = _file(file,"rb")
611611
return _cload(file)
612612

613+
# Adapted from matplotlib
614+
615+
def _getconv(dtype):
616+
typ = dtype.type
617+
if issubclass(typ, bool_):
618+
return lambda x: bool(int(x))
619+
if issubclass(typ, integer):
620+
return int
621+
elif issubclass(typ, floating):
622+
return float
623+
elif issubclass(typ, complex):
624+
return complex
625+
else:
626+
return str
627+
628+
629+
def _string_like(obj):
630+
try: obj + ''
631+
except (TypeError, ValueError): return 0
632+
return 1
633+
634+
def loadtxt(fname, dtype=float, comments='#', delimiter=None, converters=None,
635+
skiprows=0, usecols=None, unpack=False):
636+
"""
637+
Load ASCII data from fname into an array and return the array.
638+
639+
The data must be regular, same number of values in every row
640+
641+
fname can be a filename or a file handle. Support for gzipped files is
642+
automatic, if the filename ends in .gz
643+
644+
See scipy.loadmat to read and write matfiles.
645+
646+
Example usage:
647+
648+
X = loadtxt('test.dat') # data in two columns
649+
t = X[:,0]
650+
y = X[:,1]
651+
652+
Alternatively, you can do the same with "unpack"; see below
653+
654+
X = loadtxt('test.dat') # a matrix of data
655+
x = loadtxt('test.dat') # a single column of data
656+
657+
658+
dtype - the data-type of the resulting array. If this is a
659+
record data-type, the the resulting array will be 1-d and each row will
660+
be interpreted as an element of the array. The number of columns
661+
used must match the number of fields in the data-type in this case.
662+
663+
comments - the character used to indicate the start of a comment
664+
in the file
665+
666+
delimiter is a string-like character used to seperate values in the
667+
file. If delimiter is unspecified or none, any whitespace string is
668+
a separator.
669+
670+
converters, if not None, is a dictionary mapping column number to
671+
a function that will convert that column to a float. Eg, if
672+
column 0 is a date string: converters={0:datestr2num}
673+
674+
skiprows is the number of rows from the top to skip
675+
676+
usecols, if not None, is a sequence of integer column indexes to
677+
extract where 0 is the first column, eg usecols=(1,4,5) to extract
678+
just the 2nd, 5th and 6th columns
679+
680+
unpack, if True, will transpose the matrix allowing you to unpack
681+
into named arguments on the left hand side
682+
683+
t,y = load('test.dat', unpack=True) # for two column data
684+
x,y,z = load('somefile.dat', usecols=(3,5,7), unpack=True)
685+
686+
"""
687+
688+
if _string_like(fname):
689+
if fname.endswith('.gz'):
690+
import gzip
691+
fh = gzip.open(fname)
692+
else:
693+
fh = file(fname)
694+
elif hasattr(fname, 'seek'):
695+
fh = fname
696+
else:
697+
raise ValueError('fname must be a string or file handle')
698+
X = []
699+
700+
dtype = multiarray.dtype(dtype)
701+
defconv = _getconv(dtype)
702+
converterseq = None
703+
if converters is None:
704+
converters = {}
705+
if dtype.names is not None:
706+
converterseq = [_getconv(dtype.fields[name][0]) \
707+
for name in dtype.names]
708+
709+
for i,line in enumerate(fh):
710+
if i<skiprows: continue
711+
line = line[:line.find(comments)].strip()
712+
if not len(line): continue
713+
vals = line.split(delimiter)
714+
if converterseq is None:
715+
converterseq = [converters.get(j,defconv) \
716+
for j in xrange(len(vals))]
717+
if usecols is not None:
718+
row = [converterseq[j](vals[j]) for j in usecols]
719+
else:
720+
row = [converterseq[j](val) for j,val in enumerate(vals)]
721+
if dtype.names is not None:
722+
row = tuple(row)
723+
X.append(row)
724+
725+
X = array(X, dtype)
726+
r,c = X.shape
727+
if r==1 or c==1:
728+
X.shape = max([r,c]),
729+
if unpack: return X.T
730+
else: return X
731+
732+
733+
# adjust so that fmt can change across columns if desired.
734+
735+
def savetxt(fname, X, fmt='%.18e',delimiter=' '):
736+
"""
737+
Save the data in X to file fname using fmt string to convert the
738+
data to strings
739+
740+
fname can be a filename or a file handle. If the filename ends in .gz,
741+
the file is automatically saved in compressed gzip format. The load()
742+
command understands gzipped files transparently.
743+
744+
Example usage:
745+
746+
save('test.out', X) # X is an array
747+
save('test1.out', (x,y,z)) # x,y,z equal sized 1D arrays
748+
save('test2.out', x) # x is 1D
749+
save('test3.out', x, fmt='%1.4e') # use exponential notation
750+
751+
delimiter is used to separate the fields, eg delimiter ',' for
752+
comma-separated values
753+
"""
754+
755+
if _string_like(fname):
756+
if fname.endswith('.gz'):
757+
import gzip
758+
fh = gzip.open(fname,'wb')
759+
else:
760+
fh = file(fname,'w')
761+
elif hasattr(fname, 'seek'):
762+
fh = fname
763+
else:
764+
raise ValueError('fname must be a string or file handle')
765+
766+
767+
X = asarray(X)
768+
origShape = None
769+
if len(X.shape)==1:
770+
origShape = X.shape
771+
X.shape = len(X), 1
772+
for row in X:
773+
fh.write(delimiter.join([fmt%val for val in row]) + '\n')
774+
775+
if origShape is not None:
776+
X.shape = origShape
777+
778+
779+
780+
781+
782+
783+
613784
# These are all essentially abbreviations
614785
# These might wind up in a special abbreviations module
615786

0 commit comments

Comments
 (0)