1
|
|
|
import os |
2
|
|
|
import matplotlib.colors as mcolors |
3
|
|
|
import matplotlib.pyplot as plt |
4
|
|
|
import numpy as np |
5
|
|
|
import pandas as pd |
6
|
|
|
|
7
|
|
|
# creates the icons in the grid view of the documentation |
8
|
|
|
|
9
|
|
|
|
10
|
|
|
def hex_from_rgb(rgb): |
11
|
|
|
"""makes rgb to hex""" |
12
|
|
|
return "#{:02X}{:02X}{:02X}".format( |
13
|
|
|
int(rgb[0] * 255), int(rgb[1] * 255), int(rgb[2] * 255) |
14
|
|
|
) |
15
|
|
|
|
16
|
|
|
|
17
|
|
|
# colors of the color palette |
18
|
|
|
dark_palette = { |
19
|
|
|
"color1": "#1F567D", |
20
|
|
|
"color2": "#8AA8A1", |
21
|
|
|
"color3": "#FA8334", |
22
|
|
|
"color4": "#FF006E", |
23
|
|
|
"color5": "#FFFD77", |
24
|
|
|
} |
25
|
|
|
|
26
|
|
|
# crates light mode color palet |
27
|
|
|
light_palette = {"color1": dark_palette["color1"]} |
28
|
|
|
for key in ["color2", "color3", "color4", "color5"]: |
29
|
|
|
rgb = mcolors.to_rgb(dark_palette[key]) |
30
|
|
|
new_rgb = [0.7 * c + 0.3 for c in rgb] |
31
|
|
|
light_palette[key] = hex_from_rgb(new_rgb) |
32
|
|
|
|
33
|
|
|
|
34
|
|
|
def draw_lin_vs_mixed_int(mode="dark"): |
35
|
|
|
""" |
36
|
|
|
draws plot for the linear optimization vs. Mix Integer section |
37
|
|
|
""" |
38
|
|
|
if mode == "dark": |
39
|
|
|
palette = dark_palette |
40
|
|
|
bg_color = "#121212" |
41
|
|
|
text_color = "#FFFFFF" |
42
|
|
|
else: |
43
|
|
|
palette = light_palette |
44
|
|
|
bg_color = "#FFFFFF" |
45
|
|
|
text_color = "#000000" |
46
|
|
|
|
47
|
|
|
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5)) |
48
|
|
|
fig.patch.set_facecolor(bg_color) |
49
|
|
|
|
50
|
|
|
for ax in [ax1, ax2]: |
51
|
|
|
ax.set_facecolor(bg_color) |
52
|
|
|
ax.tick_params(colors=text_color) |
53
|
|
|
for spine in ax.spines.values(): |
54
|
|
|
spine.set_color(text_color) |
55
|
|
|
|
56
|
|
|
# linear function |
57
|
|
|
x = np.linspace(-10, 10, 400) |
58
|
|
|
y = 2 * x + 1 |
59
|
|
|
ax1.plot(x, y, color=palette["color1"], linewidth=2) |
60
|
|
|
ax1.set_title("Linear Programming", color=text_color, fontsize=14) |
61
|
|
|
ax1.set_xticks([]) |
62
|
|
|
ax1.set_yticks([]) |
63
|
|
|
|
64
|
|
|
# function including a jump |
65
|
|
|
x_left = np.linspace(-10, -0.01, 200) |
66
|
|
|
x_right = np.linspace(0, 10, 200) |
67
|
|
|
y_left = 2 * x_left + 1 |
68
|
|
|
y_right = 2 * x_right + 1 + 5 |
69
|
|
|
|
70
|
|
|
ax2.plot(x_left, y_left, color=palette["color1"], linewidth=2) |
71
|
|
|
ax2.plot(x_right, y_right, color=palette["color3"], linewidth=2) |
72
|
|
|
|
73
|
|
|
# setting maker for the jump |
74
|
|
|
ax2.plot( |
75
|
|
|
x_left[-1], |
76
|
|
|
y_left[-1], |
77
|
|
|
marker="o", |
78
|
|
|
markersize=8, |
79
|
|
|
markerfacecolor=bg_color, |
80
|
|
|
markeredgecolor=palette["color4"], |
81
|
|
|
markeredgewidth=2, |
82
|
|
|
) |
83
|
|
|
ax2.plot( |
84
|
|
|
x_right[0], |
85
|
|
|
y_right[0], |
86
|
|
|
marker="o", |
87
|
|
|
markersize=8, |
88
|
|
|
markerfacecolor=palette["color4"], |
89
|
|
|
markeredgecolor=palette["color4"], |
90
|
|
|
) |
91
|
|
|
|
92
|
|
|
ax2.set_title("Mixed-Integer Problem", color=text_color, fontsize=14) |
93
|
|
|
ax2.set_xticks([]) |
94
|
|
|
ax2.set_yticks([]) |
95
|
|
|
|
96
|
|
|
plt.tight_layout() |
97
|
|
|
|
98
|
|
|
# save the plot |
99
|
|
|
if mode == "dark": |
100
|
|
|
|
101
|
|
|
plt.savefig("lin_vs_mixed_int_plot_dark.png") |
102
|
|
|
if mode == "light": |
103
|
|
|
|
104
|
|
|
plt.savefig("lin_vs_mixed_int_plot_light.png") |
105
|
|
|
|
106
|
|
|
|
107
|
|
|
def draw_timeline(mode="dark", savefig_filename=None): |
108
|
|
|
""" |
109
|
|
|
draws timeline for the multiperiod icon |
110
|
|
|
""" |
111
|
|
|
if mode == "dark": |
112
|
|
|
palette = dark_palette |
113
|
|
|
bg_color = "#121212" |
114
|
|
|
text_color = "#FFFFFF" |
115
|
|
|
else: |
116
|
|
|
palette = light_palette |
117
|
|
|
bg_color = "#FFFFFF" |
118
|
|
|
text_color = "#000000" |
119
|
|
|
|
120
|
|
|
fig, ax = plt.subplots(figsize=(10, 3)) |
121
|
|
|
fig.patch.set_facecolor(bg_color) |
122
|
|
|
ax.set_facecolor(bg_color) |
123
|
|
|
|
124
|
|
|
for spine in ax.spines.values(): |
125
|
|
|
spine.set_visible(False) |
126
|
|
|
ax.tick_params( |
127
|
|
|
left=False, bottom=False, labelbottom=False, labelleft=False |
128
|
|
|
) |
129
|
|
|
|
130
|
|
|
years = list(range(2020, 2031)) |
131
|
|
|
|
132
|
|
|
# draw line |
133
|
|
|
ax.plot( |
134
|
|
|
[years[0], years[-1]], [0, 0], color=palette["color1"], linewidth=2 |
135
|
|
|
) |
136
|
|
|
|
137
|
|
|
# set markings for every year |
138
|
|
|
for i, year in enumerate(years): |
139
|
|
|
ax.plot(year, 0, marker="o", markersize=8, color=palette["color3"]) |
140
|
|
|
ax.text( |
141
|
|
|
year, |
142
|
|
|
-0.3, |
143
|
|
|
str(year), |
144
|
|
|
ha="center", |
145
|
|
|
va="top", |
146
|
|
|
color=text_color, |
147
|
|
|
fontsize=10, |
148
|
|
|
) |
149
|
|
|
ax.text( |
150
|
|
|
year, |
151
|
|
|
0.3, |
152
|
|
|
f"Period {i+1}", |
153
|
|
|
ha="center", |
154
|
|
|
va="bottom", |
155
|
|
|
color=text_color, |
156
|
|
|
fontsize=10, |
157
|
|
|
) |
158
|
|
|
|
159
|
|
|
# Set title |
160
|
|
|
ax.text( |
161
|
|
|
(years[0] + years[-1]) / 2, |
162
|
|
|
0.8, |
163
|
|
|
"Multi-period Optimization", |
164
|
|
|
ha="center", |
165
|
|
|
va="bottom", |
166
|
|
|
color=text_color, |
167
|
|
|
fontsize=14, |
168
|
|
|
fontweight="bold", |
169
|
|
|
) |
170
|
|
|
|
171
|
|
|
ax.set_xlim(years[0] - 1, years[-1] + 1) |
172
|
|
|
ax.set_ylim(-1, 1) |
173
|
|
|
|
174
|
|
|
plt.tight_layout() |
175
|
|
|
|
176
|
|
|
# save png |
177
|
|
|
if mode == "dark": |
178
|
|
|
|
179
|
|
|
plt.savefig("timeline_dark.png") |
180
|
|
|
if mode == "light": |
181
|
|
|
|
182
|
|
|
plt.savefig("timeline_light.png") |
183
|
|
|
|
184
|
|
|
|
185
|
|
|
def plot_dispatch_invest(csv_path, mode="dark"): |
186
|
|
|
""" |
187
|
|
|
draws a demand timeseries next to an bar plot symbolizing the investment decisions |
188
|
|
|
""" |
189
|
|
|
|
190
|
|
|
df = pd.read_csv(csv_path) |
191
|
|
|
|
192
|
|
|
if "Time" not in df.columns: |
193
|
|
|
df["Time"] = pd.date_range( |
194
|
|
|
start="2020-01-01", periods=len(df), freq="H" |
195
|
|
|
) |
196
|
|
|
|
197
|
|
|
if mode.lower() == "dark": |
198
|
|
|
palette = dark_palette |
199
|
|
|
bg_color = "#121212" |
200
|
|
|
text_color = "#FFFFFF" |
201
|
|
|
else: |
202
|
|
|
palette = light_palette |
203
|
|
|
bg_color = "#FFFFFF" |
204
|
|
|
text_color = "#000000" |
205
|
|
|
|
206
|
|
|
# create two subplots |
207
|
|
|
fig, axs = plt.subplots(1, 2, figsize=(16, 6)) |
208
|
|
|
fig.patch.set_facecolor(bg_color) |
209
|
|
|
|
210
|
|
|
ax1 = axs[0] |
211
|
|
|
ax1.set_facecolor(bg_color) |
212
|
|
|
for spine in ax1.spines.values(): |
213
|
|
|
spine.set_color(text_color) |
214
|
|
|
ax1.tick_params(colors=text_color, labelleft=False) |
215
|
|
|
|
216
|
|
|
# draw dispatch timeseries |
217
|
|
|
ax1.plot( |
218
|
|
|
df["Time"], |
219
|
|
|
df["demand_th"], |
220
|
|
|
marker="o", |
221
|
|
|
linestyle="-", |
222
|
|
|
color=palette["color1"], |
223
|
|
|
linewidth=2, |
224
|
|
|
) |
225
|
|
|
ax1.set_title("Dispatch Time Series (kW)", color=text_color, fontsize=14) |
226
|
|
|
ax1.set_xlabel("Time", color=text_color) |
227
|
|
|
ax1.set_ylabel("kW", color=text_color) |
228
|
|
|
|
229
|
|
|
avg_pv = df["pv"].mean() if "pv" in df.columns else 0 |
230
|
|
|
avg_wind = df["wind"].mean() if "wind" in df.columns else 0 |
231
|
|
|
avg_heatpump = 0.3 |
232
|
|
|
avg_solarthermie = 0.09 |
233
|
|
|
|
234
|
|
|
labels = ["PV", "Wind", "Heat Pump", "Solarthermie"] |
235
|
|
|
values = [avg_pv, avg_wind, avg_heatpump, avg_solarthermie] |
236
|
|
|
|
237
|
|
|
bar_colors = [ |
238
|
|
|
palette["color3"], |
239
|
|
|
palette["color4"], |
240
|
|
|
palette["color2"], |
241
|
|
|
palette["color5"], |
242
|
|
|
] |
243
|
|
|
|
244
|
|
|
ax2 = axs[1] |
245
|
|
|
ax2.set_facecolor(bg_color) |
246
|
|
|
for spine in ax2.spines.values(): |
247
|
|
|
spine.set_color(text_color) |
248
|
|
|
ax2.tick_params(colors=text_color, labelleft=False) |
249
|
|
|
|
250
|
|
|
bars = ax2.bar( |
251
|
|
|
labels, values, color=bar_colors, edgecolor=text_color, linewidth=1.5 |
252
|
|
|
) |
253
|
|
|
|
254
|
|
|
ax2.set_title("Investment Technology Sizes", color=text_color, fontsize=14) |
255
|
|
|
ax2.set_ylabel("Average Value", color=text_color, fontsize=14) |
256
|
|
|
|
257
|
|
|
fig.suptitle( |
258
|
|
|
"Dispatch vs. Invest-Optimization", color=text_color, fontsize=16 |
259
|
|
|
) |
260
|
|
|
|
261
|
|
|
plt.tight_layout(rect=[0, 0, 1, 0.95]) |
262
|
|
|
|
263
|
|
|
# save plots |
264
|
|
|
if mode == "dark": |
265
|
|
|
|
266
|
|
|
plt.savefig("plot_dispatch_invest_dark.png") |
267
|
|
|
if mode == "light": |
268
|
|
|
|
269
|
|
|
plt.savefig("plot_dispatch_invest_light.png") |
270
|
|
|
|
271
|
|
|
|
272
|
|
|
# uncomment he needed funczion to redraw the icons |
273
|
|
|
|
274
|
|
|
# draw_lin_vs_mixed_int('light') |
275
|
|
|
# draw_lin_vs_mixed_int('dark') |
276
|
|
|
|
277
|
|
|
# draw_timeline("dark") # Speichert als "timeline_dark.png" |
278
|
|
|
# draw_timeline("light") # Speichert als "timeline_light.png" |
279
|
|
|
|
280
|
|
|
file_name = os.path.realpath( |
281
|
|
|
os.path.join( |
282
|
|
|
__file__, |
283
|
|
|
"..", |
284
|
|
|
"..", |
285
|
|
|
"..", |
286
|
|
|
"..", |
287
|
|
|
"tests/test_outputlib/input_data.csv", |
288
|
|
|
) |
289
|
|
|
) |
290
|
|
|
plot_dispatch_invest(file_name, mode="light") |
291
|
|
|
plot_dispatch_invest(file_name, mode="dark") |
292
|
|
|
|