Skip to content

Commit 77f0408

Browse files
authored
Merge pull request #1 from DigitalGeographyLab/feat/graph-csv-exporter
Implement graph CSV exporter
2 parents 4dd0be3 + 0c6a6e7 commit 77f0408

File tree

5 files changed

+421
-0
lines changed

5 files changed

+421
-0
lines changed

graphs/build-config.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"areaVisibility": true
3+
}
4+

src/main/java/org/opentripplanner/graph_builder/GraphBuilder.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.opentripplanner.graph_builder.module.osm.OpenStreetMapModule;
1818
import org.opentripplanner.graph_builder.services.DefaultStreetEdgeFactory;
1919
import org.opentripplanner.graph_builder.services.GraphBuilderModule;
20+
import org.opentripplanner.graph_builder.services.GraphCsvExport;
2021
import org.opentripplanner.graph_builder.services.ned.ElevationGridCoverageFactory;
2122
import org.opentripplanner.openstreetmap.impl.AnyFileBasedOpenStreetMapProviderImpl;
2223
import org.opentripplanner.openstreetmap.services.OpenStreetMapProvider;
@@ -148,6 +149,9 @@ public void run() {
148149
if (serializeGraph) {
149150
try {
150151
graph.save(graphFile);
152+
String basePath = graphFile.getAbsolutePath().replace("/./", "/");
153+
GraphCsvExport.exportEdgesToCsv(graph, basePath.replace("Graph.obj", "edges.csv"));
154+
GraphCsvExport.exportNodesToCsv(graph, basePath.replace("Graph.obj", "nodes.csv"));
151155
} catch (Exception ex) {
152156
throw new IllegalStateException(ex);
153157
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
# OTP graph to CSV exporter
3+
4+
This procedure can be followed in order to export the internal OSM-based graph object of OTP to CSV files.
5+
6+
### Prerequisites
7+
- Git, a version control system
8+
- Java Development Kit, preferably version 8 (AKA version 1.8)
9+
- Maven, a build and dependency management system
10+
11+
### Install OTP
12+
```
13+
git clone https://github.com/HSLdevcom/OpenTripPlanner.git
14+
cd OpenTripPlanner
15+
mvn clean package -DskipTests
16+
```
17+
18+
### Create & export graph
19+
1) Download the latest OSM data for HSL area from https://api.digitransit.fi/routing-data/v2/hsl/hsl.pbf
20+
2) Add the OSM data file (hsl.pbf) to ./graphs
21+
3) Run `java -jar -Xmx8G target/otp-1.5.0-SNAPSHOT-shaded.jar --build ./graphs`
22+
4) Run GraphCsvExporter module with args (adjust if needed): `--graph graphs/Graph.obj -d -v --edges_out graphs/edges.csv --nodes_out graphs/nodes.csv`
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
package org.opentripplanner.graph_builder;
2+
3+
import com.beust.jcommander.JCommander;
4+
import com.beust.jcommander.Parameter;
5+
import com.csvreader.CsvWriter;
6+
import org.opentripplanner.routing.core.TraverseMode;
7+
import org.opentripplanner.routing.edgetype.StreetEdge;
8+
import org.opentripplanner.routing.edgetype.StreetTraversalPermission;
9+
import org.opentripplanner.routing.edgetype.StreetWithElevationEdge;
10+
import org.opentripplanner.routing.graph.Edge;
11+
import org.opentripplanner.routing.graph.Graph;
12+
import org.opentripplanner.routing.graph.Vertex;
13+
import org.opentripplanner.routing.vertextype.BarrierVertex;
14+
import org.opentripplanner.routing.vertextype.OsmVertex;
15+
import org.slf4j.Logger;
16+
import org.slf4j.LoggerFactory;
17+
18+
import java.io.File;
19+
import java.io.IOException;
20+
import java.nio.charset.Charset;
21+
import java.util.HashMap;
22+
import java.util.Map;
23+
24+
public class GraphCsvExporter {
25+
26+
private static final Logger LOG = LoggerFactory.getLogger(GraphCsvExporter.class);
27+
28+
@Parameter(names = {"-v", "--verbose"}, description = "Verbose output")
29+
private boolean verbose = false;
30+
31+
@Parameter(names = {"-d", "--debug"}, description = "Debug mode")
32+
private boolean debug = false;
33+
34+
@Parameter(names = {"-h", "--help"}, description = "Print this help message and exit", help = true)
35+
private boolean help;
36+
37+
@Parameter(names = {"-g", "--graph"}, description = "path to the graph file", required = true)
38+
private String graphPath;
39+
40+
@Parameter(names = {"-eo", "--edges_out"}, description = "output file for edges")
41+
private String outPathEdges;
42+
43+
@Parameter(names = {"-no", "--nodes_out"}, description = "output file for nodes")
44+
private String outPathNodes;
45+
46+
private JCommander jc;
47+
48+
private Graph graph;
49+
50+
private CsvWriter edgeWriter;
51+
52+
private CsvWriter nodeWriter;
53+
54+
public static void main(String[] args) {
55+
GraphCsvExporter graphCsvExporter = new GraphCsvExporter(args);
56+
graphCsvExporter.run();
57+
}
58+
59+
private GraphCsvExporter(String[] args) {
60+
jc = new JCommander(this);
61+
try {
62+
jc.parse(args);
63+
} catch (Exception e) {
64+
System.out.println(e.getMessage());
65+
jc.usage();
66+
System.exit(1);
67+
}
68+
}
69+
70+
private void run() {
71+
72+
/* open input graph (same for all commands) */
73+
File graphFile = new File(graphPath);
74+
try {
75+
graph = Graph.load(graphFile);
76+
} catch (Exception e) {
77+
LOG.error("Exception while loading graph from " + graphFile);
78+
return;
79+
}
80+
81+
/* open output stream (same for all commands) */
82+
if (outPathEdges != null && outPathNodes != null) {
83+
try {
84+
edgeWriter = new CsvWriter(outPathEdges, ';', Charset.forName("UTF8"));
85+
nodeWriter = new CsvWriter(outPathNodes, ';', Charset.forName("UTF8"));
86+
} catch (Exception e) {
87+
LOG.error("Exception while opening output file {}, exiting", outPathEdges);
88+
System.exit(1);
89+
return;
90+
}
91+
} else {
92+
LOG.error("No output files set for nodes or edges");
93+
}
94+
LOG.info("done loading graph.");
95+
96+
printEdgeStats();
97+
exportEdgesToCsv();
98+
edgeWriter.close();
99+
100+
printNodeStats();
101+
exportNodesToCsv();
102+
nodeWriter.close();
103+
}
104+
105+
public void printEdgeStats() {
106+
107+
LOG.info("Count edges by type...");
108+
Map<String, Integer> classCounts = new HashMap<>();
109+
for (Edge edge : graph.getEdges()) {
110+
String edgeClass = edge.getClass().getSimpleName();
111+
int count = classCounts.containsKey(edgeClass) ? classCounts.get(edgeClass) : 0;
112+
classCounts.put(edgeClass, count + 1);
113+
}
114+
for (Map.Entry<String, Integer> entry : classCounts.entrySet()) {
115+
LOG.info(entry.getKey() + " count: " + entry.getValue());
116+
}
117+
118+
LOG.info("Count edges by permission...");
119+
Map<String, Integer> permissionCounts = new HashMap<>();
120+
for (Edge edge : graph.getEdges()) {
121+
if (edge instanceof StreetEdge || edge instanceof StreetWithElevationEdge) {
122+
StreetEdge streetEdge = (StreetEdge) edge;
123+
String permission = String.valueOf(streetEdge.getPermission());
124+
int count = permissionCounts.containsKey(permission) ? permissionCounts.get(permission) : 0;
125+
permissionCounts.put(permission, count + 1);
126+
}
127+
}
128+
for (Map.Entry<String, Integer> entry : permissionCounts.entrySet()) {
129+
LOG.info(entry.getKey() + " count: " + entry.getValue());
130+
}
131+
132+
}
133+
134+
public void exportEdgesToCsv() {
135+
LOG.info("Writing edges to file...");
136+
// Write column names as the first row
137+
String[] record = {"id_otp", "name_otp", "node_orig_id", "node_dest_id", "length", "edge_class", "street_class", "is_stairs", "is_no_thru_traffic", "permission", "allows_walking", "allows_biking", "traversable_walking", "traversable_biking", "bike_safety_factor", "geometry"};
138+
try {
139+
edgeWriter.writeRecord(record);
140+
} catch (IOException ioe) {
141+
LOG.error("Exception while creating CSV");
142+
}
143+
// Write edges of the graph one by one
144+
int writeCount = 0;
145+
for (Edge edge : graph.getEdges()) {
146+
String id = String.valueOf(edge.getId());
147+
String name = edge.getName();
148+
String nodeOrigId = String.valueOf(edge.getFromVertex().getIndex());
149+
String nodeDestId = String.valueOf(edge.getToVertex().getIndex());
150+
String length = String.valueOf(edge.getDistance());
151+
String edgeClass = edge.getClass().getSimpleName();
152+
String streetClass = "";
153+
String isStairs = "False";
154+
String isNoThruTraffic = "False";
155+
String permission = "";
156+
String allowsWalking = "True";
157+
String allowsBiking = "True";
158+
String traversableWalking = "True";
159+
String traversableBiking = "True";
160+
String bikeSafetyFactor = "";
161+
if (edge instanceof StreetEdge) {
162+
StreetEdge streetEdge = (StreetEdge) edge;
163+
streetClass = String.valueOf(streetEdge.getStreetClass());
164+
isStairs = streetEdge.isStairs() ? "True" : "False";
165+
isNoThruTraffic = streetEdge.isNoThruTraffic() ? "True" : "False";
166+
StreetTraversalPermission traversalPermission = streetEdge.getPermission();
167+
permission = String.valueOf(traversalPermission);
168+
allowsWalking = traversalPermission.allows(TraverseMode.WALK) ? "True" : "False";
169+
allowsBiking = traversalPermission.allows(TraverseMode.BICYCLE) ? "True" : "False";
170+
traversableWalking = streetEdge.canTraverseIncludingBarrier(TraverseMode.WALK) ? "True" : "False";
171+
traversableBiking = streetEdge.canTraverseIncludingBarrier(TraverseMode.BICYCLE) ? "True" : "False";
172+
bikeSafetyFactor = String.valueOf(streetEdge.getBicycleSafetyFactor());
173+
}
174+
String geometry = String.valueOf(edge.getGeometry());
175+
// Prepare the record (CSV row) to write
176+
record = new String[]{id, name, nodeOrigId, nodeDestId, length, edgeClass, streetClass, isStairs, isNoThruTraffic, permission, allowsWalking, allowsBiking, traversableWalking, traversableBiking, bikeSafetyFactor, geometry};
177+
try {
178+
edgeWriter.writeRecord(record);
179+
writeCount += 1;
180+
} catch (IOException ioe) {
181+
LOG.error("Exception while writing CSV, exiting");
182+
System.exit(1);
183+
}
184+
}
185+
LOG.info("Wrote {} edges to file: {}", writeCount, outPathEdges);
186+
if (writeCount < graph.getEdges().size()) {
187+
LOG.warn("Did not write all edges to file, missing: {} edges", graph.getEdges().size()-writeCount);
188+
}
189+
}
190+
191+
public void printNodeStats() {
192+
LOG.info("Count nodes by type...");
193+
Map<String, Integer> classCounts = new HashMap<>();
194+
for (Vertex vertex : graph.getVertices()) {
195+
String vertexClass = vertex.getClass().getSimpleName();
196+
int count = classCounts.containsKey(vertexClass) ? classCounts.get(vertexClass) : 0;
197+
classCounts.put(vertexClass, count + 1);
198+
}
199+
for (Map.Entry<String, Integer> entry : classCounts.entrySet()) {
200+
LOG.info(entry.getKey() + " count: " + entry.getValue());
201+
}
202+
}
203+
204+
public void exportNodesToCsv() {
205+
LOG.info("Writing nodes to file...");
206+
// Write column names as the first row
207+
String[] record = {"id_otp", "name_otp", "vertex_class", "traversable_walking", "traversable_biking", "label", "traffic_light", "free_flowing", "x", "y", "geometry"};
208+
try {
209+
nodeWriter.writeRecord(record);
210+
} catch (IOException ioe) {
211+
LOG.error("Exception while creating CSV");
212+
}
213+
// Write nodes (vertices) of the graph one by one
214+
int writeCount = 0;
215+
for (Vertex vertex : graph.getVertices()) {
216+
// basic attributes
217+
String id = String.valueOf(vertex.getIndex());
218+
String vertexClass = vertex.getClass().getSimpleName();
219+
String trafficLight = "False";
220+
String freeFlowing = "";
221+
if (vertex instanceof OsmVertex) {
222+
OsmVertex osmVertex = (OsmVertex) vertex;
223+
trafficLight = osmVertex.trafficLight ? "True" : "False";
224+
freeFlowing = osmVertex.freeFlowing ? "True" : "False";
225+
}
226+
// permissions
227+
String traversableWalking = "True";
228+
String traversableBiking = "True";
229+
if (vertex instanceof BarrierVertex) {
230+
BarrierVertex barrierVertex = (BarrierVertex) vertex;
231+
traversableWalking = barrierVertex.getBarrierPermissions().allows(TraverseMode.WALK) ? "True" : "False";
232+
traversableBiking = barrierVertex.getBarrierPermissions().allows(TraverseMode.BICYCLE) ? "True" : "False";
233+
}
234+
// geometry
235+
String coordX = String.valueOf(vertex.getCoordinate().x);
236+
String coordY = String.valueOf(vertex.getCoordinate().y);
237+
String geometry = "POINT ("+ coordX + " "+ coordY +")";
238+
record = new String[]{id, vertex.getName(), vertexClass, traversableWalking, traversableBiking, vertex.getLabel(), trafficLight, freeFlowing, coordX, coordY, geometry};
239+
try {
240+
nodeWriter.writeRecord(record);
241+
writeCount += 1;
242+
} catch (IOException iow) {
243+
LOG.error("Exception while writing CSV, exiting");
244+
System.exit(1);
245+
}
246+
}
247+
LOG.info("Wrote {} nodes to file: {}", writeCount, outPathNodes);
248+
if (writeCount < graph.getVertices().size()) {
249+
LOG.warn("Did not write all nodes to file, missing {} nodes", graph.getVertices().size()-writeCount);
250+
}
251+
}
252+
}

0 commit comments

Comments
 (0)