Showing posts with label mapnik. Show all posts
Showing posts with label mapnik. Show all posts

Thursday, 19 May 2011

Rendering OpenStreetMap Data using Carto and Mapnik

Mapnik is often used to render OpenStreetMap (OSM) data.   The map style (line colours and sizes, icons etc.) are defined by a style file.  There is a very detailed one provided with OpenStreetMap's mapnik tools.   Unfortunately that level of detail means that the style definition is very complicated and it is hard to follow how it works.
A tool called carto is available which is a pre-processor that will take a simpler format of style file, and convert it into the mapnik file format.   I have been experimenting with trying to render OSM data using styles written for carto.   I had been hoping to use a nice graphical editor with map preview capability called tilemill, but tilemill does not work with postgresql datasources, which are necessary for OSM rendering.   Instead, I installed tilemill and used the version of carto that is included with it, but did not use the tilemill editor.

Carto Layer Definitions
Rendering data with carto needs you to do two things - define the data you want to plot on your map ('Layers'), and define how you want the data displayed ('Styles').

The datasource definitions go in a .mml file that looks something like this:

{
"_center":{"lat":36.870832154494,"lon":-113.79638671427,"zoom":5},
"_format":"png",
"srs":"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs",
"Stylesheet":["style2.mss",
"areas2.mss",
"roads2.mss",
"labels2.mss",
"natural2.mss",
"contours2.mss",
"POIs2.mss"],

"Layer":[
  {"id":"coastline",
   "name":"coastline",
   "srs":"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs +over",
   "class":"",
   "geometry":"polygon",
   "Datasource":{"file":"/home/graham/OSM/data/mapdata/world_boundaries/processed_p.shp","type":"shape"}},

 {"id":"landuse",
  "name":"landuse",
  "srs":"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs",
  "class":"",
  "geometry":"area",
  "Datasource": {
               "type":"postgis",
      "dbname":"kefalonia",
      "user":"www",
      "password":"1234",
      "host":"localhost",
      "port":"",
      "table":"(select way,landuse,name,\"name:en\" from planet_osm_polygon where landuse is not null) as landuse"
               }
  }
]
}
The first few lines define the projection of the output map, and the stylesheets that are to be used to define how to render the data.   The bulk of the file is layer definitions.   In this example two layers are defined.  One is a shapefile containing the coastlines (the same one that is used by the normal OSM style).   The second layer extracts all areas tagged with 'landuse=xxx'.

We have not told mapnik how to plot the data though - this is done in the style files.  The ones relevant to this example are "style2.mss" and "areas2.mss".  Style2.mss contains:

@land: #e0e0c0;
@water: #C0E0F8;
@waterline: #8CE;
Map {
  background-color:@water;
}
#coastline::outline {
  line-color:@waterline;
  line-width:1.6;
}
#coastline::fill {
  polygon-fill:@land;
  polygon-gamma:0.75;
}
Here the things starting '@' are variables which allow you to define colours etc.  at the top of the file, then use them several times throughout it, making future maintenance easier.   In this example we define the background colour for the map, fill it in blue to represent water.   We then draw a line around the costline, and fill in the land with a separate colour.

The areas2.mss style is slightly more complicated:
#landuse {
   [landuse="residential"]
   {
      polygon-fill: #b0b0b0;
   }
   [landuse="industrial"]
   {
      polygon-fill: #a0a0a0;
   }
   [landuse="forest"]
   {
      polygon-fill: #a0d0a0;
   }
}
In this example the [] expressions are filters, which allows us to define different fill colours depending on the landuse tag.

These are just extracts - the actual styles I am using are getting progressively more and more complicated.   You can see the files, and a modified version of the generate_image.py script provided by OSM, which takes a carto .mml file as input in my svn repository (soon to be copied to github..)

Using these styles, I have updated my kefalonia map to give this:
and this:




These styles are nowhere near as clever as the standard OSM ones.  In particular I have not tried to devine different styles fo rdifferent zoom levels  instead I have two sets of stylesheets for two different zoom levels - I think in the end I will have there - one for a 'country level', another for a 'town level', and a third for higher zoom levels.

There are also a few issues - the line styles do not look as nice as the OSM ones - I do not know why...and there is a problem with the road names where sometimes other roads crossing over each other obliterate the labels.   THe reason is that I draw the road and the label at the same time - it will probably look better if I do the labels after all roads have been drawn.   Will hav eto work out how to do that!



