def test_voronoi_geopandas_with_plot(): world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres')) cities = gpd.read_file(gpd.datasets.get_path('naturalearth_cities')) # focus on South America, convert to World Mercator (unit: meters) south_am = world[world.continent == 'South America'].to_crs(epsg=3395) cities = cities.to_crs( south_am.crs) # convert city coordinates to same CRS! # create the bounding shape as union of all South American countries' shapes south_am_shape = unary_union(south_am.geometry) south_am_cities = cities[cities.geometry.within( south_am_shape)] # reduce to cities in South America # convert the pandas Series of Point objects to NumPy array of coordinates coords = points_to_coords(south_am_cities.geometry) # calculate the regions region_polys, region_pts = voronoi_regions_from_coords(coords, south_am_shape, per_geom=False) # full checks for voronoi_regions_from_coords() are done in test_voronoi_regions_from_coords_italy() assert isinstance(region_polys, dict) assert isinstance(region_pts, dict) assert len(region_polys) == len(region_pts) == len(coords) # generate plot fig, ax = subplot_for_map(show_spines=True) plot_voronoi_polys_with_points_in_area(ax, south_am_shape, region_polys, coords, region_pts) return fig
def test_issue_7b(): centroids = np.array([[496712, 232672], [497987, 235942], [496425, 230252], [497482, 234933], [499331, 238351], [496081, 231033], [497090, 233846], [496755, 231645], [498604, 237018]]) polygon = Polygon([[495555, 230875], [496938, 235438], [499405, 239403], [499676, 239474], [499733, 237877], [498863, 237792], [499120, 237335], [498321, 235010], [497295, 233185], [497237, 231359], [496696, 229620], [495982, 230047], [496154, 230347], [496154, 230347], [495555, 230875]]) poly_shapes, pts, poly_to_pt_assignments = voronoi_regions_from_coords( centroids, polygon) assert isinstance(poly_shapes, list) assert 0 < len(poly_shapes) <= len(centroids) assert all([isinstance(p, (Polygon, MultiPolygon)) for p in poly_shapes]) assert np.array_equal(points_to_coords(pts), centroids) assert isinstance(poly_to_pt_assignments, list) assert len(poly_to_pt_assignments) == len(poly_shapes) assert all([isinstance(assign, list) for assign in poly_to_pt_assignments]) assert all([len(assign) == 1 for assign in poly_to_pt_assignments ]) # in this case there is a 1:1 correspondance fig, ax = subplot_for_map() plot_voronoi_polys_with_points_in_area(ax, polygon, poly_shapes, centroids, poly_to_pt_assignments) return fig
def createVoronoi(boundary, cities): """process the boundary (polygon border) and points to create the voronoi diagram. Params: boundary (geoDataFrame) : the polygon representing the container of the diagram cities (geoDataFrame) : the points that represent the "seeds" for the diagram Returns: All the datastructures needed to plot the voronoi diagram. Most important for us however, is the "regionPolys" needed for us to determine which ufos are each of the polygons. cityCoords - the seeds converted to proper coordinate system for the diagram boundaryShape - the boundary simplified or converted to a single outer ring polygon regionPolys - a dict of the internal polygons created around each seed regionPoints - a dict of the points used in the creation of the polygon """ # pre-process data so it works with voronoi boundaryProj = boundary.to_crs(epsg=3395) citiesProj = cities.to_crs(boundaryProj.crs) boundaryShape = unary_union(boundaryProj.geometry) cityCoords = points_to_coords(citiesProj.geometry) # create the polygons and such regionPolys, regionPoints = voronoi_regions_from_coords(cityCoords, boundaryShape) # return all the things created so we can use / plot return cityCoords, boundaryShape, regionPolys, regionPoints
def update_inner(inner_pos, area_shape): pts = [p for p in coords_to_points(inner_pos) if p.within(area_shape)] # converts to shapely Point coords = points_to_coords( pts) # convert back to simple NumPy coordinate array return coords
def test_voronoi_sweden_duplicate_points_with_plot(): area_shape = _get_country_shape('Sweden') coords = _rand_coords_in_shape(area_shape, 20) # duplicate a few points rand_dupl_ind = np.random.randint(len(coords), size=10) coords = np.concatenate((coords, coords[rand_dupl_ind])) poly_shapes, pts, poly_to_pt_assignments = voronoi_regions_from_coords( coords, area_shape, accept_n_coord_duplicates=10) assert isinstance(poly_shapes, list) assert 0 < len(poly_shapes) <= 20 assert all([isinstance(p, (Polygon, MultiPolygon)) for p in poly_shapes]) assert np.array_equal(points_to_coords(pts), coords) assert isinstance(poly_to_pt_assignments, list) assert len(poly_to_pt_assignments) == len(poly_shapes) assert all([isinstance(assign, list) for assign in poly_to_pt_assignments]) assert all([0 < len(assign) <= 10 for assign in poly_to_pt_assignments ]) # in this case there is not # everywhere a 1:1 correspondance pts_to_poly_assignments = np.array( get_points_to_poly_assignments(poly_to_pt_assignments)) # make point labels: counts of duplicates per points count_per_pt = [ sum(pts_to_poly_assignments == i_poly) for i_poly in pts_to_poly_assignments ] pt_labels = list(map(str, count_per_pt)) # highlight voronoi regions with point duplicates count_per_poly = np.array(list(map(len, poly_to_pt_assignments))) vor_colors = np.repeat('blue', len(poly_shapes)) # default color vor_colors[count_per_poly > 1] = 'red' # hightlight color fig, ax = subplot_for_map() plot_voronoi_polys_with_points_in_area( ax, area_shape, poly_shapes, coords, plot_voronoi_opts={'alpha': 0.2}, plot_points_opts={'alpha': 0.4}, voronoi_color=list(vor_colors), point_labels=pt_labels, points_markersize=np.array(count_per_pt) * 10) return fig
def _rand_coords_in_shape(area_shape, n_points): # generate some random points within the bounds minx, miny, maxx, maxy = area_shape.bounds randx = np.random.uniform(minx, maxx, n_points) randy = np.random.uniform(miny, maxy, n_points) coords = np.vstack((randx, randy)).T # use only the points inside the geographic area pts = [p for p in coords_to_points(coords) if p.within(area_shape)] # converts to shapely Point return points_to_coords(pts)
def test_voronoi_geopandas_with_plot(): world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres')) cities = gpd.read_file(gpd.datasets.get_path('naturalearth_cities')) # focus on South America, convert to World Mercator (unit: meters) south_am = world[world.continent == 'South America'].to_crs(epsg=3395) cities = cities.to_crs( south_am.crs) # convert city coordinates to same CRS! # create the bounding shape as union of all South American countries' shapes south_am_shape = cascaded_union(south_am.geometry) south_am_cities = cities[cities.geometry.within( south_am_shape)] # reduce to cities in South America # convert the pandas Series of Point objects to NumPy array of coordinates coords = points_to_coords(south_am_cities.geometry) # calculate the regions poly_shapes, pts, poly_to_pt_assignments = voronoi_regions_from_coords( coords, south_am_shape) assert isinstance(poly_shapes, list) assert 0 < len(poly_shapes) <= len(coords) assert all([isinstance(p, (Polygon, MultiPolygon)) for p in poly_shapes]) assert np.array_equal(points_to_coords(pts), coords) assert isinstance(poly_to_pt_assignments, list) assert len(poly_to_pt_assignments) == len(poly_shapes) assert all([isinstance(assign, list) for assign in poly_to_pt_assignments]) assert all([len(assign) == 1 for assign in poly_to_pt_assignments ]) # in this case there is a 1:1 correspondance fig, ax = subplot_for_map() plot_voronoi_polys_with_points_in_area(ax, south_am_shape, poly_shapes, pts, poly_to_pt_assignments) return fig
def test_issue_7a(): centroids = np.array([[537300, 213400], [538700, 213700], [536100, 213400]]) polygon = Polygon([[540000, 214100], [535500, 213700], [535500, 213000], [539000, 213200]]) poly_shapes, pts, poly_to_pt_assignments = voronoi_regions_from_coords( centroids, polygon) assert isinstance(poly_shapes, list) assert 0 < len(poly_shapes) <= len(centroids) assert all([isinstance(p, (Polygon, MultiPolygon)) for p in poly_shapes]) assert np.array_equal(points_to_coords(pts), centroids) assert isinstance(poly_to_pt_assignments, list) assert len(poly_to_pt_assignments) == len(poly_shapes) assert all([isinstance(assign, list) for assign in poly_to_pt_assignments]) assert all([len(assign) == 1 for assign in poly_to_pt_assignments ]) # in this case there is a 1:1 correspondance
def create_voronoi_polygons(self): """ creates Voronoi polygons with `self.antennas_data` as centers, bounded by `self.contour` :return: GeoPandas DF with VCs """ if self.antennas_data.crs == self.contour.crs: coords = points_to_coords(self.antennas_data.geometry) poly_shapes, pts = voronoi_regions_from_coords( coords, self.contour.geometry[0]) voronoi_polygons = gpd.GeoDataFrame({'geometry': poly_shapes}, crs=SWEREF_EPSG) return voronoi_polygons else: logger.error('Objects have different CRSs: %s and %s ' % (self.antennas_data.crs, self.contour.crs))
def test_voronoi_spain_area_with_plot(): area_shape = _get_country_shape('Spain') coords = _rand_coords_in_shape(area_shape, 20) poly_shapes, pts, poly_to_pt_assignments = voronoi_regions_from_coords( coords, area_shape) assert isinstance(poly_shapes, list) assert 0 < len(poly_shapes) <= 20 assert all([isinstance(p, (Polygon, MultiPolygon)) for p in poly_shapes]) assert np.array_equal(points_to_coords(pts), coords) assert isinstance(poly_to_pt_assignments, list) assert len(poly_to_pt_assignments) == len(poly_shapes) assert all([isinstance(assign, list) for assign in poly_to_pt_assignments]) assert all([len(assign) == 1 for assign in poly_to_pt_assignments ]) # in this case there is a 1:1 correspondance poly_areas = calculate_polygon_areas(poly_shapes, m2_to_km2=True) # converts m² to km² assert isinstance(poly_areas, np.ndarray) assert np.issubdtype(poly_areas.dtype, np.float_) assert len(poly_areas) == len(poly_shapes) assert np.all(poly_areas > 0) fig, ax = subplot_for_map(show_x_axis=True, show_y_axis=True) voronoi_labels = ['%d km²' % round(a) for a in poly_areas] plot_voronoi_polys_with_points_in_area(ax, area_shape, poly_shapes, coords, poly_to_pt_assignments, voronoi_labels=voronoi_labels, voronoi_label_fontsize=7, voronoi_label_color='gray') return fig
def test_voronoi_italy_with_plot(): area_shape = _get_country_shape('Italy') coords = _rand_coords_in_shape(area_shape, 100) poly_shapes, pts, poly_to_pt_assignments = voronoi_regions_from_coords( coords, area_shape) assert isinstance(poly_shapes, list) assert 0 < len(poly_shapes) <= 100 assert all([isinstance(p, (Polygon, MultiPolygon)) for p in poly_shapes]) assert np.array_equal(points_to_coords(pts), coords) assert isinstance(poly_to_pt_assignments, list) assert len(poly_to_pt_assignments) == len(poly_shapes) assert all([isinstance(assign, list) for assign in poly_to_pt_assignments]) assert all([len(assign) == 1 for assign in poly_to_pt_assignments ]) # in this case there is a 1:1 correspondance fig, ax = subplot_for_map() plot_voronoi_polys_with_points_in_area(ax, area_shape, poly_shapes, coords, poly_to_pt_assignments) return fig
def computeCrossProduct(self, reference_old_entries, second_old_entries): # 1. Reference distribution is regions, second dist is regions # - uniform distribute overlap of regions # 2. Reference distribution is regions, second dist is points # - map points to regions and perform as usual # 3. Reference distribution is points, second dist is regions # - create regions from reference dist. points with Voronoi diagram # 4. Reference distribution is points, second dist is points # - " " if 'POLYGON' in reference_old_entries[0]: if 'POLYGON' in second_old_entries[0]: # For 1. compute cross product for new regions new_entries = SpatialHelper.computeNewRegions( reference_old_entries, second_old_entries) #print('inside spatial handler') #print(len(reference_old_entries)) #print(len(second_old_entries)) #print(len(new_entries)) #print('leaving spatial handler') elif 'POINT' in second_old_entries[0] or \ type(second_old_entries[0]) is tuple: # For 2., don't need to compute cross product # Just use Regions of reference distribution new_entries = reference_old_entries elif 'POINT' in reference_old_entries[0] or \ type(reference_old_entries[0]) is tuple: # For 3. compute Voronoi ref_points_obj = SpatialHelper.getGeoObjectsFromString( list(set(reference_old_entries))) sec_regions_obj = SpatialHelper.getGeoObjectsFromString( second_old_entries) sec_regions_obj_union = unary_union(sec_regions_obj) for point in ref_points_obj: #Remove points from reference that are outside sec_region_union if not point.within(sec_regions_obj_union): raise ValueError( "Points from reference distribution lie outside union of regions from secondary distribution." ) #ref_points_obj.remove(point) #train_df = train_df[train_df.Region != (point.x,point.y)] coords = points_to_coords(ref_points_obj) ref_vor_regions_obj, pts, poly_to_pt_assignments = voronoi_regions_from_coords( coords, sec_regions_obj_union) #Convert back to string ref_vor_regions = SpatialHelper.convertGeoObjectsToString( ref_vor_regions_obj) #print(ref_vor_regions[0]) new_entries = SpatialHelper.computeNewRegions( ref_vor_regions, second_old_entries) # For 3. and 4., return error for now #raise ValueError("Invalid input for the {} variable. Spatial\ # mismatch variables of the reference distribution\ # must be 'Multipolygon' or 'Polygon.'" # .format(str(self.node))) #print('inside spatial handler') #print(len(reference_old_entries)) #print(len(second_old_entries)) #print(len(new_entries)) #print('leaving spatial handler') else: raise ValueError("Invalid input for {} variable. Spatial mismatch\ variables must be a 'Multipolygon', 'Polygon'\ or 'Point', or be a tuple of (X,Y) coordinates.". format(str(self.node))) return reference_old_entries, second_old_entries, new_entries
def update(self, outer_pos, inner_pos, UPDATE, EPS=0.1): global t t = time.time() - start outputs = [] global FLAG if FLAG: fig, ax = subplot_for_map() global ax, fig FLAG = False def reshape_coords(coords): new_coords = [] for p in poly_shapes: for n in coords: m = Point(n) if m.within(p): new_coords.append(n) return new_coords def reshape_centroids(centroids): new_centroids = [] for p in poly_shapes: for n in centroids: m = Point(n) if m.within(p): new_cent roids.append(n) return new_centroids def match_pair(poly_shapes, coords, new_centroids): sorted_coords = [] points = coords_to_points(coords) for i, p in enumerate(points): c = coords[i] #print("c: ", c[0],c[1]) for j, poly in enumerate(poly_shapes): if p.within(poly): pair = new_centroids[j] sorted_coords.append(pair) return sorted_coords N = 4 #len(inner_pos) area_shape = Polygon(outer_pos) #update_outer(outer_pos) # generate some random points within the bounds minx, miny, maxx, maxy = area_shape.bounds pts = [p for p in coords_to_points(inner_pos) if p.within(area_shape)] # converts to shapely Point while len(pts) < N: #isinstance(compensated, int): inner_pos = points_to_coords(pts) print('%d of %d drone"s pos is available' % (len(pts), N)) #print("compensated!!", compensated, type(compensated)) randx = np.random.uniform(minx, maxx, N - len(pts)) randy = np.random.uniform(miny, maxy, N - len(pts)) compensated = np.vstack((randx, randy)).T inner_pos = np.append(inner_pos, compensated, axis=0) #print(inner_pos) #inner_pos = inner_pos[sorted(np.random.choice(inner_pos.shape[0], N, replace=False)), :] pts = [ p for p in coords_to_points(inner_pos) if p.within(area_shape) ] # converts to shapely Point ax.clear() # comment out if you want to plot trajectory coords = points_to_coords( pts) # convert back to simple NumPy coordinate array poly_shapes, pts, poly_to_pt_assignments = voronoi_regions_from_coords( coords, area_shape, accept_n_coord_duplicates=0) poly_centroids = np.array([p.centroid.coords[0] for p in poly_shapes]) #new_centroids = reshape_centroids(poly_centroids) # plotting EPS = EPS err = 99999 #old_coords = coords new_centroids = match_pair(poly_shapes, coords, poly_centroids) for i in range(len(coords)): xo = coords[i][0] yo = coords[i][1] #old_coords[i][0] = xo #old_coords[i][1] = yo xc = new_centroids[i][0] yc = new_centroids[i][1] #err = np.sqrt((xo-xc)**2 + (yo-yc)**2) data = [xc, yc] outputs.append(data) #(np.array((xc, yc)).astype(np.float64)) #if err > EPS: # # print("UPDARED!!") # coords[i][0] = xc#xo + 0.2*(xc-xo) # coords[i][1] = yc#yo + 0.2*(yc-yo) # draw centroid that each drone follow for i, centroid in enumerate(new_centroids): c1 = centroid ax.plot(c1[0], c1[1], '*', label=str(i)) for coord in coords: c = coord ax.plot(c[0], c[1], 'o', alpha=0.5) fig = plot_voronoi_polys_with_points_in_area(ax, area_shape, poly_shapes, coords, poly_to_pt_assignments) plt.title(str(t) + "[s]") plt.pause(0.00001) return outputs
# focus on South America, convert to World Mercator (unit: meters) south_am = world[world.continent == 'South America'].to_crs(epsg=3395) cities = cities.to_crs(south_am.crs) # convert city coordinates to same CRS! # create the bounding shape as union of all South American countries' shapes south_am_shape = cascaded_union(south_am.geometry) south_am_cities = cities[cities.geometry.within(south_am_shape)] # reduce to cities in South America # # calculate the Voronoi regions, cut them with the geographic area shape and assign the points to them # # convert the pandas Series of Point objects to NumPy array of coordinates coords = points_to_coords(south_am_cities.geometry) # calculate the regions poly_shapes, pts, poly_to_pt_assignments = voronoi_regions_from_coords(coords, south_am_shape) # # Plotting # fig, ax = subplot_for_map() plot_voronoi_polys_with_points_in_area(ax, south_am_shape, poly_shapes, pts, poly_to_pt_assignments) ax.set_title('Cities data for South America from GeoPandas\nand Voronoi regions around them')
AoI = FILE_PATHS["AoI_file"] boundary = gpd.read_file(AoI) # need to change the projection from 32633 to 4326 gdf = gdf.set_crs(epsg=32633, inplace = True) gdf_proj =gdf.to_crs(epsg=4326) # set the projection of the AoI shapefile boundary = boundary.set_crs(epsg=4326, inplace = True) boundary_shape = cascaded_union(boundary.geometry) coords = points_to_coords(gdf_proj.geometry) # Calculate Voronoi Regions poly_shapes, pts, poly_to_pt_assignments = voronoi_regions_from_coords(coords, boundary_shape) # plot the voronoi regions in a map fig, ax = subplot_for_map() plot_voronoi_polys_with_points_in_area(ax, boundary_shape, poly_shapes, pts, poly_to_pt_assignments) ax.set_title('Voronoi regions') plt.tight_layout() plt.savefig(shpdir + 'Voronoi_polygons_validation_attributes3.png') # save the polygon objects in a shapefile
def test_coords_to_points_and_points_to_coords(coords): # test for bijectivity of points_to_coords and coords_to_points assert np.array_equal(points_to_coords(coords_to_points(coords)), coords)
def Within(pts, shape): pts = coords_to_points(pts) pts = [p for p in pts if p.within(shape)] return [(x, y) for x, y in points_to_coords(pts)]
def test_coords_to_points_and_points_to_coords(coords): assert np.array_equal(points_to_coords(coords_to_points(coords)), coords)
# generate some random points within the bounds minx, miny, maxx, maxy = area_shape.bounds randx = np.random.uniform(minx, maxx, N_POINTS) randy = np.random.uniform(miny, maxy, N_POINTS) coords = np.vstack((randx, randy)).T # use only the points inside the geographic area pts = [p for p in coords_to_points(coords) if p.within(area_shape)] # converts to shapely Point n_pts = len(pts) print( 'will use %d of %d randomly generated points that are inside geographic area' % (n_pts, N_POINTS)) coords = points_to_coords(pts) # convert back to simple NumPy coordinate array del pts #%% # # calculate the Voronoi regions, cut them with the geographic area shape and assign the points to them # region_polys, region_pts = voronoi_regions_from_coords(coords, area_shape) # calculate area in km², too poly_areas = calculate_polygon_areas(region_polys, m2_to_km2=True) # converts m² to km²
def updated_geography_plot( self, CRS=4326, attribute="EUE", line_attribute="utilization", plot_type="fills" ): if attribute != "LOLE" and attribute != "EUE": raise ValueError("can only plot LOLE or EUE") boundary = self.iso_map[self.iso_map["NAME"] == self.iso_map.at[0, "NAME"]] boundary = boundary.to_crs(epsg=CRS) gdf_proj = self.miso_seam_zone_gdf.to_crs(boundary.crs) # re-assignment due to different zone naming conventions gdf_proj.at[ gdf_proj[gdf_proj.Seams_Region == "WAPA_DK"].index.values[0], "Seams_Region" ] = "CBPC-NIPCO" # [0] = "CBPC-NIPCO" gdf_proj.at[ gdf_proj[gdf_proj.Seams_Region == "BREC"].index.values[0], "Seams_Region" ] = "AECIZ" gdf_proj.at[ gdf_proj[gdf_proj.Seams_Region == "LA-Gulf"].index.values[0], "Seams_Region" ] = "LA-GULF" # end re-assignment gdf_merge = pd.merge( gdf_proj, self.region_df, how="left", left_on="Seams_Region", right_on="names", ) self.gdf_merge = gdf_merge line_gdf = self.create_lines(line_attribute) labs = list(gdf_merge["Seams_Region"]) attribute_max = gdf_merge[attribute].max() boundary.geometry = boundary.geometry.buffer(0) boundary_shape = cascaded_union(boundary.geometry) coords = points_to_coords(gdf_proj.geometry) poly_shapes, pts, poly_to_pt_assignments = voronoi_regions_from_coords( coords, boundary_shape ) # run plotting fig, ax = subplot_for_map() myaxes = plt.axes() myaxes.set_ylim([20, 50]) myaxes.set_xlim([-104, -82]) # for i,s in enumerate(poly_shapes): # gdf_merge.at[i,'geometry'] = s divider = make_axes_locatable(myaxes) cax = divider.append_axes("bottom", size="5%", pad=0.1) if plot_type == "bubbles": gdf_merge.plot( ax=myaxes, column=attribute, cmap="Blues", legend=True, cax=cax, alpha=1.0, markersize=100, legend_kwds={ "label": attribute + " (MWh (EUE) or Hours (LOLE) /y)", "orientation": "horizontal", }, ) plot_points( myaxes, pts, 2, labels=labs, alpha=0.0 ) # mostly just adds the zonal labels elif plot_type == "fills": for i, s in enumerate(poly_shapes): plot_voronoi_polys( myaxes, s, color="g", alpha=gdf_merge.at[i, attribute] / attribute_max, ) gdf_merge.plot( ax=myaxes, column=attribute, cmap="Greens", legend=True, cax=cax, alpha=0.0, legend_kwds={ "label": attribute + " (MWh (EUE) or Hours (LOLE) /y)", "orientation": "horizontal", }, ) plot_points( myaxes, pts, 2, labels=labs ) # mostly just adds the zonal labels else: raise ValueError("plot_type must be either fills or bubbles") linewidths = list(line_gdf.MW) linewidths_2 = list(line_gdf.capacity) # finally, add the tx lines for lw, lw2 in zip(linewidths, linewidths_2): line_gdf[line_gdf.MW == lw].plot( lw=lw2 * 0.001, ax=myaxes, color="k", zorder=2, alpha=0.3 ) line_gdf[line_gdf.MW == lw].plot( lw=lw * 0.001, ax=myaxes, color="r", zorder=3 ) # could also add a MISO boundary if it seems useful self.iso_map[self.iso_map["NAME"] == self.iso_map.at[0, "NAME"]].plot( ax=myaxes, facecolor="b", edgecolor="y", alpha=0.04, linewidth=2, zorder=1 ) # last big thing would be a helpful legend.... self.states_map.plot(ax=myaxes, edgecolor="k", facecolor="None", alpha=0.3) # states_map.plot(ax=myaxes, edgecolor="k", facecolor="None") myaxes.set_title("MISO regions polygons \n (fill based on " + attribute + ")") # add manual legends to help interpret plot cap_1 = round(max(linewidths_2), -3) cap_2 = round(max(linewidths_2), -3) * 2.0 / 3.0 cap_3 = round(max(linewidths_2), -3) * 1.0 / 3.0 utilization_1 = round(max(linewidths), -2) utilization_2 = round(max(linewidths), -2) * 2.0 / 3.0 utilization_3 = round(max(linewidths), -2) * 1.0 / 3.0 custom_capacity_lines = [ Line2D([0], [0], color="k", lw=cap_1 * 0.001, alpha=0.3), Line2D([0], [0], color="k", lw=cap_2 * 0.001, alpha=0.3), Line2D([0], [0], color="k", lw=cap_3 * 0.001, alpha=0.3), Line2D([0], [0], color="r", lw=utilization_1 * 0.001), Line2D([0], [0], color="r", lw=utilization_2 * 0.001), Line2D([0], [0], color="r", lw=utilization_3 * 0.001), ] myaxes.legend( custom_capacity_lines, [ str(int(cap_1)) + " MW", str(int(cap_2)) + " MW", str(int(cap_3)) + " MW", str(int(utilization_1)) + " MW", str(int(utilization_2)) + " MW", str(int(utilization_3)) + " MW", ], loc="lower left", title="Line Capacity Line " + line_attribute.capitalize(), fontsize="x-small", title_fontsize="small", frameon=False, ncol=2, ) # custom_utilization_lines = [] # myaxes.legend(custom_utilization_lines, [], # loc="lower right",title="Line "+line_attribute, fontsize="x-small",title_fontsize="small",frameon=False) print("plotted") plt.savefig( os.path.join( self.results_folder, "voronoi" + plot_type + self.casename + ".jpg" ), dpi=300, ) # eventually create values for loading EUE, lole, etc return None