Maps · Geospatial

Nine BPS indicators, all of Indonesia, one grid.

What the Indonesian census agency publishes by province — drawn nine times. Plus a Jabodetabek close-up to show what kab/kota grain adds.

Fig. 01 · Nine BPS indicators across 34 provinces (values c. 2022–2023; pre-2022 province scheme)
Polygons from GADM 4.1. Indicator values compiled from BPS Statistik Indonesia 2024, IPM Kab/Kota 2023, SUSENAS March 2023, SAKERNAS August 2023, and SSGI 2022. Hover any province for the underlying value.
Nine indicators of one country, side by side. The structural ones: Java is rich and crowded, Papua is poor and sparse, Bali is healthy and unequal.

What you’re looking at

Thirty-four provinces of Indonesia, drawn nine times. Each panel is a different indicator from Badan Pusat Statistik, scaled and coloured on its own terms. Hover any province for the value.

The encoding follows the same three rules across both grids on this page:

  • Reds mean “more is bad” — poverty headcount, open unemployment, stunting, Gini.
  • Greens mean “more is good” — HDI (human development index), mean years of schooling, life expectancy.
  • Magma / viridis are neutral — population density and GRDP per capita are log-scaled because the spread is two orders of magnitude.

What jumps out

A few patterns that hold up across panels:

  • The eastern deficit. NTT, Papua, Papua Barat and Sulawesi Barat. The compound effect of low schooling, low life expectancy, high poverty, high stunting is what makes regional development conversations in Indonesia consistently about the east.
  • Bali is the outlier. Lowest stunting (8.0%), lowest unemployment (2.7%), second-highest life expectancy, but a Gini coefficient (measure of inequality) in the same band as Java.
  • DKI is its own thing. (Daerah Khusus Ibukota - Special Capital Region of Jakarta) GRDP per capita Rp 322 juta IDR (juta = million Indonesian rupiah) is six times the national median; similar story with the Gini coefficient, top-three in the country.
  • Sumatera Barat punches above its income. (West Sumatra) Mid-tier GRDP, but HDI and schooling sit alongside provinces twice as rich.
  • The PDRB log scale is doing real work. PDRB (Produk Domestik Regional Bruto) is the Indonesian term for GRDP — a region’s gross domestic product, the total value of everything it produces in a year. Log scaled otherwise you’d only see Riau, Kaltim, Kepri, and DKI.

Why these nine

BPS publishes hundreds of tables. The selection here is the slice that (a) is published at province or kabupaten/kota grain, (b) is updated at least annually, and (c) tells you something orthogonal to the others.

  • HDI / IPM — annual composite of education, health, expenditure.
  • Poverty headcount P0 — annual SUSENAS, % below the provincial poverty line.
  • Open unemployment TPT — annual SAKERNAS, % of labour force.
  • Gini ratio — annual SUSENAS.
  • Mean years of schooling (RLS) — HDI sub-indicator, slow-moving and very legible.
  • Life expectancy at birth (UHH) — HDI sub-indicator.
  • GRDP per capita (PDRB ADHB) — annual, log-scaled. ADHB (atas dasar harga berlaku) means “at current prices”.
  • Stunting prevalence (SSGI) — strictly Kemenkes, but reported per province/kab and the natural complement to poverty.
  • Population density — SP2020 totals divided by polygon area; log-scaled.

How Indonesia is divided

For readers who don’t spend their weekends in Indonesian boundary files: the country is administered as a nested hierarchy, and every choropleth here is a choice of which level to draw. From coarsest to finest:

  • Province (provinsi) — the top tier, 38 today (34 when this data was compiled — more on that shortly). The rough analogue of a US state or a French région. This is the grid at the top of the page. (GADM level 1.)
  • Regency / city (kabupaten / kota) — about 514 of them. A kabupaten is a mostly-rural regency; a kota is an urban municipality. Think US county or English district. This is the Jabodetabek (Greater Jakarta) grid further down. (GADM level 2.)
  • District (kecamatan) — roughly 7,200, a subdivision of a regency, with no tidy Western equivalent. (GADM level 3.)
  • Village (desa / kelurahan) — around 83,000, the smallest unit with its own administration. A desa is a rural village; a kelurahan is its urban counterpart, a ward run by an appointed head. (GADM level 4; level 0 is the national outline.)

Each step down multiplies the polygons by roughly an order of magnitude — 38 → 514 → 7,200 → 83,000 — and the published data thins out just as fast. That tension between how finely the country is divided and how finely it’s measured is the whole story of this page.

Why aggregation hides things

Province grain is convenient — 34 polygons, every indicator publicly tabulated, fits on a phone. But it flattens a lot. Jawa Barat has DKI’s suburbs and Pangandaran. Maluku averages Ambon city and remote outer islands together. The poverty rate of a province is the wrong shape for targeting a programme.

The natural next slice is kabupaten/kota. As a worked example, take Jabodetabek — the standard shorthand for Greater Jakarta, stitched from the initials of Jakarta, Bogor, Depok, Tangerang and Bekasi. The term exists because the real city outgrew its border long ago: Jakarta proper is the province of DKI Jakarta, but the continuous built-up area spills across a ring of regencies and cities in neighbouring West Java and Banten, and something like 30 million people move through that single labour market. It’s the unit planners, statisticians and transport agencies actually reach for, because the province line stopped describing the city decades ago. At regency grain:

Fig. 02 · The same nine indicators, zoomed to thirteen Jabodetabek kab/kota
The DKI Jakarta block of Fig. 01 disaggregated into five Jakarta cities plus Bogor, Depok, Bekasi, Tangerang and Tangerang Selatan (kab + kota). The within-metro variance is the part the province-level map can't show: Jakarta Pusat's GRDP per capita is fifteen times Depok's; Bogor regency's stunting rate is double Depok's. Same encoding rules as Fig. 01.

