Currently we have multiple graphics for different energytypes but still not for all buses. It is difficulat to say what Bus is actually the interesting one for the user. So instead we can just make one graphic in which any bus is selectable. This is done here. Also it would be nice for a report if this graphic was duplicable, so two buses could be viewed in parallel.
'''So this graphic could be used for taking a look into all timeseries. Only Buses are available if any flow is above 0.1, Only flows are shown that are above 0.1'''
import plotly.graph_objects as go
from itertools import cycle
import re
import pandas as pd
from oemof.solph import EnergySystem, Bus
# System laden
ensys = EnergySystem()
ensys.restore(dpath=r"C:\pythonstuff\Jupyter", filename="results_dump")
# Ergebnisse extrahieren
results = ensys.results
# Alle Busse holen
buses = [n for n in ensys.nodes if isinstance(n, Bus)]
bus_labels = [str(b.label) for b in buses]
# Farben für die Kanten (colors were chose by chat GPT)
color_cycle_template = [
"#1f77b4", "#ff7f0e", "#2ca02c", "#d62728",
"#9467bd", "#8c564b", "#e377c2", "#7f7f7f",
"#bcbd22", "#17becf"
]
fig = go.Figure()
visibility_matrix = [] # keep track of which traces belong to which bus
for bus_label in bus_labels:
flow_data = {}
for key, entry in results["Main"].items():
if isinstance(entry, dict) and "sequences" in entry:
if "flow" in entry["sequences"].columns:
if bus_label in str(key):
flow_data[str(key)] = entry["sequences"]["flow"]
edge_colors = {}
trace_visibility = []
# reset color cycle for each bus
color_cycle = cycle(color_cycle_template)
for key, flow in flow_data.items():
matches = re.findall(r"'(.*?)'", key)
if len(matches) < 2:
continue
start, end = matches[0], matches[1]
edge_key = f"{start}->{end}"
if edge_key not in edge_colors:
edge_colors[edge_key] = next(color_cycle)
color = edge_colors[edge_key]
if flow.sum()>0.01:
if end == bus_label:
fig.add_trace(go.Scatter(
x=flow.index,
y=flow.clip(lower=0),
mode='none',
fill='tozeroy',
stackgroup=f'{bus_label}_inputs',
name=f'from {start}',
fillcolor=f'rgba{tuple(int(color.lstrip("#")[i:i+2],16) for i in (0,2,4)) + (0.3,)}',
line=dict(color=color),
visible=False,
# ----- Hover customization -----
hovertemplate="from " + start + ": %{y:.1f} kWh<extra></extra>",
hoverlabel=dict(align="left")
))
trace_visibility.append(True)
elif start == bus_label:
fig.add_trace(go.Scatter(
x=flow.index,
y=flow.clip(lower=0),
mode='lines',
stackgroup=f'{bus_label}_outputs',
line=dict(color=color, width=2),
name=f'to {end}',
fill='none',
visible=False,
# ----- Hover customization -----
hovertemplate="to " + end + ": %{y:.1f} kWh<extra></extra>",
hoverlabel=dict(align="left")
))
trace_visibility.append(True)
visibility_matrix.append(trace_visibility)
# Filter only buses that actually have traces
valid_bus_labels = []
valid_visibility_matrix = []
for bus_label, traces in zip(bus_labels, visibility_matrix):
if len(traces) > 0: # keep only non-empty buses
valid_bus_labels.append(bus_label)
valid_visibility_matrix.append(traces)
# Set first valid bus visible
if valid_visibility_matrix:
for i in range(len(valid_visibility_matrix[0])):
fig.data[i].visible = True
# Dropdown menu only for valid buses
buttons = []
for i, bus_label in enumerate(valid_bus_labels):
vis = [False] * len(fig.data)
start_idx = sum(len(tr) for tr in valid_visibility_matrix[:i])
for k in range(len(valid_visibility_matrix[i])):
vis[start_idx + k] = True
buttons.append(dict(
label=bus_label,
method="update",
args=[{"visible": vis},{"title": {"text": f"Energy flows in {bus_label}"}}]
))
initial_title = "Bus Flows"
if valid_bus_labels:
initial_title = f"Energy flows for {valid_bus_labels[0]}"
fig.update_layout(
title={"text": initial_title},
xaxis_title="",
yaxis_title="Energy flow [kWh]",
hovermode="x unified",
legend_title="Time series",
updatemenus=[dict(
active=0,
buttons=buttons,
x=1.26,
y=1.2
)]
)
fig.show()
New graphics have been postponed due to likely switching from
MVSto rawoemof, which will change the post-processing workflow. This issue is to keep track of the new graphics that have been proposed.Originally posted by @mstich0 in #334
Originally posted by @mstich0 in #334
Originally posted by @FredericHirschmueller in #334