bolster.data_sources.nisra.planning_statistics
Northern Ireland Planning Activity Statistics.
Quarterly and annual planning application statistics for Northern Ireland, published by the Department for Infrastructure (DfI). Provides counts of planning applications received, decided, approved and withdrawn, both NI-wide as a quarterly time series back to Q1 2002/03 and broken down by the 11 local councils.
- Data Source:
Hub page: https://www.infrastructure-ni.gov.uk/articles/planning-activity-statistics
The module scrapes the hub page for the latest publication, then scrapes that publication page for the quarterly statistical tables Excel file.
- Update Frequency:
Quarterly (provisional) plus an annual final release after each financial year ends (April-March).
- Geographic Coverage:
Northern Ireland - whole-country totals plus the 11 local council areas (Antrim & Newtownabbey, Ards & North Down, Armagh City Banbridge & Craigavon, Belfast, Causeway Coast & Glens, Derry City & Strabane, Fermanagh & Omagh, Lisburn & Castlereagh, Mid & East Antrim, Mid Ulster, Newry Mourne & Down).
- Time Series:
Q1 2002/03 onwards for the NI-wide series (sheet 1.1). Recent quarters plus current/prior financial year for council-area data (sheet 1.2).
Example
>>> from bolster.data_sources.nisra import planning_statistics
>>> df = planning_statistics.get_latest_data()
>>> 'applications_received' in df.columns
True
Attributes
Functions
Scrape the planning statistics hub page for the latest publication page URL. |
|
|
Find the XLSX file URL on a planning statistics publication page. |
|
Parse the NI-wide quarterly applications time series (sheet |
|
Parse the council-area planning applications data (sheet |
|
Download and parse the NI-wide quarterly planning applications series. |
|
Download and parse the council-area planning applications data. |
|
Validate an NI-wide planning applications DataFrame. |
Aggregate a quarterly DataFrame to annual (financial-year) totals. |
|
|
Summarise council-area data by council across all (or one) financial year. |
Module Contents
- bolster.data_sources.nisra.planning_statistics.PLANNING_HUB_URL = 'https://www.infrastructure-ni.gov.uk/articles/planning-activity-statistics'[source]
- bolster.data_sources.nisra.planning_statistics.INFRA_BASE_URL = 'https://www.infrastructure-ni.gov.uk'[source]
- bolster.data_sources.nisra.planning_statistics.get_latest_publication_url()[source]
Scrape the planning statistics hub page for the latest publication page URL.
The hub lists publications newest-first; the first non-guidance link with a “Northern Ireland planning statistics” title is the latest release (provisional quarterly or final annual).
- Returns:
URL of the latest publication page (containing the XLSX/ODS files).
- Raises:
NISRADataNotFoundError – If the hub page cannot be fetched or no publication link can be located.
- Return type:
Example
>>> url = get_latest_publication_url() >>> url.startswith("https://www.infrastructure-ni.gov.uk/publications/") True
- bolster.data_sources.nisra.planning_statistics.get_latest_xlsx_url(publication_url=None)[source]
Find the XLSX file URL on a planning statistics publication page.
- Parameters:
publication_url (str | None) – Publication page URL. If None, calls
get_latest_publication_url()to find the most recent.- Returns:
URL of the quarterly statistical tables Excel file.
- Raises:
NISRADataNotFoundError – If the publication page has no XLSX link.
- Return type:
Example
>>> url = get_latest_xlsx_url() >>> url.endswith(".xlsx") True
- bolster.data_sources.nisra.planning_statistics.parse_planning_applications(file_path)[source]
Parse the NI-wide quarterly applications time series (sheet
1.1).Sheet 1.1 contains the quarterly headline series back to Q1 2002/03 with a merged-cell Year column (forward-filled here) plus an annual total row per financial year (filtered out).
- Parameters:
file_path (str | pathlib.Path) – Path to a downloaded planning statistics XLSX file.
- Returns:
date(datetime): First day of the calendar quarterfinancial_year(str): e.g."2024/25"quarter(str): One ofQ1-Q4year(int): Calendar year ofdateapplications_received(int)applications_decided(int)applications_approved(int)applications_withdrawn(int)approval_rate(float): Proportion 0.0-1.0mid_year_population(int): NI mid-year population estimate used for that financial year’s per-10,000 ratesapplications_per_10k(float): Applications received per 10,000 population
- Return type:
DataFrame with one row per quarter and columns
- Raises:
NISRAValidationError – If the sheet structure is unexpected.
Example
>>> import bolster.data_sources.nisra.planning_statistics as ps >>> path = ps.get_latest_data.__wrapped__ if False else None # docs only
- bolster.data_sources.nisra.planning_statistics.parse_planning_by_council(file_path)[source]
Parse the council-area planning applications data (sheet
1.2).Sheet 1.2 stacks five sub-tables (received / decided / approved / approval-rate / withdrawn) with one row per quarter and one column per of the 11 NI councils. This function unpivots all five into a tidy long DataFrame.
- Parameters:
file_path (str | pathlib.Path) – Path to a downloaded planning statistics XLSX file.
- Returns:
date(datetime),financial_year(str),quarter(str),year(int)council(str): Council nameapplications_received(int | None)applications_decided(int | None)applications_approved(int | None)applications_withdrawn(int | None)approval_rate(float | None): Proportion 0.0-1.0
- Return type:
DataFrame with one row per (date, council) and columns
- Raises:
NISRAValidationError – If the sheet structure is unexpected (no council header rows / parseable date rows found).
- bolster.data_sources.nisra.planning_statistics.get_latest_data(force_refresh=False)[source]
Download and parse the NI-wide quarterly planning applications series.
- Parameters:
force_refresh (bool) – If True, bypass the local cache and re-download.
- Returns:
DataFrame from
parse_planning_applications()(NI-wide quarterly time series, sheet 1.1).- Raises:
NISRADataNotFoundError – If the latest publication or XLSX cannot be located.
NISRAValidationError – If the downloaded file cannot be parsed.
- Return type:
Example
>>> df = get_latest_data() >>> 'applications_received' in df.columns True
- bolster.data_sources.nisra.planning_statistics.get_latest_council_data(force_refresh=False)[source]
Download and parse the council-area planning applications data.
- Parameters:
force_refresh (bool) – If True, bypass the local cache and re-download.
- Returns:
DataFrame from
parse_planning_by_council()(one row per date, council).- Raises:
NISRADataNotFoundError – If the latest publication or XLSX cannot be located.
NISRAValidationError – If the downloaded file cannot be parsed.
- Return type:
Example
>>> df = get_latest_council_data() >>> 'council' in df.columns True
- bolster.data_sources.nisra.planning_statistics.validate_data(df)[source]
Validate an NI-wide planning applications DataFrame.
- Parameters:
df (pandas.DataFrame) – DataFrame from
get_latest_data()orparse_planning_applications().- Returns:
Trueif all checks pass.- Raises:
NISRAValidationError – If the DataFrame is empty, missing required columns, has implausible values, or has too short a time series.
- Return type:
Example
>>> df = get_latest_data() >>> validate_data(df) True
- bolster.data_sources.nisra.planning_statistics.get_annual_totals(df)[source]
Aggregate a quarterly DataFrame to annual (financial-year) totals.
- Parameters:
df (pandas.DataFrame) – DataFrame from
get_latest_data().- Returns:
financial_year(str)applications_received(int)applications_decided(int)applications_approved(int)applications_withdrawn(int)approval_rate(float): Weighted by decisions (approved / decided)quarters(int): Number of quarters aggregated (4 except for the current in-progress year)
- Return type:
DataFrame with one row per financial year and columns
Example
>>> df = get_latest_data() >>> annual = get_annual_totals(df) >>> 'applications_received' in annual.columns True
- bolster.data_sources.nisra.planning_statistics.get_council_summary(council_df, financial_year=None)[source]
Summarise council-area data by council across all (or one) financial year.
- Parameters:
council_df (pandas.DataFrame) – DataFrame from
get_latest_council_data().financial_year (str | None) – Optional financial year to filter to (e.g.
"2024/25"). If None, summarises across all available quarters.
- Returns:
DataFrame with one row per council, sorted by
applications_receiveddescending.- Return type:
Example
>>> council_df = get_latest_council_data() >>> summary = get_council_summary(council_df, financial_year='2024/25') >>> 'council' in summary.columns True