-
Notifications
You must be signed in to change notification settings - Fork 1
MetaWriter
MetaWriters are a way of outputting vector features from Mapnik that exactly match the representations of rendered features. The idea is to allow for highly customizable output of specific features rendered into tiles that should also be made available as vectors to a web browser for interactivity. This support was added by Hermann Kraus (mail: herm @@@ scribus.info) in the GSOC project "Hit Areas".
A blog post on the idea is at: http://mapnik.org/news/2010/jul/06/gsoc2010_halfway/.
Slides from State of the Map Europe 2011 are available.
See also Herm's demo, which highlights both visible and invisible features: http://r2d2.stefanm.com/mapnik/demo.html
The above graphic highlights output (geojson) representing the clickable area of a MarkersSymbolizer rendered circle. This circle can change size dynamically depending on the width/height of the shape plus the thickness of the stroke and the bbox output by the MetaWriter will be intelligent to all rendering parameters.
The configuration for a MetaWriter is done as a child element of the Map.
<Map>
<MetaWriter name="meta1" type="json" file="map_meta.json"/>
<!--..snip..-->
</Map>
Parameters are:
-
name
(required) - Assign a name to your metawriter so that it can be referenced from a symbolizer
-
type
(required) - currently 'json' and 'inmem' are the only supported types
-
file
(json only, required) - relative or absolute path to the file-based output (currently json) - in the future could potentially be other kinds of output
- NOTE: this parameter accepts variable replacement (internally it is a PathExpression) so that for a given render the path can be dynamically constructed (see below for more details)
-
output-empty
(json only, optional) - if true (default) output json files even if no features are intersected, which will write an FeatureCollection with an empty features list
-
default-output
(optional) - this is a comma delimited list of attributes to output for every metawriter attached to a symbolizer
- example:
default-output="field1,field2"
- if not specified, for attributes to be output they must be requested in the symbolizer using the
meta-output
parameter -
pixel-coordinates
(relevant to json output format only, default=off) Output in image coordinates rather than long/lat (epsg:4326).
- If no features are encountered no json file is output (unless you pass the option
output-empty="true"
) - output projection is currently hardcoded to WGS84/EPSG:4326
- precision for geometries is currently fixed at 8
To actually trigger a metawriter to output features you need to attach one to a symbolizer.
Parameters that symbolizers accept (the relate to metawriters) are:
-
meta-writer
- the name of the MetaWriter to use -
meta-output
- attributes to write out for this specific symbolizer
For example, this would output geojson features (bbox's as polygons) for every point rendered by the symbolizer:
<PointSymbolizer meta-writer="meta1"/>
Example feature output:
{ "type": "Feature",
"geometry": { "type": "Polygon",
"coordinates": [ [ [11.07451289, 49.45187982], [11.07481352, 49.45187982], [11.07481352, 49.45218044], [11.07451289, 49.45218044] ] ]},
"properties": {
} },
This would do the same but also dump out the values for the attributes of 'amenity' and 'name':
<PointSymbolizer meta-writer="meta1" meta-output="amenity,name"/>
Example feature output:
{ "type": "Feature",
"geometry": { "type": "Polygon",
"coordinates": [ [ [11.07804522, 49.45285684], [11.07834585, 49.45285684], [11.07834585, 49.45315747], [11.07804522, 49.45315747] ] ]},
"properties": {
"amenity":"pharmacy",
"name":"Spital Apotheke"
} },
To dynamically contruct a file path for where to write out meta-features you can use variable replacement like:
<MetaWriter name="meta1" type="json" file="[tile_dir]/[z]/[x]/[y].json"/>
import os
import mapnik2 as mapnik
m = mapnik.Map(256,256)
x,y,z = 0,1,1
tile_dir = '.'
mapnik.load_map(m,'map.xml') # this 'map.xml' must contain a MetaWriter like above
m.zoom_all()
m.set_metawriter_property("x", str(x))
m.set_metawriter_property("y", str(y))
m.set_metawriter_property("z", str(z))
m.set_metawriter_property("tile_dir", tile_dir)
dir_ = '%s/%s/%s' % (tile_dir,z,x)
if not os.path.exists(dir_):
os.makedirs(dir_)
mapnik.render_to_file(m,'%s/%s/%s/%s.png' % (tile_dir,z,x,y))
<Map bgcolor="white" srs="+proj=latlong +datum=WGS84">
<MetaWriter name="points" type="json" file="[tile_dir]/[z]/[x]/[y].json"/>
<Style name="points">
<Rule>
<Filter>([amenity] neq '') and ([name] neq '')</Filter>
<PointSymbolizer meta-writer="points" meta-output="amenity,name"/>
</Rule>
</Style>
<Layer name="osm" srs="+proj=latlong +datum=WGS84">
<StyleName>points</StyleName>
<Datasource>
<Parameter name="type">osm</Parameter>
<Parameter name="file">testing.osm</Parameter>
</Datasource>
</Layer>
</Map>
<Map bgcolor="white" srs="+proj=latlong +datum=WGS84">
<MetaWriter name="points" type="json" file="points.json"/>
<MetaWriter name="lines" type="json" file="lines.json"/>
<Style name="points">
<Rule>
<Filter>([amenity] neq '') and ([name] neq '')</Filter>
<PointSymbolizer meta-writer="points" meta-output="amenity,name"/>
</Rule>
</Style>
<Style name="lines">
<Rule>
<Filter>([highway] neq '') and ([name] neq '')</Filter>
<LineSymbolizer stroke-width="5" stroke="green" meta-writer="lines" meta-output="highway,name"/>
</Rule>
</Style>
<Layer name="osm" srs="+proj=latlong +datum=WGS84">
<StyleName>lines</StyleName>
<StyleName>points</StyleName>
<Datasource>
<Parameter name="type">osm</Parameter>
<Parameter name="file">testing.osm</Parameter>
</Datasource>
</Layer>
</Map>