How the dating of archaeological findspots by samian potters’ stamps is modelled as RDF, and why each decision was taken.
The source is a single query over the Samian Research / IPS database, one row per findspot. The export turns each row into a small graph built on CIDOC CRM, OWL-Time, PROV-O and the local LADO vocabulary, and a companion step reconstructs the published figure from that graph alone using SPARQL. That reconstruction is the test of the modelling: if a quantity the figure needs is missing from the graph, the round trip fails rather than quietly substituting a default.
| Page | Contents |
|---|---|
| Model | The three layers, URI strategy, and the treatment of missing values |
| Vocabulary | The 14 classes and 84 properties minted here |
| Crosswalk | Mapping to CIDOC CRM, OWL-Time, GeoSPARQL, PROV-O, DCAT and SKOS |
| Statistics | The formulas behind the intervals, as implemented in SQL |
| Queries | The SPARQL used to rebuild the figure, and the round-trip check |
| Bundle | The standalone file for a triplestore, and why the crosswalk is materialised |
| Method notes | The formulae in longhand, the SQL walkthrough, and where the data come from |
flowchart LR
DB[("PostgreSQL<br/>Samian Research / IPS")]
SQL["sql/IPSDatedSites.sql<br/>one row per findspot"]
CSV["data/*.csv"]
EXP["py/ips_rdf_export.py"]
RDF["rdf/<br/>ips_sites_dating_v1.ttl<br/>ips_sites_dating_v1.jsonld<br/>lado_dating_extension.ttl<br/>IPSDatedSites-bundle.ttl"]
SPQ["py/ips_sparql.py<br/>reads everything back"]
REN["py/ips_render.py"]
IMG["img/<br/>plot_v1_classic<br/>plot_v2_modern<br/>plot_v2_gauss"]
DOC["py/make_docs.py<br/>py/make_diagrams.py"]
DOCS["docs/"]
VER["py/verify.py<br/>step 0"]
WEB["py/make_webjs.py"]
JS["webjs/<br/>ips_rdf.js<br/>to the ColdFusion server"]
SPB["py/build_sparql.py<br/>queries.yaml"]
PAGE["docs/query/<br/>docs/bundle.ttl<br/>qmd/"]
CHK{"round trip<br/>17 fields compared"}
PAR{"parity<br/>sorted N-Triples, SHA-256"}
DB --> SQL --> CSV --> EXP --> RDF --> SPQ --> REN --> IMG
CSV --> VER
EXP --> DOC --> DOCS
EXP --> WEB --> JS
RDF --> SPB --> PAGE
SPQ --> CHK
CSV -.-> CHK
WEB --> PAR
EXP -.-> PAR
class DB,SQL,CSV io
class RDF,IMG,DOCS,JS,PAGE ext
class EXP,SPQ,REN,DOC,WEB,SPB local
class CHK,PAR,VER time
classDef local fill:#e8eef7,stroke:#4a6b96,stroke-width:1px,color:#12181f
classDef crm fill:#efe7f5,stroke:#7a5a96,stroke-width:1px,color:#12181f
classDef time fill:#e3f2ec,stroke:#3f8a70,stroke-width:1px,color:#12181f
classDef ext fill:#f3f1ec,stroke:#8a857a,stroke-width:1px,color:#12181f
classDef io fill:#faf3e3,stroke:#a8872e,stroke-width:1px,color:#12181f
The pipeline. Everything after the export reads from the graph, never from the CSV — apart from the round-trip check, which compares the two.
JPG · SVG · Mermaid source — generated, do not edit.
A findspot (lado:Findspot, beneath crm:E53_Place) falls within a
published discovery site. Its dating (lado:FindspotDating, beneath both
crm:E52_Time-Span and time:ProperInterval) hangs off it and carries the
computed interval together with every quantity needed to recompute that
interval. The presentation layer sits apart: a lado:PlotRow renders the
dating and carries the whiskers, which the method documentation classes as
visual only. Provenance runs through PROV-O, with the model parameters
stated once on a prov:Plan rather than repeated on each row.
These pages are generated. Running the pipeline rewrites them:
python py/main.py
Structure comes from the code itself — classes, properties, namespaces,
figure constants and queries are read at generation time. The English
prose lives in py/ips_docs_text.py, which also supplies the English
rdfs:comment on every term in the ontology, so a definition cannot be
correct in the documentation and stale in the RDF. The generator refuses
to run if a class or property in the code has no entry there.
14 classes, 21 object properties and 63 datatype
properties. Undated by design: what these pages describe is the code, which
does not have a date, and the corpus state is recorded in
data/SNAPSHOT.json.