Friday, 29 April 2011

Installation of Carto Mapnik Style File Builder on Ubuntu

I find mapnik style files a bit clumsy to edit - lots of repetition that makes them hard to follow.
There are (at least) two utilities available that may make style file generation simpler.  These are Cascadenik and Carto.
It appears that Carto is being more actively developed at the moment, so I thought I would look at that first. Carto also reports to be much faster than Cascadenink.
The problem is that Carto is new-fangled and uses a javascript based language called node.js.   Despite my dislike of javascript, I thought I would persevere.  This is how I got it working on my Ubuntu 10.10 system:

  • Downloaded node.js version 0.4.7 from http://nodejs.org, and extracted it into /usr/local/node-v0.4.7.  Built with ./configure; make; make install.
  • Installed the node package manager npm using: curl http://npmjs.org/install.sh | sh
  • Installed carto dependencies:
    • npm install get     [used to be node-get, but the module has changed name]
    • npm install step
    • npm install srs
    • npm install underscore
    • npm install zipfile (actually did this twice because one of the document build actions failed on the first attempt...).
  • Downloaded carto using:  git clone https://github.com/mapbox/carto.git
  • No compilation necessary (it is javascript).  Executing cd carto; ./bin/carto gave no nasty errors, just "no input files", which looks promising.
I just need to work out how to use it now.

I have had a quick look at TileMill, which is a web based editor for carto stylesheets - it is very impressive - you can change the stylesheet and preview the map in real time.   The only problem that I have found with tilemill is that it does not seem to work with a postgresql database as the data source, which is where my OSM data is stored.  But at least I should get the idea about the structure of the files using that tool.

Monday, 25 April 2011

Kefalonia Map

We are going to Kefalonia on our holidays this year, and I usually like to do a bit of OSM mapping when I go somewhere new, and may do some 'armchair mapping' before I go to get a head start, so I thought I would have a look at how well mapped it is.
The answer is not very - there are the main roads, and a few minor roads and footpaths, but not much else - this is a shame because I like to know where things like supermarkets and banks are.  Unfortunately there is not a lot of information available for remote mapping - very few GPS traces, and Bing Imagery does not cover the area I am interested in.
So instead I decided to make myself a map of the island showing what is there (in OSM anyway).  Because there is not a lot of detail, I want to have contours so I can tell where the mountains are, and also highlight what points of interest there are at lower zoom levels than the standard OSM style.   These are my notes on how I produced the map, so I can remember next time I need to do it.


  • The map bounding box was found by looking at the (lon,lat)  readouts on http://www.informationfreeway.org to check the bottom left and top right of the island.  They are (20.33, 38.03) and (20.82,38.50).
  • I downloaded the OSM data from the mapquest XAPI server using: 
wget http://open.mapquestapi.com/xapi/api/0.6/map?bbox=20.33,38.03,20.82,38.50 -O kefalonia.osm

  • Imported the data into postgresql database using:
osm2pgsql -s -S default.style -d kefalonia -m kefalonia.osm

  • Downloaded the SRTM elevation data covering the island from http://dds.cr.usgs.gov/srtm/version2_1/SRTM3/Eurasia/ - only needed one file (N38E020.hgt.zip), because it is a small island.
  • Generated the contours and imported them into my postgresql kefalonia database as described in http://wiki.openstreetmap.org/wiki/Contours
  • Modified the standard osm mapnik style file as described in http://wiki.openstreetmap.org/wiki/Contours, using the 'PostGIS' method.
  • Generated the map image using the generate_image.py file from the OSM mapnik archive.  I initially had some trouble with no roads appearing, but solved this by re-compiling osm2pgsql from the latest sources - I do not know what the problem was.
  • Having done that, I get this map image:



Kefalonia Map - Version 1 (25 April 2011)
Next I wanted to add a 1km grid to the map to make it easier to judge scale..."are we nearly there yet?" etc.
I did this by adopting the generate_graticule script from mapnik-utils to produce a grid on the google spherical mercator projection (=SRS 900913).  I must admit to not really knowing how this works, but my updated version (generate_grid.py) is in my SVN repository.   I added this to the map by creating an extra xml include file to define the grid layer and style (inc/grid.xml.inc), adding this to layers.xml.inc, and finally defining the layer in osm.xml.

