OpenStreetMap Carto Tutorials - OpenStreetMap Carto documentation     Site map    
Editing Guidelines for OpenStreetMap Carto

Editing Guidelines for OpenStreetMap Carto

This page aims to describe the general editing process of OpenStreetMap Carto, the style used for the Standard tile layer of OpenStreetMap, through some suggested practices.

Development process to add or edit a feature

The following workflow summarizes the main actions.

Check DB data.dbWithin the PostGIS instance, find the DB columns related to the feature in scope.Verify that the needed column is included in openstreetmap-carto.style or that the hstore tags column can provide the needed feature through the tags->’feature’ syntax. As osm2pgsql populates hstore values for features that are not present in openstreetmap-carto.style, this file is expected to be rarely modified.
A-S
Edit project.mml.ymlCheck whether the selected columns are already managed within the appropriate layers in project.mml.If everything is already appropriately defined, all modifications can be directly implemented within the CartoCSS .mss files.Conversely, if the feature is not present within the layer(s), project.mml has to be edited.For complex development, a new layer might be needed and in this case a new section has to be developed in project.mml.
A-S
Edit the .mss style.cssThe .mss files can then be modified to define the rendering attributes of the new feature within each related layer. CartoCSS selectors shall refer layers or classes defined in project.mml. Inside a selector, filters and properties define rendering attributes.If a new layer is added, possibly a new .mss stylesheet file needs to be created.
A-S
Test modifications.htmlAll modifications must be tested (e.g., with Kosmtik) on different regions and using all zooms; regions shall be selected by analyzing wide areas, checking places with high and low concentration of the feature.

Before entering into the details of editing the styles, in case you are also willing to contribute to OpenStreetMap Carto, you are suggested to have a look to Guidelines for adding new features. It’s a long thread which qualifies and limits the current contribution scope to this project.

Description of project.mml

The definition and configuration file of openstreetmap-carto is named project.mml and uses the YAML format. Wikipedia contains an introduction to YAML.

The reason for using the YAML format instead of the former JSON is described here and here:lit is easier to edit and maintain, especially for SQL queries. The current version of carto can directly process it.

The definition of project.mml and more CartoCSS stylesheets has been adoped by Mapbox basing on a convention from Cascadenik, a predecessor to CartoCSS created outside of Mapbox. In Cascadenik, project.mml contained XML with CSS-like stylesheet embedded in <Stylesheet><![CDATA[...]]></Stylesheet> tag and, since the stylesheet included in project.mml started to grow, they moved it off to a separate file with MSS extension.1

The configuration of project.mml is grouped into sections, each configures a different aspect. Relevant sections:

  • globals settings: default values that are used in the other configuration sections;
  • _parts: definition of the YAML aliases for the projection and for the datasource;
  • Stylesheet: list of all used .mss files;
  • Layer: definition of all layers that openstreetmap-carto offers. Each layer can consist of multiple sources.

In YAML, the order of the sections is not important. The indentation is significant and shall only contain space characters. Tabulators are not permitted for indentation. The order of each layer is important.

The first part relates to the globals settings:

scale: 1
metatile: 2
name: "OpenStreetMap Carto"
description: "A general-purpose OpenStreetMap mapnik style, in CartoCSS"
bounds: &world
  - -180
  - -85.05112877980659
  - 180
  - 85.05112877980659
center:
  - 0
  - 0
  - 4
format: "png"
interactivity: false
minzoom: 0
maxzoom: 22
srs: "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over"

The above lines define the rendering settings for Mapnik. Notice that latitude bounds exclude the poles (with the same settings adopted by Google Maps), where the scale becomes infinite with Mercator projection. The center tag defines the starting lat/long centre point (0, 0) and zoom (4); these correspond to the default map image shown by TileMill at startup. srs is the adopted spatial reference system. The verbose +proj definitions ensure Mapnik is programmed with all appropriate parameters (+over for instance is required).2

The _parts section defines the YAML aliases for the projection and for the datasource:

# Various parts to be included later on
_parts:
  # Extents are used for tilemill, and don't actually make it to the generated XML
  extents: &extents
    extent: *world
    srs-name: "900913"
    srs: "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over"
  extents84: &extents84
    extent: *world
    srs-name: "WGS84"
    srs: "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"
  osm2pgsql: &osm2pgsql
    type: "postgis"
    dbname: "gis"
    key_field: ""
    geometry_field: "way"
    extent: "-20037508,-20037508,20037508,20037508"

Description:

  • extents: PostGIS data and shapefiles in EPSG:900913 Web Mercator projection (OSM target projection, same as Google Maps).
  • extents84: Shapefiles in WGS84 projection.
  • osm2pgsql: PostGIS plugin accessing the a PostgreSQL database named “gis” with default parameters (host, user, password, etc.).

Pulling an example from the file, we get this reference YAML:

# Various parts to be included later on
_parts:
  # Extents are used for tilemill, and don't actually make it to the generated XML
  extents: &extents
    extent: *world
    srs-name: "900913"
    srs: "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over"
  osm2pgsql: &osm2pgsql
    type: "postgis"
    dbname: "gis"
    key_field: ""
    geometry_field: "way"
    extent: "-20037508,-20037508,20037508,20037508"
Layer:
  - id: "citywalls"
    name: "citywalls"
    class: ""
    geometry: "linestring"
    <<: *extents
    Datasource:
      <<: *osm2pgsql
      table: |-
        (SELECT
            way
          FROM planet_osm_line
          WHERE historic = 'citywalls')
        AS citywalls
    advanced: {}

The <<: *extents key merges the keys from the &extents mapping of the _parts section into that location, avoiding having to specify them again, and same for <<: *osm2pgsql. The idea is taken from the MapProxy documentation. Fortunately, an understanding of YAML isn’t needed to use them when adding a layer - you just copy from existing layers. The _parts in JSON is ignored by carto and doesn’t impact the output XML; TileMill also appears to ignore it.3

The Stylesheet section references all used .mss CartoCSS stylesheets to be integrated in the compiled Mapnik XML input file:

Stylesheet:
  - "style.mss"
  - "shapefiles.mss"
  - "landcover.mss"
  - "water.mss"
  - "water-features.mss"
  - "road-colors-generated.mss"
  - "roads.mss"
  - "power.mss"
  - "placenames.mss"
  - "buildings.mss"
  - "stations.mss"
  - "amenity-points.mss"
  - "ferry-routes.mss"
  - "aerialways.mss"
  - "admin.mss"
  - "addressing.mss"

Subsequently to the stylesheets to be included in the source file for Mapnik, all layers are defined.

Layer:
  - ...
...

Layers are how sets of data are added to a map. Each layer references a single source file (e.g., shapefile) or database query (e.g., a PostGIS query). Multiple layers can be combined over top of each other to create the final map.4 A basic description of their definition is reported in the TimeMill documentation.

Layers are configured as arrays. The YAML format - indicates the start of the next item in an array. Generally the - appears before the id attribute (but might happen before a different attribute, e.g., name).5

