def _create_node_element_collection(node_coords, patch_maker, size=1., infos=None, repeat_infos=(1, 1), orientation=np.pi, picker=False, patch_facecolor="w", patch_edgecolor="k", line_color="k", **kwargs): """ Creates matplotlib collections of node elements. All node element collections usually consist of one patch collection representing the element itself and a small line collection that connects the element to the respective node. :param node_coords: the coordinates (x, y) of the nodes with shape (N, 2) :type node_coords: iterable :param patch_maker: a function to generate the patches of which the collections consist (cf. \ the patch_maker module) :type patch_maker: function :param size: patch size :type size: float, default 1 :param infos: list of infos belonging to each of the elements (can be displayed when hovering \ over them) :type infos: iterable, default None :param repeat_infos: determines how many times the info shall be repeated to match the number \ of patches (first element) and lines (second element) returned by the patch maker :type repeat_infos: tuple (length 2), default (1, 1) :param orientation: orientation of load collection. pi is directed downwards, increasing values\ lead to clockwise direction changes. :type orientation: float, default np.pi :param picker: picker argument passed to the line collection :type picker: bool, default False :param patch_facecolor: color of the patch face (content) :type patch_facecolor: matplotlib color, "w" :param patch_edgecolor: color of the patch edges :type patch_edgecolor: matplotlib color, "k" :param line_color: color of the connecting lines :type line_color: matplotlib color, "k" :param kwargs: key word arguments are passed to the patch function :type kwargs: :return: Return values:\ - patch_coll - patch collection representing the element\ - line_coll - connecting line collection """ angles = orientation if hasattr(orientation, '__iter__') else [orientation] * len(node_coords) assert len(node_coords) == len(angles), \ "The length of coordinates does not match the length of the orientation angles!" if infos is None: infos_pc = [] infos_lc = [] else: infos_pc = list(np.repeat(infos, repeat_infos[0])) infos_lc = list(np.repeat(infos, repeat_infos[1])) lines, polys, popped_keywords = patch_maker( node_coords, size, angles, patch_facecolor=patch_facecolor, patch_edgecolor=patch_edgecolor, **kwargs) for kw in set(popped_keywords) & set(kwargs.keys()): kwargs.pop(kw) patch_coll = PatchCollection(polys, match_original=True, picker=picker, **kwargs) line_coll = LineCollection(lines, color=line_color, picker=picker, **kwargs) patch_coll.info = infos_pc line_coll.info = infos_lc return patch_coll, line_coll
def create_ext_grid_symbol_collection(net, size=1., infofunc=None, picker=False, **kwargs): lines = [] polys = [] infos = [] for i, ext_grid in net.ext_grid.iterrows(): p1 = net.bus_geodata[["x", "y"]].loc[ext_grid.bus] p2 = p1 + np.array([0, size]) polys.append( Rectangle([p2[0] - size / 2, p2[1] - size / 2], size, size)) lines.append((p1, p2 - np.array([0, size / 2]))) if infofunc is not None: infos.append(infofunc(i)) ext_grid1 = PatchCollection(polys, facecolor=(1, 0, 0, 0), edgecolor=(0, 0, 0, 1), hatch="XX", picker=picker, **kwargs) ext_grid2 = LineCollection(lines, color="k", picker=picker, **kwargs) ext_grid1.info = infos ext_grid2.info = infos return ext_grid1, ext_grid2
def create_load_collection(net, size=1., infofunc=None, orientation=np.pi, **kwargs): lines = [] polys = [] infos = [] off = 2. ang = orientation if hasattr( orientation, '__iter__') else [orientation] * net.load.shape[0] for i, load in net.load.iterrows(): p1 = net.bus_geodata[["x", "y"]].loc[load.bus] p2 = p1 + _rotate_dim2(np.array([0, size * off]), ang[i]) p3 = p1 + _rotate_dim2(np.array([0, size * (off - 0.5)]), ang[i]) polys.append( RegularPolygon(p2, numVertices=3, radius=size, orientation=-ang[i])) lines.append((p1, p3)) if infofunc is not None: infos.append(infofunc(i)) load1 = PatchCollection(polys, facecolor="w", edgecolor="k", **kwargs) load2 = LineCollection(lines, color="k", **kwargs) load1.info = infos load2.info = infos return load1, load2
def create_sgen_collection(net, size=1., infofunc=None, orientation=np.pi, **kwargs): lines = [] polys = [] infos = [] off = 1.7 r_triangle = size*0.4 ang = orientation if hasattr(orientation, '__iter__') else [orientation]*net.sgen.shape[0] for i, sgen in net.sgen.iterrows(): bus_geo = net.bus_geodata[["x", "y"]].loc[sgen.bus] mp_circ = bus_geo + _rotate_dim2(np.array([0, size * off]), ang[i]) # mp means midpoint circ_edge = bus_geo + _rotate_dim2(np.array([0, size * (off-1)]), ang[i]) mp_tri1 = mp_circ + _rotate_dim2(np.array([r_triangle, -r_triangle/4]), ang[i]) mp_tri2 = mp_circ + _rotate_dim2(np.array([-r_triangle, r_triangle/4]), ang[i]) perp_foot1 = mp_tri1 + _rotate_dim2(np.array([0, -r_triangle/2]), ang[i]) # dropped perpendicular foot of triangle1 line_end1 = perp_foot1 + + _rotate_dim2(np.array([-2.5*r_triangle, 0]), ang[i]) perp_foot2 = mp_tri2 + _rotate_dim2(np.array([0, r_triangle/2]), ang[i]) line_end2 = perp_foot2 + + _rotate_dim2(np.array([2.5*r_triangle, 0]), ang[i]) polys.append(Circle(mp_circ, size)) polys.append(RegularPolygon(mp_tri1, numVertices=3, radius=r_triangle, orientation=-ang[i])) polys.append(RegularPolygon(mp_tri2, numVertices=3, radius=r_triangle, orientation=np.pi-ang[i])) lines.append((bus_geo, circ_edge)) lines.append((perp_foot1, line_end1)) lines.append((perp_foot2, line_end2)) if infofunc is not None: infos.append(infofunc(i)) sgen1 = PatchCollection(polys, facecolor="w", edgecolor="k", **kwargs) sgen2 = LineCollection(lines, color="k", **kwargs) sgen1.info = infos sgen2.info = infos return sgen1, sgen2
def create_gen_symbol_collection(net, size=1., infofunc=None, **kwargs): lines = [] polys = [] infos = [] off = 1.7 for i, gen in net.gen.iterrows(): p1 = net.bus_geodata[["x", "y"]].loc[gen.bus] p2 = p1 - np.array([0, size * off]) polys.append(Circle(p2, size)) polys.append( Arc(p2 + np.array([-size / 6.2, -size / 2.6]), size / 2, size, theta1=45, theta2=135)) polys.append( Arc(p2 + np.array([size / 6.2, size / 2.6]), size / 2, size, theta1=225, theta2=315)) lines.append((p1, p2 + np.array([0, size]))) if infofunc is not None: infos.append(infofunc(i)) gen1 = PatchCollection(polys, facecolor="w", edgecolor="k", **kwargs) gen2 = LineCollection(lines, color="k", **kwargs) gen1.info = infos gen2.info = infos return gen1, gen2
def create_trafo_symbol_collection(net, trafos=None, picker=False, size=None, infofunc=None, **kwargs): """ Creates a matplotlib line collection of pandapower transformers. Input: **net** (pandapowerNet) - The pandapower network OPTIONAL: **trafos** (list, None) - The transformers for which the collections are created. If None, all transformers in the network are considered. **kwargs - key word arguments are passed to the patch function """ trafo_table = net.trafo if trafos is None else net.trafo.loc[trafos] lines = [] circles = [] infos = [] for i, trafo in trafo_table.iterrows(): p1 = net.bus_geodata[["x", "y"]].loc[trafo.hv_bus].values p2 = net.bus_geodata[["x", "y"]].loc[trafo.lv_bus].values if np.all(p1 == p2): continue d = np.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**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=(1, 0, 0, 0), ec=(0, 0, 0, 1))) circles.append( Circle(circ2, size_this, fc=(1, 0, 0, 0), ec=(0, 0, 0, 1))) 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]) if not infofunc is None: infos.append(infofunc(i)) infos.append(infofunc(i)) if len(circles) == 0: return None, None color = kwargs.get("color", "k") lc = LineCollection((lines), color=color, picker=picker, **kwargs) lc.info = infos pc = PatchCollection(circles, match_original=True, picker=picker, **kwargs) pc.info = infos return lc, pc
def _create_complex_branch_collection(coords, patch_maker, size=1, infos=None, repeat_infos=(2, 2), picker=False, patch_facecolor="w", patch_edgecolor="k", line_color="k", linewidths=2., **kwargs): """ Creates a matplotlib line collection and a matplotlib patch collection representing a branch\ element that cannot be represented by just a line. :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 patch_maker: a function to generate the patches of which the collections consist (cf. \ the patch_maker module) :type patch_maker: function :param size: patch size :type size: float, default 1 :param infos: list of infos belonging to each of the branches (can be displayed when hovering \ over them) :type infos: iterable, default None :param repeat_infos: determines how many times the info shall be repeated to match the number \ of patches (first element) and lines (second element) returned by the patch maker :type repeat_infos: tuple (length 2), default (1, 1) :param picker: picker argument passed to the line collection :type picker: bool, default False :param patch_facecolor: color or colors of the patch face (content) :type patch_facecolor: matplotlib color or iterable, "w" :param patch_edgecolor: color or colors of the patch edges :type patch_edgecolor: matplotlib color or iterable, "k" :param line_color: color or colors of the connecting lines :type line_color: matplotlib color or iterable, "k" :param linewidths: linewidths of the connecting lines and the patch edges :type linewidths: float, default 2. :param kwargs: key word arguments are passed to the patch maker and the patch and line \ collections :type kwargs: :return: Return values:\ - patch_coll - patch collection representing the branch element\ - line_coll - line collection connecting the patches with the nodes """ if infos is None: infos_pc = [] infos_lc = [] else: infos_pc = list(np.repeat(infos, repeat_infos[0])) infos_lc = list(np.repeat(infos, repeat_infos[1])) lines, patches, popped_keywords = patch_maker(coords, size, patch_facecolor=patch_facecolor, patch_edgecolor=patch_edgecolor, **kwargs) for kw in set(popped_keywords) & set(kwargs.keys()): kwargs.pop(kw) patch_coll = PatchCollection(patches, match_original=True, picker=picker, **kwargs) line_coll = LineCollection(lines, color=line_color, picker=picker, linewidths=linewidths, **kwargs) patch_coll.info = infos_pc line_coll.info = infos_lc return patch_coll, line_coll
def create_sgen_collection(net, sgens=None, size=1., infofunc=None, orientation=np.pi, **kwargs): """ Creates a matplotlib patch collection of pandapower sgen. Input: **net** (pandapowerNet) - The pandapower network OPTIONAL: **size** (float, 1) - patch size **infofunc** (function, None) - infofunction for the patch element **orientation** (float, np.pi) - orientation of load collection. pi is directed downwards, increasing values lead to clockwise direction changes. **kwargs - key word arguments are passed to the patch function OUTPUT: **sgen1** - patch collection **sgen2** - patch collection """ sgen_table = net.sgen if sgens is None else net.sgen.loc[sgens] lines = [] polys = [] infos = [] off = 1.7 r_triangle = size * 0.4 ang = orientation if hasattr(orientation, '__iter__') else [orientation] * net.sgen.shape[0] color = kwargs.pop("color", "k") for i, sgen in sgen_table.iterrows(): bus_geo = net.bus_geodata[["x", "y"]].loc[sgen.bus] mp_circ = bus_geo + _rotate_dim2(np.array([0, size * off]), ang[i]) # mp means midpoint circ_edge = bus_geo + _rotate_dim2(np.array([0, size * (off - 1)]), ang[i]) mp_tri1 = mp_circ + _rotate_dim2(np.array([r_triangle, -r_triangle / 4]), ang[i]) mp_tri2 = mp_circ + _rotate_dim2(np.array([-r_triangle, r_triangle / 4]), ang[i]) perp_foot1 = mp_tri1 + _rotate_dim2(np.array([0, -r_triangle / 2]), ang[i]) # dropped perpendicular foot of triangle1 line_end1 = perp_foot1 + + _rotate_dim2(np.array([-2.5 * r_triangle, 0]), ang[i]) perp_foot2 = mp_tri2 + _rotate_dim2(np.array([0, r_triangle / 2]), ang[i]) line_end2 = perp_foot2 + + _rotate_dim2(np.array([2.5 * r_triangle, 0]), ang[i]) polys.append(Circle(mp_circ, size)) polys.append(RegularPolygon(mp_tri1, numVertices=3, radius=r_triangle, orientation=-ang[i])) polys.append(RegularPolygon(mp_tri2, numVertices=3, radius=r_triangle, orientation=np.pi - ang[i])) lines.append((bus_geo, circ_edge)) lines.append((perp_foot1, line_end1)) lines.append((perp_foot2, line_end2)) if infofunc is not None: infos.append(infofunc(i)) sgen1 = PatchCollection(polys, facecolor="w", edgecolor="k", **kwargs) sgen2 = LineCollection(lines, color="k", **kwargs) sgen1.info = infos sgen2.info = infos return sgen1, sgen2
def create_ext_grid_collection(net, size=1., infofunc=None, orientation=0, picker=False, **kwargs): """ Creates a matplotlib patch collection of pandapower ext_grid. Input: **net** (pandapowerNet) - The pandapower network OPTIONAL: **size** (float, 1) - patch size **infofunc** (function, None) - infofunction for the patch element **orientation** (float, 0) - orientation of load collection. 0 is directed upwards, increasing values lead to clockwise direction changes. **picker** (bool, False) - picker argument passed to the patch collection **kwargs - key word arguments are passed to the patch function OUTPUT: **ext_grid1** - patch collection **ext_grid2** - patch collection """ lines = [] polys = [] infos = [] color = kwargs.pop("color", "k") for i, ext_grid in net.ext_grid.iterrows(): p1 = net.bus_geodata[["x", "y"]].loc[ext_grid.bus] p2 = p1 + _rotate_dim2(np.array([0, size]), orientation) polys.append( Rectangle([p2[0] - size / 2, p2[1] - size / 2], size, size)) lines.append( (p1, p2 - _rotate_dim2(np.array([0, size / 2]), orientation))) if infofunc is not None: infos.append(infofunc(i)) ext_grid1 = PatchCollection(polys, facecolor=(1, 0, 0, 0), edgecolor=(0, 0, 0, 1), hatch="XXX", picker=picker, color=color, **kwargs) ext_grid2 = LineCollection(lines, color=color, picker=picker, **kwargs) ext_grid1.info = infos ext_grid2.info = infos return ext_grid1, ext_grid2
def _create_node_collection(nodes, coords, size=5, patch_type="circle", color=None, picker=False, infos=None, **kwargs): """ Creates a collection with patches for the given nodes. Can be used generically for different \ types of nodes (bus in pandapower network, but also other nodes, e.g. in a networkx graph). :param nodes: indices of the nodes to plot :type nodes: iterable :param coords: list of node coordinates (shape (2, N)) :type coords: iterable :param size: size of the patches (handed over to patch creation function) :type size: float :param patch_type: type of patches that chall be created for the nodes - can be one of\ - "circle" for a circle\ - "rect" for a rectangle\ - "poly<n>" for a polygon with n edges :type patch_type: str, default "circle" :param color: colors or color of the node patches :type color: iterable, float :param picker: picker argument passed to the patch collection :type picker: bool, default False :param infos: list of infos belonging to each of the patches (can be displayed when hovering \ over the elements) :type infos: list, default None :param kwargs: keyword arguments are passed to the patch maker and patch collection :type kwargs: :return: pc - patch collection for the nodes """ if len(coords) == 0: return None infos = list(infos) if infos is not None else [] patches = node_patches(coords, size, patch_type, color, **kwargs) pc = PatchCollection(patches, match_original=True, picker=picker) pc.node_indices = np.array(nodes) pc.patch_type = patch_type pc.size = size if 'orientation' in kwargs: pc.orientation = kwargs['orientation'] if "zorder" in kwargs: pc.set_zorder(kwargs["zorder"]) pc.info = infos pc.patch_type = patch_type pc.size = size if "zorder" in kwargs: pc.set_zorder(kwargs["zorder"]) if 'orientation' in kwargs: pc.orientation = kwargs['orientation'] return pc
def create_ext_grid_collection(net, size=1., infofunc=None, orientation=0, picker=False, ext_grids=None, ext_grid_buses=None, **kwargs): """ Creates a matplotlib patch collection of pandapower ext_grid. Parameters ext_grids, ext_grid_buses can be used to specify, which ext_grids the collection should be created for. Input: **net** (pandapowerNet) - The pandapower network OPTIONAL: **size** (float, 1) - patch size **infofunc** (function, None) - infofunction for the patch element **orientation** (float, 0) - orientation of load collection. 0 is directed upwards, increasing values lead to clockwise direction changes. **picker** (bool, False) - picker argument passed to the patch collection **ext_grid_buses** (np.ndarray, None) - buses to be used as ext_grid locations **kwargs - key word arguments are passed to the patch function OUTPUT: **ext_grid1** - patch collection **ext_grid2** - patch collection """ lines = [] polys = [] infos = [] color = kwargs.pop("color", "k") if ext_grid_buses is None: ext_grid_buses = net.ext_grid.bus.values if ext_grids is None: ext_grids = net.ext_grid.index.values for ext_grid_idx, bus_idx in zip(ext_grids, ext_grid_buses): p1 = net.bus_geodata[["x", "y"]].loc[bus_idx].values p2 = p1 + _rotate_dim2(np.array([0, size]), orientation) polys.append(Rectangle([p2[0] - size / 2, p2[1] - size / 2], size, size)) lines.append((p1, p2 - _rotate_dim2(np.array([0, size / 2]), orientation))) if infofunc is not None: infos.append(infofunc(ext_grid_idx)) ext_grid1 = PatchCollection(polys, facecolor=(1, 0, 0, 0), edgecolor=(0, 0, 0, 1), hatch="XXX", picker=picker, color=color, **kwargs) ext_grid2 = LineCollection(lines, color=color, picker=picker, **kwargs) ext_grid1.info = infos ext_grid2.info = infos return ext_grid1, ext_grid2
def create_load_collection(net, loads=None, size=1., infofunc=None, orientation=np.pi, **kwargs): load_table = net.load if loads is None else net.load.loc[loads] """ Creates a matplotlib patch collection of pandapower loads. Input: **net** (pandapowerNet) - The pandapower network OPTIONAL: **size** (float, 1) - patch size **infofunc** (function, None) - infofunction for the patch element **orientation** (float, np.pi) - orientation of load collection. pi is directed downwards, increasing values lead to clockwise direction changes. **kwargs - key word arguments are passed to the patch function OUTPUT: **load1** - patch collection **load2** - patch collection """ lines = [] polys = [] infos = [] off = 2. ang = orientation if hasattr( orientation, '__iter__') else [orientation] * net.load.shape[0] color = kwargs.pop("color", "k") for i, load in load_table.iterrows(): p1 = net.bus_geodata[["x", "y"]].loc[load.bus] p2 = p1 + _rotate_dim2(np.array([0, size * off]), ang[i]) p3 = p1 + _rotate_dim2(np.array([0, size * (off - 0.5)]), ang[i]) polys.append( RegularPolygon(p2, numVertices=3, radius=size, orientation=-ang[i])) lines.append((p1, p3)) if infofunc is not None: infos.append(infofunc(i)) load1 = PatchCollection(polys, facecolor="w", edgecolor=color, **kwargs) load2 = LineCollection(lines, color=color, **kwargs) load1.info = infos load2.info = infos return load1, load2
def create_gen_collection(net, size=1., infofunc=None, **kwargs): """ Creates a matplotlib patch collection of pandapower gens. Input: **net** (pandapowerNet) - The pandapower network OPTIONAL: **size** (float, 1) - patch size **infofunc** (function, None) - infofunction for the patch element **kwargs - key word arguments are passed to the patch function OUTPUT: **gen1** - patch collection **gen2** - patch collection """ lines = [] polys = [] infos = [] off = 1.7 for i, gen in net.gen.iterrows(): p1 = net.bus_geodata[["x", "y"]].loc[gen.bus] p2 = p1 - np.array([0, size * off]) polys.append(Circle(p2, size)) polys.append( Arc(p2 + np.array([-size / 6.2, -size / 2.6]), size / 2, size, theta1=45, theta2=135)) polys.append( Arc(p2 + np.array([size / 6.2, size / 2.6]), size / 2, size, theta1=225, theta2=315)) lines.append((p1, p2 + np.array([0, size]))) if infofunc is not None: infos.append(infofunc(i)) gen1 = PatchCollection(polys, facecolor="w", edgecolor="k", **kwargs) gen2 = LineCollection(lines, color="k", **kwargs) gen1.info = infos gen2.info = infos return gen1, gen2
def create_load_symbol_collection(net, size=1., infofunc=None, **kwargs): lines = [] polys = [] infos = [] off = 1.7 for i, load in net.load.iterrows(): p1 = net.bus_geodata[["x", "y"]].loc[load.bus] p2 = p1 - np.array([0, size * off]) polys.append( RegularPolygon(p2, numVertices=3, radius=size, orientation=np.pi)) lines.append((p1, p2 + np.array([0, size / 2]))) if infofunc is not None: infos.append(infofunc(i)) load1 = PatchCollection(polys, facecolor="w", edgecolor="k", **kwargs) load2 = LineCollection(lines, color="k", **kwargs) load1.info = infos load2.info = infos return load1, load2
def create_bus_collection(net, buses=None, size=5, marker="o", patch_type="circle", colors=None, z=None, cmap=None, norm=None, infofunc=None, picker=False, bus_geodata=None, cbar_title="Bus Voltage [pu]", **kwargs): """ Creates a matplotlib patch collection of pandapower buses. Input: **net** (pandapowerNet) - The pandapower network OPTIONAL: **buses** (list, None) - The buses for which the collections are created. If None, all buses in the network are considered. **size** (int, 5) - patch size **marker** (str, "o") - patch marker **patch_type** (str, "circle") - patch type, can be - "circle" for a circle - "rect" for a rectangle - "poly<n>" for a polygon with n edges **infofunc** (function, None) - infofunction for the patch element **colors** (list, None) - list of colors for every element **z** (array, None) - array of bus voltage magnitudes for colormap. Used in case of given cmap. If None net.res_bus.vm_pu is used. **cmap** (ListedColormap, None) - colormap for the patch colors **norm** (matplotlib norm object, None) - matplotlib norm object **picker** (bool, False) - picker argument passed to the patch collection **bus_geodata** (DataFrame, None) - coordinates to use for plotting If None, net["bus_geodata"] is used **cbar_title** (str, "Bus Voltage [pu]") - colormap bar title in case of given cmap **kwargs - key word arguments are passed to the patch function OUTPUT: **pc** - patch collection """ buses = net.bus.index.tolist() if buses is None else list(buses) if len(buses) == 0: return None if bus_geodata is None: bus_geodata = net["bus_geodata"] coords = zip(bus_geodata.loc[buses, "x"].values, bus_geodata.loc[buses, "y"].values) infos = [] # RegularPolygon has no param width/height, everything else might use defaults if not patch_type.startswith("poly"): if 'height' not in kwargs and 'width' not in kwargs: kwargs['height'] = kwargs['width'] = 2 * size if patch_type == "rect": kwargs['height'] *= 2 kwargs['width'] *= 2 def figmaker(x, y, i): if colors is not None: kwargs["color"] = colors[i] if patch_type == 'ellipse' or patch_type == 'circle': # circles are just ellipses angle = kwargs['angle'] if 'angle' in kwargs else 0 fig = Ellipse((x, y), angle=angle, **kwargs) elif patch_type == "rect": fig = Rectangle([x - kwargs['width'] / 2, y - kwargs['height'] / 2], **kwargs) elif patch_type.startswith("poly"): edges = int(patch_type[4:]) fig = RegularPolygon([x, y], numVertices=edges, radius=size, **kwargs) else: logger.error("Wrong patchtype. Please choose a correct patch type.") if infofunc: infos.append(infofunc(buses[i])) return fig patches = [figmaker(x, y, i) for i, (x, y) in enumerate(coords) if x != np.nan] pc = PatchCollection(patches, match_original=True, picker=picker) pc.bus_indices = np.array(buses) if cmap is not None: pc.set_cmap(cmap) pc.set_norm(norm) if z is None and net is not None: z = net.res_bus.vm_pu.loc[buses] else: logger.warning("z is None and no net is provided") pc.set_array(np.array(z)) pc.has_colormap = True pc.cbar_title = cbar_title pc.patch_type = patch_type pc.size = size if 'orientation' in kwargs: pc.orientation = kwargs['orientation'] if "zorder" in kwargs: pc.set_zorder(kwargs["zorder"]) pc.info = infos return pc
def create_bus_symbol_collection(coords, buses=None, size=5, marker="o", patch_type="circle", colors=None, z=None, cmap=None, norm=None, infofunc=None, picker=False, net=None, **kwargs): infos = [] if 'height' in kwargs and 'width' in kwargs: height, width = kwargs['height'], kwargs['width'] else: height, width = size, size def figmaker(x, y, i): if patch_type == "circle": if colors: fig = Circle((x, y), size, color=colors[i], **kwargs) else: fig = Circle((x, y), size, **kwargs) elif patch_type == 'ellipse': angle = kwargs['angle'] if 'angle' in kwargs else 0 if colors: fig = Ellipse((x, y), width=width, height=height, color=colors[i], **kwargs) else: fig = Ellipse((x, y), width=width, height=height, angle=angle, **kwargs) elif patch_type == "rect": if colors: fig = Rectangle([x - width, y - height], 2 * width, 2 * height, color=colors[i], **kwargs) else: fig = Rectangle([x - width, y - height], 2 * width, 2 * height, **kwargs) elif patch_type.startswith("poly"): edges = int(patch_type[4:]) if colors: fig = RegularPolygon([x, y], numVertices=edges, radius=size, color=colors[i], **kwargs) else: fig = RegularPolygon([x, y], numVertices=edges, radius=size, **kwargs) else: logger.error( "Wrong patchtype. Please choose a correct patch type.") if infofunc: infos.append(infofunc(buses[i])) return fig patches = [ figmaker(x, y, i) for i, (x, y) in enumerate(coords) if x != np.nan ] pc = PatchCollection(patches, match_original=True, picker=picker) pc.bus_indices = np.array(buses) if cmap: pc.set_cmap(cmap) pc.set_norm(norm) if z is None and net: z = net.res_bus.vm_pu.loc[buses] else: logger.warning("z is None and no net is provided") pc.set_array(np.array(z)) pc.has_colormap = True pc.cbar_title = "Bus Voltage [pu]" pc.patch_type = patch_type pc.size = size if 'orientation' in kwargs: pc.orientation = kwargs['orientation'] if "zorder" in kwargs: pc.set_zorder(kwargs["zorder"]) pc.info = infos return pc
def create_bus_collection(net, buses=None, size=5, marker="o", patch_type="circle", colors=None, cmap=None, norm=None, infofunc=None, **kwargs): """ Creates a matplotlib patch collection of pandapower buses. Input: **net** (PandapowerNet) - The pandapower network Optional: **buses** (list, None) - The buses for which the collections are created. If None, all buses in the network are considered. **size** (int, 5) - patch size **marker** (str, "o") - patch marker **patch_type** (str, "circle") - patch type, can be - "circle" for a circle - "rect" for a rectanlge - "poly<n>" for a polygon with n edges **infofunc** (function, None) - infofunction for the patch element **colors** (list, None) - list of colors for every element **cmap** - colormap for the patch colors **picker** - picker argument passed to the patch collection **kwargs - key word arguments are passed to the patch function """ buses = net.bus.index.tolist() if buses is None else list(buses) patches = [] infos = [] def figmaker(x, y, i): if patch_type=="circle": if colors: fig = Circle((x, y), size, color=colors[i], **kwargs) else: fig = Circle((x, y), size, **kwargs) elif patch_type=="rect": if colors: fig = Rectangle([x - size, y - size], 2*size, 2*size, color=colors[i], **kwargs) else: fig = Rectangle([x - size, y - size], 2*size, 2*size, **kwargs) elif patch_type.startswith("poly"): edges = int(patch_type[4:]) if colors: fig = RegularPolygon([x, y], numVertices=edges, radius=size, color=colors[i], **kwargs) else: fig = RegularPolygon([x, y], numVertices=edges, radius=size, **kwargs) if infofunc: infos.append(infofunc(buses[i])) return fig patches = [figmaker(x, y, i) for i, (x, y) in enumerate(zip(net.bus_geodata.loc[buses].x.values, net.bus_geodata.loc[buses].y.values)) if x != -1 and x != np.nan] pc = PatchCollection(patches, match_original=True) if cmap: pc.set_cmap(cmap) pc.set_norm(norm) pc.set_array(net.res_bus.vm_pu.loc[buses]) pc.has_colormap = True pc.cbar_title = "Bus Voltage [pu]" pc.patch_type = patch_type pc.size = size if "zorder" in kwargs: pc.set_zorder(kwargs["zorder"]) pc.info = infos return pc
def create_trafo3w_collection(net, trafo3ws=None, picker=False, size=None, infofunc=None, **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. **kwargs - key word arguments are passed to the patch function OUTPUT: **lc** - line collection **pc** - patch collection """ trafo3w_table = net.trafo3w if trafo3ws is None else net.trafo3w.loc[ trafo3ws] lines = [] circles = [] infos = [] color = kwargs.pop("color", "k") linewidth = kwargs.pop("linewidths", 2.) for i, trafo3w in trafo3w_table.iterrows(): # get bus geodata p1 = net.bus_geodata[["x", "y"]].loc[trafo3w.hv_bus].values p2 = net.bus_geodata[["x", "y"]].loc[trafo3w.mv_bus].values p3 = net.bus_geodata[["x", "y"]].loc[trafo3w.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 for i in range(3): circles.append(Circle(m[i], r, fc=(1, 0, 0, 0), ec=color)) lines.append([p[i], e[i]]) 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 return lc, pc
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