<html> |
|
<head> |
|
<link rel="stylesheet" href="main.css" type="text/css"> |
|
<title>Graphserver - The Open-Source Multi-Modal Trip Planner</title> |
|
</head> |
|
|
|
<body> |
|
<div id='container'> |
|
<a href="gallery.html"><img src="img/graphbanner.png"></a> |
|
<h1>Graphserver</h1> |
|
The open-source multi-modal trip planner. |
|
|
|
<h2>Code Repository</h2> |
|
<a href="http://github.com/bmander/graphserver/tree/master">http://github.com/bmander/graphserver/tree/master</a> |
|
|
|
<h2>Mailing List</h2> |
|
|
|
Direct questions and comments to the <a href="http://groups.google.com/group/graphserver">Graphserver Google Group</a>. |
|
|
|
<h2>Download</h2> |
|
|
|
<pre style="background-color:#F5F5F5"> $ wget http://github.com/bmander/graphserver/zipball/08132009</pre> |
|
|
|
Or, for the stout of heart, get a copy of the current working branch |
|
|
|
<pre style="background-color:#F5F5F5"> $ git clone git://github.com/bmander/graphserver.git </pre> |
|
|
|
<h2>Install</h2> |
|
|
|
<h3>Cold Start</h3> |
|
<p>You'll need a computer running linux. The following setup was tested and checked on <a href="http://aws.amazon.com/console/">Amazon EC2</a> small instance running Fedora, built from an image with id "ami-48aa4921", at a cost of $0.20/hour.<p> |
|
<p>You'll need to get git:</p> |
|
<p>On Ubuntu:</p> |
|
<pre style="background-color:#F5F5F5"> $ sudo apt-get install git-core </pre> |
|
<p>On Fedora:</p> |
|
<pre style="background-color:#F5F5F5"> $ yum install git-core</pre> |
|
|
|
<h3>Get The Prerequisites</h3> |
|
|
|
<p>You're about to compile C code against python development libraries. You need to prepare for that.</p> |
|
|
|
On Ubuntu: |
|
<pre style="background-color:#F5F5F5">$ sudo apt-get install python-setuptools |
|
$ sudo apt-get install build-essential |
|
$ sudo apt-get install python-dev |
|
</pre> |
|
|
|
On Fedora: |
|
<pre style="background-color:#F5F5F5"> |
|
$ yum install python-setuptools-devel |
|
$ yum install gcc |
|
$ yum install gcc-c++ |
|
$ yum install python-devel |
|
$ easy_install simplejson |
|
</pre> |
|
|
|
<h3>One-step Install</h3> |
|
<p>Get a copy of Graphserver</p> |
|
<pre style="background-color:#F5F5F5">$ git clone git://github.com/bmander/graphserver.git</pre> |
|
|
|
This will download and compile the core, download and install package dependencies, and install the python wrappers in one go. |
|
|
|
<pre style="background-color:#F5F5F5">$ cd graphserver/pygs |
|
$ sudo python setup.py install |
|
</pre> |
|
|
|
<h3>Install RTree</h3> |
|
<p>If you want to load OSM Data (and you probably do), you have to laboriously install RTree</p> |
|
<pre style="background-color:#F5F5F5"> $ wget http://download.osgeo.org/libspatialindex/spatialindex-1.4.0.tar.gz |
|
$ gunzip spatialindex-1.4.0.tar.gz |
|
$ tar -xvf spatialindex-1.4.0.tar |
|
$ cd spatialindex-1.4.0 |
|
$ ./configure --prefix=/usr |
|
$ make |
|
$ make install |
|
$ easy_install RTree |
|
$ cp /usr/lib/python2.5/site-packages/Rtree-0.5.0-py2.5-linux-i686.egg/libsidx.so /usr/lib |
|
</pre> |
|
|
|
<h2>A Quick Tour of the Basics</h2> |
|
|
|
<pre style="background-color:#F5F5F5"> |
|
$ python |
|
>>> from graphserver.core import Graph, Street, State |
|
>>> gg = Graph() |
|
>>> gg.add_vertex("A") |
|
<span class="computeroutput"><graphserver.core.Vertex object at 0xb7d9608c></span> |
|
>>> gg.add_vertex("B") |
|
<span class="computeroutput"><graphserver.core.Vertex object at 0xb7c397cc></span> |
|
>>> gg.add_edge( "A", "B", Street("1", 100) ) |
|
<span class="computeroutput"><graphserver.core.Edge object at 0xb7c4a92c></span> |
|
>>> gg.add_edge( "A", "B", Street("2", 50 ) ) |
|
<span class="computeroutput"><graphserver.core.Edge object at 0xb7da708c></span> |
|
>>> gg.size #the graph is quite small |
|
<span class="computeroutput">2</span> |
|
>>> gg.get_vertex("A").outgoing <span class="pycomment"># the graph is directional</span> |
|
<span class="computeroutput">[<graphserver.core.Edge object at 0xb7b9accc>, <graphserver.core.Edge object at 0xb7b9acac>]</span> |
|
>>> gg.get_vertex("A").incoming |
|
<span class="computeroutput">[]</span> |
|
>>> spt = gg.shortest_path_tree( "A", "B", State(1,0) ) |
|
>>> spt |
|
<span class="computeroutput"><graphserver.core.ShortestPathTree object at 0xb7c45b8c></span> |
|
>>> spt.get_vertex("A") <span class="pycomment"># the shortest path tree is a partial copy of the graph</span> |
|
<span class="computeroutput"><graphserver.core.Vertex object at 0xb7c4a92c></span> |
|
>>> spt.get_vertex("A").outgoing <span class="pycomment"># which only contains the shortest paths to all points closer than 'B' </span> |
|
<span class="computeroutput">[<graphserver.core.Edge object at 0xb7b9adec>]</span> |
|
>>> vertices, edges = spt.path("B") <span class="pycomment"># you can get the path 'A' to 'B' from the shortest path tree</span> |
|
>>> vertices <span class="pycomment"># a list of references to the SPT vertices along the shortest path</span> |
|
<span class="computeroutput">[<graphserver.core.Vertex object at 0xb7b9ae4c>, <graphserver.core.Vertex object at 0xb7b9adec>]</span> |
|
>>> edges <span class="pycomment"># a list of references to the SPT edges along the shortest path</span> |
|
<span class="computeroutput">[<graphserver.core.Edge object at 0xb7b9accc>]</span> |
|
>>> edges[0].payload <span class="pycomment"># the edge payload contains information about the edge</span> |
|
<span class="computeroutput"><Street name='2' length=50.000000 rise=0.000000 fall=0.000000 way=0></span> |
|
>>> vertices[-1].payload <span class="pycomment"># the payload of the final vertex has useful information</span> |
|
<span class="computeroutput"><graphserver.core.State object at 0xb7c4a92c></span> |
|
>>> vertices[-1].payload.time <span class="pycomment"># it takes 58 seconds to get from "A" to "B"</span> |
|
<span class="computeroutput">58</span> |
|
>>> spt.destroy() <span class="pycomment"># these functions are thin wrappers around C functions</span> |
|
>>> gg.destroy() <span class="pycomment"># so we have to perform garbage collection explicitly</span> |
|
>>> exit() |
|
</pre> |
|
<h2>Compiling Graphs</h2> |
|
<h3>Loading OpenStreetMap Data</h3> |
|
|
|
Grab some OSM data. Here, we download an area around of Redding, CA, US from the OpenStreetMap HTTP API. |
|
<pre style="background-color:#F5F5F5"> $ wget http://api.openstreetmap.org/api/0.6/map?bbox=-122.4624,40.5505,-122.2876,40.6334 -O map.osm |
|
</pre> |
|
<p>Compile the OSM file into an OSMDB file, and then load that OSMDB file into a graph.</p> |
|
<pre style="background-color:#F5F5F5"> $ gs_osmdb_compile map.osm map.osmdb |
|
$ gs_import_osm map.gdb map.osmdb |
|
</pre> |
|
<p>Take a look at your new graph. This prints every vertex label in the graph:</p> |
|
<pre style="background-color:#F5F5F5"> $ gs_gdb_inspect map.gdb</pre> |
|
<p>Pick one and see all edges outgoing from that vertex:</p> |
|
<pre style="background-color:#F5F5F5"> $ gs_gdb_inspect map.gdb osm-92080455</pre> |
|
Prints: |
|
<pre style="background-color:#F5F5F5">osm-92080455 -> osm-91938757 |
|
<Street name='10585937-1' length=136.119463 rise=0.000000 fall=0.000000 way=849> |
|
osm-92080455 -> osm-92080457 |
|
<Street name='10585937-2' length=139.452776 rise=0.000000 fall=0.000000 way=849> |
|
osm-92080455 -> osm-92601143 |
|
<Street name='10596654-0' length=126.551782 rise=0.000000 fall=0.000000 way=1809> |
|
osm-92080455 -> osm-92080381 |
|
<Street name='10596654-1' length=6.382770 rise=0.000000 fall=0.000000 way=1809></pre> |
|
|
|
<h3>Loading Public Transit Data</h3> |
|
|
|
Grab the GTFS file for your favorite transit agency. Here, we grab the GTFS for the transit system in Redding, CA: |
|
<pre style="background-color:#F5F5F5"> $ wget http://trilliumtransit.com/transit_feeds/redding/google_transit.zip -O redding_gtfs.zip</pre> |
|
<p>Compile the GTFS into a GTFSDB, and then compile that GTFSDB into a graph<p> |
|
<pre style="background-color:#F5F5F5"> $ gs_gtfsdb_build redding_gtfs.zip redding.gtfsdb |
|
$ gs_import_gtfs redding.gdb redding.gtfsdb</pre> |
|
<p>Use gs_gdb_inspect to check that your new transit graph is in good shape</p> |
|
<pre style="background-color:#F5F5F5"> $ gs_gdb_inspect redding.gdb sta-3622</pre> |
|
should print |
|
<pre style="background-color:#F5F5F5">sta-3622 -> psv-0-000-004 |
|
<TripBoard int_sid=0 sid=105A166 agency=0 calendar=165157760 timezone=164034504 boardings=[('1572A105B166', 23964), ('1598A105B166', 27564), ('1602A105B166', 31164), ('1607A105B166', 34764), ('1600A105B166', 38364), ('1605A105B166', 41964), ('1603A105B166', 45564), ('1608A105B166', 49164), ('1601A105B166', 52764), ('1606A105B166', 56364), ('1599A105B166', 59964), ('1604A105B166', 63564), ('1609A105B166', 67164)]> |
|
sta-3622 -> psv-0-000-004 |
|
<TripBoard int_sid=1 sid=106A166 agency=0 calendar=165157760 timezone=164034504 boardings=[('2459A106B166', 34764), ('1635A106B166', 38364), ('1640A106B166', 41964), ('1638A106B166', 45564), ('1643A106B166', 49164), ('1636A106B166', 52764), ('1641A106B166', 56364), ('1634A106B166', 59964), ('1639A106B166', 63564), ('1637A106B166', 67164)]> |
|
</pre> |
|
|
|
<h3>Intermingling Public Transit and Street Data</h3> |
|
<p>You can load both OSM and GTFS data into the same graph, then run a command to link them.</p> |
|
<pre style="background-color:#F5F5F5"> $ gs_import_gtfs redding_all.gdb redding.gtfsdb |
|
$ gs_import_osm redding_all.gdb map.osmdb |
|
$ gs_link_osm_gtfs redding_all.gdb map.osmdb redding.gtfsdb</pre> |
|
<p>Inspect:</p> |
|
<pre style="background-color:#F5F5F5"> $ gs_gdb_inspect redding.gdb sta-3622</pre> |
|
<p>prints:</p> |
|
<pre style="background-color:#F5F5F5">sta-3622 -> osm-92366549 |
|
<graphserver.core.Link object at 0x9a0b20c> |
|
sta-3622 -> psv-0-000-004 |
|
<TripBoard int_sid=0 sid=105A166 agency=0 calendar=163855912 timezone=161122808 boardings=[('1572A105B166', 23964), ('1598A105B166', 27564), ('1602A105B166', 31164), ('1607A105B166', 34764), ('1600A105B166', 38364), ('1605A105B166', 41964), ('1603A105B166', 45564), ('1608A105B166', 49164), ('1601A105B166', 52764), ('1606A105B166', 56364), ('1599A105B166', 59964), ('1604A105B166', 63564), ('1609A105B166', 67164)]> |
|
sta-3622 -> psv-0-000-004 |
|
<TripBoard int_sid=1 sid=106A166 agency=0 calendar=163855912 timezone=161122808 boardings=[('2459A106B166', 34764), ('1635A106B166', 38364), ('1640A106B166', 41964), ('1638A106B166', 45564), ('1643A106B166', 49164), ('1636A106B166', 52764), ('1641A106B166', 56364), ('1634A106B166', 59964), ('1639A106B166', 63564), ('1637A106B166', 67164)]></pre> |
|
|
|
<h3>Inspecting the graph with gs_crawl</h3> |
|
<p>Start gs_crawl, a little graph inspection web service</p> |
|
<pre style="background-color:#F5F5F5"> $ gs_crawl redding.gdb 80</pre> |
|
<p>Then steer your web browser to the appropriate location.<p> |
|
<p>If you're using Amazon EC2, using your own public DNS:</p> |
|
<pre style="background-color:#F5F5F5">http://YOUR-EC2-ADDRESS.compute-1.amazonaws.com/</pre> |
|
<p>Or if you're simply running on your local machine:</p> |
|
<pre style="background-color:#F5F5F5">http://localhost:80/</pre> |
|
|
|
<h3 id="routeserver">Getting routes with gs_routeserver</h3> |
|
<p>First, you'll need PyYAML</p> |
|
<pre style="background-color:#F5F5F5"> $ sudo easy_install pyyaml</pre> |
|
<p>The routeserver finds a path, and then uses a series of "handlers" to convert that path into a human-readable format. Those handlers are enumearted and set up by a configuration file called handlers.yaml. Graphserver comes with an example handlers.yaml which you can use to get started</p> |
|
<pre style="background-color:#F5F5F5"> $ cp /path/to/graphserver/pygs/graphserver/ext/routeserver/handlers.yaml .</pre> |
|
<p>This handlers.yaml file is filled with "CHANGEME" stubs. Replace every "CHANGEME.gtfsdb" with "redding.gtfsdb" and every "CHANGEME.osmdb" with "redding.osmdb"</p> |
|
<p>Fire up a routeserver on the compiled graph</p> |
|
<pre style="background-color:#F5F5F5"> $ gs_routeserver redding.gdb handlers.yaml -p 80</pre> |
|
<p>Get a list of all vertices in the system</p> |
|
<pre style="background-color:#F5F5F5">http://YOUR_DOMAIN_NAME/vertices</pre> |
|
<p>Get a route narrative</p> |