1

I need to sort and array of XYZ coordinates in a table style matrix to export as an .csv file.

With the help from user Michael0x2a I managed to do it more or less. My problem now is if I have repeated X and Y it will return 0 for Z.

def find_x_and_y(array):
    """Step 1: Get unique x and y coordinates and the width and height of the matrix"""

    x = sorted(list(set([i[0] for i in array])))
    y = sorted(list([i[1] for i in array]))


    height = len(x) + 1
    width = len(y) + 1

    return x, y, width, height

def construct_initial_matrix(array):
    """Step 2: Make the initial matrix (filled with zeros)"""
    x, y, width, height = find_x_and_y(array)

    matrix = []
    for i in range(height):
        matrix.append([0] * width)

    return matrix

def add_edging(array, matrix):
    """Step 3: Add the x and y coordinates to the edges"""
    x, y, width, height = find_x_and_y(array)

    for coord, position in zip(x, range(1, height)):
        matrix[position][0] = coord

    for coord, position in zip(y, range(1, width)):
        matrix[0][position] = coord

    return matrix

def add_z_coordinates(array, matrix):
    """Step 4: Map the coordinates in the array to the position in the matrix"""
    x, y, width, height = find_x_and_y(array)

    x_to_pos = dict(zip(x, range(1, height)))
    y_to_pos = dict(zip(y, range(1, width)))

    for x, y, z in array:
        matrix[x_to_pos[x]][y_to_pos[y]] = z
    return matrix

def make_csv(matrix):
    """Step 5: Printing"""
    return '\n'.join(', '.join(str(i) for i in row) for row in matrix)


def main(array):
    matrix = construct_initial_matrix(array)
    matrix = add_edging(array, matrix)
    matrix = add_z_coordinates(array, matrix)

    print make_csv(matrix)

if I run the example below it will return

example = [[1, 1, 20], [1, 1, 11], [2, 3, 12.1], [2, 5, 13], [5,4,10], [3,6,15]]
main(example)

0, 1, 1, 3, 4, 5, 6
1, 0, 11, 0, 0, 0, 0
2, 0, 0, 12.1, 0, 13, 0
3, 0, 0, 0, 0, 0, 15
5, 0, 0, 0, 10, 0, 0

so column headers are the y values, row headers are the x values.

for the 1st set of [1,1,20] it returns 1,1,0 because of the second set [1,1,11] has the same x and y values.

the end result should be:

0, 1, 1, 3, 4, 5, 6
1, 20, 11, 0, 0, 0, 0
2, 0, 0, 12.1, 0, 13, 0
3, 0, 0, 0, 0, 0, 15
5, 0, 0, 0, 10, 0, 0

I think it has something to do with this function:

    x_to_pos = dict(zip(x, range(1, height)))
    y_to_pos = dict(zip(y, range(1, width)))

can anyone help me out with this?

thanks so much

Francisco

user2725701
  • 35
  • 1
  • 7
  • What's the expected result? If you have two different values for the same coordinates then you can't fit them both into one place. Or... you can as a tuple - if that's what you want? – BartoszKP Aug 29 '13 at 09:41
  • I edit the question adding what the end result should be – user2725701 Aug 29 '13 at 09:42
  • Please edit your question and include the expected output. That way you can format the matrix properly. – thefourtheye Aug 29 '13 at 09:43
  • I edit the code, I was trying stuff out before I posted the question and I copied a code which wasn't working. now if you copy the code it should work, but still giving the initial error of putting a 0 instead of a 20 – user2725701 Aug 29 '13 at 09:54
  • May you use numpy, or does it have to be pure Python? General remark: As you need to "track" the indices of your coordinates, the solution probably includes the "key" paramater to the sorted function. – ojdo Aug 29 '13 at 10:45
  • 1
    @ojdo it really needs to be in pure python because I'm using it in rhino python. it doesn't support numpy unfortunatly – user2725701 Aug 29 '13 at 11:14
  • I tried to give an answer, but you will have to clarify *exactly* how duplicate values in either dimension are to be handled before I can make it behave correctly. Why does the duplicate `[1,1]` spawn a new column, not a new row? What should happen if there are three identical coordinates? – ojdo Aug 29 '13 at 13:01

1 Answers1

0

Here is a suggestion. It uses sorted function on a range with the key parameter to get the indices needed to sort x and y later on (more details in the question 'How to get indices of a sorted array in Python'). This automatically deals with duplicate values.

example = [[1, 1, 20], [1, 1, 11], [2, 3, 12.1], [2, 5, 13], [5,4,10], [3,6,15]]
x = [el[0] for el in example]
y = [el[1] for el in example]
z = [el[2] for el in example]

# indices for x,y to get them in sorted order later
# duplicates in both dimensions are preserved
x_idx = sorted(range(len(x)), key=lambda k:x[k])
y_idx = sorted(range(len(y)), key=lambda k:y[k])

# initialize A with 0
A = [[0 for _ in range(len(y)+1)] for _ in range(len(x)+1)]

# and fill it with values
for k, val in enumerate(z):
    A[x_idx[k]+1][y_idx[k]+1] = val
    A[k+1][0] = x[x_idx[k]]
    A[0][k+1] = y[y_idx[k]]

However, the result of this script is not (yet) as desired. A looks like this in the end:

[[0, 1, 1, 3, 4, 5, 6],
 [1, 20, 0, 0, 0, 0, 0],
 [1, 0, 11, 0, 0, 0, 0],
 [2, 0, 0, 12.1, 0, 0, 0],
 [2, 0, 0, 0, 0, 13, 0],
 [3, 0, 0, 0, 0, 0, 15],
 [5, 0, 0, 0, 10, 0, 0]]

Note that the duplicate value 1 not only created a new column, but also a new row.

Assumption: only rows with identical index shall be merged. This can be accomplished using itertools groupby function and zip+sum to "merge" the rows by simply summing them column by column. The first column (the row index) has to be sliced:

AA = []
for row_index, rows_to_be_merged in itertools.groupby(A, lambda x: x[0]):
    AA.append([row_index] + 
              [sum(rows) for rows in zip(*rows_to_be_merged)][1:])

The resulting list of lists AA looks like this:

[[0, 1, 1, 3, 4, 5, 6],
 [1, 20, 11, 0, 0, 0, 0],
 [2, 0, 0, 12.1, 0, 13, 0],
 [3, 0, 0, 0, 0, 0, 15],
 [5, 0, 0, 0, 10, 0, 0]]
Community
  • 1
  • 1
ojdo
  • 8,280
  • 5
  • 37
  • 60