Skip to content

Custom Points in OSW

Custom Points in OSW⚓︎

This guide shows how to add custom non-routable point features (like bus stops) to an OpenSidewalks dataset using the Custom Points entity type.

For a list of all guides on the TCAT Wiki, refer to the Guides List.


What are Custom Points?⚓︎

Custom Points in OpenSidewalks are user-defined non-routable point features that extend the schema beyond the predefined Core Entities and Adjacent Entities point types. While OpenSidewalks includes many built-in point types like fire hydrants, benches, and street lamps, Custom Points let you add any custom feature!

Doing so is simple - just prefix ext: before the tags that are not in the OSW schema.

This approach allows for immediately adding custom data, preserving data from existing systems.

Common Use Cases⚓︎

Custom Points are perfect for adding:

  • Transit infrastructure: Bus stops, public transport shelters
  • Accessibility features: Accessible parking spaces, wheelchair-accessible entrances, elevators
  • Wayfinding aids: Information kiosks, signage
  • Points of interest: Water fountains, ATMs, restrooms

Case Study: GTFS Bus Stops to OSW Custom Points⚓︎

In this example, we'll convert bus stop data from a GTFS stops.txt file into OpenSidewalks Custom Points. This is a common scenario for transit agencies and cities wanting to integrate public transportation data with pedestrian network information.

Understanding the Source Data⚓︎

A typical GTFS stops.txt file contains bus stop information like this:

stop_id,stop_code,stop_name,stop_desc,stop_lat,stop_lon,zone_id,stop_url,location_type,parent_station
1001,1001,Main St & 1st Ave,Northbound stop,47.6062,-122.3321,,http://example.com/stops/1001,0,
1002,1002,Main St & 2nd Ave,Southbound stop,47.6065,-122.3325,,http://example.com/stops/1002,0,

The Target: OSW Custom Points⚓︎

We want to convert each bus stop into an OpenSidewalks Custom Point that looks like this:

{
    "type": "Feature",
    "geometry": {
        "type": "Point",
        "coordinates": [-122.3321, 47.6062]
    },
    "properties": {
        "_id": "bus_stop_1001",
        "ext:stop_id": "1001",
        "ext:stop_code": "1001",
        "ext:stop_name": "Main St & 1st Ave",
        "ext:stop_desc": "Northbound stop",
        "ext:stop_url": "http://example.com/stops/1001"
    }
}

Step-by-Step Conversion Process⚓︎

Step 1: Prepare Your Data⚓︎

Start with your GTFS stops.txt file. You'll need these key fields:

  • stop_lat and stop_lon (for coordinates)
  • stop_id (for unique identification)
  • Any other fields you want to preserve (name, description, etc.)

Quality check your data:

  • Remove any stops with missing coordinates
  • Ensure stop_id values are unique
  • Verify coordinates are in decimal degrees (WGS84)

Step 2: Map Fields to OSW Structure⚓︎

Create a mapping between your GTFS fields and OSW Custom Point properties:

GTFS Field Goes in OSW as Notes
stop_lon, stop_lat geometry.coordinates Longitude first, then latitude
stop_id _id Create unique OSW ID (e.g., "bus_stop_" + stop_id)
stop_id ext:stop_id Keep original ID for reference
stop_name ext:stop_name Preserve original name
stop_desc ext:stop_desc Optional description
stop_code ext:stop_code Display code, if different from ID
stop_url ext:stop_url Link to more information

A note on the _id field: Every OSW entity needs a unique _id (string with at least one character). For bus stops, consider using a prefix like "bus_stop_" + the original stop_id to avoid conflicts with other features. Letters, numbers, and underscores are all fine!

Step 3: Create the GeoJSON Structure⚓︎

  • Required fields like _id go directly in properties
  • Custom fields get the ext: prefix and go in properties
  • Geometry goes in the geometry section, not properties

Your Custom Points need to be formatted as GeoJSON Features within a FeatureCollection. Here's how the field mapping from Step 2 translates into actual JSON:

{
    "$schema": "https://sidewalks.washington.edu/opensidewalks/0.3/schema.json",
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "geometry": {
                "type": "Point",
                "coordinates": [-122.3321, 47.6062] // stop_lon, stop_lat
            },
            "properties": {
                "_id": "bus_stop_1001", // Required OSW field
                "ext:stop_id": "1001", // Original GTFS stop_id
                "ext:stop_name": "Main St & 1st Ave", // Original GTFS stop_name
                "ext:stop_desc": "Northbound stop" // Original GTFS stop_desc
            }
        }
    ]
}

Key Structure Points:

  • All of the GTFS data fields (except coordinates) go in the properties section
  • Custom fields like ext:stop_name are the actual field names in your JSON
  • The ext: prefix is part of the field name, not a folder structure

Step 4: Add Dataset Metadata⚓︎

Include required OpenSidewalks metadata at the dataset level:

{
    "$schema": "https://sidewalks.washington.edu/opensidewalks/0.3/schema.json",
    "type": "FeatureCollection",
    "dataSource": {
        "name": "Metro Transit GTFS",
        "license": "Public Domain"
    },
    "dataTimestamp": "2024-12-01T00:00:00Z",
    "features": [
        // ... your custom points here
    ]
}

Conversion Tools⚓︎

Option 1: Purpose-built Scripts⚓︎

In the specific case of GTFS stops, a script such as this one created by TCAT, gtfs-to-tdei-converter.ps1, can be used.

Option 2: Online JSON Tools⚓︎

Use your spreadsheet software of choice to add ext: prefix to column headers, then convert CSV to GeoJSON:

  • https://geojson.io/
  • https://mapbox.github.io/csv2geojson/

Validation and Quality Assurance⚓︎

Check Your Output⚓︎

Before using your Custom Points, verify:

  1. Valid GeoJSON: Use geojson.io or a JSON validator
  2. Coordinate format: Longitude first, then latitude
  3. Unique IDs: Each _id appears only once
  4. Required fields: Every Custom Point has an _id and valid coordinates
  5. Custom fields: All additional data uses the ext: prefix

Common Issues and Fixes⚓︎

Problem Solution
Coordinates reversed Longitude should be first: [lng, lat]
Missing _id field Add unique identifier to each feature
Invalid JSON Use a JSON validator to find syntax errors
Coordinate precision GTFS uses 6+ decimal places; preserve precision

Integration with Existing OSW Data⚓︎

Manual Adding to Existing Datasets⚓︎

To add Custom Points to an existing OpenSidewalks dataset:

  1. Load your existing .osw file
  2. Add your Custom Point features to the features array
  3. Ensure all _id values remain unique across the entire dataset

Coordinate System Compatibility⚓︎

OpenSidewalks uses WGS84 (EPSG:4326) coordinates in decimal degrees. GTFS data is already in this format, so no conversion is needed. If your source data uses a different coordinate system, you'll need to reproject it first.

Best Practices⚓︎

Fields⚓︎

  • Use descriptive ext: field names: ext:stop_name not ext:name
  • Keep original field names when possible for easier maintenance
  • Be consistent across all your Custom Points
  • Remove unnecessary fields to keep file sizes manageable