-
Notifications
You must be signed in to change notification settings - Fork 5
gs geography for the geographer
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 gs-geography for the programmer to your reading list.
As a gs-geography user, the main objects that you handle are geo sources. A GeoSource
, 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 tranferred.
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. The relevant data from the input file is loaded into memory and organized.
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 become 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 five 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.
- The attribute keys that the objects must not possess, whatever their values.
- The attribute key/value pairs that the objects must not possess.
For example, here is the descriptor used internally by GeoSourceOSM_Roadnetwork
:
[...] roadDescriptor.mustBe(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 just to change the set of elements mirrored in the output graph. However, you can retrieve handles to the descriptors of preset 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 edges do not keep any attribute 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 in 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.
By default, gs-geography binds all data that it receives to a single time step. If, however, your data is time-dependent, you can notify gs-geography and it will separate elements appearing at different times and acknowledge any attribute change or shape change.
With a call to src.timeDependsOnFile()
before read()
, each file that you pass to the constructor of the source is considered as a different time step. Please make sure that the file are provided in the correct temporal order.
With a call to src.timeDependsOnAttribute(key)
, the time of appearance of a geographic object is read from its attribute with the ''key'' key.
With a call to src.noTime()
, time is not considered (this is the default setting).
Here is a simple example in which three files are read, each representing a single step:
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); src.timeDependsOnFile(); 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.