How to get center of set of points using Python

Question:

I would like to get the center point(x,y) of a figure created by a set of points.

How do I do this?

Asked By: Dominik Szopa

||

Answers:

If you mean centroid, you just get the average of all the points.

x = [p[0] for p in points]
y = [p[1] for p in points]
centroid = (sum(x) / len(points), sum(y) / len(points))
Answered By: Colin

I assume that a point is a tuple like (x,y), so you can use zip to join the x’s and y’s. Then using the min and max of x and y’s, you can determine the center point.

x,y=zip(*points)
center=(max(x)+min(x))/2., (max(y)+min(y))/2.

Sample output

Points in an array : [(411, 148), (304, 148), (357, 241)]
x:(411, 304, 357)
y:(148, 148, 241)
center: (357.5, 194.5)
Answered By: Kabie

If the set of points is a numpy array positions of sizes N x 2, then the centroid is simply given by:

centroid = positions.mean(axis=0)

It will directly give you the 2 coordinates a a numpy array.

In general, numpy arrays can be used for all these measures in a vectorized way, which is compact and very quick compared to for loops.

Answered By: meduz

In this case the average of the points isn’t the centroid. Generally speaking the center of area is the first moment of area. So you have to calculate the areas of the polygons that define the shape of your figure, then compute the first moment of area for each axis: sum((r_i * A_i), for i in range(N))/sum(A_i). So we can have a set of points lying on the contour of the figure:

Contents of data.dat:

x,y
0.99159,0.00467
0.97822,0.00828
0.96383,0.01237
0.94834,0.01703
0.93166,0.02231
0.91374,0.02816
0.89456,0.03443
0.87415,0.04092
0.85265,0.04755
0.83029,0.05426
0.80736,0.06099
0.78414,0.06766
0.76087,0.07423
0.73768,0.08064
0.71456,0.08687
0.69143,0.09294
0.6681,0.09886
0.64446,0.10469
0.62058,0.11041
0.59684,0.11598
0.57378,0.12127
0.55182,0.12613
0.53101,0.13048
0.51113,0.13432
0.49187,0.13766
0.47287,0.14054
0.4538,0.14301
0.43445,0.14514
0.4148,0.14694
0.39496,0.14844
0.37527,0.14964
0.3561,0.15051
0.33766,0.151
0.31999,0.15111
0.303,0.15081
0.28655,0.15011
0.27048,0.149
0.25467,0.14748
0.23907,0.14558
0.22372,0.14331
0.20869,0.14071
0.19411,0.13782
0.1801,0.1347
0.16677,0.13138
0.1542,0.12788
0.1424,0.12422
0.13136,0.12042
0.12106,0.1165
0.11142,0.11244
0.1024,0.10826
0.09391,0.10393
0.08588,0.09944
0.07824,0.09486
0.07098,0.0903
0.06412,0.08592
0.05772,0.08177
0.05182,0.07782
0.04641,0.07403
0.04142,0.07034
0.03683,0.06673
0.03258,0.0632
0.02864,0.05975
0.025,0.05637
0.02164,0.05307
0.01853,0.04985
0.01567,0.04669
0.01307,0.04357
0.01073,0.04047
0.00864,0.03735
0.00679,0.03423
0.00517,0.0311
0.00377,0.02798
0.00258,0.02487
0.00158,0.02177
0.00078,0.0187
0.00017,0.01565
-0.00025,0.01262
-0.00049,0.00962
-0.00055,0.00663
-0.00042,0.00367
-9.00E-05,0.00073
0.00043,-0.00218
0.00114,-0.00508
0.00206,-0.00793
0.00316,-0.01073
0.00447,-0.01346
0.00599,-0.0161
0.00772,-0.01865
0.00968,-0.02106
0.01188,-0.02333
0.01435,-0.02541
0.01711,-0.02728
0.02016,-0.02894
0.02351,-0.03043
0.02714,-0.03179
0.03101,-0.03309
0.03514,-0.03434
0.03955,-0.03555
0.04429,-0.03675
0.04937,-0.03795
0.05483,-0.03918
0.06069,-0.04048
0.06697,-0.0418
0.07372,-0.04312
0.081,-0.04436
0.0889,-0.0455
0.0976,-0.04653
0.10725,-0.04749
0.11801,-0.0484
0.13002,-0.04926
0.1434,-0.05007
0.15815,-0.05085
0.17419,-0.05161
0.19136,-0.05227
0.20955,-0.05274
0.22884,-0.05293
0.2494,-0.05286
0.27136,-0.05256
0.29473,-0.05206
0.3192,-0.05146
0.3442,-0.05081
0.36921,-0.05008
0.39401,-0.04924
0.41866,-0.04826
0.44342,-0.04713
0.46845,-0.04586
0.49376,-0.04447
0.51919,-0.04299
0.54445,-0.04142
0.56941,-0.03976
0.5941,-0.03796
0.61869,-0.036
0.64343,-0.03387
0.66852,-0.03162
0.69403,-0.0293
0.7199,-0.02698
0.74597,-0.02469
0.77207,-0.02242
0.79809,-0.02016
0.82397,-0.0179
0.84958,-0.01566
0.8746,-0.01347
0.8986,-0.01136
0.92114,-0.00939
0.94183,-0.00758
0.96037,-0.00596
0.97676,-0.00453
0.99124,-0.00326
1,-0.0025

Code: Calculate the first moment of area

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

data = pd.read_table('data.dat',delim_whitespace=True,skiprows=[0],names=['x','y'],index_col=False)
x = data.x.to_numpy() 
y = data.y.to_numpy()

N = range(len(data)-1)
M = np.array([(x[i]-x[i+1])*(y[i]+y[i+1])/2 for i in N]) #Area of each trapezoid
My = np.array([(x[i]+x[i+1])/2 for i in N])*M #Moment of area (area*distance to centroid) with respect to the Y axis of each trapezoid
Mx = np.array([(y[i]+y[i+1])/4 for i in N])*M #Moment of area (area*distance to centroid) with respect to the X axis of each trapezoid
X = sum(My)/sum(M)
Y = sum(Mx)/sum(M)

centroid = [X , Y]

points_ave = data.mean(axis=0)

plt.plot(data.x, data.y, 'r',marker='.',markeredgecolor='black', markersize=3)
plt.plot(*centroid, 'blue', marker='o',markeredgecolor='black', markersize=7)
plt.plot(*points_ave, 'green', marker='o',markeredgecolor='black', markersize=7)
plt.axis('equal')
plt.xlim((-0.05, 1.05))
plt.legend(['GOE 383 AIRFOIL','Centroid','Average of points'])

In the following image you can very clearly see how the non-uniform point sampling skews the results. The average of points is only useful for point masses or concentrated properties.

Figure Centroid

Answered By: Michel G
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.