Posts tagged ‘Mapnik’

February 6, 2012

Rendering SQL Server spatial data with Mapnik (Part 2 of n, where n is large)

Last year, I wrote what was intended to be the first of a series of posts about Mapnik – a software toolkit for generating beautiful maps from various sets of spatial data. My intention had been to describe how to render spatial data from SQL Server as styled raster tile layers on Bing Maps, but the series got cut short rather prematurely when I discovered that it didn’t appear to be possible to connect Mapnik to SQL Server (even though it was an OGR-supported format).

Unfortunately, as is often the case with OS software, it seems that almost all Mapnik developers use PostGIS as a backend spatial database, and I failed to find anybody with any experience of SQL Server on either the Mapnik developers mailing list or on StackExchange (rather amusingly, the top-rated answer given to me on StackExchange gives, as its reference source, my own blog post where I explicitly state that the suggested approach doesn’t work!).

image

Since, at the time, I needed a tool to render SQL geometry data there and then, I left Mapnik alone and developed a solution using MapServer instead.

Now, MapServer is a great product: It’s a venerable and highly-respected product in the world of open source spatial software, developed by the University of Minnesota on behalf of NASA, and first released over 16 years ago (to put that in context: MapServer was released at around the same time as HTML 3.2 – long before CSS, AJAX, or Google Maps were heard of). And it’s still going strong today. However, I find that the archaic MapServer architecture and idiosyncracies of its syntax give away its age slightly.

Mapnik, by contrast, is freshly-designed, has a modern XML-style syntax, supports groovy things like node.js and Ruby, and generally feels like it’s not carrying so much baggage. If only it supported SQL Server….

6 months later, and the Release Candidate for Mapnik 2.0 is  now available to download, which claims to support SQL Server, so I thought I’d give it another try. Having just set it up and rendered some quick OS OpenData, I can confirm that it works. Hurray!

image

SSMS Spatial Results Tab Rendering of SQL Server data

image

Mapnik Rendering of the same SQL Server data

Since it seems that I’m one of only few people trying to use Mapnik and SQL Server together (and one of even less writing about it), I’ve started to document some tips in a page here – I’ll add to this page as I go along.

(On a separate note, I now have a whole different problem, because a recent change in the Bing Maps Terms of Use prevents you from adding your own custom road tile layers onto the Bing Map control. So, any tiles of OpenStreetMap or Ordnance Survey road data you create with Mapnik can’t be used with Bing Maps. Fortunately, there’s a workaround for that, but that’s for another post….)

July 18, 2011

Rendering Text Labels with Custom Fonts in Mapnik

The default font family used for rendering text labels on maps created by Mapnik (and the one shipped with it) is Deja Vu. Deja Vu Sans Book is a pretty nice font, and can be seen, for example, in all the labels used on Open Street Map:

image

So what if you want to render text onto a custom tile overlay using a different font?

  • Perhaps you’d like to create a custom tile layer using image labels to match Google Maps?
  • Or how about going for a Bing Maps feel with image labels?

To do so, first you need to register the location of the directory containing the fonts you want to use. For example, to make all the installed Windows fonts available to Mapnik, add the following to the top of your python render script:

mapnik.register_fonts('c:/windows/fonts/')

Mapnik needs to reference these fonts by their font name (not by filename, for example); To find out the correct name to use for each font, once you’ve registered your custom fonts directory you can call the following:

for face in mapnik.FontEngine.face_names(): print face

