Findspot datings as linked data

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.

Pages

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.

The shape of it in one paragraph

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.

Regenerating

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.