Python API¶
There are two ways to use fair-shares from your own code, and they have very different requirements.
The allocation functions, on data you supply¶
The allocation functions take population (and, for capability-adjusted
approaches, GDP) as pandas dataframes and hand back a result object. They read
no files, need no data directory, and take no configuration — a plain
pip install fair-shares is enough, and the code below runs from any directory:
import pandas as pd
from fair_shares.library.allocations.budgets.per_capita import equal_per_capita_budget
years = [str(y) for y in range(2020, 2051)]
population = pd.DataFrame(
[[50.0] * len(years), [10.0] * len(years)],
index=pd.MultiIndex.from_tuples(
[("AAA", "million"), ("BBB", "million")], names=["iso3c", "unit"]
),
columns=years,
)
result = equal_per_capita_budget(
population_ts=population,
allocation_year=2020,
emission_category="co2-ffi",
)
print(result.relative_shares_cumulative_emission["2020"])
Country AAA gets 50/60 of the budget, BBB gets 10/60. Multiply those shares by your global budget to get absolute numbers. The dataframe needs one row per country, a two-level index of country code and unit, and one column per year labelled as a string.
The full set is in Budget Functions and Pathway Functions.
The orchestrated timeseries API¶
The fair_shares.library.python_api module runs a whole allocation — budget,
remaining budget, and annual pathway — in memory and returns it as a dataclass,
so downstream consumers never have to execute a notebook or manage its output
directories. Unlike the functions above, it loads processed data from disk.
Overview¶
Notebook 601_reproduce_esabcc_2023 computes, for one remaining-carbon-budget anchor (a rcb_source / climate_assessment / quantile triple) and one emission category:
- budget allocations of the remaining carbon budget (§ 4),
- each country's remaining budget after netting observed emissions (§ 5), and
- an annual pathway to
pathway_end_yearthat spreads that remaining budget under a normative distribution grid, plus the non-CO2 and combined parts (§ 6).
calculate_allocation_timeseries performs exactly that computation and returns a ResultContainer. The heavy lifting stays in the existing library functions; this module ports the notebook's § 5 / § 6 orchestration and ties it together per (anchor, category).
The notebook and this module are two implementations of the same calculation. tests/integration/test_python_api_reproduces_notebook.py is the guard against them drifting apart: it re-runs calculate_allocation_timeseries against fixtures saved from the notebook. If you change either side, regenerate the fixtures with uv run python tests/fixtures/save_python_api_fixture.py and confirm that test still passes.
Scope
This module computes remaining-carbon-budget allocations only (TARGET = "rcbs"), for a single fully-specified allocation under a single RCB anchor. Loop over allocations, distribution settings and debt modes around it to build a fuller set. To run parameter grids or pathway targets, use the notebook workflows described in the User Guide.
Data location
calculate_allocation_timeseries reads processed data from disk. Inside a
checkout it finds data/ and output/ on its own. From an installed wheel,
set FAIR_SHARES_DATA_DIR and FAIR_SHARES_OUTPUT_DIR, or pass data_dir=
and output_dir=. If the processed files are missing it rebuilds them with
Snakemake, which only ships in the pipeline extra — so a plain
pip install fair-shares works against a data tree that has already been
built, but not one that has to be built first. (The older project_root
argument still works and maps onto the two directories, but is deprecated.)
Computing Allocation Timeseries¶
calculate_allocation_timeseries¶
fair_shares.library.python_api.calculate_allocation_timeseries ¶
calculate_allocation_timeseries(
*,
emission_category: str,
climate_assessment: str,
quantile: float,
rcb_source: str,
allocation: dict[str, dict[str, Any]],
shape: str,
deviation_end_year: int,
convergence_year: int,
nonco2_debt_mode: str | None,
pathway_end_year: int,
base_share_floor_mt: float,
desired_harmonisation_year: int,
emissions_source: str,
gdp_source: str,
population_source: str,
gini_source: str,
lulucf_source: str,
allocation_folder: str,
project_root: Path | None = None,
data_dir: Path | str | None = None,
output_dir: Path | str | None = None
) -> ResultContainer
Compute the distributed allocation timeseries for one (anchor, category).
Runs §4 (budget allocation, in memory), §5 (remaining budget) and §6 (time
distribution) for a single fully-specified allocation, under the single
RCB anchor (rcb_source, climate_assessment, quantile). Loop over
allocations / distributions / debt modes around this function to build a
fuller set. No files are written and no notebook is executed; every input is
explicit (wrap this with your own defaults if desired).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
allocation
|
dict[str, dict[str, Any]]
|
One approach mapped to its scalar parameters, e.g.
|
required |
shape
|
str
|
The single §6 distribution setting (debt-redress envelope shape, the year it closes, and the per-capita convergence year). |
required |
deviation_end_year
|
str
|
The single §6 distribution setting (debt-redress envelope shape, the year it closes, and the per-capita convergence year). |
required |
convergence_year
|
str
|
The single §6 distribution setting (debt-redress envelope shape, the year it closes, and the per-capita convergence year). |
required |
nonco2_debt_mode
|
str | None
|
The single non-CO2 debt-settlement mode ( |
required |
project_root
|
Path | None
|
Deprecated. Superseded by |
None
|
data_dir
|
Path | str | None
|
Input and product directories. Both default to the resolved
directories — see :mod: |
None
|
output_dir
|
Path | str | None
|
Input and product directories. Both default to the resolved
directories — see :mod: |
None
|
Allocation Steps¶
These are the individual steps calculate_allocation_timeseries composes. Call them directly when you already hold an allocations frame and want only part of the calculation.
compute_remaining_budgets¶
fair_shares.library.python_api.compute_remaining_budgets ¶
compute_remaining_budgets(
category: str,
allocations_absolute: DataFrame,
processed_dir: Path,
) -> DataFrame
Remaining budget per country after netting observed emissions (§5).
Budget parts: remaining = allocated total minus actual consumption from the
allocation year through the last observed year. Non-CO2 pathway parts:
remaining = the forward-window allocation, with the historical deviation
(actual minus allocated over the past window) reported separately. For
composite categories a combined row per configuration is added (CO2
budget part + non-CO2 pathway part), matched on the shared equity params.
distribute_remaining_pathways¶
fair_shares.library.python_api.distribute_remaining_pathways ¶
distribute_remaining_pathways(
category: str,
allocations_absolute: DataFrame,
remaining: DataFrame,
processed_dir: Path,
*,
distribution_grid: dict[str, Sequence[Any]],
pathway_end_year: int,
base_share_floor_mt: float,
nonco2_debt_modes: Sequence[str]
) -> DataFrame
Distribute every budget configuration's remaining budget to 2100 (§6).
Spreads each remaining budget to pathway_end_year across the
distribution grid. For composite categories each CO2 configuration is
distributed under every
nonco2_debt_modes entry (free-rider leaves the CO2 budget as is;
co2-debit subtracts the country's past non-CO2 over-use and retires it),
and the allocated non-CO2 and combined rows are appended.
build_history¶
fair_shares.library.python_api.build_history ¶
Observed emissions for every coverage this category needs (§5 inputs).
One frame with a (coverage, unit, iso3c) MultiIndex and year columns. The
combined basket is the sum of its parts (NaN where either part lacks a
year, e.g. the all-ghg basket before the NGHGI CO2 record starts).
Results¶
ResultContainer¶
fair_shares.library.python_api.ResultContainer
dataclass
¶
ResultContainer(
allocation_timeseries: DataFrame,
history: DataFrame,
emission_category: str,
climate_assessment: str,
quantile: float,
rcb_source: str,
source_id: str,
emissions_source: str,
gdp_source: str,
population_source: str,
gini_source: str,
lulucf_source: str,
unit: str,
harmonisation_year: int | None,
netting_end_year: int,
pathway_end_year: int,
base_share_floor_mt: float,
shape: str,
deviation_end_year: int,
convergence_year: int,
nonco2_debt_mode: str | None,
allocation_folder: str,
metadata: dict[str, Any] = dict(),
)
The allocation timeseries for one (anchor, category), with its inputs.
Everything common to every row is an explicit attribute; metadata is a
fallback only for approach-specific extras that do not belong on the frame.
allocation_timeseries
instance-attribute
¶
Distributed annual pathways. MultiIndex holds every identifying column (category, emission-category part, unit, source, climate-assessment, quantile, approach, config params, the §6 knobs shape / deviation-end-year / nonco2-debt-mode, iso3c); columns are the years.
history
instance-attribute
¶
Observed emissions used, one row per (coverage, unit, iso3c); columns are
the years. Includes the summed combined basket(s) for this category.
metadata
class-attribute
instance-attribute
¶
save_results¶
fair_shares.library.python_api.save_results ¶
save_results(
results: ResultContainer, outpath: Path
) -> Path
Persist a :class:ResultContainer under outpath (created if needed).
Writes allocation_timeseries.parquet, history.parquet, a
metadata.json of every scalar attribute, and CITATIONS.md listing
the software and the data sources this run used. Returns outpath.
Citing a run¶
Most inputs are third-party datasets that require attribution, and which ones a
run uses depends on its settings: a budget run subtracts international bunker
emissions, a composite category such as all-ghg also draws on the AR6 scenario
ensemble, and the Gini source is whichever you chose.
save_results writes a CITATIONS.md into the output directory alongside the
parquet files, so a saved run always records what to cite. Runs kept in memory
produce no file, since there is no directory to put one in.
To get the same list directly:
from fair_shares.library.citations import citations
run = citations(active_sources, emission_category="all-ghg")
print(run.text()) # software, then each data source with DOI and licence
print(run.bibtex()) # the same as BibTeX entries
Or from the command line, without writing any code:
Sources with no DOI issued (World Bank, OWID, UN WPP) are credited by name, and the output says so rather than leaving a blank field. Sources whose terms ask for more than attribution — the Global Carbon Project's co-authorship request, CMIP7's component datasets, WIID's non-commercial clause — are called out in a separate section.
fair_shares.library.citations.citations ¶
citations(
active_sources: dict[str, str],
*,
emission_category: str | None = None,
registry: Registry | None = None
) -> RunCitations
Return everything a run should cite: the software and its data sources.
See Also¶
- Allocation Manager: The allocation engine this module calls into
- Math Utilities: The convergence and pathway-distribution solvers used by § 6
- Output Schema: Column meanings for the returned frames