The within-metro variance is the entire point. Five neighbours within Jabodetabek differ on poverty by 4x and on PDRB per capita by 7x. The country-scale map averages all of that into a single dark-green tile.

Even this is not fully satisfactory. The city of Jakarta is full of extremes, which you see driving through wealthy suburbs like Mengteng or Pondok Indah.

Why the data stops where it does

The obvious next question is why this map doesn’t just skip to the village level and dodge the averaging problem entirely. The answer is that the polygons go all the way down, but the numbers don’t - not openly, and not reliably.

As a data journalist at the Herald, we were pretty spoiled for New Zealand data. The census is every five years, and the detailed tables are released in full down to the (anonymised) meshblock (smallest / roughly neighbourhood-sized) level. The government open-data portal has a well-documented API, and the statistical agency is responsive to queries. In Indonesia, the situation is more complicated.

Most of these nine indicators come from sample surveys: SUSENAS for poverty and inequality, SAKERNAS for employment. Those samples are sized to be representative at the province level, and for some indicators the regency level. Push the same sample down to a kecamatan or a kelurahan and the margin of error swallows the estimate, so BPS simply doesn’t publish it. The ten-yearly census (SP2020) does reach every village, but its detailed cross-tabulations are released sparingly, partly for statistical-disclosure reasons: at small-area granularity, a published table can start to re-identify individual households. And there’s plain cost — comparable, annually refreshed data for 83,000 villages is a different universe of effort from 38 provinces. The one survey that is village-level, PODES (the village-potential census), runs on its own cadence and isn’t fully exposed through the open API.

So the finest grain you can actually map is bounded by the finest hurdle, that someone has measured and published the data.

Boundaries are political

A choropleth quietly presents its boundaries as facts of geography.

Since the Reformasi decentralisation of 1999, the country has been in near-constant pemekaran (literally “blossoming”), the splitting of regions into new ones. A new regency or province arrives with its own budget, its own civil-service payroll and a new capital, so they’re created for a tangle of administrative, ethnic and patronage reasons.

The largest recent move was Papua. In 2022 the national parliament split the two Papuan provinces into six: Papua kept its name but shed territory to Central Papua, Highland Papua and South Papua, while West Papua spun off Southwest Papua. The national total jumped from 34 provinces to 38.

It was contested. Many Papuans and civil-society groups read it as: the splits were legislated in Jakarta on a fast timetable, without the consultation that Papua’s special-autonomy arrangement was understood to require; critics warned they would dilute indigenous Papuan political control, slice an already marginalised population into smaller and more governable units, and extend the security presence in a region with a long-running independence movement. There were street protests in several Papuan cities. Some coverage in CNN and background in Human Rights Watch is worth reading.

In terms of the data, there a hard limit on what this map can show. GADM 4.1, and most of BPS’s multi-year tables, still use the 34-province scheme. A long time series and a current boundary map can’t coexist: you can’t paint 2010 figures onto provinces that didn’t exist until 2022.

How it was built

The polygons come from GADM 4.1 — a free academic source of administrative boundaries, levels 1–4 for Indonesia (province → regency → sub-district → village). For the national grid, the level-2 polygons are dissolved up to level-1, simplified to ~5.5 km tolerance, and sub-polygons under 25 km² dropped (mostly tiny islets that don’t render visibly at country scale anyway). For the Jabodetabek grid, level-2 polygons go in direct.

Why GADM? Indonesia’s authoritative boundaries come from BIG (the national geospatial agency) and BPS, but getting them in a clean, multi-level, web-ready form is its own project — licensing, government portals, and shapefiles that assume you’re a GIS analyst. GADM, the Database of Global Administrative Areas, is the pragmatic pick for a reproducible web piece: free for non-commercial use, every country covered to a consistent level-0-through-4 hierarchy, versioned, and downloadable as ready-to-project geometry. The trade-offs are: it lags official redistricting (hence 34 provinces), the licence is non-commercial, and the raw polygons are far too heavy to ship to a browser, so they’re simplified hard before they arrive. For this blog post this is fine; for updates and higher accuracy go to official sources (BIG).

The notebooks and the JSON shapes the components read are in github.com/tuttinator/wilayah.

# In the wilayah repo
uv run python notebooks/04_bps_provinces.py    # → indonesia_provinces_bps.geojson (449 KB)
uv run python notebooks/03_bps_multi_indicator.py  # → jabodetabek_bps_indicators.geojson (67 KB)

The Svelte component is the same for both grids — one shared d3-geo projection per data source, nine sequential colour scales, one ResizeObserver, one tooltip. The only thing that changes between calls is the data URL, the label key (NAME_1 vs NAME_2), and the panel aspect ratio (Indonesia is wide; Jabodetabek is squarish).

Important caveats

  • Pre-2022 province scheme. As mentioned above, this looks at the original 34 provinces, the set BPS’s multi-year tables are keyed to, not the 38 that exist today.
  • Indicator values are c. 2022–2023. Province aggregates at this vintage are publicly cited and stable, but worth checking bps.go.id.
  • No kelurahan data available. The real prize — PODES village-level infrastructure, disaster exposure, social conflict, plus SP2020 Long Form disaggregations, isn’t on the BPS open API yet.
  • The Gini panel has a known limitation. Provincial Gini ratios understate inequality because they average within-area rich and poor together. Living in Jakarta the physical proximity of wealth and poverty is very visible on a daily basis.

If you’ve already wrangled BPS Web API quirks or have a fresher PODES extract, drop me a line.