惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 三生石上(FineUI控件)
博客园 - 叶小钗
博客园 - 聂微东
博客园 - 司徒正美
Hugging Face - Blog
Hugging Face - Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Google DeepMind News
Google DeepMind News
Recent Announcements
Recent Announcements
IT之家
IT之家
J
Java Code Geeks
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
I
InfoQ
爱范儿
爱范儿
Vercel News
Vercel News
Apple Machine Learning Research
Apple Machine Learning Research
阮一峰的网络日志
阮一峰的网络日志
博客园 - Franky
U
Unit 42
酷 壳 – CoolShell
酷 壳 – CoolShell
腾讯CDC
F
Fortinet All Blogs
V
Visual Studio Blog
人人都是产品经理
人人都是产品经理

herrkaefer

"Vibe planning \u003e vibe coding" "Anything to Markdown" "Built anocus: anonymous commenting for static sites" "日记与小说 -- AI 续写小说欣赏" "Any-podcast: from newsletters to a podcast" "Made MicPipe: a simple voice input tool using ChatGPT dictation" "关于 Tools 和 Skills 的一点感想" "Realtime monitoring of ComEd hourly price" "Introducing SwiftEdgeTTS" "Thoughts on the philosophy of building AI-native apps" "jelly鼻屎" "等饭的人" "Use home assistant to motivate my kid to brush teeth" "Migrated Blog to Hugo and Cloudflare Pages" "Easy Aspen monitoring for Chicago parents" "Introducing HabitBuilder: A simple Telegram bot for habit tracking" "鼓捣" "Open folder or file with Sublime Text from Finder toolbar" "Python dev workflow on macOS" "Create new text file from Finder toolbar" "Uno reinvented for 3-year-old kids" "Uno变身儿童数字游戏" "自动转发Twitter到微博" "Handle annoying operations of objects in Realm DB" "Move Jekyll blog to Ubuntu VPS" "Introducing Mole" "Note taking without note taking app" "Deploy Python web application on Ubuntu server" "Setup Shadowsocks / VPN on Ubuntu Server" "Linode Notes - Basic Setup"
"psycopgr Tutorial"
"herrkaefer" · 2016-09-01 · via herrkaefer

What is psycopgr

psycopgr is a Python wrapper of pgRouting written by me.

As said in pgRouting docs:

Just considering the different ways that the cost can be calculated, makes it almost impossible to create a general wrapper, that can work on all applications.

Indeed, in many applications you may need to modify the database tables and fill some computed values to fit your specific purpose, which is often done in a preprocessing stage by SQL, before real routing starts working. It is not appropriate to be wrapped.

However, after preprocessing things such as database creation, map data import, tables re-calculation and update, you are ready to use psycopgr to do another simple thing: computing optimal routes from nodes to nodes on real map, in Python.

Note that psycopgr is never a general purpose wrapper of pgRouting. I am a novice in GIS and what I want from this tool is just routes (with lowest costs) from places to places without writing a single line of SQL.

For preprocessing stage, I have a post “pgRouting notes” for my own reference. Before enjoyable Python coding, you have to prepare a few things.

Tutorial

Requirements

  1. Prepare a PostgreSQL database, install PostGIS and pgRouting extensions, and import map data to database. “pgRouting notes” is a practical guide.

  2. Update database tables according to your specific requirement.

Install psycopgr

(Yes, it is on PyPI now.)

Or,

As you may have guessed from the name, psycopgr uses psycopg2 as PostgreSQL driver. The above command will install it automatically.

Steps

First,

from psycopgr import PgrNode, PGRouting

Create a PGRouting instance with database connection:

pgr = PGRouting(database='mydb', user='user')

Adjust meta data of tables including the edge table properties if they are different from the default (only the different properties need to be set), e.g.:

pgr.set_meta_data(cost='cost_s', reverse_cost='reverse_cost_s', directed=True)

This is the default meta data:

{
    'table': 'ways',
    'id': 'gid',
    'source': 'source',
    'target': 'target',
    'cost': 'cost_s', # driving time in second
    'reverse_cost': 'reverse_cost_s', # reverse driving time in second
    'x1': 'x1',
    'y1': 'y1',
    'x2': 'x2',
    'y2': 'y2',
    'geometry': 'the_geom',
    'has_reverse_cost': True,
    'directed': True,
    'srid': 4326
}

Prepare nodes. Nodes are represented by PgrNode namedtuple with geographic coordinates rather than vertex id (vid) in the tables. PgrNode is defined as:

PgrNode = namedtuple('PgrNode', ['id', 'lon', 'lat'])

in which id could be None or self-defined value, and lon and lat are double precision values. Of course nodes could be input from various interfaces such as database or another program.

For example:

nodes = [PgrNode(None, 116.30150, 40.05500),
         PgrNode(None, 116.36577, 40.00253),
         PgrNode(None, 116.30560, 39.95458),
         PgrNode(None, 116.46806, 39.99857)]

Now we can do routings:

# many-to-many
routings = pgr.get_routes(nodes, nodes, end_speed=5.0, gpx_file='r.gpx')

# one-to-one
routings = pgr.get_routes(nodes[0], nodes[1])

# one-to-many
routings = pgr.get_routes(nodes[0], nodes)

# many-to-one
routings = pgr.get_routes(nodes, nodes[2])
  • end_speed: speed from node to nearest vertices on ways in unit km/h.
  • gpx_file: set it to output paths to a gpx file.

The returned is a dict of dict: {(start_node, end_node): {'path': [PgrNode], 'cost': cost}

By default, cost is traveling time along the path in unit second. It depends on the columns of the edge table that you set as cost and reverse_cost. You can assign the relations by set_meta_data function.

We can also get only costs without detailed paths returned:

costs = pgr.get_costs(nodes, nodes)

The returned is also a dict: {(start_node, end_node): cost}

Low-level wrapper of pgRouting functions

psycopgr functionpgRouting function
dijkstrapgr_dijkstra
dijkstra_costpgr_dijkstraCost
astarpgr_astar

These are direct wrappings of pgRouting functions. For example, dijkstra takes vertex ids as input. This list may be extended in the future.