Skip to main content

psgc

Philippine Standard Geographic Code (PSGC) Python package with latitude/longitude coordinates, spatial queries, fuzzy search, reverse geocoding, address parsing, and GeoJSON export.

42,010 barangays, 1,656 cities/municipalities/sub-municipalities, 82 official provinces, 20 package parent groups, and 18 regions with 2024 Census population data. Based on the official PSA PSGC Q1 2026 release.

Live Demo


Quick Start

pip install psgc
import psgc

place = psgc.get("Ermita")
place.coordinate        # Coordinate(14.5838, 120.9823)
place.coordinate_source # 'child_area_weighted_centroid'
place.parent            # Province('National Capital Region (NCR)', ...)
place.breadcrumb        # ['National Capital Region (NCR)', 'Ermita']

Requirements: Python 3.10+


Features

Feature Description
Coordinates Lat/lng with coordinate_source provenance for all ~42,000 barangays, cities, provinces, and regions
get() Look up any place by name or PSGC code
Fuzzy Search RapidFuzz-based matching with Filipino phonetic rules
Spatial Queries Nearest barangay, radius search, distance by place name
Reverse Geocoding Coordinates to barangay (point-in-polygon + centroid fallback)
Address Parsing Parse unstructured Filipino addresses into components
Autocomplete Prefix trie for sub-millisecond suggestions
GeoJSON Export Export points and boundaries as GeoJSON FeatureCollections
Island Groups Every unit tagged Luzon / Visayas / Mindanao
ZIP Codes Supplemental ZIP code to location mapping
Hierarchical Navigation .parent, .children, .siblings, .breadcrumb
Population Density Computed from population and polygon area
CLI Full command-line interface for all features
Lightweight 1 core dependency (rapidfuzz). stdlib dataclasses, no pydantic.
Typed PEP 561 py.typed, full IDE autocomplete support

Installation

# Core package (search, data, address parsing)
pip install psgc

# With spatial queries (nearest, radius, reverse geocode)
pip install psgc[geo]

# With CLI
pip install psgc[cli]

# Everything
pip install psgc[all]

Optional Extras

Extra Adds Use Case
[geo] scipy Spatial index, nearest/radius queries
[cli] click Command-line interface
[yaml] pyyaml YAML export format
[all] All of the above Full install

Versioning

psgc uses date-based PEP 440 versions because the bundled PSGC data release is the main compatibility signal.

  • Format: YYYY.M.D.N
  • YYYY.M.D is the PSGC data release date, also exposed as psgc.__data_date__.
  • N increments for package, parser, or data-correction releases against the same data date.
  • Current package version: 2026.4.13.0

Check the installed version with:

import psgc

psgc.__version__    # '2026.4.13.0'
psgc.__data_date__  # '2026-04-13'

Release notes live in CHANGELOG.md. Maintainer release steps live in RELEASING.md.


Python API

Look Up a Place

import psgc

# By name (fuzzy matched)
place = psgc.get("Ermita")
place.name          # 'Ermita'
place.coordinate    # Coordinate(14.5838, 120.9823)
place.parent        # Province('National Capital Region (NCR)', ...)
place.breadcrumb    # ['National Capital Region (NCR)', 'Ermita']
place.coordinate_source  # 'child_area_weighted_centroid'

# By PSGC code (instant O(1) lookup)
place = psgc.get("1380608000")

# Check if a place exists
psgc.exists("Ermita")      # True
psgc.exists("Xanadu")      # False

# Ambiguous names raise with helpful guidance
try:
    psgc.get("Barangay 1 (Poblacion)")
except psgc.AmbiguousLookupError as e:
    print(e.matches)  # list of matching places to choose from
    # Disambiguate:
    psgc.get("Barangay 1 (Poblacion), Legazpi City")

Fuzzy Search

results = psgc.search("Cebu")

results[0].name     # 'Cebu'
results[0].score    # 100.0
results[0].level    # 'province'
results[0].place    # Province('Cebu', ...) -- the actual object

# From the result, navigate the hierarchy
results[0].place.children   # list of cities in Cebu

