From 8244c1f6bbd2c60f905f33d4e6bfe93a42f81a5e Mon Sep 17 00:00:00 2001 From: jnnr <32454596+jnnr@users.noreply.github.com> Date: Wed, 15 Sep 2021 09:24:23 +0200 Subject: [PATCH 1/5] Dump tuple labels and introduce functions that match tuples --- oemoflex/tools/colors.csv | 6 ++-- oemoflex/tools/labels.yaml | 57 ++++++++++++------------------------ oemoflex/tools/plots.py | 59 ++++++++++++++------------------------ 3 files changed, 43 insertions(+), 79 deletions(-) diff --git a/oemoflex/tools/colors.csv b/oemoflex/tools/colors.csv index e4a8f18..d443929 100644 --- a/oemoflex/tools/colors.csv +++ b/oemoflex/tools/colors.csv @@ -11,9 +11,9 @@ H2 GT,magenta CH4 GT,#d62728 Nuclear ST,pink -Liion Battery,#9467bd -BAT discharge,#9467bd -BAT charge,#9467bd +Battery,#9467bd +Battery out,#9467bd +Battery in,#9467bd El. H2 cavern,orchid BEV,gold diff --git a/oemoflex/tools/labels.yaml b/oemoflex/tools/labels.yaml index 1f88b19..d76b410 100644 --- a/oemoflex/tools/labels.yaml +++ b/oemoflex/tools/labels.yaml @@ -1,39 +1,18 @@ -!!python/tuple ['-biomass-gt', '-electricity', 'flow']: Biomass GT -!!python/tuple ['-biomass-st', '-electricity', 'flow']: Biomass ST -!!python/tuple ['-ch4-gt', '-electricity', 'flow']: CH4 GT -!!python/tuple ['-electricity', '-electricity-demand', 'flow']: El. demand -!!python/tuple ['-electricity', '-electricity-curtailment', 'flow']: Curtailment -!!python/tuple ['-electricity-shortage', '-electricity', 'flow']: Shortage -!!python/tuple ['-electricity', '-electricity-liion-battery', 'flow']: BAT charge -!!python/tuple ['-electricity-liion-battery', '-electricity', 'flow']: BAT discharge -!!python/tuple ['-solar-pv', '-electricity', 'flow']: PV -!!python/tuple ['-wind-onshore', '-electricity', 'flow']: Wind on -!!python/tuple ['-electricity-transmission', '-electricity', 'flow']: Import -!!python/tuple ['-electricity', '-electricity-transmission', 'flow']: Export -!!python/tuple ['-heat', '-heat-demand', 'flow']: Heat demand -!!python/tuple ['-ch4-boiler', '-heat', 'flow']: CH4 Boiler - -biomass : Biomass -ch4: CH4 -hard coal: Hard coal -oil: Oil -lignite: Lignite -other: Other - -BE-biomass-st: Biomass ST -BB-biomass-st: Biomass ST -BE-electricity-curtailment: El. curtailment -BB-electricity-curtailment: Curtailment -BE-electricity-demand: El demand -BB-electricity-demand: El. Demand -BE-electricity-liion-battery: Liion Battery -BB-electricity-liion-battery: Liion Battery -BE-electricity-shortage: El. shortage -BB-electricity-shortage: Shortage -BE-BB-electricity-transmission: Transmission -BE-ch4-gt: CH4 -BB-ch4-gt: CH4 -BE-solar-pv: PV -BB-solar-pv: PV -BE-wind-onshore: Wind on -BB-wind-onshore: Wind +biomass-gt: Biomass GT +biomass-st: Biomass ST +ch4-boiler: CH4 Boiler +ch4-bpchp: CH4 Backpressure CHP +ch4-extchp: CH4 Extraction CHP +ch4-gt: CH4 GT +electricity-curtailment: Curtailment +electricity-demand: El. demand +electricity-electrolyzer: Electrolyzer +electricity-liion_battery: Battery +electricity-pth: res. PtH +electricity-shortage: Shortage +electricity-transmission: Import/Export +h2-gt: H2 GT +heat-demand: Heat demand +hydro-ror: Hydro ROR +solar-pv: PV +wind-onshore: Wind on diff --git a/oemoflex/tools/plots.py b/oemoflex/tools/plots.py index f3c3ac0..e6355ef 100644 --- a/oemoflex/tools/plots.py +++ b/oemoflex/tools/plots.py @@ -67,7 +67,7 @@ def rename_by_string_matching(columns, labels_dict): List with new column names. """ - def map_tuple(tuple, dictionary): + def map_tuple(tupl, dictionary): r""" The corresponding value of the tuple which is supposed to be a key in the dictionary is retrieved. @@ -85,56 +85,41 @@ def map_tuple(tuple, dictionary): mapped : string String with new column name. """ - mapped = None + mapped = [value for key, value in dictionary.items() if any([key in y for y in tupl])] - for key, value in dictionary.items(): - - if concrete_in_generic(tuple, key): - mapped = value - - else: - continue + if len(mapped) > 1: + raise ValueError("Multiple labels are matching.") + else: + mapped = mapped[0] if not mapped: - raise KeyError(f"No mapping defined for {col}.") + raise KeyError(f"No label matches for {tuple}.") return mapped - def concrete_in_generic(concrete_tuple, generic_tuple): + def rename_duplicated(columns_tuple, columns_mapped, dictionary): r""" - It is checked if the concrete_tuple is contained in the generic_tuple which is a key of - the labels_dict. Thus, it is checked if a multilevel column name is contained in the - labels_dict. - - Parameters - --------------- - concrete_tuple : tuple - Column names which need to be adapted to a concise name. - generic_tuple : tuple - Contains old and new column names. The new column names are used for the labels in the - plot. - - Returns - ---------- - True or False : Boolean - Boolean whether concrete_tuple is contained in generic_tuple. + Appends a suffix to those columns that are not unique. This happens in + oemof because a component can appear as the first or second entry in a tuple, which + signifies the output or input of the component, respectively. """ - for concrete, generic in zip(concrete_tuple, generic_tuple): - if generic in concrete: - continue + columns_duplicated = columns_mapped.duplicated(keep=False) + + mapped_where = [j for tupl in columns_tuple for j, x in enumerate(tupl) if any([key in x for key in dictionary.keys()])] - else: - return False + mapped_where = pd.Series(mapped_where) - return True + columns_mapped.loc[columns_duplicated & (mapped_where == 0)] += " out" - renamed_columns = list() + columns_mapped.loc[columns_duplicated & mapped_where == 1] += " in" - for col in columns: + return columns_mapped - renamed_col = map_tuple(col, labels_dict) + # Map column names + renamed_columns = pd.Series(map(lambda x: map_tuple(x, labels_dict), columns)) - renamed_columns.append(renamed_col) + # If there are duplicates, append in/out + renamed_columns = rename_duplicated(columns, renamed_columns, labels_dict) return renamed_columns From 90809440bcf2eb0197565df7001b23212eed57b7 Mon Sep 17 00:00:00 2001 From: jnnr <32454596+jnnr@users.noreply.github.com> Date: Wed, 15 Sep 2021 14:05:29 +0200 Subject: [PATCH 2/5] Apply black --- oemoflex/tools/plots.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/oemoflex/tools/plots.py b/oemoflex/tools/plots.py index e6355ef..83ed1c8 100644 --- a/oemoflex/tools/plots.py +++ b/oemoflex/tools/plots.py @@ -85,7 +85,9 @@ def map_tuple(tupl, dictionary): mapped : string String with new column name. """ - mapped = [value for key, value in dictionary.items() if any([key in y for y in tupl])] + mapped = [ + value for key, value in dictionary.items() if any([key in y for y in tupl]) + ] if len(mapped) > 1: raise ValueError("Multiple labels are matching.") @@ -105,7 +107,12 @@ def rename_duplicated(columns_tuple, columns_mapped, dictionary): """ columns_duplicated = columns_mapped.duplicated(keep=False) - mapped_where = [j for tupl in columns_tuple for j, x in enumerate(tupl) if any([key in x for key in dictionary.keys()])] + mapped_where = [ + j + for tupl in columns_tuple + for j, x in enumerate(tupl) + if any([key in x for key in dictionary.keys()]) + ] mapped_where = pd.Series(mapped_where) From 1cb9575f9cb68549902f8313a94c9fabda80368a Mon Sep 17 00:00:00 2001 From: jnnr <32454596+jnnr@users.noreply.github.com> Date: Wed, 15 Sep 2021 15:02:04 +0200 Subject: [PATCH 3/5] Fix error handling of tuple mapping --- oemoflex/tools/plots.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/oemoflex/tools/plots.py b/oemoflex/tools/plots.py index 83ed1c8..8d1c909 100644 --- a/oemoflex/tools/plots.py +++ b/oemoflex/tools/plots.py @@ -91,12 +91,11 @@ def map_tuple(tupl, dictionary): if len(mapped) > 1: raise ValueError("Multiple labels are matching.") + elif not mapped: + raise KeyError(f"No label matches for {tupl}.") else: mapped = mapped[0] - if not mapped: - raise KeyError(f"No label matches for {tuple}.") - return mapped def rename_duplicated(columns_tuple, columns_mapped, dictionary): From 2c05c8c6cb2eb07c88c9cb140b5b9d31ff052b07 Mon Sep 17 00:00:00 2001 From: jnnr <32454596+jnnr@users.noreply.github.com> Date: Wed, 15 Sep 2021 15:52:44 +0200 Subject: [PATCH 4/5] Check if there are undefined colors --- oemoflex/tools/plots.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/oemoflex/tools/plots.py b/oemoflex/tools/plots.py index 8d1c909..39e0fa9 100644 --- a/oemoflex/tools/plots.py +++ b/oemoflex/tools/plots.py @@ -21,6 +21,13 @@ colors_odict[i] = colors_csv.loc["Color", i] +def check_undefined_colors(labels, color_labels): + undefined_colors = list(set(labels).difference(color_labels)) + + if undefined_colors: + raise KeyError(f"Undefined colors {undefined_colors}.") + + def map_labels(df, labels_dict=general_labels_dict): r""" Renames columns according to the specifications in the label_dict. The data has multilevel @@ -123,10 +130,10 @@ def rename_duplicated(columns_tuple, columns_mapped, dictionary): # Map column names renamed_columns = pd.Series(map(lambda x: map_tuple(x, labels_dict), columns)) - + print(renamed_columns) # If there are duplicates, append in/out renamed_columns = rename_duplicated(columns, renamed_columns, labels_dict) - + print(renamed_columns) return renamed_columns @@ -305,6 +312,8 @@ def plot_dispatch_plotly( fig : plotly.graph_objs._figure.Figure Interactive plotly dispatch plot """ + check_undefined_colors(df.columns, colors_odict.keys()) + # make sure to obey order as definded in colors_odict generic_order = list(colors_odict) concrete_order = generic_order.copy() @@ -386,6 +395,8 @@ def stackplot(ax, df, colors_odict): colors_odict : collections.OrderedDictionary Ordered dictionary with labels as keys and colourcodes as values. """ + check_undefined_colors(df.columns, colors_odict.keys()) + # y is a list which gets the correct stack order from colors file colors = [] labels = [] @@ -417,6 +428,8 @@ def lineplot(ax, df, colors_odict): colors_odict : collections.OrderedDictionary Ordered dictionary with labels as keys and colourcodes as values. """ + check_undefined_colors(df.columns, colors_odict.keys()) + for i in df.columns: ax.plot(df.index, df[i], color=colors_odict[i], label=i) @@ -440,6 +453,8 @@ def plot_dispatch(ax, df, df_demand, unit, colors_odict=colors_odict): colors_odict : collections.OrderedDictionary Ordered dictionary with labels as keys and colourcodes as values. """ + check_undefined_colors(df.columns, colors_odict.keys()) + # apply EngFormatter on axis ax = eng_format(ax, unit=unit) From cefc033ad23232d02ebacaaaa5becf470604c423 Mon Sep 17 00:00:00 2001 From: jnnr <32454596+jnnr@users.noreply.github.com> Date: Wed, 15 Sep 2021 15:53:23 +0200 Subject: [PATCH 5/5] Check if there are undefined colors --- oemoflex/tools/plots.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oemoflex/tools/plots.py b/oemoflex/tools/plots.py index 39e0fa9..4383703 100644 --- a/oemoflex/tools/plots.py +++ b/oemoflex/tools/plots.py @@ -130,10 +130,10 @@ def rename_duplicated(columns_tuple, columns_mapped, dictionary): # Map column names renamed_columns = pd.Series(map(lambda x: map_tuple(x, labels_dict), columns)) - print(renamed_columns) + # If there are duplicates, append in/out renamed_columns = rename_duplicated(columns, renamed_columns, labels_dict) - print(renamed_columns) + return renamed_columns