-
Notifications
You must be signed in to change notification settings - Fork 5
Home
gs-geography is part of the GraphStream library and focuses on the import of geographic data into graph structures. It has been conceived to be easily and quickly used by anyone while giving the possibility to customize your use of it.
This tutorial helps to understand the basic mechanisms of gs-geography. If you are a programmer and you want to go deeper into its core and learn how to write your own importer implementations, consider adding LINK to your reading list.
As a gs-geography user, the main objects that you handle are geo sources. A geo source, is an importer that reads one or several files containing geographic data and convert their content into a graph.
Some examples of existing geo sources are:
-
GeoSourceOSM_RoadNetwork, builds a road network graph from an OpenStreetMap XML file. -
GeoSourceOSM_Neighborhood, builds a land lot neighborhood graph from an OpenStreetMap XML file. -
GeoSourceNavteq, builds a road network graph from Navteq shapefiles.
Let's build a road network from OpenStreetMap data. At its simplest, such a gs-geography use-case looks like:
Graph graph = new SingleGraph("road network");
GeoSourceOSM_RoadNetwork src = new GeoSourceOSM_RoadNetwork("/home/osm/le_havre.osm");
src.addSink(graph);
src.read();
src.end();
graph.display(false);
The first block instantiates the output graph to which the content of the input file will be tranfered.
The second block creates the geo source that will be used to convert data from the file. The path to the considered file is passed as a parameter. By adding the graph as a sink to our geo source, we link the source to the output graph.
The third block starts the import process. This is the part that may be the more time consuming so please be patient if you commit large datasets to gs-geography.
Then, all the data read from the file is repercuted to the graph with a call to the end() method.
Finally, the resulting graph is displayed.
The previous example built a road network from an OpenStreetMap file. If you ran it with your own data, you surely noticed that all roads have been imported without any exception. This is fine for a simple use but what if you only want to study a subset of your data? For example, you may prefer to study the canvas of major roads in a particular area. All the other secondary and tertiary roads then becomes irrelevant and clutter the final output (besides, it also speeds down the whole import).
Geographic data files are often huge and may contain a lot of information. gs-geography uses special selectors known as descriptors to specify which features will be kept in the final graph and which ones will be ignored.
The geo sources that you are susceptible to use already contain default descriptors. For example, GeoSourceOSM_RoadNetwork has a single descriptor that selects objects from the input files that are lines and that have a highway attributes and identify them as roads. Conveniently, it is possible to customize it with your own criteria.
A descriptor has three main fields:
- The geometric type of the targetted objects.
- The attribute keys that the objects must possess, whatever their values.
- The attribute key/value pairs that the objects must possess.
For example, here is the descriptor used internally by GeoSourceOSM_Roadnetwork:
[...]
roadDescriptor.mustBe(Element.Type.LINE);
roadDescriptor.mustHave("highway");
You can see that it accepts all linear elements that have a highway attribute attached to them, whatever its value. For a simple use, it is inadvisable to write your own geo source implementation to change the set of elements mirrored in the output graph. However, you can retrieve handles to the descriptors of geo sources and add extra specifications:
Graph graph = new SingleGraph("road network");
GeoSourceOSM_RoadNetwork src = new GeoSourceOSM_RoadNetwork("/home/osm/le_havre.osm");
src.addSink(graph);
ElementDescriptor descriptor = src.getRoadDescriptor();
descriptor.mustHave("highway", "primary");
src.read();
src.end();
graph.display(false);
This capability lets you extract only the features that you really need but beware of conflicting criteria. In case of doubt, use the toString() method of any descriptor to display its full definition.
You now have a graph representing a network of primary roads but, by default, its nodes and edges do not keep any attributes from the input file. Depending on the type of data that you wish to import and depending on your use of it, you may want to have some attributes left like the name of the roads or their speed limits.
In this perspective, gs-geography offers attribute filters. An attribute filter has a list of attribute keys and a mode. The mode is either KEEP or FILTER. With KEEP mode chosen, only attributes specified by the filter will be retained in the graph (this is the default mode). With FILTER mode chosen, all attributes except for those specified in the filter will be kept.
Like descriptors, filters can be retrieved and are customizable:
Graph graph = new SingleGraph("road network");
GeoSourceOSM_RoadNetwork src = new GeoSourceOSM_RoadNetwork("/home/osm/le_havre.osm");
src.addSink(graph);
ElementDescriptor descriptor = src.getRoadDescriptor();
descriptor.mustHave("highway", "primary");
AttributeFilter filter = src.getRoadFilter();
filter.addAttribute("name");
filter.addAttribute("maxspeed");
src.read();
src.end();
graph.display(false);
The appropriate geographic data from the input file is selected, its attributes are filtered and the output graph is populated. You can now execute regular GraphStream commands and algorithms on the produced graph.
Note: this feature is still experimental!
It is possible to represent evolution through time by supplying several files to the library. Each file then corresponds to a specific time step following the order in which they are listed.
The only condition is that each element represented across several files must keep a coherent ID. Then all modifications to the geographic data represented will be taken into account (new elements, removal of elements, shape changes, attribute changes, ...) and temporally indexed:
Graph graph = new SingleGraph("road network");
GeoSourceOSM_RoadNetwork src = new GeoSourceOSM_RoadNetwork(
"/home/osm/map_t0.osm",
"/home/osm/map_t1.osm",
"/home/osm/map_t2.osm"
);
src.addSink(graph);
ElementDescriptor descriptor = src.getRoadDescriptor();
descriptor.setTimeConsideration(TimeConsideration.TIME_FILE);
src.read();
do {
try {
Thread.sleep(1000);
}
catch (Exception e) {
e.printStackTrace();
}
} while(src.next());
The main difference, apart from the several file names passed as attributes to the constructor of the geo source, is that end() is no longer called to populate the graph. Instead, successive calls to next() populate the graph step by step.
At the moment only the time consideration mode TIME_FILE is supported. A TIME_ATTRIBUTE mode is anticipated for any hypothetic file format that would
represent changes in the data via a specific attribute.