Wbpy
Python interface to the World Bank Indicators and Climate APIs
Install / Use
/learn @mattduck/WbpyREADME
wbpy
A Python interface to the World Bank Indicators and Climate APIs.
Readthedocs <http://wbpy.readthedocs.org/en/latest>__Github source <https://github.com/mattduck/wbpy>__World Bank API docs <http://data.worldbank.org/developers>__
The Indicators API lets you access a large number of world development indicators - country data on education, environment, gender, health, population, poverty, technology, and more.
The Climate API lets you access modelled and historical data for temperature and precipitation.
Why use wbpy?
- Dataset models let you access processed data and associated metadata in different formats.
- If you don’t want processed data objects, you can still access the raw JSON response.
- Single method calls to do the equivalent of multiple API requests, eg. wbpy handles the specific date pairs which would otherwise be required for the Climate API.
- Works with both ISO 1366 alpha-2 and alpha-3 country codes (the web APIs mostly just support alpha-3).
Elsewhere, there is also
wbdata <https://github.com/OliverSherouse/wbdata>__, a wrapper for the
Indicators API which supports Pandas structures and has some
command-line functionality.
Installation
pip install wbpy, or download the source code and
python setup.py install.
Contributors
@bcipolli <https://github.com/bcipolli>__ upgraded wbpy to support Python 3 and v2 of the world bank API.
Development and maintenance
This project was unmaintained for a couple of years, although was
updated in July 2020 to support Python 3 and to use the v2 endpoint of
the API, as v1 has not been supported for a while (thanks
@bcipolli <https://github.com/bcipolli>__). Although I’m not actively
adding new features or looking for issues, I’m happy to accept
contributions, and to provide commit access if anybody wants to work on
the project.
Indicators API
Basic use
Here’s a small case where we already know what API codes to use:
.. code:: python
import wbpy
from pprint import pprint
api = wbpy.IndicatorAPI()
iso_country_codes = ["GB", "FR", "JP"]
total_population = "SP.POP.TOTL"
dataset = api.get_dataset(total_population, iso_country_codes, date="2010:2012")
dataset
.. parsed-literal::
http://api.worldbank.org/v2/countries/GBR;FRA;JPN/indicators/SP.POP.TOTL?date=2010%3A2012&format=json&per_page=10000
.. parsed-literal::
<wbpy.indicators.IndicatorDataset('SP.POP.TOTL', 'Population, total') with id: 140421139962456>
The IndicatorDataset instance contains the direct API response and
various metadata. Use dataset.as_dict() to return a tidy dictionary
of the data:
.. code:: python
dataset.as_dict()
.. parsed-literal::
{'FR': {'2012': 65659809.0, '2011': 65342780.0, '2010': 65027507.0},
'GB': {'2012': 63700215.0, '2011': 63258810.0, '2010': 62766365.0},
'JP': {'2012': 127629000.0, '2011': 127833000.0, '2010': 128070000.0}}
Some examples of the metadata available:
.. code:: python
dataset.api_url
.. parsed-literal::
'http://api.worldbank.org/v2/countries/GBR;FRA;JPN/indicators/SP.POP.TOTL?date=2010%3A2012&format=json&per_page=10000'
.. code:: python
dataset.indicator_name
.. parsed-literal::
'Population, total'
.. code:: python
dataset.indicator_topics
.. parsed-literal::
http://api.worldbank.org/v2/indicator/SP.POP.TOTL?format=json&per_page=10000
.. parsed-literal::
[{'id': '19', 'value': 'Climate Change'}, {'id': '8', 'value': 'Health '}]
.. code:: python
dataset.countries
.. parsed-literal::
{'FR': 'France', 'GB': 'United Kingdom', 'JP': 'Japan'}
If you want to create your own data structures, you can process the raw API response:
.. code:: python
dataset.api_response
.. parsed-literal::
[{'page': 1,
'pages': 1,
'per_page': 10000,
'total': 9,
'sourceid': '2',
'lastupdated': '2020-07-01'},
[{'indicator': {'id': 'SP.POP.TOTL', 'value': 'Population, total'},
'country': {'id': 'FR', 'value': 'France'},
'countryiso3code': 'FRA',
'date': '2012',
'value': 65659809,
'unit': '',
'obs_status': '',
'decimal': 0},
{'indicator': {'id': 'SP.POP.TOTL', 'value': 'Population, total'},
'country': {'id': 'FR', 'value': 'France'},
'countryiso3code': 'FRA',
'date': '2011',
'value': 65342780,
'unit': '',
'obs_status': '',
'decimal': 0},
{'indicator': {'id': 'SP.POP.TOTL', 'value': 'Population, total'},
'country': {'id': 'FR', 'value': 'France'},
'countryiso3code': 'FRA',
'date': '2010',
'value': 65027507,
'unit': '',
'obs_status': '',
'decimal': 0},
{'indicator': {'id': 'SP.POP.TOTL', 'value': 'Population, total'},
'country': {'id': 'GB', 'value': 'United Kingdom'},
'countryiso3code': 'GBR',
'date': '2012',
'value': 63700215,
'unit': '',
'obs_status': '',
'decimal': 0},
{'indicator': {'id': 'SP.POP.TOTL', 'value': 'Population, total'},
'country': {'id': 'GB', 'value': 'United Kingdom'},
'countryiso3code': 'GBR',
'date': '2011',
'value': 63258810,
'unit': '',
'obs_status': '',
'decimal': 0},
{'indicator': {'id': 'SP.POP.TOTL', 'value': 'Population, total'},
'country': {'id': 'GB', 'value': 'United Kingdom'},
'countryiso3code': 'GBR',
'date': '2010',
'value': 62766365,
'unit': '',
'obs_status': '',
'decimal': 0},
{'indicator': {'id': 'SP.POP.TOTL', 'value': 'Population, total'},
'country': {'id': 'JP', 'value': 'Japan'},
'countryiso3code': 'JPN',
'date': '2012',
'value': 127629000,
'unit': '',
'obs_status': '',
'decimal': 0},
{'indicator': {'id': 'SP.POP.TOTL', 'value': 'Population, total'},
'country': {'id': 'JP', 'value': 'Japan'},
'countryiso3code': 'JPN',
'date': '2011',
'value': 127833000,
'unit': '',
'obs_status': '',
'decimal': 0},
{'indicator': {'id': 'SP.POP.TOTL', 'value': 'Population, total'},
'country': {'id': 'JP', 'value': 'Japan'},
'countryiso3code': 'JPN',
'date': '2010',
'value': 128070000,
'unit': '',
'obs_status': '',
'decimal': 0}]]
Searching for indicators
We don’t always know what indicators we want to use, so we can search:
.. code:: python
population_indicators = api.get_indicators(search="population")
len(population_indicators)
.. parsed-literal::
http://api.worldbank.org/v2/indicator?format=json&per_page=10000
.. parsed-literal::
1591
Ah. That’s not a very manageable number. The API returns over 8000
indicator codes, and lots of them have “population” in the title.
Luckily, most of those indicators don’t really have much data, so we can
forget about them. You can browse the indicators with the best data
coverage at http://data.worldbank.org/indicator, and you can pass
common_only=True to throw away all indicators that aren’t included
on that page:
.. code:: python
population_indicators = api.get_indicators(search="population", common_only=True)
print("There are now only %d indicators to browse." % len(population_indicators))
.. parsed-literal::
http://api.worldbank.org/v2/indicator?format=json&per_page=10000
There are now only 246 indicators to browse!
We don’t want to print that many results in the documentation, so let’s
filter some more. The API query string parameters are directly mapped to
kwargs for each method. For the get_indicators method, this means we
can filter by topic or source:
.. code:: python
health_topic_id = 8
health_indicators = api.get_indicators(search="population", common_only=True, topic=health_topic_id)
print("We've narrowed it down to %d indicators." % len(health_indicators))
.. parsed-literal::
http://api.worldbank.org/v2/topic/8/indicator?format=json&per_page=10000
We've narrowed it down to 109 indicators.
Each indicator has a variety of metadata:
.. code:: python
pprint(list(health_indicators.items())[2])
.. parsed-literal::
('SH.DYN.AIDS.FE.ZS',
{'name': "Women's share of population ages 15+ living with HIV (%)",
'source': {'id': '2', 'value': 'World Development Indicators'},
'sourceNote': 'Prevalence of HIV is the percentage of people who are '
'infected with HIV. Female rate is as a percentage of the '
'total population ages 15+ who are living with HIV.',
'sourceOrganization': 'UNAIDS estimates.',
'topics': [{'id': '8', 'value': 'Health '}, {'id': '17', 'value': 'Gender'}],
'unit': ''})
That data might be useful, but it’s not very friendly if you just want
to grab some API codes. If that’s what you want, you can pass the
results to the print_codes method:
.. code:: python
api.print_codes(api.get_indicators(search="tuberculosis"))
.. parsed-literal::
http://api.worldbank.org/v2/indicator?format=json&per_page=10000
SH.TBS.CURE.ZS Tuberculosis treatment success rate (% of new cases)
SH.TBS.DOTS Tuberculosis cases detected under DOTS (%)
SH.TBS.DTEC.ZS Tuberculosis case detection rate (%, all forms)
SH.TBS.INCD Incidence of tuberculosis (per 100,000 people)
SH.TBS.INCD.HG Incidence of tuberculosis, high uncertainty bound (per 100,000 people)
SH.TBS.INCD.LW Incidence of tuberculosis, low uncertainty bound (per 100,000 people)
SH.TBS.MORT Tuberculosis death rate (per 100,000 people)
SH.TBS.MORT.HG Deaths
Related Skills
node-connect
333.7kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
claude-opus-4-5-migration
82.0kMigrate prompts and code from Claude Sonnet 4.0, Sonnet 4.5, or Opus 4.1 to Opus 4.5
frontend-design
82.0kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
model-usage
333.7kUse CodexBar CLI local cost usage to summarize per-model usage for Codex or Claude, including the current (most recent) model or a full model breakdown. Trigger when asked for model-level usage/cost data from codexbar, or when you need a scriptable per-model summary from codexbar cost JSON.