The result (Version 2) is shown below:
Kefalonia Map Version 2 (26 April 2011)
I created another include file for holiday based points of interests (holiday_pois.xml.inc), added it to layers.xml.inc and again added the actual layer definition to osm.xml.
This gave the following map:
Kefalonia Map Version 3 (26 April 2011)

The final thing I needed was the English spelling adding to the Greek text labels.   I did this by adding name:en to the default.style file used by osm2pgsql and re-importing the OSM data into the database.
The challenge was updating the mapnik style file to use the name:en column - the OSM style files are very complicated with lots of SQL SELECT statements to extract the data out of the database.  I was tempted to do a global replace of 'name' with 'name:en'...but 'name' appears all over the place.
I decided the main thing I wanted with both writing styles were place names and I found the code for them in inc/layer-placenames.xml.inc.
I modified the SELECT statement from a simple 'name' to ,'"name" || ' (' || "name:en" || ')' as name'.  This gives me the greek spelling followed by the english spelling in brackets using the postgresql '||' string concatenation operator.  The result is here:
Kefalonia Map Version 4 (27 April 2011)
I think that is about the finished product - I will have to try printing it to see how it looks, then may need to adjust the image size to suit printing....then do some mapping to add some more POIs - Sacla in the south east of the island should be a lot better by the middle of June....

Thursday, 24 February 2011

Easier Map Creation with OpenStreetMap Data

I have been giving some thought to making the process of creating maps form OpenStreetMap data easier.  The problem is that to use the mapnik map renderer, you need to install quite a lot of tools and set different configuration files before you can even start to create a map.
This means you have to be pretty keen to persevere enough to get to an end result.
I am thinking of creating a service to allow you to bypass the tool installing bits, and concentrate on the setting up of the map configuration, so you can get to a result quicker - see http://wiki.openstreetmap.org/wiki/User:Grahamjones#Speciality%20Maps.

Quite a few of the responses that I got to that proposal were about the lack of good documentation to get people started on the process.  I have had a go at addressing this by putting together a simple overview presentation to go through the main concepts and tools that you need to generate a map using mapnik.   The presentation is on slideshare.net, and should be visible below:

Friday, 21 January 2011

Mapnik Map Rendering

Someone asked a question on the osm-gb mailing list about viewing coverage of waterways - canals and navigable rivers.
We don't seem to have one, so I created one on my http://maps.webhop.net web site.
The trouble with that site is that although it is running on a nice powerful computer (my old laptop), it is behind my domestic broadband service from Virgin Media.   Although this service has a nice fast download speed, the upload speed is very poor ~900 kbps compared to 9600 kbps download.   This makes the web site very slow from the outside world.

I have a little virtual server provided by CloudNext - it is nowhere near as powerful as my own server, and has much less disk space, but at least it has a fast internet connection.

I loaded a british isles extract of OpenStreetMap data into the database - it took a very long time - maybe getting on for 12 hours (not sure when it finished!) - my server takes about 2 hours.   Performance rendering maps was not too bad though - rendering down to zoom level 14 took about 2 hours, which is respectable.

Just need to get the database updating to keep it up to date, and re-generate changed tiles now....
You can see the difference at http://maps.webhop.net/canals (my home server) compared to http://maps2.webhop.net/canals (the virtual server)

Sunday, 3 October 2010

OS Vector Map District with PostGIS - Take 3

To recap:

  • The entire UK's VectorMapDistrict dataset has been loaded into my postgresql/postgis database using my vmd2pgsql script, which is based around shp2pgsql.
  • I created some stylesheets for mapnik rendering of the data based on the mapnik tutorial, but they came out with a transparent background and black lines and text, which is not what I wanted.
The rendering problem turned out to be quite easy - it is just that the mapnik tutorial is based on Mapnik 0.7, not mapnik2.  To make it work with mapnik2 you need to:
  1. Replace the bgcolor parameter of the map element with background-color.
  2. Remove all of the CSSParameter business in the style definitions with simple name="xyz" constructs.
It is a shame that mapnik did not complain about these issues, even in debug mode, but never mind!
Adding the different linear features works ok - you see something of an improvement from the black and white version to something resembling a map:
So now all I need to do is add the areas (water, woodland towns etc.) to make it look extra pretty, and sort out what to plot at different zoom levels so it is reasonable.