Layers referring type: "postgis" (e.g., <<: *osm2pgsql in Datasource:) use the Mapnik postgis plugin. Plugins read geometric data from some specific external format to the internal format used by Mapnik. The PostGIS plugin requires to specify a SQL query that returns a table of data. That table must contain a column called way (of PostGIS type geometry). The table may contain arbitrary other columns, which are used to support rendering and can be invoked in the styling rules. The SQL query will be augmented with a bounding box condition by Mapnik (ST_SetSRID(‘BOX3D(…). The SELECT needs a subquery specifying a SQL table alias, which is generally the same identifier used in the id. In the above example, as the layer is named citywalls (- id: "citywalls"), the query after table: |- can be (but not necessarily is):

(SELECT way, ... FROM ... WHERE ...) AS citywalls

The Strip chomp modifier |- (ref. YAML Reference card) is used to insert a block, preserving newlines and stripping the final line break character.

Some tokens can appear in a query processed by the PostGIS plugin of Mapnik: !bbox!, !scale_denominator!, !pixel_width! and !pixel_height!.

PostgreSQL queries which can be defined in project.mml might become complex and always need tuning. Check OptimizeRenderingWithPostGIS for details and analysis. Check also Identifying Slow Rendering Queries.

Relation between Geometry and SQL Table is the following:

Geometry SQL Table Type
“linestring” planet_osm_line way
“linestring” planet_osm_roads way
“point” planet_osm_point node
“polygon” planet_osm_polygon relation

project.mml at the moment provides 79 layers. Generally, the more features that your map will include, the more layers that you’ll want. Basing on the painter algorithm, the order in which they are defined is the order in which they are rendered.

Relevant attributes of each layer:

  • id: layer identifier; defines a “#identifier” selector (selector preceded by hash), to be used in *.mss files.
  • name: the name of the layer, generally the same as id; this references the layer and is used by programs like Tilemill, allowing the user to select layers and filter their visibility. Notice that carto 0.17 marks name as deprecated and it will be removed in carto 1.06.
  • class: when set, defines one or more classes, to be used in mss files as *.identifier selector (selector preceded by dot); classes are used to define a single rendering description for many layers sharing the same class name. For instance, class: "barriers" is used by id: "area-barriers" and by id: "line-barriers"; then, in landcover.mss, a selector named .barriers {...} defines attributes which are common to both layers.
  • geometry: symbolizer type which can be linestring (way), point (node) or polygon. These attributes can be used as filters.
  • Datasource: can be file: "filename"/type: "shape" for shapefiles, or <<: *osm2pgsql/table: |- for PostGIS queries.
  • properties might indicate minzoom and maxzoom, which filter the Mapnik rendering to the defined set of zoom levels (also used to improve rendering performance, by avoiding to process layers which are only filtered within specific zooms in their .mss stylesheets).
  • advanced is not valued in openstreetmap-carto (e.g., advanced: {}).

CartoCSS .mss stylesheets

.mss stylesheets are in CartoCSS format.

The CartoCSS reference manual (by Mapbox) can be found in the Carto documentation.

A description of efficient methods for structuring CartoCSS styles is available at CartoCSS Best Practices.

A critical review of CartoCSS is reported in The end of CartoCSS blog post.

The columns in the SQL queries define the CartoCSS properties used as filter selectors or labels.

Consider the following style defined in project.mml (with some revisions as example):

  - id: "water-areas"
    name: "water-areas"
    class: "water-elements"
    geometry: "polygon"
    <<: *extents
    Datasource:
      <<: *osm2pgsql
      table: |-
        (SELECT
            way,
            "natural",
            waterway,
            landuse,
            name,
            way_area/NULLIF(!pixel_width!::real*!pixel_height!::real,0) AS way_pixels
          FROM planet_osm_polygon
          WHERE
            (waterway IN ('dock', 'riverbank', 'canal')
              OR landuse IN ('reservoir', 'basin')
              OR "natural" IN ('water', 'glacier'))
            AND building IS NULL
            AND way_area > 0.01*!pixel_width!::real*!pixel_height!::real
          ORDER BY z_order, way_area DESC
        ) AS water_areas
    properties:
      minzoom: 4
    advanced: {}

In the above example, the style is identified as “water-areas”, named with the same label, rendered at zoom >= 4; it uses polygons, defines a class named “water-elements” and provides the following properties for the CartoCSS stylesheet: [name], [landuse], [waterway], [way_pixels] (the latter produces the area in screen pixels), [natural] (in double quotes to prevent being interpreted as SQL token); these are the columns of the SQL Query.

Notice that the area is calculated in pixels and not in meters, to avoid the need of compensation at different latitudes in relation to the Mercator projection. Similarly, a line length should be calculated in pixels using the geometric mean of x and y (sqrt(x*y))7:

ST_Length(way)/NULLIF(SQRT(!pixel_width!::real*!pixel_height!::real),0)

A file named water.mss includes the related CartoCSS styles.

It might have a selector named #water-areas to specifically refer this layer:

#water-areas {
  # styles will apply to 'water-areas' layer only
  ...
}

Or it might have the .water-elements class:

.water-elements {
  # this applies to all layers with class 'water-elements'
  ...
}

SQL statements might also include ordering by user-supplied strings in the last term of an ORDER BY clause to get a consistent ordering across metatiles.

Let us consider this simplified CartoCSS example:

#water-areas {
  [natural = 'glacier']::natural {
    [zoom >= 6] {
      line-width: 0.75;
      line-color: @glacier-line;
      polygon-fill: @glacier;
      [zoom >= 8] {
        line-width: 1.0;
      }
      [zoom >= 10] {
      ...
      }
    }
  }

  [waterway = 'dock'],
  [waterway = 'canal'] {
    text-name: "[name]";
    ...
  }

  [landuse = 'basin'][zoom >= 7]::landuse {
    polygon-fill: @water-color;
    [way_pixels >= 4] {
      polygon-gamma: 0.75;
    }
    [way_pixels >= 64] {
      polygon-gamma: 0.6;
    }
  }
  ...
}

