3

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) enter image description here

But the result I am looking for is something like this: enter image description here

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:

  1. 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).

  2. 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)

  3. 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: enter image description here

EDIT2: The problem was sorted out by changing part of my code as suggested by @Reblochon Masque in the comment section in his answer.

3
  • Plot only the points on the convex hull as a parallelogram connecting these points. However, there has to be a better way... How did you generate the points in the first place? Could you do it differently? Commented Apr 21, 2016 at 8:26
  • Plot only the points on the convex hull as a parallelogram connecting these points - Could you elaborate please.? The points were generated by processing some old images, by manually picking the points. It will take couple of days to try and generate it again. :( Commented Apr 21, 2016 at 8:34
  • I posted an example on how this can be done using scipy.spatial. Commented Apr 21, 2016 at 8:43

2 Answers 2

9

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:

Convex hull in a plot

Notice this method will create a bounding box for your points.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for the reply. I have edited my question to include ConvexHull, could you please help me understand why are the lines appearing twice.? Also what if I have Concave shapes.? Any solutions for that.?
You are probably using two plot commands for slightly different stuff but I need to see the code to be sure.
@AshSharma besides my previous comment, there might be ways to achieve the same effect on more complex shapes but I think you should open a new question for it. If you want to try it out before doing a new question take a look into Delaunay triangulation (docs.scipy.org/doc/scipy-0.14.0/reference/generated/…).
4

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.

enter image description here

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.

3 Comments

Thank you for the reply. I have edited my question to include ConvexHull, could you please help me understand why are the lines appearing twice.? Also most of my shapes are Concave in nature :(
I think it is because you are using plt.plot(x[hull.vertices], y[hull.vertices]) instead of points[hull.vertices[0],0], points[hull.vertices[0],1].
Thank you! That sorted out the problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.