Reputation: 4626
I have a list of tuples e.g. like this:
l=[ (2,2,1), (2,4,0), (2,8,0),
(4,2,0), (4,4,1), (4,8,0),
(8,2,0), (8,4,0), (8,8,1) ]
and want to transform it to an numpy array like this (only z values in the matrix, corresponding to the sequence of x, y coordinates, the coordinates should be stored separately) ):
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]])
I'm posting my solution below, but it's pretty low-level and I think there should be some higher-lever solution for this, either using matplotlib or numpy. Any idea?
One needs this kind of conversion to provide the arrays to matplotlib plotting functions like pcolor
, imshow
, contour
.
Upvotes: 0
Views: 1129
Reputation: 879849
It looks like np.unique with the return_inverse
option fits the bill. For example,
In [203]: l[:,0]
Out[203]: array([2, 2, 2, 4, 4, 4, 8, 8, 8])
In [204]: np.unique(l[:,0], return_inverse = True)
Out[204]: (array([2, 4, 8]), array([0, 0, 0, 1, 1, 1, 2, 2, 2]))
np.unique
returns a 2-tuple. The first array in the 2-tuple is an array of all the unique values in l[:,0]
. The second array is the
index values associating values in array([2, 4, 8])
with values in the original array l[:,0]
. It also happens to be the rank, since np.unique
returns the unique values in sorted order.
import numpy as np
import matplotlib.pyplot as plt
l = np.array([ (2,2,1), (2,4,0), (2,8,0),
(4,2,0), (4,4,1), (4,8,0),
(8,2,0), (8,4,0), (8,8,1) ])
x, xrank = np.unique(l[:,0], return_inverse = True)
y, yrank = np.unique(l[:,1], return_inverse = True)
a = np.zeros((max(xrank)+1, max(yrank)+1))
a[xrank,yrank] = l[:,2]
fig = plt.figure()
ax = plt.subplot(111)
ax.pcolor(x, y, a)
plt.show()
yields
Upvotes: 2
Reputation: 6085
a solution using standard python construct set, list and sorted. if you don't have a lot of pointsit gains in readability even if slower than the numpy solution given by unutbu
l=[ (2,2,1), (2,4,0), (2,8,0),
(4,2,0), (4,4,1), (4,8,0),
(8,2,0), (8,4,0), (8,8,1) ]
#get the ranks of the values for x and y
xi = sorted(list(set( i[0] for i in l )))
yi = sorted(list(set( i[1] for i in l )))
a = np.zeros((len(xi),len(yi)))
#fill the matrix using the list.index
for x,y,v in l:
a[xi.index(x),yi.index(y)]=v
ax=plt.subplot(111)
ax.pcolor(array(xi), array(yi), a)
Upvotes: 0
Reputation: 97601
I don't understand why you're making this so complex. You can do it simply with:
array([
[cell[2] for cell in row] for row in zip(*[iter(x)] * 3)
])
Or perhaps more readably:
array([
[a[2], b[2], c[2]] for a, b, c in zip(x[0::3], x[1::3], x[2::3])
])
Upvotes: 0
Reputation: 4626
My solution first ranks the x and y values, and then creates the array.
l=[ (2,2,1), (2,4,0), (2,8,0),
(4,2,0), (4,4,1), (4,8,0),
(8,2,0), (8,4,0), (8,8,1) ]
def rankdata_ignoretied(data):
"""ranks data counting all tied values as one"""
# first translate the data values to integeres in increasing order
counter=0
encountered=dict()
for e in sorted(data):
if e not in encountered:
encountered[e]=counter
counter+=1
# then map the original sequence of the data values
result=[encountered[e] for e in data]
return result
x=[e[0] for e in l]
y=[e[1] for e in l]
z=[e[2] for e in l]
xrank=rankdata_ignoretied(x)
yrank=rankdata_ignoretied(y)
import numpy
a=numpy.zeros((max(xrank)+1, max(yrank)+1))
for i in range(len(l)):
a[xrank[i],yrank[i]]=l[i][2]
To use the resulting array for plotting one also needs the original x and y values, e.g.:
ax=plt.subplot(511)
ax.pcolor(sorted(set(x)), sorted(set(y)), a)
Anyone has a better idea of how to achieve this?
Upvotes: 0