In the above example, landuse, waterway, way_pixels and natural are used as filters, while name is used as label. All are DB columns.

A feature might be rendered through more layers. Generally (but not always) a layer is rendered through a specific stylesheet (.mss).

Take for instance amenity=place_of_worship, which is defined in the following layers (within the current version of project.mml):

  • landcover (geometry: “polygon”):
    • #landcover selector in landcover.mss
    • related rendering produces regular highlights for polygons
  • buildings-major (geometry: “polygon”):
    • #buildings-major selector in buildings.mss
    • related rendering produces special highlights for polygons with wide “way_area”
  • amenity-points-poly (class: “points”, geometry: “polygon”):
    • .points class in amenity-points.mss
    • related rendering adds marker icon for polygons
  • amenity-points (class: “points”, geometry: “point”):
    • .points class in amenity-points.mss (uses the same class of amenity-points-poly)
    • related rendering adds marker icon for points
  • text-poly (class: “text”, geometry: “polygon”):
    • .text class in amenity-points.mss
    • related rendering produces adds text label

Stylesheet landcover.mss:

...

#landcover-low-zoom[zoom < 10],
#landcover[zoom >= 10] {
  ...
  [feature = 'amenity_place_of_worship'][zoom >= 13] {
    ... # fill polygon
  }
  ...
}
...

Stylesheet buildings.mss:

...
#buildings-major {
  [zoom >= 13] {
    ...
    [amenity = 'place_of_worship'] {
      ... # special highlights for polygons with wide "way_area"
    }
  }
}
...

Stylesheet amenity-points.mss:

...
.points {
...
  [feature = 'amenity_place_of_worship'][zoom >= 16] {
    ... # add marker
  }
...
}
...
.text-low-zoom[zoom < 10],
.text[zoom >= 10] {
...
  [feature = 'amenity_place_of_worship'][zoom >= 17] {
    ... # add text
  }
...
}
...

Reference documentation

Cartography design goals and guidelines

The reference document is CARTOGRAPHY. It is an important prerequisite to start contributing to the Openstreetmap Carto style.

Instructions for contributions

The reference document is CONTRIBUTING. This document includes essential development guidelines.

Design patterns

A file named USECASES describes which features should be rendered on a given zoomlevel and for a specific use case. This report is currently restricted to some low zoom levels (5, 6 and 7).

All colours used in openstreetmap-carto are defined in RGB, with annotations in LCh. This makes it much easier to review different colours comparing their related LCh parameters. An example is the need to define a number of tones at the same saturation/chroma and lightness but with different hues. When you do this in LCh, simply the hue parameter can be changed, keeping the other two values unaltered.8

