AARoads:Maps/Tutorial

From the AARoads Wiki: Read about the road before you go
Jump to navigation Jump to search

This is a tutorial on how to create a GeoJSON map file from OpenStreetMap (OSM) data. Using OSM data is convenient compared to using traditional shapefiles in a GIS application, and because it is freely licensed, eliminates the risk of importing copyright-encumbered data into Wikimedia Commons (which may lead to its deletion).

Getting the relation

Underneath the slick editor and fancy rendering code, OpenStreetMap is essentially a database of vector objects. There are a few different types of these objects, but the ones we're interested in are known in OSM parlance as ways. Ways are used to represent segments of linear features like streets, roads, footpaths, streams, railroads, etc. Each of these ways is tagged, key/value style, with relevant data: the type of feature the way represents, its relative importance, its name, and so on. These tags are then used by the tile server (which renders the data into an actual human-readable map) to determine how to represent each feature.

A collection of ways can be grouped together using a property known as a relation. Numbered routes are expressed on OSM as a specially-tagged relation. Conveniently, relations typically break at state lines, so it is easy to select just the portion of, say, Interstate 70 in Utah without selecting the entire route clear to Baltimore. In some cases, there may be multiple relations that make up a route—routes which have multiple carriageways, or routes that exist in multiple disjointed sections are two situations in which this often applies. In these cases, there will often be a super-relation, which is essentially a relation of relations.

Using the OpenStreetMap website

The simplest method to select all of the relevant ways for export is by finding the ID number(s) of the relation(s) corresponding to your desired route.

  1. Go to OpenStreetMap and zoom into the general area where the route runs.
  2. Select the target route by right-clicking (control-click on Macs) and selecting 'Query features'.
  3. Then search through the list for the route you desire; selecting it will bring you the relation representing the route, with the route displayed beside it on the map. If a super-relation exists for the route, it will be noted here; select it rather than one of the child relations.

Advanced: Querying by attributes

If you already know how the relation would be tagged, you can modify the queries below to have Overpass search for relations with specified tags instead of relation numbers. To do this, replace the line relation(id:?); in the first query example below with rel["route"="road"]["network"="net"]["ref"="num"];, where

So, a query for New Jersey Route 3 might look like

[out:json][timeout:25];
rel["route"="road"]["network"="US:NJ"]["ref"="3"];
out geom;

To query for relations that are similar to the desired base relation, changing the = to ~ in each tag will ask Overpass to look for the requested anywhere in the attribute, instead of requesting an exact match. So for example, the line rel["route"="road"]["network"="US:NJ:CR"]["ref"~"561"]; not only looks for New Jersey County Route 561, but also its spurs, alternates, former alignments, and bypasses.

Exporting the data using Overpass Turbo

The Overpass API is a text-based interface for, among other things, directing the OSM server to export the data you want to access. The Overpass Turbo website provides a human-accessible interface to the Overpass API.

  1. Go to the Overpass Turbo page and paste the appropriate code into the editing pane at the left, replacing the ? with your relation ID number:
  • If you have just one relation:
[out:json][timeout:25];
relation(id:?);
out geom;
  • If you have two or more relations, use the above query, separating the relation numbers with a comma.
  • If you have a super-relation, use the following query with the super-relation number:
[out:json][timeout:25];
relation(id:?);
rel(r);
out geom;
  1. Click the ▶ "Run" button.
  2. Click the Magnifying glass.png "Zoom to data" button to move the map to the extents of the data and verify that it has returned what you expected it to.
  3. Click "Export" in the toolbar, and select "Download/copy as GeoJSON".

