This work is dedicated to Sam Moorhead, who inspired so many with Roman numismatics, notes on the back of pieces of paper and bored us all with Reece Periods at every coin conference, PAS meeting and canteen lunch. He got his way, they are in Nomisma, PAS and beyond. Richard Reece's lectures at UCL were always entertaining, not sure I always understood them...
This repository holds data and scripts for working with Roman coins from Reece Period 1 on the Portable Antiquities Scheme and mapping them onto an instance of Peripleo. I have created all of this for the 2025 European Coin Find Network XII Annual Meeting being held at my former place of study, UCL Institute of Archaeology, where I'm giving a talk called 'Peripleo and PAS Republican coins: powered by an army of elves since 2003'.
The Portable Antiquities Scheme (PAS) is a project in England and Wales to encourage the reporting of archaeological finds by the public. I built the database from 2006 - 2016, and my code is still in use now in 2025. There are plans to replace what I built, but for now, it continues to serve its purpose. This demonstration shows how linked open data drawn from the database can be used to produce interesting visualizations and insights. The presentation title refers to how the database has been nationally available since 2003, and the elves refers to a header that has been returned on every request since then x-powered-by: Dan's magic army of elves. More background data on the database can be found in my publications, for example The Portable Antiquities Scheme's Database: its development for research since 1998.
The process to do this has been made considerably harder than when I was in post and I no longer have access to the same resources I did then. The British Museum IT team have removed lots of features making it harder to access data, assign recorders and finders and produce any insight into who recorded what, when or how their knowledge grew. They have also blocked search indexing and are using Cloudflare to try and prevent robots and programmatic access to data - or at least that is what they probably think.
I wanted images and data from the system and geographical context, so I wrote a series of scripts to extract and process the information I needed. These are all in Python and do the following:
- Scrape and download JSON data from the PAS website (csv download now restrictive)
- Geocode known as places to allows them to be mapped (badly)
- Download images of the coins
- Compress the images to a smaller size for use in Peripleo
- Create Linked Pasts geojson for use in Peripleo
- Split the images into obverse and reverse
- Create a ML model for coin identification
- Provide an example of running the scripts
This social preview card with nonsense coins on was generated with Google Gemini using this prompt:
Create me a social preview card with a map of England with Roman Republican coins imposed on it, with the text 'Exploring Roman coins from Reece Period 1'
To run the python code I recommend using a virtual environment and then run the code snippets in the appropriate sections. The libraries you will need include: OpenCV, tensorflow, Numpy, Pandas and a few others.
git clone https://github.com/portableant/republican-coins.git
cd republican-coins
python3 -m venv venv
source venv/bin/activate
pip3 install -r requirements.txtA working demo showing steps for this can be seen in [notebooks/obtainData.ipynb](notebooks/obtainData.ipynb).
To get round Cloudflare, I use the cloudscraper library.
To scrape the JSON data from the PAS website and convert it to CSV format, run the following commands. This takes the JSON search results and pages through the API, without being blocked by the Cloudflare javascript challenge. When I designed the PAS database, it was meant to be interoperable, machine readable and open to all. There's now no indexed finds records on Google for instance! When I left the Scheme, over 700,000 pages were indexed and the system was engineered for low bandwidth council evironments. If I'd kept building it, it would be very different now, but Cool URIS, open data and interoperability would still be the key tenets. I created all the interlinked tables, dropdowns and mechanism for coin recording and linked them all off to Nomisma when possible.
cd scrapers
python records.pyTo download images of the coins, run the following command, some will fail as they are either missing or inaccessible (how that happened...) Some can be got from wikicommons if you fancy some manual searching. They have done a mighty job saving images on there - but are now encountering the cloudflare issue.
python images.pyTo compress downloaded images assume you are in the scrapers folder, change directory and use the following script. Compressing keeps the size down so you actually run your peripleo instance off GH pages build. I don't trust the PAS images to remain accessible easily, so they are used under CC-BY license here (I changed the BM stance on using this in 2006). If you don't compress the images, you'll get a 5GB or so repo and the pages mechanism will shout at you and say no.
cd ../scripts
python compress.pyThe way the PAS was set up, we hid grid references for some finds at the request of the finder or landowner and used a field called 'known as'. This usually gives a geographical hint you can use for georeferencing using an API like Nominatim.
python geocode.pyTo generate LinkedPasts geojson for use within the Peripleo instance we want to run, you can run the following command. This takes the geocoded csv file and manipulates it to meet the required structure - indexing, features with the correct structure including properties, links, depictions and types.
python createLPgeoJson.pyThis dataset is well structured and I didn't need to go off and find additional data. The IDs for linked open data already exist - this is a product of LAWDI and NOMISMA - and we have access to pleiadesID, dbPediaID, Wikidata, VIAF and Nomisma IDs (and WOEID and OS IDs, but hey, they went...) Time period is linked to a Periodo identifier.
All the work for linked data and RDF was done in around 2010-2013 and is discussed in these papers:
- Linking Portable Antiquities to a wider web
- Portable Antiquities on the Web
- Semantic Web Technologies Applied to Numismatic Collections
If you're interested more in the numismatic side of these data then work by Sam Moorhead, Philippa Walton, Roger Bland, Andrew Brown and lately Richard Henry would be worth reviewing.
So one feature will look something like this:
{
"@id": "https://finds.org.uk/database/artefacts/record/id/757656",
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-0.11395435,
51.50376016
]
},
"properties": {
"findIdentifier": "finds-757656",
"oldFindID": "LON-00A134",
"objecttype": "COIN",
"broadperiod": "ROMAN",
"description": "Roman Republican silver denarius, moneyer C. Cato, mint Rome 123.BC, Reece period 1. Reverse is Victory, right, in biga. legend (C.CATO); [ROMA] in exergue.\n\n\n\nWeight: 2.36g\nDiameter: 17.45mm",
"county": "Greater London Authority",
"district": "City and County of the City of London",
"parish": "Castle Baynard",
"ruler": "Republic",
"moneyer": "Porcius Cato, C.",
"moneyerNomismaID": "c_cato_rrc",
"denomination": "Denarius (Roman Republic)",
"mint": "Rome",
"manufacture": "Struck or hammered",
"reeceID": "1",
"nomismaMint": "rome",
"pleiadesID": "423025",
"materialTerm": "Silver",
"weight": "2.36",
"date_from": "-123",
"date_to": "-123",
"axis": "12",
"discovery": "Metal detector",
"institution": "LON",
"created": "2015"
},
"depictions": [
{
"@id": "https://republican-coins.museologi.st/images/DenariusLON00A134.jpg",
"thumbnail": "https://republican-coins.museologi.st/images/DenariusLON00A134.jpg",
"label": "A depiction of LON-00A134"
}
],
"descriptions": [
{
"value": "Roman Republican silver denarius, moneyer C. Cato, mint Rome 123.BC, Reece period 1. Reverse is Victory, right, in biga. legend (C.CATO); [ROMA] in exergue.\n\n\n\nWeight: 2.36g\nDiameter: 17.45mm"
}
],
"when": {
"timespans": [
{
"start": {
"in": "-123"
},
"end": {
"in": "-123"
}
}
],
"periods": [
{
"name": "Roman Republican 510 BC - 27 BC",
"uri": "http://n2t.net/ark:/99152/p08m57h65c8"
}
],
"label": "for a century during the Roman period",
"certainty": "certain",
"duration": "P100Y"
},
"links": [
{
"identifier": "https://pleiades.stoa.org/places/423025",
"type": "seeAlso",
"label": "Pleiades place: 423025"
},
{
"identifier": "https://nomisma.org/id/rome",
"type": "seeAlso",
"label": "Nomisma mint: rome"
},
{
"identifier": "https://nomisma.org/id/reece1",
"type": "seeAlso",
"label": "Nomisma Reece Period: 1"
},
{
"identifier": "https://nomisma.org/id/c_cato_rrc",
"type": "seeAlso",
"label": "Nomisma moneyer: Porcius Cato, C."
}
]
}And rendered here as geoJSON (note point precision is either based off a 4 figure British National Grid Reference, or gecoded to a place name):
{
"@id": "https://finds.org.uk/database/artefacts/record/id/757656",
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-0.11395435,
51.50376016
]
},
"properties": {
"findIdentifier": "finds-757656",
"oldFindID": "LON-00A134",
"objecttype": "COIN",
"broadperiod": "ROMAN",
"description": "Roman Republican silver denarius, moneyer C. Cato, mint Rome 123.BC, Reece period 1. Reverse is Victory, right, in biga. legend (C.CATO); [ROMA] in exergue.\n\n\n\nWeight: 2.36g\nDiameter: 17.45mm",
"county": "Greater London Authority",
"district": "City and County of the City of London",
"parish": "Castle Baynard",
"ruler": "Republic",
"moneyer": "Porcius Cato, C.",
"moneyerNomismaID": "c_cato_rrc",
"denomination": "Denarius (Roman Republic)",
"mint": "Rome",
"manufacture": "Struck or hammered",
"reeceID": "1",
"nomismaMint": "rome",
"pleiadesID": "423025",
"materialTerm": "Silver",
"weight": "2.36",
"date_from": "-123",
"date_to": "-123",
"axis": "12",
"discovery": "Metal detector",
"institution": "LON",
"created": "2015"
},
"depictions": [
{
"@id": "https://republican-coins.museologi.st/images/DenariusLON00A134.jpg",
"thumbnail": "https://republican-coins.museologi.st/images/DenariusLON00A134.jpg",
"label": "A depiction of LON-00A134"
}
],
"descriptions": [
{
"value": "Roman Republican silver denarius, moneyer C. Cato, mint Rome 123.BC, Reece period 1. Reverse is Victory, right, in biga. legend (C.CATO); [ROMA] in exergue.\n\n\n\nWeight: 2.36g\nDiameter: 17.45mm"
}
],
"when": {
"timespans": [
{
"start": {
"in": "-123"
},
"end": {
"in": "-123"
}
}
],
"periods": [
{
"name": "Roman Republican 510 BC - 27 BC",
"uri": "http://n2t.net/ark:/99152/p08m57h65c8"
}
],
"label": "for a century during the Roman period",
"certainty": "certain",
"duration": "P100Y"
},
"links": [
{
"identifier": "https://pleiades.stoa.org/places/423025",
"type": "seeAlso",
"label": "Pleiades place: 423025"
},
{
"identifier": "https://nomisma.org/id/rome",
"type": "seeAlso",
"label": "Nomisma mint: rome"
},
{
"identifier": "https://nomisma.org/id/reece1",
"type": "seeAlso",
"label": "Nomisma Reece Period: 1"
},
{
"identifier": "https://nomisma.org/id/c_cato_rrc",
"type": "seeAlso",
"label": "Nomisma moneyer: Porcius Cato, C."
}
]
}
These data are varied in quality, FLOs are not numismatists and there's lots of holes and dirty data. To make this an excellent resource, the csv download could be cleaned and enriched automatically from nomisma and other resources. Maybe I'll write some scripts for this later.
To map these data and provide a visualisation tool, I am using the Peripleo framework that was created for Locating a National Collection. This is well documented for setup and runs on Github pages direct from the docs folder. It is therefore served for free and uses a custom URL to link semantically with other work I have done. Documentation for that is found in the README in the peripleo folder.
The below scripts demonstrate a proof of concept for using machine learning to classify coin images based on their RRC IDs. Other people have done similar things, but I'm trying again using live coin find data rather than pristine copies. As I note below, the other way maybe better but the field/desk archaeologist doesn't see many top quality speciments. The images are processed and used to train a model that can predict the RRC ID of new coin images. However, there's not many of each type on PAS. So, this would work far better taking images from CRRO and then using these data there to try and predict the PAS coin and RRC ID. I didn't have time to do it that way, so try this for now.
Assuming you are still in the scripts directory, you can split the images into obverse and reverse, run the following command:
python splitImages.py The classification script takes the images and uses obverse and reverse images for training, aligned to their respective rrcIDs.
python classification.py This script takes the trained model and makes predictions on new images, which are stored in a folder. The first will give you the top choice, but that might be too specific.
python scripts/classifier_single.pyThis script will give you a set of predictions with their probabilities.
python scripts/classifier_multiple.py
