ConvexHull not accurate enough - alternatives? - python

I have a cluster consistent of about 25k points and I want to find the borders. It works with ConvexHull, but the result is that I only get about 19 coordinates as output. This is definitely too few.
Here is the sample code from the SciPy documentation. If you run it you can see that the number of points is very limited.
from scipy.spatial import ConvexHull
import numpy as np
import matplotlib.pyplot as plt
points = np.random.rand(50, 2) # 30 random points in 2-D
hull = ConvexHull(points, incremental=False)
plt.plot(points[:,0], points[:,1], 'o')
for simplex in hull.simplices:
plt.plot(points[simplex,0], points[simplex,1], 'r-')
plt.show()
Is it possible to get more points to increase the accuracy of the boarder? Or do I need a different code?

Well then your hull wouldn't be convex!
Try http://www.geosensor.net/papers/duckham08.PR.pdf for an algorithm that will attempt to get what you probably want, which is something that morally follows the "border" of the set of points.
You could also try alpha-shapes.

Related

Struggling with piecewise polynomial interpolation in python

So I have this task, where im supposed to interpolate a function with polynomials. The entire interval is divided into N subintervals, and the polynomial interpolating in each subinterval is of order k. I generet all my interpolating points, but I am running into two problems.
I) For k=1, i.e first order polynomials, I've tried solving the task by having a loop generate a first order polynomial in each subinterval using the scipy interp1d, but I'd like to get all the different polynomials in a single plot.
This is my code, tried only including the nessescary bits, sorry if something is missing. intpoint here are the interpolation points, and funky(x) is just the arbitrary function im approximating.
import numpy as np
import matplotlib.pyplot as plt
import scipy.interpolate as sc
intpoint=np.array([-3,-2,-1,0,1,2,3])
for i in range(len(intpoint)):
intleng=[intpoint[i],intpoint[i+1]]
myinterval=np.linspace(intpoint[i],intpoint[i+1],1000)
mypol=sc.interp1d(intleng,np.sin(intleng),1)
plt.plot(intleng, mypol(intleng))
plt.plot(myinterval,np.sin(myinterval))
plt.show()
Apologies in advance if anything is unclear, or my code is hard to follow/untidy.
import numpy as np
import matplotlib.pyplot as plt
import scipy.interpolate as sc
intpoint=np.array([-3,-2,-1,0,1,2,3])
for i in range(len(intpoint)-1):
intleng=[intpoint[i],intpoint[i+1]]
myinterval=np.linspace(intpoint[i],intpoint[i+1],1000)
mypol=sc.interp1d(intleng,np.sin(intleng),1)
plt.plot(myinterval,mypol(myinterval))
plt.plot(myinterval,np.sin(myinterval))
plt.show()
I think this is what you want. There was a mistake in the plotting and you should do plt.show() only once to get one plot.

How to properly scale graph of highly disproprtionate matrix in matplotlib?

I have a set of matrices I'm graphing with plt.matshow(matrix) and it works fine for matrices with dimensions that are close to each other (i.e. 56,000 x 5,000 or 64x6). However, when I try it with a 56,000x6 matrix, I just get a really large scale and no graph (See attached image), which I suspect is due to matplotlib not being sure how to scale the image. Does anyone know how to handle this?
you could use a logarithmic scale:
import matplotlib.pyplot as plt
import numpy as np
# dummy matrix:
a = np.arange(20000).reshape(10000, 2)
plt.matshow(a)
plt.yscale('log')
plt.show()
Alternatively, you can manually change the aspect of your plot:
plt.matshow(a)
plt.gca().set_aspect(0.0001)

Boundary points from a set of coordinates

I have a set of lat,long points, and from this points I'd like to extract the points that form the boundaries, I've used convexhull, but for my purpouse is not enough as convehull just returns the most distant points that form the polygon where all the points fit, I need ALL the points that form the peremiter, something like the image I've attached. What could I do? Is there some kind of package ready to use instead of implement any spatial algorithm?
Thanks
You must use a package for convex polygons. Here is an example:
import alphashape
import matplotlib.pyplot as plt
points = put your points here (can be array)!
alpha = 0.95 * alphashape.optimizealpha(points)
hull = alphashape.alphashape(points, alpha)
hull_pts = hull.exterior.coords.xy
fig, ax = plt.subplots()
ax.scatter(hull_pts[0], hull_pts[1], color='red')
Use Concave hull (Alpha shape) instead.
Assuming that you have all points (latitudes and longitudes) in two lists LATS, LONGS respectively, this python snippet cand do the trick. hullPoint will have the set of points that can draw the convex hull.
import numpy as np
from scipy.spatial import ConvexHull
allPoints=np.column_stack((LATS,LONGS))
hullPoints = ConvexHull(allPoints)

Delaunay triangularization of Polyhedron (Python)