On a fairly vanilla installation of Window 7, this gave me a list of available fonts as follows:

  • Aharoni Bold
  • Andalus Regular
  • Andy Bold
  • Angsana New Bold
  • Angsana New Bold Italic
  • Angsana New Italic
  • Angsana New Regular
  • AngsanaUPC Bold
  • AngsanaUPC Bold Italic
  • AngsanaUPC Italic
  • AngsanaUPC Regular
  • Aparajita Bold
  • Aparajita Bold Italic
  • Aparajita Italic
  • Aparajita Regular
  • Arabic Typesetting Regular
  • Arial Black
  • Arial Bold
  • Arial Bold Italic
  • Arial Italic
  • Arial Regular
  • Browallia New Bold
  • Browallia New Bold Italic
  • Browallia New Italic
  • Browallia New Regular
  • BrowalliaUPC Bold
  • BrowalliaUPC Bold Italic
  • BrowalliaUPC Italic
  • BrowalliaUPC Regular
  • Buxton Sketch Regular
  • Calibri Bold
  • Calibri Bold Italic
  • Calibri Italic
  • Calibri Regular
  • Candara Bold
  • Candara Bold Italic
  • Candara Italic
  • Candara Regular
  • Comic Sans MS Bold
  • Comic Sans MS Regular
  • Consolas Bold
  • Consolas Bold Italic
  • Consolas Italic
  • Consolas Regular
  • Constantia Bold
  • Constantia Bold Italic
  • Constantia Italic
  • Constantia Regular
  • Corbel Bold
  • Corbel Bold Italic
  • Corbel Italic
  • Corbel Regular
  • Cordia New Bold
  • Cordia New Bold Italic
  • Cordia New Italic
  • Cordia New Regular
  • CordiaUPC Bold
  • CordiaUPC Bold Italic
  • CordiaUPC Italic
  • CordiaUPC Regular
  • Courier New Bold
  • Courier New Bold Italic
  • Courier New Italic
  • Courier New Regular
  • DFKai-SB Regular
  • DRMS T1 Regular
  • DaunPenh Regular
  • David Bold
  • David Regular
  • DengXian Bold
  • DengXian Regular
  • DilleniaUPC Bold
  • DilleniaUPC Bold Italic
  • DilleniaUPC Italic
  • DilleniaUPC Regular
  • DokChampa Regular
  • Ebrima Bold
  • Ebrima Regular
  • Estrangelo Edessa Regular
  • EucrosiaUPC Bold
  • EucrosiaUPC Bold Italic
  • EucrosiaUPC Italic
  • EucrosiaUPC Regular
  • Euphemia Regular
  • FangSong Regular
  • FrankRuehl Regular
  • Franklin Gothic Medium Italic
  • Franklin Gothic Medium Regular
  • FreesiaUPC Bold
  • FreesiaUPC Bold Italic
  • FreesiaUPC Italic
  • FreesiaUPC Regular
  • Gabriola Regular
  • Gautami Bold
  • Gautami Regular
  • Georgia Bold
  • Georgia Bold Italic
  • Georgia Italic
  • Georgia Regular
  • Gisha Bold
  • Gisha Regular
  • Impact Regular
  • IrisUPC Bold
  • IrisUPC Bold Italic
  • IrisUPC Italic
  • IrisUPC Regular
  • Iskoola Pota Bold
  • Iskoola Pota Regular
  • JasmineUPC Bold
  • JasmineUPC Bold Italic
  • JasmineUPC Italic
  • JasmineUPC Regular
  • Jing Jing Regular
  • KaiTi Regular
  • Kalinga Bold
  • Kalinga Regular
  • Kartika Bold
  • Kartika Regular
  • Khmer UI Bold
  • Khmer UI Regular
  • KodchiangUPC Bold
  • KodchiangUPC Bold Italic
  • KodchiangUPC Italic
  • KodchiangUPC Regular
  • Kokila Bold
  • Kokila Bold Italic
  • Kokila Italic
  • Kokila Regular
  • Kootenay Regular
  • Lao UI Bold
  • Lao UI Regular
  • Latha Bold
  • Latha Regular
  • Leelawadee Bold
  • Leelawadee Regular
  • Levenim MT Bold
  • Levenim MT Regular
  • LilyUPC Bold
  • LilyUPC Bold Italic
  • LilyUPC Italic
  • LilyUPC Regular
  • Lindsey Regular
  • Lucida Console Regular
  • Lucida Sans Unicode Regular
  • MV Boli Regular
  • Malgun Gothic Bold
  • Malgun Gothic Regular
  • Mangal Bold
  • Mangal Regular
  • Marlett Regular
  • Microsoft Himalaya Regular
  • Microsoft JhengHei Bold
  • Microsoft JhengHei Regular
  • Microsoft MHei Bold
  • Microsoft MHei Regular
  • Microsoft NeoGothic Bold
  • Microsoft NeoGothic Regular
  • Microsoft New Tai Lue Bold
  • Microsoft New Tai Lue Regular
  • Microsoft PhagsPa Bold
  • Microsoft PhagsPa Regular
  • Microsoft Sans Serif Regular
  • Microsoft Tai Le Bold
  • Microsoft Tai Le Regular
  • Microsoft Uighur Regular
  • Microsoft YaHei Bold
  • Microsoft YaHei Regular
  • Microsoft Yi Baiti Regular
  • Miramonte Bold
  • Miramonte Regular
  • Miriam Fixed Regular
  • Miriam Regular
  • Moire Bold
  • Moire ExtraBold
  • Moire Light
  • Moire Regular
  • Mongolian Baiti Regular
  • MoolBoran Regular
  • Motorwerk Regular
  • Narkisim Regular
  • Nina Bold
  • Nina Regular
  • Nyala Regular
  • Palatino Linotype Bold
  • Palatino Linotype Bold Italic
  • Palatino Linotype Italic
  • Palatino Linotype Regular
  • Pericles Light
  • Pericles Regular
  • Pescadero Bold
  • Pescadero Regular
  • Plantagenet Cherokee Regular
  • Raavi Bold
  • Raavi Regular
  • Rod Regular
  • Sakkal Majalla Bold
  • Sakkal Majalla Regular
  • Segoe Condensed Bold
  • Segoe Condensed Regular
  • Segoe Marker Regular
  • Segoe Print Bold
  • Segoe Print Regular
  • Segoe Script Bold
  • Segoe Script Regular
  • Segoe UI Bold
  • Segoe UI Bold Italic
  • Segoe UI Italic
  • Segoe UI Light
  • Segoe UI Regular
  • Segoe UI Semibold
  • Segoe UI Symbol Regular
  • Segoe WP Black
  • Segoe WP Bold
  • Segoe WP Light
  • Segoe WP Regular
  • Segoe WP SemiLight
  • Segoe WP Semibold
  • Shonar Bangla Bold
  • Shonar Bangla Regular
  • Shruti Bold
  • Shruti Regular
  • SimHei Regular
  • SimSun-ExtB Regular
  • Simplified Arabic Bold
  • Simplified Arabic Fixed Regular
  • Simplified Arabic Regular
  • SketchFlow Print Regular
  • Sylfaen Regular
  • Symbol Regular
  • Tahoma Bold
  • Tahoma Regular
  • Times New Roman Bold
  • Times New Roman Bold Italic
  • Times New Roman Italic
  • Times New Roman Regular
  • Traditional Arabic Bold
  • Traditional Arabic Regular
  • Transport Medium
  • Trebuchet MS Bold
  • Trebuchet MS Bold Italic
  • Trebuchet MS Italic
  • Trebuchet MS Regular
  • Tunga Bold
  • Tunga Regular
  • Utsaah Bold
  • Utsaah Bold Italic
  • Utsaah Italic
  • Utsaah Regular
  • Vani Bold
  • Vani Regular
  • Verdana Bold
  • Verdana Bold Italic
  • Verdana Italic
  • Verdana Regular
  • Vijaya Bold
  • Vijaya Regular
  • Vrinda Bold
  • Vrinda Regular
  • Webdings Regular
  • Wingdings Regular
  • Yu Gothic Bold
  • Yu Gothic Regular

To use one of these fonts, set the TextSymbolizer face_name attribute in the style applied to your layer to the name of whatever font you want.

For example, here’s a style with default Deja Vu Sans Book text labels:

<Style name="text">
  <Rule>
    <TextSymbolizer
      name="NAME"
      placement="point"
      fill="black"
      size="18"
      face_name="Deja Vu Sans Book"
      min_distance="10"
      avoid_edges="false"
      allow_overlap="true"
      spacing="5"
      wrap_width="20"
      halo_radius="1"
      halo_fill="#DFDBE3"
    /> 
  </Rule>
</Style>

and this is the map it creates:

image

And here’s the same map rendered with, oh I don’t know, say Comic Sans MS Regular style (don’t ever, ever do this! Maybe unless you’re creating a map of how to get to a children’s party…)

<Style name="text">
  <Rule>
    <TextSymbolizer
      name="NAME"
      placement="point"
      fill="black"
      size="18"
      face_name="Comic Sans MS Regular"
      min_distance="10"
      avoid_edges="false"
      allow_overlap="true"
      spacing="5"
      wrap_width="20"
      halo_radius="1"
      halo_fill="#DFDBE3"
    /> 
  </Rule>
</Style>

which leads to this:

image

I’m not saying it’s an improvement! But now you know how to do it…

