Python and command line tools for quick access to DataBC geo-data available via WFS/WCS.
There is a wealth of British Columbia geographic information available as open
data,
but direct file download urls are not available and the syntax to accesss WFS via ogr2ogr
and/or curl/wget
can be awkward.
This tool attempts to simplify downloads of BC geographic data and smoothly integrate with PostGIS and Python GIS tools like geopandas
, fiona
and rasterio
. As noted above, the module is an interface only to geographic data avialable via WFS/WCS - to work with other BC open data, use the bcdata R package.
Note that this tool depends on BC Open Geospatial Web Services API at openmaps.gov.bc.ca and the BC Data Catalogue API. If downloads are failing, consult the BCGov Data Systems and Services uptime monitor.
Disclaimer
It is the user's responsibility to check the licensing for any downloads, data are generally licensed as OGL-BC
Install with pip
:
$ pip install bcdata
Note that bcdata
requires gdal
to already be installed to a known location.
If this is not the case on your system, the GeoPandas guide is useful for setting up a stand alone environment with conda
.
The default target database connection (used by bc2pg
) can be set via the DATABASE_URL
environment variable (the password parameter should not be required if using a .pgpass file)
Linux/Mac: export DATABASE_URL=postgresql://{username}:{password}@{hostname}:{port}/{database}
Windows: SET DATABASE_URL=postgresql://{username}:{password}@{hostname}:{port}/{database}
To reduce the volume of requests, information about data requested is cached locally.
Schemas of individual layers that have previously been requested are cached with the cache file name matching the object/table name.
Location of the cache defaults to ~/.bcdata
but can be modified by setting the BCDATA_CACHE
environment variable:
export BCDATA_CACHE=/path/to/bcdata_cache
The cache will automatically refresh after 30 days - force a cache refresh by deleting the files in the cache or the entire cache folder.
Typical usage will involve a manual search of the DataBC Catalogue to find a layer of interest. Once a dataset of interest is found, note the key with which to retreive it. This can be either the id
/package name
(the last portion of the url) or the Object Name
(Under Object Description
).
For example, for BC Airports, either of these keys will work:
- id/package name:
bc-airports
- object name:
WHSE_IMAGERY_AND_BASE_MAPS.GSR_AIRPORTS_SVW
Note that some packages may have more than one layer - if you request a package like this, bcdata
will prompt you with a list of valid object/table names to use instead of the package name.
import bcdata
# get a feature as geojson
geojson = bcdata.get_data(
'bc-airports',
query="AIRPORT_NAME='Terrace (Northwest Regional) Airport'"
)
geojson
{'type': 'FeatureCollection', 'features': [{'type': 'Feature', 'id': 'WHSE_IMAGERY_AND_BASE_MAPS.GSR_AIRPORTS_SVW.fid-f0cdbe4_16811fe142b_-6f34', 'geometry': {'type': 'Point', ...
# optionally, load data as a geopandas GeoDataFrame
gdf = bcdata.get_data(
'bc-airports',
query="AIRPORT_NAME='Terrace (Northwest Regional) Airport'",
as_gdf=True
)
gdf.head()
AERODROME_STATUS AIRCRAFT_ACCESS_IND AIRPORT_NAME ... TC_LID_CODE WEBSITE_URL geometry
0 Certified Y Terrace (Northwest Regional) Airport ... None None POINT (-128.5783333 54.46861111)
Commands available via the bcdata command line interface are documented with the --help option
$ bcdata --help
Usage: bcdata [OPTIONS] COMMAND [ARGS]...
Options:
--version Show the version and exit.
--help Show this message and exit.
Commands:
bc2pg Load a DataBC WFS layer to a postgres db
cat Write DataBC features to stdout as GeoJSON feature objects.
dem Dump BC DEM to TIFF
dump Write DataBC features to stdout as GeoJSON feature collection.
info Print basic metadata about a DataBC WFS layer as JSON.
list List DataBC layers available via WFS
$ bcdata bc2pg --help
Usage: bcdata bc2pg [OPTIONS] DATASET
Load a DataBC WFS layer to a postgres db
$ bcdata bc2pg whse_imagery_and_base_maps.gsr_airports_svw
Options:
-db, --db_url TEXT Target database url, defaults to
$DATABASE_URL environment variable if set
--table TEXT Destination table name
--schema TEXT Destination schema name
--geometry_type TEXT Spatial type of geometry column
--query TEXT A valid CQL or ECQL query
--bounds TEXT Bounds: "left bottom right top" or "[left,
bottom, right, top]". Coordinates are BC
Albers (default) or --bounds_crs
--bounds-crs, --bounds_crs TEXT
CRS of provided bounds
-c, --count INTEGER Total number of features to load
-k, --primary_key TEXT Primary key of dataset
-s, --sortby TEXT Name of sort field
-e, --schema_only Create empty table from catalogue schema
-a, --append Append to existing table
-r, --refresh Truncate from existing table before load
-t, --no_timestamp Do not log download to bcdata.log
-v, --verbose Increase verbosity.
-q, --quiet Decrease verbosity.
--help Show this message and exit.
$ bcdata cat --help
Usage: bcdata cat [OPTIONS] DATASET
Write DataBC features to stdout as GeoJSON feature objects.
Options:
--query TEXT A valid CQL or ECQL query
-c, --count INTEGER Number of features to request and dump
--bounds TEXT Bounds: "left bottom right top" or "[left,
bottom, right, top]". Coordinates are BC
Albers (default) or --bounds_crs
--bounds-crs, --bounds_crs TEXT
CRS of provided bounds
--indent INTEGER Indentation level for JSON output
--compact / --not-compact Use compact separators (',', ':').
-s, --sortby TEXT Name of sort field
-l, --lowercase Write column/properties names as lowercase
-m, --promote-to-multi Promote features to multipart
-v, --verbose Increase verbosity.
-q, --quiet Decrease verbosity.
--help Show this message and exit.
$ bcdata dem --help
Usage: bcdata dem [OPTIONS]
Dump BC DEM to TIFF
Options:
-o, --out_file TEXT Output file
--bounds TEXT Bounds: "left bottom right top" or "[left,
bottom, right, top]". Coordinates are BC
Albers (default) or --bounds_crs [required]
--bounds-crs TEXT CRS of provided bounds
-r, --resolution INTEGER
-a, --align Align provided bounds to provincial standard
-i, --interpolation [nearest|bilinear|bicubic]
-v, --verbose Increase verbosity.
-q, --quiet Decrease verbosity.
--help Show this message and exit.
$ bcdata dump --help
Usage: bcdata dump [OPTIONS] DATASET
Write DataBC features to stdout as GeoJSON feature collection.
$ bcdata dump bc-airports
$ bcdata dump bc-airports --query "AIRPORT_NAME='Victoria Harbour (Shoal Point) Heliport'"
$ bcdata dump bc-airports --bounds xmin ymin xmax ymax
It can also be combined to read bounds of a feature dataset using Fiona:
$ bcdata dump bc-airports --bounds $(fio info aoi.shp --bounds)
Options:
--query TEXT A valid CQL or ECQL query
-c, --count INTEGER Number of features to request and dump
--bounds TEXT Bounds: "left bottom right top" or "[left,
bottom, right, top]". Coordinates are BC
Albers (default) or --bounds_crs
--bounds-crs, --bounds_crs TEXT
CRS of provided bounds
-s, --sortby TEXT Name of sort field
-l, --lowercase Write column/properties names as lowercase
-m, --promote-to-multi Promote features to multipart
-v, --verbose Increase verbosity.
-q, --quiet Decrease verbosity.
--help Show this message and exit.
$ bcdata info --help
Usage: bcdata info [OPTIONS] DATASET
Print basic metadata about a DataBC WFS layer as JSON.
Optionally print a single metadata item as a string.
Options:
--indent INTEGER Indentation level for JSON output
--count Print the count of features.
--name Print the table name of the dateset.
--description Print the description of the dateset.
-v, --verbose Increase verbosity.
-q, --quiet Decrease verbosity.
--help Show this message and exit.
$ bcdata list --help
Usage: bcdata list [OPTIONS]
List DataBC layers available via WFS
Options:
-r, --refresh Refresh the cached list
--help Show this message and exit.
Note that bc2pg
creates bcdata.log
and logs the most recent download date for each table downloaded.
Disable with the switch --no_timestamp
if you do not wish to create this table.
Example of a record in bcdata.log
:
mydb=# select * from bcdata.log;
table_name | latest_download
---------------------------------------------+-------------------------------
whse_imagery_and_base_maps.gsr_airports_svw | 2021-02-17 11:50:34.044481-08
Search the data listing for airports:
$ bcdata list | grep AIRPORTS
WHSE_IMAGERY_AND_BASE_MAPS.GSR_AIRPORTS_SVW
Describe a dataset. Note that if we know the id of a dataset, we can use that rather than the object name:
$ bcdata info bc-airports --indent 2
{
"name": "WHSE_IMAGERY_AND_BASE_MAPS.GSR_AIRPORTS_SVW",
"count": 455,
"schema": {
"properties": {
"CUSTODIAN_ORG_DESCRIPTION": "string",
"BUSINESS_CATEGORY_CLASS": "string",
"BUSINESS_CATEGORY_DESCRIPTION": "string",
"OCCUPANT_TYPE_DESCRIPTION": "string",
...etc...
},
"geometry": "GeometryCollection",
"geometry_column": "SHAPE"
}
}
The JSON output can be manipulated with jq. For example, to show only the fields available in the dataset:
$ bcdata info bc-airports | jq '.schema'
{
"CUSTODIAN_ORG_DESCRIPTION": "string",
"BUSINESS_CATEGORY_CLASS": "string",
"BUSINESS_CATEGORY_DESCRIPTION": "string",
"OCCUPANT_TYPE_DESCRIPTION": "string",
etc...
}
Dump data as supplied by server (BC Albers):
$ bcdata dump bc-airports > bc-airports.geojson
Dump data to geojson that conforms to RFC7946):
$ bcdata dump bc-airports | \
ogr2ogr -f GeoJSON -lco RFC7946=YES /vsistdout/ /vsistdin/ > bc-airports-4326.geojson
Dump to Parquet on S3:
$ bcdata dump bc-airports | \
ogr2ogr -f Parquet /vsis3/$BUCKET/airports.parquet /vsistdin/
Load data to postgres and run a spatial query:
$ bcdata bc2pg bc-airports \
--db_url postgresql://postgres:postgres@localhost:5432/postgis
$ bcdata bc2pg WHSE_LEGAL_ADMIN_BOUNDARIES.ABMS_MUNICIPALITIES_SP \
--db_url postgresql://postgres:postgres@localhost:5432/postgis
$ psql -c \
"SELECT airport_name
FROM whse_imagery_and_base_maps.gsr_airports_svw a
INNER JOIN whse_legal_admin_boundaries.abms_municipalities_sp m
ON ST_Intersects(a.geom, m.geom)
WHERE admin_area_name LIKE '%Victoria%'"
airport_name
------------------------------------------------------------------
Victoria Harbour (Camel Point) Heliport
Victoria Inner Harbour Airport (Victoria Harbour Water Airport)
Victoria Harbour (Shoal Point) Heliport
(3 rows)
All data are as supplied from the server by default: BC Albers / EPSG:3005
.
Use some other tool to reproject the data as required.
bc2pg
tests require database postgresql://postgres@localhost:5432/test_bcdata
exists and has PostGIS installed:
psql -c "create database test_bcdata"
psql test_bcdata -c "create extension postgis"
Create virtualenv and install bcdata
in development mode:
$ git clone git@github.com:smnorris/bcdata.git
$ cd bcdata
$ python -m venv .venv
$ source .venv/bin/activate
(.venv)$ pip install -e .[test]
(.venv)$ py.test
- bcdata R package - official BC Open Data R client
- OWSLib - used internally by
bcdata
- pgsql-ogr-fdw - read WFS data directly into with postgres foreign data wrapper
- general purpose command line tools (
ogr2ogr
/curl
/wget
)