Here I hit a problem.   When I tried to add the settlement_area or naturalfeature_area items, mapnik crashed with an "invalid geometry" error, after taking quite a long time thinking about it!   It is something to do with polygons not being closed properly.   I suspect it is rounding errors, but am not too sure.  One possibility is that I should have used the shp2pgsql option to just use integers, which would have avoided rounding, or I could try to fix the database.  As it took 9 hours to import, and I don't know if integers will work, I'll try to fix it.

With much internet searching I discovered that you can check the validity of each geometric feature with the postgis st_isvalid() function.  Running a simple select statement on the database like:
select gid from naturalfeature_area where not st_isvalid(the_geom);
takes a long time (about an hour I think) and gives me a list of invalid geometries, after pages and pages of warnings about things crossing over themselves.
It seems that one trick that people use to force gemetries to be valid is to use the st_buffer() command with the buffer radius set to zero.   I checked it worked by doing:
select st_isvalid(st_buffer(the_geom,0.0)) from naturalfeature_area where gid=2342149;
(2342149 was the first entry in my list of invalid geometries) - Success - it returns 't' for true meaning the st_buffer trick fixes it.
Now to update the database.  To correct the error I had to do:
update naturalfeature_area set the_geom=st_multi(st_buffer(the_geom,0.0)) where gid=2342149;
Note that I do not really know what the st_multi thing does, but I got errors about geometry constraint violations without it - I think that st_buffer returns the simplest type of geometry it can, and st_multi forces it to be a multipolygon, but I could be wrong!.

Now all I need to do is remember enough about subqueries to write a bit of SQL that does the correction for every invalid geometry - back to that well known search engine....

Well, I have set it going using the following to try to repair the geometries:
update naturalfeature_area set the_geom=st_multi(st_buffer(the_geom,0.0)) where gid in (select gid from naturalfeature_area where not st_isvalid(the_geom));
I think I'll leave it for a few hours....

OS Vector Map District with PostGIS - Take 3

To recap:

  • The entire UK's VectorMapDistrict dataset has been loaded into my postgresql/postgis database using my vmd2pgsql script, which is based around shp2pgsql.
  • I created some stylesheets for mapnik rendering of the data based on the mapnik tutorial, but they came out with a transparent background and black lines and text, which is not what I wanted.
The rendering problem turned out to be quite easy - it is just that the mapnik tutorial is based on Mapnik 0.7, not mapnik2.  To make it work with mapnik2 you need to:
  1. Replace the bgcolor parameter of the map element with background-color.
  2. Remove all of the CSSParameter business in the style definitions with simple name="xyz" constructs.
It is a shame that mapnik did not complain about these issues, even in debug mode, but never mind!
Adding the different linear features works ok - you see something of an improvement from the black and white version to something resembling a map:
So now all I need to do is add the areas (water, woodland towns etc.) to make it look extra pretty, and sort out what to plot at different zoom levels so it is reasonable.

Here I hit a problem.   When I tried to add the settlement_area or naturalfeature_area items, mapnik crashed with an "invalid geometry" error, after taking quite a long time thinking about it!   It is something to do with polygons not being closed properly.   I suspect it is rounding errors, but am not too sure.  One possibility is that I should have used the shp2pgsql option to just use integers, which would have avoided rounding, or I could try to fix the database.  As it took 9 hours to import, and I don't know if integers will work, I'll try to fix it.

With much internet searching I discovered that you can check the validity of each geometric feature with the postgis st_isvalid() function.  Running a simple select statement on the database like:
select gid from naturalfeature_area where not st_isvalid(the_geom);
takes a long time (about an hour I think) and gives me a list of invalid geometries, after pages and pages of warnings about things crossing over themselves.
It seems that one trick that people use to force gemetries to be valid is to use the st_buffer() command with the buffer radius set to zero.   I checked it worked by doing:
select st_isvalid(st_buffer(the_geom,0.0)) from naturalfeature_area where gid=2342149;
(2342149 was the first entry in my list of invalid geometries) - Success - it returns 't' for true meaning the st_buffer trick fixes it.
Now to update the database.  To correct the error I had to do:
update naturalfeature_area set the_geom=st_multi(st_buffer(the_geom,0.0)) where gid=2342149;
Note that I do not really know what the st_multi thing does, but I got errors about geometry constraint violations without it - I think that st_buffer returns the simplest type of geometry it can, and st_multi forces it to be a multipolygon, but I could be wrong!.