# Custom search with hooks and threshold
results = psgc.search(
    "Sebu",
    n=5,
    match_hooks=["city"],     # search cities only
    threshold=70.0,
    phonetic=True,            # Filipino phonetic matching
)

Autocomplete

results = psgc.suggest("mak", limit=5)
# [{"name": "Makati City", "psgc_code": "...", "level": "city"}, ...]

Spatial Queries

Requires pip install psgc[geo].

# Nearest barangays to a GPS point
results = psgc.nearest(14.5995, 120.9842, n=5)
results[0].place        # Barangay('Barangay 394', ...)
results[0].distance_km  # 0.108

# All barangays within 5 km
results = psgc.within_radius(14.5995, 120.9842, radius_km=5)

# Straight-line distance between two places (not driving distance)
psgc.distance("Ermita, Manila", "Cebu City")  # 562.266 km (as the crow flies)

# Reverse geocode: coordinates -> barangay
result = psgc.reverse_geocode(14.5547, 121.0244)
result.barangay   # 'Poblacion'
result.city       # 'Makati City'
result.province   # 'NCR, Third District'
result.place      # Barangay('Poblacion', ...) -- full object

Data Access

# All 18 regions
for r in psgc.regions:
    print(f"{r.name} ({r.island_group.value})")
    print(f"  Lat: {r.coordinate.latitude}, Lng: {r.coordinate.longitude}")

# Hierarchical navigation
brgy = psgc.barangays[0]
brgy.parent                    # parent City
brgy.parent.parent             # parent Province
brgy.parent.parent.parent      # parent Region
brgy.siblings[:3]              # other barangays in same city
brgy.is_urban                  # True/False

# Cities with sub-municipalities (e.g. Manila)
manila = psgc.get("Manila")
manila.children                # 897 barangays (walks through sub-municipalities)
manila.sub_municipalities      # [Tondo I/II, Binondo, Sampaloc, ...]

# Flat denormalized list (ideal for filtering)
urban_ncr = [b for b in psgc.flat if b.region_name and "NCR" in b.region_name and b.urban_rural == "U"]

# Recursive tree
for region_node in psgc.tree:
    for province_node in region_node.components:
        print(f"  {province_node.name}: {len(province_node.components)} cities")

Address Parsing

result = psgc.parse_address("123 Rizal St., Brgy. San Antonio, Makati City")
result.street       # '123 Rizal St.'
result.barangay     # 'San Antonio'
result.city         # 'Makati City'
result.province     # 'NCR, Third District'
result.confidence   # 0.95

ZIP Code Lookup

info = psgc.zip_lookup("1000")
info["area"]      # 'Ermita, Manila'
info["city"]      # 'City of Manila'

PSGC Code Validation

is_valid, reason = psgc.validate("1380608000")
# (True, "Valid city/municipality code")

Export

# GeoJSON with coordinates
geojson = psgc.to_geojson(level="barangay", region="NCR", as_dict=True)

# CSV with lat/lng columns
psgc.to_csv(level="barangay", output="barangays.csv")

Logging

# Silent by default. Enable for debugging:
# Enable verbose output:
psgc.setup_logging(verbose=True)

# Or via environment variable:
# PSGC_VERBOSE=true python my_script.py

CLI

Requires pip install psgc[cli].

# Look up
psgc search "Cebu" -n 3
psgc suggest "makat"

# Spatial (requires psgc[geo])
psgc nearest 14.5995 120.9842 -n 5
psgc within-radius 14.5995 120.9842 --km 10
psgc reverse-geocode 14.5833 120.9822
psgc distance "Ermita, Manila" "Cebu City"

# Address parsing
psgc parse "Brgy. San Antonio, Makati City"

# Export
psgc export --format geojson --level barangay --region "NCR" -o ncr.geojson
psgc export --format csv --level city -o cities.csv

# Info
psgc info stats
psgc info version
psgc validate 1380608000
psgc zip 1000

Data Sources