Uploading to Commons

  1. On Wikimedia Commons, create a page in the Data: namespace with the .map extension, like Data:Oklahoma State Highway 7.map.
  2. When you create the page, replace the ... GeoJSON ... placeholder (including the two brackets) with the GeoJSON you generated.
  3. Remove the // from the beginning of the line "license": "ODbL-1.0", // ODC Open Database License v1.0.
  4. Add below this a line something like "sources": "Map data © OpenStreetMap contributors",.
  5. Remove all remaining lines starting with //. (In theory these are comments that the server is supposed to delete automatically, but it doesn't seem like it works on all browsers.)
  6. Delete the zoom, latitude, and longitude lines.
  7. To make the line red and bold in the map view, find the properties stanza, and add the following code just before its closing brace (if there's more than one, add the code each time it occurs; if you added the bounding box using npm, ignore this step):
,
"stroke": "#c00"
  1. (opt.) Add the line "title": "?" to that list, where ? is the name of the route. (While this step isn't strictly necessary, it allows for disambiguation in case multiple routes are combined into one map). Then, if you wish to convey more information, add a "description" attribute.
    • Note that the JSON format requires commas between items of the same level but not after the last one. Take care to ensure the code is correctly formed!
  2. Save the page.
  3. Go to the talk page for the data item and categorize it in both Map data of roads in state and the category for the highway, if one exists.
  4. You can now use {{map}} to display the map on AARoads Wiki!

You can copy and paste this code into the edit window to save a couple of the steps above.

{
    "description": {"en": "map description"},
    "sources": "Map data © OpenStreetMap contributors",
    "license": "ODbL-1.0",
    "data": {

        ... GeoJSON ...

    }
}

Advanced

Adjust OSM Relation

Though most of the time the data you pull from will be accurate, no data set as complex as OpenStreetMap's can be 100% accurate. If you need to adjust a route relation in OpenStreetMap, or create new relations entirely, instructions to do so can be found here. iD is OSM's native web-browser editor, and is considered the simplest editor, while Potlatch and JOSM are generally used for more ambitious tasks.

Query by ways

Sometimes, ways are not joined by relations, but instead by common attributes for each way. To query ways using these attributes, change the relation(id:?); in the first query example below with way["key"="value"];, replacing each key and value pair as desired, and adding more ["key"="value"] segments before the semicolon as desired to filter further. For example, old alignments of a route are often labelled using an old_ref tag, so if you wanted to query for all ways that were once numbered 66, the query would look like way["old_ref"="66"];.

Restrict query to a region

In case you want to restrict your search to a specific region, add a line before the query line in the form of area(#); or area["key"="value"];, and on the query line add (area) before the semicolon. So, if you wished to restrict a query to just look in Ohio, it might look like:

[out:json][timeout:25];
area["name"="Ohio"];
relation["key"="value"](area);
out geom;

Combine features

Querying for multiple ways or rels results in valid data, but each way or rel will be considered its own "feature". This will rub up against the highlighting abilities of {{Map}}, which highlights features individually. So, if you query for multiple ways individually within a given route, clicking on one way will only highlight that way, and not the whole route. Combining these ways into a single Feature can be done in a rudimentary form in the Overpass query. To do so, add this segment before the out statement:

make Feature
  ::geom = gcat(geom());

This will unify everything in the query into one GeometryCollection. You will find that after running the query, the map will appear empty. This is because the query's output does not follow the standard format of OSM query output, and so the map will not render it. However, if you switch to the Data tab, the only element in the "elements" array will have a valid GeoJSON object- this is what should be copied for further processing.

Map extents

In most cases, the Map gadget will determine where to center the map and how far in it's zoomed on first loading. However, should you wish to override this, there are two different ways to set the boundaries of the map. The simpler option is to specify the center coordinates and zoom level of the map, which can be done directly in the Map template. However, it is unlikely that the map will display correctly in all viewers, especially the smaller ones used in infoboxes. The more bulletproof, but complex, method is to specify four coordinates, making up a bbox (bounding box).

Using geojson.io

The easiest way to add a bbox to your GeoJSON code is to use GeoJSON.io.

  1. Click "New" to get a blank map, if necessary.
  2. Paste your GeoJSON code into the editing pane.
  3. Click "Meta" → "Add bboxes". This code can now be transferred to Commons.

It should be noted that this method generates bounding boxes at every data level; for example, if a dataset has multiple features, every feature will have its own bounding box, as will the dataset as a whole.

Using npm

Another method to render bounding boxes is to use the npm package geojson-bbox. While this method is more low-level, it does not render more bounding boxes than necessary, and it also allows for cleanup of extraneous pieces of data that the map renderer will not look for, and can automate the process of styling features.

This process can be run in the browser using RunKit, but it can also be run using any Node implementation, as long as the package geojson-bbox is installed. To do this, run the following code (replacing ? with the data copied from Overpass):

var geojsonBbox = require("geojson-bbox")
var data = ?
if (data.features) {
    delete data.generator;
    delete data.copyright;
    delete data.timestamp;
}
else
    data = {
        type: "FeatureCollection",
        features: [data]
    };
for (feature of data.features) {
    delete feature.id;
    if (feature.properties)
        feature.properties = {
            title: "Route " + feature.properties.ref,
            stroke: "#c00"
        };
}
if (data.features.length == 1) data = data.features[0];
data.bbox = geojsonBbox(data);
JSON.stringify(data);

The line with title ought to be changed as shown in the #Uploading to Commons section; feature.properties.ref represents the route number, while other parts of the line should be surrounded with quotation marks and joined with a +.

Once this is run, the console will print the processed data. (If there is no output, the last line may need to be changed to console.log(JSON.stringify(data));. Copy this output for use in the next step.

Manual creation

If you're comfortable with JSON syntax, you can add the bbox manually as well. The "current map view" option in Overpass Turbo will display the relevant coordinates.

Styling Features

There are established standards and conventions for color that were established before the creation of this wiki:

Type w:Colorimetry
Road highlighted
#c00
R:204 G:0 B:0
Toll highways
Business routes
#008000
R:0 G:160 B:0
Spur routes
#00f
R:0 G:0 B:255
Subsidiary routes (Truck Routes, etc.)
#faf
R:255 G:170 B:255
Former segments
#888
R:136 G:136 B:136

Colors beyond this are left to the discretion of the mapper.

Standard convention is to have the line width be 3 pixels wide; this is the default in the {{Map}} template. Other properties that can be included in the same manner include stroke-width and stroke-opacity.

External Links