Skip to content

Layer format

The layer format is the only interface between openwater (which writes layers and projects) and the viewer and docs (which read them). It is defined in openwater/src/openwater/spec/: the JSON Schemas layer.schema.json and project.schema.json plus the feature rules in spec/__init__.py. The viewer image contains a copy of the schemas and nothing else from openwater.

Current version: 1 (spec_version in every layer.json).

A layer package

<data dir>/layers/<layer id>/
├── layer.json      metadata (below), validated against layer.schema.json
└── data.geojson    FeatureCollection with the features

Consumers may add their own files to the folder (the viewer adds style.json, tiles.pmtiles, .tiles.json). openwater never touches them, and replaces layer.json and data.geojson atomically on every export.

Layer ids are lowercase letters, digits and hyphens, e.g. kiel-hydrants.

data.geojson

  • One FeatureCollection. Geometry type matches layer.json → geometry: Point; LineString/MultiLineString; Polygon/MultiPolygon. Coordinates in WGS84.
  • Each feature's properties are exactly the layer's attributes, with the declared type, present unless the attribute is optional, and for closed attributes one of the listed values.
  • If osm_tags is true, features also carry their raw OSM tags as osm:<key>.
  • No other properties.

layer.json

Field Content
spec_version "1"
id, title, description Identity and texts
geometry point, line or polygon
region {id, name}
bbox [west, south, east, north]
data {file: "data.geojson", count, sha256}. The checksum lets consumers detect changed data
generated_at, osm_timestamp When exported; state of the OSM data
generator {name, version, script}
parameters Name → {value, unit, description}
osm_tags Whether features carry osm:<key> tags
attributes Attribute id → {type, label, description, unit, optional, closed, values, source} in evaluation order. values: value key → {label, description}, booleans as "true"/"false". source documents how the value was produced (osm_id, feature_id, tag, matching_rules, none_matched, nearest, classify, sum_within, index, value_at, with their parameters)
rule_sets Id → {title, description, attribute, rules}; attribute holds the ids of matching rules; each rule {id, title, description, where, source, status}
assumptions [{id, title, description, status}]
planned [{id, title, description, step}]
sources [{id, title, used_for, url, license, license_url, attribution}]
stats {count, value_counts, completeness, rule_counts, numeric}: features per value (attributes with values and booleans), share of features where an attribute's OSM tag is present, features per rule, and for numeric attributes min, max, mean, p25–p95 (optional; the viewer scales heat maps with it)

Status of rules and assumptions: assumption (working hypothesis, not yet checked), verified (confirmed by a named source), rejected (kept for the record, no longer applied).

Conditions (where in rules, in nearest and in classify cases): attribute id → a scalar (equals), a list (one of), {"op": "not_empty"}, {"op": "empty"}, {"op": "min", "value": x}, {"op": "max", "value": x}. All must hold; a condition on an absent attribute is false except empty.

Projects

A project groups layers that are shown together, e.g. the five layers of one study region. The viewer shows one project at a time; the docs list the layers by project.

<data dir>/projects/<project id>.json
Field Content
spec_version "1"
id, title, description Identity and texts; the id matches the file name
layers [{id, visible}] in drawing order, the first on top. visible: false = listed but switched off when the project is opened
generated_at, generator When exported; {name, version, script}

The layers are referenced by id and live in layers/<id>/; a layer may belong to several projects, and a layer in no project is not shown on the map. A project may list a layer that isn't exported yet; the viewer shows it as missing.

Checking a package

from openwater import spec
spec.package_errors("data/viewer/layers/kiel-hydrants")   # [] if valid

spec.project_errors(doc) checks a project document. The viewer checks layer.json and project files against the schemas and lists invalid ones in Settings with the reason, without loading them.

Changing the format

The format is versioned. Additions that old readers can ignore keep the version (e.g. a new optional field). Anything that changes the meaning of existing fields needs a new spec_version, an update of the viewer and docs, and a re-export of all layers.