NREL-reV 0.8.7__py3-none-any.whl → 0.8.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {NREL_reV-0.8.7.dist-info → NREL_reV-0.8.9.dist-info}/METADATA +12 -10
- {NREL_reV-0.8.7.dist-info → NREL_reV-0.8.9.dist-info}/RECORD +38 -38
- {NREL_reV-0.8.7.dist-info → NREL_reV-0.8.9.dist-info}/WHEEL +1 -1
- reV/SAM/SAM.py +182 -133
- reV/SAM/econ.py +18 -14
- reV/SAM/generation.py +608 -419
- reV/SAM/windbos.py +93 -79
- reV/bespoke/bespoke.py +690 -445
- reV/bespoke/place_turbines.py +6 -6
- reV/config/project_points.py +220 -140
- reV/econ/econ.py +165 -113
- reV/econ/economies_of_scale.py +57 -34
- reV/generation/base.py +310 -183
- reV/generation/generation.py +298 -190
- reV/handlers/exclusions.py +16 -15
- reV/handlers/multi_year.py +12 -9
- reV/handlers/outputs.py +6 -5
- reV/hybrids/hybrid_methods.py +28 -30
- reV/hybrids/hybrids.py +304 -188
- reV/nrwal/nrwal.py +262 -168
- reV/qa_qc/cli_qa_qc.py +14 -10
- reV/qa_qc/qa_qc.py +217 -119
- reV/qa_qc/summary.py +228 -146
- reV/rep_profiles/rep_profiles.py +349 -230
- reV/supply_curve/aggregation.py +349 -188
- reV/supply_curve/competitive_wind_farms.py +90 -48
- reV/supply_curve/exclusions.py +138 -85
- reV/supply_curve/extent.py +75 -50
- reV/supply_curve/points.py +536 -309
- reV/supply_curve/sc_aggregation.py +366 -225
- reV/supply_curve/supply_curve.py +505 -308
- reV/supply_curve/tech_mapping.py +144 -82
- reV/utilities/__init__.py +199 -16
- reV/utilities/pytest_utils.py +8 -4
- reV/version.py +1 -1
- {NREL_reV-0.8.7.dist-info → NREL_reV-0.8.9.dist-info}/LICENSE +0 -0
- {NREL_reV-0.8.7.dist-info → NREL_reV-0.8.9.dist-info}/entry_points.txt +0 -0
- {NREL_reV-0.8.7.dist-info → NREL_reV-0.8.9.dist-info}/top_level.txt +0 -0
reV/qa_qc/summary.py
CHANGED
@@ -3,15 +3,17 @@
|
|
3
3
|
Compute and plot summary data
|
4
4
|
"""
|
5
5
|
import logging
|
6
|
-
import numpy as np
|
7
6
|
import os
|
7
|
+
|
8
|
+
import numpy as np
|
8
9
|
import pandas as pd
|
9
|
-
import plotting as mplt
|
10
10
|
import plotly.express as px
|
11
|
-
|
11
|
+
import plotting as mplt
|
12
12
|
from rex import Resource
|
13
13
|
from rex.utilities import SpawnProcessPool, parse_table
|
14
14
|
|
15
|
+
from reV.utilities import SupplyCurveField, ResourceMetaField
|
16
|
+
|
15
17
|
logger = logging.getLogger(__name__)
|
16
18
|
|
17
19
|
|
@@ -19,6 +21,7 @@ class SummarizeH5:
|
|
19
21
|
"""
|
20
22
|
reV Summary data for QA/QC
|
21
23
|
"""
|
24
|
+
|
22
25
|
def __init__(self, h5_file, group=None):
|
23
26
|
"""
|
24
27
|
Parameters
|
@@ -28,7 +31,7 @@ class SummarizeH5:
|
|
28
31
|
group : str, optional
|
29
32
|
Group within h5_file to summarize datasets for, by default None
|
30
33
|
"""
|
31
|
-
logger.info(
|
34
|
+
logger.info("QAQC Summarize initializing on: {}".format(h5_file))
|
32
35
|
self._h5_file = h5_file
|
33
36
|
self._group = group
|
34
37
|
|
@@ -73,12 +76,12 @@ class SummarizeH5:
|
|
73
76
|
sites = slice(None)
|
74
77
|
|
75
78
|
with Resource(h5_file, group=group) as f:
|
76
|
-
sites_meta = f[
|
79
|
+
sites_meta = f["meta", sites]
|
77
80
|
sites_data = f[ds_name, :, sites]
|
78
81
|
|
79
82
|
sites_summary = pd.DataFrame(sites_data, columns=sites_meta.index)
|
80
|
-
sites_summary = sites_summary.describe().T.drop(columns=[
|
81
|
-
sites_summary[
|
83
|
+
sites_summary = sites_summary.describe().T.drop(columns=["count"])
|
84
|
+
sites_summary["sum"] = sites_data.sum(axis=0)
|
82
85
|
|
83
86
|
return sites_summary
|
84
87
|
|
@@ -105,13 +108,14 @@ class SummarizeH5:
|
|
105
108
|
ds_data = f[ds_name, :]
|
106
109
|
|
107
110
|
ds_summary = pd.DataFrame(ds_data, columns=[ds_name])
|
108
|
-
ds_summary = ds_summary.describe().drop([
|
109
|
-
ds_summary.at[
|
111
|
+
ds_summary = ds_summary.describe().drop(["count"])
|
112
|
+
ds_summary.at["sum", ds_name] = ds_data.sum()
|
110
113
|
|
111
114
|
return ds_summary
|
112
115
|
|
113
|
-
def summarize_dset(
|
114
|
-
|
116
|
+
def summarize_dset(
|
117
|
+
self, ds_name, process_size=None, max_workers=None, out_path=None
|
118
|
+
):
|
115
119
|
"""
|
116
120
|
Compute dataset summary. If dataset is 2D compute temporal statistics
|
117
121
|
for each site
|
@@ -144,46 +148,52 @@ class SummarizeH5:
|
|
144
148
|
if process_size is None:
|
145
149
|
process_size = ds_shape[-1]
|
146
150
|
|
147
|
-
sites =
|
148
|
-
np.
|
149
|
-
|
150
|
-
loggers = [__name__,
|
151
|
-
with SpawnProcessPool(
|
152
|
-
|
151
|
+
sites = np.array_split(
|
152
|
+
sites, int(np.ceil(len(sites) / process_size))
|
153
|
+
)
|
154
|
+
loggers = [__name__, "reV"]
|
155
|
+
with SpawnProcessPool(
|
156
|
+
max_workers=max_workers, loggers=loggers
|
157
|
+
) as ex:
|
153
158
|
futures = []
|
154
159
|
for site_slice in sites:
|
155
|
-
futures.append(
|
156
|
-
|
157
|
-
|
158
|
-
|
160
|
+
futures.append(
|
161
|
+
ex.submit(
|
162
|
+
self._compute_sites_summary,
|
163
|
+
self.h5_file,
|
164
|
+
ds_name,
|
165
|
+
sites=site_slice,
|
166
|
+
group=self._group,
|
167
|
+
)
|
168
|
+
)
|
159
169
|
|
160
170
|
summary = [future.result() for future in futures]
|
161
171
|
|
162
172
|
summary = pd.concat(summary)
|
173
|
+
elif process_size is None:
|
174
|
+
summary = self._compute_sites_summary(self.h5_file,
|
175
|
+
ds_name,
|
176
|
+
sites=sites,
|
177
|
+
group=self._group)
|
163
178
|
else:
|
164
|
-
|
165
|
-
|
166
|
-
ds_name,
|
167
|
-
sites=sites,
|
168
|
-
group=self._group)
|
169
|
-
else:
|
170
|
-
sites = np.array_split(
|
171
|
-
sites, int(np.ceil(len(sites) / process_size)))
|
172
|
-
|
173
|
-
summary = []
|
174
|
-
for site_slice in sites:
|
175
|
-
summary.append(self._compute_sites_summary(
|
176
|
-
self.h5_file, ds_name,
|
177
|
-
sites=site_slice,
|
178
|
-
group=self._group))
|
179
|
+
sites = np.array_split(
|
180
|
+
sites, int(np.ceil(len(sites) / process_size)))
|
179
181
|
|
180
|
-
|
182
|
+
summary = []
|
183
|
+
for site_slice in sites:
|
184
|
+
summary.append(self._compute_sites_summary(
|
185
|
+
self.h5_file, ds_name,
|
186
|
+
sites=site_slice,
|
187
|
+
group=self._group))
|
181
188
|
|
182
|
-
|
189
|
+
summary = pd.concat(summary)
|
190
|
+
|
191
|
+
summary.index.name = ResourceMetaField.GID
|
183
192
|
|
184
193
|
else:
|
185
|
-
summary = self._compute_ds_summary(
|
186
|
-
|
194
|
+
summary = self._compute_ds_summary(
|
195
|
+
self.h5_file, ds_name, group=self._group
|
196
|
+
)
|
187
197
|
|
188
198
|
if out_path is not None:
|
189
199
|
summary.to_csv(out_path)
|
@@ -206,9 +216,9 @@ class SummarizeH5:
|
|
206
216
|
"""
|
207
217
|
with Resource(self.h5_file, group=self._group) as f:
|
208
218
|
meta = f.meta
|
209
|
-
if
|
210
|
-
if meta.index.name !=
|
211
|
-
meta.index.name =
|
219
|
+
if ResourceMetaField.GID not in meta:
|
220
|
+
if meta.index.name != ResourceMetaField.GID:
|
221
|
+
meta.index.name = ResourceMetaField.GID
|
212
222
|
|
213
223
|
meta = meta.reset_index()
|
214
224
|
|
@@ -223,8 +233,15 @@ class SummarizeH5:
|
|
223
233
|
return meta
|
224
234
|
|
225
235
|
@classmethod
|
226
|
-
def run(
|
227
|
-
|
236
|
+
def run(
|
237
|
+
cls,
|
238
|
+
h5_file,
|
239
|
+
out_dir,
|
240
|
+
group=None,
|
241
|
+
dsets=None,
|
242
|
+
process_size=None,
|
243
|
+
max_workers=None,
|
244
|
+
):
|
228
245
|
"""
|
229
246
|
Summarize all datasets in h5_file and dump to out_dir
|
230
247
|
|
@@ -249,19 +266,25 @@ class SummarizeH5:
|
|
249
266
|
|
250
267
|
if dsets is None:
|
251
268
|
with Resource(h5_file, group=group) as f:
|
252
|
-
dsets = [
|
253
|
-
|
269
|
+
dsets = [
|
270
|
+
dset
|
271
|
+
for dset in f.datasets
|
272
|
+
if dset not in ["meta", "time_index"]
|
273
|
+
]
|
254
274
|
elif isinstance(dsets, str):
|
255
275
|
dsets = [dsets]
|
256
276
|
|
257
277
|
summary = cls(h5_file)
|
258
278
|
for ds_name in dsets:
|
259
|
-
out_path = os.path.join(out_dir,
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
279
|
+
out_path = os.path.join(out_dir, "{}_summary.csv".format(ds_name))
|
280
|
+
summary.summarize_dset(
|
281
|
+
ds_name,
|
282
|
+
process_size=process_size,
|
283
|
+
max_workers=max_workers,
|
284
|
+
out_path=out_path,
|
285
|
+
)
|
286
|
+
|
287
|
+
out_path = os.path.basename(h5_file).replace(".h5", "_summary.csv")
|
265
288
|
out_path = os.path.join(out_dir, out_path)
|
266
289
|
summary.summarize_means(out_path=out_path)
|
267
290
|
|
@@ -270,6 +293,7 @@ class SummarizeSupplyCurve:
|
|
270
293
|
"""
|
271
294
|
Summarize Supply Curve table
|
272
295
|
"""
|
296
|
+
|
273
297
|
def __init__(self, sc_table):
|
274
298
|
self._sc_table = self._parse_summary(sc_table)
|
275
299
|
|
@@ -343,27 +367,27 @@ class SummarizeSupplyCurve:
|
|
343
367
|
|
344
368
|
sc_summary = []
|
345
369
|
sc_stat = sc_table.mean(axis=0)
|
346
|
-
sc_stat.name =
|
370
|
+
sc_stat.name = "mean"
|
347
371
|
sc_summary.append(sc_stat)
|
348
372
|
|
349
373
|
sc_stat = sc_table.std(axis=0)
|
350
|
-
sc_stat.name =
|
374
|
+
sc_stat.name = "stdev"
|
351
375
|
sc_summary.append(sc_stat)
|
352
376
|
|
353
377
|
sc_stat = sc_table.median(axis=0)
|
354
|
-
sc_stat.name =
|
378
|
+
sc_stat.name = "median"
|
355
379
|
sc_summary.append(sc_stat)
|
356
380
|
|
357
381
|
sc_stat = sc_table.min(axis=0)
|
358
|
-
sc_stat.name =
|
382
|
+
sc_stat.name = "min"
|
359
383
|
sc_summary.append(sc_stat)
|
360
384
|
|
361
385
|
sc_stat = sc_table.max(axis=0)
|
362
|
-
sc_stat.name =
|
386
|
+
sc_stat.name = "max"
|
363
387
|
sc_summary.append(sc_stat)
|
364
388
|
|
365
389
|
sc_stat = sc_table.sum(axis=0)
|
366
|
-
sc_stat.name =
|
390
|
+
sc_stat.name = "sum"
|
367
391
|
sc_summary.append(sc_stat)
|
368
392
|
|
369
393
|
sc_summary = pd.concat(sc_summary, axis=1).T
|
@@ -392,7 +416,7 @@ class SummarizeSupplyCurve:
|
|
392
416
|
os.makedirs(out_dir, exist_ok=True)
|
393
417
|
|
394
418
|
summary = cls(sc_table)
|
395
|
-
out_path = os.path.basename(sc_table).replace(
|
419
|
+
out_path = os.path.basename(sc_table).replace(".csv", "_summary.csv")
|
396
420
|
out_path = os.path.join(out_dir, out_path)
|
397
421
|
summary.supply_curve_summary(columns=columns, out_path=out_path)
|
398
422
|
|
@@ -401,6 +425,7 @@ class PlotBase:
|
|
401
425
|
"""
|
402
426
|
QA/QC Plotting base class
|
403
427
|
"""
|
428
|
+
|
404
429
|
def __init__(self, data):
|
405
430
|
"""
|
406
431
|
Parameters
|
@@ -438,7 +463,7 @@ class PlotBase:
|
|
438
463
|
out_path : str
|
439
464
|
File path to save plot to, can be a .html or static image
|
440
465
|
"""
|
441
|
-
if out_path.endswith(
|
466
|
+
if out_path.endswith(".html"):
|
442
467
|
fig.write_html(out_path)
|
443
468
|
else:
|
444
469
|
fig.write_image(out_path)
|
@@ -461,12 +486,13 @@ class PlotBase:
|
|
461
486
|
values = [values]
|
462
487
|
|
463
488
|
if scatter:
|
464
|
-
values += [
|
489
|
+
values += [SupplyCurveField.LATITUDE, SupplyCurveField.LONGITUDE]
|
465
490
|
|
466
491
|
for value in values:
|
467
492
|
if value not in df:
|
468
|
-
msg =
|
469
|
-
|
493
|
+
msg = "{} is not a valid column in summary table:\n{}".format(
|
494
|
+
value, df
|
495
|
+
)
|
470
496
|
logger.error(msg)
|
471
497
|
raise ValueError(msg)
|
472
498
|
|
@@ -475,6 +501,7 @@ class SummaryPlots(PlotBase):
|
|
475
501
|
"""
|
476
502
|
Plot summary data for QA/QC
|
477
503
|
"""
|
504
|
+
|
478
505
|
def __init__(self, summary):
|
479
506
|
"""
|
480
507
|
Parameters
|
@@ -506,7 +533,7 @@ class SummaryPlots(PlotBase):
|
|
506
533
|
"""
|
507
534
|
return list(self.summary.columns)
|
508
535
|
|
509
|
-
def scatter_plot(self, value, cmap=
|
536
|
+
def scatter_plot(self, value, cmap="viridis", out_path=None, **kwargs):
|
510
537
|
"""
|
511
538
|
Plot scatter plot of value versus longitude and latitude using
|
512
539
|
pandas.plot.scatter
|
@@ -523,10 +550,11 @@ class SummaryPlots(PlotBase):
|
|
523
550
|
Additional kwargs for plotting.dataframes.df_scatter
|
524
551
|
"""
|
525
552
|
self._check_value(self.summary, value)
|
526
|
-
mplt.df_scatter(self.summary, x=
|
527
|
-
|
553
|
+
mplt.df_scatter(self.summary, x=SupplyCurveField.LONGITUDE,
|
554
|
+
y=SupplyCurveField.LATITUDE, c=value, colormap=cmap,
|
555
|
+
filename=out_path, **kwargs)
|
528
556
|
|
529
|
-
def scatter_plotly(self, value, cmap=
|
557
|
+
def scatter_plotly(self, value, cmap="Viridis", out_path=None, **kwargs):
|
530
558
|
"""
|
531
559
|
Plot scatter plot of value versus longitude and latitude using
|
532
560
|
plotly
|
@@ -544,8 +572,9 @@ class SummaryPlots(PlotBase):
|
|
544
572
|
Additional kwargs for plotly.express.scatter
|
545
573
|
"""
|
546
574
|
self._check_value(self.summary, value)
|
547
|
-
fig = px.scatter(self.summary, x=
|
548
|
-
|
575
|
+
fig = px.scatter(self.summary, x=SupplyCurveField.LONGITUDE,
|
576
|
+
y=SupplyCurveField.LATITUDE, color=value,
|
577
|
+
color_continuous_scale=cmap, **kwargs)
|
549
578
|
fig.update_layout(font=dict(family="Arial", size=18, color="black"))
|
550
579
|
|
551
580
|
if out_path is not None:
|
@@ -553,24 +582,27 @@ class SummaryPlots(PlotBase):
|
|
553
582
|
|
554
583
|
fig.show()
|
555
584
|
|
556
|
-
def _extract_sc_data(self, lcoe=
|
585
|
+
def _extract_sc_data(self, lcoe=SupplyCurveField.MEAN_LCOE):
|
557
586
|
"""
|
558
587
|
Extract supply curve data
|
559
588
|
|
560
589
|
Parameters
|
561
590
|
----------
|
562
591
|
lcoe : str, optional
|
563
|
-
LCOE value to use for supply curve,
|
592
|
+
LCOE value to use for supply curve,
|
593
|
+
by default :obj:`SupplyCurveField.MEAN_LCOE`
|
564
594
|
|
565
595
|
Returns
|
566
596
|
-------
|
567
597
|
sc_df : pandas.DataFrame
|
568
598
|
Supply curve data
|
569
599
|
"""
|
570
|
-
values = [
|
600
|
+
values = [SupplyCurveField.CAPACITY, lcoe]
|
571
601
|
self._check_value(self.summary, values, scatter=False)
|
572
602
|
sc_df = self.summary[values].sort_values(lcoe)
|
573
|
-
sc_df['cumulative_capacity'] =
|
603
|
+
sc_df['cumulative_capacity'] = (
|
604
|
+
sc_df[SupplyCurveField.CAPACITY].cumsum()
|
605
|
+
)
|
574
606
|
|
575
607
|
return sc_df
|
576
608
|
|
@@ -614,8 +646,15 @@ class SummaryPlots(PlotBase):
|
|
614
646
|
fig.show()
|
615
647
|
|
616
648
|
@classmethod
|
617
|
-
def scatter(
|
618
|
-
|
649
|
+
def scatter(
|
650
|
+
cls,
|
651
|
+
summary_csv,
|
652
|
+
out_dir,
|
653
|
+
value,
|
654
|
+
plot_type="plotly",
|
655
|
+
cmap="viridis",
|
656
|
+
**kwargs,
|
657
|
+
):
|
619
658
|
"""
|
620
659
|
Create scatter plot for given value in summary table and save to
|
621
660
|
out_dir
|
@@ -636,25 +675,31 @@ class SummaryPlots(PlotBase):
|
|
636
675
|
Additional plotting kwargs
|
637
676
|
"""
|
638
677
|
splt = cls(summary_csv)
|
639
|
-
if plot_type ==
|
640
|
-
out_path = os.path.basename(summary_csv).replace(
|
678
|
+
if plot_type == "plot":
|
679
|
+
out_path = os.path.basename(summary_csv).replace(".csv", ".png")
|
641
680
|
out_path = os.path.join(out_dir, out_path)
|
642
|
-
splt.scatter_plot(
|
643
|
-
|
644
|
-
|
645
|
-
|
681
|
+
splt.scatter_plot(
|
682
|
+
value, cmap=cmap.lower(), out_path=out_path, **kwargs
|
683
|
+
)
|
684
|
+
elif plot_type == "plotly":
|
685
|
+
out_path = os.path.basename(summary_csv).replace(".csv", ".html")
|
646
686
|
out_path = os.path.join(out_dir, out_path)
|
647
|
-
splt.scatter_plotly(
|
648
|
-
|
687
|
+
splt.scatter_plotly(
|
688
|
+
value, cmap=cmap.capitalize(), out_path=out_path, **kwargs
|
689
|
+
)
|
649
690
|
else:
|
650
|
-
msg = (
|
651
|
-
|
691
|
+
msg = (
|
692
|
+
"plot_type must be 'plot' or 'plotly' but {} was given".format(
|
693
|
+
plot_type
|
694
|
+
)
|
695
|
+
)
|
652
696
|
logger.error(msg)
|
653
697
|
raise ValueError(msg)
|
654
698
|
|
655
699
|
@classmethod
|
656
|
-
def scatter_all(
|
657
|
-
|
700
|
+
def scatter_all(
|
701
|
+
cls, summary_csv, out_dir, plot_type="plotly", cmap="viridis", **kwargs
|
702
|
+
):
|
658
703
|
"""
|
659
704
|
Create scatter plot for all summary stats in summary table and save to
|
660
705
|
out_dir
|
@@ -674,24 +719,29 @@ class SummaryPlots(PlotBase):
|
|
674
719
|
"""
|
675
720
|
splt = cls(summary_csv)
|
676
721
|
splt._data = splt.summary.select_dtypes(include=np.number)
|
677
|
-
datasets = [
|
678
|
-
|
722
|
+
datasets = [
|
723
|
+
c for c in splt.summary.columns if not c.startswith(("lat", "lon"))
|
724
|
+
]
|
679
725
|
|
680
726
|
for value in datasets:
|
681
|
-
if plot_type ==
|
682
|
-
out_path =
|
683
|
-
out_path =
|
684
|
-
|
727
|
+
if plot_type == "plot":
|
728
|
+
out_path = "_{}.png".format(value)
|
729
|
+
out_path = os.path.basename(summary_csv).replace(
|
730
|
+
".csv", out_path
|
731
|
+
)
|
685
732
|
out_path = os.path.join(out_dir, out_path)
|
686
|
-
splt.scatter_plot(
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
out_path =
|
691
|
-
|
733
|
+
splt.scatter_plot(
|
734
|
+
value, cmap=cmap.lower(), out_path=out_path, **kwargs
|
735
|
+
)
|
736
|
+
elif plot_type == "plotly":
|
737
|
+
out_path = "_{}.html".format(value)
|
738
|
+
out_path = os.path.basename(summary_csv).replace(
|
739
|
+
".csv", out_path
|
740
|
+
)
|
692
741
|
out_path = os.path.join(out_dir, out_path)
|
693
|
-
splt.scatter_plotly(
|
694
|
-
|
742
|
+
splt.scatter_plotly(
|
743
|
+
value, cmap=cmap.capitalize(), out_path=out_path, **kwargs
|
744
|
+
)
|
695
745
|
else:
|
696
746
|
msg = ("plot_type must be 'plot' or 'plotly' but {} was given"
|
697
747
|
.format(plot_type))
|
@@ -735,52 +785,58 @@ class SupplyCurvePlot(PlotBase):
|
|
735
785
|
"""
|
736
786
|
return list(self.sc_table.columns)
|
737
787
|
|
738
|
-
def _extract_sc_data(self, lcoe=
|
788
|
+
def _extract_sc_data(self, lcoe=SupplyCurveField.MEAN_LCOE):
|
739
789
|
"""
|
740
790
|
Extract supply curve data
|
741
791
|
|
742
792
|
Parameters
|
743
793
|
----------
|
744
794
|
lcoe : str, optional
|
745
|
-
LCOE value to use for supply curve,
|
795
|
+
LCOE value to use for supply curve,
|
796
|
+
by default :obj:`SupplyCurveField.MEAN_LCOE`
|
746
797
|
|
747
798
|
Returns
|
748
799
|
-------
|
749
800
|
sc_df : pandas.DataFrame
|
750
801
|
Supply curve data
|
751
802
|
"""
|
752
|
-
values = [
|
803
|
+
values = [SupplyCurveField.CAPACITY, lcoe]
|
753
804
|
self._check_value(self.sc_table, values, scatter=False)
|
754
805
|
sc_df = self.sc_table[values].sort_values(lcoe)
|
755
|
-
sc_df['cumulative_capacity'] =
|
806
|
+
sc_df['cumulative_capacity'] = (
|
807
|
+
sc_df[SupplyCurveField.CAPACITY].cumsum()
|
808
|
+
)
|
756
809
|
|
757
810
|
return sc_df
|
758
811
|
|
759
|
-
def supply_curve_plot(self, lcoe=
|
812
|
+
def supply_curve_plot(self, lcoe=SupplyCurveField.MEAN_LCOE, out_path=None,
|
813
|
+
**kwargs):
|
760
814
|
"""
|
761
815
|
Plot supply curve (cumulative capacity vs lcoe) using seaborn.scatter
|
762
816
|
|
763
817
|
Parameters
|
764
818
|
----------
|
765
819
|
lcoe : str, optional
|
766
|
-
LCOE value to plot, by default
|
820
|
+
LCOE value to plot, by default :obj:`SupplyCurveField.MEAN_LCOE`
|
767
821
|
out_path : str, optional
|
768
822
|
File path to save plot to, by default None
|
769
823
|
kwargs : dict
|
770
824
|
Additional kwargs for plotting.dataframes.df_scatter
|
771
825
|
"""
|
772
826
|
sc_df = self._extract_sc_data(lcoe=lcoe)
|
773
|
-
mplt.df_scatter(
|
774
|
-
|
827
|
+
mplt.df_scatter(
|
828
|
+
sc_df, x="cumulative_capacity", y=lcoe, filename=out_path, **kwargs
|
829
|
+
)
|
775
830
|
|
776
|
-
def supply_curve_plotly(self, lcoe=
|
831
|
+
def supply_curve_plotly(self, lcoe=SupplyCurveField.MEAN_LCOE,
|
832
|
+
out_path=None, **kwargs):
|
777
833
|
"""
|
778
834
|
Plot supply curve (cumulative capacity vs lcoe) using plotly
|
779
835
|
|
780
836
|
Parameters
|
781
837
|
----------
|
782
838
|
lcoe : str, optional
|
783
|
-
LCOE value to plot, by default
|
839
|
+
LCOE value to plot, by default SupplyCurveField.MEAN_LCOE
|
784
840
|
out_path : str, optional
|
785
841
|
File path to save plot to, can be a .html or static image,
|
786
842
|
by default None
|
@@ -788,7 +844,7 @@ class SupplyCurvePlot(PlotBase):
|
|
788
844
|
Additional kwargs for plotly.express.scatter
|
789
845
|
"""
|
790
846
|
sc_df = self._extract_sc_data(lcoe=lcoe)
|
791
|
-
fig = px.scatter(sc_df, x=
|
847
|
+
fig = px.scatter(sc_df, x="cumulative_capacity", y=lcoe, **kwargs)
|
792
848
|
fig.update_layout(font=dict(family="Arial", size=18, color="black"))
|
793
849
|
|
794
850
|
if out_path is not None:
|
@@ -797,8 +853,8 @@ class SupplyCurvePlot(PlotBase):
|
|
797
853
|
fig.show()
|
798
854
|
|
799
855
|
@classmethod
|
800
|
-
def plot(cls, sc_table, out_dir, plot_type='plotly',
|
801
|
-
**kwargs):
|
856
|
+
def plot(cls, sc_table, out_dir, plot_type='plotly',
|
857
|
+
lcoe=SupplyCurveField.MEAN_LCOE, **kwargs):
|
802
858
|
"""
|
803
859
|
Create supply curve plot from supply curve table using lcoe value
|
804
860
|
and save to out_dir
|
@@ -812,22 +868,25 @@ class SupplyCurvePlot(PlotBase):
|
|
812
868
|
plot_type : str, optional
|
813
869
|
plot_type of plot to create 'plot' or 'plotly', by default 'plotly'
|
814
870
|
lcoe : str, optional
|
815
|
-
LCOE value to plot, by default
|
871
|
+
LCOE value to plot, by default :obj:`SupplyCurveField.MEAN_LCOE`
|
816
872
|
kwargs : dict
|
817
873
|
Additional plotting kwargs
|
818
874
|
"""
|
819
875
|
splt = cls(sc_table)
|
820
|
-
if plot_type ==
|
821
|
-
out_path = os.path.basename(sc_table).replace(
|
876
|
+
if plot_type == "plot":
|
877
|
+
out_path = os.path.basename(sc_table).replace(".csv", ".png")
|
822
878
|
out_path = os.path.join(out_dir, out_path)
|
823
879
|
splt.supply_curve_plot(lcoe=lcoe, out_path=out_path, **kwargs)
|
824
|
-
elif plot_type ==
|
825
|
-
out_path = os.path.basename(sc_table).replace(
|
880
|
+
elif plot_type == "plotly":
|
881
|
+
out_path = os.path.basename(sc_table).replace(".csv", ".html")
|
826
882
|
out_path = os.path.join(out_dir, out_path)
|
827
883
|
splt.supply_curve_plotly(lcoe=lcoe, out_path=out_path, **kwargs)
|
828
884
|
else:
|
829
|
-
msg = (
|
830
|
-
|
885
|
+
msg = (
|
886
|
+
"plot_type must be 'plot' or 'plotly' but {} was given".format(
|
887
|
+
plot_type
|
888
|
+
)
|
889
|
+
)
|
831
890
|
logger.error(msg)
|
832
891
|
raise ValueError(msg)
|
833
892
|
|
@@ -879,8 +938,9 @@ class ExclusionsMask(PlotBase):
|
|
879
938
|
|
880
939
|
return excl_mask
|
881
940
|
|
882
|
-
def exclusions_plot(
|
883
|
-
|
941
|
+
def exclusions_plot(
|
942
|
+
self, cmap="Viridis", plot_step=100, out_path=None, **kwargs
|
943
|
+
):
|
884
944
|
"""
|
885
945
|
Plot exclusions mask as a seaborn heatmap
|
886
946
|
|
@@ -896,11 +956,16 @@ class ExclusionsMask(PlotBase):
|
|
896
956
|
kwargs : dict
|
897
957
|
Additional kwargs for plotting.colormaps.heatmap_plot
|
898
958
|
"""
|
899
|
-
mplt.heatmap_plot(
|
900
|
-
|
959
|
+
mplt.heatmap_plot(
|
960
|
+
self.mask[::plot_step, ::plot_step],
|
961
|
+
cmap=cmap,
|
962
|
+
filename=out_path,
|
963
|
+
**kwargs,
|
964
|
+
)
|
901
965
|
|
902
|
-
def exclusions_plotly(
|
903
|
-
|
966
|
+
def exclusions_plotly(
|
967
|
+
self, cmap="Viridis", plot_step=100, out_path=None, **kwargs
|
968
|
+
):
|
904
969
|
"""
|
905
970
|
Plot exclusions mask as a plotly heatmap
|
906
971
|
|
@@ -916,8 +981,11 @@ class ExclusionsMask(PlotBase):
|
|
916
981
|
kwargs : dict
|
917
982
|
Additional kwargs for plotly.express.imshow
|
918
983
|
"""
|
919
|
-
fig = px.imshow(
|
920
|
-
|
984
|
+
fig = px.imshow(
|
985
|
+
self.mask[::plot_step, ::plot_step],
|
986
|
+
color_continuous_scale=cmap,
|
987
|
+
**kwargs,
|
988
|
+
)
|
921
989
|
fig.update_layout(font=dict(family="Arial", size=18, color="black"))
|
922
990
|
|
923
991
|
if out_path is not None:
|
@@ -926,8 +994,15 @@ class ExclusionsMask(PlotBase):
|
|
926
994
|
fig.show()
|
927
995
|
|
928
996
|
@classmethod
|
929
|
-
def plot(
|
930
|
-
|
997
|
+
def plot(
|
998
|
+
cls,
|
999
|
+
mask,
|
1000
|
+
out_dir,
|
1001
|
+
plot_type="plotly",
|
1002
|
+
cmap="Viridis",
|
1003
|
+
plot_step=100,
|
1004
|
+
**kwargs,
|
1005
|
+
):
|
931
1006
|
"""
|
932
1007
|
Plot exclusions mask and save to out_dir
|
933
1008
|
|
@@ -947,22 +1022,29 @@ class ExclusionsMask(PlotBase):
|
|
947
1022
|
Additional plotting kwargs
|
948
1023
|
"""
|
949
1024
|
excl_mask = cls(mask)
|
950
|
-
if plot_type ==
|
951
|
-
out_path =
|
1025
|
+
if plot_type == "plot":
|
1026
|
+
out_path = "exclusions_mask.png"
|
952
1027
|
out_path = os.path.join(out_dir, out_path)
|
953
|
-
excl_mask.exclusions_plot(
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
1028
|
+
excl_mask.exclusions_plot(
|
1029
|
+
cmap=cmap.lower(),
|
1030
|
+
plot_step=plot_step,
|
1031
|
+
out_path=out_path,
|
1032
|
+
**kwargs,
|
1033
|
+
)
|
1034
|
+
elif plot_type == "plotly":
|
1035
|
+
out_path = "exclusions_mask.html"
|
959
1036
|
out_path = os.path.join(out_dir, out_path)
|
960
|
-
excl_mask.exclusions_plotly(
|
961
|
-
|
962
|
-
|
963
|
-
|
1037
|
+
excl_mask.exclusions_plotly(
|
1038
|
+
cmap=cmap.capitalize(),
|
1039
|
+
plot_step=plot_step,
|
1040
|
+
out_path=out_path,
|
1041
|
+
**kwargs,
|
1042
|
+
)
|
964
1043
|
else:
|
965
|
-
msg = (
|
966
|
-
|
1044
|
+
msg = (
|
1045
|
+
"plot_type must be 'plot' or 'plotly' but {} was given".format(
|
1046
|
+
plot_type
|
1047
|
+
)
|
1048
|
+
)
|
967
1049
|
logger.error(msg)
|
968
1050
|
raise ValueError(msg)
|