Reputation: 468
I have (tons of) coordinates of points for closed curve(s) sorted in x-increasing order.
When plot it in the regular way the result i get is this:
(circle as an example only, the shapes I currently have can be, at best, classified as amoeboids)
But the result I am looking for is something like this:
I have looked through matplotlib and I couldn't find anything. (Maybe I had my keywords wrong...?)
I have tried to reformat the data in the following ways:
Pick a point at random, find its nearest neighbor and then the next nearest neighbor and so on.. It fails at the edges where, sometimes the data isn't too consistent (the nearest neighbor maybe on the opposite side of the curve).
To account for inconsistent data, I tried to check if the slope between two points (which are being considered as nearest neighbors) matches with the previously connected slope - Fails, for reasons I could not find. (spent considerable number of hours before I gave up)
Pick x_minimum and x_maximum (and corresponding y coordinates) and draw an imaginary line and sort for points on either side of the line. - Fails when you have a curve that looks like a banana.
Is there a python package/library that can help me get to where I want.? Or can you help me with ideas to sort my data points better.? Thanks in advance.
EDIT:
Tried the ConcaveHull on the circle I had, any idea why the lines are overlapping at places.? Here's the image:
EDIT2: The problem was sorted out by changing part of my code as suggested by @Reblochon Masque in the comment section in his answer.
Upvotes: 3
Views: 9065
Reputation: 36682
Here is an example that will maybe do what you want and solve your problem: more info here
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial import ConvexHull
points = np.random.rand(30, 2) # 30 random points in 2-D
hull = ConvexHull(points)
#xs = np.array([point[0] for point in points])
#ys = np.array([point[1] for point in points])
#xh = np.array([point[0] for point in hull.points])
#yh = np.array([point[1] for point in hull.points])
plt.plot(points[:,0], points[:,1], 'o')
for simplex in hull.simplices:
plt.plot(points[simplex, 0], points[simplex, 1], 'k-')
plt.plot(points[hull.vertices,0], points[hull.vertices,1], 'r--', lw=2)
plt.plot(points[hull.vertices[0],0], points[hull.vertices[0],1], 'ro')
plt.show()
The points on the of the convex hull are plotted separately and joined to form a polygon. You can further manipulate them if you want.
I think this is maybe a good solution (easy and cheap) to implement in your case. It will work well if your shapes are convex.
In case your shapes are not all convex, one approach that might be successful could be to sort the points according to which neighbor is closest, and draw a polygon from this sorted set.
Upvotes: 4
Reputation: 13465
If you don't know how your points are set up (if you do I recommend you follow that order, it will be faster) you can use Convex Hull from scipy:
import matplotlib.pyplot as plt
from scipy.spatial import ConvexHull
# RANDOM DATA
x = np.random.normal(0,1,100)
y = np.random.normal(0,1,100)
xy = np.hstack((x[:,np.newaxis],y[:,np.newaxis]))
# PERFORM CONVEX HULL
hull = ConvexHull(xy)
# PLOT THE RESULTS
plt.scatter(x,y)
plt.plot(x[hull.vertices], y[hull.vertices])
plt.show()
, which in the example above results is this:
Notice this method will create a bounding box for your points.
Upvotes: 9