how to solve the edges issue in hexagonal plot? - python

I'm a beginner and I hope to be clear in exposing the problem.
I created a matrix like this:
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 6 8 9 1 0 0]
[0 0 4 6 5 4 0 0]
[0 0 4 2 8 9 0 0]
[0 0 1 3 6 7 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
the point is that I have to create a hexagonal plot in which the color scale represents the random numbers in the individual cells.
This is what I did:
import numpy as np
import matplotlib.pyplot as plt
n=4
A=np.zeros([2*n,2*n], dtype=int)
B=np.random.randint(1,10, size=(n,n))
A[2:6,2:6]=B
plt.figure(figsize=(5,5))
plt.imshow(A, origin=['lower'], cmap=plt.cm.Purples_r)
plt.colorbar()
x=[]
y=[]
for i in range (np.shape(A)[0]):
for j in range (np.shape(A)[1]):
N_occurence=A[i,j]
print(N_occurence)
for k in range (N_occurence):
x=np.append(x, i)
y=np.append(y, j)
plt.figure(figsize=(5,5))
plt.hexbin(x,y,gridsize=(10), cmap=plt.cm.Purples_r)
plt.xlim([1, 6])
plt.ylim([1, 6])
plt.colorbar()
plt.show()
but I can not solve the problem of edges, I always get half hexagons and the plot is not accurate. Does anyone know a simpler way or a similar example?

I'm still not really sure, what you're looking for, but I guess you want to have a imshow plot which uses hexagons like hexbin?
Maybe this helps a little bit:
import matplotlib.pyplot as plt
import numpy as np
# Generate array
A = np.zeros([8, 8], dtype=int)
A[2:6, 2:6] = np.random.randint(1, 10, size=(4, 4))
# Print array
print(A)
# `imshow` plot
plt.figure(figsize=(5,5))
plt.imshow(A, extent=(0, 8, 0, 8), origin='lower')
plt.colorbar()
# Rewrite array to get x and y values
# TODO: There has to be a better way than to use two `for` loops
X = []
Y = []
for y in range(len(A)):
for x, n in enumerate(A[len(A)-y-1]):
X += [x]*n
Y += [y]*n
# `scatter` plot to visualize rewritten array data
plt.figure(figsize=(5,5))
plt.scatter(X, Y)
# `hexbin` plot
plt.figure(figsize=(5,5))
plt.hexbin(X, Y, gridsize=5, extent=(0, 7, 0, 7))
plt.colorbar()
# show plots
plt.show()
Which results for random array A
[[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]
[0 0 3 7 3 3 0 0]
[0 0 3 5 8 1 0 0]
[0 0 4 8 7 3 0 0]
[0 0 1 7 9 3 0 0]
[0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0]]
in
imshow
scatter
hexbin
I think you might be better off with a custom solution like a scatterplot plotting hexagon tiles with your specified color.

Related

Numpy get secondary diagonal with offset=1 and change the values

I have this 6x6 matrix filled with 0s. I got the secondary diagonal in sec_diag. The thing I am trying to do is to change the values of above the sec_diag inside the matrix with the odds numbers from 9-1 [9,7,5,3,1]
import numpy as np
x = np.zeros((6,6), int)
sec_diag = np.diagonal(np.fliplr(x), offset=1)
The result should look like this:
[[0,0,0,0,9,0],
[0,0,0,7,0,0],
[0,0,5,0,0,0],
[0,3,0,0,0,0],
[1,0,0,0,0,0],
[0,0,0,0,0,0]]
EDIT: np.fill_diagonal isn't going to work.
You should use roll
x = np.zeros((6,6),dtype=np.int32)
np.fill_diagonal(np.fliplr(x), [9,7,5,3,1,0])
xr = np.roll(x,-1,axis=1)
print(xr)
Output
[[0 0 0 0 9 0]
[0 0 0 7 0 0]
[0 0 5 0 0 0]
[0 3 0 0 0 0]
[1 0 0 0 0 0]
[0 0 0 0 0 0]]
Maybe you should try with a double loop

Plot a 2D binary matrix as a line in matplotlib using plot?

I have a 2D matrix containing zeros and ones. The ones define a shape from which I want to plot its contour/edge on a matplotlib figure. The initial 2D binary matrix:
[[0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 1 1 1 1 1 0 0 0]
[0 0 0 1 1 1 1 1 0 0 0]
[0 0 0 1 1 1 1 1 0 0 0]
[0 0 0 1 1 1 1 1 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0]]
I found here the method to get the corresponding 2D binary matrix of the edge of the shape:
[[0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 1 1 1 1 1 0 0 0]
[0 0 0 1 0 0 0 1 0 0 0]
[0 0 0 1 0 0 0 1 0 0 0]
[0 0 0 1 1 1 1 1 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0]]
Using plt.imshow, I get the following result:
How would you do to plot the ones in this matrix as a dotted line in a matplotlib figure using plt.plot() ? I would like to get this result:
For more complex geometries than a rectangle you can use the ConvexHull from scipy.spatial:
#starting with the original data
data = [
[0,0,0,0,0,0,0,0,0,0,0]
,[0,0,0,1,1,1,1,1,0,0,0]
,[0,0,0,1,1,1,1,1,0,0,0]
,[0,0,0,1,1,1,1,1,0,0,0]
,[0,0,0,1,1,1,1,1,0,0,0]
,[0,0,0,0,0,0,0,0,0,0,0]]
#convert the data array into x-y coordinates
#assume (0,0) is the lower left corner of the array
def array_to_coords(data):
for y, line in enumerate(reversed(data)):
for x, point in enumerate(line):
if point == 1:
yield(x, y)
points = list(array_to_coords(data))
#plot the points, skip this if you only need the dotted line
x,y = zip(*points)
plt.plot(x, y, 'o')
plt.xlim(0,10)
plt.ylim(0,5)
#plot the convex hull
from scipy.spatial import ConvexHull
hull = ConvexHull(points)
for simplex in hull.simplices:
plt.plot(hull.points[simplex,0], hull.points[simplex,1], 'ro-')
A more complex situation:
data = [
[0,0,0,0,0,1,0,0,0,0,0]
,[0,0,0,1,1,1,1,1,0,0,0]
,[0,0,0,1,1,1,1,1,0,0,0]
,[0,0,0,1,1,1,1,1,0,0,0]
,[0,0,1,1,1,1,1,0,0,0,0]
,[0,0,0,0,0,0,0,0,0,0,0]]
This isn't exactly the same, but maybe it can give you a start. You can see what I did. I extracted the x,y locations of the 1 values, then plotted x against y in a scatter plot.
import matplotlib.pyplot as plt
import numpy as np
array = np.array(
[[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,1,1,1,1,0,0,0],
[0,0,0,1,0,0,0,1,0,0,0],
[0,0,0,1,0,0,0,1,0,0,0],
[0,0,0,1,1,1,1,1,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0]])
coords = np.argwhere(array==1)
plt.xlim(0,10)
plt.ylim(0,5)
plt.scatter(coords[:,1],coords[:,0])
plt.show()
Output:
Followup
import matplotlib.pyplot as plt
import numpy as np
array = np.array(
[[0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,1,1,1,1,0,0,0],
[0,0,0,1,0,0,0,1,0,0,0],
[0,0,0,1,0,0,0,1,0,0,0],
[0,0,0,1,1,1,1,1,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0]])
coords = np.argwhere(array==1)
xmin = np.min(coords[:,1])
xmax = np.max(coords[:,1])
ymin = np.min(coords[:,0])
ymax = np.max(coords[:,0])
x = [xmin,xmin,xmax,xmax,xmin]
y = [ymin,ymax,ymax,ymin,ymin]
plt.xlim(0,10)
plt.ylim(0,5)
plt.plot(x, y, '--')
plt.show()
Output:

Create a matrix for datapoints in same or different clusters

I want to iterate through my datapoints and check whether they are in the same cluster, after using KMeans to cluster them.
And then I need to create a matrix for all the datapoints, and have 1 if they belong on the same cluster, and 0 if they don't.
After using Kmeans, I'm not sure how to retrieve which cluster every datapoint belongs to so I can create such matrix.
Do I do that using labels_ argument?
k_means = KMeans(n_clusters=5).fit(X)
labels_columns = k_means.labels_
labels_row = k_means.labels_
for row in labels_row:
for column in labels_columns:
if row == columns:
--add 1 in matrix position
else:
--add 0 in matrix position
How to best create this matrix? Or do they labels_ provide different information from what my understanding?
Any help is appreciated!
You are on the right track. Kmeans.labels_ returns a vector of n elements which tells you that the
cluster each point belongs to: [3, 4, 10, ...] tells you that point 0 belongs to cluster 3, point 1
belongs to cluster 4 and so on.
You can build the matrix you want in many ways. One possibility I thought which is a bit more elegant than
2 for loops would be the following:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
n_samples, n_features = 10, 2
X, y = make_blobs(n_samples, n_features)
plt.scatter(X[:, 0], X[:, 1], c=y)
plt.show()
kmeans = KMeans(n_clusters=3).fit(X)
plt.scatter(X[:, 0], X[:, 1], c=kmeans.labels_)
plt.show()
neighbour_matrix = np.zeros(n_samples)
repeat_labels = np.repeat(kmeans.labels_.T, n_samples, axis=0).reshape(n_samples, n_samples)
print(kmeans.labels_)
print(repeat_labels)
proximity_matrix = (repeat_labels == repeat_labels.T).astype(int)
print(proximity_matrix)
I use the vector of labels as my starting point. Let's say that it is the following:
[1 0 0 1 1 2 2 2 2 0]
I transform it in a 2D matrix with np.repeat which has the following shape:
[[1 1 1 1 1 1 1 1 1 1]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[1 1 1 1 1 1 1 1 1 1]
.....
So I repeat the labels as many times as is the number of points n. Then I can just check where this
matrix and its transpose are equal. That will be true only if two points belong to the same cluster:
[[1 0 0 1 1 0 0 0 0 0]
[0 1 1 0 0 0 0 0 0 1]
[0 1 1 0 0 0 0 0 0 1]
[1 0 0 1 1 0 0 0 0 0]
.....
I casted the matrix to int, but mind you that the original output is actually a boolean array.
I left the print statements and the plots in the code to hopefully make it more clear.
Hope it helps!

bounding box of numpy array

Suppose you have a 2D numpy array with some random values and surrounding zeros.
Example "tilted rectangle":
import numpy as np
from skimage import transform
img1 = np.zeros((100,100))
img1[25:75,25:75] = 1.
img2 = transform.rotate(img1, 45)
Now I want to find the smallest bounding rectangle for all the nonzero data. For example:
a = np.where(img2 != 0)
bbox = img2[np.min(a[0]):np.max(a[0])+1, np.min(a[1]):np.max(a[1])+1]
What would be the fastest way to achieve this result? I am sure there is a better way since the np.where function takes quite a time if I am e.g. using 1000x1000 data sets.
Edit: Should also work in 3D...
You can roughly halve the execution time by using np.any to reduce the rows and columns that contain non-zero values to 1D vectors, rather than finding the indices of all non-zero values using np.where:
def bbox1(img):
a = np.where(img != 0)
bbox = np.min(a[0]), np.max(a[0]), np.min(a[1]), np.max(a[1])
return bbox
def bbox2(img):
rows = np.any(img, axis=1)
cols = np.any(img, axis=0)
rmin, rmax = np.where(rows)[0][[0, -1]]
cmin, cmax = np.where(cols)[0][[0, -1]]
return rmin, rmax, cmin, cmax
Some benchmarks:
%timeit bbox1(img2)
10000 loops, best of 3: 63.5 µs per loop
%timeit bbox2(img2)
10000 loops, best of 3: 37.1 µs per loop
Extending this approach to the 3D case just involves performing the reduction along each pair of axes:
def bbox2_3D(img):
r = np.any(img, axis=(1, 2))
c = np.any(img, axis=(0, 2))
z = np.any(img, axis=(0, 1))
rmin, rmax = np.where(r)[0][[0, -1]]
cmin, cmax = np.where(c)[0][[0, -1]]
zmin, zmax = np.where(z)[0][[0, -1]]
return rmin, rmax, cmin, cmax, zmin, zmax
It's easy to generalize this to N dimensions by using itertools.combinations to iterate over each unique combination of axes to perform the reduction over:
import itertools
def bbox2_ND(img):
N = img.ndim
out = []
for ax in itertools.combinations(reversed(range(N)), N - 1):
nonzero = np.any(img, axis=ax)
out.extend(np.where(nonzero)[0][[0, -1]])
return tuple(out)
If you know the coordinates of the corners of the original bounding box, the angle of rotation, and the centre of rotation, you could get the coordinates of the transformed bounding box corners directly by computing the corresponding affine transformation matrix and dotting it with the input coordinates:
def bbox_rotate(bbox_in, angle, centre):
rmin, rmax, cmin, cmax = bbox_in
# bounding box corners in homogeneous coordinates
xyz_in = np.array(([[cmin, cmin, cmax, cmax],
[rmin, rmax, rmin, rmax],
[ 1, 1, 1, 1]]))
# translate centre to origin
cr, cc = centre
cent2ori = np.eye(3)
cent2ori[:2, 2] = -cr, -cc
# rotate about the origin
theta = np.deg2rad(angle)
rmat = np.eye(3)
rmat[:2, :2] = np.array([[ np.cos(theta),-np.sin(theta)],
[ np.sin(theta), np.cos(theta)]])
# translate from origin back to centre
ori2cent = np.eye(3)
ori2cent[:2, 2] = cr, cc
# combine transformations (rightmost matrix is applied first)
xyz_out = ori2cent.dot(rmat).dot(cent2ori).dot(xyz_in)
r, c = xyz_out[:2]
rmin = int(r.min())
rmax = int(r.max())
cmin = int(c.min())
cmax = int(c.max())
return rmin, rmax, cmin, cmax
This works out to be very slightly faster than using np.any for your small example array:
%timeit bbox_rotate([25, 75, 25, 75], 45, (50, 50))
10000 loops, best of 3: 33 µs per loop
However, since the speed of this method is independent of the size of the input array, it can be quite a lot faster for larger arrays.
Extending the transformation approach to 3D is slightly more complicated, in that the rotation now has three different components (one about the x-axis, one about the y-axis and one about the z-axis), but the basic method is the same:
def bbox_rotate_3d(bbox_in, angle_x, angle_y, angle_z, centre):
rmin, rmax, cmin, cmax, zmin, zmax = bbox_in
# bounding box corners in homogeneous coordinates
xyzu_in = np.array(([[cmin, cmin, cmin, cmin, cmax, cmax, cmax, cmax],
[rmin, rmin, rmax, rmax, rmin, rmin, rmax, rmax],
[zmin, zmax, zmin, zmax, zmin, zmax, zmin, zmax],
[ 1, 1, 1, 1, 1, 1, 1, 1]]))
# translate centre to origin
cr, cc, cz = centre
cent2ori = np.eye(4)
cent2ori[:3, 3] = -cr, -cc -cz
# rotation about the x-axis
theta = np.deg2rad(angle_x)
rmat_x = np.eye(4)
rmat_x[1:3, 1:3] = np.array([[ np.cos(theta),-np.sin(theta)],
[ np.sin(theta), np.cos(theta)]])
# rotation about the y-axis
theta = np.deg2rad(angle_y)
rmat_y = np.eye(4)
rmat_y[[0, 0, 2, 2], [0, 2, 0, 2]] = (
np.cos(theta), np.sin(theta), -np.sin(theta), np.cos(theta))
# rotation about the z-axis
theta = np.deg2rad(angle_z)
rmat_z = np.eye(4)
rmat_z[:2, :2] = np.array([[ np.cos(theta),-np.sin(theta)],
[ np.sin(theta), np.cos(theta)]])
# translate from origin back to centre
ori2cent = np.eye(4)
ori2cent[:3, 3] = cr, cc, cz
# combine transformations (rightmost matrix is applied first)
tform = ori2cent.dot(rmat_z).dot(rmat_y).dot(rmat_x).dot(cent2ori)
xyzu_out = tform.dot(xyzu_in)
r, c, z = xyzu_out[:3]
rmin = int(r.min())
rmax = int(r.max())
cmin = int(c.min())
cmax = int(c.max())
zmin = int(z.min())
zmax = int(z.max())
return rmin, rmax, cmin, cmax, zmin, zmax
I've essentially just modified the function above using the rotation matrix expressions from here - I haven't had time to write a test-case yet, so use with caution.
Here is an algorithm to calculate the bounding box for N dimensional arrays,
def get_bounding_box(x):
""" Calculates the bounding box of a ndarray"""
mask = x == 0
bbox = []
all_axis = np.arange(x.ndim)
for kdim in all_axis:
nk_dim = np.delete(all_axis, kdim)
mask_i = mask.all(axis=tuple(nk_dim))
dmask_i = np.diff(mask_i)
idx_i = np.nonzero(dmask_i)[0]
if len(idx_i) != 2:
raise ValueError('Algorithm failed, {} does not have 2 elements!'.format(idx_i))
bbox.append(slice(idx_i[0]+1, idx_i[1]+1))
return bbox
which can be used with 2D, 3D, etc arrays as follows,
In [1]: print((img2!=0).astype(int))
...: bbox = get_bounding_box(img2)
...: print((img2[bbox]!=0).astype(int))
...:
[[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0]
[0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0]
[0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0]
[0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0]
[0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0]
[0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0]
[0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0]
[0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0]
[0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0]
[0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]
[[0 0 0 0 0 0 1 1 0 0 0 0 0 0]
[0 0 0 0 0 1 1 1 1 0 0 0 0 0]
[0 0 0 0 1 1 1 1 1 1 0 0 0 0]
[0 0 0 1 1 1 1 1 1 1 1 0 0 0]
[0 0 1 1 1 1 1 1 1 1 1 1 0 0]
[0 1 1 1 1 1 1 1 1 1 1 1 1 0]
[1 1 1 1 1 1 1 1 1 1 1 1 1 1]
[1 1 1 1 1 1 1 1 1 1 1 1 1 1]
[0 1 1 1 1 1 1 1 1 1 1 1 1 0]
[0 0 1 1 1 1 1 1 1 1 1 1 0 0]
[0 0 0 1 1 1 1 1 1 1 1 0 0 0]
[0 0 0 0 1 1 1 1 1 1 0 0 0 0]
[0 0 0 0 0 1 1 1 1 0 0 0 0 0]
[0 0 0 0 0 0 1 1 0 0 0 0 0 0]]
Although replacing the np.diff and np.nonzero calls by one np.where might be better.
I was able to squeeze out a little more performance by replacing np.where with np.argmax and working on a boolean mask.
def bbox(img):
img = (img > 0)
rows = np.any(img, axis=1)
cols = np.any(img, axis=0)
rmin, rmax = np.argmax(rows), img.shape[0] - 1 - np.argmax(np.flipud(rows))
cmin, cmax = np.argmax(cols), img.shape[1] - 1 - np.argmax(np.flipud(cols))
return rmin, rmax, cmin, cmax
This was about 10µs faster for me than the bbox2 solution above on the same benchmark. There should also be a way to just use the result of argmax to find the non-zero rows and columns, avoiding the extra search done by using np.any, but this may require some tricky indexing that I wasn't able to get working efficiently with simple vectorized code.
I know this post is old and has already been answered, but I believe I've identified an optimized approach for large arrays and arrays loaded as np.memmaps.
I was using ali_m's response that was optimized by Allen Zelener for smaller ndarrays, but this approach turns out to be quite slow for np.memmaps.
Below is my implementation that has extremely similar performance speeds to ali_m's approach approach for arrays that fit in the working memory, but that far outperforms when bounding large arrays or np.memmaps.
import numpy as np
from numba import njit, prange
#njit(parallel=True, nogil=True, cache=True)
def bound(volume):
"""
Bounding function to bound large arrays and np.memmaps
volume: A 3D np.array or np.memmap
"""
mins = np.array(volume.shape)
maxes = np.zeros(3)
for z in prange(volume.shape[0]):
for y in range(volume.shape[1]):
for x in range(volume.shape[2]):
if volume[z,y,x]:
if z < mins[0]:
mins[0] = z
elif z > maxes[0]:
maxes[0] = z
if y < mins[1]:
mins[1] = y
elif y > maxes[1]:
maxes[1] = y
if x < mins[2]:
mins[2] = x
elif x > maxes[2]:
maxes[2] = x
return mins, maxes
My approach is somewhat inefficient in the sense that it just iterates over every point rather than flattening the arrays over specific dimensions. However, I found flattening np.memmaps using np.any() with a dimension argument to be quite slow. I tried using numba to speed up the flattening, but it doesn't support np.any() with arguments. As such, I came to my iterative approach that seems to perform quite well.
On my computer (2019 16" MacBook Pro, 6-core i7, 16 GB 2667 MHz DDR4), I'm able to bound a np.memmap with a shape of (1915, 4948, 3227) in ~33 seconds, as opposed to the ali_m approach that takes around ~250 seconds.
Not sure if anyone will ever see this, but hopefully it helps in the niche cases of needing to bound np.memmaps.

find mean position and area of labelled objects

I have a 2D labeled image (numpy array), each label represents an object. I have to find the object's center and its area. My current solution:
centers = [np.mean(np.where(label_2d == i),1) for i in range(1,num_obj+1)]
surface_area = np.array([np.sum(label_2d == i) for i in range(1,num_obj+1)])
Note that label_2d used for centers is not the same as the one for surface area, so I can't combine both operations. My current code is about 10-100 times to slow.
In C++ I would iterate through the image once (2 for loops) and fill the table (an array), from which I would than calculate centers and surface area.
Since for loops are quite slow in python, I have to find another solution. Any advice?
You could use the center_of_mass function present in scipy.ndimage.measurements for the first problem and then use np.bincount for the second problem. Because these are in the mainstream libraries, they will be heavily optimized, so you can expect decent speed gains.
Example:
>>> import numpy as np
>>> from scipy.ndimage.measurements import center_of_mass
>>>
>>> a = np.zeros((10,10), dtype=np.int)
>>> # add some labels:
... a[3:5, 1:3] = 1
>>> a[7:9, 0:3] = 2
>>> a[5:6, 4:9] = 3
>>> print(a)
[[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 1 1 0 0 0 0 0 0 0]
[0 1 1 0 0 0 0 0 0 0]
[0 0 0 0 3 3 3 3 3 0]
[0 0 0 0 0 0 0 0 0 0]
[2 2 2 0 0 0 0 0 0 0]
[2 2 2 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]]
>>>
>>> num_obj = 3
>>> surface_areas = np.bincount(a.flat)[1:]
>>> centers = center_of_mass(a, labels=a, index=range(1, num_obj+1))
>>> print(surface_areas)
[4 6 5]
>>> print(centers)
[(3.5, 1.5), (7.5, 1.0), (5.0, 6.0)]
Speed gains depend on the size of your input data though, so I can't make any serious estimates on that. Would be nice if you could add that info (size of a, number of labels, timing results for the method you used and these functions) in the comments.

Categories