GeoJSON and Trinity College Camb. R.3.14

This image is taken from the Project Gutenberg edition of Whitaker’s text (made from TCC B.15.17) that includes this rendering of a drawing on the opening folio of TCC R.3.14.

To pair with yesterday’s visualization of Piers Plowman in space, I’m going to do a post today about GeoJSON.

GeoJSON is compatible with JSON-LD; both different uses of JSON are trying to link object data (or “feature” data) to other data.  In the case of GeoJSON, that is very specifically linking data with spatial components, particularly in such a way that this data can be mapped.

In order to write GeoJSON, all data has to exist with a single object, which is something we’ve covered before.  A GeoJSON object can only represent very specific types of data, though, that comes as a geometry, a feature, or a collection of features.

GEOMETRIES are different ways of representing a phenomenon in space.  GeoJSON supports these different kinds of geometry:

  • Point (done with Latitude and Longitude coordinates representing a single position)
  • LineString (has “coordinates” in an array of two or more positions)
  • Polygon (“coordinates” make an array of coordinates that form a Linear Ring–where the LineString is ‘closed’ by making the first and last positions equivalent)
  • MultiPoint (“coordinates” are an array of positions)
  • MultiLineString (“coordinates” are an array of LineString coordinate arrays–an array within an array)
  • MultiPolygon (an array of polygon arrays)
  • Geometry Collection (which allows you to mix and match your geometries, but be careful, not all applications read different geometries equally well; CartoDB, for instance, cannot import both points and polygons into a single table)

Like in our regular JSON, in GeoJSON an object is made up of name/value pairs called “members.” Just like before, the name is a string and the values must always be a stringnumberobjectarray, or a boolean value of “true,” “false,” or “null.”

GeoJSON is always a single object organized into one of the above named geometries, or as a feature or collection of features. According to the GeoJSON specs, there are a few rules for writing GeoJSON.  Here they are according to the specs, though we may not need to deal with all of these rules ourselves.

Screen Shot 2014-06-01 at 5.59.18 PM
The Rules for GeoJSON Objects — we aren’t really going to be using CRS or Bounding Boxes, but if you want to know more, go to

The fundamental way in which GeoJSON communicates spatial information is through positions, which are always conveyed using the member name “coordinates”. Positions are always an array of numbers. 

FEATURE OBJECTS are primarily what we’re going to be concerned with here, because they are most compatible with the kinds of data objects we’re used to working with.  We simply have to follow a few rules with our data to make sure it’s GeoJSON rather than JSON-LD.

  • A feature object must have a member named “geometry” represented as I outlined above or as “null.”
  • It also must have a “properties” member, which is where we are going to store all our additional (i.e. non-geographical ) data in our code.
  • Finally, if the feature has a commonly used identifier, there needs to be an “id” member of the feature object.

Now, for mapping a corpus, we aren’t just going to write one Feature, though we certainly could.  It would be entirely possible for us to take a full array of geometries (out of our Google KML or CartoDB table from yesterday) and make them into one, single “feature,” but then we would not be able to include individual MS data.  If we were, say, comparing several corpora, this might help us. We would make one feature for Piers, one for The Canterbury Talesand one for Gower’s Confessio Amantis, for example.  Then we could compare all these MultiPolygon features to each other.

Still, what we’d be doing then is making a Feature Collection, which is what we are actually going to model for Piers MSS.

FEATURE COLLECTION is simply a bunch of features arranged in an array and with a member that has the name “features” with the value being that array.

So, using data we are already familiar with, we’ll start our feature collection:

Screen Shot 2014-06-01 at 6.15.41 PM

And then I’m going to add in my “features” and room for that array:

Screen Shot 2014-06-01 at 6.16.36 PM

Inside the “features” array, we will have a list of GeoJSON objects with Polygon geometries (which we are taking from the CartoDB table that made the map we looked at yesterday). We are only going to include the four MSS that we have thus far encoded, so I’ll go ahead and make space for them by inserting blank sets of curly brackets that I will then start working in.

Screen Shot 2014-06-01 at 6.19.05 PM

Each object is going to be a “Feature” so I make sure to designate that:

Screen Shot 2014-06-01 at 6.21.00 PM

