Plotting a Set of Given Points to Form a Closed Curve in Matplotlib

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:

  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:

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

2 Answers

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.

3

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.

3

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Elena Rostova

Elena Rostova

Lead Health, Wellness & Medical Journalist

Elena Rostova holds a Master's degree in Public Health Journalism. She covers groundbreaking medical research, holistic wellness trends, mental health awareness, and nutritional science.

Share this article
Twitter Facebook Pinterest