def test_sort_vertices_of_regions_flattened(self): expected = sorted([[0, 6, 5, 2, 3], [2, 3, 10, 11, 8, 7], [0, 6, 4, 1], [4, 8, 7, 5, 6], [9, 11, 10], [2, 7, 5], [1, 4, 8, 11, 9], [0, 3, 10, 9, 1]]) expected = list(itertools.chain(*sorted(expected))) sv = SphericalVoronoi(self.points) sv.sort_vertices_of_regions() actual = list(itertools.chain(*sorted(sv.regions))) assert_array_equal(actual, expected)
class SphericalVorSort(Benchmark): params = [10, 100, 1000, 5000, 10000] param_names = ['num_points'] def setup(self, num_points): self.points = generate_spherical_points(num_points) self.sv = SphericalVoronoi(self.points, radius=1, center=np.zeros(3)) def time_spherical_polygon_vertex_sorting(self, num_points): """Time the vertex sorting operation in the Spherical Voronoi code. """ self.sv.sort_vertices_of_regions()
def test_sort_vertices_of_regions(self): sv = SphericalVoronoi(self.points) unsorted_regions = sv.regions sv.sort_vertices_of_regions() assert_array_equal(sorted(sv.regions), sorted(unsorted_regions))
def getVoronoiCollection(data, lat_name, lon_name, bmap = None, v_name = None, full_sphere = False, max_v=.3, min_v=-0.3, cmap = cm.get_cmap('jet'), test_point = None, proj1=None, proj2=None, **kwargs): ''' Perform a Spherical Voronoi Tessellation on the input data. In the case where the data is restricted to one part of the globe, a polygon will not be returned for all objects, as matplotlib polygons won't be able to stretch over half the globe. @param data: Input pandas data frame @param lat_name: Name of latitude column @param lon_name: Name of longitude column @param bmap: Basemap instance used to convert from lat, lon coordinates to projection coordinates @param v_name: Name of value column. Use this to color each cell according to a value. @param full_sphere: Set to true if the data spans the entire globe. If false, a fictional point is created during tessellation and removed later to work around issues when polygons are suppose to span the over half the globe. @param max_v: Specify a maximum value to use when assigning values to the tessellation @param min_v: Specify a minimum value to use when assigning values to the tessellation @param cmap: Matplotlib color map to use @param test_point: Tuple containing the latitude and longitude of the ficitonal point to used to remove polygons that wrap around the earth. If none, a point is automatically chosen @param proj1: PyProj projection of input coordinates @param proj2: PyProj projection of sphere @return Matplotlib patch collection of tessellation, scipy.spatial.SphericalVoronoi object, integer index of objects in patch collection. ''' data = data.copy() if full_sphere == False: if test_point == None: test_lat = -1*np.mean(data[lat_name]) test_lon = np.mean(data[lon_name]) + 180 else: test_lat = test_point[0] test_lon = test_point[1] full_data = data full_data = pd.concat([full_data, pd.DataFrame({lat_name: test_lat, lon_name: test_lon}, index=[full_data.index[0]])]) full_data.set_index(np.arange(len(full_data)), inplace=True) else: full_data = data # print(full_data.tail()) if proj1 != None and proj2 != None: results = pyproj.transform(proj1, proj2, full_data[lon_name].as_matrix(), full_data[lat_name].as_matrix()) full_data[lon_name] = results[0] full_data[lat_name] = results[1] xyz = pd.DataFrame(sphericalToXYZ(full_data[lat_name], full_data[lon_name]),columns=['x','y','z'],index=full_data.index) if v_name != None: full_data = pd.concat([full_data.loc[:,[lat_name,lon_name, v_name]],xyz],axis=1) else: full_data = pd.concat([full_data.loc[:,[lat_name,lon_name, v_name]],xyz],axis=1) unique_index = np.unique(full_data.loc[:,lat_name] + 1j*full_data.loc[:,lon_name],return_index=True)[1] full_data = full_data.iloc[np.sort(unique_index)] voronoi = SphericalVoronoi(full_data.loc[:,['x','y','z']].as_matrix(), **kwargs) voronoi.sort_vertices_of_regions() #latlon_verts = xyzToSpherical(voronoi.vertices[:,0],voronoi.vertices[:,1], voronoi.vertices[:,2]) #if proj1 != None and proj2 != None: # results = pyproj.transform(proj2, proj1, latlon_verts[:,1], latlon_verts[:,0]) # latlon_verts[:, 1] = results[0] # latlon_verts[:, 0] = results[1] #matches = list(map(lambda x: find_match(x, voronoi.regions), range(len(voronoi.regions)))) #patch_list = [] #patch_index = [] #for i, (region,match,(station,row)) in enumerate(zip(voronoi.regions,matches, full_data.iterrows())): # if full_sphere or (len(matches)-1) not in match: # Keep an index of regions in patchcollection # patch_index.append(i) # if bmap != None: # xy = np.array(bmap(latlon_verts[region,1],latlon_verts[region,0])).T # else: # xy = np.array([latlon_verts[region,1],latlon_verts[region,0]]).T # if v_name != None: # value = row[v_name] # scaled_value = (value - min_v) / (max_v - min_v) # if scaled_value > 1: # scaled_value = 1.0 # elif scaled_value < 0: # scaled_value = 0.0 # poly = Polygon(xy, fill=True,facecolor = cmap(scaled_value),edgecolor=cmap(scaled_value)) # else: # poly = Polygon(xy, fill=False) # # patch_list.append(poly) return voronoi
def test_sort_vertices_of_regions(self): sv = SphericalVoronoi(self.points) unsorted_regions = sv.regions sv.sort_vertices_of_regions() assert_equal(sorted(sv.regions), sorted(unsorted_regions))
def test_old_radius_api_warning(self): with assert_warns(DeprecationWarning): SphericalVoronoi(self.points, None)
def test_old_radius_api(self): sv_unit = SphericalVoronoi(self.points, radius=1) with suppress_warnings() as sup: sup.filter(DeprecationWarning, "`radius` is `None`") sv = SphericalVoronoi(self.points, None) assert_array_almost_equal(sv_unit.vertices, sv.vertices)
def test_equal_area_regions(self, poly): points = _generate_polyhedron(poly) sv = SphericalVoronoi(points) areas = sv.calculate_areas() assert_almost_equal(areas, 4 * np.pi / len(points))
def setup(self, num_points): self.points = generate_spherical_points(num_points) self.sv = SphericalVoronoi(self.points, radius=1, center=np.zeros(3))
def time_spherical_voronoi_calculation(self, num_points): """Perform spherical Voronoi calculation, but not the sorting of vertices in the Voronoi polygons. """ SphericalVoronoi(self.points, radius=1, center=np.zeros(3))
def voronoi_plot(points_in, losses, path, cmap): from matplotlib import colors from mpl_toolkits.mplot3d.art3d import Poly3DCollection import matplotlib.pyplot as plt from scipy.spatial import SphericalVoronoi from mpl_toolkits.mplot3d import proj3d # get input points in correct format cart = [point['cartesian'] for point in points_in] points = np.array(cart) center = np.array([0, 0, 0]) radius = 1 # calculate spherical Voronoi diagram sv = SphericalVoronoi(points, radius, center) # sort vertices (optional, helpful for plotting) sv.sort_vertices_of_regions() # generate plot fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # plot the unit sphere for reference (optional) u = np.linspace(0, 2 * np.pi, 100) v = np.linspace(0, np.pi, 100) x = np.outer(np.cos(u), np.sin(v)) y = np.outer(np.sin(u), np.sin(v)) z = np.outer(np.ones(np.size(u)), np.cos(v)) ax.plot_surface(x, y, z, color='y', alpha=0.1) ax.grid(False) ax.set_xticks([]) ax.set_yticks([]) ax.set_zticks([]) plt.axis('off') # normalize and map losses to colormap mi = min(losses) ma = max(losses) norm = matplotlib.colors.Normalize(vmin=mi, vmax=ma, clip=True) mapper = cm.ScalarMappable(norm=norm, cmap=cmap) loss_color = [mapper.to_rgba(l) for l in losses] # indicate Voronoi regions (as Euclidean polygons) for i in range(len(sv.regions)): region = sv.regions[i] random_color = colors.rgb2hex(loss_color[i]) polygon = Poly3DCollection([sv.vertices[region]], alpha=1.0) polygon.set_color(random_color) ax.add_collection3d(polygon) fig.savefig(os.path.join(path, "landscape.png"), dpi=fig.dpi) # determine neighbours neighbours = [] for i in range(len(sv.regions)): vertices = sv.regions[i] neighbours_for_i = [] for j in range(len(sv.regions)): neigh = False shared = 0 vert2 = sv.regions[j] for vert in vertices: if vert in vert2: shared += 1 if shared >= 2: neigh = True break if neigh and i != j: neighbours_for_i.append(j) neighbours.append(neighbours_for_i) regions, steepest_neighbour = steepest_region(neighbours, losses) #plot_boundaries(regions, neighbours, sv, ax) temp = [] for i in range(len(neighbours)): point1 = sv.points[i] point2 = points[steepest_neighbour[i]] temp.append(point2 - point1) x1, y1, z1 = zip(*sv.points) dx, dy, dz = zip(*temp) col = [[0, 0, 0, 0.5] for i in range(len(neighbours))] #ax.quiver(x1, y1, z1, dx, dy, dz, length=0.02, normalize=True, colors=col) # uncomment this get directional arrows as well num_sets = len(regions) colors = cm.rainbow(np.linspace(0, 1, num_sets)) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.plot_surface(x, y, z, color='y', alpha=0.1) ax.grid(False) ax.set_xticks([]) ax.set_yticks([]) ax.set_zticks([]) plt.axis('off') # indicate Voronoi regions (as Euclidean polygons) i = 0 centers = [] for reg in regions: set = regions[reg]['region_set'] centers.append(reg) for index in set: region = sv.regions[index] polygon = Poly3DCollection([sv.vertices[region]], alpha=1.0) polygon.set_color(colors[i]) ax.add_collection3d(polygon) i += 1 x_p, y_p, z_p = zip(*sv.points) x_p = [x_p[i] for i in centers] y_p = [y_p[i] for i in centers] z_p = [z_p[i] for i in centers] ax.scatter(x_p, y_p, z_p, c='k', s=1) fig.savefig(os.path.join(path, "regions.png"), dpi=fig.dpi) plt.show()
def getVoronoiCollection(data, lat_name, lon_name, voronoi_plot=False, bmap=None, v_name=None, full_sphere=False, max_v=.3, min_v=-0.3, cmap=cm.get_cmap('jet'), test_point=None, proj1=None, proj2=None, **kwargs): ''' Perform a Spherical Voronoi Tessellation on the input data. In the case where the data is restricted to one part of the globe, a polygon will not be returned for all objects, as matplotlib polygons won't be able to stretch over half the globe. @param data: Input pandas data frame @param lat_name: Name of latitude column @param lon_name: Name of longitude column @param bmap: Basemap instance used to convert from lat, lon coordinates to projection coordinates @param v_name: Name of value column. Use this to color each cell according to a value. @param full_sphere: Set to true if the data spans the entire globe. If false, a fictional point is created during tessellation and removed later to work around issues when polygons are suppose to span the over half the globe. @param max_v: Specify a maximum value to use when assigning values to the tessellation @param min_v: Specify a minimum value to use when assigning values to the tessellation @param cmap: Matplotlib color map to use @param test_point: Tuple containing the latitude and longitude of the ficitonal point to used to remove polygons that wrap around the earth. If none, a point is automatically chosen @param proj1: PyProj projection of input coordinates @param proj2: PyProj projection of sphere @return Matplotlib patch collection of tessellation, scipy.spatial.SphericalVoronoi object, integer index of objects in patch collection. ''' data = data.copy() if full_sphere == False: if test_point == None: test_lat = -1 * np.mean(data[lat_name]) test_lon = np.mean(data[lon_name]) + 180 else: test_lat = test_point[0] test_lon = test_point[1] full_data = data full_data = pd.concat([ full_data, pd.DataFrame({ lat_name: test_lat, lon_name: test_lon }, index=[full_data.index[0]]) ]) full_data.set_index(np.arange(len(full_data)), inplace=True) else: full_data = data # print(full_data.tail()) if proj1 != None and proj2 != None: results = pyproj.transform(proj1, proj2, full_data[lon_name].as_matrix(), full_data[lat_name].as_matrix()) full_data[lon_name] = results[0] full_data[lat_name] = results[1] xyz = pd.DataFrame(sphericalToXYZ(full_data[lat_name], full_data[lon_name]), columns=['x', 'y', 'z'], index=full_data.index) if v_name != None: full_data = pd.concat( [full_data.loc[:, [lat_name, lon_name, v_name]], xyz], axis=1) else: full_data = pd.concat( [full_data.loc[:, [lat_name, lon_name, v_name]], xyz], axis=1) unique_index = np.unique(full_data.loc[:, lat_name] + 1j * full_data.loc[:, lon_name], return_index=True)[1] full_data = full_data.iloc[np.sort(unique_index)] voronoi = SphericalVoronoi(full_data.loc[:, ['x', 'y', 'z']].as_matrix(), **kwargs) voronoi.sort_vertices_of_regions() # BELOW IS ONLY FOR PLOTTING if voronoi_plot: latlon_verts = xyzToSpherical(voronoi.vertices[:, 0], voronoi.vertices[:, 1], voronoi.vertices[:, 2]) if proj1 != None and proj2 != None: results = pyproj.transform(proj2, proj1, latlon_verts[:, 1], latlon_verts[:, 0]) latlon_verts[:, 1] = results[0] latlon_verts[:, 0] = results[1] matches = list( map(lambda x: find_match(x, voronoi.regions), range(len(voronoi.regions)))) patch_list = [] patch_index = [] for i, (region, match, (station, row)) in enumerate( zip(voronoi.regions, matches, full_data.iterrows())): if full_sphere or (len(matches) - 1) not in match: # Keep an index of regions in patchcollection patch_index.append(i) if bmap != None: xy = np.array( bmap(latlon_verts[region, 1], latlon_verts[region, 0])).T else: xy = np.array( [latlon_verts[region, 1], latlon_verts[region, 0]]).T if v_name != None: value = row[v_name] scaled_value = (value - min_v) / (max_v - min_v) if scaled_value > 1: scaled_value = 1.0 elif scaled_value < 0: scaled_value = 0.0 poly = Polygon(xy, fill=True, facecolor=cmap(scaled_value), edgecolor=cmap(scaled_value)) else: poly = Polygon(xy, fill=False) patch_list.append(poly) return matplotlib.collections.PatchCollection( patch_list, match_original=True), voronoi, patch_index else: return voronoi
def test_old_center_api_warning(self): with assert_warns(DeprecationWarning): sv = SphericalVoronoi(self.points, None, None)
def generate(self, N, iterate=5): points = self._samplePoints(N) relaxedPoints = self._relaxPoints(points, iterate) sv = SphericalVoronoi(relaxedPoints) sv.sort_vertices_of_regions() return sv
def test_vertices_regions_scaling_invariance(self): sv_unit = SphericalVoronoi(self.points) sv_scaled = SphericalVoronoi(self.points * 2, 2) assert_equal(sv_unit.regions, sv_scaled.regions) assert_array_almost_equal(sv_unit.vertices * 2, sv_scaled.vertices)
def setup(self, num_points): self.points = generate_spherical_points(num_points) self.sv = SphericalVoronoi(self.points, radius=1, center=np.zeros(3))
from matplotlib import colors from mpl_toolkits.mplot3d.art3d import Poly3DCollection import matplotlib.pyplot as plt from scipy.spatial import SphericalVoronoi from mpl_toolkits.mplot3d import proj3d import numpy as np a = read_text_row("params_027.txt")[:100] points = angles_to_normals(a) l = len(points) points = np.array(points) center = np.array([0, 0, 0]) radius = 1 # calculate spherical Voronoi diagram sv = SphericalVoronoi(points, radius, center) # sort vertices (optional, helpful for plotting) sv.sort_vertices_of_regions() # generate plot fig = plt.figure() ax = fig.add_subplot(111, projection='3d') # plot the unit sphere for reference (optional) u = np.linspace(0, 2 * np.pi, 100) v = np.linspace(0, np.pi, 100) x = np.outer(np.cos(u), np.sin(v)) y = np.outer(np.sin(u), np.sin(v)) z = np.outer(np.ones(np.size(u)), np.cos(v)) ax.plot_surface(x, y, z, color='y', alpha=0.1) # plot generator points #ax.scatter(points[:, 0], points[:, 1], points[:, 2], c='b') # plot Voronoi vertices