Skip to content

OsmGT Wiki

amauryval edited this page Sep 20, 2020 · 49 revisions

What is it ?

OsmGt is a geospatial python library to help you to play with OpenStreetMap (OSM) roads data and to do network analysis with Graph-tool.

This library offers some main features :

  • get roads data into a Geodataframe (GeoPandas) : vehicle or pedestrian paths [more coming soon]
  • generate a graph-tool graph linked to the roads GeoDataframe (topolygy checking and fixing)
  • add new nodes on the network to extend you network analysis

Additional features about OpenStreetMap data are available

  • get OSM points of interest

Also, OsmGt can be a tool to do some common network analysis:

  • (a lot of ) shortest paths
  • isochrones based on time and distance

Of course you can use the geodataframe and the graph without this functions according to your specific requirements.

Don"t forge to check these examples on this Jupyter Notebook


How to install it ?

conda install -c amauryval osmgt

How to use it ?

Before to present code lines, we have to present you some prerequisites informations about functions arguments.

You can load/compute data from:

  1. a location name (ex: Lyon) ; a Nominatim api call is done to catch the boundaries of the input location name area
  2. a bounding box (min_x=-74.018433, min_y=40.718087, max_x=-73.982749, max_y=40.733356)

You can load a specific network based on the transport mode (from Overpass Turbo query):

  1. vehicle mode: will create a directed graph, because direction are important
  2. pedestrian mode (freeway are not load here for example): will create an undirected graph
  3. more will comming soon...

How to load data ?

Roads and graph

2 methods are available.

  • Get roads network from a location name :
from osmgt import OsmGt

roads_osmgt_initialized = OsmGt.roads_from_location(
    location_name="Lyon",
    mode="vehicle",  # or "pedestrian"
    additional_nodes=my_additional_nodes_gdf  # eat a GeoDataframe [optional]
)

# You can get the GeoDataframe
roads_gdf = roads_osmgt_initialized.get_gdf()

# You can get the graph-tool graph based on the roads gdf built
roads_graph = roads_osmgt_initialized.get_graph()

As you can see add additionals nodes on your next network:

  1. with a nodes Geodataframe (attributes are preserved)
  • Get roads network from a bounding box:
from osmgt import OsmGt

roads_osmgt_initialized = OsmGt.roads_from_bbox(
    bbox_values=(min_x=-74.018433, min_y=40.718087, max_x=-73.982749, max_y=40.733356),
    mode="vehicle",  # or "pedestrian"
    additional_nodes=my_additional_nodes_gdf  # eat a GeoDataframe [optional]
)

# You can get a roads GeoDataframe
roads_gdf = roads_osmgt_initialized.get_gdf()
# the topology processing generate a column named "topo_uuid" used as unique id for each features, because the network has been fixing (intersection, connection...)
# OSM attributes are present, especially the OSM ID named "id" (not unique after processing)

# You can get the graph-tool graph based on the roads GeoDataframe built above
roads_graph = roads_osmgt_initialized.get_graph()

Of course you are free to use the graph-tool library !

Attributes added

Roads Geodataframe returns all the existing OSM attributes. Also OsmGt creates some news fields :

  • topo_uuid: unique id created during the topology fixing ;
  • topology: value indicates the topology fix applied (split, added or unchanged) ;
  • osm_url: OSM url to the original object (based on the OSM id: 'id' column).

Point of interests

2 methods are available.

  • Get POIs from a location name:
from osmgt import OsmGt

pois_initialized = OsmGt.pois_from_location(
    location_name="Lyon"
)
pois_gdf = pois_initialized .get_gdf()
  • Get POIs from a bounding box:
from osmgt import OsmGt

pois_initialized = OsmGt.pois_from_bbox(
    bbox_values=(min_x=-74.018433, min_y=40.718087, max_x=-73.982749, max_y=40.733356),
)
pois_gdf = pois_initialized .get_gdf()

Now we can use the GeoDataframe output as argument on the OsmGt.roads_from_bbox() method to add all the POIs found on the roads network !

Attributes added

POIs Geodataframe returns all the existing OSM attributes. Also OsmGt creates some news fields :

  • topo_uuid: unique id created during the topology fixing ;
  • osm_url: OSM url to the original object (based on the OSM id: 'id' column).

Results

osmgt output

Bonus

Data area

For roads and POIs, you can get the shapely geometry study area (Polygon) of your loaded data:

roads_study_area_geom = roads_osmgt_initialized.study_area

pois_study_area_geom = pois_initialized.study_area

Topology checker

You can analyse the topology of the output data

roads_topology_gdfs = roads_osmgt_initialized.topology_checker()

osmgt topology

Graph visualization

You can visualize the graph build and export it to a image

roads_graph = roads_osmgt_initialized.get_graph()
roads_graph.plot()

osmgt graphe

Let's go to play

Now you have load some data. So we can play with the graph-tool library, compute some network analysis.

We are starting with this:

from osmgt import OsmGt

bbox_area = (74.018433, 40.718087, -73.982749, 40.733356)

