OpenStreetMapX - Julia vehicle routing simulation tutorial + folium vizualisation

In this tutorial we will run a vehicle routing simulation in Julia with the OpenStreetMapX.jl library and use Python's folium package for providing an interactive vizualization of results.

This notebook can be downloaded in Jupyter ipynb format here (right-click to download).

Firstly, start by installing the required Julia and Python packages.

In [ ]:
#required installation for map vizualiztion
using Pkg
Pkg.add("PyCall")
Pkg.add("Conda")
Pkg.add("OpenStreetMapX")
using Conda
Conda.runconda(`install folium -c conda-forge`)

Let us load the map of east of Reno (this file is provided together with the OpenStreetMapX.jl package) and move few thousands of cars around it between random pairs of destinations

In [12]:
using OpenStreetMapX
# you can replace the line below with a String representing another path to an OSM map file.
map_file_path = joinpath(dirname(pathof(OpenStreetMapX)),"..","test/data/reno_east3.osm")
mx = get_map_data(map_file_path, use_cache=false);
using Random 
Random.seed!(0)
node_ids = collect(keys(mx.nodes)) 
routes = Vector{Vector{Int}}()
visits = Dict{Int,Int}()
for i in 1:5000
    a,b = [point_to_nodes(generate_point_in_bounds(mx), mx) for _ in 1:2]
    route, route_time = OpenStreetMapX.shortest_route(mx,a,b)
    if route_time < Inf # when we select points neaer edges no route might be found
        push!(routes, route)
        for n in route
            visits[n] = get(visits, n,0)+1
        end 
    end
end                                   
println("We have generated ",length(routes)," non-empty routes")
We have generated 4244 non-empty routes

Now we vizualize the first 20 random paths in the actual map.

Note that the map is interactive - you can browse around etc..

In [13]:
using PyCall
flm = pyimport("folium")
matplotlib_cm = pyimport("matplotlib.cm")
matplotlib_colors = pyimport("matplotlib.colors")

cmap = matplotlib_cm.get_cmap("prism")

SHOW_PATHS=20
m = flm.Map()
for k=1:min(SHOW_PATHS, length(routes))
    locs = [LLA(mx.nodes[n],mx.bounds) for n in routes[k]]
    info = "Sample route number $k\n<BR>"*
        "Length: $(length(routes[k])) nodes\n<br>" *
        "From: $(routes[k][1]) $(round.((locs[1].lat, locs[1].lon),digits=4))\n<br>" *
        "To: $(routes[k][end]) $(round.((locs[end].lat, locs[end].lon),digits=4))"
    flm.PolyLine(        
        [(loc.lat, loc.lon) for loc in locs ],
        popup=info,
        tooltip=info,
        color=matplotlib_colors.to_hex(cmap(k/SHOW_PATHS))       
    ).add_to(m)
end

MAP_BOUNDS = [(mx.bounds.min_y,mx.bounds.min_x),(mx.bounds.max_y,mx.bounds.max_x)]
flm.Rectangle(MAP_BOUNDS, color="black",weight=6).add_to(m)
m.fit_bounds(MAP_BOUNDS)
m
Out[13]:

Now let show the most freqeuntly visited intersections in our simulation.

In [14]:
m = flm.Map()

max_visits= maximum(values(visits))
for k=keys(visits)
    visits[k] < 25 && continue  #skip nodes infrequently visited
    loc = LLA(mx.nodes[k],mx.bounds)
    info = "Node $(k) at ($(round(loc.lat,digits=4)), $(round(loc.lon,digits=4)))\n<br>"*
           "visits: $(visits[k])"
    flm.Circle(
      location=[loc.lat,loc.lon],
      popup=info,
      tooltip=info,
      radius=500*visits[k]/max_visits,
      color="crimson",
      weight=0.5,
      fill=true,
      fill_color="crimson"
   ).add_to(m)
end
flm.Rectangle(MAP_BOUNDS, color="black",weight=6).add_to(m)
m.fit_bounds(MAP_BOUNDS)
m
Out[14]: