Matplotlib plot spaces separated data array - python

What's the easiest way to format this array data so that I can connect the points on the graph iterating, assuming each line contains x and y coordinates of a single point?
import matplotlib.pyplot as plt
(...)
<class 'numpy.ndarray'>
[-22.58343371 7.97162262]
[-49.08400669 -28.64111278]
[-71.47754547 -25.78248676]
[-46.27120899 -21.72541444]
[ 43.6158669 109.61815799]
[-22.58343371 7.97162262]
(...)
plt.plot(x, y, color='orange')
Sorry, below is almost complete code (order is calculated by another alghoritm) corrected thanks to Quang Hoang's comment. This is obviously part of the solution to the well known tsp problem. The point, of course, is to connect the points according to the correct order in the list which in this case is: (0, 2, 1, 3, 4, 0).
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import numpy as np
n = 5
order = (0, 2, 1, 3, 4, 0)
distances = [[0, 39, 22, 59, 54, 33, 57, 32, 89, 73, 29, 46],
[39, 0, 20, 20, 81, 8, 49, 64, 63, 84, 10, 61],
[22, 20, 0, 39, 74, 18, 60, 44, 71, 73, 11, 46],
[59, 20, 39, 0, 93, 27, 51, 81, 48, 80, 30, 69],
[54, 81, 74, 93, 0, 73, 43, 56, 104, 76, 76, 77],
[33, 8, 18, 27, 73, 0, 45, 61, 71, 88, 8, 63],
[57, 49, 60, 51, 43, 45, 0, 85, 88, 115, 52, 103],
[32, 64, 44, 81, 56, 61, 85, 0, 74, 43, 55, 23],
[89, 63, 71, 48, 104, 71, 88, 74, 0, 38, 69, 51],
[73, 84, 73, 80, 76, 88, 115, 43, 38, 0, 81, 28],
[29, 10, 11, 30, 76, 8, 52, 55, 69, 81, 0, 55],
[46, 61, 46, 69, 77, 63, 103, 23, 51, 28, 55, 0]]
pca = PCA(n_components=2)
coord = pca.fit_transform(distances[:n])
plt.scatter(coord[:,0], coord[:,1])
for i in coord:
x = np.where(coord == i)
plt.annotate((x[0][0]) ,i, color='red')
for j in order:
print(coord[j])
plt.plot(coord[:,0], coord[:,1], color='orange')
plt.show()

Sometimes, after many hours, things feel more difficult than they are:) Thank's a lot Kapocsi! Working solution below:
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import numpy as np
n = 5
order = [0, 2, 1, 3, 4, 0]
distances = [[0, 39, 22, 59, 54, 33, 57, 32, 89, 73, 29, 46],
[39, 0, 20, 20, 81, 8, 49, 64, 63, 84, 10, 61],
[22, 20, 0, 39, 74, 18, 60, 44, 71, 73, 11, 46],
[59, 20, 39, 0, 93, 27, 51, 81, 48, 80, 30, 69],
[54, 81, 74, 93, 0, 73, 43, 56, 104, 76, 76, 77],
[33, 8, 18, 27, 73, 0, 45, 61, 71, 88, 8, 63]]
pca = PCA(n_components=2)
coord = pca.fit_transform(distances[:n])
plt.scatter(coord[:,0], coord[:,1])
for i in coord:
x = np.where(coord == i)
plt.annotate((x[0][0]) ,i, color='red')
x = coord[order]
print(x)
plt.plot(x[:, 0], x[:, 1], color='orange', marker='o', linestyle='-')
plt.show()

You likely need to sort the data to get the visualization you want:
import numpy as np
import matplotlib.pyplot as plt
a = np.array([[-22.58343371, 7.97162262],
[-49.08400669, -28.64111278],
[-71.47754547, -25.78248676],
[-46.27120899, -21.72541444],
[ 43.6158669 , 109.61815799],
[-22.58343371, 7.97162262]])
order = a[:, 0].argsort()
plt.plot(a[order, 0], a[order, 1], color='orange', marker='o', linestyle='-')
plt.show()
If you don't sort it, you will end up with something like this:
import numpy as np
import matplotlib.pyplot as plt
a = np.array([[-22.58343371, 7.97162262],
[-49.08400669, -28.64111278],
[-71.47754547, -25.78248676],
[-46.27120899, -21.72541444],
[ 43.6158669 , 109.61815799],
[-22.58343371, 7.97162262]])
plt.plot(a[:, 0], a[:, 1], color='orange', marker='o', linestyle='-')
plt.show()

Related

How to shift numpy slices?

I have a class like this
class A:
def __init__(self):
self.top_left = (1,2)
self.arr = np.reshape(np.arange(100), (10,10))
def __setitem__(self, key, val):
return self.arr[shifted(key, self.top_left)] = val
I want all the row indices appear in key to be shifted by 1 and all the column indices appear in key shifted by 2. Is it possible?
Edit:
Consider a = A() and a.arr to be
[[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
[70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]]
Now when I set a[0,0] = 5, a.arr changes at index (1,2). Because it gets shifted by (1,2).
Again if I set a[3:6, 3:6] = np.ones((3,3)) then a.arr looks like this:
[[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
[40, 41, 42, 43, 44, 1, 1, 1, 48, 49],
[50, 51, 52, 53, 54, 1, 1, 1, 58, 59],
[60, 61, 62, 63, 64, 1, 1, 1, 68, 69],
[70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]]
because all the index in the key, gets shifted by (1,2).
Edit 2:
Currently I am storing the values in a separate array. And then putting this whole array, back to arr.
self.arr2[key] = value
self.arr[self.top_left[1] : self.top_left[1] + self.shape[1],
self.top_left[0] : self.top_left[0] + self.shape[1],
] = self.arr2
self.shape is shape of the editable window in a.arr
Numpy array operate on builtin python slice or tuple.
shifter function decides what kind of index you passed.
import numpy as np
class A:
def __init__(self):
self.top_left = (1,2)
self.arr = np.reshape(np.arange(100), (10,10))
def __setitem__(self, key, val):
self.arr[self.shifter(key)] = val
def shifter(self, key):
if isinstance(key[0], slice):
shift_func = self.shifted_slice
else:
shift_func = self.shifted_point
return shift_func(key)
def shifted_slice(self, key):
row_slice, col_slice = key
row_offset, col_offset = self.top_left
return slice(row_slice.start + row_offset, row_slice.stop + row_offset), \
slice(col_slice.start + col_offset, col_slice.stop + col_offset)
def shifted_point(self, key):
row_num, col_num = key
row_offset, col_offset = self.top_left
return row_num + row_offset, \
col_num + col_offset
a = A()
a[0, 0] = 5
a[3:6, 3:6] = np.ones((3,3))
print(a.arr)
Outputs:
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[10, 11, 5, 13, 14, 15, 16, 17, 18, 19],
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
[40, 41, 42, 43, 44, 1, 1, 1, 48, 49],
[50, 51, 52, 53, 54, 1, 1, 1, 58, 59],
[60, 61, 62, 63, 64, 1, 1, 1, 68, 69],
[70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])

Numpy blocks reshaping

I am looking for a way to reshape the following 1d-numpy array:
# dimensions
n = 2 # int : 1 ... N
h = 2 # int : 1 ... N
m = n*(2*h+1)
input_data = np.arange(0,(n*(2*h+1))**2)
The expected output should be reshaped into (2*h+1)**2 blocks of shape (n,n) such as:
input_data.reshape(((2*h+1)**2,n,n))
>>> array([[[ 0 1]
[ 2 3]]
[[ 4 5]
[ 6 7]]
...
[[92 93]
[94 95]]
[[96 97]
[98 99]]]
These blocks finally need to be reshaped into a (m,m) matrix so that they are stacked in rows of 2*h+1 blocks:
>>> array([[ 0, 1, 4, 5, 8, 9, 12, 13, 16, 17],
[ 2, 3, 6, 7, 10, 11, 14, 15, 18, 19],
...
[80, 81, 84, 85, 88, 89, 92, 93, 96, 97],
[82, 83, 86, 87, 90, 91, 94, 95, 98, 99]])
My problem is that I can't seem to find proper axis permutations after the first reshape into (n,n) blocks. I have looked at several answers such as this one but in vain.
As the real dimensions n and h are quite bigger and this operation takes place in an iterative process, I am looking for an efficient reshaping operation.
I don't think you can do this with reshape and transpose alone (although I'd love to be proven wrong). Using np.block works, but it's a bit messy:
np.block([list(i) for i in input_data.reshape( (2*h+1), (2*h+1), n, n )])
array([[ 0, 1, 4, 5, 8, 9, 12, 13, 16, 17],
[ 2, 3, 6, 7, 10, 11, 14, 15, 18, 19],
[20, 21, 24, 25, 28, 29, 32, 33, 36, 37],
[22, 23, 26, 27, 30, 31, 34, 35, 38, 39],
[40, 41, 44, 45, 48, 49, 52, 53, 56, 57],
[42, 43, 46, 47, 50, 51, 54, 55, 58, 59],
[60, 61, 64, 65, 68, 69, 72, 73, 76, 77],
[62, 63, 66, 67, 70, 71, 74, 75, 78, 79],
[80, 81, 84, 85, 88, 89, 92, 93, 96, 97],
[82, 83, 86, 87, 90, 91, 94, 95, 98, 99]])
EDIT: Never mind, you can do without np.block:
input_data.reshape( (2*h+1), (2*h+1), n, n).transpose(0, 2, 1, 3).reshape(10, 10)
array([[ 0, 1, 4, 5, 8, 9, 12, 13, 16, 17],
[ 2, 3, 6, 7, 10, 11, 14, 15, 18, 19],
[20, 21, 24, 25, 28, 29, 32, 33, 36, 37],
[22, 23, 26, 27, 30, 31, 34, 35, 38, 39],
[40, 41, 44, 45, 48, 49, 52, 53, 56, 57],
[42, 43, 46, 47, 50, 51, 54, 55, 58, 59],
[60, 61, 64, 65, 68, 69, 72, 73, 76, 77],
[62, 63, 66, 67, 70, 71, 74, 75, 78, 79],
[80, 81, 84, 85, 88, 89, 92, 93, 96, 97],
[82, 83, 86, 87, 90, 91, 94, 95, 98, 99]])

Numpy array split by pairs of irregular (start, stop)

I have an numpy array with x and y values of points. I have another array which contains pairs of start and end indices. Originally this data was in pandas DataFrame, but since it was over 60 millions items, the loc algorithm was very slow. Is there any numpy fast method to split this?
import numpy as np
xy_array = np.arange(100).reshape(2,-1)
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])
split_paris = [[0, 10], [10, 13], [13, 17], [20, 22]]
expected_result = [
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [50, 51, 52, 53, 54, 55, 56, 57, 58, 59]],
[[10, 11, 12], [60, 61, 62]],
[[13, 14, 15, 16], [63, 64, 65, 66]],
[[20, 21], [70, 71]]
]
Update:
It is not always the case that, next pair will start from end of previous.
This will do it:
import numpy as np
xy_array = np.array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])
split_paris = [[0, 10], [10, 13], [13, 17]]
expected_result = [xy_array[:, x:y] for x, y in split_paris]
expected_result
#[array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
# [50, 51, 52, 53, 54, 55, 56, 57, 58, 59]]), array([[10, 11, 12],
# [60, 61, 62]]), array([[13, 14, 15, 16],
# [63, 64, 65, 66]])]
It is using index slicing basically working in sense array[rows, columns] having : take all rows and x:y taking columns from x to y.
you can always use the np.array_split function provided by numpy. and use the ranges you want
x = np.arange(8.0)
>>> np.array_split(x, 3)
[array([ 0., 1., 2.]), array([ 3., 4., 5.]), array([ 6., 7.])]

Cropping an image in python (numpy), array reshape [duplicate]

Let's say I have a numpy image of some width x and height y.
I have to crop the center portion of the image to width cropx and height cropy. Let's assume that cropx and cropy are positive non zero integers and less than the respective image size. What's the best way to apply the slicing for the output image?
Something along these lines -
def crop_center(img,cropx,cropy):
y,x = img.shape
startx = x//2-(cropx//2)
starty = y//2-(cropy//2)
return img[starty:starty+cropy,startx:startx+cropx]
Sample run -
In [45]: img
Out[45]:
array([[88, 93, 42, 25, 36, 14, 59, 46, 77, 13, 52, 58],
[43, 47, 40, 48, 23, 74, 12, 33, 58, 93, 87, 87],
[54, 75, 79, 21, 15, 44, 51, 68, 28, 94, 78, 48],
[57, 46, 14, 98, 43, 76, 86, 56, 86, 88, 96, 49],
[52, 83, 13, 18, 40, 33, 11, 87, 38, 74, 23, 88],
[81, 28, 86, 89, 16, 28, 66, 67, 80, 23, 95, 98],
[46, 30, 18, 31, 73, 15, 90, 77, 71, 57, 61, 78],
[33, 58, 20, 11, 80, 25, 96, 80, 27, 40, 66, 92],
[13, 59, 77, 53, 91, 16, 47, 79, 33, 78, 25, 66],
[22, 80, 40, 24, 17, 85, 20, 70, 81, 68, 50, 80]])
In [46]: crop_center(img,4,6)
Out[46]:
array([[15, 44, 51, 68],
[43, 76, 86, 56],
[40, 33, 11, 87],
[16, 28, 66, 67],
[73, 15, 90, 77],
[80, 25, 96, 80]])
A more general solution based on #Divakar 's answer:
def cropND(img, bounding):
start = tuple(map(lambda a, da: a//2-da//2, img.shape, bounding))
end = tuple(map(operator.add, start, bounding))
slices = tuple(map(slice, start, end))
return img[slices]
and if we have an array a
>>> a = np.arange(100).reshape((10,10))
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
[70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])
We can clip it with cropND(a, (5,5)), you will get:
>>> cropND(a, (5,5))
array([[33, 34, 35, 36, 37],
[43, 44, 45, 46, 47],
[53, 54, 55, 56, 57],
[63, 64, 65, 66, 67],
[73, 74, 75, 76, 77]])
It not only works with 2D image but also 3D image.
Have a nice day.
Thanks, Divakar.
Your answer got me going the right direction. I came up with this using negative slice offsets to count 'from the end':
def cropimread(crop, xcrop, ycrop, fn):
"Function to crop center of an image file"
img_pre= msc.imread(fn)
if crop:
ysize, xsize, chan = img_pre.shape
xoff = (xsize - xcrop) // 2
yoff = (ysize - ycrop) // 2
img= img_pre[yoff:-yoff,xoff:-xoff]
else:
img= img_pre
return img
A simple modification from #Divakar 's answer that preserves the image channel:
def crop_center(self, img, cropx, cropy):
_, y, x = img.shape
startx = x // 2 - (cropx // 2)
starty = y // 2 - (cropy // 2)
return img[:, starty:starty + cropy, startx:startx + cropx]
Another simple modification from #Divakar's answer to preserve color channels:
def crop_center(img,cropx,cropy):
y,x,_ = img.shape
startx = x//2-(cropx//2)
starty = y//2-(cropy//2)
return img[starty:starty+cropy,startx:startx+cropx,:]
I had a problem in which I needed to crop the center from both 2D and 3D arrays. That meant unpacking a varying number of items from img.shape.
Dropping this here in case someone runs into the same problem. This modification of Divkar's solution allows cropping 2D OR 3D arrays
def crop_center(img, cropx, cropy):
y, x, *_ = img.shape
startx = x // 2 - (cropx // 2)
starty = y // 2 - (cropy // 2)
return img[starty:starty + cropy, startx:startx + cropx, ...]

Slicing numpy ayarray with padding independent of array dimension

Given an array image which might be a 2D, 3D or 4D, but preferable nD array, I want to extract a contiguous part of the array around a point with a list denoting how I extend in along all axis and pad the array with a pad_value if the extensions is out of the image.
I came up with this:
def extract_patch_around_point(image, loc, extend, pad_value=0):
offsets_low = []
offsets_high = []
for i, x in enumerate(loc):
offset_low = -np.min([x - extend[i], 0])
offsets_low.append(offset_low)
offset_high = np.max([x + extend[i] - image.shape[1] + 1, 0])
offsets_high.append(offset_high)
upper_patch_offsets = []
lower_image_offsets = []
upper_image_offsets = []
for i in range(image.ndim):
upper_patch_offset = 2*extend[i] + 1 - offsets_high[i]
upper_patch_offsets.append(upper_patch_offset)
image_offset_low = loc[i] - extend[i] + offsets_low[i]
image_offset_high = np.min([loc[i] + extend[i] + 1, image.shape[i]])
lower_image_offsets.append(image_offset_low)
upper_image_offsets.append(image_offset_high)
patch = pad_value*np.ones(2*np.array(extend) + 1)
# This is ugly
A = np.ix_(range(offsets_low[0], upper_patch_offsets[0]),
range(offsets_low[1], upper_patch_offsets[1]))
B = np.ix_(range(lower_image_offsets[0], upper_image_offsets[0]),
range(lower_image_offsets[1], upper_image_offsets[1]))
patch[A] = image[B]
return patch
Currently it only works in 2D because of the indexing trick with A, B etc. I do not want to check for the number of dimensions and use a different indexing scheme. How can I make this independent on image.ndim?
Based on my understanding of the requirements, I would suggest a zeros-padded version and then using slice notation to keep it generic on number of dimensions, like so -
def extract_patch_around_point(image, loc, extend, pad_value=0):
extend = np.asarray(extend)
image_ext_shp = image.shape + 2*np.array(extend)
image_ext = np.full(image_ext_shp, pad_value)
insert_idx = [slice(i,-i) for i in extend]
image_ext[insert_idx] = image
region_idx = [slice(i,j) for i,j in zip(loc,extend*2+1+loc)]
return image_ext[region_idx]
Sample runs -
2D case :
In [229]: np.random.seed(1234)
...: image = np.random.randint(11,99,(13,8))
...: loc = (5,3)
...: extend = np.array([2,4])
...:
In [230]: image
Out[230]:
array([[58, 94, 49, 64, 87, 35, 26, 60],
[34, 37, 41, 54, 41, 37, 69, 80],
[91, 84, 58, 61, 87, 48, 45, 49],
[78, 22, 11, 86, 91, 14, 13, 30],
[23, 76, 86, 92, 25, 82, 71, 57],
[39, 92, 98, 24, 23, 80, 42, 95],
[56, 27, 52, 83, 67, 81, 67, 97],
[55, 94, 58, 60, 29, 96, 57, 48],
[49, 18, 78, 16, 58, 58, 26, 45],
[21, 39, 15, 93, 66, 89, 34, 61],
[73, 66, 95, 11, 44, 32, 82, 79],
[92, 63, 75, 96, 52, 12, 25, 14],
[41, 23, 84, 30, 37, 79, 75, 33]])
In [231]: image[loc]
Out[231]: 24
In [232]: out = extract_patch_around_point(image, loc, extend, pad_value=0)
In [233]: out
Out[233]:
array([[ 0, 78, 22, 11, 86, 91, 14, 13, 30],
[ 0, 23, 76, 86, 92, 25, 82, 71, 57],
[ 0, 39, 92, 98, 24, 23, 80, 42, 95], <-- At middle
[ 0, 56, 27, 52, 83, 67, 81, 67, 97],
[ 0, 55, 94, 58, 60, 29, 96, 57, 48]])
^
3D case :
In [234]: np.random.seed(1234)
...: image = np.random.randint(11,99,(13,5,8))
...: loc = (5,2,3)
...: extend = np.array([1,2,4])
...:
In [235]: image[loc]
Out[235]: 82
In [236]: out = extract_patch_around_point(image, loc, extend, pad_value=0)
In [237]: out.shape
Out[237]: (3, 5, 9)
In [238]: out
Out[238]:
array([[[ 0, 23, 87, 19, 58, 98, 36, 32, 33],
[ 0, 56, 30, 52, 58, 47, 50, 28, 50],
[ 0, 70, 93, 48, 98, 49, 19, 65, 28],
[ 0, 52, 58, 30, 54, 55, 46, 53, 31],
[ 0, 37, 34, 13, 76, 38, 89, 79, 71]],
[[ 0, 14, 92, 58, 72, 74, 43, 24, 67],
[ 0, 59, 69, 46, 68, 71, 94, 20, 71],
[ 0, 61, 62, 60, 82, 92, 15, 14, 57], <-- At middle
[ 0, 58, 74, 95, 16, 94, 83, 83, 74],
[ 0, 67, 25, 92, 71, 19, 52, 44, 80]],
[[ 0, 74, 28, 12, 12, 13, 62, 88, 63],
[ 0, 25, 58, 86, 76, 40, 20, 91, 61],
[ 0, 28, 42, 85, 22, 45, 64, 35, 66],
[ 0, 64, 34, 69, 27, 17, 92, 89, 68],
[ 0, 15, 57, 86, 17, 98, 29, 59, 50]]])
^
Here is a simple working example that demonstrates how to iteratively "wittle down" your input matrix to obtain the patch around a point in nDims:
import numpy as np
# Givens. Matrix to be sliced, point around which to slice,
# and the padding around the given point
matrix = np.random.normal(size=[5,5,5])
loc = (3,3,3)
padding = 2
# If one knows the dimensionality, the slice can be obtained easily
ans1 = matrix[loc[0] - padding:loc[0] + 1,
loc[1] - padding:loc[1] + 1,
loc[2] - padding:loc[2] + 1]
# If one does not know the dimensionality, the slice can be
# obtained iteratively
ans2 = matrix
for i in range(matrix.ndim):
# Compute slice for the particular axis
s = slice(loc[i] - padding, loc[i] + 1, 1)
# Move particular axis to front, slice it, then move it back
ans2 = np.moveaxis(np.moveaxis(ans2, i, 0)[s], 0, i)
# Assert the two answers are equal
np.testing.assert_array_equal(ans1, ans2)
This example does not take into account slicing beyond the existing dimensions, but that exception can be easily caught in the loop.

Categories