Source code for monee.visualization.visualization

import networkx as nx
import networkx.drawing.nx_agraph as nxd
import plotly.express as px
import plotly.graph_objects as go
import plotly.io as pio

import monee.model as mm

pio.templates["publish"] = go.layout.Template(
    layout=go.Layout(
        font=dict(family="sans-serif", size=19),
    )
)
pio.templates["publish3"] = go.layout.Template(
    layout=go.Layout(
        font=dict(family="sans-serif", size=19),
    )
)
pio.templates["publish2"] = go.layout.Template(
    layout=go.Layout(
        font=dict(family="sans-serif", size=13),
    )
)
pio.templates["publish1"] = go.layout.Template(
    layout=go.Layout(
        font=dict(family="sans-serif", size=9),
    )
)

GRID_NAME_TO_SHIFT_X = {
    "power": 0,
    "water": 0.0003,
    "gas": 0.0006,
    "None": 0.0003,
    None: 0.0003,
}
GRID_NAME_TO_SHIFT_Y = {
    "power": 0,
    "water": 0.0003,
    "gas": 0.0006,
    "None": -0.0003,
    None: -0.0003,
}


def _retr_grid_name(grid):
    if isinstance(grid, list):
        return "None"
    return grid.name


[docs] def plot_network( network: mm.Network, color_df=None, color_name=None, color_legend_text=None, title=None, plot_node_characteristics=True, template="plotly_white+publish", without_nodes=False, use_monee_positions=False, write_to="net.pdf", ): """Plot a monee network using plotly. Args: network (mm.Network): _description_ color_df (_type_, optional): _description_. Defaults to None. color_name (_type_, optional): _description_. Defaults to None. color_legend_text (_type_, optional): _description_. Defaults to None. title (_type_, optional): _description_. Defaults to None. plot_node_characteristics (bool, optional): _description_. Defaults to True. template (str, optional): _description_. Defaults to "plotly_white+publish". without_nodes (bool, optional): _description_. Defaults to False. use_monee_positions (bool, optional): _description_. Defaults to False. write_to (str, optional): _description_. Defaults to "net.pdf". Returns: _type_: the plotly figure """ graph: nx.Graph = network._network_internal pos = {} if not use_monee_positions: pos = nxd.pygraphviz_layout(graph, prog="fdp") x_edges = [] y_edges = [] color_edges = [] cp_edge = [] for from_node, to_node, uid in graph.edges: from_m_node = network.node_by_id(from_node) to_m_node = network.node_by_id(to_node) if use_monee_positions: add_to_from_x = GRID_NAME_TO_SHIFT_X[_retr_grid_name(from_m_node.grid)] add_to_from_y = GRID_NAME_TO_SHIFT_Y[_retr_grid_name(from_m_node.grid)] add_to_to_x = GRID_NAME_TO_SHIFT_X[_retr_grid_name(to_m_node.grid)] add_to_to_y = GRID_NAME_TO_SHIFT_Y[_retr_grid_name(to_m_node.grid)] x0, y0 = ( from_m_node.position[0] + add_to_from_x, from_m_node.position[1] + add_to_from_y, ) x1, y1 = ( to_m_node.position[0] + add_to_to_x, to_m_node.position[1] + add_to_to_y, ) pos[from_node] = (x0, y0) pos[to_node] = (x1, y1) else: x0, y0 = pos[from_node] x1, y1 = pos[to_node] if color_df is not None: color_data = 0 color_data_list = list( color_df.loc[ color_df["id"] == f"branch:({from_node}, {to_node}, {uid})" ][color_name] ) if len(color_data_list) > 0: color_data = color_data_list[0] color_edges.append(color_data) x_edges.append([x0, x1, None]) y_edges.append([y0, y1, None]) branch = network.get_branch_between(from_node, to_node) cp_edge.append(isinstance(branch.model, mm.MultiGridBranchModel)) node_x_power = [] node_y_power = [] node_color_power = [] node_text_power = [] node_x_heat = [] node_y_heat = [] node_color_heat = [] node_text_heat = [] node_x_gas = [] node_y_gas = [] node_color_gas = [] node_text_gas = [] node_cp_x = [] node_cp_y = [] node_color_cp = [] node_text_cp = [] for node in graph.nodes: node_id = f"node:{node}" x, y = pos[node] node_data = graph.nodes[node] int_node = node_data["internal_node"] color_data = 0 if color_df is not None: color_data_list = list(color_df.loc[color_df["id"] == node_id][color_name]) if len(color_data_list) > 0: color_data = color_data_list[0] if not int_node.independent: node_cp_x.append(x) node_cp_y.append(y) node_color_cp.append(color_data) node_text = "" node_text_cp.append(node_text) elif "Water" in str(type(int_node.grid)): node_x_heat.append(x) node_y_heat.append(y) node_color_heat.append(color_data) node_text = "" if plot_node_characteristics: node_text = f"<b>{round(mm.value(int_node.model.t_k), 2)}</b>" node_text_heat.append(node_text) elif "Gas" in str(type(int_node.grid)): node_x_gas.append(x) node_y_gas.append(y) node_color_gas.append(color_data) node_text = "" if plot_node_characteristics: node_text = f"<b>{round(mm.value(int_node.model.mass_flow), 2)}</b>" node_text_gas.append(node_text) elif "Power" in str(type(int_node.grid)): node_x_power.append(x) node_y_power.append(y) node_color_power.append(color_data) node_text = "" if plot_node_characteristics: node_text = f"<b>{round(mm.value(int_node.model.p_mw), 2)}</b>" node_text_power.append(node_text) max_color_val = max( color_edges if without_nodes else node_color_gas + node_color_cp + node_color_heat + node_color_power + color_edges ) edge_traces = [] coloraxis_v = None if color_df is None else "coloraxis" for i in range(len(x_edges)): edge_text = "" if color_df is None else f"{color_edges[i]}" edge_traces.append( go.Scatter( x=x_edges[i], y=y_edges[i], line=dict( dash="dash" if cp_edge[i] else "solid", width=3, color="rgb(0,0,0)" if color_df is None else px.colors.sample_colorscale( px.colors.sequential.Sunsetdark, (color_edges[i] / max_color_val) + min(color_edges), )[0], ), hoverinfo="text", mode="lines", text=edge_text, showlegend=False, marker=dict( coloraxis=coloraxis_v, ), ) ) edge_traces.append( go.Scatter( x=[None], y=[None], mode="lines", line=dict(color="black", width=3, dash="solid"), name="Branches", showlegend=True, ) ) edge_traces.append( go.Scatter( x=[None], y=[None], mode="lines", line=dict(color="black", width=3, dash="dash"), name="CP Branches", showlegend=True, ) ) # cp node_trace_cp = go.Scatter( x=node_cp_x, y=node_cp_y, mode="markers+text", textposition="top center", hoverinfo="text", text=node_text_cp, legendgroup="points", showlegend=True, name="CP", marker=dict( color=node_color_cp, symbol="diamond", size=12, coloraxis=coloraxis_v, line=dict(width=3, color="#616161"), ), ) # heat node_trace_heat = go.Scatter( x=node_x_heat, y=node_y_heat, mode="markers+text", textposition="top center", hoverinfo="text", text=node_text_heat, legendgroup="points", showlegend=True, name="Heat", marker=dict( color=node_color_heat, symbol="pentagon", size=12, coloraxis=coloraxis_v, line=dict(width=3, color="#d62728"), ), ) # power node_trace_power = go.Scatter( x=node_x_power, y=node_y_power, mode="markers+text", textposition="top center", hoverinfo="text", text=node_text_power, legendgroup="points", showlegend=True, name="Electricity", marker=dict( color=node_color_power, symbol="square", size=12, coloraxis=coloraxis_v, line=dict(width=3, color="#2ca02c"), ), ) # gas node_trace_gas = go.Scatter( x=node_x_gas, y=node_y_gas, mode="markers+text", textposition="top center", hoverinfo="text", text=node_text_gas, legendgroup="points", showlegend=True, name="Gas", marker=dict( color=node_color_gas, symbol="triangle-up", size=12, coloraxis=coloraxis_v, line=dict(width=3, color="#1f77b4"), ), ) fig = go.Figure( data=edge_traces + ( [ go.Scatter( x=[None], y=[None], mode="markers", marker=dict( coloraxis=coloraxis_v, showscale=True, ), hoverinfo="none", ) ] if without_nodes else [ node_trace_heat, node_trace_power, node_trace_gas, node_trace_cp, ] ), layout=go.Layout( title=title, hovermode="closest", xaxis=dict(showgrid=False, zeroline=False, showticklabels=False), yaxis=dict(showgrid=False, zeroline=False, showticklabels=False), template=template, ), ) fig.update_layout( height=400, width=600, margin={"l": 20, "b": 30, "r": 10, "t": 30}, xaxis_title="", legend={"title": color_legend_text}, yaxis_title="", title=title, coloraxis_colorbar=dict( title=color_legend_text, ), ) if color_df is not None: fig.layout.coloraxis.showscale = True fig.layout.coloraxis.colorscale = "Sunsetdark" fig.layout.coloraxis.reversescale = False fig.layout.coloraxis.colorbar.thickness = 15 fig.layout.coloraxis.colorbar.xanchor = "left" fig.layout.coloraxis.colorbar.outlinewidth = 2 fig.layout.coloraxis.colorbar.outlinecolor = "#888" fig.layout.coloraxis.cmin = min( node_color_gas + node_color_cp + node_color_heat + node_color_power + color_edges ) fig.layout.coloraxis.cmax = max_color_val if write_to is not None: fig.write_image(write_to) return fig