I'm trying to get the Delaunay Triangulation of a polyhedron in python so that I can calculate the centroid. I see that there is a Delaunay function in scipy.spatial and that it works in n-dimensions. The trouble is that the documentation shows 2D use and gives me no indication of what to do with higher dimensions. Being able to decompose this object into an array would probably solve this issue for me, but I don't know how to do that.
The problem I'm running into is that I do not know how to verify that this is working correctly as it is outputting an object. I can find nothing on Google about how to graph a polyhedron or how to use this object that scipy is spitting back.
If I do
import numpy as np
from scipy.spatial import Delaunay
points = np.array([[0,0,0],[1,0,0],[1,1,0],[1,0,1],[1,1,1],[0,1,0],[0,1,1],[0,0,1]])
Delaunay(points)
I really would just like to be able to get back the coordinates of these tetrahedrons so that I can calculate the centroids of the polyhedrons. It would also be really nice if I were able to graph the tesselated polyhedron too. I saw in MATLAB that I can do this with a fuction called trimesn, and I found one from matplotlib but it seems to be really different and its documentation is not great.
from matplotlib.collections import TriMesh TriMesh.__doc__
u'\n Class for the efficient drawing of a triangular mesh using\n
Gouraud shading.\n\n A triangular mesh is a
:class:`~matplotlib.tri.Triangulation`\n object.\n '
What tess = Delaunay(pts) returns is an object of the Delanauy class. You can check the tetrahedrons as tess.simplices. It has different attributes and methods. In 2D, for example, it can plot you triangulation, convex hull and Voronoi tesselation.
Regarding the visualization of the final collection of tetrahedrons I didn't find a straightforward way of doing it, but I managed to get a working script. Check the code below.
from __future__ import division
import numpy as np
from scipy.spatial import Delaunay
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollection
from itertools import combinations
def plot_tetra(tetra, pts, color="green", alpha=0.1, lc="k", lw=1):
combs = combinations(tetra, 3)
for comb in combs:
X = pts[comb, 0]
Y = pts[comb, 1]
Z = pts[comb, 2]
verts = [zip(X, Y, Z)]
triangle = Poly3DCollection(verts, facecolors=color, alpha=0.1)
lines = Line3DCollection(verts, colors=lc, linewidths=lw)
ax.add_collection3d(triangle)
ax.add_collection3d(lines)
pts = np.array([
[0,0,0],
[1,0,0],
[1,1,0],
[1,0,1],
[1,1,1],
[0,1,0],
[0,1,1],
[0,0,1]])
tess = Delaunay(pts)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
for k, tetra in enumerate(tess.simplices):
color = plt.cm.Accent(k/(tess.nsimplex - 1))
plot_tetra(tetra, pts, color=color, alpha=0.1, lw=0.5, lc="k")
ax.scatter(pts[:, 0], pts[:, 1], pts[:, 2], c='k')
plt.savefig("Delaunay.png", dpi=600)
plt.show()
The resulting image is
You do not need the Delaunay triangulation to compute the centroid of a polyhedron.
The centroid is a weighted sum of tetrahedra centroids, where the weight is the volume of each tetrahedron.
You do not need to partition the polyhedron into tetrahedra.
First, triangulate the faces of the polyhedron, i.e., quads get partitioned
into two coplanar triangles, etc.
Next, pick an arbitrary point p in space, say, the origin.
Now, for each triangle face (a,b,c), compute the signed volume of the tetrahedron
(p,a,b,c). This works if all triangles are oriented counterclockwise.
The signed volume takes care of everything via cancellation.
Use the signed volume as the weight
to multiply the tetrahedra centroids.
Tetrahedra signed volume is explained in Chapter 1 of my book,
"Computational Geometry in C."

Boxcar convolve a scatter plot in python/astropy?

I believe the fix to this will be relatively simple, but I can't seem to figure out how to convolve a scatter plot that I've plotted in python.
I have 2 data arrays, one of galactic latitudes and one of galactic longitudes, and I've plotted them with a hammer projection to represent a distribution of stars in galactic coordinates.
Now, I want to use boxcar smoothing to smooth the plot with 15 degree boxes.
I have tried using astropy.convolution with convolve and Box2DKernel, but I can't seem to make it work.
I've also looked at examples from http://docs.astropy.org/en/stable/convolution/kernels.html
but I don't understand how to translate their examples to what I need to do. They seem to be plotting a 2D function and smoothing that. Can I not convolve a plot and bin up the points by where they are on the graph? The only thing that I've gotten to display anything produces a straight line and I don't understand why. I'm very new to python so this has been giving me a lot of trouble.
This is the code that I have so far:
This plots the two arrays into a hammer projection:
from astropy import units as u
import astropy.coordinates as coord
glat = coord.Angle(pos_data['GLAT']*u.degree)
glon = coord.Angle(pos_data['GLON']*u.degree)
glon= glon.wrap_at(180*u.degree)
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(10,12))
ax = fig.add_subplot(211, projection="hammer")
ax.scatter(glon.radian, glat.radian)
ax.grid(True)
This is my attempt at convolving the data:
from astropy.convolution import convolve, Box2DKernel
data = [glon, glat]
kernel = Box2DKernel(10)
smoothed = convolve(data, kernel)
ax = fig.add_subplot(212, projection="hammer")
ax.scatter(smoothed[0]*u.radian, smoothed[1]*u.radian)
ax.grid(True)
Like I said, it's just one of many attempts that ended up giving something instead of an error, but I'm not sure that I'm using the function correctly at all. I'm not sure (or I don't think) that I can create "data" the way that I did, but any other combination of arrays or convolving each as a 1D array didn't work either.
Any ideas would be really helpful, thanks.
It seems like you're looking for Kernel Density Estimation, which is a way of turning individual measurements of spatial point patterns into a continuous distribution. I happen to prefer the scikit-learn implementation. You can then use the basemap package to do your plotting. The following code should be adaptable to your situation, where ra and dec are arrays of your stars' Right Ascension and Declination (you'll have to be careful about radians vs degrees here):
from sklearn.neighbors import KernelDensity
from sklearn.grid_search import GridSearchCV
data = np.column_stack((ra, dec))
# use a tophat/boxcar kernel and a haversine (spherical) metric
p = {'bandwidth': np.logspace(-1, 1, 20), 'kernel'='tophat',
'metric'='haversine'}
grid = GridSearchCV(KernelDensity(), params)
grid.fit(data)
Then you should be able to define a meshgrid over which to evaluate your KDE, and then plot it using imshow/pcolormesh/something else over a Hammer projection (see here or here)

Categories

Resources