Consider a specification of numpy
arrays, typical for specifying matplotlib
plotting data:
t = np.arange(0.0,1.5,0.25)
s = np.sin(2*np.pi*t)
Basically, this stores the x
coordinates of our (x,y)
data points in the array t
; and the resulting y
coordinates (result of y=f(x), in this case sin(x)
) in the array s
. Then, it is very convenient to use the numpy.nditer
function to obtain consecutive pairs of entries in t
and s
, representing the (x,y)
coordinate of a data point, as in:
for x, y in np.nditer([t,s]):
print("xy: %f:%f" % (x,y))
So, I'm trying the following snippet as test.py
:
import numpy as np
print("numpy version {0}".format(np.__version__))
t = np.arange(0.0,1.5,0.25) ; print("t", ["%+.2e"%i for i in t])
s = np.sin(2*np.pi*t) ; print("s", ["%+.2e"%i for i in s])
print("i", ["% 9d"%i for i in range(0, len(t))])
for x, y in np.nditer([t,s]):
print("xy: %f:%f" % (x,y))
... and the results are:
$ python3.2 test.py
numpy version 1.7.0
t ['+0.00e+00', '+2.50e-01', '+5.00e-01', '+7.50e-01', '+1.00e+00', '+1.25e+00']
s ['+0.00e+00', '+1.00e+00', '+1.22e-16', '-1.00e+00', '-2.45e-16', '+1.00e+00']
i [' 0', ' 1', ' 2', ' 3', ' 4', ' 5']
xy: 0.000000:0.000000
xy: 0.250000:1.000000
xy: 0.500000:0.000000
xy: 0.750000:-1.000000
xy: 1.000000:-0.000000
xy: 1.250000:1.000000
$ python2.7 test.py
numpy version 1.5.1
('t', ['+0.00e+00', '+2.50e-01', '+5.00e-01', '+7.50e-01', '+1.00e+00', '+1.25e+00'])
('s', ['+0.00e+00', '+1.00e+00', '+1.22e-16', '-1.00e+00', '-2.45e-16', '+1.00e+00'])
('i', [' 0', ' 1', ' 2', ' 3', ' 4', ' 5'])
Traceback (most recent call last):
File "test.py", line 10, in <module>
for x, y in np.nditer([t,s]):
AttributeError: 'module' object has no attribute 'nditer'
Ah - it turns out, that the iterator object nditer, introduced in NumPy 1.6, is not available in the numpy
version of my Python 2.7 installation.
So, as I'd like to support that particular version too, I'd need to find a way working for older numpy
- but I'd still like the convenience of just specifying for x,y in somearray
, and getting the coordinates directly in the loop.
After some messing about with numpy
documentation, I came up with this getXyIter
function:
import numpy as np
print("numpy version {0}".format(np.__version__))
t = np.arange(0.0,1.5,0.25) ; print("t", ["%+.2e"%i for i in t])
s = np.sin(2*np.pi*t) ; print("s", ["%+.2e"%i for i in s])
print("i", ["% 9d"%i for i in range(0, len(t))])
def getXyIter(inarr):
if np.__version__ >= "1.6.0":
return np.nditer(inarr.tolist())
else:
dimensions = inarr.shape
xlen = dimensions[1]
xinds = np.arange(0, xlen, 1)
return np.transpose(np.take(inarr, xinds, axis=1))
for x, y in getXyIter(np.array([t,s])):
print("xyIt: %f:%f" % (x,y))
for x, y in np.nditer([t,s]):
print("xynd: %f:%f" % (x,y))
... which seems to work fine
$ python2.7 test.py
numpy version 1.5.1
('t', ['+0.00e+00', '+2.50e-01', '+5.00e-01', '+7.50e-01', '+1.00e+00', '+1.25e+00'])
('s', ['+0.00e+00', '+1.00e+00', '+1.22e-16', '-1.00e+00', '-2.45e-16', '+1.00e+00'])
('i', [' 0', ' 1', ' 2', ' 3', ' 4', ' 5'])
xyIt: 0.000000:0.000000
xyIt: 0.250000:1.000000
xyIt: 0.500000:0.000000
xyIt: 0.750000:-1.000000
xyIt: 1.000000:-0.000000
xyIt: 1.250000:1.000000
Traceback (most recent call last):
File "test.py", line 23, in <module>
for x, y in np.nditer([t,s]):
AttributeError: 'module' object has no attribute 'nditer'
$ python3.2 test.py
numpy version 1.7.0
t ['+0.00e+00', '+2.50e-01', '+5.00e-01', '+7.50e-01', '+1.00e+00', '+1.25e+00']
s ['+0.00e+00', '+1.00e+00', '+1.22e-16', '-1.00e+00', '-2.45e-16', '+1.00e+00']
i [' 0', ' 1', ' 2', ' 3', ' 4', ' 5']
xyIt: 0.000000:0.000000
xyIt: 0.250000:1.000000
xyIt: 0.500000:0.000000
xyIt: 0.750000:-1.000000
xyIt: 1.000000:-0.000000
xyIt: 1.250000:1.000000
xynd: 0.000000:0.000000
xynd: 0.250000:1.000000
xynd: 0.500000:0.000000
xynd: 0.750000:-1.000000
xynd: 1.000000:-0.000000
xynd: 1.250000:1.000000
My question is - is this the way, this kind of iteration is supposed to be done, in versions of numpy < 1.6.0?
How about concatenating the two vectors into an array:
for x,y in np.c_[t,s]:
print("xy: %f:%f" % (x,y))
This gives
xy: 0.000000:0.000000
xy: 0.250000:1.000000
xy: 0.500000:0.000000
xy: 0.750000:-1.000000
xy: 1.000000:-0.000000
xy: 1.250000:1.000000
If you want to iterate so you can save memory, you can use the itertools.izip
function:
for x,y in itertools.izip(t,s):
print("xy: %f:%f" % (x,y))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With