LCh is a perceptually uniform reference color space based on actual studies of how people perceive colors. The LCh color wheel has four “primary” colors, yellow, cyan, violet-blue, and magenta-red. In this color space, L indicates lightness, C represents chroma or relative saturation, and h is the hue angle in polar coordinates. The value of chroma C is the distance from the lightness axis (L) and starts at 0 in the center. Hue angle is expressed in degrees ranging from 0 to 360 (e.g., 0° is red, and 90° is or yellow, 360° is red). It uses cylindrical coordinates. Lightness ranges from 0 to 100; dark to bright. Chroma ranges from 0 to 100 too, unsaturated to fully saturated.

All colours in openstreetmap-carto are anyway just annotated in LCh and reported in RGB as this is the color space used by Mapnik, to avoid gamut outside of RGB color space9. The conversion between LCh and RGB shall be done manually with an external program. As LCh has the problem that it is possible to specify colours that cannot be represented in RGB, a preliminarily defined LCh color has to be manually adjusted so that the corresponding RGB value exists.


Christoph Hormann published an excellent document on Design goals and guidelines for the Openstreetmap-carto style. It extends the official CARTOGRAPHY document with considerations on colors and zoom levels; reading and understanding it is recommended.

Check also the various notes within the Imagico’s blog.

Zoom filter in stylesheets

When defining the appropriate zoom level to render a feature, it is important to consider the effect of the Mercator projection.

Because Mercator is a variable scale projection, there is no direct relationship between zoom level and scale. At a typical resolution computer screen, z13 for example can be somewhere between about 1:70000 (Equator) and 1:8000 (northern Greenland).

A given scale for equator can be adjusted to a specific latitude by multiplying it by cos(latitude). For example, divide by 2 for latitude 60 (Oslo, Helsinki, Saint-Petersburg).

Resolution and Scale of Slippy map tiles is described here and here.

Some features need to scale up their font size according to the zoom level. If you are implementing different text sizes according to the zoom, consider also different wordwrap. The pattern to follow for the text size logic is described in Multi-line labels in CONTRIBUTING, landuse samples and lakes.

Additional recommendations

  • Render only verifiable features Before considering to render a feature, it is important to verify whether its definition does not lack verifiability and that the related spatial data model is appropriate (for instance, a natural area might be defined as polygon and shall not be defined as way). Also, the definition of the feature in the OSM Wiki shall be based on mapping considerations and not on rendering (for instance, it is important to check the existence of inappropriate definitions including wrong suggestion to mappers, for instance with reference to specific colors, or to rendering shapes, or to any other misleading indication which would ultimately end up in orienting mappers to map in a way that primarily works around the shortcomings of rendering engines rather than defining the appropriate shape and geometry of the feature). It is worthwhile to check the Approval status in the OpenStreetMap wiki and related usage statistics. Note anyway there is no formal approval about the tag page on the wiki. The status in the description box refers to the fact that there is an approved proposal that mentions a tag. The proposal process in the OpenStreetMap wiki is essentially meaningless for rendering decisions, it is just a means (but no guarantee) to improve tagging consistency 10. Also the Talk page shall be analyzed to verify whether there are remarks to be taken into consideration or to highlight some issue on tagging.
  • Before starting to code the rendering of a feature, verify that you are rendering an appropriate tagging; check that the Wiki supports it and that there is no case of missing or misunderstood tag. Also, verify its usage in different regions.
  • When considering to implement an improvement to the style, it is suggested to first create an issue, presenting the idea, asking whether there is a reason for the current style and discuss the most appropriate way to address a solution.
  • Count the number of uses for a tag you are going to render. For low usage, the reason to introduce a new feature has to be deeply discussed. Always consider the possibility to merge a newly rendered feature with some existing one, rather than adding something with separate code.
  • Everything currently found in the style has been deeply discussed by many contributors. When considering to change something, an extensive research has to be accomplished, shared and discussed. Besides, all previous repository issues related to the feature need to be revised and understood.
  • Always keep the same format, style and exactly the same coding conventions already adopted for the OpenStreetMap Carto project.
  • Implement the smallest set of modifications within a specific branch, at the cost of creating more branches; consider one feature per PR-
  • Test your development with many zones.
  • When making an improvement, try to reuse similar methods already included in the style for other features.
  • Do not use any Mapnik syntax like text-allow-overlap: true which make characters overlap (not allowed in cartography).
  • Do not think that your contribution might be incomplete or partial, with some hope that other people could further improve it in the future: the history of merges demonstrates the contrary.
  • Avoid comments or including your name in the code
  • Allow the commenters and maintainers to challenge a new feature, support your idea and be ready to accept the decision not to merge it.

