[Numpy-svn] r5108 - in trunk/numpy/lib: . tests

numpy-svn@scip... numpy-svn@scip...
Mon Apr 28 18:27:20 CDT 2008


Author: stefan
Date: 2008-04-28 18:27:11 -0500 (Mon, 28 Apr 2008)
New Revision: 5108

Modified:
   trunk/numpy/lib/io.py
   trunk/numpy/lib/tests/test_io.py
Log:
Support for multi formatting elements in savetxt [patch by David Huard].
Closes #663.


Modified: trunk/numpy/lib/io.py
===================================================================
--- trunk/numpy/lib/io.py	2008-04-28 23:07:12 UTC (rev 5107)
+++ trunk/numpy/lib/io.py	2008-04-28 23:27:11 UTC (rev 5108)
@@ -1,4 +1,3 @@
-
 __all__ = ['savetxt', 'loadtxt',
            'load', 'loads',
            'save', 'savez',
@@ -322,7 +321,6 @@
     else:  return X
 
 
-# adjust so that fmt can change across columns if desired.
 
 def savetxt(fname, X, fmt='%.18e',delimiter=' '):
     """
@@ -332,49 +330,55 @@
     Parameters
     ----------
     fname : filename or a file handle
-      If the filename ends in .gz, the file is automatically saved in
-      compressed gzip format.  The load() command understands gzipped files
-      transparently.
+        If the filename ends in .gz, the file is automatically saved in
+        compressed gzip format.  The load() command understands gzipped
+        files transparently.
     X : array or sequence
-      Data to write to file.
-    fmt : string
-      A format string %[flags][width][.precision]specifier. See notes below for
-      a description of some common flags and specifiers.
+        Data to write to file.
+    fmt : string or sequence of strings
+        A single format (%10.5f), a sequence of formats, or a
+        multi-format string, e.g. 'Iteration %d -- %10.5f', in which
+        case delimiter is ignored.
     delimiter : str
-      Character separating columns.
+        Character separating columns.
 
     Examples
     --------
-      >>> savetxt('test.out', x, delimiter=',')         # X is an array
-      >>> savetxt('test.out', (x,y,z))     # x,y,z equal sized 1D arrays
-      >>> savetxt('test.out', x, fmt='%1.4e')  # use exponential notation
+    >>> savetxt('test.out', x, delimiter=',') # X is an array
+    >>> savetxt('test.out', (x,y,z)) # x,y,z equal sized 1D arrays
+    >>> savetxt('test.out', x, fmt='%1.4e') # use exponential notation
 
     Notes on fmt
     ------------
     flags:
-      - : left justify
-      + : Forces to preceed result with + or -.
-      0 : Left pad the number with zeros instead of space (see width).
+        - : left justify
+        + : Forces to preceed result with + or -.
+        0 : Left pad the number with zeros instead of space (see width).
+
     width:
-      Minimum number of characters to be printed. The value is not truncated.
+        Minimum number of characters to be printed. The value is not truncated.
+
     precision:
-      For integer specifiers (eg. d,i,o,x), the minimum number of digits.
-      For e, E and f specifiers, the number of digits to print after the decimal
-      point.
-      For g and G, the maximum number of significant digits.
-      For s, the maximum number of characters.
+        - For integer specifiers (eg. d,i,o,x), the minimum number of
+          digits.
+        - For e, E and f specifiers, the number of digits to print
+          after the decimal point.
+        - For g and G, the maximum number of significant digits.
+        - For s, the maximum number of charac ters.
+
     specifiers:
-      c : character
-      d or i : signed decimal integer
-      e or E : scientific notation with e or E.
-      f : decimal floating point
-      g,G : use the shorter of e,E or f
-      o : signed octal
-      s : string of characters
-      u : unsigned decimal integer
-      x,X : unsigned hexadecimal integer
+        c : character
+        d or i : signed decimal integer
+        e or E : scientific notation with e or E.
+        f : decimal floating point
+        g,G : use the shorter of e,E or f
+        o : signed octal
+        s : string of characters
+        u : unsigned decimal integer
+        x,X : unsigned hexadecimal integer
 
     This is not an exhaustive specification.
+
     """
 
     if _string_like(fname):
@@ -388,18 +392,34 @@
     else:
         raise ValueError('fname must be a string or file handle')
 
+    X = np.asarray(X)
+    if X.ndim == 1:
+        if X.dtype.names is None:
+            X = np.atleast_2d(X).T
+            ncol = 1
+        else:
+            ncol = len(X.dtype.descr)
+    else:
+        ncol = X.shape[1]
 
-    X = np.asarray(X)
-    origShape = None
-    if len(X.shape)==1 and X.dtype.names is None:
-        origShape = X.shape
-        X.shape = len(X), 1
+    # Fmt can be a string with multiple insertion points or a list of formats.
+    # E.g. '%10.5f\t%10d' or ('%10.5f', '$10d')
+    if type(fmt) in (list, tuple):
+        if len(fmt) != ncol:
+            raise AttributeError, 'fmt has wrong shape.  '+ str(fmt)
+        format = delimiter.join(fmt)
+    elif type(fmt) is str:
+        if fmt.count('%') == 1:
+            fmt = [fmt,]*ncol
+            format = delimiter.join(fmt)
+        elif fmt.count('%') != ncol:
+            raise AttributeError, 'fmt has wrong number of % formats.  ' + fmt
+        else:
+            format = fmt
+
     for row in X:
-        fh.write(delimiter.join([fmt%val for val in row]) + '\n')
+        fh.write(format%tuple(row) + '\n')
 
-    if origShape is not None:
-        X.shape = origShape
-
 import re
 def fromregex(file, regexp, dtype):
     """Construct a record array from a text file, using regular-expressions parsing.

Modified: trunk/numpy/lib/tests/test_io.py
===================================================================
--- trunk/numpy/lib/tests/test_io.py	2008-04-28 23:07:12 UTC (rev 5107)
+++ trunk/numpy/lib/tests/test_io.py	2008-04-28 23:27:11 UTC (rev 5108)
@@ -39,30 +39,29 @@
         c.seek(0)
         assert_equal(c.readlines(), ['1,2\n', '3,4\n'])
 
+    def test_format(self):
+        a = np.array([(1, 2), (3, 4)])
+        c = StringIO.StringIO()
+        # Sequence of formats
+        np.savetxt(c, a, fmt=['%02d', '%3.1f'])
+        c.seek(0)
+        assert_equal(c.readlines(), ['01 2.0\n', '03 4.0\n'])
 
-##    def test_format(self):
-##        a = np.array([(1, 2), (3, 4)])
-##        c = StringIO.StringIO()
-##        # Sequence of formats
-##        np.savetxt(c, a, fmt=['%02d', '%3.1f'])
-##        c.seek(0)
-##        assert_equal(c.readlines(), ['01 2.0\n', '03 4.0\n'])
-##
-##        # A single multiformat string
-##        c = StringIO.StringIO()
-##        np.savetxt(c, a, fmt='%02d : %3.1f')
-##        c.seek(0)
-##        lines = c.readlines()
-##        assert_equal(lines, ['01 : 2.0\n', '03 : 4.0\n'])
-##
-##        # Specify delimiter, should be overiden
-##        c = StringIO.StringIO()
-##        np.savetxt(c, a, fmt='%02d : %3.1f', delimiter=',')
-##        c.seek(0)
-##        lines = c.readlines()
-##        assert_equal(lines, ['01 : 2.0\n', '03 : 4.0\n'])
+        # A single multiformat string
+        c = StringIO.StringIO()
+        np.savetxt(c, a, fmt='%02d : %3.1f')
+        c.seek(0)
+        lines = c.readlines()
+        assert_equal(lines, ['01 : 2.0\n', '03 : 4.0\n'])
 
+        # Specify delimiter, should be overiden
+        c = StringIO.StringIO()
+        np.savetxt(c, a, fmt='%02d : %3.1f', delimiter=',')
+        c.seek(0)
+        lines = c.readlines()
+        assert_equal(lines, ['01 : 2.0\n', '03 : 4.0\n'])
 
+
 class TestLoadTxt(NumpyTestCase):
     def test_record(self):
         c = StringIO.StringIO()



More information about the Numpy-svn mailing list