Tags: ,
June 16, 2011

Tile Rendering with Mapnik (Part 1 of n, where n is large)

In my last blog post, I explained a little about the process by which you can overlay raster data on Bing Maps, by geo-referencing the source data (if necessary), projecting into the appropriate spherical Mercator projection, then cutting the resulting image into 256px x 256px tiles named according to the quadkey tile numbering system.

The application I used in the last example to do this was Microsoft Mapcruncher. Mapcruncher has got a lot of benefits:

  • It’s free
  • It’s a windows application with no special dependencies and easy to install
  • It’s got a nice GUI that’s very easy to use
  • It will perform geo-referencing/warping/tile-cutting for you as part of a single process

Mapcruncher is great if you have a relatively small raster image that you want to integrate into Bing Maps / Google Maps as part of a one-off process. However, there are many occasions when you might need a little more than that. As part of a current project, for example, I need to create a tileset that covers an area of approximately 60km x 50km (not that small), based on data held in SQL Server 2008 (not raster), that will be updated approximately every month (not one-off).

So I set out to evaluate alternatives, and the first I considered was mapnik.

Installing Mapnik

Mapnik is an open-source mapping toolkit. It’s what openstreetmap uses to render the tiles used in their base map imagery. They’ve got over 220Gb of XML data in the planet.osm file, covering the whole world, with thousands of updates every day, so if mapnik can render that I’m pretty certain it should be able to cope with my modest requirements.

Mapnik tiles in Open Street Map

Installing and configuring mapnik, unfortunately, turned out to be quite a challenge, and has taken me a significant amount of time to get a working installation. In fact, had I realised quite how many steps would be involved, I’d probably have taken more care to document them carefully. As it is, I’m going to try to note down in this post what I did while they’re still relatively fresh in my mind.

What about using pre-compiled Windows binaries?

Mapnik, like many open source applications, is primarily targeted at a UNIX stack. That means that a large part of the documentation will refer to commands like sudo apt-get, which will look fairly alien to many Windows users. There’s also a lot of dependencies on other packages – python, libboost, libpng, etc. which you may not be familiar with.

Now, fortunately, some kind people have taken the time to prepare pre-compiled Windows binaries of these various tools, and even packaged them together in convenient download format.

For example, the OSGeo4W package contains windows binary executables for Mapnik, along with the GDAL library (used for importing, converting of various spatial data formats), QGIS (open source desktop GIS application), and many other useful open source spatial goodies. The problem is that, with trying to keep track of all those separate dependencies, the package itself can become out-of-date quite quickly. The latest build of OSGeo4W, for example, is still based on python 2.5.2-1. The current build of the 2.x branch of python is 2.7.1, and even that represents the end-of-life release for the 2.x branch. The latest version of python is actually 3.2. I didn’t really want to start a project on software that had already been deprecated.

Likewise, the excellent FWTools project, which also bundles together many of the same packages as OSGeo4W still comes bundled with Python 2.3.4 and version 1.7 of the GDAL library. Crucially, for me, GDAL introduced support for SQL Server as a spatial data source only in version 1.8, so using FWTools wasn’t an option either.

What’s more, Mapnik itself seems to have forked into two versions – the current stable release being 0.7.1, but with many comments being made about breaking changes in the new 2.x development version. The only precompiled windows binaries I could find were of the 0.7 version and, again, I didn’t want to invest a lot of time setting up a project based on software that was about to go out of date.

So, precompiled binaries was, at this stage, a no-go.

Build-It-Yourself

I decided I was going to have to build my own installation, and here was my wish list:

  • Python 3.2
  • GDAL 1.8
  • Mapnik 2.x

Python was (thankfully) easy to install – there’s an installer package available from http://python.org/ftp/python/3.2/python-3.2.msi