pois_gdf = OsmGt.pois_from_bbox(
    bbox_values=bbox_area
)

roads_osmgt_initialized = OsmGt.roads_from_bbox(
    bbox_values=bbox_area,
    mode="vehicle",
    additional_nodes=pois_gdf
)

# You have a roads GeoDataframe
roads_gdf = roads_osmgt_initialized.get_gdf()

# You have a graph-tool graph based on the roads GeoDataframe built above
roads_graph = roads_osmgt_initialized.get_graph()

Be careful: if you apply some geometry changes on the output roads Geodataframe, the roads graph generated won't match anymore, because the link between them is based on the node wkt geometry value :

  • graph is build with the start and end geom wkt nodes of each road lines
  • graph edge are based on the "topo_uuid" linestring value
  • graph edge weigth based on the line length

That's why the graph-tool graph have some specified methods to link the roads GeoDataframe:

roads_graph = roads_osmgt_initialized.get_graph()

# find a specific vertex based on the name (means geom wkt)
a_vertex = roads_graph.find_vertex_from_name("POINT (1 0)")  # vertex (or node)
an_edge = roads_graph.find_edge_from_name("10_0")  # edge (meaning linestring on the GeoDataframe)

# find a specific edge/vertex based on a graph-tool edge/vertex
an_edge = roads_graph.edge_names[a_graph_tool_edge]
a_vertex = roads_graphaph.vertex_names[a_graph_tool_vertex]

So if you are doing a shortest path computing, you can match the shortest path graph-tool output with your GeoDataframe with these methods. You can find an example here at this topic ; but OsmGt can help you to do some network analysis!

Network analysis tools

You can find some examples from here

OsmGt have other method to help you to do some network analysis:

  • shortest paths ;
  • isochrones.

Shortest paths

How to

2 methods are available:

  • Find some shortest paths from a location name
from osmgt import OsmGt

shortest_paths_gdf = OsmGt.shortest_path_from_location(
    location_name="Lyon",
    source_target_points=source_targets_pairs,  # a list of tuples containing a source and target shapely Point,
    mode="pedestrian",  # or "vehicle"
)
  • Find some shortest paths from a bounding box
from osmgt import OsmGt

shortest_paths_gdf = OsmGt.shortest_path_from_bbox(
    bbox_values=(74.018433, 40.718087, -73.982749, 40.733356),
    source_target_points=source_targets_pairs,  # a list of tuples containing a source and target shapely Point,
    mode="pedestrian",  # or "vehicle"
)

Each function returns 1 GeoDataframe containing all the shortest paths computed

Results

Shortest path

Output attributes

You can find these attributes :

  • source_node: the geom wkt of the source node ;
  • target_node: the geom wkt of the target node ;.
  • osm_ids: the list of the OSM id used by the shortest path computed ;
  • osm_urls: the list of the OSM url of each path feature (based on the OSM id).

Isochrones

isochrones functions

2 methods are available:

  • create isochrone based on times
from osmgt import OsmGt

isochrones_polygons_gdf, isochrones_lines_gdf = OsmGt.isochrone_from_coordinates(
    source_node=source_point,  # a shapely Point
    isochrones_times=[2, 5, 10],  # in minutes, so we'll create 3 isochrones based on time
    trip_speed=3,  # km/h
    mode="pedestrian",  # or "vehicle"
)
  • create isochrone based on distances
from osmgt import OsmGt

isochrones_polygons_gdf, isochrones_lines_gdf = isochrone_distance_from_coordinates(
    source_node=source_point,  # a shapely Point
    distances=[100, 1000],  # in meters, so we'll create 2 isochrones based on distance
    trip_speed=3,  # km/h
    mode="pedestrian",  # or "vehicle"
)

Each function returns 2 GeoDataframe containing:

  1. isochrones polygons
  2. roads network concerned and tagged by each isochrone

Results

  • Isochrones based on times (minutes)

Mode : pedestrian :

isochrone pedestrian from time

  • Isochrones based on distances (meters)

Mode : pedestrian :

isochrone pedestrian from distance

And if you want to use an other mode (here vehicle) :

isochrone vehicle from distance

Output attributes

About isochrones polygons attributes:

  • iso_name: the name of the isochrone based on the time (in minutes) ;
  • iso_distance: the distance of the isochrone (in meters).

About isochrones lines attributes:

  • OSM attributes
  • topo_uuid: unique id created during the topology fixing ;
  • topology: value indicates the topology fix applied (split, added or unchanged) ;
  • osm_url: OSM url to the original object (based on the OSM id: 'id' column).
  • iso_name: the name of the isochrone based on the time (in minutes) ;
  • iso_distance: the distance of the isochrone (in meters).

Analysis limits

I recommend to use both outputs for interpreting the results. After a very detailed analysis, you can notice some slight "error" between roads and polygons. It's caused by the tolerance value used to build polygon isochrones.

tolerance issue

Also, isochrones polygons output need some improvements in order to fill some interiors polygons which are not consistent with theirs neighbors isochrones (fix is on going).

polygon inconsistence

Clone this wiki locally