Scripts

The following scripts are provided to support coding. They are necessary and useful solely during making changes to the map style and are unnecessary for map rendering.

scripts/get-external-data.py

This script generates and populates the data directory with all needed shapefiles, including indexing them through shapeindex. Check INSTALL for further documentation.

The shapefile configuration is read from a dictionary file which is by default external-data.yml, that describes the datasets as well as related download and installation process as declarative workflow.

At list 24 GB HD and 4 GB RAM are suggested to successfully run this procedure.

usage: get-external-data.py [-h] [-f] [-c CONFIG] [-D DATA] [-d DATABASE] [-H HOST] [-p PORT] [-U USERNAME] [-v] [-q] [-w PASSWORD] [-R RENDERUSER]

Load external data into a database

optional arguments:
  -h, --help            show this help message and exit
  -f, --force           Download new data, even if not required
  -c CONFIG, --config CONFIG
                        Name of configuration file (default external-data.yml)
  -D DATA, --data DATA  Override data download directory
  -d DATABASE, --database DATABASE
                        Override database name to connect to
  -H HOST, --host HOST  Override database server host or socket directory
  -p PORT, --port PORT  Override database server port
  -U USERNAME, --username USERNAME
                        Override database user name
  -v, --verbose         Be more verbose. Overrides -q
  -q, --quiet           Only report serious problems
  -w PASSWORD, --password PASSWORD
                        Override database password
  -R RENDERUSER, --renderuser RENDERUSER
                        User to grant access for rendering

get-external-data.py can be run from the scripts directory of openstreetmap-carto, or from its base folder.

Typical usage:

scripts/get-external-data.py

scripts/generate_road_colours.py

For any modification on the road classes colours, do not modify road-colors-generated.mss directly. Check instead road-colors.yaml and related internal description. Then run scripts/generate_road_colours.py > road-colors-generated.mss.

usage: generate_road_colours.py [-h] [-v]

Generates road colours

optional arguments:
  -h, --help     show this help message and exit
  -v, --verbose  Generates information about colour differences

Typical usage:

$ pip install colormath # (or "sudo pip install colormath" to install the needed Python prerequisite)

$ scripts/generate_road_colours.py > road-colors-generated.mss

Not all values are possible; generate_road_colours.py will throw an error if you pick values that cannot be converted to RGB. Usage of HUSL is recommended.

scripts/generate_shields.py

This script generates all SVG files inside the symbols/shields folder related to highway shields. It uses road-colors.yaml to configure the shield colors.

The generated files are then used by roads.mss (specifically, by roads-text-ref-low-zoom and roads-text-ref styles).

Files are named symbols/shields/[highway]_[width]x[height].svg, symbols/shields/[highway]_[width]x[height]_z16.svg and symbols/shields/[highway]_[width]x[height]_z18.svg where width = 1 to 10 and height = 1 to 4.

Related configuration is internal. The script exploits generate_road_colours.py to read road-colors.yaml configuration file.

The currently produced files are related to motorway, trunk, primary, secondary and tertiary highway tags (while track and path are not managed at the moment).

Installation

  • Installation of prerequisite components with Windows:

    Download the LXML WHL library from https://pypi.python.org/pypi/lxml

    Example using Python 2.7:

        > pip install lxml-3.6.4-cp27-cp27m-win32.whl
        > pip install colormath
    

    Example using Python 3.5:

        > pip install lxml-3.6.4-cp35-cp35m-win32.whl
        > pip install colormath
    

    Running the script:

        > scripts/generate_road_colours.py > road-colors-generated.mss
        > scripts/generate_shields.py
    
  • Installation of prerequisite components with Ubuntu:

    sudo apt-get install -y python-pip python3-pip libxml2-dev libxslt1-dev python-dev python-lxml python-colormath
    sudo pip install colormath
    sudo pip install lxml
    

    Running the script:

      $ scripts/generate_road_colours.py > road-colors-generated.mss
      $ scripts/generate_shields.py
    