Data Source Coverage
Names, codes, hierarchy PSA PSGC Q1 2026 release; Q4 2025 Publication Datafile as base All 42,010 current barangays
Population 2024 Census (via PSGC masterlist) 100% of current barangays
Urban/Rural PSGC masterlist 100%
Income classification PSGC masterlist 99% of cities
Coordinates HDX/OCHA Nov 2023 shapefiles plus PSA correspondence-code/name-parent matching 99.8% HDX-derived (41,926 barangays), 84 fallback
Area (km2) HDX/OCHA Nov 2023 shapefiles 99.8% (41,926 barangays)
ZIP codes Supplemental open ZIP dataset plus legacy curated entries 1,783 ZIP codes

Coordinates: Every record with coordinates also has a coordinate_source value. Barangays are classified as:

  • hdx_exact_2023: current PSGC code matched a November 2023 HDX/NAMRIA polygon.
  • hdx_correspondence_2023: current PSGC code was matched to an HDX polygon using the PSA correspondence code.
  • hdx_name_parent_2023: current PSGC code was matched to a unique HDX polygon by barangay name within the same parent city/municipality.
  • merged_hdx_area_weighted_2026q1: Q1 2026 merge applied from multiple HDX polygons.
  • fallback_unverified: no HDX polygon match is available; coordinates are retained only as low-confidence display points.

Parent city, province, package-group, and region coordinates are recomputed from child barangay coordinates using area-weighted centroids. Package parent groups are used for NCR, highly urbanized cities, and PSA special groupings so independent cities are no longer attached to unrelated provinces. See CHANGELOG.md for release-specific changes.


Performance

Operation Time (42K barangays)
import psgc < 1ms (lazy loading)
get("1380100000") ~0.001ms (code lookup)
get("Taguig") ~100ms (fuzzy search)
search("Manila") ~100ms
suggest("mak") ~0.5ms
validate(code) ~0.001ms
nearest(lat, lng) < 1ms (after first call builds index)

Known Limitations

What Limitation Details
Coordinates 84 barangays remain low-confidence fallback points 41,926 barangays are HDX-derived or HDX-merged. Check coordinate_source before research or distance work.
Distance Straight-line (Haversine), not driving/walking Use a routing API (OSRM, Google Maps) for road distance
Reverse geocode Uses nearest centroid unless boundaries are supplied separately Good for approximate lookup, not a substitute for polygon containment in formal GIS workflows
ZIP codes Supplemental, not a PSA field ZIP data is not part of PSGC and should be verified against PHLPost for mailing-critical uses
Area (km2) Available for 41,926 barangays population_density works only where area_km2 is present
City names PSA uses "City of X" format get("Makati") auto-resolves to "City of Makati" for major cities. For obscure cities, use the full PSA name or PSGC code.

Disclaimer

This is a community-maintained open-source project. It is not affiliated with, endorsed by, or officially connected to the Philippine Statistics Authority (PSA) or NAMRIA.

Data Attribution

License

MIT

Metadata

Release files for psgc 2026.4.13.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for psgc 2026.4.13.0
File Size Uploaded Provenance
psgc-2026.4.13.0.tar.gz 1.4 MB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for psgc 2026.4.13.0
File Interpreter ABI Platform
psgc-2026.4.13.0-py3-none-any.whl Python 3 none any Details

Total release size: 2.9 MB

Release files / psgc-2026.4.13.0.tar.gz

Download URL psgc-2026.4.13.0.tar.gz
Size 1.4 MB
Tags Source
SHA-256 checksum
How to use checksums
c5d4a9b5dd0b3a35260a57e167d1bc8577693c0d3d65ace1c2db488e7c535958
BLAKE2b-256 checksum
How to use checksums
483de3c5f5ed299786119ea0e64cab697aa6bd2006df6fdbef7df0cb17c5e4d2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 30, 2026.

Transparency log

Release files / psgc-2026.4.13.0-py3-none-any.whl

Download URL psgc-2026.4.13.0-py3-none-any.whl
Size 1.5 MB
Tags Python 3
SHA-256 checksum
How to use checksums
e9662b69f3313d90089896c567d9b82be2452358d16f3eb561a9f44b5212a778
BLAKE2b-256 checksum
How to use checksums
a6a9f2a14efb788e536dc0bf76df3b9d69f86a2da382175d02bb9615ad0f6516
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 30, 2026.

Transparency log

Security for psgc 2026.4.13.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for psgc-2026.4.13.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 30, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page