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 ellipse_patches(node_coords, width, height, angle=0, color=None, **kwargs): """ Function to create a list of ellipse patches from node coordinates. :param node_coords: coordinates of the nodes to draw :type node_coords: iterable :param width: width of the ellipse (described by an exterior rectangle) :type width: float :param height: height of the ellipse (described by an exterior rectangle) :type height: float :param angle: angle by which to rotate the ellipse :type angle: float :param color: color or colors of the patches :type color: iterable, float :param kwargs: additional keyword arguments to pass to the Ellipse initialization :type kwargs: dict :return: patches - list of ellipse patches for the nodes """ if not MATPLOTLIB_INSTALLED: soft_dependency_error( str(sys._getframe().f_code.co_name) + "()", "matplotlib") patches = list() angles = get_angle_list(angle, len(node_coords)) if color is not None: colors = get_color_list(color, len(node_coords)) for (x, y), col, ang in zip(node_coords, colors, angles): patches.append( Ellipse((x, y), width, height, angle=ang, color=col, **kwargs)) else: for (x, y), ang in zip(node_coords, angles): patches.append(Ellipse((x, y), width, height, angle=ang, **kwargs)) return patches
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 rectangle_patches(node_coords, width, height, color=None, **kwargs): """ Function to create a list of rectangle patches from node coordinates. :param node_coords: coordinates of the nodes to draw :type node_coords: iterable :param width: width of the rectangle :type width: float :param height: height of the rectangle :type height: float :param color: color or colors of the patches :type color: iterable, float :param kwargs: additional keyword arguments to pass to the Rectangle initialization :type kwargs: dict :return: patches - list of rectangle patches for the nodes """ if not MATPLOTLIB_INSTALLED: soft_dependency_error( str(sys._getframe().f_code.co_name) + "()", "matplotlib") patches = list() if color is not None: colors = get_color_list(color, len(node_coords)) for (x, y), col in zip(node_coords, colors): patches.append( Rectangle((x - width / 2, y - height / 2), width, height, color=color, **kwargs)) else: for x, y in node_coords: patches.append( Rectangle((x - width / 2, y - height / 2), width, height, **kwargs)) return patches
def heat_exchanger_patches(coords, size, **kwargs): polys, lines = list(), list() facecolor = kwargs.pop('patch_facecolor') colors = get_color_list(facecolor, 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 m = 3 * size / 4 direc = diff / np.sqrt(diff[0]**2 + diff[1]**2) normal = np.array([-direc[1], direc[0]]) path1 = (p1 + diff / 2 + direc * m / 2) + normal * (size * 9 / 8) path2 = p1 + diff / 2 + direc * m / 2 path3 = p1 + diff / 2 + normal * size / 3 path4 = p1 + diff / 2 - direc * m / 2 path5 = (p1 + diff / 2 - direc * m / 2) + normal * (size * 9 / 8) path = [path1, path2, path3, path4, path5] radius = size #np.sqrt(diff[0]**2+diff[1]**2)/15 pa = Path(path) polys.append( Circle(p1 + diff / 2, radius=radius, edgecolor=col, facecolor="w", lw=lw)) polys.append(PathPatch(pa, fill=False, lw=lw, edgecolor=col)) lines.append([p1, p1 + diff / 2 - direc * radius]) lines.append([p2, p1 + diff / 2 + direc * radius]) return lines, polys, {}
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 polygon_patches(node_coords, radius, num_edges, color=None, **kwargs): """ Function to create a list of polygon patches from node coordinates. The number of edges for the polygon can be defined. :param node_coords: coordinates of the nodes to draw :type node_coords: iterable :param radius: radius for the polygon (from centroid to edges) :type radius: float :param num_edges: number of edges of the polygon :type num_edges: int :param color: color or colors of the patches :type color: iterable, float :param kwargs: additional keyword arguments to pass to the Polygon initialization :type kwargs: dict :return: patches - list of rectangle patches for the nodes """ patches = list() if color is not None: colors = get_color_list(color, len(node_coords)) for (x, y), col in zip(node_coords, colors): patches.append( RegularPolygon([x, y], numVertices=num_edges, radius=radius, color=color, **kwargs)) else: for x, y in node_coords: patches.append( RegularPolygon([x, y], numVertices=num_edges, radius=radius, **kwargs)) return patches
def rectangle_patches(node_coords, width, height, color=None, **kwargs): """ Function to create a list of rectangle patches from node coordinates. :param node_coords: coordinates of the nodes to draw :type node_coords: iterable :param width: width of the rectangle :type width: float :param height: height of the rectangle :type height: float :param color: color or colors of the patches :type color: iterable, float :param kwargs: additional keyword arguments to pass to the Rectangle initialization :type kwargs: dict :return: patches - list of rectangle patches for the nodes """ patches = list() if color is not None: colors = get_color_list(color, len(node_coords)) for (x, y), col in zip(node_coords, colors): patches.append( Rectangle((x - width / 2, y - height / 2), width, height, color=color, **kwargs)) else: for x, y in node_coords: patches.append( Rectangle((x - width / 2, y - height / 2), width, height, **kwargs)) return patches
def trafo_patches(coords, size, **kwargs): """ Creates a list of patches and line coordinates representing transformers each connecting two nodes. :param coords: list of connecting node coordinates (usually should be \ `[((x11, y11), (x12, y12)), ((x21, y21), (x22, y22)), ...]`) :type coords: (N, (2, 2)) shaped iterable :param size: size of the trafo patches :type size: float :param kwargs: additional keyword arguments (might contain parameters "patch_edgecolor" and\ "patch_facecolor") :type kwargs: :return: Return values are: \ - lines (list) - list of coordinates for lines connecting nodes and transformer patches\ - circles (list of Circle) - list containing the transformer patches (rings) """ edgecolor = kwargs.get("patch_edgecolor", "w") facecolor = kwargs.get("patch_facecolor", (1, 0, 0, 0)) edgecolors = get_color_list(edgecolor, len(coords)) facecolors = get_color_list(facecolor, len(coords)) linewidths = kwargs.get("linewidths", 2.) linewidths = get_linewidth_list(linewidths, len(coords), name_entries="trafos") circles, lines = list(), list() for i, (p1, p2) in enumerate(coords): p1 = np.array(p1) p2 = np.array(p2) if np.all(p1 == p2): continue d = np.sqrt(np.sum((p1 - p2) ** 2)) if size is None: size_this = np.sqrt(d) / 5 else: size_this = size off = size_this * 0.35 circ1 = (0.5 - off / d) * (p1 - p2) + p2 circ2 = (0.5 + off / d) * (p1 - p2) + p2 circles.append(Circle(circ1, size_this, fc=facecolors[i], ec=edgecolors[i], lw=linewidths[i])) circles.append(Circle(circ2, size_this, fc=facecolors[i], ec=edgecolors[i], lw=linewidths[i])) lp1 = (0.5 - off / d - size_this / d) * (p2 - p1) + p1 lp2 = (0.5 - off / d - size_this / d) * (p1 - p2) + p2 lines.append([p1, lp1]) lines.append([p2, lp2]) return lines, circles, {"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 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 """ if not MATPLOTLIB_INSTALLED: soft_dependency_error( str(sys._getframe().f_code.co_name) + "()", "matplotlib") 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 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"}