Source code for relsad.visualization.plotting.topology

import matplotlib.pyplot as plt

from relsad.network.components import (
    Bus,
    CircuitBreaker,
    Disconnector,
    EVPark,
    IntelligentSwitch,
    Line,
    Sensor,
    ICTNode,
    ICTLine,
)


[docs]def plot_topology( buses: list, lines: list, ict_nodes: list = None, ict_lines: list = None, bus_text: bool = True, line_text: bool = False, circuitbreaker_text: bool = False, disconnector_text: bool = False, intelligent_switch_text: bool = False, sensor_text: bool = False, text_dx: tuple = (0, -0.1), **kwargs ): """ Plots the system topology Parameters ---------- buses : list List with Bus elements in the system lines : list List with Line elements in the system bus_text : bool Flag determining if bus name will be plotted line_text : bool Flag determining if line name will be plotted circuitbreaker_text : bool Flag determining if circuitbreaker name will be plotted disconnector_text : bool Flag determining if disconnector name will be plotted intelligent_switch_text : bool Flag determining if intelligent switch name will be plotted sensor_text : bool Flag determining if sensor name will be plotted **kwargs : dict Plotting keyword arguments. Returns ---------- fig : figure Figure of the system topology None """ # Handle keyword arguments left = kwargs["left"] if "left" in kwargs else 0.02 right = kwargs["right"] if "right" in kwargs else 0.98 bottom = kwargs["bottom"] if "bottom" in kwargs else 0.1 top = kwargs["top"] if "top" in kwargs else 0.75 text_size = kwargs["text_size"] if "text_size" in kwargs else 6 ncol = kwargs["ncol"] if "ncol" in kwargs else None # Clear used keyword arguments kwargs.pop("left", None) kwargs.pop("right", None) kwargs.pop("bottom", None) kwargs.pop("top", None) kwargs.pop("text_size", None) kwargs.pop("ncol", None) fig, ax = plt.subplots(**kwargs) fig.subplots_adjust( left=left, bottom=bottom, right=right, top=top, wspace=None, hspace=None, ) legends = {} for bus in buses: _plot_bus( ax=ax, bus=bus, text=bus_text, text_size=text_size, text_dx=text_dx, ) legends["Bus"] = Bus.handle if bus.ev_park is not None: legends["EV park"] = EVPark.handle for line in lines: _plot_line( ax=ax, line=line, text=line_text, text_size=text_size, ) legends["Line"] = Line.handle if line.circuitbreaker is not None: _plot_circuitbreaker( ax=ax, line=line, text=circuitbreaker_text, text_size=text_size, ) legends["Circuit breaker"] = CircuitBreaker.handle for discon in line.disconnectors: _plot_disconnector( ax=ax, discon=discon, text=disconnector_text, text_size=text_size, ) legends["Disconnector"] = Disconnector.handle if discon.intelligent_switch: _plot_intelligent_switch( ax=ax, discon=discon, text=intelligent_switch_text, text_size=text_size, ) legends["Intelligent switch"] = IntelligentSwitch.handle if line.sensor: _plot_sensor( ax=ax, sensor=line.sensor, text=sensor_text, text_size=text_size, ) legends["Sensor"] = Sensor.handle if ict_nodes is not None: for ict_node in ict_nodes: _plot_ict_node( ax=ax, ict_node=ict_node, text=False, text_size=text_size, text_dx=text_dx, ) legends["ICT node"] = ICTNode.handle if ict_lines is not None: for ict_line in ict_lines: _plot_ict_line( ax=ax, ict_line=ict_line, text=False, text_size=text_size, ) legends["ICT line"] = ICTLine.handle plt.figlegend( legends.values(), legends.keys(), ncol=ncol if ncol is not None else len(legends), loc="upper center", bbox_to_anchor=(left + (right - left) / 2, 0.978), frameon=False, prop={"size": 8}, handleheight=3, ) plt.axis("off") return fig
def _plot_bus( ax: plt.axis, bus: Bus, text: bool = False, text_size: int = 8, text_dx: tuple = (0, 0), ): """ Plot bus Parameters ---------- ax : matplotlib.axes.Axes Plot axis bus : Bus Bus element text : bool Flag determining if bus name will be plotted text_size : int The size of the text in the plot text_dx : tuple The distance from the text to the center point Returns ---------- None """ x, y = bus.coordinate ax.plot( x, y, marker=bus.marker, markeredgewidth=bus.handle.get_markeredgewidth(), markersize=bus.size, linestyle="None", color=bus.color, clip_on=False, zorder=3, ) if text: ax.text( x + text_dx[0], y + text_dx[1], bus.name, ha="center", va="center", size=text_size, ) if bus.ev_park is not None: ax.plot( x, y, marker=bus.ev_park.marker, markeredgewidth=bus.ev_park.handle.get_markeredgewidth(), markersize=bus.ev_park.size, linestyle="None", color=bus.color, clip_on=False, zorder=3, ) def _plot_line( ax: plt.axis, line: Line, text: bool = False, text_size: int = 8, ): """ Plot line Parameters ---------- ax : matplotlib.axes.Axes Plot axis line : Line A Line element text : bool Flag determining if line name will be plotted text_size : int The size of the text in the plot Returns ---------- None """ dx_fraction = 0.1 x1, y1 = line.fbus.coordinate x2, y2 = line.tbus.coordinate linestyle = ":" if line.is_backup else line.linestyle ax.plot( [x1, x2], [y1, y2], color=line.color, linestyle=linestyle, zorder=2, ) if text: dx = x2 - x1 dy = y2 - y1 x = (x1 + x2) / 2 y = (y1 + y2) / 2 if dx == 0 and dy != 0: x += dy * dx_fraction elif dx != 0 and dy == 0: y += dx * dx_fraction else: x += dx * dx_fraction y -= dy * dx_fraction ax.text( x, y, line.name, ha="center", va="center", size=text_size, ) def _plot_circuitbreaker( ax: plt.axis, line: Line, text: bool = False, text_size: int = 8, ): """ Plot circuitbreakers Parameters ---------- ax : matplotlib.axes.Axes Plot axis line : Line A Line element text : bool Flag determining if circuitbreaker name will be plotted text_size : int The size of the text in the plot Returns ---------- None """ cb = line.circuitbreaker x, y = cb.coordinate ax.plot( x, y, marker=cb.marker, markeredgewidth=cb.handle.get_markeredgewidth(), markersize=cb.size, linestyle="None", color=cb.color, markeredgecolor=cb.edgecolor, zorder=3, ) if text: ax.text( x, y - 0.2, cb.name, ha="center", va="center", size=text_size, ) def _plot_disconnector( ax: plt.axis, discon: Disconnector, text: bool = False, text_size: int = 8, ): """ Plot disconnectors Parameters ---------- ax : matplotlib.axes.Axes Plot axis discon : Disconnecotr A Disconnector elements text : bool Flag determining if disconnector name will be plotted text_size : int The size of the text in the plot Returns ---------- None """ x, y = discon.coordinate ax.plot( x, y, marker=discon.marker, markeredgewidth=discon.handle.get_markeredgewidth(), markersize=discon.size, linestyle="None", color=discon.color, markeredgecolor=discon.edgecolor, zorder=3, ) if text: ax.text( x, y - 0.2, discon.name, ha="center", va="center", size=text_size, ) def _plot_intelligent_switch( ax: plt.axis, discon: Disconnector, text: bool = False, text_size: int = 8, ): """ Plot intelligent switches Parameters ---------- ax : matplotlib.axes.Axes Plot axis discon : Disconnector A Disconnector elements text : bool Flag determining if intelligent switch name will be plotted text_size : int The size of the text on the plot Returns ---------- None """ x, y = discon.coordinate ax.plot( x, y, marker=discon.intelligent_switch.marker, markeredgewidth=discon.intelligent_switch.handle.get_markeredgewidth(), markersize=discon.intelligent_switch.size, linestyle="None", color=discon.intelligent_switch.color, zorder=3, ) if text: ax.text( x, y - 0.2, discon.intelligent_switch.name, ha="center", va="center", size=text_size, ) def _plot_sensor( ax: plt.axis, sensor: Sensor, text: bool = False, text_size: int = 8, ): """ Plot sensors Parameters ---------- ax : matplotlib.axes.Axes Plot axis sensor : Sensor A Line element text : bool Flag determining if sensor name will be plotted text_size : int The size of the text in the plot Returns ---------- None """ x, y = sensor.coordinate ax.plot( x, y, marker=sensor.marker, markeredgewidth=sensor.handle.get_markeredgewidth(), markersize=sensor.size, linestyle="None", color=sensor.color, zorder=3, ) if text: ax.text( x, y + 0.2, sensor.name, ha="center", va="center", size=text_size, ) def _plot_ict_node( ax: plt.axis, ict_node: ICTNode, text: bool = False, text_size: int = 8, text_dx: tuple = (0, 0), ): """ Plot ICT node Parameters ---------- ax : matplotlib.axes.Axes Plot axis ict_node : ICTNode ICTNode element text : bool Flag determining if bus name will be plotted text_size : int The size of the text in the plot text_dx : tuple The distance from the text to the center point Returns ---------- None """ x, y = ict_node.coordinate ax.plot( x, y, marker=ict_node.marker, markeredgewidth=ict_node.handle.get_markeredgewidth(), markersize=ict_node.size, linestyle="None", color=ict_node.color, clip_on=False, zorder=3, ) if text: ax.text( x + text_dx[0], y + text_dx[1], ict_node.name, ha="center", va="center", size=text_size, ) def _plot_ict_line( ax: plt.axis, ict_line: ICTLine, text: bool = False, text_size: int = 8, ): """ Plot ICT line Parameters ---------- ax : matplotlib.axes.Axes Plot axis ict_line : ICTLine An ICTLine element text : bool Flag determining if line name will be plotted text_size : int The size of the text in the plot Returns ---------- None """ dx_fraction = 0.1 x1, y1 = ict_line.fnode.coordinate x2, y2 = ict_line.tnode.coordinate ax.plot( [x1, x2], [y1, y2], color=ict_line.color, linestyle=ict_line.linestyle, zorder=2, ) if text: dx = x2 - x1 dy = y2 - y1 x = (x1 + x2) / 2 y = (y1 + y2) / 2 if dx == 0 and dy != 0: x += dy * dx_fraction elif dx != 0 and dy == 0: y += dx * dx_fraction else: x += dx * dx_fraction y -= dy * dx_fraction ax.text( x, y, ict_line.name, ha="center", va="center", size=text_size, )