Australia SAF Policy Cost-Benefit Analysis
Model SAF blending mandates and visualise policy trade-offs in Python.
Introduction
30 Second Summary
Every time you board a domestic flight in Australia, about a third of your ticket price goes straight to jet fuel. The aviation industry is under pressure to decarbonise, but the cleaner alternative costs significantly more.
In this project, you will build a cost-benefit analysis that answers whether Australian airlines and passengers should pay more for sustainable aviation fuel, and whether the economic benefits justify the cost.
What You'll Build
A Jupyter Notebook that models the costs and benefits of SAF blending mandates for Australian aviation using real published data from CSIRO, Deloitte, and the Australian Government.
By the end of this project, you'll have:
- A completed cost-benefit analysis notebook comparing three SAF policy scenarios (2%, 5%, and 10% blending targets) with calculations of industry cost, passenger impact, and economic returns.
- Four professional data visualisations suitable for a policy document, including a cost-vs-benefit comparison, cost-per-passenger chart, benefit-cost ratio chart, and emissions reduction chart.
- A policy brief with evidence-based recommendations written in the style of Deloitte Access Economics, demonstrating your ability to translate quantitative modelling into persuasive advice for decision-makers.
- Secret Mission: a sensitivity analysis showing how oil prices and SAF cost trajectories change the policy calculus.
Are there any prerequisites?
You need basic Python syntax (variables, functions, lists) and Anaconda installed on your machine. Familiarity with pandas DataFrames is helpful but not required.
Set Up the Notebook
Every professional analysis starts with a well-configured environment. Consistent styling and clear documentation make your work reproducible and polished.
In this step, you will import the data analysis libraries that power your cost-benefit model, set a professional chart style, and add a title block to your notebook.
In this step, get ready to:
- Import pandas, numpy, matplotlib, and seaborn.
- Configure professional chart styling for your policy visualisations.
- Add a title and executive summary placeholder to the notebook.
Import the data analysis libraries
Your analysis relies on four libraries that handle different parts of the workflow. pandas manages tabular data, NumPy handles numerical calculations, and matplotlib plus seaborn produce the charts.
- Click into the first empty cell in your saf_green_premium_analysis.ipynb notebook.
- Make sure the cell type dropdown (in the toolbar) says Code.
- Paste the following code into the cell:
# Cell 1: Imports and Setup
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# Set professional plot style
plt.style.use('seaborn-v0_8-whitegrid')
sns.set_palette("colorblind")
plt.rcParams['figure.figsize'] = (10, 6)
plt.rcParams['font.size'] = 11
What does this code do?
The first four lines import the libraries you need. The as keyword gives each library a short alias so you can type pd instead of pandas every time you use it.
The style configuration lines set chart defaults for the entire notebook. seaborn-v0_8-whitegrid gives charts a clean grid background. The colorblind palette ensures your charts are accessible to all readers.
- Run the cell by pressing Shift+Enter.
- You should see no output and no error messages. The cell number on the left changes from In [ ] to In [1], confirming the code ran successfully.
Seeing a ModuleNotFoundError?
All four libraries come pre-installed with Anaconda. If you see an import error, you may have launched a non-Anaconda Python kernel.
- In the Jupyter toolbar, click Kernel, then Change kernel, and select the kernel that includes "anaconda" or "base" in its name.
- Re-run the cell with Shift+Enter.
Why can't Jupyter find my libraries?
Add a title markdown cell
Professional notebooks open with a clear title, author name, and a brief summary of the analysis. This mirrors how Deloitte Access Economics formats deliverables for clients.
- Click at the very top of the notebook, above your imports cell.
- In the menu bar, click Insert, then Insert Cell Above.
- Change the cell type dropdown from Code to Markdown.
- Paste the following into the new markdown cell:
# SAF Green Premium Analysis
**Author:** [[YOURNAME="your full name"]]
**Date:** [[TODAYS_DATE="today's date (e.g. 4 July 2026)"]]
## Executive Summary
This analysis examines the cost-benefit case for Sustainable Aviation Fuel (SAF) blending mandates in Australian aviation. Using published data from CSIRO, Deloitte, and the Australian Government, it models the economic impact of 2%, 5%, and 10% blending targets and provides evidence-based policy recommendations.
*[This summary will be updated with key findings as the analysis progresses.]*
What does this markdown cell do?
Markdown cells in Jupyter Notebook render as formatted text instead of running code. The # symbol creates a heading, **text** makes text bold, and *text* makes text italic.
The executive summary placeholder gives your notebook the structure of a Deloitte policy brief from the start. You will update it with actual findings at the end of the project.
- Run the markdown cell by pressing Shift+Enter.
- You should see the title rendered as a large heading, your name in bold, and the executive summary as a formatted paragraph.
- Save your notebook by pressing Cmd+S (macOS) or Ctrl+S (Windows).
Seeing raw markdown text instead of formatted output?
If the cell still shows the raw # and ** symbols, the cell type is still set to Code. Change the dropdown in the toolbar to Markdown and press Shift+Enter again.
My markdown cell isn't rendering properly in Jupyter. How do I fix this?
✔️ Awesome, I've got everything!
Great. Double check you have saved your notebook before moving on.
ⓧ I'd like to double check the full code
Here is the complete code for your imports cell (Cell 1). Your markdown title cell sits above this cell in the notebook.
# Cell 1: Imports and Setup
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# Set professional plot style
plt.style.use('seaborn-v0_8-whitegrid')
sns.set_palette("colorblind")
plt.rcParams['figure.figsize'] = (10, 6)
plt.rcParams['font.size'] = 11
Your analytical environment is ready and your notebook has a professional structure. Next up, you will build the data model that powers the entire cost-benefit analysis.
Build the Data Model
Your notebook is set up and ready for analysis. Now it's time to give it something to analyse.
Every policy cost-benefit analysis starts with a data model. You need to capture the key market figures, define the policy scenarios you want to test, and quantify the expected benefits. In this step, you'll build three pandas DataFrames that form the backbone of your analysis.
In this step, get ready to:
- Create a market data DataFrame with published aviation fuel figures and their sources.
- Model three SAF blending scenarios (2%, 5%, 10%) with cost calculations.
- Calculate economic benefits and a benefit-cost ratio for each scenario.
Create the aviation fuel market DataFrame
Policy analysis at firms like Deloitte Access Economics starts by collecting published figures from authoritative sources and structuring them for calculation. You'll build a DataFrame that captures Australia's aviation fuel market in a single, citable reference table.
- Click on the next empty cell below your imports cell in your notebook.
- Paste the following code into the cell:
# Cell 2: Australia Aviation Fuel Market Data
market_data = {
'metric': [
'Annual jet fuel consumption (billion litres)',
'Projected 2050 consumption (billion litres)',
'Current jet fuel price (AUD/litre)',
'SAF green premium (AUD/litre)',
'Fuel as % of airline cost base',
'Domestic passengers per year (million)',
'Average domestic airfare (AUD)',
'Australia fuel import dependence (%)'
],
'value': [
10.0, 17.5, 1.50, 2.80, 35.0, 65.0, 350.0, 80.0
],
'source': [
'ABC News, April 2026',
'ABC News, April 2026 (75% increase projection)',
'CSIRO SAF Roadmap, 2023',
'Deloitte analysis, 2025 (cited in ABC News)',
'CSIRO SAF Roadmap, 2023',
'BITRE Aviation Statistics (approximate)',
'Approximate industry average',
'CEFC/Deloitte Refined Ambitions, 2025'
]
}
df_market = pd.DataFrame(market_data)
print('=== Australian Aviation Fuel Market Overview ===')
print(df_market.to_string(index=False))
What does this code do?
This cell creates a structured dictionary with three columns: the metric name, its numerical value, and the published source it came from. The figures are drawn from CSIRO, Deloitte, and government reports.
The key figure driving the entire analysis is the SAF green premium of $2.80 per litre. This is how much more Australian-made SAF costs compared to conventional jet fuel. Every cost calculation in this notebook flows from that gap.
- Run the cell by pressing Shift+Enter.
- You should see a neatly formatted table with all 8 metrics, their values, and source citations printed below the cell.
Seeing a NameError?
If you see an error mentioning pd is not defined, your imports cell (Cell 1) hasn't been run yet. Click on Cell 1 and press Shift+Enter to run it first, then run Cell 2 again.
help me debug a NameError in my Jupyter Notebook
Why include a source column?
In professional policy analysis, every number needs a citation. Including the source directly in your DataFrame means anyone reviewing your notebook can verify your inputs without hunting through external references. This is standard practice at consulting firms like Deloitte Access Economics.
Model three SAF blending policy scenarios
With your market data established, you can now ask the core policy question: what would it actually cost if Australia mandated airlines to use 2%, 5%, or 10% SAF? This cell translates those targets into dollar figures.
- Click on the next empty cell below your market data output.
- Paste the following code into the cell:
# Cell 3: Policy Scenario Modelling
annual_consumption_litres = 10e9
green_premium_per_litre = 2.80
domestic_passengers = 65e6
average_airfare = 350.0
scenarios = {
'Blending Target (%)': [2, 5, 10],
'SAF Volume Required (million litres)': [
annual_consumption_litres * 0.02 / 1e6,
annual_consumption_litres * 0.05 / 1e6,
annual_consumption_litres * 0.10 / 1e6
],
'Additional Industry Cost (AUD billion/year)': [
annual_consumption_litres * 0.02 * green_premium_per_litre / 1e9,
annual_consumption_litres * 0.05 * green_premium_per_litre / 1e9,
annual_consumption_litres * 0.10 * green_premium_per_litre / 1e9
],
'Cost Per Passenger Per Flight (AUD)': [
(annual_consumption_litres * 0.02 * green_premium_per_litre) / domestic_passengers,
(annual_consumption_litres * 0.05 * green_premium_per_litre) / domestic_passengers,
(annual_consumption_litres * 0.10 * green_premium_per_litre) / domestic_passengers
]
}
df_scenarios = pd.DataFrame(scenarios)
print('\n=== Policy Scenario Cost Analysis ===')
print(df_scenarios.to_string(index=False))
What does this code do?
The variables at the top (annual_consumption_litres, green_premium_per_litre, etc.) store the key inputs from your market data. Defining them as named variables means every calculation below stays readable and easy to update.
For each blending target, the code calculates three things: how many litres of SAF would be needed, what that costs the industry in total, and what it means per passenger. The per-passenger figure is what decision-makers care about most. It answers the question: how much more would you pay for a flight?
- Run the cell by pressing Shift+Enter.
- You should see a table showing three rows (one per blending target) with the SAF volume, industry cost, and cost per passenger for each scenario.
Seeing all zeros in the output?
Check that annual_consumption_litres is set to 10e9 (10 billion), not 10. The e9 is scientific notation for multiplying by one billion.
help me fix my scenario calculations
Calculate economic benefits and the benefit-cost ratio
Costs alone don't tell the full story. A good cost-benefit analysis also quantifies what Australia gains from a SAF mandate: jobs, emissions reductions, and reduced dependence on imported fuel. This cell builds the benefits side and produces the single number decision-makers need: the benefit-cost ratio.
- Click on the next empty cell below your scenario output.
- Paste the following code into the cell:
# Cell 4: Economic Benefits Data
blending_targets = [2, 5, 10]
jobs_per_percent = 1800
co2_per_litre_saved = 2.5 * 0.65
import_bill_reduction_per_litre = 1.50
benefits = {
'Blending Target (%)': blending_targets,
'Jobs Created': [jobs_per_percent * t for t in blending_targets],
'Annual CO2 Reduction (million tonnes)': [
annual_consumption_litres * (t/100) * co2_per_litre_saved / 1e9
for t in blending_targets
],
'Fuel Security Value (AUD billion/year)': [
annual_consumption_litres * (t/100) * import_bill_reduction_per_litre / 1e9
for t in blending_targets
],
'Annual Economic Benefit (AUD billion)': [
(jobs_per_percent * t * 80000 / 1e9) +
(annual_consumption_litres * (t/100) * import_bill_reduction_per_litre / 1e9) +
(annual_consumption_litres * (t/100) * co2_per_litre_saved / 1e9 * 0.075)
for t in blending_targets
]
}
df_benefits = pd.DataFrame(benefits)
print('\n=== Economic Benefits by Scenario ===')
print(df_benefits.to_string(index=False))
df_combined = pd.DataFrame({
'Blending Target (%)': blending_targets,
'Annual Cost (AUD billion)': df_scenarios['Additional Industry Cost (AUD billion/year)'].values,
'Annual Benefit (AUD billion)': df_benefits['Annual Economic Benefit (AUD billion)'].values
})
df_combined['Benefit-Cost Ratio'] = df_combined['Annual Benefit (AUD billion)'] / df_combined['Annual Cost (AUD billion)']
print('\n=== Benefit-Cost Summary ===')
print(df_combined.to_string(index=False))
What does this code do?
The first half builds a benefits DataFrame with three value streams for each blending target. Jobs are scaled at 1,800 per percentage point (based on ARENA's estimate of 18,000 jobs at full scale). Emissions savings use a 65% lifecycle reduction factor. Fuel security is valued at $1.50 per litre of domestic production replacing imports.
The second half creates df_combined, which brings costs and benefits together and divides benefit by cost to produce the ratio. A ratio above 1.0 means benefits exceed costs. This single number is what your charts and policy brief will revolve around.
- Run the cell by pressing Shift+Enter.
- You should see two printed tables. The first shows jobs, emissions, and fuel security values per scenario. The second shows the benefit-cost ratio for each blending target.
Seeing a NameError for annual_consumption_litres?
Cell 4 uses variables defined in Cell 3 (annual_consumption_litres and df_scenarios). If you skipped running Cell 3, those variables don't exist yet. Run Cell 3 first, then re-run Cell 4.
help me fix cell dependency errors in Jupyter
✔️ Awesome, I've got everything!
Great. Double check that you've saved your notebook by pressing Cmd+S (macOS) or Ctrl+S (Windows).
ⓧ I'd like to double check the full code
Here is the complete code for your notebook up to this point. Compare it against your cells to spot any differences.
# Cell 1: Imports and Setup
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
plt.style.use('seaborn-v0_8-whitegrid')
sns.set_palette("colorblind")
plt.rcParams['figure.figsize'] = (10, 6)
plt.rcParams['font.size'] = 11
# Cell 2: Australia Aviation Fuel Market Data
market_data = {
'metric': [
'Annual jet fuel consumption (billion litres)',
'Projected 2050 consumption (billion litres)',
'Current jet fuel price (AUD/litre)',
'SAF green premium (AUD/litre)',
'Fuel as % of airline cost base',
'Domestic passengers per year (million)',
'Average domestic airfare (AUD)',
'Australia fuel import dependence (%)'
],
'value': [
10.0, 17.5, 1.50, 2.80, 35.0, 65.0, 350.0, 80.0
],
'source': [
'ABC News, April 2026',
'ABC News, April 2026 (75% increase projection)',
'CSIRO SAF Roadmap, 2023',
'Deloitte analysis, 2025 (cited in ABC News)',
'CSIRO SAF Roadmap, 2023',
'BITRE Aviation Statistics (approximate)',
'Approximate industry average',
'CEFC/Deloitte Refined Ambitions, 2025'
]
}
df_market = pd.DataFrame(market_data)
print('=== Australian Aviation Fuel Market Overview ===')
print(df_market.to_string(index=False))
# Cell 3: Policy Scenario Modelling
annual_consumption_litres = 10e9
green_premium_per_litre = 2.80
domestic_passengers = 65e6
average_airfare = 350.0
scenarios = {
'Blending Target (%)': [2, 5, 10],
'SAF Volume Required (million litres)': [
annual_consumption_litres * 0.02 / 1e6,
annual_consumption_litres * 0.05 / 1e6,
annual_consumption_litres * 0.10 / 1e6
],
'Additional Industry Cost (AUD billion/year)': [
annual_consumption_litres * 0.02 * green_premium_per_litre / 1e9,
annual_consumption_litres * 0.05 * green_premium_per_litre / 1e9,
annual_consumption_litres * 0.10 * green_premium_per_litre / 1e9
],
'Cost Per Passenger Per Flight (AUD)': [
(annual_consumption_litres * 0.02 * green_premium_per_litre) / domestic_passengers,
(annual_consumption_litres * 0.05 * green_premium_per_litre) / domestic_passengers,
(annual_consumption_litres * 0.10 * green_premium_per_litre) / domestic_passengers
]
}
df_scenarios = pd.DataFrame(scenarios)
print('\n=== Policy Scenario Cost Analysis ===')
print(df_scenarios.to_string(index=False))
# Cell 4: Economic Benefits Data
blending_targets = [2, 5, 10]
jobs_per_percent = 1800
co2_per_litre_saved = 2.5 * 0.65
import_bill_reduction_per_litre = 1.50
benefits = {
'Blending Target (%)': blending_targets,
'Jobs Created': [jobs_per_percent * t for t in blending_targets],
'Annual CO2 Reduction (million tonnes)': [
annual_consumption_litres * (t/100) * co2_per_litre_saved / 1e9
for t in blending_targets
],
'Fuel Security Value (AUD billion/year)': [
annual_consumption_litres * (t/100) * import_bill_reduction_per_litre / 1e9
for t in blending_targets
],
'Annual Economic Benefit (AUD billion)': [
(jobs_per_percent * t * 80000 / 1e9) +
(annual_consumption_litres * (t/100) * import_bill_reduction_per_litre / 1e9) +
(annual_consumption_litres * (t/100) * co2_per_litre_saved / 1e9 * 0.075)
for t in blending_targets
]
}
df_benefits = pd.DataFrame(benefits)
print('\n=== Economic Benefits by Scenario ===')
print(df_benefits.to_string(index=False))
df_combined = pd.DataFrame({
'Blending Target (%)': blending_targets,
'Annual Cost (AUD billion)': df_scenarios['Additional Industry Cost (AUD billion/year)'].values,
'Annual Benefit (AUD billion)': df_benefits['Annual Economic Benefit (AUD billion)'].values
})
df_combined['Benefit-Cost Ratio'] = df_combined['Annual Benefit (AUD billion)'] / df_combined['Annual Cost (AUD billion)']
print('\n=== Benefit-Cost Summary ===')
print(df_combined.to_string(index=False))
Your data model is complete. You have the costs, the benefits, and the ratio that ties them together. Next up, you'll turn these numbers into professional visualisations that make the story impossible to miss.
Visualise the Analysis
You have a data model that quantifies the costs and benefits of SAF blending mandates. Numbers in a table are useful for calculation, but decision-makers respond to visual evidence.
In this step, you will create four professional charts that tell the story of your analysis. Each chart answers a specific question a policymaker would ask: Is this affordable? Does the benefit justify the cost? What is the environmental payoff?
In this step, get ready to:
- Create a grouped bar chart comparing cost to industry vs. economic benefit for each scenario.
- Visualise the per-passenger cost impact with reference lines showing how small it is relative to airfares.
- Build benefit-cost ratio and emissions reduction charts that make the policy case visually clear.
Create the cost vs. benefit grouped bar chart
The first question a policymaker asks is simple: does the benefit outweigh the cost? A grouped bar chart places these two values side by side for each blending scenario so the comparison is immediate.
- Create a new cell below Cell 4 and paste the following code:
# Cell 5: Chart 1 - Cost vs Benefit Comparison
fig, ax = plt.subplots(figsize=(10, 6))
x = np.arange(len(blending_targets))
width = 0.35
bars1 = ax.bar(x - width/2, df_combined['Annual Cost (AUD billion)'], width,
label='Annual Cost to Industry', color='#d62728', alpha=0.8)
bars2 = ax.bar(x + width/2, df_combined['Annual Benefit (AUD billion)'], width,
label='Annual Economic Benefit', color='#2ca02c', alpha=0.8)
ax.set_xlabel('SAF Blending Target')
ax.set_ylabel('AUD Billion per Year')
ax.set_title('Cost vs. Economic Benefit of SAF Blending Mandates\nAustralian Aviation Sector')
ax.set_xticks(x)
ax.set_xticklabels(['2%', '5%', '10%'])
ax.legend()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.tight_layout()
plt.savefig('chart1_cost_vs_benefit.png', dpi=150, bbox_inches='tight')
plt.show()
What does this code do?
This creates a grouped bar chart with red bars for cost and green bars for benefit at each blending target (2%, 5%, 10%).
- np.arange(len(blending_targets)) creates evenly spaced positions for the bar groups on the x-axis.
- The width/2 offset places cost bars slightly left and benefit bars slightly right so they sit side by side.
- plt.savefig() exports the chart as a PNG file for your portfolio.
- Run the cell by pressing Shift+Enter.
- You should see a grouped bar chart displayed inline. The green bars (benefit) should be taller than the red bars (cost) at every scenario.
Don't see a chart?
Make sure you ran Cells 1-4 first. The chart depends on df_combined and blending_targets which are created in earlier cells.
If you see a NameError, click into Cell 1 and run each cell in order from the top using Shift+Enter.
Help me debug my chart
Create the cost-per-passenger impact chart
A billion-dollar cost sounds alarming in isolation. The next chart reframes that cost at the individual passenger level, showing it relative to the average domestic airfare.
- Create a new cell below Cell 5 and paste the following code:
# Cell 6: Chart 2 - Cost Per Passenger Impact
fig, ax = plt.subplots(figsize=(10, 6))
cost_per_pax = df_scenarios['Cost Per Passenger Per Flight (AUD)'].values
ax.bar(['2%', '5%', '10%'], cost_per_pax, color='#1f77b4', alpha=0.8, width=0.5)
ax.axhline(y=average_airfare, color='gray', linestyle='--', alpha=0.5,
label=f'Average domestic airfare (${average_airfare:.0f})')
ax.axhline(y=average_airfare * 0.01, color='orange', linestyle='--', alpha=0.7,
label='1% of average airfare')
ax.set_xlabel('SAF Blending Target')
ax.set_ylabel('Additional Cost Per Passenger (AUD)')
ax.set_title('Impact on Passenger: Additional Cost Per Domestic Flight\nUnder SAF Blending Scenarios')
ax.legend(loc='upper left')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# Add value labels on bars
for i, v in enumerate(cost_per_pax):
ax.text(i, v + 0.1, f'${v:.2f}', ha='center', fontweight='bold')
plt.tight_layout()
plt.savefig('chart2_cost_per_passenger.png', dpi=150, bbox_inches='tight')
plt.show()
What does this code do?
This chart puts the cost in human terms. Instead of billions, it shows the dollar amount each passenger would pay extra per flight.
- ax.axhline() draws horizontal reference lines. The gray dashed line marks the $350 average domestic airfare. The orange line marks 1% of that airfare.
- The for loop adds dollar-value labels directly on top of each bar so the exact cost is visible without reading the axis.
When the bars are far below the reference lines, the visual argument is immediate: the SAF cost is a tiny fraction of what passengers already pay.
- Run the cell by pressing Shift+Enter.
- You should see a bar chart with three blue bars sitting well below a gray dashed line at $350 and an orange dashed line near the bottom of the chart.
Bars look squished or invisible?
The bars represent small values ($0.86 to $4.31) while the reference line sits at $350. This large scale difference is intentional. If you cannot see the bars at all, check that you used cost_per_pax (not df_combined) as the bar values.
Help me fix my passenger cost chart
Create the benefit-cost ratio and emissions charts
The final two charts answer the bottom-line questions. Does the benefit exceed the cost (ratio above 1.0)? How many tonnes of CO2 do we actually avoid?
- Create a new cell below Cell 6 and paste the following code for the benefit-cost ratio chart:
# Cell 7: Chart 3 - Benefit-Cost Ratio
fig, ax = plt.subplots(figsize=(10, 5))
ratios = df_combined['Benefit-Cost Ratio'].values
colors = ['#2ca02c' if r > 1.0 else '#d62728' for r in ratios]
bars = ax.barh(['2% Blend', '5% Blend', '10% Blend'], ratios, color=colors, alpha=0.8, height=0.5)
ax.axvline(x=1.0, color='black', linestyle='-', linewidth=1.5, label='Break-even (ratio = 1.0)')
ax.set_xlabel('Benefit-Cost Ratio')
ax.set_title('Benefit-Cost Ratio of SAF Blending Mandates\n(Values > 1.0 indicate net positive economic impact)')
ax.legend(loc='lower right')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# Add value labels
for i, v in enumerate(ratios):
ax.text(v + 0.02, i, f'{v:.2f}', va='center', fontweight='bold')
plt.tight_layout()
plt.savefig('chart3_benefit_cost_ratio.png', dpi=150, bbox_inches='tight')
plt.show()
What does this code do?
- ax.barh() creates horizontal bars. This orientation makes it easy to read the ratio values from left to right.
- The colour logic assigns green to ratios above 1.0 (benefits exceed costs) and red to ratios below 1.0. This is conditional formatting applied at plot time.
- ax.axvline(x=1.0) draws a solid vertical line at the break-even point. Any bar extending past this line represents a net-positive policy.
- Run the cell by pressing Shift+Enter.
- You should see a horizontal bar chart. All three bars should extend past the vertical black break-even line at 1.0, indicating net-positive outcomes.
Bars are all red?
If all bars are red instead of green, your benefit-cost ratios may be below 1.0. This usually means Cell 4 has an error in the benefits calculation. Re-run Cell 4 and check that df_combined['Benefit-Cost Ratio'] values are all above 1.0.
Help me debug my benefit-cost ratio chart
Now for the final chart. This one quantifies the environmental payoff in concrete terms: tonnes of CO2 avoided per year.
- Create a new cell below Cell 7 and paste the following code:
# Cell 8: Chart 4 - Emissions Reduction Potential
fig, ax = plt.subplots(figsize=(10, 6))
emissions = df_benefits['Annual CO2 Reduction (million tonnes)'].values
ax.bar(['2%', '5%', '10%'], emissions, color='#17becf', alpha=0.8, width=0.5)
ax.set_xlabel('SAF Blending Target')
ax.set_ylabel('Annual CO2 Reduction (Million Tonnes)')
ax.set_title('Aviation Emissions Reduction Under SAF Blending Scenarios\n(Based on 65% lifecycle emission reduction vs. conventional jet fuel)')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
for i, v in enumerate(emissions):
ax.text(i, v + 0.01, f'{v:.2f} Mt', ha='center', fontweight='bold')
plt.tight_layout()
plt.savefig('chart4_emissions_reduction.png', dpi=150, bbox_inches='tight')
plt.show()
What does this code do?
- emissions pulls the pre-calculated CO2 reduction values from your benefits DataFrame.
- The subtitle references the 65% lifecycle emission reduction figure. This comes from the ARENA Jet Zero Lessons Learnt Report and grounds the chart in a cited source.
- Value labels show the exact megatonne figure above each bar, making the chart readable without needing to trace to the y-axis.
- Run the cell by pressing Shift+Enter.
- You should see a bar chart with three cyan bars showing increasing CO2 reductions from the 2% scenario to the 10% scenario, with megatonne labels above each bar.
Seeing a KeyError?
If you see a KeyError mentioning the column name, check that your Cell 4 DataFrame uses the exact column name Annual CO2 Reduction (million tonnes). Column names are case-sensitive and must match exactly.
Help me fix my emissions chart
✔️ Awesome, I've got everything!
Great. Double check you have all four charts displaying inline in your notebook. Save your notebook using Cmd+S (macOS) or Ctrl+S (Windows).
ⓧ I'd like to double check the full code
Here are all four chart cells together. Compare against your notebook:
# Cell 5: Chart 1 - Cost vs Benefit Comparison
fig, ax = plt.subplots(figsize=(10, 6))
x = np.arange(len(blending_targets))
width = 0.35
bars1 = ax.bar(x - width/2, df_combined['Annual Cost (AUD billion)'], width,
label='Annual Cost to Industry', color='#d62728', alpha=0.8)
bars2 = ax.bar(x + width/2, df_combined['Annual Benefit (AUD billion)'], width,
label='Annual Economic Benefit', color='#2ca02c', alpha=0.8)
ax.set_xlabel('SAF Blending Target')
ax.set_ylabel('AUD Billion per Year')
ax.set_title('Cost vs. Economic Benefit of SAF Blending Mandates\nAustralian Aviation Sector')
ax.set_xticks(x)
ax.set_xticklabels(['2%', '5%', '10%'])
ax.legend()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.tight_layout()
plt.savefig('chart1_cost_vs_benefit.png', dpi=150, bbox_inches='tight')
plt.show()
# Cell 6: Chart 2 - Cost Per Passenger Impact
fig, ax = plt.subplots(figsize=(10, 6))
cost_per_pax = df_scenarios['Cost Per Passenger Per Flight (AUD)'].values
ax.bar(['2%', '5%', '10%'], cost_per_pax, color='#1f77b4', alpha=0.8, width=0.5)
ax.axhline(y=average_airfare, color='gray', linestyle='--', alpha=0.5,
label=f'Average domestic airfare (${average_airfare:.0f})')
ax.axhline(y=average_airfare * 0.01, color='orange', linestyle='--', alpha=0.7,
label='1% of average airfare')
ax.set_xlabel('SAF Blending Target')
ax.set_ylabel('Additional Cost Per Passenger (AUD)')
ax.set_title('Impact on Passenger: Additional Cost Per Domestic Flight\nUnder SAF Blending Scenarios')
ax.legend(loc='upper left')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# Add value labels on bars
for i, v in enumerate(cost_per_pax):
ax.text(i, v + 0.1, f'${v:.2f}', ha='center', fontweight='bold')
plt.tight_layout()
plt.savefig('chart2_cost_per_passenger.png', dpi=150, bbox_inches='tight')
plt.show()
# Cell 7: Chart 3 - Benefit-Cost Ratio
fig, ax = plt.subplots(figsize=(10, 5))
ratios = df_combined['Benefit-Cost Ratio'].values
colors = ['#2ca02c' if r > 1.0 else '#d62728' for r in ratios]
bars = ax.barh(['2% Blend', '5% Blend', '10% Blend'], ratios, color=colors, alpha=0.8, height=0.5)
ax.axvline(x=1.0, color='black', linestyle='-', linewidth=1.5, label='Break-even (ratio = 1.0)')
ax.set_xlabel('Benefit-Cost Ratio')
ax.set_title('Benefit-Cost Ratio of SAF Blending Mandates\n(Values > 1.0 indicate net positive economic impact)')
ax.legend(loc='lower right')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# Add value labels
for i, v in enumerate(ratios):
ax.text(v + 0.02, i, f'{v:.2f}', va='center', fontweight='bold')
plt.tight_layout()
plt.savefig('chart3_benefit_cost_ratio.png', dpi=150, bbox_inches='tight')
plt.show()
# Cell 8: Chart 4 - Emissions Reduction Potential
fig, ax = plt.subplots(figsize=(10, 6))
emissions = df_benefits['Annual CO2 Reduction (million tonnes)'].values
ax.bar(['2%', '5%', '10%'], emissions, color='#17becf', alpha=0.8, width=0.5)
ax.set_xlabel('SAF Blending Target')
ax.set_ylabel('Annual CO2 Reduction (Million Tonnes)')
ax.set_title('Aviation Emissions Reduction Under SAF Blending Scenarios\n(Based on 65% lifecycle emission reduction vs. conventional jet fuel)')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
for i, v in enumerate(emissions):
ax.text(i, v + 0.01, f'{v:.2f} Mt', ha='center', fontweight='bold')
plt.tight_layout()
plt.savefig('chart4_emissions_reduction.png', dpi=150, bbox_inches='tight')
plt.show()
You now have four publication-quality charts that tell a clear visual story. Next up, you will weave these charts into a written policy brief that translates the numbers into persuasive recommendations for decision-makers.
Write the Policy Brief
Your data model produces the numbers, and your charts make the numbers visible. But a Deloitte Access Economics deliverable needs one more layer: narrative that connects the analysis to a decision.
In this step, you will add professional markdown cells that frame your analysis as a policy brief, write specific recommendations, and export the finished notebook as a portfolio-ready deliverable.
In this step, get ready to:
- Add narrative markdown cells structured as Context, Key Findings, and Implications.
- Write a Recommendations section with evidence-based policy advice in DAE style.
- Review and export the notebook as both .ipynb and .html.
Add narrative markdown cells between your code sections
Raw code cells with output tables tell you that the numbers work. Markdown cells tell the reader why those numbers matter. The difference is what separates an analysis script from a consulting deliverable.
You will add three markdown cells that structure the narrative as: Context (why this matters now), Key Findings (3 bullet points with numbers), and Implications (what decision-makers should take away).
- In your Jupyter Notebook, click between Cell 1 (Imports) and Cell 2 (Market Data) to position your cursor there.
- Click the + button in the toolbar to insert a new cell.
- Change the cell type from Code to Markdown using the dropdown in the toolbar.
- Paste the following context narrative into the markdown cell:
## Context: Why SAF Policy Matters Now
Australia's aviation sector consumes approximately 10 billion litres of jet fuel per year,
80% of which is imported. The 2026-27 Federal Budget announced a demand-side measure for
low-carbon liquid fuels, signalling that a blending mandate is imminent.
This analysis quantifies the cost to airlines and passengers under three blending scenarios
(2%, 5%, and 10%), then compares those costs against the economic benefits of domestic SAF
production: jobs, fuel security, and emissions reduction.
**Data sources:** CSIRO SAF Roadmap (2023), CEFC/Deloitte *Refined Ambitions* (2025),
ARENA Jet Zero Lessons Learnt Report (2026), Australian Government media releases.
What makes this a policy-style opening?
Notice three things: it starts with the scale of the problem (10 billion litres, 80% imported), names the policy trigger (2026-27 Budget announcement), and clearly states what the analysis will answer. This mirrors how DAE frames briefings for government clients.
- Now insert another markdown cell after Cell 4 (Economic Benefits Data), using the same process of clicking between cells and adding a new Markdown cell.
- Paste the following Key Findings and Implications narrative:
## Key Findings
1. **Cost to industry is modest relative to revenue.** A 10% SAF blending mandate would
cost the aviation industry approximately $2.8 billion per year, equivalent to just
$4.31 per domestic passenger per flight.
2. **Benefits exceed costs across all scenarios.** Every blending target tested produces
a benefit-cost ratio above 1.0, meaning the economic returns (jobs, fuel security,
emissions value) outweigh the additional fuel cost.
3. **Passenger impact is minimal.** Even at 10% blending, the per-flight cost increase
represents approximately 1.2% of the average domestic airfare.
## Implications for Decision-Makers
The analysis supports early action on a SAF blending mandate. The green premium is real
but manageable, and the economic case strengthens as domestic production scales. Delaying
action risks ceding first-mover advantage to competing fuel-exporting nations while
Australia's import dependence remains at 80%.
What does this structure do?
The Key Findings section uses numbered bullet points with bold lead-ins. Each finding starts with the conclusion, then provides the supporting number. This is the inverted-pyramid style that policy readers expect.
The Implications section connects the numbers to a recommendation without being prescriptive yet. It creates urgency (first-mover advantage, 80% import dependence) while staying evidence-based.
- Press Shift+Enter on each markdown cell to render it.
- Confirm both cells display as formatted text with bold headings and numbered lists.
Markdown cell showing raw text instead of formatted output?
Make sure the cell type dropdown says Markdown (not Code). If you accidentally ran it as a code cell, change the type to Markdown and press Shift+Enter again.
help me fix my markdown cell rendering
Add the Recommendations section and summary output
The Recommendations section is where the analysis becomes advice. DAE frames each recommendation as: what to do, why (citing your evidence), and what the expected outcome is.
- Insert a new Markdown cell after your last chart cell (Cell 8 - Emissions Reduction).
- Paste the following Recommendations content:
## Recommendations
Based on this cost-benefit analysis, we recommend the following:
**1. Implement a 5% SAF blending mandate from 2030, escalating to 10% by 2035.**
The 5% target balances ambition with supply readiness. Australia's four most advanced
SAF refinery projects have a combined expected capacity of 1.4 billion litres, exceeding
the 500 million litres required for a 5% mandate. Escalation to 10% by 2035 aligns with
CSIRO projections of expanded feedstock availability.
**2. Pair the mandate with the $1.1 billion Cleaner Fuels Program to de-risk producer investment.**
A demand mandate alone creates certainty for buyers but does not address production risk.
The Cleaner Fuels Program should prioritise projects that can deliver first production by
2029, creating a domestic supply base before the mandate takes effect.
**3. Index the mandate to verified domestic production capacity.**
If domestic supply falls short, airlines should not be forced to purchase imported SAF at
higher prices. A capacity-indexed trigger protects against supply-side shocks while
maintaining long-term ambition.
Why three specific recommendations?
DAE typically provides 2-3 actionable recommendations that a decision-maker could implement. Each one references data from your analysis (the 500 million litre threshold, the $1.1 billion program, the supply constraint). Generic advice like "invest in SAF" would not meet the standard.
- Press Shift+Enter to render the Recommendations cell.
- Now create a new Code cell (not Markdown) directly below the Recommendations cell.
- Paste the following summary output code into this new code cell:
# Cell 9: Summary Output Table
print('\n' + '='*70)
print('POLICY BRIEF: SAF Blending Mandate Cost-Benefit Analysis')
print('='*70)
print(f'\nKey Finding: A 10% SAF blending mandate would cost the aviation')
print(f'industry approximately ${df_combined["Annual Cost (AUD billion)"].iloc[2]:.1f} billion per year,')
print(f'equivalent to ${cost_per_pax[2]:.2f} per domestic passenger per flight.')
print(f'\nThis delivers an estimated ${df_combined["Annual Benefit (AUD billion)"].iloc[2]:.2f} billion')
print(f'in annual economic benefits (jobs, fuel security, emissions reduction),')
print(f'yielding a benefit-cost ratio of {ratios[2]:.2f}.')
print(f'\nAt the passenger level, the cost represents just')
print(f'{(cost_per_pax[2]/average_airfare)*100:.1f}% of the average domestic airfare.')
print('='*70)
What does this code do?
- It pulls the 10% scenario figures directly from your DataFrames using .iloc[2] (the third row, which is the 10% target).
- The f-string formatting (:.1f, :.2f) ensures numbers display with consistent decimal places.
- The output reads like a policy brief executive summary, not a data dump.
- Press Shift+Enter to run the cell.
- You should see a formatted text block with the heading "POLICY BRIEF: SAF Blending Mandate Cost-Benefit Analysis" followed by the key finding numbers for cost, benefit, and benefit-cost ratio.
Seeing a NameError for df_combined or cost_per_pax?
This means your earlier cells have not been run in the current kernel session. Click Kernel in the top menu, then Restart & Run All to re-execute every cell from the top.
help me fix a NameError in my Jupyter Notebook
Review the notebook and export for your portfolio
A finished notebook should read top-to-bottom like a document, not a collection of disconnected code cells. Before exporting, you will add one-sentence captions below each chart and do a final read-through.
- Scroll through the notebook from top to bottom.
- Add a brief markdown cell below each chart cell with a one-sentence caption describing what the chart shows. For example, below Chart 1: "Figure 1: Economic benefits exceed costs across all three blending scenarios."
- Confirm every chart has a clear title and axis labels (these were set in your code in the previous step).
- Check that the narrative flows logically: Context, then data, then charts, then findings, then recommendations.
Read it like a recruiter would
Imagine someone opens this notebook for 30 seconds. Can they understand what question you answered, what you found, and what you recommend? If the markdown narrative answers those three questions without requiring them to read any code, you are done.
- Save your notebook by pressing Ctrl+S (Windows) or Cmd+S (macOS). This saves the .ipynb file.
- Export the notebook as HTML by clicking File in the menu bar, then Save and Export Notebook As, then HTML.
- The HTML file will download to your default downloads folder. Move it into your saf-policy-analysis folder so both files live together.
What if the menu says Download as instead?
Older Jupyter Notebook versions show File > Download as > HTML (.html) instead. Either path produces the same result. You can also export from a terminal with:
jupyter nbconvert --to html saf_green_premium_analysis.ipynb
This command works regardless of which Jupyter interface you are using, and places the HTML file in the same folder as the notebook.
- Open the exported saf_green_premium_analysis.html file in your browser to confirm it renders correctly with all charts, narrative, and code visible.
HTML export showing errors or missing charts?
Make sure you ran all cells before exporting. Click Kernel then Restart & Run All first, wait for every cell to finish, then export again. The HTML export captures whatever output is currently displayed in the notebook.
help me fix missing chart outputs in my Jupyter HTML export
✔️ Awesome, I've got everything!
Great. Double check you have saved your notebook and both files (.ipynb and .html) are in your saf-policy-analysis folder.
ⓧ I'd like to double check the full code
Here is the complete Python code across all 9 cells. Your markdown cells are separate and not shown here since they are narrative content, not executable code.
# Cell 1: Imports and Setup
import pandas as pd
import numpy as np
import import matplotlib.pyplot as plt
import seaborn as sns
plt.style.use('seaborn-v0_8-whitegrid')
sns.set_palette("colorblind")
plt.rcParams['figure.figsize'] = (10, 6)
plt.rcParams['font.size'] = 11
# Cell 2: Australia Aviation Fuel Market Data
market_data = {
'metric': ['Annual jet fuel consumption (billion litres)','Projected 2050 consumption (billion litres)','Current jet fuel price (AUD/litre)','SAF green premium (AUD/litre)','Fuel as % of airline cost base','Domestic passengers per year (million)','Average domestic airfare (AUD)','Australia fuel import dependence (%)'],
'value': [10.0,17.5,1.50,2.80,35.0,65.0,350.0,80.0],
'source': ['ABC News, April 2026','ABC News, April 2026 (75% increase projection)','CSIRO SAF Roadmap, 2023','Deloitte analysis, 2025 (cited in ABC News)','CSIRO SAF Roadmap, 2023','BITRE Aviation Statistics (approximate)','Approximate industry average','CEFC/Deloitte Refined Ambitions, 2025']
}
df_market = pd.DataFrame(market_data)
print('=== Australian Aviation Fuel Market Overview ===')
print(df_market.to_string(index=False))
# Cell 3: Policy Scenario Modelling
annual_consumption_litres = 10e9
green_premium_per_litre = 2.80
domestic_passengers = 65e6
average_airfare = 350.0
scenarios = {
'Blending Target (%)': [2, 5, 10],
'SAF Volume Required (million litres)': [annual_consumption_litres * 0.02 / 1e6, annual_consumption_litres * 0.05 / 1e6, annual_consumption_litres * 0.10 / 1e6],
'Additional Industry Cost (AUD billion/year)': [annual_consumption_litres * 0.02 * green_premium_per_litre / 1e9, annual_consumption_litres * 0.05 * green_premium_per_litre / 1e9, annual_consumption_litres * 0.10 * green_premium_per_litre / 1e9],
'Cost Per Passenger Per Flight (AUD)': [(annual_consumption_litres * 0.02 * green_premium_per_litre) / domestic_passengers, (annual_consumption_litres * 0.05 * green_premium_per_litre) / domestic_passengers, (annual_consumption_litres * 0.10 * green_premium_per_litre) / domestic_passengers]
}
df_scenarios = pd.DataFrame(scenarios)
print('\n=== Policy Scenario Cost Analysis ===')
print(df_scenarios.to_string(index=False))
# Cell 4: Economic Benefits Data
blending_targets = [2, 5, 10]
jobs_per_percent = 1800
co2_per_litre_saved = 2.5 * 0.65
import_bill_reduction_per_litre = 1.50
benefits = {
'Blending Target (%)': blending_targets,
'Jobs Created': [jobs_per_percent * t for t in blending_targets],
'Annual CO2 Reduction (million tonnes)': [annual_consumption_litres * (t/100) * co2_per_litre_saved / 1e9 for t in blending_targets],
'Fuel Security Value (AUD billion/year)': [annual_consumption_litres * (t/100) * import_bill_reduction_per_litre / 1e9 for t in blending_targets],
'Annual Economic Benefit (AUD billion)': [(jobs_per_percent * t * 80000 / 1e9) + (annual_consumption_litres * (t/100) * import_bill_reduction_per_litre / 1e9) + (annual_consumption_litres * (t/100) * co2_per_litre_saved / 1e9 * 0.075) for t in blending_targets]
}
df_benefits = pd.DataFrame(benefits)
print('\n=== Economic Benefits by Scenario ===')
print(df_benefits.to_string(index=False))
df_combined = pd.DataFrame({
'Blending Target (%)': blending_targets,
'Annual Cost (AUD billion)': df_scenarios['Additional Industry Cost (AUD billion/year)'].values,
'Annual Benefit (AUD billion)': df_benefits['Annual Economic Benefit (AUD billion)'].values
})
df_combined['Benefit-Cost Ratio'] = df_combined['Annual Benefit (AUD billion)'] / df_combined['Annual Cost (AUD billion)']
print('\n=== Benefit-Cost Summary ===')
print(df_combined.to_string(index=False))
# Cell 5: Chart 1 - Cost vs Benefit Comparison
fig, ax = plt.subplots(figsize=(10, 6))
x = np.arange(len(blending_targets))
width = 0.35
bars1 = ax.bar(x - width/2, df_combined['Annual Cost (AUD billion)'], width, label='Annual Cost to Industry', color='#d62728', alpha=0.8)
bars2 = ax.bar(x + width/2, df_combined['Annual Benefit (AUD billion)'], width, label='Annual Economic Benefit', color='#2ca02c', alpha=0.8)
ax.set_xlabel('SAF Blending Target')
ax.set_ylabel('AUD Billion per Year')
ax.set_title('Cost vs. Economic Benefit of SAF Blending Mandates\nAustralian Aviation Sector')
ax.set_xticks(x)
ax.set_xticklabels(['2%', '5%', '10%'])
ax.legend()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.tight_layout()
plt.savefig('chart1_cost_vs_benefit.png', dpi=150, bbox_inches='tight')
plt.show()
# Cell 6: Chart 2 - Cost Per Passenger Impact
fig, ax = plt.subplots(figsize=(10, 6))
cost_per_pax = df_scenarios['Cost Per Passenger Per Flight (AUD)'].values
ax.bar(['2%', '5%', '10%'], cost_per_pax, color='#1f77b4', alpha=0.8, width=0.5)
ax.axhline(y=average_airfare, color='gray', linestyle='--', alpha=0.5, label=f'Average domestic airfare (${average_airfare:.0f})')
ax.axhline(y=average_airfare * 0.01, color='orange', linestyle='--', alpha=0.7, label='1% of average airfare')
ax.set_xlabel('SAF Blending Target')
ax.set_ylabel('Additional Cost Per Passenger (AUD)')
ax.set_title('Impact on Passenger: Additional Cost Per Domestic Flight\nUnder SAF Blending Scenarios')
ax.legend(loc='upper left')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
for i, v in enumerate(cost_per_pax):
ax.text(i, v + 0.1, f'${v:.2f}', ha='center', fontweight='bold')
plt.tight_layout()
plt.savefig('chart2_cost_per_passenger.png', dpi=150, bbox_inches='tight')
plt.show()
# Cell 7: Chart 3 - Benefit-Cost Ratio
fig, ax = plt.subplots(figsize=(10, 5))
ratios = df_combined['Benefit-Cost Ratio'].values
colors = ['#2ca02c' if r > 1.0 else '#d62728' for r in ratios]
bars = ax.barh(['2% Blend', '5% Blend', '10% Blend'], ratios, color=colors, alpha=0.8, height=0.5)
ax.axvline(x=1.0, color='black', linestyle='-', linewidth=1.5, label='Break-even (ratio = 1.0)')
ax.set_xlabel('Benefit-Cost Ratio')
ax.set_title('Benefit-Cost Ratio of SAF Blending Mandates\n(Values > 1.0 indicate net positive economic impact)')
ax.legend(loc='lower right')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
for i, v in enumerate(ratios):
ax.text(v + 0.02, i, f'{v:.2f}', va='center', fontweight='bold')
plt.tight_layout()
plt.savefig('chart3_benefit_cost_ratio.png', dpi=150, bbox_inches='tight')
plt.show()
# Cell 8: Chart 4 - Emissions Reduction Potential
fig, ax = plt.subplots(figsize=(10, 6))
emissions = df_benefits['Annual CO2 Reduction (million tonnes)'].values
ax.bar(['2%', '5%', '10%'], emissions, color='#17becf', alpha=0.8, width=0.5)
ax.set_xlabel('SAF Blending Target')
ax.set_ylabel('Annual CO2 Reduction (Million Tonnes)')
ax.set_title('Aviation Emissions Reduction Under SAF Blending Scenarios\n(Based on 65% lifecycle emission reduction vs. conventional jet fuel)')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
for i, v in enumerate(emissions):
ax.text(i, v + 0.01, f'{v:.2f} Mt', ha='center', fontweight='bold')
plt.tight_layout()
plt.savefig('chart4_emissions_reduction.png', dpi=150, bbox_inches='tight')
plt.show()
# Cell 9: Summary Output Table
print('\n' + '='*70)
print('POLICY BRIEF: SAF Blending Mandate Cost-Benefit Analysis')
print('='*70)
print(f'\nKey Finding: A 10% SAF blending mandate would cost the aviation')
print(f'industry approximately ${df_combined["Annual Cost (AUD billion)"].iloc[2]:.1f} billion per year,')
print(f'equivalent to ${cost_per_pax[2]:.2f} per domestic passenger per flight.')
print(f'\nThis delivers an estimated ${df_combined["Annual Benefit (AUD billion)"].iloc[2]:.2f} billion')
print(f'in annual economic benefits (jobs, fuel security, emissions reduction),')
print(f'yielding a benefit-cost ratio of {ratios[2]:.2f}.')
print(f'\nAt the passenger level, the cost represents just')
print(f'{(cost_per_pax[2]/average_airfare)*100:.1f}% of the average domestic airfare.')
print('='*70)
Your analysis is complete and portfolio-ready. You now have a professional policy brief that demonstrates applied economic research, quantitative modelling, data visualisation, and clear policy communication. Next up, you will take on a bonus challenge that adds depth to your analysis.
Secret mission
Add a Sensitivity Analysis
Your cost-benefit analysis uses a single set of assumptions. But what happens if oil prices shift, or SAF production costs fall faster than expected? In this extension, you'll build a sensitivity matrix that shows decision-makers exactly when a mandate makes economic sense and when it doesn't.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally, so there are no ongoing costs or cloud resources to worry about. Decide whether to keep your files for your portfolio, or delete them entirely.
Resources you used:
- Local folder saf-policy-analysis containing your Jupyter Notebook, HTML export, and 5 chart PNG files.
Keep everything running
No action needed. Choose this if you plan to refine your analysis further or want the notebook ready for your portfolio.
- Your saf-policy-analysis folder stays on your Desktop with all files intact.
- Consider uploading to GitHub as a public repository to share with recruiters.
Pause - I'll come back to this later
There are no running processes or servers to stop. Your notebook is just a file on disk, so it takes no resources while idle.
- Close the Jupyter Notebook browser tab.
- In Anaconda Navigator, click the Stop button next to Jupyter Notebook if it is still running.
- Your files remain in the saf-policy-analysis folder, ready for you to reopen later.
Delete - I don't want to use this again
Remove all project files from your machine. This deletes your notebook, charts, and HTML export permanently.
- Close the Jupyter Notebook browser tab.
- In Anaconda Navigator, click the Stop button next to Jupyter Notebook if it is still running.
Delete the project folder by running the command for your operating system.
macOS
- Open Terminal and run:
rm -rf ~/Desktop/saf-policy-analysis
Windows
- Open PowerShell and run:
rmdir /s /q "$HOME\Desktop\saf-policy-analysis"
- Confirm the folder is gone by checking your Desktop.
That's a Wrap!
That's a Wrap!
Nice work! You just built a portfolio-ready economic analysis that mirrors the exact type of deliverable Deloitte Access Economics produces for government clients.
You've learned how to:
- Build a cost-benefit analysis of Australian SAF policy using real published data from CSIRO, Deloitte, and the Australian Government.
- Create 4 professional data visualisations suitable for a policy document, including grouped bar charts, line charts, and horizontal bar charts.
- Write a policy brief with specific, evidence-based recommendations in the style of Deloitte Access Economics.
- Secret Mission: Built a sensitivity analysis showing how oil prices and SAF cost trajectories change the policy calculus.
Ready to quiz yourself?