{"id":25254245,"url":"https://github.com/trafficgcn/optimal_path_dijkstra_for_data_science","last_synced_at":"2025-10-27T01:31:03.207Z","repository":{"id":173108993,"uuid":"527054995","full_name":"TrafficGCN/optimal_path_dijkstra_for_data_science","owner":"TrafficGCN","description":"Plotting the Optimal Route in Python for Data Scientists using the Dijkstra Algorithm","archived":false,"fork":false,"pushed_at":"2023-02-26T01:57:31.000Z","size":949,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2023-11-23T21:26:45.479Z","etag":null,"topics":["data-science","dijkstra","dijkstra-algorithm","dijkstra-shortest-path","map","mapping","open-street-map","optimal-route","osm","osmnx","python"],"latest_commit_sha":null,"homepage":"https://thomasafink.com/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TrafficGCN.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2022-08-20T22:40:06.000Z","updated_at":"2023-11-23T21:26:48.316Z","dependencies_parsed_at":"2023-11-23T21:42:32.502Z","dependency_job_id":null,"html_url":"https://github.com/TrafficGCN/optimal_path_dijkstra_for_data_science","commit_stats":null,"previous_names":["thomasafink/optimal_path_dijkstra_for_data_science","trafficgcn/optimal_path_dijkstra_for_data_science"],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TrafficGCN%2Foptimal_path_dijkstra_for_data_science","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TrafficGCN%2Foptimal_path_dijkstra_for_data_science/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TrafficGCN%2Foptimal_path_dijkstra_for_data_science/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TrafficGCN%2Foptimal_path_dijkstra_for_data_science/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TrafficGCN","download_url":"https://codeload.github.com/TrafficGCN/optimal_path_dijkstra_for_data_science/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238418236,"owners_count":19468869,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-science","dijkstra","dijkstra-algorithm","dijkstra-shortest-path","map","mapping","open-street-map","optimal-route","osm","osmnx","python"],"created_at":"2025-02-12T05:31:29.147Z","updated_at":"2025-10-27T01:30:57.856Z","avatar_url":"https://github.com/TrafficGCN.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Plotting the Optimal Route in Python for Data Scientists using the Dijkstra Algorithm\n\n\u003cimg src=\"https://github.com/ThomasAFink/optimal_path_dijkstra_for_data_science/blob/main/output/dijkstra_map.jpg?raw=true\" width=\"450\" align=\"right\"\u003e\n\nThe following example uses [OSMnx](https://osmnx.readthedocs.io/en/stable/) to generate the optimal path between two geocoordinates and between one and many points and plotting the path(s) on a [Plotly](https://plotly.com/) map. This is a quick and simple example that data scientists can use to illustrate a path(s) for their professional or academic papers.\n\nA brief file structure overview of the repository is provided. The dijkstra_map.py is in the root directory. The data folder houses a list of target geocoordinates in a csv file. The out map is generated in the output folder.\n\n    /\n    dijkstra_map.py\n\n    - / data /\n    geocoordinates.csv\n\n    - / output /\n    dijkstra_map.jpg\n    \nThe geocoordinates.csv includes the following target geocoordinates.\n\n    LATITUDE\tLONGITUDE\n    48.13485\t11.5173913\n    48.1348182\t11.577103\n    48.1492002\t11.5592469\n    48.11005\t11.59344\n    48.158903\t11.5856\n    \nBefore jumping into the code the following requirements and packages are needed to run the code:\n\n    Python 3.10.6\n    pip3 install osmnx==0.16.1 \n    pip3 install geopandas==0.9.0\n    pip3 install shapely==1.8.0\n    pip3 install -U kaleido\n    pip3 install networkx\n    pip3 install plotly\n    pip3 install pandas\n    \nFirst the packages that were just installed are imported into our file dijkstra_map.py\n\n    import networkx as nx\n    import plotly.graph_objects as go\n    import osmnx as ox\n    import pandas as pd\n    import geopandas\n\nNext a function is created which returns a list of geocoordinates belonging to the optimal path between two geocoordinates. The function is needed to iterate through several target points. The function takes three parameters an origin coordinate, a target coordinate, and a perimeter around those coordinates. The perimeter should be larger for points that a further from another, but a small as possible to keep processing time practical. For plotting routes in a city a perimeter value between 0.10 and 0.20 is should suffice.\n\n    ##### Interface to OSMNX    \n    def generate_path(origin_point, target_point, perimeter):\n    \nInside the function a cache configuration is an optional method to store maps from OSM. This is especially resourceful for storing larger maps as it requires fewer requests to the api. For plotting a handful of paths this really does not impact processing time sigificantly.\n\n    # Using the cache accelerates processing for a large map\n    ox.config(log_console=True, use_cache=True)\n    \nNext inside the function the gecoordinates are spliced and the underlying structure of the graph network is set up. If the origin point is further from the equator than the target point, then the path starts from the north and ends in the south (and viceversa). If the origin point is further from the prime meridian than the target point, then the path starts in the east and ends in the west and (viceversa). This [logic](https://github.com/jasonmanesis/Vehicle-Navigation-Shortest-Path/blob/main/vehicle_navigation_shortest_path.py) was provided by [jasonmanesis](https://github.com/jasonmanesis) on [GitHub](https://github.com/jasonmanesis/Vehicle-Navigation-Shortest-Path).\n\n    # Splice the geographical coordinates in long and lat\n    origin_lat = origin_point[0]\n    origin_long = origin_point[1]\n\n    target_lat = target_point[0]\n    target_long = target_point[1]\n\n    # Build the geocoordinate structure of the path's graph\n\n    # If the origin is further from the equator than the target\n    if  origin_lat \u003e target_lat:\n        north = origin_lat \n        south = target_lat\n    else:\n        north = target_lat\n        south = origin_lat\n\n    # If the origin is further from the prime meridian than the target\n    if  origin_long \u003e target_long:\n        east = origin_long \n        west = target_long\n    else:\n        east = target_long\n        west = origin_long\nAfter the underlying graph structure is determined the graph mode is set to drive. Drive captures the road network used by automobiles. Bike capture the path network used by bicycles. Walk capture the walkway network used by pedestrians. Finding an optimal walkway is usually too resources intensive when processing due to the fact that their are many more nodes on the walking graph.\n\n    # Construct the road graph\n    # Modes 'drive', 'bike', 'walk' (walk is usually too slow)\n    mode = 'drive'\nFinally the graph can be requested and downloaded from the OSMnx api. The graph perimeters are set in the parameters and passed to the api request. The graph mode is also passed along.\n\n    # Create the path/road network graph via setting the perimeters\n    roadgraph = ox.graph_from_bbox(north+perimeter, south-perimeter, \n    east+perimeter, west-perimeter, network_type = mode, simplify=False)\nAlternatively a map can also be requested via the place instead of using coordinates. This may be useful for requesting larger maps and storing them locally in the cache.\n\n    '''\n    # Alternatively a road network can be determined via providing a place\n    place  = 'Munich, Bavaria, Germany'\n    roadgraph = ox.graph_from_bbox(place, network_type = 'drive', simplify=False )\n    '''\nNext the nearest node in the graph network is found for both the origin and target coordinates. It could for example be that the origin or target does not fall on the road, bike, or walk grid in the OSMnx graph network.\n\n    # Get the nearest node in the OSMNX graph for the origin point\n    origin_node = ox.get_nearest_node(roadgraph, origin_point) \n\n    # Get the nearest node in the OSMNX graph for the target point\n    target_node = ox.get_nearest_node(roadgraph, target_point)\nUsing the shortest_path function provided by NetworkX the optimal route is found using the dijkstra as the method and the length between the nodes as the weight. Another method is the bellman-ford algorithm.\n\n    # Get the optimal path via dijkstra\n    route = nx.shortest_path(roadgraph, origin_node, target_node, weight =\n    'length', method='dijkstra')\nFinally the optimal path and its geocoordinates are returned via the route variable and stored in longitude and latitude arrays.\n\n    # Create the arrays for storing the paths\n    lat = []\n    long = []\n\n    for i in route:\n        point = roadgraph.nodes[i]\n        long.append(point['x'])\n        lat.append(point['y'])\nTo conclude the function the optimal path is then returned as two arrays, longitude and latitude.\n\n    # Return the paths\n    return long, lat\nNow that the function for finding the optimal paths between two points generate_path(origin_point, target_point, perimeter) is setup a function to plot the results on the Plotly map is created. This function takes the origin point the target points and the optimal paths provided by two lists as longitude and latitude.\n\ndef plot_map(origin_point, target_points, long, lat):\nFirst inside the function a Plotly map figure is created and the origin point is defined as black marker.\n\n    # Create a plotly map and add the origin point to the map\n    print(\"Setting up figure...\")  \n    fig = go.Figure(go.Scattermapbox(\n        name = \"Origin\",\n        mode = \"markers\",\n        lon = [origin_point[1]],\n        lat = [origin_point[0]],\n        marker = {'size': 16, 'color':\"#333333\"},\n        )   \n\n    )\nNext the optimal paths are added to the Plotly map figure as a yellow color.\n\n    # Plot the optimal paths to the map\n    print(\"Generating paths...\")   \n    for i in range(len(lat)):\n        #print(lat[i])\n        #print(long[i])\n        fig.add_trace(go.Scattermapbox(\n            name = \"Path\",\n            mode = \"lines\",\n            lon = long[i],\n            lat = lat[i],\n            marker = {'size': 10},\n            showlegend=False,\n            line = dict(width = 4.5, color = '#ffd700'))\n        )\nThe target points are also added as yellow markers.\n\n    # Plot the target geocoordinates to the map\n    print(\"Generating target...\")  \n    for target_point in target_points:\n        fig.add_trace(go.Scattermapbox(\n            name = \"Destination\",\n            mode = \"markers\",\n            showlegend=False,\n            lon = [target_point[1]],\n            lat = [target_point[0]],\n            marker = {'size': 16, 'color':'#ffd700'}))\nNext the style of the map layout is determined. The light theme from Mapbox was used. An API access token from [Mapbox](https://www.mapbox.com/) can be acquired for free after [signing up](https://account.mapbox.com/auth/signup/). Mapbox has many beautiful maps from a variety of contributors. These look nice in academic papers. Remember to attribute the map creator. Times New Roman was used and the shape was set to a square.\n\n    # Style the map layout\n    fig.update_layout(\n        mapbox_style=\"light\",       \n        mapbox_accesstoken=\"############\",\n        legend=dict(yanchor=\"top\", y=1, xanchor=\"left\", x=0.83), #x 0.9\n        title=\"\u003cspan style='font-size: 32px;'\u003e\u003cb\u003eThe Shortest Paths Dijkstra\n        Map\u003c/b\u003e\u003c/span\u003e\",\n        font_family=\"Times New Roman\",\n        font_color=\"#333333\",\n        title_font_size = 32,\n        font_size = 18,\n        width=1000, #2000\n        height=1000,\n    )\nNext the center of the map was manually added. There are methods for calculating this, but not included in this tutorial. An easy way to determine the map center is to look at Google Maps and gauge it that way. It may be better to include the map’s center with the function parameters.\n\n    # Set the center of the map\n    lat_center = 48.14\n    long_center = 11.57\n\n    # Add the center to the map layout\n    fig.update_layout(margin={\"r\":0,\"t\":0,\"l\":0,\"b\":0},\n        title=dict(yanchor=\"top\", y=.97, xanchor=\"left\", x=0.03), #x 0.75\n        mapbox = {\n            'center': {'lat': lat_center, \n            'lon': long_center},\n            'zoom': 12.2}\n    )\nFinally the function saves the map as a jpg in the output folder as dijkstra_map.jpg and then generates an interactive Plotly map in the default OS browser.\n\n    # Save map in output folder\n    print(\"Saving image to output folder...\");\n    fig.write_image('output/dijkstra_map.jpg', scale=3)\n\n    # Show the map in the web browser\n    print(\"Generating map in browser...\");\n    fig.show()\nNow that both functions are set up the main section of the script is written.\n\nFirst in the main part of the script a list of target geocoordinates are fetched from the data folder in the geocoordinates.csv file and loaded into python using pandas’ dataframe method. The geocoordinates are then formatted as geocoordinates using geopandas.\n\n    # Data import path\n    SENSORS_CSV   = 'data/geocoordinates.csv'\n\n    # Data Import\n    df1 = pd.read_csv(SENSORS_CSV)\n\n    # Keep only relevant columns\n    df = df1.loc[:, (\"LATITUDE\", \"LONGITUDE\")]\n\n    # Create point geometries\n    geometry = geopandas.points_from_xy(df.LONGITUDE, df.LATITUDE)\n    geo_df = geopandas.GeoDataFrame(df[['LATITUDE', 'LONGITUDE']], geometry=geometry)\n\n    # Format the target geocoordinates from the csv file\n    target_points = []\n    for lo, la in zip(df[\"LONGITUDE\"], df[\"LATITUDE\"]):\n       print(lo)\n       target_points.append((la,lo))\n\nNext the origin point is defined.\n\n    # Set the origin geocoordinate from which the paths are calculated\n    origin_point = (48.1372038, 11.565651)  \n    Lists are declared to store the optimal paths.\n\n    # Create the lists for storing the paths\n    long = []\n    lat = []\n\nUsing the list of target points from the data folder our generate_path function is called to return an optimal path for every target point. The perimeter can also be set here.\n\n    i = 0\n    for target_point in target_points:\n\n        # Perimeter is the scope of the road network around a geocoordinate\n        perimeter = 0.10\n\n        # Process the optimal path\n        print(\"Processing *************************************** \" + str(i))\n        x, y = generate_path(origin_point, target_point, perimeter)\n    \n        # Append the paths\n        long.append(x)\n        lat.append(y)\n\n        i += 1\n\nFinally our plot_map function is called after getting the optimal paths.\n\n    plot_map(origin_point, target_points, long, lat)\n\nGenerating optimal paths may be particularly helpful for example when visualising and understanding graph neural networks, or GNNs, in for traffic forecasting.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrafficgcn%2Foptimal_path_dijkstra_for_data_science","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrafficgcn%2Foptimal_path_dijkstra_for_data_science","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrafficgcn%2Foptimal_path_dijkstra_for_data_science/lists"}