Search code examples
pythongraphnetworkxosmnx

How to project GPS coordinates correctly with osmnx?


I'm trying to model a French city (Annecy) with osmnx to test and develop shortest path algorithms. However, to have correct distances I must apply ox.project_graph but I'm then unable to search for the nearest node of any GPS point within the city's boundaries...

Is there a way to project a single coordinates?

I think the problem comes from the coordinates as in the raw graph, the x and y coordinates are exactly the latitude and longitude whereas in the corrected graph, the values are completely different but I don't see any ways to change the x-y coordinates of my points individually...

Here is the code with the raw graph and a shortest point between 2 points:

import osmnx as ox
import networkx as nx

graphe_ville = ox.graph.graph_from_bbox(45.949160, 45.868544, 6.176136, 6.071052, network_type='drive', simplify=True, truncate_by_edge=False, clean_periphery =True)

graphe_ville = ox.add_edge_speeds(graphe_ville)
graphe_ville = ox.add_edge_travel_times(graphe_ville)


x_start, y_start = (6.148903, 45.909408)
x_arrival, y_arrival  = (6.127705, 45.905936)

Start = ox.distance.nearest_nodes(graphe_ville, x_start, y_start)
Arrival = ox.distance.nearest_nodes(graphe_ville, x_arrival, y_arrival)

path = nx.dijkstra_path(graphe_ville,Start,Arrival)

fig, ax = ox.plot_graph_route(graphe_ville, path, route_linewidth=4,node_size=1, figsize=(7,7), bgcolor='#FFFFFF', node_color='#111111')

and here is what I got : Raw graph

Here is the code I have to apply to get correct distance :

import osmnx as ox
import networkx as nx

city_graph = ox.graph.graph_from_bbox(45.949160, 45.868544, 6.176136, 6.071052, network_type='drive', simplify=True, truncate_by_edge=False, clean_periphery =True)
city_graph = ox.project_graph(city_graph) # Allows to get correct distance
city_graph = ox.consolidate_intersections(city_graph, rebuild_graph=True, tolerance=15, dead_ends=True) # Simplify the nodes (eg. for traffic circles)

city_graph = ox.add_edge_speeds(city_graph)
city_graph = ox.add_edge_travel_times(city_graph)

fig, ax = ox.plot_graph(city_graph, figsize=(7,7), bgcolor='#FFFFFF', node_color='#111111')

and here the graph I have : Simplified graph

and if I try to add these lines to the previous code to have the shortest path between the same 2 points

x_start, y_start = (6.148903, 45.909408)
x_arrival, y_arrival  = (6.127705, 45.905936)

Start = ox.distance.nearest_nodes(graphe_ville, x_start, y_start)
Arrival = ox.distance.nearest_nodes(graphe_ville, x_arrival, y_arrival)

path = nx.dijkstra_path(graphe_ville,Start,Arrival)

fig, ax = ox.plot_graph_route(graphe_ville, path, route_linewidth=4,node_size=1, figsize=(7,7), bgcolor='#FFFFFF', node_color='#111111')

I got : Not the right result...


Solution

  • Looking at this answer from @gboeing I've code this function that allows to return the closest node of a point given with its longitude and latitude

    import osmnx as ox
    import geopandas as gpd
    from shapely.geometry import Point
    
    def closest_node(P, G):
        '''
        P is list of two elements that represents the point : the longitude and the latitude (ie. P = [longitude, latitude])
        G is the projected OSMnx graph you are working with 
        returns the ID of the closest node
        '''
        longitude, latitude = P
        shapely_coordinates = gpd.GeoSeries(Point(longitude, latitude), crs='epsg:4326') # epsg:4326 is the Geodetic coordinate system for World which is used by the GPS
        
        projected_point = shapely_coordinates.to_crs(G.graph['crs'])
        
        return ox.distance.nearest_nodes(G, projected_point.x, projected_point.y)[0]