Python: How to change matrix indexing to cartesian indexing?

287 Views Asked by At

I have a matrix

import numpy as np
matrix = np.array([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])

And I want to represent a discrete 2D physical space on cartesian coordinates with it. So for example, when accessing the values I'd get matrix[0,0] = 7, matrix[1,2] = 6, matrix[3,3] = 3.

How can I accomplish that? I have tried using np.meshgrid, but as far as I have managed to implement it, the results are not what I am looking for. What I'm looking for could be accomplished by transposing the matrix every time I try to access a value, but I would like a way to just change the indexing of the matrix directly.

Thanks!

3

There are 3 best solutions below

0
Corralien On

You can use a view of your matrix with np.flip:

vmatrix = np.flip(matrix, axis=0)
print(vmatrix)

# Output
array([[7, 8, 9],
       [4, 5, 6],
       [1, 2, 3]])

Usage:

>>> vmatrix[0, 0]
7

>>> vmatrix[1, 2]
6

>>> vmatrix[2, 2]
3

You can also use np.pad:

vmatrix = np.pad(np.flip(matrix, axis=0), [[1, 0], [1, 0]])
print(vmatrix)

# Output
[[0 0 0 0]
 [0 7 8 9]
 [0 4 5 6]
 [0 1 2 3]]

Usage:

>>> vmatrix[1, 1]
7

>>> vmatrix[2, 3]
6

>>> vmatrix[3, 3]
3

You can also Subclassing ndarray and override __getitem__ and __setitem__ methods.

4
Joss On

In regards to the fact that numpy.ndarray.__getitem__ is not writable, it is recommended to access the values in another way.

The numpy.flip function can be used to flip or reverse the order of elements in an array along a specified axis. This can be useful in various data processing and analysis tasks, such as image processing, signal processing, and data manipulation.

I would like to apologize to you for my previous incorrect response. The most optimal solution for this problem is to utilize the numpy.flip function.

0
MufasaChan On

I will provide a solution to your problem. Although I will explain why the approach is very clunky and will lead to problem later in your experiments. I would advise to look at meshgrid for this. Here is a simple example how to perform computation on a 2D cartesian plane with meshgrid. I think this the standard and straightforward way, therefore the privilegied way to do that.

The solution

Before, I will introduce some variables. The matrix which is meant to represent the cartesian plane between x_values = np.arange(-2, 2+1), y_values = np.arrange(-1, 1+1):

matrix = np.array[
  [ 1, 1, 0, 2, 2],
  [ 0, 0, 0, 0, 0],
  [ 3, 3, 0, 4, 4]]

We will denote the indices of this matrix as i and j. Also we will note x and y as our cartesian indices. What you want is a mapping from (x, y) to (i, j). For example from (2, 1) you want the top left value with matrix indices (0, 4).

The last introduced variable are i_origin and j_origin. Those variables are the i and j for the cartesian origin of the plane (0, 0). We can do i_origin = matrix.shape[0] // 2 and j_origin = matrix.shape[1] // 2. We wil use i_origin as an offset for the lines' indices - vertical - so for y and j_origin for x

If you take a pencil and a paper I think we can agree that:

i = i_origin - y
j = j_origin + x

So, we can write the two short functions:

def map_to_i(i_origin: int, y: int) -> int:
  return i_origin - y
def map_to_j(j_origin: int, x: int) -> int:
  return j_origin - x

If you want, we can even make a function to have a tuple of (i, j):

def map_to_matrix_indices(i_origin: int, j_origin: int, x: int, y: int) -> tuple[int, int]:
  return map_to_i(i_origin, y), map_to_j(j_origin, x)

The we can simply write:

>>> matrix[map_to_matrix_indices(i_origin, j_origin, 2, 1)]
2

Problems

Well, we can say we have your solution, but this approach brings a bunch of problems:

  • The interface of accessing/setting your values is not standard. As such, it might not work well with libraries. Plus, you lose a part of the broadcasting from numpy.
  • One way to get around this would be to implement a class CartesianMatrix - for example - and put our functions in its method. You can inherit from or composed it from the ndarray. It might be feasible but needs additional work. (Note: it would be interesting to do actually)
  • Written as such, it cannot be generalized for more dimension. I do think it can be easily formalized.

In general, you must set the interface of your new class the same as ndarray to have no problem. Else, you will have to find a workaround for every problem you encounter because you do not access/set indices by the standard way.

Note: interface of an object is how an object must behave.