Introduction to Brightway2#
Read me first...
Authors
This chapter was created by Karin Treyer in 2024. It was edited for publication by Michael Weinold with the help of Maria Höller and Mehdi Iguider as part of the Brightcon 2024 Documentation Hackathon.
In order to complete this tutorial successfully, you will need:
Basic knowledge of the Conda package manager (manage environments & install packages).
A working installation of Brightway 2 (NOT 2.5!).
Basic knowledge of Python data types.
Basic understanding of matrix-based LCA data and calculations.
How to use this Tutorial…
You could read it online on this website and copy/paste some snippets of code into a Jupyter Notebook to play around.
If you click on the download button in the top right corner, you can download this section as a Jupyter Notebook (
.ipynb).
Cheat Sheet
You can download a helpful cheat sheet for Brightway2 commands from the main documentation site: bw_cheatsheet_may_2024.pdf
1. Installing Activity Browser#
The Activity Browser (“AB”) is a tool that allows you to perform Brightway life-cycle assessment calculations using a visual interface. To install AB on your computer, you can follow the setup instructions here. There are different ways how you can install AB. You will already understand the “quick way” installation by now, which is shown here:
Create a Conda environment named
abwith the following command:
conda create -n ab -c conda-forge --solver libmamba activity-browser
Activate the environment:
conda activate ab
Start the Activity Browser:
activity-browser
Activity Browser “sees” all the Brightway projects you have on your computer, and adopts all new projects you create and all new databases as you are working on. This means that you can make edits to a Brightway project using the command line and these changes will be reflected in the Activity Browser interface.
2. Create an Environment Brightway#
You should create a separate environment for your Brightway installation. To install Brightway on your computer, you can follow the setup instruction here:
Create a Conda environment named
bwwith the following command:
conda create -n bw -c conda-forge --solver libmamba brightway2=2.4.7 jupyterlab
Note that here we have installed both Brightway and the jupyterlab package, which is required to work with Jupyter Notebooks.
Activate the environment:
conda activate bw
Start Jupyter Lab so that you can work on a notebook:
jupyter lab
Now that you have understood how to get the Brightway packages on your computer and you want to do what your heart longs for: LCA 💚
3. Example Project#
We investigate Hydrogen production via water electrolysis technologies. It’s good practice to describe your project shortly, and which data you are using:
Origin of LCI data:
ecoinvent v3.9.1 cut-off system
literature data
original data from company X (confidential)
Goal of the study:
Import the biosphere, LCIA methods
Import the background database ecoinvent
Import the foreground inventories (you can look at all these databases in AB in a human friendly way)
Calculate the LCIA results, create an easy plot, but additionally output them an Excel file so that you can visualise it there, if you are not used to visualisation with Python.
3.1 Notebook Preparations#
First, we must import the required Brightway packages and set up the project:
import bw2io as bi
import bw2data as bd
import bw2calc as bc
Often, we need to use other helpful Python packages. For each of these, very helpful CheatSheets exist on the web! In our example, the Pandas library for working with tabulated data will be sufficient.
import pandas as pd
3.2 Setting up Projects#
Information
You can do the next steps in ActivityBrowser if you prefer. It’s possible to create, rename, and delete projects there.
You can check which projects exist on my computer - to see which ones are there, or if you have forgotten the name of your project. Of course, on your computer, you will see a different list of projects:
list(bd.projects) #the prefix "bw" indicates that "projects" is a method of the bw2data package
[Project: default,
Project: ei_3.10,
Project: debug,
Project: banana,
Project: ddd,
Project: USEEIO-1.1,
Project: bw_panel,
Project: learn_brightway_bw2]
Let’s create a project (or activate it when you come back to work on your project):
bd.projects.set_current('learn_brightway_bw2') # activates a project, or creates it first if it doesn't exist yet
3.3 Filling your project with the Biosphere, LCIA Methods, and Ecoinvent#
Information
You can do the next steps in ActivityBrowser if you prefer. It’s possible to import biosphere, LCIA methods, and ecoinvent (and other databases) there.
You only have to import the databases once. After that, they will be present in your project.
list(bd.databases) # check if there are databases in the project, and how they are named.
Ok, nothing is there yet. There are now two ways to import the necessary Ecoinvent database. You can choose either option A or option B, but you don’t have to execute both!
Option A#
This option imports the biosphere, LCIA methods, and ecoinvent all in one go!
Change Placeholder Text!
Below, change the placeholder text JohnDoe to your own Ecoinvent username and the password 1234 to your own Ecoinvent password.
if 'ecoinvent-3.9.1-cutoff' in bd.databases:
print('ecoinvent 3.9.1 is already present in the project')
else:
bi.import_ecoinvent_release(
version='3.9.1',
system_model='cutoff', # can be cutoff / apos / consequential / EN15804
username='JohnDoe',
password='1234'
)
Applying strategy: normalize_units
Applying strategy: drop_unspecified_subcategories
Applying strategy: ensure_categories_are_tuples
Applied 3 strategies in 0.00 seconds
4718 datasets
0 exchanges
0 unlinked exchanges
Warning: No valid output stream.
Title: Writing activities to SQLite3 database:
Started: 09/24/2024 10:10:17
Finished: 09/24/2024 10:10:17
Total time elapsed: 00:00:00
CPU %: 99.30
Memory %: 1.64
Created database: ecoinvent-3.9.1-biosphere
Extracting XML data from 21238 datasets
Extracted 21238 datasets in 18.87 seconds
Applying strategy: normalize_units
Applying strategy: update_ecoinvent_locations
Applying strategy: remove_zero_amount_coproducts
Applying strategy: remove_zero_amount_inputs_with_no_activity
Applying strategy: remove_unnamed_parameters
Applying strategy: es2_assign_only_product_with_amount_as_reference_product
Applying strategy: assign_single_product_as_activity
Applying strategy: create_composite_code
Applying strategy: drop_unspecified_subcategories
Applying strategy: fix_ecoinvent_flows_pre35
Applying strategy: drop_temporary_outdated_biosphere_flows
Applying strategy: link_biosphere_by_flow_uuid
Applying strategy: link_internal_technosphere_by_composite_code
Applying strategy: delete_exchanges_missing_activity
Applying strategy: delete_ghost_exchanges
Applying strategy: remove_uncertainty_from_negative_loss_exchanges
Applying strategy: fix_unreasonably_high_lognormal_uncertainties
Applying strategy: convert_activity_parameters_to_list
Applying strategy: add_cpc_classification_from_single_reference_product
Applying strategy: delete_none_synonyms
Applying strategy: update_social_flows_in_older_consequential
Applying strategy: set_lognormal_loc_value
Applied 22 strategies in 3.79 seconds
21238 datasets
674593 exchanges
0 unlinked exchanges
Warning: No valid output stream.
Title: Writing activities to SQLite3 database:
Started: 09/24/2024 10:10:46
Finished: 09/24/2024 10:11:02
Total time elapsed: 00:00:16
CPU %: 98.70
Memory %: 10.41
Created database: ecoinvent-3.9.1-cutoff
Let’s check if the databases are now there…
list(bd.databases)
['ecoinvent-3.9.1-biosphere', 'ecoinvent-3.9.1-cutoff']
Option B#
In most older notebooks you will find on the web, you will still see the old way of importing all these. There, we first import the biosphere and LCIA methods:
if any("biosphere" in db for db in bd.databases):
print('Biosphere is already present in the project.')
else:
bi.bw2setup()
Biosphere database already present!!! No setup is needed
Only now, we import the Ecoinvent data. First, download the Ecoinvent data from the Ecoinvent website and unzip the file. Then, provide the path to the unzipped folder datasets in the code below:
if 'ecoinvent-3.9.1-cutoff' in bd.databases:
print('Ecoinvent 3.9.1 is already present in the project.')
else:
ei = bi.SingleOutputEcospold2Importer(dirpath=r'C:\Users\johndoe\Downloads\ecoinvent\ecoinvent 3.9.1_cutoff_ecoSpold02\datasets', db_name='ev391cutoff') #recommendation for consistent databases naming: database name (ecoinvent), version number, system model
ei.apply_strategies() #fixing some issues when ecoinvent and brightway have to talk together by going through all datasets and manipulating them in a specific way
ei.statistics() #checking if everything worked out with strategies and linking
ei.write_database() #save the database to our hard drive
ecoinvent 3.9.1 is already present in the project
You may want to switch to AB now to look at the databases you have just imported. In case they are not yet displayed in your project, switch to another project and switch back for the new database(s) to appear
3.4 Importing your own Data#
File Download
You can download the example files required for this section here:
lci_hydrogen_electrolysis.xlsx
lci_rawdata_import.xlsx
imp = bi.ExcelImporter(r'C:\Users\johndoe\Downloads\lci_hydrogen_electrolysis.xlsx') # the path to your inventory excel file
imp.apply_strategies()
imp.match_database("ecoinvent-3.9.1-cutoff", fields=('name', 'unit', 'location', 'reference product')) # 'reference product'
imp.match_database(fields=('name', 'unit', 'location'))
imp.statistics()
imp.write_excel(only_unlinked=True)
list(imp.unlinked)
imp.write_database()
Extracted 1 worksheets in 0.10 seconds
Applying strategy: csv_restore_tuples
Applying strategy: csv_restore_booleans
Applying strategy: csv_numerize
Applying strategy: csv_drop_unknown
Applying strategy: csv_add_missing_exchanges_section
Applying strategy: normalize_units
Applying strategy: normalize_biosphere_categories
Applying strategy: normalize_biosphere_names
Applying strategy: strip_biosphere_exc_locations
Applying strategy: set_code_by_activity_hash
Applying strategy: link_iterable_by_fields
Applying strategy: assign_only_product_as_production
Applying strategy: link_technosphere_by_activity_hash
Applying strategy: drop_falsey_uncertainty_fields_but_keep_zeros
Applying strategy: convert_uncertainty_types_to_integers
Applying strategy: convert_activity_parameters_to_list
Applied 16 strategies in 2.70 seconds
Applying strategy: link_iterable_by_fields
Applying strategy: link_iterable_by_fields
17 datasets
343 exchanges
0 unlinked exchanges
Wrote matching file to:
/Users/michaelweinold/Library/Application Support/Brightway3/learn_brightway_bw2.64db5ecb6d8079342bb61bf76f7f8046/output/db-matching-h2_electrolysis-unlinked.xlsx
Warning: No valid output stream.
Title: Writing activities to SQLite3 database:
Started: 09/24/2024 11:32:27
Finished: 09/24/2024 11:32:27
Total time elapsed: 00:00:00
CPU %: 40.50
Memory %: 6.93
Created database: h2_electrolysis
This should have worked smoothly. Again, you can also look at this database in the AB.
HOWEVER, importing from Excel won’t always be so easy! This is demonstrated here:
imp = bi.ExcelImporter(r'/Users/michaelweinold/github/brightway-book/content/chapters/BW2/_data/lci_rawdata_import.xlsx')
imp.apply_strategies()
imp.match_database("ecoinvent-3.9.1-cutoff", fields=('name','unit','location', 'reference product'))
imp.match_database(fields=('name', 'unit', 'location'))
imp.statistics()
imp.write_excel() #(only_unlinked=True)
list(imp.unlinked)
imp.write_database()
Extracted 1 worksheets in 0.02 seconds
Applying strategy: csv_restore_tuples
Applying strategy: csv_restore_booleans
Applying strategy: csv_numerize
Applying strategy: csv_drop_unknown
Applying strategy: csv_add_missing_exchanges_section
Applying strategy: normalize_units
Applying strategy: normalize_biosphere_categories
Applying strategy: normalize_biosphere_names
Applying strategy: strip_biosphere_exc_locations
Applying strategy: set_code_by_activity_hash
Applying strategy: link_iterable_by_fields
Applying strategy: assign_only_product_as_production
Applying strategy: link_technosphere_by_activity_hash
Applying strategy: drop_falsey_uncertainty_fields_but_keep_zeros
Applying strategy: convert_uncertainty_types_to_integers
Applying strategy: convert_activity_parameters_to_list
Applied 16 strategies in 2.77 seconds
Applying strategy: link_iterable_by_fields
Applying strategy: link_iterable_by_fields
2 datasets
42 exchanges
3 unlinked exchanges
Type biosphere: 1 unique unlinked exchanges
Type technosphere: 2 unique unlinked exchanges
Wrote matching file to:
/Users/michaelweinold/Library/Application Support/Brightway3/learn_brightway_bw2.64db5ecb6d8079342bb61bf76f7f8046/output/db-matching-hydrogen_demo.xlsx
Warning: No valid output stream.
---------------------------------------------------------------------------
InvalidExchange Traceback (most recent call last)
Cell In[21], line 9
6 imp.write_excel() #(only_unlinked=True)
7 list(imp.unlinked)
----> 9 imp.write_database()
File /opt/homebrew/Caskroom/miniconda/base/envs/env_bw2/lib/python3.11/site-packages/bw2io/importers/excel.py:284, in ExcelImporter.write_database(self, **kwargs)
282 """Same as base ``write_database`` method, but ``activate_parameters`` is True by default."""
283 kwargs["activate_parameters"] = kwargs.get("activate_parameters", True)
--> 284 super(ExcelImporter, self).write_database(**kwargs)
File /opt/homebrew/Caskroom/miniconda/base/envs/env_bw2/lib/python3.11/site-packages/bw2io/importers/base_lci.py:273, in LCIImporter.write_database(self, data, delete_existing, backend, activate_parameters, **kwargs)
270 self.write_database_parameters(activate_parameters, delete_existing)
272 existing.update(data)
--> 273 db.write(existing)
275 if activate_parameters:
276 self._write_activity_parameters(activity_parameters)
File /opt/homebrew/Caskroom/miniconda/base/envs/env_bw2/lib/python3.11/site-packages/bw2data/project.py:358, in writable_project(wrapped, instance, args, kwargs)
356 if projects.read_only:
357 raise ReadOnlyProject(READ_ONLY_PROJECT)
--> 358 return wrapped(*args, **kwargs)
File /opt/homebrew/Caskroom/miniconda/base/envs/env_bw2/lib/python3.11/site-packages/bw2data/backends/peewee/database.py:260, in SQLiteBackend.write(self, data, process)
258 if data:
259 try:
--> 260 self._efficient_write_many_data(data)
261 except:
262 # Purge all data from database, then reraise
263 self.delete(warn=False)
File /opt/homebrew/Caskroom/miniconda/base/envs/env_bw2/lib/python3.11/site-packages/bw2data/backends/peewee/database.py:204, in SQLiteBackend._efficient_write_many_data(self, data, indices)
197 self.pbar = pyprind.ProgBar(
198 len(data),
199 title="Writing activities to SQLite3 database:",
200 monitor=True
201 )
203 for index, (key, ds) in enumerate(data.items()):
--> 204 exchanges, activities = self._efficient_write_dataset(
205 index, key, ds, exchanges, activities
206 )
208 if not getattr(config, "is_test", None):
209 print(self.pbar)
File /opt/homebrew/Caskroom/miniconda/base/envs/env_bw2/lib/python3.11/site-packages/bw2data/backends/peewee/database.py:156, in SQLiteBackend._efficient_write_dataset(self, index, key, ds, exchanges, activities)
154 for exchange in ds.get('exchanges', []):
155 if 'input' not in exchange or 'amount' not in exchange:
--> 156 raise InvalidExchange
157 if 'type' not in exchange:
158 raise UntypedExchange
InvalidExchange:
As you can see, there are some unlinked flows. This means that no corresponding dataset for an exchange listed in the spreadsheet could be found. Usually, this is because of types, wrong type, wrong unit, etc.
To fix this, open the excel file with the unlinked flows. It will show you the lines where a problem has occurred. Did you find the errors?
In the first activity, I misspelled “granulate” in the reference product. In the second case, I put “biosphere” as type instead of “technosphere”. And in the third case, I am using a location for which no market for deionised water exists. It should be CH, not AT.
In case you do not want to fix the file yourself, here is the corrected version:
File Download
You can download the CORRECTED example file here:
lci_rawdata_import_corrected.xlsx
list(bd.databases)
['ecoinvent-3.9.1-biosphere',
'ecoinvent-3.9.1-cutoff',
'h2_electrolysis',
'hydrogen_demo']
3.5 Looking at the Databases#
License
This is more “human friendly” in AB! For quick overviews, searches etc., AB is more convenient than the Jupyter Notebook.
First, we choose the activities we want to analyse later in the LCA. Here, I want to compare hydrogen production with different electrolysers.
h2elec = bd.Database('h2_electrolysis')
h2prod = [a for a in h2elec if 'hydrogen production, gaseous' in a ['name']]
h2prod
['hydrogen production, gaseous, 20 bar, from AEC electrolysis, from grid electricity' (kilogram, CH, None),
'hydrogen production, gaseous, 30 bar, from PEM electrolysis, from grid electricity' (kilogram, RER, None),
'hydrogen production, gaseous, 1 bar, from SOEC electrolysis, from grid electricity' (kilogram, CH, None),
'hydrogen production, gaseous, 1 bar, from SOEC electrolysis, with steam input, from grid electricity' (kilogram, CH, None)]
We can look at one of these activities here. But you might prefer to do that in AB.
list(h2prod[0].technosphere())
[Exchange: 9.391435011269722e-07 unit 'electrolyzer production, 1MWe, AEC, Stack' (unit, RER, None) to 'hydrogen production, gaseous, 20 bar, from AEC electrolysis, from grid electricity' (kilogram, CH, None)>,
Exchange: 2.3478587528174306e-07 unit 'electrolyzer production, 1MWe, AEC, Balance of Plant' (unit, RER, None) to 'hydrogen production, gaseous, 20 bar, from AEC electrolysis, from grid electricity' (kilogram, CH, None)>,
Exchange: -9.391435011269722e-07 unit 'treatment of fuel cell stack, 1MWe, AEC' (unit, RER, None) to 'hydrogen production, gaseous, 20 bar, from AEC electrolysis, from grid electricity' (kilogram, CH, None)>,
Exchange: -2.3478587528174306e-07 unit 'treatment of fuel cell balance of plant, 1MWe, AEC' (unit, RER, None) to 'hydrogen production, gaseous, 20 bar, from AEC electrolysis, from grid electricity' (kilogram, CH, None)>,
Exchange: 51.8 kilowatt hour 'market for electricity, low voltage' (kilowatt hour, CH, None) to 'hydrogen production, gaseous, 20 bar, from AEC electrolysis, from grid electricity' (kilogram, CH, None)>,
Exchange: 0.0037 kilogram 'market for potassium hydroxide' (kilogram, GLO, None) to 'hydrogen production, gaseous, 20 bar, from AEC electrolysis, from grid electricity' (kilogram, CH, None)>,
Exchange: 14 kilogram 'market for water, deionised' (kilogram, Europe without Switzerland, None) to 'hydrogen production, gaseous, 20 bar, from AEC electrolysis, from grid electricity' (kilogram, CH, None)>]
We also need to choose LCIA methods. Here, I only chose to compare the different IPCC GWP time horizons to make it simple
bd.methods # if you don't know the names of the different LCIA methods, you can check all methods in AB, or get a list of all of them here.
Methods dictionary with 762 objects, including:
('CML v4.8 2016', 'acidification', 'acidification (incl. fate, average Europe total, A&B)')
('CML v4.8 2016', 'climate change', 'global warming potential (GWP100)')
('CML v4.8 2016', 'ecotoxicity: freshwater', 'freshwater aquatic ecotoxicity (FAETP inf)')
('CML v4.8 2016', 'ecotoxicity: marine', 'marine aquatic ecotoxicity (MAETP inf)')
('CML v4.8 2016', 'ecotoxicity: terrestrial', 'terrestrial ecotoxicity (TETP inf)')
('CML v4.8 2016', 'energy resources: non-renewable', 'abiotic depletion potential (ADP): fossil fuels')
('CML v4.8 2016', 'eutrophication', 'eutrophication (fate not incl.)')
('CML v4.8 2016', 'human toxicity', 'human toxicity (HTP inf)')
('CML v4.8 2016', 'material resources: metals/minerals', 'abiotic depletion potential (ADP): elements (ultimate reserves)')
('CML v4.8 2016', 'ozone depletion', 'ozone layer depletion (ODP steady state)')
Use `list(this object)` to get the complete list.
ipcc = [m for m in bd.methods if 'IPCC' in str(m) and '2021' in str(m) and 'GWP' in str(m) and 'LT' not in str(m) and 'fossil' not in str(m) and 'biogenic' not in str(m) and 'land use' not in str(m) and 'SLCFs' not in str(m)]
ipcc
[('IPCC 2021', 'climate change', 'global warming potential (GWP100)'),
('IPCC 2021', 'climate change', 'global warming potential (GWP20)'),
('IPCC 2021', 'climate change', 'global warming potential (GWP500)')]
3.6 Performing an LCA#
FU = [{x:1} for x in h2prod] # defining the functional units: we want "1" of the activities which produce hydrogen.
bd.calculation_setups['GWPs_electrolysis'] = {'inv':FU, 'ia': ipcc}
mylca = bc.MultiLCA('GWPs_electrolysis')
mylca.results
array([[ 2.37768162, 2.92877936, 2.12446524],
[19.44666019, 21.77269211, 18.49650242],
[ 1.80959294, 2.23680139, 1.61681642],
[ 3.44325776, 4.1221398 , 3.15629171]])
That’s nice, but not very human friendly. Let’s look at a snippet of these results.
{k:v for k,v in zip(ipcc, mylca.results[0])}
{('IPCC 2021',
'climate change',
'global warming potential (GWP100)'): 19.44666019329231,
('IPCC 2021',
'climate change',
'global warming potential (GWP20)'): 21.772692106938454,
('IPCC 2021',
'climate change',
'global warming potential (GWP500)'): 18.496502417248085}
Better, but still not so convenient. We are using pandas to show the results in a way which is better defined.
mylcadf = pd.DataFrame(index = ipcc, columns = [(x['name'], x['location']) for y in FU for x in y], data=mylca.results.T)
mylcadf
| (hydrogen production, gaseous, 20 bar, from AEC electrolysis, from grid electricity, CH) | (hydrogen production, gaseous, 30 bar, from PEM electrolysis, from grid electricity, RER) | (hydrogen production, gaseous, 1 bar, from SOEC electrolysis, from grid electricity, CH) | (hydrogen production, gaseous, 1 bar, from SOEC electrolysis, with steam input, from grid electricity, CH) | |
|---|---|---|---|---|
| (IPCC 2021, climate change, global warming potential (GWP100)) | 2.377682 | 19.446660 | 1.809593 | 3.443258 |
| (IPCC 2021, climate change, global warming potential (GWP20)) | 2.928779 | 21.772692 | 2.236801 | 4.122140 |
| (IPCC 2021, climate change, global warming potential (GWP500)) | 2.124465 | 18.496502 | 1.616816 | 3.156292 |
mylcadf.to_excel('lcia_results.xlsx') # export to excel, e.g. for creating figures
3.7 Plotting Results#
You can any Python plotting library, like seaborn or matplotlib for plotting. If you already have your data stored in a Pandas DataFrame, you can plot it directly with Pandas.
mylcadf # we are using the mylcadf dataframe created further above.
| (hydrogen production, gaseous, 20 bar, from AEC electrolysis, from grid electricity, CH) | (hydrogen production, gaseous, 30 bar, from PEM electrolysis, from grid electricity, RER) | (hydrogen production, gaseous, 1 bar, from SOEC electrolysis, from grid electricity, CH) | (hydrogen production, gaseous, 1 bar, from SOEC electrolysis, with steam input, from grid electricity, CH) | |
|---|---|---|---|---|
| (IPCC 2021, climate change, global warming potential (GWP100)) | 2.377682 | 19.446660 | 1.809593 | 3.443258 |
| (IPCC 2021, climate change, global warming potential (GWP20)) | 2.928779 | 21.772692 | 2.236801 | 4.122140 |
| (IPCC 2021, climate change, global warming potential (GWP500)) | 2.124465 | 18.496502 | 1.616816 | 3.156292 |
print(mylcadf.columns.tolist())
[('hydrogen production, gaseous, 20 bar, from AEC electrolysis, from grid electricity', 'CH'), ('hydrogen production, gaseous, 30 bar, from PEM electrolysis, from grid electricity', 'RER'), ('hydrogen production, gaseous, 1 bar, from SOEC electrolysis, from grid electricity', 'CH'), ('hydrogen production, gaseous, 1 bar, from SOEC electrolysis, with steam input, from grid electricity', 'CH')]
We can now look at the long names of the impact assessment methods:
ipcc
[('IPCC 2021', 'climate change', 'global warming potential (GWP100)'),
('IPCC 2021', 'climate change', 'global warming potential (GWP20)'),
('IPCC 2021', 'climate change', 'global warming potential (GWP500)')]
…and come up with shorter, more “human-friendly” descriptions:
labels_methods = {
('IPCC 2021', 'climate change', 'global warming potential (GWP100)'): "IPCC GWP100",
('IPCC 2021', 'climate change', 'global warming potential (GWP20)'): 'IPCC GWP20',
('IPCC 2021', 'climate change', 'global warming potential (GWP500)'): 'IPCC GWP500',
}
Similarly, we can look at the long names of the activities:
h2prod
['hydrogen production, gaseous, 20 bar, from AEC electrolysis, from grid electricity' (kilogram, CH, None),
'hydrogen production, gaseous, 30 bar, from PEM electrolysis, from grid electricity' (kilogram, RER, None),
'hydrogen production, gaseous, 1 bar, from SOEC electrolysis, from grid electricity' (kilogram, CH, None),
'hydrogen production, gaseous, 1 bar, from SOEC electrolysis, with steam input, from grid electricity' (kilogram, CH, None)]
…and come up with shorter, more “human-friendly” descriptions:
labels_act = {
('hydrogen production, gaseous, 1 bar, from SOEC electrolysis, from grid electricity', 'CH'): "SOEC_with_steam",
('hydrogen production, gaseous, 20 bar, from AEC electrolysis, from grid electricity', 'CH'): "AEC",
('hydrogen production, gaseous, 30 bar, from PEM electrolysis, from grid electricity', 'RER'): "PEM",
('hydrogen production, gaseous, 1 bar, from SOEC electrolysis, with steam input, from grid electricity', 'CH'): "SOEC"
}
Now, we can update the labels in the dataframe:
mylcadf
| (hydrogen production, gaseous, 20 bar, from AEC electrolysis, from grid electricity, CH) | (hydrogen production, gaseous, 30 bar, from PEM electrolysis, from grid electricity, RER) | (hydrogen production, gaseous, 1 bar, from SOEC electrolysis, from grid electricity, CH) | (hydrogen production, gaseous, 1 bar, from SOEC electrolysis, with steam input, from grid electricity, CH) | |
|---|---|---|---|---|
| (IPCC 2021, climate change, global warming potential (GWP100)) | 2.377682 | 19.446660 | 1.809593 | 3.443258 |
| (IPCC 2021, climate change, global warming potential (GWP20)) | 2.928779 | 21.772692 | 2.236801 | 4.122140 |
| (IPCC 2021, climate change, global warming potential (GWP500)) | 2.124465 | 18.496502 | 1.616816 | 3.156292 |
df = mylcadf.rename(columns=labels_act, index=labels_methods)
df
| AEC | PEM | SOEC_with_steam | SOEC | |
|---|---|---|---|---|
| IPCC GWP100 | 2.377682 | 19.446660 | 1.809593 | 3.443258 |
| IPCC GWP20 | 2.928779 | 21.772692 | 2.236801 | 4.122140 |
| IPCC GWP500 | 2.124465 | 18.496502 | 1.616816 | 3.156292 |
Now can we plot the dataframe. Here, we are using the plotting functionality of Pandas itself:
df.plot.bar(
xlabel='Impact category',
ylabel='Impact score',
figsize=(14,8)
)
<Axes: xlabel='Impact category', ylabel='Impact score'>
We can also normalise our data:
df_norm = (df.T / df.abs().max(axis=1)).T
…and plot it again:
df_norm.plot.bar(
xlabel='Impact category',
ylabel='Impact score',
figsize=(14,8)
)
<Axes: xlabel='Impact category', ylabel='Impact score'>
As you can see, the y-axis only goes up to 1.0. This is because we normalised the data.