GDAL was also not too bad – there are x86 and x64 packages (bundled with mapserver) that you can download from http://www.gisinternals.com/sdk/

Now onto Mapnik. And it is here, with retrospect, that I wish I’d stated taking notes. You can download the source for mapnik from here. However, before compiling mapnik itself, you need to download and/or compile its required dependencies. These are: proj4, boost, zlib, freetype, icu, libxml2, libpng, libjpeg, and libtiff.

Now, you could download the source for each of these and build them separately but fortunately, once again, some kind soul has done much of this work for us. If you go to the gnuwin32 project on sourceforge, you’ll find links to download most of these libraries. For those packages not included in gbuwin32, ICU is available from here, and you can get the latest zlib from here.

Once you’ve got all the dependencies sorted out, it’s onto the configuration changes. If you follow the article at http://trac.mapnik.org/wiki/Python3k you’ll see a number of steps required to rebuild the python bindings with Mapnik to target Python 3.x. After some fiddling about with these and a bit of guesswork, I managed eventually to get everything built.

Testing it Out

Mapnik comes with a test script so, gingerly, I tried running it. Lots of errors – couldn’t find xxx etc. I realised this was because I hadn’t set the environment variables and paths correctly so, after sorting this out, I had another go. This time looked a lot more promising:

image

And, lo and behold, here was the (beautiful) example image generated:

demo_high

Over-confident of my new found ability, I then tried altering the example rundemo.py script to point at a SQL Server datasource. Mapnik supports OGR datasources, so I first created a virtual layer that connected to my SQL Server. For the purposes of testing, I decided to select a set of data from the OS VectorMap District settlement area data (note that I’m not sure if OGR can deal with SQL Server’s native binary geography/geometry format, so I use STAsText() to get the WKT representation and then specify WKT encoding in the GeometryField):

<OGRVRTDataSource>
  <OGRVRTLayer name="AASQLlayer">
    <SrcDataSource>MSSQL:server=.\SQLEXPRESS;database=OSVectorMap;trusted_connection=yes</SrcDataSource> 
    <SrcSQL>SELECT geom27700.STAsText() AS geomWKT FROM TG11_Settlement_Area</SrcSQL>
    <GeometryField encoding="WKT" field="geomWKT"/>
  </OGRVRTLayer>
</OGRVRTDataSource>

Testing the virtual layer with ogrinfo seemed to suggest that everything was working ok:

image

So then I modifed the python script to add the new layer. Note that OS Vectormap data is defined using the OSGB British National Grid coordinate system (EPSG:27700), and mapnik expects the parameters for the srs property to use PROJ4 syntax, which you can get from http://spatialreference.org/ref/epsg/27700/proj4/:

vectormap_lyr = mapnik.Layer('OS Vectormap')
vectormap_lyr.srs = "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs"

vectormap_lyr.datasource = mapnik.Ogr(file='MSSQL.ovf',layer="AASQLlayer")

Unfortunately, here I hit another problem:

image

And it seems here my luck has run out, because I simply can’t work out how to get round this one. The error message is simply “Failed to open datasource”, yet ogrinfo confirms that the datasource is fine, and other GDAL/OGR components can read from it, so I don’t know if it’s because I built mapnik wrong or forgot to change/include a particular setting.

I did just notice that there’s a Google Summer of Code Project to improve Mapnik installation on Windows, and I’m really hoping it’s successful because the results generated by Mapnik are beautiful.

As a workaround, I actually used OGR2OGR to export my data from SQL Server into a shapefile called MSSQL_export.shp, and then used that as a datasource in Mapnik by changing the python datasource to:

vectormap_lyr.datasource = mapnik.Shapefile(file='MSSQL_export')

Finally, after a bit of XML styling, I was able to get the following image (click for full size):

image

I’m actually really pleased with the image quality, but until I can get Mapnik to retrieve data directly from SQL Server there’s not much point proceeding with the tilecutting process – I can’t really justify an additional step of exporting from SQL Server to shapefile just to get Mapnik to load it.

If anyone has had any success of getting Mapnik and SQL Server to play nicely together, please let me know!

Follow

Get every new post delivered to your Inbox.

Join 53 other followers