Now all I need to do is remember enough about subqueries to write a bit of SQL that does the correction for every invalid geometry - back to that well known search engine....

Well, I have set it going using the following to try to repair the geometries:
update naturalfeature_area set the_geom=st_multi(st_buffer(the_geom,0.0)) where gid in (select gid from naturalfeature_area where not st_isvalid(the_geom));
I think I'll leave it for a few hours....

Saturday, 2 October 2010

Using VectorMapDistrict with PostGIS

Well, vmd2pgsql took about 9 hours to import the entire UK into my postgresql database...No too bad.
Now I need to do something with it, because the mapnik stylesheets that I set up to use the shapefiles will not work - need to change it to use the postgresql database instead.
The things that need changing are:

  1. Add the layers and datasources in XML (no need to do it in python now I don't have hundreds of separate datasources).
  2. Convert the styles to use lowercase letters for the fields ('featcode' rather than 'FEATCODE') - postgresql seems to be case sensitive, and they have gone into the database lower case, but were upper case in the shapefiles.
Sounds easy,  but I decided I don't want it to look like the OSM stylesheet, which is a bit garbled - I want a nice structure to make it easy to maintain.  I could have used XML entities, but that seems a bit crude - define an entity, then 'use' it to actually 'call' it.   Includes seem much more suitable....But to get includes working I need mapnik2.  I have put a basic structure at code.google.com/p/ntmisc/vmdmap, but still have a few issues:
  • I have had to define the database parameters manually because entities do not seem to be working in the include files, which is no good!
  • The output is transparent background with black lines (see picture below), which is not what I asked for - not sure if this is a problem with the style file, or my build of mpanik2 - I'll have to run some tests on mapnik2 to make sure it works right.
  • But it's too late to fix it now - job for tomorrow!

Using VectorMapDistrict with PostGIS

Well, vmd2pgsql took about 9 hours to import the entire UK into my postgresql database...No too bad.
Now I need to do something with it, because the mapnik stylesheets that I set up to use the shapefiles will not work - need to change it to use the postgresql database instead.
The things that need changing are:

  1. Add the layers and datasources in XML (no need to do it in python now I don't have hundreds of separate datasources).
  2. Convert the styles to use lowercase letters for the fields ('featcode' rather than 'FEATCODE') - postgresql seems to be case sensitive, and they have gone into the database lower case, but were upper case in the shapefiles.
Sounds easy,  but I decided I don't want it to look like the OSM stylesheet, which is a bit garbled - I want a nice structure to make it easy to maintain.  I could have used XML entities, but that seems a bit crude - define an entity, then 'use' it to actually 'call' it.   Includes seem much more suitable....But to get includes working I need mapnik2.  I have put a basic structure at code.google.com/p/ntmisc/vmdmap, but still have a few issues:
  • I have had to define the database parameters manually because entities do not seem to be working in the include files, which is no good!
  • The output is transparent background with black lines (see picture below), which is not what I asked for - not sure if this is a problem with the style file, or my build of mpanik2 - I'll have to run some tests on mapnik2 to make sure it works right.
  • But it's too late to fix it now - job for tomorrow!

Friday, 1 October 2010

More Rendering of VectorMapDistrict Data

The nice people from Ordnance Survey have sent me a complete set of VectorMapDistrict data (which is on 6 DVDs!).   Surprisingly they didn't even charge me for the DVDs or postage.
Now I have all that data I thought I'd better do something with it!

First step was to get it onto a nice fast disk, so I copied it onto the hard disk of my server...which took a while...

Then I tried to use my vmdmap.py program to render it all, but mapnik bombed out with an error as it was adding the various shapefile layers.  I suspect that this is because every single shapefile is in its own layer, as it is a completely separate datasource, and I think I either ran out of memory or hit some mapnik internal limit.   This means I can't use vmdmap.py to render the whole country, which is a bit of a shame.

To get around this I think I need to merge them into a single datasource.  I don't know enough about manipulating shapefiles to do this, so instead am making use of shp2pgsql which allows you to import a shapefile into a postgresql database.   I have written another program, based on vmdmap.py called vmd2pgsql which will scan through a directory tree looking for the various shapefiles in the vectormap district dataset, and importing them into postgresql.   This gives a much lower number of tables - just one per shapefile name, but each one will have a lot of data.

It is importing now, so will see how long the import takes, then how well it renders.  I suppose it should render ok because I have the whole UK OSM dataset in a single database and that works, but we'll see over the weekend if it ever finishes!  The code is at my google code site.

More Rendering of VectorMapDistrict Data

The nice people from Ordnance Survey have sent me a complete set of VectorMapDistrict data (which is on 6 DVDs!).   Surprisingly they didn't even charge me for the DVDs or postage.
Now I have all that data I thought I'd better do something with it!

First step was to get it onto a nice fast disk, so I copied it onto the hard disk of my server...which took a while...

Then I tried to use my vmdmap.py program to render it all, but mapnik bombed out with an error as it was adding the various shapefile layers.  I suspect that this is because every single shapefile is in its own layer, as it is a completely separate datasource, and I think I either ran out of memory or hit some mapnik internal limit.   This means I can't use vmdmap.py to render the whole country, which is a bit of a shame.

To get around this I think I need to merge them into a single datasource.  I don't know enough about manipulating shapefiles to do this, so instead am making use of shp2pgsql which allows you to import a shapefile into a postgresql database.   I have written another program, based on vmdmap.py called vmd2pgsql which will scan through a directory tree looking for the various shapefiles in the vectormap district dataset, and importing them into postgresql.   This gives a much lower number of tables - just one per shapefile name, but each one will have a lot of data.

It is importing now, so will see how long the import takes, then how well it renders.  I suppose it should render ok because I have the whole UK OSM dataset in a single database and that works, but we'll see over the weekend if it ever finishes!  The code is at my google code site.

Friday, 3 September 2010

Mapnik and OS_OpenData

I decided to compare the quality of OpenStreetMap mapping to that which has been released by Ordnance Survey OpenData.  
I started with VectorMapDistrict, which is a dataset provided as ESRI Shapefiles.   It is provided as a large number of shapefiles, so setting up a mapnik stylesheet manually would have been a pain.  Instead I separated the styles into an XML file, but added the layers using a python program which scans down the directory tree to add the various shapefiles to the map.  The python code is vmdmap.py and the stylesheet is styles.xml.

Then I tried Meridian2.  This is much simpler - just one shapefile for each sort of feature (A-Road, river etc.).  I kept the same structure with the styles defined in an XML file, and the layers in python, but it could have all been done in a single XML file this time.  The python code is md2map.py and the stylesheet is styles_md2.xml.

You can see the results below.

The most notable things are that Meridian2 is much simpler geometry, but it includes more road names than Vector Map District.  The OpenStreetMap rendering is fancier because I used the standard OSM style, rather than the home made ones I used for the OS Data.   I do like the rocks that appear in the VectorMap District rendering though - I will have to import it into OSM!.

VectorMapDistrict
Meridian2
OpenStreetMap


Mapnik and OS_OpenData

I decided to compare the quality of OpenStreetMap mapping to that which has been released by Ordnance Survey OpenData.  
I started with VectorMapDistrict, which is a dataset provided as ESRI Shapefiles.   It is provided as a large number of shapefiles, so setting up a mapnik stylesheet manually would have been a pain.  Instead I separated the styles into an XML file, but added the layers using a python program which scans down the directory tree to add the various shapefiles to the map.  The python code is vmdmap.py and the stylesheet is styles.xml.

Then I tried Meridian2.  This is much simpler - just one shapefile for each sort of feature (A-Road, river etc.).  I kept the same structure with the styles defined in an XML file, and the layers in python, but it could have all been done in a single XML file this time.  The python code is md2map.py and the stylesheet is styles_md2.xml.

You can see the results below.

The most notable things are that Meridian2 is much simpler geometry, but it includes more road names than Vector Map District.  The OpenStreetMap rendering is fancier because I used the standard OSM style, rather than the home made ones I used for the OS Data.   I do like the rocks that appear in the VectorMap District rendering though - I will have to import it into OSM!.

VectorMapDistrict
Meridian2
OpenStreetMap