Skip to content

Usage notes #32

@mbonsma

Description

@mbonsma

Sharing in case it's helpful my step-by-step for using pgMapMatch. I have almost no knowledge of SQL so I'm including instructions for setting up the postgres database as well. I am using Ubuntu 22.

  1. Set up a postgres database. Run the following in a terminal:
  • Install pgrouting extension for postgres: sudo apt install postgresql-14-pgrouting
  • Change to default user "postgres": sudo -u postgres -i
  • Create a new postgres database: createdb database-name
  • Connect to the database: psql database-name
  • Add postgis extension: CREATE EXTENSION postgis;
  • Add pgrouting extension: CREATE EXTENSION pgRouting;

Note: I had to uninstall postgres and reinstall it to allow me to install a compatible version of postgis. If this applies, do this before step 1:

  • sudo apt-get --purge remove postgresql postgresql-*
  • sudo apt update
  • sudo apt install postgresql
  • sudo apt install postgresql-14-postgis-3
  1. Create Python environment. Since the fix to mapmatcher.py for newer scipy versions, requiring scipy=1.8 may not be necessary.
  • conda create -n pgmapmatch -c conda-forge python=3 "scipy=1.8" pandas gpxpy psycopg2 sqlalchemy docopt
  1. Save street network file to postgis database. Using the sample data provided as a shapefile and working in Python:
from sqlalchemy import create_engine
import geopandas as gpd

engine = create_engine("postgresql+psycopg2://postgres:postgres@localhost:5432/database-name")
sf_streets = gpd.read_file("sf_streets.shp") # sample data
sf_streets.columns = sf_streets.columns.str.lower() # postgres doesn't like uppercase?
sf_streets.to_postgis("sf_streets", engine, if_exists = 'replace') # save to postgis database
  1. Run pgMapMatch. I was not able to get my trace data to work as a postgis database, so I am running with individual gpx files. See note at the bottom for creating gpx files from shapefiles.
  • Copy config_template.py to config.py
  • Update database connection info in config.py, it will look something like this if using a local database:
pgInfo = {'db': 'database-name',
          'schema': 'public',    # schema with GPS traces and streets table
          'user': 'postgres',
          'host': 'localhost',
          'requirePassword': False  # Prompt for password? Normally, False for localhost
          }
  • Add current folder to PATH to import pgMapMatch as a package: export PYTHONPATH=.
  • In Python (same as the sample code in the README):
import pgMapMatch

streets_table = 'sf_streets'   # the name of your Postgres table with streets
mm = pgMapMatch.mapMatcher(streets_table)
your_gpx_filename = 'pgMapMatch/testdata/testtrace_36.gpx'
mm.matchGPXTrace(your_gpx_filename)
print(mm.bestRoute)

Best route output: [107059, 107060, 87737, 107056, 107057, 108203, 113936, 125564, 107060, 87796, 107055, 107056, 87725, 125408, 37189, 37188, 87797, 87796, 87795, 39950, 39951]

Note: to create gpx files from shapefile data or a csv with lat long (with timestamps, required for the package), do something like below, which is based on the example in the gpxpy docs:

import gpxpy
import geopandas as gpd
import datetime

data = gpd.read_file("your_trace_data.shp")

def save_gpx(gdf, trip_id):
    gpx = gpxpy.gpx.GPX()
    # Create first track in our GPX:
    gpx_track = gpxpy.gpx.GPXTrack()
    gpx.tracks.append(gpx_track)
    
    # Create first segment in our GPX track:
    gpx_segment = gpxpy.gpx.GPXTrackSegment()
    gpx_track.segments.append(gpx_segment)
    
    # Create points:
    for i, row in gdf.iterrows():
        lat = row['latitude']
        lon = row['longitude']
        ts = datetime.datetime.fromtimestamp(row['ts']) # 'ts' is the timestamp column in ISO 8601 format
        gpx_segment.points.append(gpxpy.gpx.GPXTrackPoint(lat, lon, time=ts))
    
    # save to file
    with open("{}.gpx".format(trip_id), "w") as f:
        f.write(gpx.to_xml())
        
for trip_id, group in data.groupby('trip_id'):
    save_gpx(group, trip_id)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions