What I would like to plot is to make vector from high values to low values. If code would start from:
a = [[1, 8, 9, 10],[2, 15, 3, -1],[3,1,6,11],[13,15,5,-2]]
X,Y = np.meshgrid(np.arange(4), np.arange(4))
U = ?
V = ?
From this point, I should set U
and V
components of the vector.
The magnitude of each point would be a[x][y]
. I don't have much idea of how I can set U
and V
to make arrow from high to low value at each grid point.
Here's a solution (doesn't require numpy):
import itertools as it
a = [[1, 8, 9, 10],[2, 15, 3, -1],[3,1,6,11],[13,15,5,-2]]
rowSize = len(a[0])
maxVal = a[0][0]
maxIndex = 0
minVal = a[0][0]
minIndex = 0
for k, v in enumerate(it.chain(*a)): # Loop through a flattened list of the values in the array, and locate the indices of the max and min values.
if v > maxVal:
maxVal = v
maxIndex = k
if v < minVal:
minVal = v
minIndex = k
U = (minIndex % rowSize) - (maxIndex % rowSize)
V = (minIndex / rowSize) - (maxIndex / rowSize)
print U, ",", V
2 , 2
Note that you haven't defined what behavior you want when there are two equal maximum values, as there are in your example. The code above uses the "first" (upper-leftmost) one as the true maximum, and ignores all others.
I flattened the list (which means I read the values like you would the words on a book - first the first row, then the second row, then the third row). Each value got a single index, like so:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
For example, a value in the second row and the third column would get an index of 6, since it's the 7th value if you read the array like a book.
At the end, when we've found the index of the max or min value, we need to get 2D coordinates from the 1D index. So, we can use the mod operator (%) to get the x-value.
For example, 6 % 4 = 2
, so X = 2
(the 3rd column)
To get the Y value, we use the integer division operator (/).
For example, 6 / 4 = 1
, so Y = 1
(the second row)
The formulas for U
and V
are simply taking the X and Y values for the max and min and subtracting them to get the vector coordinates, like so:
U = xMin - xMax
V = yMin - yMax
If you're wondering, "why the heck didn't he just use the meshgrid solution I started with", there are two reasons: One, using a non-standard library like numpy is generally undesirable if there is an easy way to solve the problem without non-standard libraries, and two, if you ever need to deal with large arrays, generating a large meshgrid could become time/memory expensive.
import itertools as it
a = [[1, 8, 9, 10],[2, 15, 3, -1],[3,1,6,11],[13,15,5,-2]]
rowSize = len(a[0])
values = sorted(enumerate(it.chain(*a)), key=lambda x:x[1]) # Pair each value with its 1D index, then sort the list.
minVal = values[0][1]
maxVal = values[-1][1]
maxIndices = map(lambda x:x[0], filter(lambda x:x[1]==maxVal, values)) # Get a list of all the indices that match the maximum value
minIndices = map(lambda x:x[0], filter(lambda x:x[1]==minVal, values)) # Get a list of all the indices that match the minimum value
def getVector(index1, index2, rowSize): # A function that translates a pair of 1D index values to a "quiver vector"
return ((index1 % rowSize) - (index2 % rowSize), (index1 / rowSize) - (index2 / rowSize))
vectors = [getVector(k2, k1, rowSize) for k1, k2 in it.product(maxIndices, minIndices)] # produce a list of the vectors formed by all possible combinations of the 1D indices for maximum and minimum values
U, V = sorted(vectors, key=lambda x:(x[0]*x[0] + x[1]*x[1])**0.5)[0]
print U, ",", V
2 , 0