scripts/shop_values.rb

This Ruby script generates a list of popular shop values with more than MIN_COUNT occurences in OpenStreetMap database according to taginfo. it is useful during creating/updating list of shops displayed with generic dot icon.

scripts/indexes.py

A new SQL query defined in project.mml might need the definition of SQL indexes that shall be coded in indexes.yml, which is the related dictionary adopted by OpenStreetMap Carto.

Do not modify indexes.sql directly: use this script instead, which reads indexes.yml and creates SQL statements to the standard output, to be redirected to indexes.sql. There are a number of options for concurrent index creation, recreating the osm2pgsql-built indexes, fillfactors, and other settings to give full control of the resulting statements.

usage: indexes.py [-h] [--concurrent] [--fillfactor FILLFACTOR] [--notexist]
                  [--osm2pgsql] [--reindex]

Generates custom index statements

optional arguments:
  -h, --help            show this help message and exit
  --concurrent          Generate indexes CONCURRENTLY
  --fillfactor FILLFACTOR
                        Custom fillfactor to use
  --notexist            Use IF NOT EXISTS (requires 9.5)
  --osm2pgsql           Include indexes normally built by osm2pgsql
  --reindex             Rebuild existing indexes

Typical usage:

$ scripts/index.py > index.sql

A goal with the indexes is to have them general-purpose enough to not need frequent changing with stylesheet changes, but to be usable with many versions, and potentially other styles.

Other useful scripts and commands

Validate the MML against multiple Mapnik versions, and report its lines for debugging purposes:

sudo apt install libxml2-utils
for m in 3.0.0 3.0.12; do carto -a $m project.mml 2>&- | xmllint - | wc -l; done

Validate that the SVGs are valid XML:

find symbols/ -name '*.svg' | xargs xmllint --noout

Check and validate the Lua tag transforms:

sudo apt install lua5.2  # install Lua interpreter (osm2pgsql embeds it)
cd openstreetmap-carto   # position inside the openstreetmap-carto directory
lua scripts/lua/test.lua # run the test script

Pattern casing

Within openstreetmap-carto project, folder with pathname symbols/generating_patterns includes sources (.svg files), process description (.md files) and produced images (.png files) of patterns built from two separately generated svg files by means of raster processing.

Details are in generating_patterns folder, which also includes *.md (markdown) documents.

Useful tools

OpenStreetMap Data structure

OpenStreetMap uses a topological data structure with four core elements (also known as data primitives):

  • Nodes are points with a geographic position, stored as coordinates (pairs of a latitude and a longitude) according to WGS 84. Outside of their usage in ways, they are used to represent map features without a size, such as points of interest or mountain peaks.
  • Ways are ordered lists of nodes, representing a polyline, or possibly a polygon if they form a closed loop. They are used both for representing linear features such as streets, rivers and areas (like forests, parks, parking areas and lakes).
  • Relations are ordered lists of nodes and ways (together called “members”), where each member can optionally have a “role” (a string). Relations are used for representing the relationship of existing nodes and ways. Examples include turn restrictions on roads, routes that span several existing ways (for instance, a long-distance motorway), and areas with holes.
  • Tags are key-value pairs (both arbitrary strings). They are used to store metadata about the map objects (such as their type, their name and their physical properties). Tags are not free-standing, but are always attached to an object, to a node, a way, a relation, or to a member of an relation.

A recommended ontology of map features (the meaning of tags) is maintained on the OSM Wiki.


Please, avoid using Disqus below to notify issues on this page, just use it for general comments. Create a GitHub issue instead. This is the most effective way to track problems.
comments powered by Disqus