8
8
from ..misc .str_handler import clean_strings
9
9
from ..common import commons
10
10
11
- from .postprocessing import get_imports , get_plot_data , filter_by_zone
11
+ from .postprocessing import get_imports , get_plot_data , filter_by_zone , filter_by_tech , filter_by_storage
12
12
13
13
14
- def plot_dispatch (demand , plotdata , level = None , curtailment = None , rng = None ,
14
+ def plot_dispatch (demand , plotdata , level = None , curtailment = None , shedload = None , rng = None ,
15
15
alpha = None , figsize = (13 , 6 )):
16
16
"""
17
17
Function that plots the dispatch data and the reservoir level as a cumulative sum
18
18
19
19
:param demand: Pandas Series with the demand curve
20
20
:param plotdata: Pandas Dataframe with the data to be plotted. Negative columns should be at the beginning. Output of the function GetPlotData
21
- :param level: Optional pandas series with an aggregated reservoir level for the considered zone.
21
+ :param level: Optional pandas series/dataframe with an (dis) aggregated reservoir level for the considered zone.
22
22
:param curtailment: Optional pandas series with the value of the curtailment
23
+ :param shedload: Optional pandas series with the value of the shed load
23
24
:param rng: Indexes of the values to be plotted. If undefined, the first week is plotted
24
25
"""
25
26
import matplotlib .patches as mpatches
@@ -34,7 +35,7 @@ def plot_dispatch(demand, plotdata, level=None, curtailment=None, rng=None,
34
35
raise ValueError ()
35
36
elif rng [0 ] < plotdata .index [0 ] or rng [0 ] > plotdata .index [- 1 ] or rng [- 1 ] < plotdata .index [0 ] or rng [- 1 ] > \
36
37
plotdata .index [- 1 ]:
37
- logging .warn ('Plotting range is not properly defined, considering the first simulated week' )
38
+ logging .warning ('Plotting range is not properly defined, considering the first simulated week' )
38
39
pdrng = plotdata .index [:min (len (plotdata ) - 1 , 7 * 24 )]
39
40
else :
40
41
pdrng = rng
@@ -74,22 +75,50 @@ def plot_dispatch(demand, plotdata, level=None, curtailment=None, rng=None,
74
75
75
76
fig .suptitle ('Power dispatch for zone ' + demand .name [1 ])
76
77
78
+ # Define labels, patches and colors
77
79
labels = []
78
80
patches = []
79
81
colorlist = []
80
82
81
- # # Plot negative values:
83
+ # Plot reservoir levels (either separated or as one value)
84
+ if level is not None :
85
+ if isinstance (level , pd .DataFrame ):
86
+ cols_lvl = level .columns .tolist ()
87
+ sumplot_lev = level [cols_lvl [0 :]].cumsum (axis = 1 )
88
+ sumplot_lev ['zero' ] = 0
89
+ sumplot_lev = sumplot_lev [['zero' ] + sumplot_lev .columns [:- 1 ].tolist ()]
90
+ print ('Its dataframe' )
91
+ for j in range (len (sumplot_lev .columns ) - 1 ):
92
+ col3 = sumplot_lev .columns [j ]
93
+ col4 = sumplot_lev .columns [j + 1 ]
94
+ rez_color = commons ['colors' ][col4 ]
95
+ rez_hatch = commons ['hatches' ][col4 ]
96
+ axes [1 ].fill_between (pdrng , sumplot_lev .loc [pdrng , col3 ], sumplot_lev .loc [pdrng , col4 ],
97
+ facecolor = rez_color , alpha = alpha , hatch = rez_hatch )
98
+ labels .append (col4 )
99
+ patches .append (mpatches .Patch (facecolor = rez_color , alpha = alpha , hatch = rez_hatch , label = col4 ))
100
+ colorlist .append (rez_color )
101
+ elif isinstance (level , pd .Series ):
102
+ # Create right axis:
103
+ axes [1 ].plot (pdrng , level [pdrng ], color = 'k' , alpha = alpha , linestyle = ':' )
104
+ axes [1 ].fill_between (pdrng , 0 , level [pdrng ],
105
+ facecolor = commons ['colors' ]['WAT' ], alpha = .3 )
106
+ axes [1 ].set_ylabel ('Level [TWh]' )
107
+ axes [1 ].yaxis .label .set_fontsize (12 )
108
+ line_SOC = mlines .Line2D ([], [], color = 'black' , alpha = alpha , label = 'Reservoir' , linestyle = ':' )
109
+
110
+ # Plot negative values:
82
111
for j in range (idx_zero ):
83
112
col1 = sumplot_neg .columns [j ]
84
113
col2 = sumplot_neg .columns [j + 1 ]
85
114
color = commons ['colors' ][col2 ]
86
115
hatch = commons ['hatches' ][col2 ]
87
116
axes [0 ].fill_between (pdrng , sumplot_neg .loc [pdrng , col1 ], sumplot_neg .loc [pdrng , col2 ], facecolor = color ,
88
- alpha = alpha ,
89
- hatch = hatch )
90
- labels .append (col1 )
91
- patches .append (mpatches .Patch (facecolor = color , alpha = alpha , hatch = hatch , label = col2 ))
92
- colorlist .append (color )
117
+ alpha = alpha , hatch = hatch )
118
+ if col2 not in labels :
119
+ labels .append (col1 )
120
+ patches .append (mpatches .Patch (facecolor = color , alpha = alpha , hatch = hatch , label = col2 ))
121
+ colorlist .append (color )
93
122
94
123
# Plot Positive values:
95
124
for j in range (len (sumplot_pos .columns ) - 1 ):
@@ -117,22 +146,32 @@ def plot_dispatch(demand, plotdata, level=None, curtailment=None, rng=None,
117
146
axes [0 ].set_ylabel ('Power [GW]' )
118
147
axes [0 ].yaxis .label .set_fontsize (12 )
119
148
120
- if level is not None :
121
- # Create right axis:
122
- axes [1 ].plot (pdrng , level [pdrng ], color = 'k' , alpha = alpha , linestyle = ':' )
123
- axes [1 ].fill_between (pdrng , 0 , level [pdrng ],
124
- facecolor = commons ['colors' ]['WAT' ], alpha = .3 )
125
-
126
- axes [1 ].set_ylabel ('Level [TWh]' )
127
- axes [1 ].yaxis .label .set_fontsize (12 )
128
- line_SOC = mlines .Line2D ([], [], color = 'black' , alpha = alpha , label = 'Reservoir' , linestyle = ':' )
149
+ if isinstance (shedload , pd .Series ):
150
+ if not shedload .index .equals (demand .index ):
151
+ logging .error ('The shedload time series must have the same index as the demand' )
152
+ sys .exit (1 )
153
+ reduced_demand = demand - shedload
154
+ axes [0 ].plot (pdrng , reduced_demand [pdrng ], color = 'k' , alpha = alpha , linestyle = 'dashed' )
155
+ line_shedload = mlines .Line2D ([], [], color = 'black' , alpha = alpha , label = 'Shed Load' , linestyle = 'dashed' )
129
156
130
157
line_demand = mlines .Line2D ([], [], color = 'black' , label = 'Load' )
131
- plt .legend (handles = [line_demand ] + patches [::- 1 ], loc = 4 )
132
- if level is None :
133
- plt .legend (handles = [line_demand ] + patches [::- 1 ], loc = 4 )
158
+ # plt.legend(handles=[line_demand] + patches[::-1], loc=4)
159
+
160
+ if shedload is None and level is None :
161
+ plt .legend (handles = [line_demand ] + patches [::- 1 ], loc = 4 , bbox_to_anchor = (1.2 , 0.5 ))
162
+ if shedload is None :
163
+ plt .legend (handles = [line_demand ] + [line_SOC ] + patches [::- 1 ], loc = 4 , bbox_to_anchor = (1.2 , 0.5 ))
164
+ elif level is None :
165
+ plt .legend (handles = [line_demand ] + [line_shedload ] + patches [::- 1 ], loc = 4 , bbox_to_anchor = (1.2 , 0.5 ))
166
+ axes [0 ].fill_between (demand .index , demand , reduced_demand , facecolor = "none" , hatch = "X" , edgecolor = "k" ,
167
+ linestyle = 'dashed' )
134
168
else :
135
- plt .legend (title = 'Dispatch for ' + demand .name [1 ], handles = [line_demand ] + [line_SOC ] + patches [::- 1 ], loc = 4 )
169
+ plt .legend (title = 'Dispatch for ' + demand .name [1 ], handles = [line_demand ] + [line_shedload ] + [line_SOC ] +
170
+ patches [::- 1 ], loc = 4 , bbox_to_anchor = (1.2 , 0.5 ))
171
+ axes [0 ].fill_between (demand .index , demand , reduced_demand , facecolor = "none" , hatch = "X" , edgecolor = "k" ,
172
+ linestyle = 'dashed' )
173
+
174
+ plt .subplots_adjust (right = 0.8 )
136
175
plt .show ()
137
176
138
177
@@ -249,6 +288,7 @@ def plot_energy_zone_fuel(inputs, results, PPindicators):
249
288
demand = inputs ['param_df' ]['Demand' ]['DA' ].sum () / 1E6
250
289
ax .barh (demand , left = ax .get_xticks () - 0.4 , width = [0.8 ] * len (demand ), height = ax .get_ylim ()[1 ] * 0.005 , linewidth = 2 ,
251
290
color = 'k' )
291
+ plt .show ()
252
292
return ax
253
293
254
294
@@ -274,7 +314,7 @@ def plot_zone_capacities(inputs, plot=True):
274
314
PowerCapacity = PowerCapacity [cols ]
275
315
if plot :
276
316
colors = [commons ['colors' ][tech ] for tech in PowerCapacity .columns ]
277
- ax = PowerCapacity .plot (kind = "bar" , figsize = (12 , 8 ), stacked = True , color = colors , alpha = 1.0 , legend = 'reverse' ,
317
+ ax = PowerCapacity .plot (kind = "bar" , figsize = (12 , 8 ), stacked = True , color = colors , alpha = 0.8 , legend = 'reverse' ,
278
318
title = 'Installed capacity per zone (the horizontal lines indicate the peak demand)' )
279
319
ax .set_ylabel ('Capacity [MW]' )
280
320
demand = inputs ['param_df' ]['Demand' ]['DA' ].max ()
@@ -304,9 +344,22 @@ def plot_zone(inputs, results, z='', rng=None, rug_plot=True):
304
344
305
345
plotdata = get_plot_data (inputs , results , z ) / 1000 # GW
306
346
347
+ aggregation = False
307
348
if 'OutputStorageLevel' in results :
308
- level = filter_by_zone (results ['OutputStorageLevel' ], inputs , z ) / 1E6 # TWh
309
- level = level .sum (axis = 1 )
349
+ lev = filter_by_zone (results ['OutputStorageLevel' ], inputs , z ) / 1E6 # TWh
350
+ level = filter_by_storage (lev , inputs , StorageSubset = 's' )
351
+ levels = pd .DataFrame (index = results ['OutputStorageLevel' ].index ,columns = inputs ['sets' ]['t' ])
352
+ for t in ['HDAM' ,'HPHS' ,'BEVS' ,'BATS' ]:
353
+ temp = filter_by_tech (level ,inputs ,t )
354
+ levels [t ] = temp .sum (axis = 1 )
355
+ levels .dropna (axis = 1 ,inplace = True )
356
+ for col in levels .columns :
357
+ if levels [col ].max () == 0 and levels [col ].min () == 0 :
358
+ del levels [col ]
359
+ if aggregation is True :
360
+ level = level .sum (axis = 1 )
361
+ else :
362
+ level = levels
310
363
else :
311
364
level = pd .Series (0 , index = results ['OutputPower' ].index )
312
365
@@ -324,18 +377,25 @@ def plot_zone(inputs, results, z='', rng=None, rug_plot=True):
324
377
# if 'OutputShedLoad' in results:
325
378
if 'OutputShedLoad' in results and z in results ['OutputShedLoad' ]:
326
379
shed_load = results ['OutputShedLoad' ][z ] / 1000 # GW
380
+ shed_load = pd .Series (shed_load , index = demand .index ).fillna (0 )
327
381
else :
328
382
shed_load = pd .Series (0 , index = demand .index ) / 1000 # GW
329
383
diff = (sum_generation - demand + shed_load ).abs ()
330
384
if diff .max () > 0.01 * demand .max ():
331
385
logging .critical ('There is up to ' + str (
332
386
diff .max () / demand .max () * 100 ) + '% difference in the instantaneous energy balance of zone ' + z )
333
387
334
- if 'OutputCurtailedPower' in results and z in results ['OutputCurtailedPower' ]:
388
+ if 'OutputCurtailedPower' in results and z in results ['OutputCurtailedPower' ] \
389
+ and 'OutputShedLoad' in results and z in results ['OutputShedLoad' ]:
390
+ curtailment = results ['OutputCurtailedPower' ][z ] / 1000 # GW
391
+ plot_dispatch (demand , plotdata , level , curtailment = curtailment , shedload = shed_load , rng = rng , alpha = 0.8 )
392
+ elif 'OutputCurtailedPower' in results and z in results ['OutputCurtailedPower' ]:
335
393
curtailment = results ['OutputCurtailedPower' ][z ] / 1000 # GW
336
- plot_dispatch (demand , plotdata , level , curtailment = curtailment , rng = rng )
394
+ plot_dispatch (demand , plotdata , level , curtailment = curtailment , rng = rng , alpha = 0.8 )
395
+ elif 'OutputShedLoad' in results and z in results ['OutputShedLoad' ]:
396
+ plot_dispatch (demand , plotdata , level , shedload = shed_load , rng = rng , alpha = 0.8 )
337
397
else :
338
- plot_dispatch (demand , plotdata , level , rng = rng )
398
+ plot_dispatch (demand , plotdata , level , rng = rng , alpha = 0.8 )
339
399
340
400
# Generation plot:
341
401
if rug_plot :
0 commit comments