And then I have to include a geometry, so I insert those next. Each geometry is going to have to have a type as well, so I’ll include that as well. Notice that each “geometry” requires another nested object to be made (with { } that I line up using tabs).

Screen Shot 2014-06-01 at 6.24.44 PM

That’s because each geometry object is going to need several more members, including at the very least some “coordinates” and “properties” as well as an “id” to help us keep everything straight.

Screen Shot 2014-06-01 at 6.29.13 PM

To add coordinates, I’m going to access the same polygon information I have stored in my CartoDB table.

Screen Shot 2014-06-01 at 6.32.44 PM

When I copy+paste that polygon information, it looks like this:


All I need to do now is copy+paste only the content inside the [[[[ ]]]] (inclusive of the brackets, we don’t want to mess up any GeoJSON syntax and we’ll check our brackets using a JSON editor). I also notice that CartoDB is using “MultiPolygon” to designate this data, so I will do the same in my data.

Screen Shot 2014-06-01 at 6.39.31 PMScreen Shot 2014-06-01 at 6.40.16 PM

Now, the last thing I have to do to make this valid GeoJSON that also carries my other data is add “properties”. For the sake of simplicity, we’re just going to throw in a few basic things like date and textual variant so that if we graph this on a map, it’s easy to pull up additional data.

Screen Shot 2014-06-01 at 6.45.11 PM

Now we run our GeoJSON through the JSONeditoronline to double check and make sure all our code is correct. First thing we note, the JSON editor HATES the representation of number range with a hyphen.

Screen Shot 2014-06-01 at 6.48.13 PM

While we got away with it in our JSON-LD because of our @context, which told our JSON to expect a number or hyphenated range of numbers for “DateRange”, here, we have to either make the date range two items, expecting two numbers OR we can simply make it a string by adding ” ” around it. I’m going to make it a string so that we can change as little data as possible.

Screen Shot 2014-06-01 at 6.52.19 PM

I make sure to change all the “DateRange” members because even though the last one would be valid JSON as a number ( 1400 ), it won’t read like the same kind of data as all the other “DateRange”s, so I make it “ca1400”.

My only other problem is one little extraneous comma

Screen Shot 2014-06-01 at 6.53.05 PM

which we just remove and then we are good to go.

Screen Shot 2014-06-01 at 6.57.00 PM


But if we test our GeoJSON in a GeoJSON specific sandbox, we find there’s a problem:

Screen Shot 2014-06-01 at 7.20.51 PM

So if we go back and look, we can see that our “properties” were listed as part of the “geometry”,  so we have to go back and take those out of the geometry object and make sure they’re in our “Feature” object instead.

Screen Shot 2014-06-01 at 7.23.50 PM

To do that, I’ve deleted the } ending that was in the space between the red and the closing } and moved it up to close the “geometry” object.  I’ve also moved “id” and “properties” members over to line up with the “geometry” member.

We can now try out our GeoJSON again in When we do, it tells us we have a JSON serialization error, so we have to go back and check the code.  Easy. We’ve named some of our features “Polygon” and some “MultiPolygon.” I tested out both, and they both work just fine, but to stick with our naming above, each feature (MS) has only one Polygon (and not more), so we’ll just change everything back to “Polygon” and we’re all set.

Screen Shot 2014-06-01 at 7.36.42 PM

If we just copy+paste our information into the Polygon editor, it pops up our map RIGHT away! Le voila!  Go ahead, give it a try yourself by opening this file, EarlyPiersGeoJSON, and copy+paste the complete code into the geojsonlint editor.

Now, my MS data isn’t so GeoJSON specific, so I’m not going to reformat all my data as a features collection.  Instead, I can add geographical information for TCC R.3.14 to our existing JSON-LD, which means that once the data is complete, it’s easy to change the existing JSON-LD into GeoJSON.  All we’d have to do is make each MS a “Feature”, give it a “geometry” like we did here, and shift all that data into the “properties”.

That’s more work than is necessary at the moment, though, so what I’m going to do today is add the GeoJSON geometry to the dialect region in my existing JSON-LD for TCC R.3.14.

Screen Shot 2014-06-01 at 7.51.20 PM

