def pump_patches(coords, size, **kwargs): polys, lines = list(), list() edgecolor = kwargs.pop('patch_edgecolor') colors = get_color_list(edgecolor, len(coords)) lw = kwargs.get("linewidths", 2.) for geodata, col in zip(coords, colors): p1, p2 = np.array(geodata[0]), np.array(geodata[-1]) diff = p2 - p1 angle = np.arctan2(*diff) vec_size = _rotate_dim2(np.array([0, size]), angle) line1 = _rotate_dim2(np.array([0, size * np.sqrt(2)]), angle - np.pi / 4) line2 = _rotate_dim2(np.array([0, size * np.sqrt(2)]), angle + np.pi / 4) radius = size polys.append( Circle(p1 + diff / 2, radius=radius, edgecolor=col, facecolor='w', lw=lw)) lines.append( [p1 + diff / 2 + vec_size, p1 + diff / 2 - vec_size + line1]) lines.append( [p1 + diff / 2 + vec_size, p1 + diff / 2 - vec_size + line2]) lines.append([p1, p1 + diff / 2 - vec_size]) lines.append([p2, p1 + diff / 2 + vec_size]) return lines, polys, {}
def source_patches(node_coords, size, angles, **kwargs): """ Creation function of patches for sources. :param node_coords: coordinates of the nodes that the sources belong to. :type node_coords: iterable :param size: size of the patch :type size: float :param angles: angles by which to rotate the patches (in radians) :type angles: iterable(float), float :param kwargs: additional keyword arguments (might contain parameter "offset") :type kwargs: :return: Return values are: \ - lines (list) - list of coordinates for lines leading to source patches and diagonals\ - polys (list of RegularPolygon) - list containing the load patches\ - keywords (set) - set of keywords removed from kwargs """ offset = kwargs.get("offset", size * 2) all_angles = get_angle_list(angles, len(node_coords)) facecolor = kwargs.get("patch_faceolor", "w") edgecolor = kwargs.get("patch_edgecolor", "k") facecolors = get_color_list(facecolor, len(node_coords)) edgecolors = get_color_list(edgecolor, len(node_coords)) polys, lines = list(), list() for i, node_geo in enumerate(node_coords): p2 = node_geo + _rotate_dim2(np.array([0, offset]), all_angles[i]) p_edge_left = p2 + _rotate_dim2(np.array([size, size]), all_angles[i]) p_edge_right = p2 + _rotate_dim2(np.array([- size, size]), all_angles[i]) p_ll = p2 + _rotate_dim2(np.array([-size, 0]), all_angles[i]) polys.append(Rectangle(p_ll, 2 * size, 2 * size, angle=(- all_angles[i] / np.pi * 180), fc=facecolors[i], ec=edgecolors[i])) lines.append((node_geo, p2)) lines.append((p2, p_edge_left)) lines.append((p2, p_edge_right)) return lines, polys, {"offset"}
def load_patches(node_coords, size, angles, **kwargs): """ Creation function of patches for loads. :param node_coords: coordinates of the nodes that the loads belong to. :type node_coords: iterable :param size: size of the patch :type size: float :param angles: angles by which to rotate the patches (in radians) :type angles: iterable(float), float :param kwargs: additional keyword arguments (might contain parameters "offset",\ "patch_edgecolor" and "patch_facecolor") :type kwargs: :return: Return values are: \ - lines (list) - list of coordinates for lines leading to load patches\ - polys (list of RegularPolygon) - list containing the load patches\ - keywords (set) - set of keywords removed from kwargs """ offset = kwargs.get("offset", 1.2 * size) all_angles = get_angle_list(angles, len(node_coords)) edgecolor = kwargs.get("patch_edgecolor", "w") facecolor = kwargs.get("patch_facecolor", "w") edgecolors = get_color_list(edgecolor, len(node_coords)) facecolors = get_color_list(facecolor, len(node_coords)) polys, lines = list(), list() for i, node_geo in enumerate(node_coords): p2 = node_geo + _rotate_dim2(np.array([0, offset + size]), all_angles[i]) p3 = node_geo + _rotate_dim2(np.array([0, offset + size / 2]), all_angles[i]) polys.append(RegularPolygon(p2, numVertices=3, radius=size, orientation=-all_angles[i], fc=facecolors[i], ec=edgecolors[i])) lines.append((node_geo, p3)) return lines, polys, {"offset", "patch_edgecolor", "patch_facecolor"}
def gen_patches(node_coords, size, angles, **kwargs): """ Creation function of patches for generators. :param node_coords: coordinates of the nodes that the generators belong to. :type node_coords: iterable :param size: size of the patch :type size: float :param angles: angles by which to rotate the patches (in radians) :type angles: iterable(float), float :param kwargs: additional keyword arguments (might contain parameters "offset",\ "patch_edgecolor" and "patch_facecolor") :type kwargs: :return: Return values are: \ - lines (list) - list of coordinates for lines leading to generator patches\ - polys (list of RegularPolygon) - list containing the generator patches\ - keywords (set) - set of keywords removed from kwargs """ if not MATPLOTLIB_INSTALLED: soft_dependency_error( str(sys._getframe().f_code.co_name) + "()", "matplotlib") polys, lines = list(), list() offset = kwargs.get("offset", 2. * size) all_angles = get_angle_list(angles, len(node_coords)) edgecolor = kwargs.get("patch_edgecolor", "k") facecolor = kwargs.get("patch_facecolor", (1, 0, 0, 0)) edgecolors = get_color_list(edgecolor, len(node_coords)) facecolors = get_color_list(facecolor, len(node_coords)) for i, node_geo in enumerate(node_coords): p2 = node_geo + _rotate_dim2(np.array([0, size + offset]), all_angles[i]) polys.append(Circle(p2, size, fc=facecolors[i], ec=edgecolors[i])) polys.append( Arc(p2 + np.array([-size / 6.2, -size / 2.6]), size / 2, size, theta1=65, theta2=120, ec=edgecolors[i])) polys.append( Arc(p2 + np.array([size / 6.2, size / 2.6]), size / 2, size, theta1=245, theta2=300, ec=edgecolors[i])) lines.append( (node_geo, p2 + _rotate_dim2(np.array([0, size]), -all_angles[i]))) return lines, polys, {"offset", "patch_edgecolor", "patch_facecolor"}
def valve_patches(coords, size, **kwargs): polys, lines = list(), list() edgecolor = kwargs.pop('patch_edgecolor') colors = get_color_list(edgecolor, len(coords)) lw = kwargs.get("linewidths", 2.) filled = kwargs.pop("filled", np.full(len(coords), 0, dtype=np.bool)) filled = get_filled_list(filled, len(coords)) for geodata, col, filled_ind in zip(coords, colors, filled): p1, p2 = np.array(geodata[0]), np.array(geodata[-1]) diff = p2 - p1 angle = np.arctan2(*diff) vec_size = _rotate_dim2(np.array([0, size]), angle) centroid_tri1 = p1 + diff / 2 - vec_size centroid_tri2 = p1 + diff / 2 + vec_size face_col = "w" if not filled_ind else col polys.append( RegularPolygon(centroid_tri1, numVertices=3, radius=size, orientation=-angle, ec=col, fc=face_col, lw=lw)) polys.append( RegularPolygon(centroid_tri2, numVertices=3, radius=size, orientation=-angle + np.pi / 3, ec=col, fc=face_col, lw=lw)) lines.append([p1, p1 + diff / 2 - vec_size / 2 * 3]) lines.append([p2, p1 + diff / 2 + vec_size / 2 * 3]) return lines, polys, {"filled"}
def ext_grid_patches(node_coords, size, angles, **kwargs): """ Creation function of patches for external grids. :param node_coords: coordinates of the nodes that the external grids belong to. :type node_coords: iterable :param size: size of the patch :type size: float :param angles: angles by which to rotate the patches (in radians) :type angles: iterable(float), float :param kwargs: additional keyword arguments (might contain parameters "offset",\ "patch_edgecolor" and "patch_facecolor") :type kwargs: :return: Return values are: \ - lines (list) - list of coordinates for lines leading to external grid patches\ - polys (list of RegularPolygon) - list containing the external grid patches\ - keywords (set) - set of keywords removed from kwargs (empty """ if not MATPLOTLIB_INSTALLED: soft_dependency_error( str(sys._getframe().f_code.co_name) + "()", "matplotlib") offset = kwargs.get("offset", 2 * size) all_angles = get_angle_list(angles, len(node_coords)) edgecolor = kwargs.get("patch_edgecolor", "w") facecolor = kwargs.get("patch_facecolor", "w") edgecolors = get_color_list(edgecolor, len(node_coords)) facecolors = get_color_list(facecolor, len(node_coords)) polys, lines = list(), list() for i, node_geo in enumerate(node_coords): p2 = node_geo + _rotate_dim2(np.array([0, offset]), all_angles[i]) p_ll = p2 + _rotate_dim2(np.array([-size, 0]), all_angles[i]) polys.append( Rectangle(p_ll, 2 * size, 2 * size, angle=(-all_angles[i] / np.pi * 180), fc=facecolors[i], ec=edgecolors[i], hatch="XXX")) lines.append((node_geo, p2)) return lines, polys, {"offset", "patch_edgecolor", "patch_facecolor"}
def sgen_patches(node_coords, size, angles, **kwargs): """ Creation function of patches for static generators. :param node_coords: coordinates of the nodes that the static generators belong to. :type node_coords: iterable :param size: size of the patch :type size: float :param angles: angles by which to rotate the patches (in radians) :type angles: iterable(float), float :param kwargs: additional keyword arguments (might contain parameters "offset", "r_triangle",\ "patch_edgecolor" and "patch_facecolor") :type kwargs: :return: Return values are: \ - lines (list) - list of coordinates for lines leading to static generator patches\ - polys (list of RegularPolygon) - list containing the static generator patches\ - keywords (set) - set of keywords removed from kwargs """ polys, lines = list(), list() offset = kwargs.get("offset", 2 * size) r_triangle = kwargs.get("r_triangles", size * 0.4) edgecolor = kwargs.get("patch_edgecolor", "w") facecolor = kwargs.get("patch_facecolor", "w") edgecolors = get_color_list(edgecolor, len(node_coords)) facecolors = get_color_list(facecolor, len(node_coords)) for i, node_geo in enumerate(node_coords): mid_circ = node_geo + _rotate_dim2(np.array([0, offset + size]), angles[i]) circ_edge = node_geo + _rotate_dim2(np.array([0, offset]), angles[i]) mid_tri1 = mid_circ + _rotate_dim2(np.array([r_triangle, -r_triangle / 4]), angles[i]) mid_tri2 = mid_circ + _rotate_dim2(np.array([-r_triangle, r_triangle / 4]), angles[i]) # dropped perpendicular foot of triangle1 perp_foot1 = mid_tri1 + _rotate_dim2(np.array([0, -r_triangle / 2]), angles[i]) line_end1 = perp_foot1 + + _rotate_dim2(np.array([-2.5 * r_triangle, 0]), angles[i]) perp_foot2 = mid_tri2 + _rotate_dim2(np.array([0, r_triangle / 2]), angles[i]) line_end2 = perp_foot2 + + _rotate_dim2(np.array([2.5 * r_triangle, 0]), angles[i]) polys.append(Circle(mid_circ, size, fc=facecolors[i], ec=edgecolors[i])) polys.append(RegularPolygon(mid_tri1, numVertices=3, radius=r_triangle, orientation=-angles[i], fc=facecolors[i], ec=edgecolors[i])) polys.append(RegularPolygon(mid_tri2, numVertices=3, radius=r_triangle, orientation=np.pi - angles[i], fc=facecolors[i], ec=edgecolors[i])) lines.append((node_geo, circ_edge)) lines.append((perp_foot1, line_end1)) lines.append((perp_foot2, line_end2)) return lines, polys, {"offset", "r_triangle", "patch_edgecolor", "patch_facecolor"}
def storage_patches(node_coords, size, angles, **kwargs): """ Creation function of patches for storage systems. :param node_coords: coordinates of the nodes that the storage system belong to. :type node_coords: iterable :param size: size of the patch :type size: float :param angles: angles by which to rotate the patches (in radians) :type angles: iterable(float), float :param kwargs: additional keyword arguments (might contain parameters "offset", "r_triangle",\ "patch_edgecolor" and "patch_facecolor") :type kwargs: :return: Return values are: \ - lines (list) - list of coordinates for lines leading to storage patches\ - polys (list of RegularPolygon) - list containing the storage patches\ - keywords (set) - set of keywords removed from kwargs """ polys, lines = list(), list() offset = kwargs.get("offset", 1 * size) r_triangle = kwargs.get("r_triangles", size * 0.4) for i, node_geo in enumerate(node_coords): mid_circ = node_geo + _rotate_dim2( np.array([0, offset + r_triangle * 2.]), angles[i]) circ_edge = node_geo + _rotate_dim2(np.array([0, offset]), angles[i]) mid_tri1 = mid_circ + _rotate_dim2( np.array([-r_triangle, -r_triangle]), angles[i]) # dropped perpendicular foot of triangle1 perp_foot1 = mid_tri1 + _rotate_dim2( np.array([r_triangle * 0.5, -r_triangle / 4]), angles[i]) line_end1 = perp_foot1 + _rotate_dim2(np.array([1 * r_triangle, 0]), angles[i]) perp_foot2 = mid_tri1 + _rotate_dim2(np.array([0, -r_triangle]), angles[i]) line_end2 = perp_foot2 + _rotate_dim2(np.array([2. * r_triangle, 0]), angles[i]) lines.append((node_geo, circ_edge)) lines.append((perp_foot1, line_end1)) lines.append((perp_foot2, line_end2)) return lines, polys, { "offset", "r_triangle", "patch_edgecolor", "patch_facecolor" }
def create_trafo3w_collection(net, trafo3ws=None, picker=False, infofunc=None, cmap=None, norm=None, z=None, clim=None, cbar_title="3W-Transformer Loading", plot_colormap=True, **kwargs): """ Creates a matplotlib line collection of pandapower transformers. Input: **net** (pandapowerNet) - The pandapower network OPTIONAL: **trafo3ws** (list, None) - The three winding transformers for which the collections are created. If None, all three winding transformers in the network are considered. **picker** (bool, False) - picker argument passed to the patch collection **infofunc** (function, None) - infofunction for the patch element **kwargs - key word arguments are passed to the patch function OUTPUT: **lc** - line collection **pc** - patch collection """ trafo3ws = get_index_array(trafo3ws, net.trafo3w.index) trafo3w_table = net.trafo3w.loc[trafo3ws] lines = [] circles = [] infos = [] color = kwargs.pop("color", "k") linewidth = kwargs.pop("linewidths", 2.) if cmap is not None and z is None: z = net.res_trafo3w.loading_percent for i, idx in enumerate(trafo3w_table.index): # get bus geodata p1 = net.bus_geodata[["x", "y"]].loc[net.trafo3w.at[idx, "hv_bus"]].values p2 = net.bus_geodata[["x", "y"]].loc[net.trafo3w.at[idx, "mv_bus"]].values p3 = net.bus_geodata[["x", "y"]].loc[net.trafo3w.at[idx, "lv_bus"]].values if np.all(p1 == p2) and np.all(p1 == p3): continue p = np.array([p1, p2, p3]) # determine center of buses and minimum distance center-buses center = sum(p) / 3 d = np.linalg.norm(p - center, axis=1) r = d.min() / 3 # determine closest bus to center and vector from center to circle midpoint in closest # direction closest = d.argmin() to_closest = (p[closest] - center) / d[closest] * 2 * r / 3 # determine vectors from center to circle midpoint order = list(range(closest, 3)) + list(range(closest)) cm = np.empty((3, 2)) cm[order.pop(0)] = to_closest ang = 2 * np.pi / 3 # 120 degree cm[order.pop(0)] = _rotate_dim2(to_closest, ang) cm[order.pop(0)] = _rotate_dim2(to_closest, -ang) # determine midpoints of circles m = center + cm # determine endpoints of circles e = (center - p) * (1 - 5 * r / 3 / d).reshape(3, 1) + p # save circle and line collection data ec = color if cmap is None else cmap(norm(z.at[idx])) for j in range(3): circles.append(Circle(m[j], r, fc=(1, 0, 0, 0), ec=ec)) lines.append([p[j], e[j]]) if infofunc is not None: infos.append(infofunc(i)) infos.append(infofunc(i)) if len(circles) == 0: return None, None lc = LineCollection(lines, color=color, picker=picker, linewidths=linewidth, **kwargs) lc.info = infos pc = PatchCollection(circles, match_original=True, picker=picker, linewidth=linewidth, **kwargs) pc.info = infos if cmap is not None: z_duplicated = np.repeat(z.values, 3) lc.set_cmap(cmap) lc.set_norm(norm) if clim is not None: lc.set_clim(clim) lc.set_array(np.ma.masked_invalid(z_duplicated)) lc.has_colormap = plot_colormap lc.cbar_title = cbar_title return lc, pc