I had to make “DialectRegion” into an object with our GREEN curly brackets, and then I moved the string describing it to a new member named “Locale”. Then I just imported the “geometry” object we just built, with the value for “geometry” contained in the RED curly brackets.

Our complete code, with new additions highlighted in purple, is as follows: TCCR.3.14p1 TCCR.3.14p2 TCCR.3.14p3





“@context”: {


“name”: {“@id”:”foaf:name”},

“MSshortHand”: {“@id”:”foaf:nick”},


“dcterms”: “”,

“DateRange”: {“@id”: “dcterms:PeriodOfTime”},

“provenance”: {“@id”: “dcterms:provenance”},

“language”: {“@id”: “dcterms:language”},

“PhysicalObject”: ““,

“PrintedEdition(s)”: {“@id”: “dcterms:BibliographicResource”},


“TEI”: ““,

“msDesc”: {“@id”: “TEI:msDesc.html”},

“msIdentifier”: {“@id”: “TEI:msIdentifier.html”},

“repository”: {“@id”: “TEI:repository.html”},

“msContents”: {“@id”: “TEI:msContents.html”},

“work”: {“@id”: “TEI:msItem.html”},

“title”: {“@id”: “TEI:title”},

“author”: {“@id”: “TEI:author.html”},

“DialectRegion”: {“@id”: “TEI:region.html”},

“publisher”: {“@id”: “TEI:publisher.html”},



“date”: {“@id”: “xsd:date”},


“LALME”: “”,

“IMEVid”: “”

“MEScribesid”: “”,

“MECompBib”: “”,



“@type”: “PhysicalObject”,

“MSshortHand”: “TCCR.3.14”,

“HoldingLocation”: “Cambridge, UK”,

“repository”: “Trinity College Library”,

“msIdentifier”: “R.3.14”,

“Olim.”: null,


“LALMEGrid”: 359213,


“MEScribesurl”: “”,

“MEScribesid”: {“@id”: “MEScribesid:364”}

“MSSOnline”: null,

“PPEA”: null,

“TEAMS”: null,

“IMEVNo”: [1585-2,2458-8],

“IMEVid”: {“@id”: “IMEVid:CamTCC594”},

“IMEVurl”: “”,

“MECompBib”: “”,

“DateRange”: 1400,

“Provenance”: “Sir Thomas Neville”,

“AquisitionDate”: 1615,

“Material”: “Vellum”,

“SupportQuality”: 6,

“Folios”: 74,

“Script”: “Anglicana formata w. cursive features”,

“ScriptQuality”: 5,

“msContents”: [“Piers Plowman”],

“NumberOfWorks”: 1,

“PositionOfPiers”: 1,

“PiersFolios”: 73,

“PiersPercentMS”: 98.6,

“PiersTextVariety”: “AC”,

“LinesOfPiers”: 6260,

“DialectRegion”: {

“Locale”: “mixed East Midlands w/ relict. Worcestershire forms”,

“geometry”: {


“coordinates”: [[[[0.016479,53.528881],[-0.010986,53.41608],[-0.175781,53.376774],[-0.230713,53.46843],[-0.20874,53.559891],[-0.351562,53.582722],[-0.571289,53.478237],[-0.892639,53.417717],[-1.038208,53.340714],[-1.257935,53.136887],[-1.625977,53.00156],[-1.587524,52.726311],[-1.516113,52.576351],[-1.362305,52.519566],[-1.318359,52.399067],[-1.098633,52.321911],[-0.576782,52.462704],[-0.098877,52.599712],[0.241699,52.742943],[0.219727,52.799438],[0.032959,52.892334],[0.043945,52.958565],[0.115356,53.034607],[0.280151,53.070927],[0.31311,53.159946],[0.258179,53.32431],[0.016479,53.528881]]]]



“Collation”: [“I2“, “a12″,”I*-f12″,”g2],

“PassusMarkers”: [

{“(I)”: “fol. 2r”,

“HeightInLines”: 9,

“Color”: red,


“Rubric”: null,

“Line”: “In a som: sesoun whanne softe was the sonne”},

{“( )”: “fol. 3r”,

“HeightInLines”: null,

“Color”: null,


“Rubric”: “Primus passus de visione in regular ink”,

“Line”: “What þe monnteyne meniþ …”},

{“( )”: “fol. 5r”,

“HeightInLines”: null,

“Color”: null,


“Rubric”: “Passus secundus de visione”,

“Line”: “Ȝet knelide I on my kne”},

{“( )”: “fol. 7v”,

“HeightInLines”: null,

“Color”: null,


“Rubric”: “Passus tcius de visione”,

“Line”: “Now is mede þe mayde…”},

{“( )”: “fol. 10v”,

“HeightInLines”: null,

“Color”: null,


“Rubric”: “Passus quartus de visione”,

“Line”: “Sessiþ seide þe kyng…”},

{“( )”: “fol. 12v”,

“HeightInLines”: null,

“Color”: null,


“Rubric”: “Passus quint9 de visione”,

“Line”: “Þe Kyng & kniȝtes to þe chirche went”},

{“( )”: “fol. 15v”,

“HeightInLines”: null,

“Color”: null,


“Rubric”: “Passus sextus de visione vt primis”,

“Line”: “Ac þe was fowe men so wys þt þei þid couþe”},

{“( )”: “fol. 17r”,

“HeightInLines”: null,

“Color”: null,


“Rubric”: “Passus septim9 de visione vt prims “,

“Line”: “Þis were a wikkid weye…”},

{“( )”: “fol. 20v”,

“HeightInLines”: null,

“Color”: null,


“Rubric”: “Passus octauus de visione vt p…”,

“Line”: “Treuþe herde telle here of & to peris sente”},

{“( )”: “fol. 22v”,

“HeightInLines”: null,

“Color”: null,


“Rubric”: “Explicit hic visio willi de petro de plouȝman : Eriam Incipit vita de do wel do bet & do best sedm wyt & reson”,

“Line”: “Thus yrobid in russet…”},

{“( )”: “fol. 24r”,

“HeightInLines”: null,

“Color”: null,


“Rubric”: “Passus primus de dowel …”,

“Line”: “Sire dowel dwelliþ…”},

{“( )”: “fol. 26v”,

“HeightInLines”: null,

“Color”: null,


“Rubric”: “Passus secundus de dowel etc.”,

“Line”: “Þanne hadde wyt a wyf…”},

{“( )”: “fol. 30r”,

“HeightInLines”: null,

“Color”: null,


“Rubric”: “Passus tertius de dowel/Brevis oracio Penetrat celum”,

“Line”: “Selde falliþ þe suaunt so depe ni arerage”},

{“(B)”: “fol. 33r”,

“HeightInLines”: 2,

“Color”: red,


“Rubric”: null,

“Line”: “But wel worþe pout fye he may walke unrobbit”},

{“( )”: “fol. 36r”,

“HeightInLines”: null,

“Color”: null,


“Rubric”: “Passus quartus de dowel”,

“Line”: “I am ymaginatif”},

{“(A)”: “fol. 39r”,

“HeightInLines”: 2,

“Color”: red,


“Rubric”: “Passus quint9 de visione vt sup”,

“Line”: “And I awakide…”},

{“(A)”: “fol. 42v”,

“HeightInLines”: 2,

“Color”: red,


“Rubric”: “Passus sextus de dowel “,

“Line”: “Allas þat richesse…”},

{“(T)”: “fol. 47v”,

“HeightInLines”: 2,

“Color”: null,


“Rubric”: “Passus septim9 de dowel & explicit”,

“Line”: “There is non such I ferde…”},

{“(L)”: “fol. 51r-v”,

“HeightInLines”: 2,

“Color”: red,


“Rubric”: “Passus primus de dobet”,

“Line”: “Loue hbim arbitum…”},

{“(I)”: “fol. 55r”,

“HeightInLines”: 2,

“Color”: red,


“Rubric”: “Passus secundus de dobet”,

“Line”: “I am spes… “},

{“(W)”: “fol. 58v-59r”,

“HeightInLines”: 2,

“Color”: red,


“Rubric”: “Passus tcius de dobet”,

“Line”: “Wollewerd…”},

{“(A)”: “fol. 70r”,

“HeightInLines”: 2,

“Color”: red,


“Rubric”: “Secundus passus de dobest”,

“Line”: “And as I wente be  þe way…”}


“PublishedEdition(s)”: null




Please do collaborate!

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s